Flow123d  release_2.2.0-914-gf1a3a4f
field_python.impl.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file field_python.impl.hh
15  * @brief
16  */
17 
18 #ifndef FIELD_PYTHON_IMPL_HH_
19 #define FIELD_PYTHON_IMPL_HH_
20 
21 
22 #include <boost/type_traits.hpp>
23 #include "fields/field_python.hh"
24 
25 /// Implementation.
26 
27 namespace it = Input::Type;
28 
29 FLOW123D_FORCE_LINK_IN_CHILD(field_python)
30 
31 
32 
33 template <int spacedim, class Value>
34 const Input::Type::Record & FieldPython<spacedim, Value>::get_input_type()
35 {
36  return it::Record("FieldPython", FieldAlgorithmBase<spacedim,Value>::template_name()+" Field given by a Python script.")
39  .declare_key("script_string", it::String(), it::Default::read_time("Obligatory if 'script_file' is not given. "),
40  "Python script given as in place string")
41  .declare_key("script_file", it::FileName::input(), it::Default::read_time("Obligatory if 'script_striong' is not given. "),
42  "Python script given as external file")
44  "Function in the given script that returns tuple containing components of the return type.\n"
45  "For NxM tensor values: tensor(row,col) = tuple( M*row + col ).")
46  //.declare_key("units", FieldAlgorithmBase<spacedim, Value>::get_field_algo_common_keys(), it::Default::optional(),
47  // "Definition of unit.")
48  .close();
49 }
50 
51 
52 template <int spacedim, class Value>
54  Input::register_class< FieldPython<spacedim, Value>, unsigned int >("FieldPython") +
56 
57 
58 
59 template <int spacedim, class Value>
61 : FieldAlgorithmBase<spacedim, Value>( n_comp)
62 {
63 #ifdef FLOW123D_HAVE_PYTHON
64  p_func_=NULL;
65  p_module_=NULL;
66  p_args_=NULL;
67  p_value_=NULL;
68 #else
69  xprintf(UsrErr, "Flow123d compiled without support for Python, FieldPython can not be used.\n");
70 #endif // FLOW123D_HAVE_PYTHON
71 }
72 
73 
74 
75 template <int spacedim, class Value>
76 void FieldPython<spacedim, Value>::set_python_field_from_string(const string &python_source, const string &func_name)
77 {
78 #ifdef FLOW123D_HAVE_PYTHON
79  p_module_ = PythonLoader::load_module_from_string("python_field_"+func_name, python_source);
80  set_func(func_name);
81 #endif // FLOW123D_HAVE_PYTHON
82 }
83 
84 
85 
86 
87 
88 template <int spacedim, class Value>
90  this->init_unit_conversion_coefficient(rec, init_data);
91 
92  Input::Iterator<string> it = rec.find<string>("script_string");
93  if (it) {
94  set_python_field_from_string( *it, rec.val<string>("function") );
95  } else {
96  Input::Iterator<FilePath> it = rec.find<FilePath>("script_file");
97  if (! it) xprintf(UsrErr, "Either 'script_string' or 'script_file' has to be specified in PythonField initialization.");
98  try {
99  set_python_field_from_file( *it, rec.val<string>("function") );
100  } INPUT_CATCH(FilePath::ExcFileOpen, FilePath::EI_Address_String, rec)
101  }
102 }
103 
104 
105 
106 template <int spacedim, class Value>
107 void FieldPython<spacedim, Value>::set_python_field_from_file(const FilePath &file_name, const string &func_name)
108 {
109 #ifdef FLOW123D_HAVE_PYTHON
110  p_module_ = PythonLoader::load_module_from_file( string(file_name) );
111  set_func(func_name);
112 #endif // FLOW123D_HAVE_PYTHON
113 }
114 
115 
116 
117 
118 template <int spacedim, class Value>
119 void FieldPython<spacedim, Value>::set_func(const string &func_name)
120 {
121 #ifdef FLOW123D_HAVE_PYTHON
122  p_func_ = PythonLoader::get_callable(p_module_, func_name);
123 
124  p_args_ = PyTuple_New( spacedim );
125 
126  // try field call
127  for(unsigned int i = 0; i < spacedim; i++) {
128  p_value_ = PyFloat_FromDouble( double(i) );
129  PyTuple_SetItem(p_args_, i, p_value_);
130  }
131  p_value_ = PyObject_CallObject(p_func_, p_args_);
132  PythonLoader::check_error();
133 
134  if ( ! PyTuple_Check( p_value_)) {
135  stringstream ss;
136  ss << "Field '" << func_name << "' from the python module: " << PyModule_GetName(p_module_) << " doesn't return Tuple." << endl;
137  THROW( ExcMessage() << EI_Message( ss.str() ));
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 // FLOW123D_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  this->value_.scale(this->unit_conversion_coefficient_);
160  return this->r_value_;
161 }
162 
163 
164 /**
165  * Returns std::vector of scalar values in several points at once.
166  */
167 template <int spacedim, class Value>
170 {
171  OLD_ASSERT_EQUAL( point_list.size(), value_list.size() );
172  for(unsigned int i=0; i< point_list.size(); i++) {
173  Value envelope(value_list[i]);
174  OLD_ASSERT( envelope.n_rows()==this->value_.n_rows(),
175  "value_list[%d] has wrong number of rows: %d; should match number of components: %d\n",
176  i, envelope.n_rows(),this->value_.n_rows());
177  set_value(point_list[i], elm, envelope );
178  envelope.scale(this->unit_conversion_coefficient_);
179  }
180 }
181 
182 /**
183 * Returns one vector value in one given point.
184 */
185 template <int spacedim, class Value>
187 {
188 #ifdef FLOW123D_HAVE_PYTHON
189  for(unsigned int i = 0; i < spacedim; i++) {
190  p_value_ = PyFloat_FromDouble( p[i] );
191  PyTuple_SetItem(p_args_, i, p_value_);
192  }
193  p_value_ = PyObject_CallObject(p_func_, p_args_);
194  PythonLoader::check_error();
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 // FLOW123D_HAVE_PYTHON
203 }
204 
205 
206 
207 
208 template <int spacedim, class Value>
210 #ifdef FLOW123D_HAVE_PYTHON
211  Py_CLEAR(p_module_);
212  Py_CLEAR(p_func_);
213  Py_CLEAR(p_value_);
214  Py_CLEAR(p_args_);
215 #endif // FLOW123D_HAVE_PYTHON
216 }
217 
218 
219 #endif /* FIELD_PYTHON_IMPL_HH_ */
void set_python_field_from_file(const FilePath &file_name, const string &func_name)
void init_unit_conversion_coefficient(const Input::Record &rec, const struct FieldAlgoBaseInitData &init_data)
Init value of unit_conversion_coefficient_ from input.
void set_func(const string &func_name)
void set_python_field_from_string(const string &python_source, const string &func_name)
virtual void value_list(const std::vector< Point > &point_list, const ElementAccessor< spacedim > &elm, std::vector< typename Value::return_type > &value_list)
Abstract linear system class.
Definition: equation.hh:37
#define INPUT_CATCH(ExceptionType, AddressEITag, input_accessor)
Definition: accessors.hh:64
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
Iterator< Ret > find(const string &key) const
Helper struct stores data for initizalize descentants of FieldAlgorithmBase.
void set_value(const Point &p, const ElementAccessor< spacedim > &elm, Value &value)
Value::return_type r_value_
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:303
static constexpr bool value
Definition: json.hpp:87
double unit_conversion_coefficient_
Coeficient of conversion of user-defined unit.
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:195
#define OLD_ASSERT(...)
Definition: global_defs.h:131
FieldPython(unsigned int n_comp=0)
static FileName input()
The factory function for declaring type FileName for input files.
Definition: type_base.cc:526
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
const Ret val(const string &key) const
#define xprintf(...)
Definition: system.hh:92
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:490
Space< spacedim >::Point Point
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:215
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
Definition: system.hh:64
static Default read_time(const std::string &description)
The factory function to make an default value that will be specified at the time when a key will be r...
Definition: type_record.hh:97
Value value_
Last value, prevents passing large values (vectors) by value.
virtual ~FieldPython()
#define OLD_ASSERT_EQUAL(a, b)
Definition: global_defs.h:133
Record type proxy class.
Definition: type_record.hh:182
virtual void init_from_input(const Input::Record &rec, const struct FieldAlgoBaseInitData &init_data)
Class for declaration of the input data that are in string format.
Definition: type_base.hh:588
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
virtual Value::return_type const & value(const Point &p, const ElementAccessor< spacedim > &elm)
#define FLOW123D_FORCE_LINK_IN_CHILD(x)
Definition: global_defs.h:180