1 /******************************************************************************
2  *
3  * MantaFlow fluid solver framework
4  * Copyright 2011 Tobias Pfaff, Nils Thuerey
5  *
6  * This program is free software, distributed under the terms of the
7  * Apache License, Version 2.0
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Functions for property setting/getting via python
11  *
12  ******************************************************************************/
13 
14 #include "pythonInclude.h"
15 #include "structmember.h"
16 #include "manta.h"
17 #include "general.h"
18 #include "timing.h"
19 
20 #ifdef GUI
21 #  include <QMutex>
22 #else
23 class QMutex {
24  public:
lock()25   void lock(){};
unlock()26   void unlock(){};
tryLock()27   bool tryLock()
28   {
29     return true;
30   };
31 };
32 #endif
33 
34 using namespace std;
35 namespace Manta {
36 
37 //******************************************************************************
38 // Free functions
39 
pbPreparePlugin(FluidSolver * parent,const string & name,bool doTime)40 void pbPreparePlugin(FluidSolver *parent, const string &name, bool doTime)
41 {
42   if (doTime)
43     TimingData::instance().start(parent, name);
44 }
45 
pbFinalizePlugin(FluidSolver * parent,const string & name,bool doTime)46 void pbFinalizePlugin(FluidSolver *parent, const string &name, bool doTime)
47 {
48   if (doTime)
49     TimingData::instance().stop(parent, name);
50 
51   // GUI update, also print name of parent if there's more than one
52   std::ostringstream msg;
53   if (name != "FluidSolver::step") {
54     if (parent && (parent->getNumInstances() > 0))
55       msg << parent->getName() << string(".");
56     msg << name;
57   }
58   updateQtGui(false, 0, 0., msg.str());
59 
60   debMsg(name << " done", 3);
61   // name unnamed PbClass Objects from var name
62   PbClass::renameObjects();
63 }
64 
pbSetError(const string & fn,const string & ex)65 void pbSetError(const string &fn, const string &ex)
66 {
67   debMsg("Error in " << fn, 1);
68   if (!ex.empty())
69     PyErr_SetString(PyExc_RuntimeError, ex.c_str());
70 }
71 
72 //******************************************************************************
73 // Helpers
74 
str() const75 string PbTypeVec::str() const
76 {
77   if (T.empty())
78     return "";
79   string s = "<";
80   for (int i = 0; i < (int)T.size(); i++) {
81     s += T[i].str();
82     s += (i != (int)T.size() - 1) ? ',' : '>';
83   }
84   return s;
85 }
str() const86 string PbType::str() const
87 {
88   if (S == "float")
89     return "Real";
90   if (S == "manta.vec3")
91     return "Vec3";
92   return S;
93 }
94 
95 //******************************************************************************
96 // PbClass
97 
98 vector<PbClass *> PbClass::mInstances;
99 
PbClass(FluidSolver * parent,const string & name,PyObject * obj)100 PbClass::PbClass(FluidSolver *parent, const string &name, PyObject *obj)
101     : mMutex(NULL), mParent(parent), mPyObject(obj), mName(name), mHidden(false)
102 {
103   mMutex = new QMutex();
104 }
105 
PbClass(const PbClass & a)106 PbClass::PbClass(const PbClass &a)
107     : mMutex(NULL), mParent(a.mParent), mPyObject(0), mName("_unnamed"), mHidden(false)
108 {
109   mMutex = new QMutex();
110 }
111 
~PbClass()112 PbClass::~PbClass()
113 {
114   for (vector<PbClass *>::iterator it = mInstances.begin(); it != mInstances.end(); ++it) {
115     if (*it == this) {
116       mInstances.erase(it);
117       break;
118     }
119   }
120   delete mMutex;
121 }
122 
lock()123 void PbClass::lock()
124 {
125   mMutex->lock();
126 }
unlock()127 void PbClass::unlock()
128 {
129   mMutex->unlock();
130 }
tryLock()131 bool PbClass::tryLock()
132 {
133   return mMutex->tryLock();
134 }
135 
getInstance(int idx)136 PbClass *PbClass::getInstance(int idx)
137 {
138   if (idx < 0 || idx > (int)mInstances.size())
139     errMsg("PbClass::getInstance(): invalid index");
140   return mInstances[idx];
141 }
142 
getNumInstances()143 int PbClass::getNumInstances()
144 {
145   return mInstances.size();
146 }
147 
isNullRef(PyObject * obj)148 bool PbClass::isNullRef(PyObject *obj)
149 {
150   return PyLong_Check(obj) && PyLong_AsDouble(obj) == 0;
151 }
152 
isNoneRef(PyObject * obj)153 bool PbClass::isNoneRef(PyObject *obj)
154 {
155   return (obj == Py_None);
156 }
157 
registerObject(PyObject * obj,PbArgs * args)158 void PbClass::registerObject(PyObject *obj, PbArgs *args)
159 {
160   // cross link
161   Pb::setReference(this, obj);
162   mPyObject = obj;
163 
164   mInstances.push_back(this);
165 
166   if (args) {
167     string _name = args->getOpt<std::string>("name", -1, "");
168     if (!_name.empty())
169       setName(_name);
170   }
171 }
172 
createPyObject(const string & classname,const string & name,PbArgs & args,PbClass * parent)173 PbClass *PbClass::createPyObject(const string &classname,
174                                  const string &name,
175                                  PbArgs &args,
176                                  PbClass *parent)
177 {
178   return Pb::createPy(classname, name, args, parent);
179 }
180 
checkParent()181 void PbClass::checkParent()
182 {
183   if (getParent() == NULL) {
184     errMsg("New class " + mName + ": no parent given -- specify using parent=xxx !");
185   }
186 }
187 //! Assign unnamed PbClass objects their Python variable name
renameObjects()188 void PbClass::renameObjects()
189 {
190   PyObject *sys_mod_dict = PyImport_GetModuleDict();
191   PyObject *loc_mod = PyMapping_GetItemString(sys_mod_dict, (char *)"__main__");
192   if (!loc_mod)
193     return;
194   PyObject *locdict = PyObject_GetAttrString(loc_mod, "__dict__");
195   if (!locdict)
196     return;
197 
198   // iterate all PbClass instances
199   for (size_t i = 0; i < mInstances.size(); i++) {
200     PbClass *obj = mInstances[i];
201     if (obj->getName().empty()) {
202       // empty, try to find instance in module local dictionary
203 
204       PyObject *lkey, *lvalue;
205       Py_ssize_t lpos = 0;
206       while (PyDict_Next(locdict, &lpos, &lkey, &lvalue)) {
207         if (lvalue == obj->mPyObject) {
208           string varName = fromPy<string>(PyObject_Str(lkey));
209           obj->setName(varName);
210           // cout << "assigning variable name '" << varName << "' to unnamed instance" << endl;
211           break;
212         }
213       }
214     }
215   }
216   Py_DECREF(locdict);
217   Py_DECREF(loc_mod);
218 }
219 
220 }  // namespace Manta
221