~yade-dev/yade/0.80

« back to all changes in this revision

Viewing changes to core/Omega.cpp

  • Committer: Anton Gladky
  • Date: 2012-05-02 21:50:42 UTC
  • Revision ID: gladky.anton@gmail.com-20120502215042-v1fa9r65usqe7kfk
0.80.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*************************************************************************
 
2
*  Copyright (C) 2004 by Olivier Galizzi                                 *
 
3
*  olivier.galizzi@imag.fr                                               *
 
4
*  Copyright (C) 2004 by Janek Kozicki                                   *
 
5
*  cosurgi@berlios.de                                                    *
 
6
*                                                                        *
 
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
*************************************************************************/
 
10
 
 
11
#include"Omega.hpp"
 
12
#include"Scene.hpp"
 
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>
 
18
#include<cstdlib>
 
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>
 
26
 
 
27
#include<yade/lib/serialization/ObjectIO.hpp>
 
28
 
 
29
 
 
30
#include<cxxabi.h>
 
31
 
 
32
#if BOOST_VERSION<103500
 
33
class RenderMutexLock: public boost::try_mutex::scoped_try_lock{
 
34
        public:
 
35
        RenderMutexLock(): boost::try_mutex::scoped_try_lock(Omega::instance().renderMutex,true){/*cerr<<"Lock renderMutex"<<endl;*/}
 
36
        ~RenderMutexLock(){/* cerr<<"Unlock renderMutex"<<endl; */}
 
37
};
 
38
#else
 
39
class RenderMutexLock: public boost::mutex::scoped_lock{
 
40
        public:
 
41
        RenderMutexLock(): boost::mutex::scoped_lock(Omega::instance().renderMutex){/* cerr<<"Lock renderMutex"<<endl; */}
 
42
        ~RenderMutexLock(){/* cerr<<"Unlock renderMutex"<<endl;*/ }
 
43
};
 
44
#endif
 
45
 
 
46
CREATE_LOGGER(Omega);
 
47
SINGLETON_SELF(Omega);
 
48
 
 
49
const map<string,DynlibDescriptor>& Omega::getDynlibsDescriptor(){return dynlibs;}
 
50
 
 
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(){
 
55
        RenderMutexLock lock;
 
56
        scenes.resize(1);
 
57
        scenes[0] = shared_ptr<Scene>(new Scene);
 
58
        currentSceneNb=0;
 
59
}
 
60
int Omega::addScene(){
 
61
        scenes.push_back(shared_ptr<Scene>(new Scene));
 
62
        return scenes.size()-1;
 
63
}
 
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.");
 
67
                return;
 
68
        }
 
69
        currentSceneNb=i;
 
70
}
 
71
 
 
72
 
 
73
 
 
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;}
 
76
 
 
77
 
 
78
void Omega::initTemps(){
 
79
        char dirTemplate[]="/tmp/yade-XXXXXX";
 
80
        tmpFileDir=mkdtemp(dirTemplate);
 
81
        tmpFileCounter=0;
 
82
}
 
83
 
 
84
void Omega::cleanupTemps(){
 
85
        filesystem::path tmpPath(tmpFileDir);
 
86
        filesystem::remove_all(tmpPath);
 
87
}
 
88
 
 
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++);
 
93
}
 
94
 
 
95
void Omega::reset(){
 
96
        stop();
 
97
        init();
 
98
}
 
99
 
 
100
void Omega::init(){
 
101
        sceneFile="";
 
102
        //resetScene();
 
103
        resetAllScenes();
 
104
        sceneAnother=shared_ptr<Scene>(new Scene);
 
105
        timeInit();
 
106
        createSimulationLoop();
 
107
}
 
108
 
 
109
void Omega::timeInit(){
 
110
        startupLocalTime=microsec_clock::local_time();
 
111
}
 
112
 
 
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>(); }
 
115
 
 
116
/* WARNING: even a single simulation step is run asynchronously; the call will return before the iteration is finished. */
 
