Skip to content
This repository was archived by the owner on Nov 3, 2022. It is now read-only.

Commit 32c3fc7

Browse files
author
Dilawar Singh
committed
Finfo is also vectorised.
1 parent d716124 commit 32c3fc7

File tree

9 files changed

+295
-36
lines changed

9 files changed

+295
-36
lines changed

pybind11/Finfo.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace py = pybind11;
2525
#include "Finfo.h"
2626

2727
__Finfo__::__Finfo__(const ObjId& oid, const Finfo* f, const string& finfoType)
28-
: oid_(oid), f_(f), finfoType_(finfoType)
28+
: oid_(oid), f_(f), finfoType_(finfoType), pVec_(nullptr)
2929
{
3030
if(finfoType == "DestFinfo")
3131
func_ = [oid, f](const py::object& key) {
@@ -127,7 +127,7 @@ py::object __Finfo__::getItem(const py::object& key)
127127

128128
py::object __Finfo__::operator()(const py::object& key)
129129
{
130-
return func_(key);
130+
return getItem(key);
131131
}
132132

133133
py::cpp_function __Finfo__::getDestFinfoSetterFunc(const ObjId& oid,
@@ -311,3 +311,17 @@ ObjId __Finfo__::getObjId() const
311311
{
312312
return ObjId(oid_.path() + '/' + f_->name());
313313
}
314+
315+
// Return by copy.
316+
MooseVec __Finfo__::getMooseVec()
317+
{
318+
return MooseVec(getObjId());
319+
}
320+
321+
MooseVec* __Finfo__::getMooseVecPtr()
322+
{
323+
if(! pVec_)
324+
pVec_.reset(new MooseVec(getObjId()));
325+
return pVec_.get();
326+
}
327+

pybind11/Finfo.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#ifndef FINFO_H
1111
#define FINFO_H
1212

13+
class MooseVec;
14+
1315
class __Finfo__ {
1416
public:
1517
__Finfo__(const ObjId& oid, const Finfo* f, const string& finfoType);
@@ -105,6 +107,12 @@ class __Finfo__ {
105107

106108
string type() const;
107109

110+
// Return a MooseVec element (copy).
111+
MooseVec getMooseVec();
112+
113+
// Retun by pointer.
114+
MooseVec* getMooseVecPtr();
115+
108116
// Finfo Id.
109117
static ObjId getObjIdStatic(const ObjId& oid, const Finfo* f);
110118
ObjId getObjId() const;
@@ -114,6 +122,9 @@ class __Finfo__ {
114122
const Finfo* f_;
115123
const std::string finfoType_;
116124
std::function<py::object(const py::object& key)> func_;
125+
126+
// __Finfo__ needs to be copiable.
127+
shared_ptr<MooseVec> pVec_;
117128
};
118129

119130
#endif /* end of include guard: FINFO_H */

pybind11/MooseVec.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,28 @@ ObjId MooseVec::getItem(const int index) const
8787
return getDataItem(i);
8888
}
8989

90+
vector<ObjId> MooseVec::getItemRange(const py::slice& slice) const
91+
{
92+
vector<ObjId> res;
93+
int start=0, step=1, stop = size();
94+
95+
py::object pstart = slice.attr("start");
96+
if(! pstart.is(py::none()))
97+
start = pstart.cast<int>();
98+
99+
py::object pstop = slice.attr("stop");
100+
if(! pstop.is(py::none()))
101+
stop = pstop.cast<int>();
102+
103+
py::object pstep = slice.attr("step");
104+
if(! pstep.is(py::none()))
105+
step = pstep.cast<int>();
106+
107+
for (int i = start; i < stop; i += step)
108+
res.push_back(getItem(i));
109+
return res;
110+
}
111+
90112
ObjId MooseVec::getDataItem(const size_t i) const
91113
{
92114
return ObjId(oid_.path(), i, oid_.fieldIndex);

pybind11/MooseVec.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class MooseVec
4545
// Get vector element. Vector element could be `dataIndex` or `fieldIndex`.
4646
// Allows negative indexing.
4747
ObjId getItem(const int i) const;
48+
vector<ObjId> getItemRange(const py::slice& slice) const;
4849

4950
ObjId getDataItem(const size_t i) const;
5051
ObjId getFieldItem(const size_t i) const;
@@ -140,6 +141,7 @@ class MooseVec
140141

141142
// Get attributes.
142143
py::object getAttribute(const string& key);
144+
bool setAttribute(const string& name, const py::object& val);
143145

144146
vector<ObjId> objs() const;
145147

pybind11/pymoose.cpp

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -135,19 +135,20 @@ py::object getFieldGeneric(const ObjId &oid, const string &fieldName)
135135

136136
string finfoType = cinfo->getFinfoType(finfo);
137137

138-
// Either return a simple value (ValueFinfo), list, dict or DestFinfo
139-
// setter.
140-
// The DestFinfo setter is a function.
141-
138+
// Things are very compilcated here. There return object from this function
139+
// can be of different types: a simple value (ValueFinfo), list, dict or
140+
// DestFinfo setter which is a function.
142141
if(finfoType == "ValueFinfo")
143142
return __Finfo__::getFieldValue(oid, finfo);
144143
else if(finfoType == "FieldElementFinfo") {
144+
// This is a Finfo
145145
return py::cast(__Finfo__(oid, finfo, "FieldElementFinfo"));
146146
} else if(finfoType == "LookupValueFinfo") {
147-
// Return function.
147+
// This is a function.
148148
return py::cast(__Finfo__(oid, finfo, "LookupValueFinfo"));
149149
} else if(finfoType == "DestFinfo") {
150-
// Return a setter function. It can be used to set field on DestFinfo.
150+
// Return a setter function.
151+
// It can be used to set field on DestFinfo.
151152
return __Finfo__::getDestFinfoSetterFunc(oid, finfo);
152153
}
153154

@@ -157,7 +158,6 @@ py::object getFieldGeneric(const ObjId &oid, const string &fieldName)
157158
return pybind11::none();
158159
}
159160

160-
161161
/* --------------------------------------------------------------------------*/
162162
/**
163163
* @Synopsis MOOSE extension module _moose.so.
@@ -174,20 +174,14 @@ PYBIND11_MODULE(_moose, m)
174174

175175
initModule(m);
176176

177-
py::object melement;
178-
179-
// A thin wrapper around Id from ../basecode/Id.h . Usually this is shows
180-
// at moose.vec.
181-
py::class_<Id>(m, "mid")
177+
// A thin wrapper around Id from ../basecode/Id.h .
178+
py::class_<Id>(m, "__id__")
182179
.def(py::init<>())
183180
.def(py::init<unsigned int>())
184181
.def(py::init<const string &>())
185182
.def(py::init<const ObjId &>())
186183
// properties
187184
.def_property_readonly("numIds", &Id::numIds)
188-
// FIXME/NB: Don't expose path. Note that Stoich as `path` attribute
189-
// which
190-
// will not work if this is exposed.
191185
.def_property_readonly("path", &Id::path)
192186
.def_property_readonly(
193187
"name", [](const Id &id) { return id.element()->getName(); })
@@ -208,6 +202,8 @@ PYBIND11_MODULE(_moose, m)
208202
.def("__eq__", [](const Id &a, const Id &b) { return a == b; })
209203
.def("__ne__", [](const Id &a, const Id &b) { return a != b; })
210204
.def("__hash__", &Id::value)
205+
206+
// Id attributes are same as ObjItem attributes.
211207
.def("__getattr__", [](const Id &id, const string &key) {
212208
return getFieldGeneric(ObjId(id), key);
213209
})
@@ -216,32 +212,32 @@ PYBIND11_MODULE(_moose, m)
216212
return setFieldGeneric(ObjId(id), key, val);
217213
});
218214

219-
220215
// This is a wrapper around Field::get and LookupField::get which may
221216
// return simple values or vector. Python scripts expect LookupField to
222217
// return either list of dict which can be queried by key and index. This
223218
// class bind both __getitem__ to the getter function call.
224219
// Note that both a.isA["Compartment"] and a.isA("Compartment") are valid
225220
// now.
226-
py::class_<__Finfo__>(m, "Field", py::dynamic_attr())
221+
py::class_<__Finfo__>(m, "__Field__", py::dynamic_attr())
227222
.def(py::init<const ObjId &, const Finfo *, const char *>())
228223
.def_property_readonly("type", &__Finfo__::type)
229-
.def_property_readonly("vec", [](const __Finfo__ &finfo) {
230-
return MooseVec(finfo.getObjId());
231-
})
232-
.def_property("num", &__Finfo__::getNumField,
233-
&__Finfo__::setNumField) // Only for FieldElementFinfos
234-
.def("__call__", &__Finfo__::operator())
224+
.def_property("num", &__Finfo__::getNumField, &__Finfo__::setNumField)
225+
.def_property_readonly(
226+
"vec", [](__Finfo__ &finfo) { return finfo.getMooseVecPtr(); },
227+
py::return_value_policy::reference_internal)
228+
229+
// Only for FieldElementFinfos
230+
.def("__len__", &__Finfo__::getNumField)
235231
.def("__call__", &__Finfo__::operator())
236232
.def("__getitem__", &__Finfo__::getItem)
237233
.def("__setitem__", &__Finfo__::setItem)
238-
.def("__len__", &__Finfo__::getNumField);
234+
;
239235

240236
/**
241237
* @name ObjId. It is a base of all other moose objects.
242238
* @{ */
243239
/** @} */
244-
py::class_<ObjId>(m, "ObjId", py::metaclass(melement))
240+
py::class_<ObjId>(m, "melement")
245241
.def(py::init<>())
246242
.def(py::init<Id>())
247243
.def(py::init<Id, unsigned int>())
@@ -311,14 +307,15 @@ PYBIND11_MODULE(_moose, m)
311307
py::class_<Variable>(m, "_Variable").def(py::init<>());
312308

313309
// Cinfo.
314-
py::class_<Cinfo>(m, "_Cinfo")
310+
py::class_<Cinfo>(m, "__Cinfo__")
315311
.def(py::init<>())
316312
.def_property_readonly("name", &Cinfo::name)
317313
.def_property_readonly("finfoMap", &Cinfo::finfoMap,
318-
py::return_value_policy::reference)
314+
py::return_value_policy::reference_internal)
319315
// .def("findFinfo", &Cinfo::findFinfoWrapper)
320-
.def("baseCinfo", &Cinfo::baseCinfo, py::return_value_policy::reference)
321-
.def("isA", &Cinfo::isA);
316+
.def("baseCinfo", &Cinfo::baseCinfo,
317+
py::return_value_policy::reference_internal)
318+
.def("isA", &Cinfo::isA, py::return_value_policy::reference_internal);
322319

323320
// Vec class.
324321
py::class_<MooseVec>(m, "vec")
@@ -338,9 +335,10 @@ PYBIND11_MODULE(_moose, m)
338335
return py::make_iterator(v.objref().begin(), v.objref().end());
339336
},
340337
py::keep_alive<0, 1>())
338+
341339
.def("__getitem__", &MooseVec::getItem)
342-
// Beware of pybind11 overload resolution order:
343-
// https://pybind11.readthedocs.io/en/stable/advanced/functions.html#overload-resolution-order
340+
.def("__getitem__", &MooseVec::getItemRange)
341+
344342
// Templated function won't work here. The first one is always called.
345343
.def("__getattr__", &MooseVec::getAttribute)
346344
.def("__setattr__", &MooseVec::setAttrOneToOne<double>)

python/moose/moose.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
# etc.
2020
__class_types__ = {}
2121

22-
class PyObjId(_moose.ObjId):
22+
class PyObjId(_moose.melement):
2323

2424
__class__ = 'Unknown'
2525

tests/py_moose/test_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def test_children():
2929
assert ax1 == a11
3030
assert a11.isA['Neutral'], a11.isA
3131
assert ax1.isA['Neutral'], a11.isA
32+
print("test_children is done")
3233

3334

3435
def test_other():
@@ -66,8 +67,7 @@ def test_finfos():
6667
assert s.numSynapses == 10
6768

6869
syns = s.synapse.vec
69-
70-
print(s.synapse)
70+
print(s.synapse, '111')
7171
s8a = s.synapse[8]
7272
s8b = s.synapse[-2]
7373
assert s8a == s8b, (s8a, s8b)
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# -*- coding: utf-8 -*-
2+
#########################################################################
3+
## This program is part of 'MOOSE', the
4+
## Messaging Object Oriented Simulation Environment.
5+
## Copyright (C) 2013 Upinder S. Bhalla. and NCBS
6+
## It is made available under the terms of the
7+
## GNU Lesser General Public License version 2.1
8+
## See the file COPYING.LIB for the full notice.
9+
#########################################################################
10+
11+
import numpy
12+
import moose
13+
14+
useY = False
15+
16+
def makeModel():
17+
# create container for model
18+
moose.Neutral( 'model' )
19+
compartment = moose.CubeMesh( '/model/compartment' )
20+
compartment.volume = 1e-15
21+
# the mesh is created automatically by the compartment
22+
moose.element( '/model/compartment/mesh' )
23+
24+
# create molecules and reactions
25+
# a <----> b
26+
# b + 10c ---func---> d
27+
a = moose.Pool( '/model/compartment/a' )
28+
b = moose.Pool( '/model/compartment/b' )
29+
c = moose.Pool( '/model/compartment/c' )
30+
d = moose.BufPool( '/model/compartment/d' )
31+
reac = moose.Reac( '/model/compartment/reac' )
32+
func = moose.Function( '/model/compartment/d/func' )
33+
func.numVars = 2
34+
#func.x.num = 2
35+
36+
# connect them up for reactions
37+
38+
moose.connect( reac, 'sub', a, 'reac' )
39+
moose.connect( reac, 'prd', b, 'reac' )
40+
if useY:
41+
moose.connect( func, 'requestOut', b, 'getN' )
42+
moose.connect( func, 'requestOut', c, 'getN' )
43+
else:
44+
moose.connect( b, 'nOut', func.x[0], 'input' )
45+
moose.connect( c, 'nOut', func.x[1], 'input' )
46+
47+
moose.connect( func, 'valueOut', d, 'setN' )
48+
if useY:
49+
func.expr = "y0 + 10*y1"
50+
else:
51+
func.expr = "x0 + 10*x1"
52+
53+
# connect them up to the compartment for volumes
54+
#for x in ( a, b, c, cplx1, cplx2 ):
55+
# moose.connect( x, 'mesh', mesh, 'mesh' )
56+
57+
# Assign parameters
58+
a.concInit = 1
59+
b.concInit = 0.5
60+
c.concInit = 0.1
61+
reac.Kf = 0.001
62+
reac.Kb = 0.01
63+
64+
# Create the output tables
65+
moose.Neutral( '/model/graphs' )
66+
outputA = moose.Table2 ( '/model/graphs/concA' )
67+
outputB = moose.Table2 ( '/model/graphs/concB' )
68+
outputC = moose.Table2 ( '/model/graphs/concC' )
69+
outputD = moose.Table2 ( '/model/graphs/concD' )
70+
71+
# connect up the tables
72+
moose.connect( outputA, 'requestOut', a, 'getConc' );
73+
moose.connect( outputB, 'requestOut', b, 'getConc' );
74+
moose.connect( outputC, 'requestOut', c, 'getConc' );
75+
moose.connect( outputD, 'requestOut', d, 'getConc' );
76+
77+
def test_func_change_expr():
78+
makeModel()
79+
ksolve = moose.Ksolve( '/model/compartment/ksolve' )
80+
stoich = moose.Stoich( '/model/compartment/stoich' )
81+
stoich.compartment = moose.element( '/model/compartment' )
82+
stoich.ksolve = ksolve
83+
stoich.path = "/model/compartment/##"
84+
moose.reinit()
85+
moose.start( 100.0 )
86+
func = moose.element( '/model/compartment/d/func' )
87+
if useY:
88+
func.expr = "-y0 + 10*y1"
89+
else:
90+
func.expr = "-x0 + 10*x1"
91+
moose.start( 100.0 )
92+
b = moose.element('/model/compartment/b')
93+
assert int(b.n) == int(106384558.57472235), b.n
94+
xs = func.x.vec
95+
assert len(xs.value) == 2, (len(xs.value), xs.value)
96+
assert (xs.value == [0, 0]).all(), xs.value
97+
98+
if __name__ == '__main__':
99+
test_func_change_expr()

0 commit comments

Comments
 (0)