Flow123d
field_python_impl.hh
Go to the documentation of this file.
1 /*
2  * function_python_impl.hh
3  *
4  * Created on: Oct 10, 2012
5  * Author: jb
6  */
7 
8 #ifndef FIELD_PYTHON_IMPL_HH_
9 #define FIELD_PYTHON_IMPL_HH_
10 
11 
12 #include <boost/type_traits.hpp>
13 #include "fields/field_python.hh"
14 
15 /// Implementation.
16 
17 namespace it = Input::Type;
18 
19 template <int spacedim, class Value>
21 
22 
23 
24 template <int spacedim, class Value>
26  Input::Type::AbstractRecord &a_type, const typename Value::ElementInputType *eit
27  )
28 {
29  it::Record type
30  = it::Record("FieldPython", FieldBase<spacedim,Value>::template_name()+" Field given by a Python script.")
31  .derive_from(a_type)
32  .declare_key("script_string", it::String(), it::Default::read_time("Obligatory if 'script_file' is not given."),
33  "Python script given as in place string")
34  .declare_key("script_file", it::FileName::input(), it::Default::read_time("Obligatory if 'script_striong' is not given."),
35  "Python script given as external file")
37  "Function in the given script that returns tuple containing components of the return type.\n"
38  "For NxM tensor values: tensor(row,col) = tuple( M*row + col ).");
39 
40  return type;
41 }
42 
43 
44 
45 template <int spacedim, class Value>
47 : FieldBase<spacedim, Value>( n_comp)
48 {
49 #ifdef HAVE_PYTHON
50  p_func_=NULL;
51  p_module_=NULL;
52  p_args_=NULL;
53  p_value_=NULL;
54 #else
55  xprintf(UsrErr, "Flow123d compiled without support for Python, FieldPython can not be used.\n");
56 #endif // HAVE_PYTHON
57 }
58 
59 
60 
61 template <int spacedim, class Value>
62 void FieldPython<spacedim, Value>::set_python_field_from_string(const string &python_source, const string &func_name)
63 {
64 #ifdef HAVE_PYTHON
65  p_module_ = PythonLoader::load_module_from_string("python_field_"+func_name, python_source);
66  set_func(func_name);
67 #endif // HAVE_PYTHON
68 }
69 
70 
71 
72 
73 
74 template <int spacedim, class Value>
76  Input::Iterator<string> it = rec.find<string>("script_string");
77  if (it) {
78  set_python_field_from_string( *it, rec.val<string>("function") );
79  } else {
80  Input::Iterator<FilePath> it = rec.find<FilePath>("script_file");
81  if (! it) xprintf(UsrErr, "Either 'script_string' or 'script_file' has to be specified in PythonField initialization.");
82  set_python_field_from_file( *it, rec.val<string>("function") );
83  }
84 }
85 
86 
87 
88 template <int spacedim, class Value>
89 void FieldPython<spacedim, Value>::set_python_field_from_file(const FilePath &file_name, const string &func_name)
90 {
91 #ifdef HAVE_PYTHON
92  p_module_ = PythonLoader::load_module_from_file( string(file_name) );
93  set_func(func_name);
94 #endif // HAVE_PYTHON
95 }
96 
97 
98 
99 
100 template <int spacedim, class Value>
101 void FieldPython<spacedim, Value>::set_func(const string &func_name)
102 {
103 #ifdef HAVE_PYTHON
104  char func_char[func_name.size()+2];
105  std::strcpy(func_char, func_name.c_str());
106  p_func_ = PyObject_GetAttrString(p_module_, func_char );
107  if (! p_func_) {
108  if (PyErr_Occurred()) PyErr_Print();
109  xprintf(UsrErr, "Field '%s' not found in the python module: %s\n", func_name.c_str(), PyModule_GetName(p_module_) );
110  Py_XDECREF(p_func_);
111  Py_XDECREF(p_module_);
112 
113  }
114  if (! PyCallable_Check(p_func_)) {
115  xprintf(UsrErr, "Field '%s' from the python module: %s is not callable.\n", func_name.c_str(), PyModule_GetName(p_module_) );
116  Py_XDECREF(p_func_);
117  Py_XDECREF(p_module_);
118 
119  }
120 
121  p_args_ = PyTuple_New( spacedim );
122 
123  // try field call
124  for(unsigned int i = 0; i < spacedim; i++) {
125  p_value_ = PyFloat_FromDouble( double(i) );
126  PyTuple_SetItem(p_args_, i, p_value_);
127  }
128  p_value_ = PyObject_CallObject(p_func_, p_args_);
129 
130  if (p_value_ == NULL) {
131  PyErr_Print();
132  // TODO: use cout to output also field arguments
133  xprintf(Err,"Failed to call field '%s' from the python module: %s\n", func_name.c_str(), PyModule_GetName(p_module_) );
134  }
135 
136  if ( ! PyTuple_Check( p_value_)) {
137  xprintf(UsrErr, "Field '%s' from the python module: %s doesn't return Tuple.\n", func_name.c_str(), PyModule_GetName(p_module_) );
138  }
139 
140  unsigned int size = PyTuple_Size( p_value_);
141 
142  unsigned int value_size=this->value_.n_rows() * this->value_.n_cols();
143  if ( size != value_size) {
144  xprintf(UsrErr, "Field '%s' from the python module: %s returns %d components but should return %d components.\n"
145  ,func_name.c_str(), PyModule_GetName(p_module_), size, value_size);
146  }
147 
148 #endif // HAVE_PYTHON
149 
150 }
151 
152 /**
153  * Returns one value in one given point. ResultType can be used to avoid some costly calculation if the result is trivial.
154  */
155 template <int spacedim, class Value>
156 typename Value::return_type const & FieldPython<spacedim, Value>::value(const Point &p, const ElementAccessor<spacedim> &elm)
157 {
158  set_value(p,elm, this->value_);
159  return this->r_value_;
160 }
161 
162 
163 /**
164  * Returns std::vector of scalar values in several points at once.
165  */
166 template <int spacedim, class Value>
169 {
170  ASSERT_EQUAL( point_list.size(), value_list.size() );
171  for(unsigned int i=0; i< point_list.size(); i++) {
172  Value envelope(value_list[i]);
173  set_value(point_list[i], elm, envelope );
174 
175  }
176 }
177 
178 /**
179 * Returns one vector value in one given point.
180 */
181 template <int spacedim, class Value>
183 {
184 #ifdef HAVE_PYTHON
185  for(unsigned int i = 0; i < spacedim; i++) {
186  p_value_ = PyFloat_FromDouble( p[i] );
187  PyTuple_SetItem(p_args_, i, p_value_);
188  }
189  p_value_ = PyObject_CallObject(p_func_, p_args_);
190 
191  if (p_value_ == NULL) {
192  PyErr_Print();
193  xprintf(Err,"FieldPython call failed\n");
194  }
195 
196  unsigned int pos =0;
197  for(unsigned int row=0; row < value.n_rows(); row++)
198  for(unsigned int col=0; col < value.n_cols(); col++, pos++)
199  if ( boost::is_integral< typename Value::element_type >::value ) value(row,col) = PyLong_AsLong( PyTuple_GetItem( p_value_, pos ) );
200  else value(row,col) = PyFloat_AsDouble( PyTuple_GetItem( p_value_, pos ) );
201 
202 #endif // HAVE_PYTHON
203 }
204 
205 
206 
207 
208 template <int spacedim, class Value>
210 #ifdef HAVE_PYTHON
211  Py_CLEAR(p_module_);
212  Py_CLEAR(p_func_);
213  Py_CLEAR(p_value_);
214  Py_CLEAR(p_args_);
215 #endif // HAVE_PYTHON
216 }
217 
218 
219 #endif /* FIELD_PYTHON_IMPL_HH_ */