117
void Omega::step(){
 
118
        if (simulationLoop){
 
119
                simulationLoop->spawnSingleAction();
 
120
        }
 
121
}
 
122
 
 
123
void Omega::run(){
 
124
        if(!simulationLoop){ LOG_ERROR("No Omega::simulationLoop? Creating one (please report bug)."); createSimulationLoop(); }
 
125
        if (simulationLoop && !simulationLoop->looping()){
 
126
                simulationLoop->start();
 
127
        }
 
128
}
 
129
 
 
130
 
 
131
void Omega::pause(){
 
132
        if (simulationLoop && simulationLoop->looping()){
 
133
                simulationLoop->stop();
 
134
        }
 
135
}
 
136
 
 
137
bool Omega::isRunning(){ if(simulationLoop) return simulationLoop->looping(); else return false; }
 
138
 
 
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;
 
145
                try {
 
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));
 
153
                        }
 
154
                        if(dynlibs[name].isSerializable) pythonables.push_back(name);
 
155
                }
 
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; */      
 
159
                }
 
160
        }
 
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));
 
171
                        try{
 
172
                                if(getenv("YADE_DEBUG")) cerr<<"{{"<<*I<<"}}";
 
173
                                s->pyRegisterClass(wrapperScope);
 
174
                                std::list<string>::iterator prev=I++;
 
175
                                pythonables.erase(prev);
 
176
                        } catch (...){
 
177
                                if(getenv("YADE_DEBUG")){ cerr<<"["<<*I<<"]"; PyErr_Print(); }
 
178
                                boost::python::handle_exception();
 
179
                                I++;
 
180
                        }
 
181
                }
 
182
        }
 
183
 
 
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){
 
190
                        string name = *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));
 
198
                        }
 
199
                }
 
200
        }
 
201
}
 
202
 
 
203
 
 
204
bool Omega::isInheritingFrom(const string& className, const string& baseClassName){
 
205
        return (dynlibs[className].baseClasses.find(baseClassName)!=dynlibs[className].baseClasses.end());
 
206
}
 
207
 
 
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;
 
212
        }
 
213
        return false;
 
214
}
 
215
 
 
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.");
 
226
                        }
 
227
                        else {
 
228
                                LOG_FATAL(plugin<<": "<<err<<" ."); /* leave space to not to confuse c++filt */ LOG_FATAL("Bailing out.");
 
229
                        }
 
230
                        abort();
 
231
                }
 
232
        }
 
233
        list<string>& plugins(ClassFactory::instance().pluginClasses);
 
234
        plugins.sort(); plugins.unique();
 
235
        buildDynlibDatabase(vector<string>(plugins.begin(),plugins.end()));
 
236
}
 
237
 
 
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);
 
242
        
 
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();
 
247
        {
 
248
                stop(); // stop current simulation if running
 
249
                resetScene();
 
250
                RenderMutexLock lock;
 
251
                if(isMem){
 
252
                        istringstream iss(memSavedSimulations[f]);
 
253
                        yade::ObjectIO::load<typeof(scene),boost::archive::binary_iarchive>(iss,"scene",scene);
 
254
                } else {
 
255
                        yade::ObjectIO::load(f,"scene",scene);
 
256
                }
 
257
        }
 
258
        if(scene->getClassName()!="Scene") throw logic_error("Wrong file format (scene is not a Scene!?) in "+f);
 
259
        sceneFile=f;
 
260
        timeInit();
 
261
        if(!quiet) LOG_DEBUG("Simulation loaded");
 
262
}
 
263
 
 
264
 
 
265
 
 
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);
 
274
                ostringstream oss;
 
275
                yade::ObjectIO::save<typeof(scene),boost::archive::binary_oarchive>(oss,"scene",scene);
 
276
                memSavedSimulations[f]=oss.str();
 
277
        }
 
278
        else {
 
279
                // handles automatically the XML/binary distinction as well as gz/bz2 compression
 
280
                yade::ObjectIO::save(f,"scene",scene); 
 
281
        }
 
282
        sceneFile=f;
 
283
}
 
284
 
 
285
 
 
286
 
 
287