MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
vec.cpp
Go to the documentation of this file.
1 // vec.cpp ---
2 //
3 // Filename: vec.cpp
4 // Description:
5 // Author:
6 // Maintainer:
7 // Created: Mon Jul 22 16:46:37 2013 (+0530)
8 // Version:
9 // Last-Updated: Fri Sep 25 23:00:48 2015 (-0400)
10 // By: subha
11 // Update #: 80
12 // URL:
13 // Keywords:
14 // Compatibility:
15 //
16 //
17 
18 // Commentary:
19 //
20 //
21 //
22 //
23 
24 // Change log:
25 //
26 // Mon Jul 22 16:47:10 IST 2013 - Splitting contents of
27 // moosemodule.cpp into speparate files.
28 //
29 //c
30 // This program is free software; you can redistribute it and/or
31 // modify it under the terms of the GNU General Public License as
32 // published by the Free Software Foundation; either version 3, or
33 // (at your option) any later version.
34 //
35 // This program is distributed in the hope that it will be useful,
36 // but WITHOUT ANY WARRANTY; without even the implied warranty of
37 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38 // General Public License for more details.
39 //
40 // You should have received a copy of the GNU General Public License
41 // along with this program; see the file COPYING. If not, write to
42 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth
43 // Floor, Boston, MA 02110-1301, USA.
44 //
45 //
46 
47 // Code:
48 
49 #include <Python.h>
50 #include <structmember.h> // This defines the type id macros like T_STRING
51 // #include "numpy/arrayobject.h"
52 
53 #include "../utility/simple_logger.hpp"
54 
55 #include <iostream>
56 #include <typeinfo>
57 #include <cstring>
58 #include <map>
59 #include <ctime>
60 
61 #ifdef USE_MPI
62 #include <mpi.h>
63 #endif
64 
65 #include "../basecode/header.h"
66 #include "../basecode/global.h"
67 #include "../basecode/Id.h"
68 #include "../basecode/ObjId.h"
69 #include "../utility/utility.h"
70 #include "../shell/Shell.h"
71 #include "../shell/Wildcard.h"
72 
73 #include "moosemodule.h"
74 
75 using namespace std;
76 
77 extern int verbosity;
78 
80 // Python method lists for PyObject of Id
82 PyDoc_STRVAR(moose_Id_delete_doc,
83  "vec.delete() -> None"
84  "\n"
85  "\nDelete the underlying moose object. This will invalidate all"
86  "\nreferences to this object and any attempt to access it will raise a"
87  "\nValueError."
88  "\n Example"
89  "\n--------"
90  "\n >>>iaf.delete()"
91  "\n >>>print iaf.path"
92  "\n \\ "
93  "\n");
94 
95 PyDoc_STRVAR(moose_Id_setField_doc,
96  "setField(fieldname, value_vector) -> None\n"
97  "\n"
98  "Set the value of `fieldname` in all elements under this vec.\n"
99  "\n"
100  "Parameters\n"
101  "----------\n"
102  "fieldname: str\n"
103  " field to be set.\n"
104  "value: sequence of values\n"
105  " sequence of values corresponding to individual elements"
106  " under this vec.\n"
107  "\n Example"
108  "\n--------"
109  "\n >>> iaf.setField('Vm', 20)"
110  "\n >>> print iaf.Vm"
111  "\n [ 20. 20. 20. 20. 20. 20. 20. 20. 20. 20.]"
112  "\n >>> iaf.setField('Vm', (1, 2, 3, 4, 5, 6, 7, 8, 9, 10))"
113  "\n >>> print iaf.Vm"
114  "\n [ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]"
115  "Notes\n"
116  "-----\n"
117  " This is an interface to SetGet::setVec"
118  "\n");
119 
120 static PyMethodDef IdMethods[] =
121 {
122  // {"init", (PyCFunction)moose_Id_init, METH_VARARGS,
123  // "Initialize a Id object."},
124  {
125  "delete", (PyCFunction)moose_Id_delete, METH_NOARGS,
126  moose_Id_delete_doc
127  },
128  {
129  "getValue", (PyCFunction)moose_Id_getValue, METH_NOARGS,
130  "Returns integer representation of the id of the element."
131  },
132  {
133  "getPath", (PyCFunction)moose_Id_getPath, METH_NOARGS,
134  "Returns the path of this vec object."
135  },
136  {
137  "getShape", (PyCFunction)moose_Id_getShape, METH_NOARGS,
138  "Returns the shape of the vec object as a tuple."
139  },
140  {
141  "setField", (PyCFunction)moose_Id_setField, METH_VARARGS,
142  moose_Id_setField_doc
143  },
144  {NULL, NULL, 0, NULL}, /* Sentinel */
145 };
146 
147 static PySequenceMethods IdSequenceMethods =
148 {
149  (lenfunc)moose_Id_getLength, // sq_length
150  0, //sq_concat
151  0, //sq_repeat
152  (ssizeargfunc)moose_Id_getItem, //sq_item
153 #ifndef PY3K
154  (ssizessizeargfunc)moose_Id_getSlice, // getslice
155 #else
156  0,
157 #endif
158  0, //sq_ass_item
159  0, // setslice
160  (objobjproc)moose_Id_contains, // sq_contains
161  0, // sq_inplace_concat
162  0 // sq_inplace_repeat
163 };
164 
165 static PyMappingMethods IdMappingMethods =
166 {
167  (lenfunc)moose_Id_getLength, //mp_length
168  (binaryfunc)moose_Id_subscript, // mp_subscript
169  0 // mp_ass_subscript
170 };
171 
173 // Type defs for PyObject of Id
175 
176 PyDoc_STRVAR(moose_Id_doc,
177  "An object uniquely identifying a moose array-element.\n"
178  "\n"
179  "array-elements are array-like objects which can have one or more"
180  " single-elements within them."
181  " vec can be traversed like a Python sequence and its each item is an"
182  " element identifying single-objects contained in the array element.\n"
183  "\n"
184  "you can create multiple references to the same MOOSE object in Python."
185  " As long as they have the same path/id value, they all point to"
186  " the same entity in MOOSE.\n"
187  "\n"
188  "Field access are vectorized. For example, if `comp` is a vec of"
189  " Compartments (of size 10), which has a field called `Vm` as membrane voltage, then"
190  " `comp.Vm` returns a"
191  " tuple containing the `Vm` value of all 10 single-elements in this"
192  " vec. There are a few special fields that are unique for vec and are not"
193  " vectorized. These are `path`, `name`, `value`, `shape` and `className`."
194  " There are two ways an vec can be initialized, \n"
195  "(1) create a new array element or \n"
196  "(2) create a reference to an existing object.\n"
197  "\n"
198  "\n Constructor:"
199  "\n"
200  "\n vec(self, path=path, n=size, g=isGlobal, dtype=className)"
201  "\n "
202  "\n "
203  "\n Parameters"
204  "\n ----------"
205  "\n path : str/vec/int "
206  "\n Path of an existing array element or for creating a new one. This has"
207  "\n the same format as unix file path: /{element1}/{element2} ... "
208  "\n If there is no object with the specified path, moose attempts to create "
209  "\n a new array element. For that to succeed everything until the last `/`"
210  "\n character must exist or an error is raised"
211  "\n"
212  "\n Alternatively, path can be vec or integer value of the Id of an"
213  "\n existing vec object. The new object will be another reference to"
214  "\n the existing object."
215  "\n "
216  "\n n : positive int"
217  "\n This is a positive integers specifying the size of the array element"
218  "\n to be created. Thus n=2 will create an vec with 2 elements."
219  "\n "
220  "\n g : int"
221  "\n Specify if this is a global or local element. Global elements are"
222  "\n shared between nodes in a computing cluster."
223  "\n "
224  "\n dtype: string"
225  "\n The vector will be of this moose-class."
226  "\n "
227  "\n Attributes:"
228  "\n -----------"
229  "\n path : str"
230  "\n Path of the vec. In moose vecs are organized in a tree structure"
231  " like unix file system and the paths follow the same convention."
232  "\n"
233  "\n name : str"
234  "\n Name of the vec."
235  "\n"
236  "\n value : int/long"
237  "\n Numeric identifier of the vec. This is unique within a single"
238  " execution. vec comparison is based on this value and its hash is also"
239  " this. So you can compare and sort vecs and use them as dict keys."
240  "\n"
241  "\n shape : tuple of ints"
242  "\n Dimensions of the vec (as shape in numpy.ndarray). Currently only"
243  " one-dimensional vecs are implemented."
244  "\n"
245  "\n className: str"
246  "\n The class of the moose object this vec contains. MOOSE core"
247  " implements its own class system independent of Python. pymoose creates"
248  " thin wrappers around them. This field provides you the moose class"
249  " name as defined in C++"
250  "\n"
251  "\n "
252  "\n Examples"
253  "\n ---------"
254  "\n >>> iaf = moose.vec('/iaf', n=10, dtype='IntFire')"
255  "\n >>> iaf.Vm = range(10)"
256  "\n >>> print iaf[5].Vm"
257  "\n 5.0"
258  "\n >>> print iaf.Vm"
259  "\n array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])"
260  );
261 
262 PyTypeObject IdType =
263 {
264  PyVarObject_HEAD_INIT(NULL, 0) /* tp_head */
265  "moose.vec", /* tp_name */
266  sizeof(_Id), /* tp_basicsize */
267  0, /* tp_itemsize */
268  0, /* tp_dealloc */
269  0, /* tp_print */
270  0, /* tp_getattr */
271  0, /* tp_setattr */
272  0, /* tp_compare */
273  (reprfunc)moose_Id_repr, /* tp_repr */
274  0, /* tp_as_number */
275  &IdSequenceMethods, /* tp_as_sequence */
276  &IdMappingMethods, /* tp_as_mapping */
277  (hashfunc)moose_Id_hash, /* tp_hash */
278  0, /* tp_call */
279  (reprfunc)moose_Id_str, /* tp_str */
280  (getattrofunc)moose_Id_getattro, /* tp_getattro */
281  (setattrofunc)moose_Id_setattro, /* tp_setattro */
282  0, /* tp_as_buffer */
283  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
284  moose_Id_doc,
285  0, /* tp_traverse */
286  0, /* tp_clear */
287  (richcmpfunc)moose_Id_richCompare, /* tp_richcompare */
288  0, /* tp_weaklistoffset */
289  0, /* tp_iter */
290  0, /* tp_iternext */
291  IdMethods, /* tp_methods */
292  0, /* tp_members */
293  0, /* tp_getset */
294  0, /* tp_base */
295  0, /* tp_dict */
296  0, /* tp_descr_get */
297  0, /* tp_descr_set */
298  0, /* tp_dictoffset */
299  (initproc) moose_Id_init, /* tp_init */
300  0, /* tp_alloc */
301  0, /* tp_new */
302  0, /* tp_free */
303 };
304 
305 
306 extern PyTypeObject ObjIdType;
307 
309 // Id functions
311 
312 PyObject* get_Id_attr(_Id * id, string attribute)
313 {
314  if (attribute == "path")
315  {
316  return moose_Id_getPath(id);
317  }
318  else if (attribute == "name")
319  {
320  string name = Field<string>::get(id->id_, "name");
321  return Py_BuildValue("s", name.c_str());
322  }
323  else if (attribute == "value")
324  {
325  return moose_Id_getValue(id);
326  }
327  else if (attribute == "shape")
328  {
329  return moose_Id_getShape(id);
330  }
331  else if (attribute == "className")
332  {
333  // !NOTE: Subha: 2012-08-20 19:52:21 (+0530) - the second
334  // !check is to catch a strange bug where the field passed
335  // !to moose_Id_getattro is 'class' in stead of
336  // !'class_'. Need to figure out how it is happening.
337  // !Subha: 2012-08-21 13:25:06 (+0530) It turned out to be
338  // !a GCC optimization issue. GCC was optimizing the call
339  // !to get_field_alias by directly replacing `class_` with
340  // !`class`. This optimized run-path was somehow being
341  // !used only when therewas access to
342  // !obj.parent.class_. Possibly some form of cache
343  // !optimization.
344  // class is a common attribute to all ObjIds under this
345  // Id. Expect it to be a single value in stead of a list
346  // of class names.
347 
348  string classname = Field<string>::get(id->id_, "className");
349  return Py_BuildValue("s", classname.c_str());
350  }
351  return NULL;
352 }
353 
358 Id create_Id_from_path(string path, unsigned int numData, unsigned int isGlobal, string type)
359 {
360  string parent_path;
361  string name;
362 
363  string trimmed_path = moose::trim( path );
364  size_t pos = trimmed_path.rfind("/");
365  if (pos != string::npos)
366  {
367  name = trimmed_path.substr(pos+1);
368  parent_path = trimmed_path.substr(0, pos);
369  //cerr << "Parent path is : " << parent_path << endl;
370  }
371  else
372  {
373  name = trimmed_path;
374  }
375  // handle relative path
376  if (trimmed_path[0] != '/')
377  {
378  string current_path = SHELLPTR->getCwe().path();
379  if (current_path != "/")
380  {
381  parent_path = current_path + "/" + parent_path;
382  }
383  else
384  {
385  parent_path = current_path + parent_path;
386  }
387  }
388  else if (parent_path.empty())
389  {
390  parent_path = "/";
391  }
392  ObjId parent_id(parent_path);
393  if (parent_id.bad() )
394  {
395  string message = "Parent element does not exist: ";
396  message += parent_path;
397  PyErr_SetString(PyExc_ValueError, message.c_str());
398  return Id();
399  }
400  Id nId = SHELLPTR->doCreate(type,
401  parent_id,
402  string(name),
403  numData,
404  static_cast< NodePolicy >( isGlobal )
405  );
406  if (nId == Id() && trimmed_path != "/" && trimmed_path != "/root")
407  {
408  string message = "no such moose class : " + type;
409  PyErr_SetString(PyExc_TypeError, message.c_str());
410 
411  }
412 
413  return nId;
414 }
415 
416 int moose_Id_init(_Id * self, PyObject * args, PyObject * kwargs)
417 {
418  extern PyTypeObject IdType;
419  PyObject * src = NULL;
420  unsigned int id = 0;
421  unsigned int isGlobal = 0;
422  char * type = NULL;
423  // first try parsing the arguments as (path, size, classname)
424  static char _path[] = "path";
425  static char _dtype[] = "dtype";
426  static char _size[] = "n";
427  static char _global[] = "g";
428  static char * kwlist[] = {_path, _size, _global, _dtype, NULL};
429  char * path = NULL;
430  char _default_type[] = "Neutral";
431  // set it to 0 for unspecified value in case the user tries to
432  // get an existing id without specifying it. If the user is
433  // specifying it but the existing vec does not have same
434  // numData we warn the user about the misconception. If it is
435  // nonexisting vec, we change the unspecifed numData to 1.
436  unsigned int numData = 0;
437  // char *type = _default_type;
438  /* The expected arguments are:
439  string path,
440  [unsigned int numData] - default: 1
441  [unsigned int isGlobal] - default: 0
442  [string type] - default: Neutral
443  */
444  if (PyArg_ParseTupleAndKeywords(args, kwargs, "s|IIs:moose_Id_init",
445  kwlist, &path, &numData, &isGlobal,
446  &type)
447  )
448  {
449  // Parsing args successful, if any error happens now,
450  // different argument processing will not help. Return error
451  string trimmed_path(path);
452  trimmed_path = moose::trim(trimmed_path);
453  size_t length = trimmed_path.length();
454  if (length <= 0)
455  {
456  PyErr_SetString(PyExc_ValueError,
457  "moose_Id_init: path must be non-empty string.");
458  return -1;
459  }
460  self->id_ = Id(trimmed_path);
461 
462  // Return already existing object
463  if (self->id_ != Id() || trimmed_path == "/" || trimmed_path == "/root")
464  {
465  if ((numData > 0) && (numData != Field<unsigned int>::get(self->id_, "numData")))
466  {
467  PyErr_WarnEx(NULL, "moose_Id_init_: Length specified does not match that of existing object.", 1);
468  }
469  return 0;
470  }
471  if (type == NULL)
472  type = _default_type;
473  if (numData <= 0)
474  numData = 1;
475 
476  self->id_ = create_Id_from_path(trimmed_path, numData, isGlobal, type);
477  if (self->id_ == Id() && PyErr_Occurred())
478  {
479  return -1;
480  }
481  return 0;
482  }
483  // The arguments could not be parsed as (path, dims, class),
484  // try to parse it as an existing Id
485  PyErr_Clear();
486  if (PyArg_ParseTuple(args, "O:moose_Id_init", &src) && Id_SubtypeCheck(src))
487  {
488  self->id_ = ((_Id*)src)->id_;
489  return 0;
490  }
491  // The arguments could not be parsed as (path, dims, class), or Id
492  // try to parse it as an existing ObjId
493  PyErr_Clear();
494  if (PyArg_ParseTuple(args, "O:moose_Id_init", &src) && ObjId_SubtypeCheck(src))
495  {
496  self->id_ = ((_ObjId*)src)->oid_.id;
497  return 0;
498  }
499  // Next try to parse it as an integer value for an existing Id
500  PyErr_Clear(); // clear the error from parsing error
501  if (PyArg_ParseTuple(args, "I:moose_Id_init", &id))
502  {
503  self->id_ = Id(id);
504  return 0;
505  }
506  return -1;
507 }// ! moose_Id_init
508 
509 long moose_Id_hash(_Id * self)
510 {
511  return self->id_.value(); // hash is the same as the Id value
512 }
513 
514 
515 // 2011-03-23 15:14:11 (+0530)
516 // 2011-03-26 17:02:19 (+0530)
517 //
518 // 2011-03-26 19:14:34 (+0530) - This IS UGLY! Destroying one
519 // ObjId will destroy the containing element and invalidate all
520 // the other ObjId with the same Id.
521 // 2011-03-28 13:44:49 (+0530)
522 PyObject * deleteObjId(ObjId oid)
523 {
524 #ifndef NDEBUG
525  if (verbosity > 1)
526  {
527  cout << "Deleting ObjId " << oid << endl;
528  }
529 #endif
530  SHELLPTR->doDelete(oid);
531  Py_RETURN_NONE;
532 }
533 
534 PyObject * moose_Id_delete(_Id * self)
535 {
536  if (self->id_ == Id())
537  {
538  PyErr_SetString(PyExc_ValueError, "moose_Id_delete: cannot delete moose shell.");
539  return NULL;
540  }
541  if (!Id::isValid(self->id_))
542  {
543  RAISE_INVALID_ID(NULL, "moose_Id_delete");
544  }
545  deleteObjId(self->id_);
546  self->id_ = Id();
547  Py_CLEAR(self);
548  Py_RETURN_NONE;
549 }
550 
551 PyObject * moose_Id_repr(_Id * self)
552 {
553  if (!Id::isValid(self->id_))
554  {
555  RAISE_INVALID_ID(NULL, "moose_Id_repr");
556  }
557  ostringstream repr;
558  repr << "<moose.vec: class="
559  << Field<string>::get(self->id_, "className") << ", "
560  << "id=" << self->id_.value() << ", "
561  << "path=" << self->id_.path() << ">";
562  return PyString_FromString(repr.str().c_str());
563 } // ! moose_Id_repr
564 
565 // The string representation is unused. repr is used everywhere.
566 PyObject * moose_Id_str(_Id * self)
567 {
568  if (!Id::isValid(self->id_))
569  {
570  RAISE_INVALID_ID(NULL, "moose_Id_str");
571  }
572  return PyString_FromFormat("<moose.vec: class=%s, id=%u, path=%s>",
573  Field<string>::get(self->id_, "className").c_str(),
574  self->id_.value(), self->id_.path().c_str());
575 } // ! moose_Id_str
576 
577 // 2011-03-23 15:09:19 (+0530)
578 PyObject* moose_Id_getValue(_Id * self)
579 {
580  unsigned int id = self->id_.value();
581  PyObject * ret = Py_BuildValue("I", id);
582  return ret;
583 }
584 
588 PyObject * moose_Id_getPath(_Id * self)
589 {
590  if (!Id::isValid(self->id_))
591  {
592  RAISE_INVALID_ID(NULL, "moose_Id_getPath");
593  }
594  string path = self->id_.path();
595  string default_end("[0]");
596  if (moose::endswith(path, default_end))
597  {
598  path.erase(path.length() - default_end.length(), default_end.length());
599  }
600  PyObject * ret = Py_BuildValue("s", path.c_str());
601  return ret;
602 }
603 
605 // Subset of sequence protocol functions
607 Py_ssize_t moose_Id_getLength(_Id * self)
608 {
609  if (!Id::isValid(self->id_))
610  {
611  RAISE_INVALID_ID(-1, "moose_Id_getLength");
612  }
613  if (self->id_.element()->hasFields())
614  {
615  return (Py_ssize_t)(Field < unsigned int >::get(self->id_, "numField"));
616  }
617  else
618  {
619  return (Py_ssize_t)(self->id_.element()->numData());
620  }
621 }
622 
623 PyObject * moose_Id_getShape(_Id * self)
624 {
625  if (!Id::isValid(self->id_))
626  {
627  RAISE_INVALID_ID(NULL, "moose_Id_getShape");
628  }
629  unsigned int numData = 1;
630  if (self->id_.element()->hasFields())
631  {
632  numData = Field < unsigned int >::get(self->id_, "numField");
633  }
634  else
635  {
636  // numData = Field < unsigned int >::get(self->id_, "numData");
637  numData = self->id_.element()->numData();
638  }
639  PyObject * ret = PyTuple_New((Py_ssize_t)1);
640  if (PyTuple_SetItem(ret, (Py_ssize_t)0, Py_BuildValue("I", numData)))
641  {
642  Py_XDECREF(ret);
643  PyErr_SetString(PyExc_RuntimeError, "moose_Id_getShape: could not set tuple entry.");
644  return NULL;
645  }
646  return ret;
647 }
648 
649 PyObject * moose_Id_getItem(_Id * self, Py_ssize_t index)
650 {
651  if (!Id::isValid(self->id_))
652  {
653  RAISE_INVALID_ID(NULL, "moose_Id_getItem");
654  }
655  if (index < 0)
656  {
657  index += moose_Id_getLength(self);
658  }
659  if ((index < 0) || (index >= moose_Id_getLength(self)))
660  {
661  PyErr_SetString(PyExc_IndexError, "index out of bounds.");
662  return NULL;
663  }
664  ObjId oid(self->id_.path()); // This is just to get the dataIndex of parent
665  if (self->id_.element()->hasFields())
666  {
667  // How to efficiently get the dataIndex of parent element
668  // without creating ObjId from path?
669  oid = ObjId(self->id_, oid.dataIndex, index);
670  }
671  else
672  {
673  oid = ObjId(self->id_, index, 0);
674  }
675  return oid_to_element(oid);
676 }
677 
678 static PyObject* moose_Id_fillSlice(_Id *self,
679  Py_ssize_t start,
680  Py_ssize_t end,
681  Py_ssize_t step,
682  Py_ssize_t slicelength)
683 {
684 
685  PyObject * ret = PyTuple_New(slicelength);
686  bool has_fields = self->id_.element()->hasFields();
687  for (int ii = start; ii < end; ii += step)
688  {
689  ObjId oid(self->id_.path());
690  PyObject *value;
691  if (has_fields)
692  value = oid_to_element(ObjId(self->id_, oid.dataIndex, ii));
693  else
694  value = oid_to_element(ObjId(self->id_, ii));
695 
696  PyTuple_SET_ITEM(ret, (Py_ssize_t)(ii-start)/step, value);
697  }
698  return ret;
699 }
700 
701 #ifndef PY3K
702 PyObject * moose_Id_getSlice(_Id * self, Py_ssize_t start, Py_ssize_t end)
703 {
704  if (!Id::isValid(self->id_))
705  {
706  RAISE_INVALID_ID(NULL, "moose_Id_getSlice");
707  }
708  Py_ssize_t len = moose_Id_getLength(self);
709  while (start < 0)
710  {
711  start += len;
712  }
713  while (end < 0)
714  {
715  end += len;
716  }
717  return moose_Id_fillSlice(self, start, end, 1, std::max(end - start, (Py_ssize_t) 0));
718 }
719 #endif
720 
721 #ifdef PY3K
722 # define SLICE_OBJ(x) (x)
723 #else
724 # define SLICE_OBJ(x) ((PySliceObject*)(x))
725 #endif
726 
728 // Mapping protocol
730 PyObject * moose_Id_subscript(_Id * self, PyObject *op)
731 {
732  if (PySlice_Check(op))
733  {
734  const Py_ssize_t len = moose_Id_getLength(self);
735  Py_ssize_t start, stop, step, slicelength;
736 
737  if (PySlice_GetIndicesEx(SLICE_OBJ(op), len, &start, &stop, &step, &slicelength) < 0)
738  return NULL;
739 
740  return moose_Id_fillSlice(self, start, stop, step, slicelength);
741  }
742 
743  if (PyInt_Check(op) || PyLong_Check(op))
744  {
745  Py_ssize_t value = PyInt_AsLong(op);
746  return moose_Id_getItem(self, value);
747  }
748  else
749  {
750  PyErr_SetString(PyExc_KeyError, "moose_Id_subscript: invalid index.");
751  return NULL;
752  }
753 }
754 
755 PyObject * moose_Id_richCompare(_Id * self, PyObject * other, int op)
756 {
757  extern PyTypeObject IdType;
758  bool ret = false;
759  Id other_id = ((_Id*)other)->id_;
760  if (!self || !other)
761  {
762  ret = false;
763  }
764  else if (!PyObject_IsInstance(other, (PyObject*)&IdType))
765  {
766  ret = false;
767  }
768  else if (op == Py_EQ)
769  {
770  ret = self->id_ == other_id;
771  }
772  else if (op == Py_NE)
773  {
774  ret = self->id_ != other_id;
775  }
776  else if (op == Py_LT)
777  {
778  ret = self->id_ < other_id;
779  }
780  else if (op == Py_GT)
781  {
782  ret = other_id < self->id_;
783  }
784  else if (op == Py_LE)
785  {
786  ret = (self->id_ < other_id) || (self->id_ == other_id);
787  }
788  else if (op == Py_GE)
789  {
790  ret = (other_id < self->id_) || (self->id_ == other_id);
791  }
792  if (ret)
793  {
794  Py_RETURN_TRUE;
795  }
796  Py_RETURN_FALSE;
797 }
798 
799 int moose_Id_contains(_Id * self, PyObject * obj)
800 {
801  extern PyTypeObject ObjIdType;
802  int ret = 0;
803  if (ObjId_SubtypeCheck(obj))
804  {
805  ret = (((_ObjId*)obj)->oid_.id == self->id_);
806  }
807  return ret;
808 }
809 
810 PyObject * moose_Id_getattro(_Id * self, PyObject * attr)
811 {
812  int new_attr = 0;
813  if (!Id::isValid(self->id_))
814  {
815  RAISE_INVALID_ID(NULL, "moose_Id_getattro");
816  }
817  char * field = PyString_AsString(attr);
818  PyObject * _ret = get_Id_attr(self, field);
819  if (_ret != NULL)
820  {
821  return _ret;
822  }
823  string className = Field<string>::get(self->id_, "className");
824  string type = getFieldType(className, string(field));
825  if (type.empty())
826  {
827  // Check if this field name is aliased and update fieldname and type if so.
828  map<string, string>::const_iterator it = get_field_alias().find(string(field));
829  if (it != get_field_alias().end())
830  {
831  field = const_cast<char*>((it->second).c_str());
832  type = getFieldType(Field<string>::get(self->id_, "className"), it->second);
833  // Update attr for next level (PyObject_GenericGetAttr) in case.
834  // Py_XDECREF(attr);
835  attr = PyString_FromString(field);
836  new_attr = 1;
837  }
838  }
839  if (type.empty())
840  {
841  return PyObject_GenericGetAttr((PyObject*)self, attr);
842  }
843  char ftype = shortType(type);
844  if (!ftype)
845  {
846  return PyObject_GenericGetAttr((PyObject*)self, attr);
847  }
848 
849  switch (ftype)
850  {
851  case 'd':
852  {
853  vector < double > val;
854  Field< double >::getVec(self->id_, string(field), val);
855  _ret = to_pytuple(&val, ftype);
856  break;
857  }
858  case 's':
859  {
860  vector < string > val;
861  Field< string >::getVec(self->id_, string(field), val);
862  _ret = to_pytuple(&val, ftype);
863  break;
864  }
865  case 'l':
866  {
867  vector < long > val;
868  Field< long >::getVec(self->id_, string(field), val);
869  _ret = to_pytuple(&val, ftype);
870  break;
871  }
872  case 'x':
873  {
874  vector < Id > val;
875  Field< Id >::getVec(self->id_, string(field), val);
876  _ret = to_pytuple(&val, ftype);
877  break;
878  }
879  case 'y':
880  {
881  vector < ObjId > val;
882  Field< ObjId >::getVec(self->id_, string(field), val);
883  _ret = to_pytuple(&val, ftype);
884  break;
885  }
886  case 'i':
887  {
888  vector < int > val;
889  Field< int >::getVec(self->id_, string(field), val);
890  _ret = to_pytuple(&val, ftype);
891  break;
892  }
893  case 'I':
894  {
895  vector < unsigned int > val;
896  Field< unsigned int >::getVec(self->id_, string(field), val);
897  _ret = to_pytuple(&val, ftype);
898  break;
899  }
900  case 'k':
901  {
902  vector < unsigned long > val;
903  Field< unsigned long >::getVec(self->id_, string(field), val);
904  _ret = to_pytuple(&val, ftype);
905  break;
906  }
907  case 'f':
908  {
909  vector < float > val;
910  Field< float >::getVec(self->id_, string(field), val);
911  _ret = to_pytuple(&val, ftype);
912  break;
913  }
914  case 'b':
915  {
916  vector<bool> val;
917  Field< bool >::getVec(self->id_, string(field), val);
918  _ret = to_pytuple(&val, ftype);
919  break;
920  }
921  case 'c':
922  {
923  vector < char > val;
924  Field< char >::getVec(self->id_, string(field), val);
925  _ret = to_pytuple(&val, ftype);
926  break;
927  }
928  case 'h':
929  {
930  vector < short > val;
931  Field< short >::getVec(self->id_, string(field), val);
932  _ret = to_pytuple(&val, ftype);
933  break;
934  }
935  case 'z':
936  {
937  PyErr_SetString(PyExc_NotImplementedError,
938  "moose_Id_getattro: DataId handling not implemented yet.");
939  _ret = NULL;
940  break;
941  }
942  default:
943  ostringstream msg;
944  msg << "moose_Id_getattro: unhandled field type '" << type << "'\n"
945  << "This is a vec object. Perhaps you are trying to access the field in an"
946  << " element in this. Then use indexing to get the element first.";
947  PyErr_SetString(PyExc_ValueError, msg.str().c_str());
948  _ret = NULL;
949  break;
950  }
951  if (new_attr)
952  {
953  Py_DECREF(attr);
954  }
955  return _ret;
956 }
957 
958 PyObject * moose_Id_setField(_Id * self, PyObject * args)
959 {
960  if (!Id::isValid(self->id_))
961  {
962  RAISE_INVALID_ID(NULL, "moose_Id_setField");
963  }
964  PyObject * field = NULL;
965  PyObject * value = NULL;
966  if (!PyArg_ParseTuple(args, "OO:moose_Id_setField", &field, &value))
967  {
968  return NULL;
969  }
970  if (moose_Id_setattro(self, field, value) == -1)
971  {
972  return NULL;
973  }
974  Py_RETURN_NONE;
975 }
976 
977 int moose_Id_setattro(_Id * self, PyObject * attr, PyObject *value)
978 {
979  if (!Id::isValid(self->id_))
980  {
981  RAISE_INVALID_ID(-1, "moose_Id_setattro");
982  }
983  char * fieldname = NULL;
984  int ret = -1;
985  if (PyString_Check(attr))
986  {
987  fieldname = PyString_AsString(attr);
988  }
989  else
990  {
991  PyErr_SetString(PyExc_TypeError, "moose_Id_setattro: Attribute name must be a string");
992  return -1;
993  }
994  string moose_class = Field<string>::get(self->id_, "className");
995  string fieldtype = getFieldType(moose_class, string(fieldname));
996  if (fieldtype.length() == 0)
997  {
998  // If it is instance of a MOOSE Id then throw
999  // error (to avoid silently creating new attributes due to
1000  // typos). Otherwise, it must have been subclassed in
1001  // Python. Then we allow normal Pythonic behaviour and
1002  // consider such mistakes user's responsibility.
1003  string className = ((PyTypeObject*)PyObject_Type((PyObject*)self))->tp_name;
1004  if (className != "vec")
1005  {
1006  Py_INCREF(attr);
1007  ret = PyObject_GenericSetAttr((PyObject*)self, attr, value);
1008  Py_XDECREF(attr);
1009  return ret;
1010  }
1011  ostringstream msg;
1012  msg << "moose_Id_setattro: '" << moose_class << "' class has no field '" << fieldname << "'" << endl;
1013  PyErr_SetString(PyExc_AttributeError, msg.str().c_str());
1014  return -1;
1015  }
1016  char ftype = shortType(fieldtype);
1017  Py_ssize_t length = moose_Id_getLength(self);
1018  bool is_seq = true;
1019  if (!PySequence_Check(value))
1020  {
1021  is_seq = false;
1022  }
1023  else if (length != PySequence_Length(value))
1024  {
1025  PyErr_SetString(PyExc_IndexError,
1026  "moose_Id_setattro: length of the sequence on the right hand side does not match Id size.");
1027  return -1;
1028  }
1029  switch(ftype)
1030  {
1031  case 'd': //SET_VECFIELD(double, d)
1032  {
1033  vector<double> _value;
1034  if (is_seq)
1035  {
1036  for ( int ii = 0; ii < length; ++ii)
1037  {
1038  PyObject * vo = PySequence_GetItem(value, ii);
1039  double v = PyFloat_AsDouble(vo);
1040  Py_XDECREF(vo);
1041  _value.push_back(v);
1042  }
1043  }
1044  else
1045  {
1046  double v = PyFloat_AsDouble(value);
1047  _value.assign(length, v);
1048  }
1049  ret = Field<double>::setVec(self->id_, string(fieldname), _value);
1050  break;
1051  }
1052  case 's':
1053  {
1054  vector<string> _value;
1055  if (is_seq)
1056  {
1057  for ( int ii = 0; ii < length; ++ii)
1058  {
1059  PyObject * vo = PySequence_GetItem(value, ii);
1060  char * v = PyString_AsString(vo);
1061  Py_XDECREF(v);
1062  _value.push_back(string(v));
1063  }
1064  }
1065  else
1066  {
1067  char * v = PyString_AsString(value);
1068  _value.assign(length, string(v));
1069  }
1070  ret = Field<string>::setVec(self->id_, string(fieldname), _value);
1071  break;
1072  }
1073  case 'i':
1074  {
1075  vector<int> _value;
1076  if (is_seq)
1077  {
1078  for ( int ii = 0; ii < length; ++ii)
1079  {
1080  PyObject * vo = PySequence_GetItem(value, ii);
1081  int v = PyInt_AsLong(vo);
1082  Py_XDECREF(vo);
1083  _value.push_back(v);
1084  }
1085  }
1086  else
1087  {
1088  int v = PyInt_AsLong(value);
1089  _value.assign(length, v);
1090  }
1091  ret = Field< int >::setVec(self->id_, string(fieldname), _value);
1092  break;
1093  }
1094  case 'I': //SET_VECFIELD(unsigned int, I)
1095  {
1096  vector<unsigned int> _value;
1097  if (is_seq)
1098  {
1099  for ( int ii = 0; ii < length; ++ii)
1100  {
1101  PyObject * vo = PySequence_GetItem(value, ii);
1102  unsigned int v = PyInt_AsUnsignedLongMask(vo);
1103  Py_DECREF(vo);
1104  _value.push_back(v);
1105  }
1106  }
1107  else
1108  {
1109  unsigned int v = PyInt_AsUnsignedLongMask(value);
1110  _value.assign(length, v);
1111  }
1112  ret = Field< unsigned int >::setVec(self->id_, string(fieldname), _value);
1113  break;
1114  }
1115  case 'l': //SET_VECFIELD(long, l)
1116  {
1117  vector<long> _value;
1118  if (is_seq)
1119  {
1120  for ( int ii = 0; ii < length; ++ii)
1121  {
1122  PyObject * vo = PySequence_GetItem(value, ii);
1123  long v = PyInt_AsLong(vo);
1124  Py_DECREF(vo);
1125  _value.push_back(v);
1126  }
1127  }
1128  else
1129  {
1130  long v = PyInt_AsLong(value);
1131  _value.assign(length, v);
1132  }
1133  ret = Field<long>::setVec(self->id_, string(fieldname), _value);
1134  break;
1135  }
1136  case 'k': //SET_VECFIELD(unsigned long, k)
1137  {
1138  vector<unsigned long> _value;
1139  if (is_seq)
1140  {
1141  for ( int ii = 0; ii < length; ++ii)
1142  {
1143  PyObject * vo = PySequence_GetItem(value, ii);
1144  unsigned long v = PyInt_AsUnsignedLongMask(vo);
1145  Py_XDECREF(vo);
1146  _value.push_back(v);
1147  }
1148  }
1149  else
1150  {
1151  unsigned long v = PyInt_AsUnsignedLongMask(value);
1152  _value.assign(length, v);
1153  }
1154  ret = Field< unsigned long >::setVec(self->id_, string(fieldname), _value);
1155  break;
1156  }
1157  case 'b':
1158  {
1159  vector<bool> _value;
1160  if (is_seq)
1161  {
1162  for ( int ii = 0; ii < length; ++ii)
1163  {
1164  PyObject * _v = PySequence_GetItem(value, ii);
1165  bool v = (Py_True ==_v) || (PyInt_AsLong(_v) != 0);
1166  Py_XDECREF(_v);
1167  _value.push_back(v);
1168  }
1169  }
1170  else
1171  {
1172  bool v = (Py_True ==value) || (PyInt_AsLong(value) != 0);
1173  _value.assign(length, v);
1174  }
1175  ret = Field< bool >::setVec(self->id_, string(fieldname), _value);
1176  break;
1177  }
1178  case 'c':
1179  {
1180  vector<char> _value;
1181  if (is_seq)
1182  {
1183  for ( int ii = 0; ii < length; ++ii)
1184  {
1185  PyObject * _v = PySequence_GetItem(value, ii);
1186  char * v = PyString_AsString(_v);
1187  Py_XDECREF(_v);
1188  if (v && v[0])
1189  {
1190  _value.push_back(v[0]);
1191  }
1192  else
1193  {
1194  ostringstream err;
1195  err << "moose_Id_setattro:" << ii << "-th element is NUL";
1196  PyErr_SetString(PyExc_ValueError, err.str().c_str());
1197  return -1;
1198  }
1199  }
1200  }
1201  else
1202  {
1203  char * v = PyString_AsString(value);
1204  if (v && v[0])
1205  {
1206  _value.assign(length, v[0]);
1207  }
1208  else
1209  {
1210  PyErr_SetString(PyExc_ValueError, "moose_Id_setattro: value is an empty string");
1211  return -1;
1212  }
1213  }
1214  ret = Field< char >::setVec(self->id_, string(fieldname), _value);
1215  break;
1216  }
1217  case 'h':
1218  {
1219  vector<short> _value;
1220  if (is_seq)
1221  {
1222  for ( int ii = 0; ii < length; ++ii)
1223  {
1224  PyObject * vo = PySequence_GetItem(value, ii);
1225  short v = PyInt_AsLong(vo);
1226  Py_XDECREF(vo);
1227  _value.push_back(v);
1228  }
1229  }
1230  else
1231  {
1232  short v = PyInt_AsLong(value);
1233  _value.assign(length, v);
1234  }
1235  ret = Field< short >::setVec(self->id_, string(fieldname), _value);
1236  break;
1237  }
1238  case 'f': //SET_VECFIELD(float, f)
1239  {
1240  vector<float> _value;
1241  if (is_seq)
1242  {
1243  for ( int ii = 0; ii < length; ++ii)
1244  {
1245  PyObject * vo = PySequence_GetItem(value, ii);
1246  float v = PyFloat_AsDouble(vo);
1247  Py_XDECREF(vo);
1248  _value.push_back(v);
1249  }
1250  }
1251  else
1252  {
1253  float v = PyFloat_AsDouble(value);
1254  _value.assign(length, v);
1255  }
1256  ret = Field<float>::setVec(self->id_, string(fieldname), _value);
1257  break;
1258  }
1259  default:
1260  break;
1261  }
1262  // MOOSE Field::set returns 1 for success 0 for
1263  // failure. Python treats return value 0 from setters as
1264  // success, anything else failure.
1265  if (ret && (PyErr_Occurred() == NULL))
1266  {
1267  return 0;
1268  }
1269  else
1270  {
1271  return -1;
1272  }
1273 
1274 }
1275 
1276 
1277 //
1278 // vec.cpp ends here
PyObject_HEAD Id id_
Definition: moosemodule.h:114
Py_ssize_t moose_Id_getLength(_Id *self)
Definition: vec.cpp:607
#define ObjId_SubtypeCheck(v)
Definition: moosemodule.h:98
char shortType(string)
uint32_t value
Definition: moosemodule.h:42
#define SHELLPTR
Definition: moosemodule.h:105
PyObject * moose_Id_getItem(_Id *self, Py_ssize_t index)
Definition: vec.cpp:649
PyTypeObject ObjIdType
static double op(double x)
bool endswith(const string &full, const string &ending)
Definition: strutil.cpp:138
PyObject * moose_Id_getattro(_Id *self, PyObject *attr)
Definition: vec.cpp:810
bool bad() const
Definition: ObjId.cpp:18
PyObject * moose_Id_getSlice(_Id *self, Py_ssize_t start, Py_ssize_t end)
Definition: vec.cpp:702
#define SLICE_OBJ(x)
Definition: vec.cpp:724
Definition: SetGet.h:236
PyObject * moose_Id_getPath(_Id *self)
Definition: vec.cpp:588
Definition: ObjId.h:20
static PyMappingMethods IdMappingMethods
Definition: vec.cpp:165
const map< string, string > & get_field_alias()
int moose_Id_contains(_Id *self, PyObject *obj)
Definition: vec.cpp:799
PyObject * moose_Id_delete(_Id *self)
Definition: vec.cpp:534
Id create_Id_from_path(string path, unsigned int numData, unsigned int isGlobal, string type)
Definition: vec.cpp:358
PyObject * moose_Id_getValue(_Id *self)
Definition: vec.cpp:578
#define RAISE_INVALID_ID(ret, msg)
Definition: moosemodule.h:71
PyObject * moose_Id_getShape(_Id *self)
Definition: vec.cpp:623
long moose_Id_hash(_Id *self)
Definition: vec.cpp:509
#define Id_SubtypeCheck(v)
Definition: moosemodule.h:96
PyObject * moose_Id_richCompare(_Id *self, PyObject *other, int op)
Definition: vec.cpp:755
PyObject * moose_Id_repr(_Id *self)
Definition: vec.cpp:551
static PyMethodDef IdMethods[]
Definition: vec.cpp:120
PyObject * to_pytuple(void *obj, char typecode)
PyObject * moose_Id_str(_Id *self)
Definition: vec.cpp:566
PyObject * get_Id_attr(_Id *id, string attribute)
Definition: vec.cpp:312
PyDoc_STRVAR(moose_Id_delete_doc,"vec.delete() -> None""\n""\nDelete the underlying moose object. This will invalidate all""\nreferences to this object and any attempt to access it will raise a""\nValueError.""\n Example""\n--------""\n >>>iaf.delete()""\n >>>print iaf.path""\n \\ ""\n")
string getFieldType(string className, string fieldName)
static bool setVec(ObjId destId, const string &field, const vector< A > &arg)
Definition: SetGet.h:252
static bool isValid(Id id)
Definition: Id.h:145
int verbosity
int moose_Id_init(_Id *self, PyObject *args, PyObject *kwargs)
Definition: vec.cpp:416
PyObject * deleteObjId(ObjId oid)
Definition: vec.cpp:522
static char name[]
Definition: mfield.cpp:401
PyTypeObject IdType
Definition: vec.cpp:262
PyObject * moose_Id_setField(_Id *self, PyObject *args)
Definition: vec.cpp:958
Definition: Id.h:17
PyObject * moose_Id_subscript(_Id *self, PyObject *op)
Definition: vec.cpp:730
static A get(const ObjId &dest, const string &field)
Definition: SetGet.h:284
std::string trim(const std::string myString, const string &delimiters)
Definition: strutil.cpp:53
static void getVec(ObjId dest, const string &field, vector< A > &vec)
Definition: SetGet.h:317
PyObject * oid_to_element(ObjId oid)
int moose_Id_setattro(_Id *self, PyObject *attr, PyObject *value)
Definition: vec.cpp:977
unsigned int id_
Definition: Id.h:172
static PyObject * moose_Id_fillSlice(_Id *self, Py_ssize_t start, Py_ssize_t end, Py_ssize_t step, Py_ssize_t slicelength)
Definition: vec.cpp:678
static char path[]
Definition: mfield.cpp:403
static PySequenceMethods IdSequenceMethods
Definition: vec.cpp:147