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