1
/*************************************************************************
2
* Copyright (C) 2004 by Olivier Galizzi *
3
* olivier.galizzi@imag.fr *
4
* Copyright (C) 2004 by Janek Kozicki *
7
* This program is free software; it is licensed under the terms of the *
8
* GNU General Public License v2 or later. See file LICENSE for details. *
9
*************************************************************************/
13
#include"TimeStepper.hpp"
14
#include"ThreadRunner.hpp"
15
#include<yade/lib/base/Math.hpp>
16
#include<yade/lib/multimethods/FunctorWrapper.hpp>
17
#include<yade/lib/multimethods/Indexable.hpp>
19
#include<boost/filesystem/operations.hpp>
20
#include<boost/filesystem/convenience.hpp>
21
#include<boost/filesystem/exception.hpp>
22
#include<boost/algorithm/string.hpp>
23
#include<boost/thread/mutex.hpp>
24
#include<boost/version.hpp>
25
#include<boost/python.hpp>
27
#include<yade/lib/serialization/ObjectIO.hpp>
32
#if BOOST_VERSION<103500
33
class RenderMutexLock: public boost::try_mutex::scoped_try_lock{
35
RenderMutexLock(): boost::try_mutex::scoped_try_lock(Omega::instance().renderMutex,true){/*cerr<<"Lock renderMutex"<<endl;*/}
36
~RenderMutexLock(){/* cerr<<"Unlock renderMutex"<<endl; */}
39
class RenderMutexLock: public boost::mutex::scoped_lock{
41
RenderMutexLock(): boost::mutex::scoped_lock(Omega::instance().renderMutex){/* cerr<<"Lock renderMutex"<<endl; */}
42
~RenderMutexLock(){/* cerr<<"Unlock renderMutex"<<endl;*/ }
47
SINGLETON_SELF(Omega);
49
const map<string,DynlibDescriptor>& Omega::getDynlibsDescriptor(){return dynlibs;}
51
const shared_ptr<Scene>& Omega::getScene(){return scenes.at(currentSceneNb);}
52
void Omega::resetCurrentScene(){ RenderMutexLock lock; scenes.at(currentSceneNb) = shared_ptr<Scene>(new Scene);}
53
void Omega::resetScene(){ resetCurrentScene(); }//RenderMutexLock lock; scene = shared_ptr<Scene>(new Scene);}
54
void Omega::resetAllScenes(){
57
scenes[0] = shared_ptr<Scene>(new Scene);
60
int Omega::addScene(){
61
scenes.push_back(shared_ptr<Scene>(new Scene));
62
return scenes.size()-1;
64
void Omega::switchToScene(int i) {
65
if (i<0 || i>=int(scenes.size())) {
66
LOG_ERROR("Scene "<<i<<" has not been created yet, no switch.");
74
Real Omega::getRealTime(){ return (microsec_clock::local_time()-startupLocalTime).total_milliseconds()/1e3; }
75
time_duration Omega::getRealTime_duration(){return microsec_clock::local_time()-startupLocalTime;}
78
void Omega::initTemps(){
79
char dirTemplate[]="/tmp/yade-XXXXXX";
80
tmpFileDir=mkdtemp(dirTemplate);
84
void Omega::cleanupTemps(){
85
filesystem::path tmpPath(tmpFileDir);
86
filesystem::remove_all(tmpPath);
89
std::string Omega::tmpFilename(){
90
if(tmpFileDir.empty()) throw runtime_error("tmpFileDir empty; Omega::initTemps not yet called()?");
91
boost::mutex::scoped_lock lock(tmpFileCounterMutex);
92
return tmpFileDir+"/tmp-"+lexical_cast<string>(tmpFileCounter++);
104
sceneAnother=shared_ptr<Scene>(new Scene);
106
createSimulationLoop();
109
void Omega::timeInit(){
110
startupLocalTime=microsec_clock::local_time();
113
void Omega::createSimulationLoop(){ simulationLoop=shared_ptr<ThreadRunner>(new ThreadRunner(&simulationFlow_));}
114
void Omega::stop(){ LOG_DEBUG(""); if (simulationLoop&&simulationLoop->looping())simulationLoop->stop(); if (simulationLoop) simulationLoop=shared_ptr<ThreadRunner>(); }
116
/* WARNING: even a single simulation step is run asynchronously; the call will return before the iteration is finished. */
119
simulationLoop->spawnSingleAction();
124
if(!simulationLoop){ LOG_ERROR("No Omega::simulationLoop? Creating one (please report bug)."); createSimulationLoop(); }
125
if (simulationLoop && !simulationLoop->looping()){
126
simulationLoop->start();
132
if (simulationLoop && simulationLoop->looping()){
133
simulationLoop->stop();
137
bool Omega::isRunning(){ if(simulationLoop) return simulationLoop->looping(); else return false; }
139
void Omega::buildDynlibDatabase(const vector<string>& dynlibsList){
140
LOG_DEBUG("called with "<<dynlibsList.size()<<" plugins.");
141
boost::python::object wrapperScope=boost::python::import("yade.wrapper");
142
std::list<string> pythonables;
143
FOREACH(string name, dynlibsList){
144
shared_ptr<Factorable> f;
146
LOG_DEBUG("Factoring plugin "<<name);
147
f = ClassFactory::instance().createShared(name);
148
dynlibs[name].isIndexable = dynamic_pointer_cast<Indexable>(f);
149
dynlibs[name].isFactorable = dynamic_pointer_cast<Factorable>(f);
150
dynlibs[name].isSerializable = dynamic_pointer_cast<Serializable>(f);
151
for(int i=0;i<f->getBaseClassNumber();i++){
152
dynlibs[name].baseClasses.insert(f->getBaseClassName(i));
154
if(dynlibs[name].isSerializable) pythonables.push_back(name);
156
catch (std::runtime_error& e){
157
/* FIXME: this catches all errors! Some of them are not harmful, however:
158
* when a class is not factorable, it is OK to skip it; */
161
// handle Serializable specially
162
//Serializable().pyRegisterClass(wrapperScope);
163
/* python classes must be registered such that base classes come before derived ones;
164
for now, just loop until we succeed; proper solution will be to build graphs of classes
165
and traverse it from the top. It will be done once all classes are pythonable. */
166
for(int i=0; i<100 && pythonables.size()>0; i++){
167
if(getenv("YADE_DEBUG")) cerr<<endl<<"[[[ Round "<<i<<" ]]]: ";
168
std::list<string> done;
169
for(std::list<string>::iterator I=pythonables.begin(); I!=pythonables.end(); ){
170
shared_ptr<Serializable> s=static_pointer_cast<Serializable>(ClassFactory::instance().createShared(*I));
172
if(getenv("YADE_DEBUG")) cerr<<"{{"<<*I<<"}}";
173
s->pyRegisterClass(wrapperScope);
174
std::list<string>::iterator prev=I++;
175
pythonables.erase(prev);
177
if(getenv("YADE_DEBUG")){ cerr<<"["<<*I<<"]"; PyErr_Print(); }
178
boost::python::handle_exception();
184
map<string,DynlibDescriptor>::iterator dli = dynlibs.begin();
185
map<string,DynlibDescriptor>::iterator dliEnd = dynlibs.end();
186
for( ; dli!=dliEnd ; ++dli){
187
set<string>::iterator bci = (*dli).second.baseClasses.begin();
188
set<string>::iterator bciEnd = (*dli).second.baseClasses.end();
189
for( ; bci!=bciEnd ; ++bci){
191
if (name=="Dispatcher1D" || name=="Dispatcher2D") (*dli).second.baseClasses.insert("Dispatcher");
192
else if (name=="Functor1D" || name=="Functor2D") (*dli).second.baseClasses.insert("Functor");
193
else if (name=="Serializable") (*dli).second.baseClasses.insert("Factorable");
194
else if (name!="Factorable" && name!="Indexable") {
195
shared_ptr<Factorable> f = ClassFactory::instance().createShared(name);
196
for(int i=0;i<f->getBaseClassNumber();i++)
197
dynlibs[name].baseClasses.insert(f->getBaseClassName(i));
204
bool Omega::isInheritingFrom(const string& className, const string& baseClassName){
205
return (dynlibs[className].baseClasses.find(baseClassName)!=dynlibs[className].baseClasses.end());
208
bool Omega::isInheritingFrom_recursive(const string& className, const string& baseClassName){
209
if (dynlibs[className].baseClasses.find(baseClassName)!=dynlibs[className].baseClasses.end()) return true;
210
FOREACH(const string& parent,dynlibs[className].baseClasses){
211
if(isInheritingFrom_recursive(parent,baseClassName)) return true;
216
void Omega::loadPlugins(vector<string> pluginFiles){
217
FOREACH(const string& plugin, pluginFiles){
218
LOG_DEBUG("Loading plugin "<<plugin);
219
if(!ClassFactory::instance().load(plugin)){
220
string err=ClassFactory::instance().lastError();
221
if(err.find(": undefined symbol: ")!=std::string::npos){
222
size_t pos=err.rfind(":"); assert(pos!=std::string::npos);
223
std::string sym(err,pos+2); //2 removes ": " from the beginning
224
int status=0; char* demangled_sym=abi::__cxa_demangle(sym.c_str(),0,0,&status);
225
LOG_FATAL(plugin<<": undefined symbol `"<<demangled_sym<<"'"); LOG_FATAL(plugin<<": "<<err); LOG_FATAL("Bailing out.");
228
LOG_FATAL(plugin<<": "<<err<<" ."); /* leave space to not to confuse c++filt */ LOG_FATAL("Bailing out.");
233
list<string>& plugins(ClassFactory::instance().pluginClasses);
234
plugins.sort(); plugins.unique();
235
buildDynlibDatabase(vector<string>(plugins.begin(),plugins.end()));
238
void Omega::loadSimulation(const string& f, bool quiet){
239
bool isMem=algorithm::starts_with(f,":memory:");
240
if(!isMem && !filesystem::exists(f)) throw runtime_error("Simulation file to load doesn't exist: "+f);
241
if(isMem && memSavedSimulations.count(f)==0) throw runtime_error("Cannot load nonexistent memory-saved simulation "+f);
243
if(!quiet) LOG_INFO("Loading file "+f);
244
//shared_ptr<Scene> scene = getScene();
245
shared_ptr<Scene>& scene = scenes[currentSceneNb];
246
//shared_ptr<Scene>& scene = getScene();
248
stop(); // stop current simulation if running
250
RenderMutexLock lock;
252
istringstream iss(memSavedSimulations[f]);
253
yade::ObjectIO::load<typeof(scene),boost::archive::binary_iarchive>(iss,"scene",scene);
255
yade::ObjectIO::load(f,"scene",scene);
258
if(scene->getClassName()!="Scene") throw logic_error("Wrong file format (scene is not a Scene!?) in "+f);
261
if(!quiet) LOG_DEBUG("Simulation loaded");
266
void Omega::saveSimulation(const string& f, bool quiet){
267
if(f.size()==0) throw runtime_error("f of file to save has zero length.");
268
if(!quiet) LOG_INFO("Saving file " << f);
269
//shared_ptr<Scene> scene = getScene();
270
shared_ptr<Scene>& scene = scenes[currentSceneNb];
271
//shared_ptr<Scene>& scene = getScene();
272
if(algorithm::starts_with(f,":memory:")){
273
if(memSavedSimulations.count(f)>0 && !quiet) LOG_INFO("Overwriting in-memory saved simulation "<<f);
275
yade::ObjectIO::save<typeof(scene),boost::archive::binary_oarchive>(oss,"scene",scene);
276
memSavedSimulations[f]=oss.str();
279
// handles automatically the XML/binary distinction as well as gz/bz2 compression
280
yade::ObjectIO::save(f,"scene",scene);