Flow123d  JS_before_hm-979-g397e552
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 <type_traits>
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  this->is_constant_in_space_ = false;
64 
65 #ifdef FLOW123D_HAVE_PYTHON
66  p_func_=NULL;
67  p_module_=NULL;
68  p_args_=NULL;
69  p_value_=NULL;
70 #else
71  xprintf(UsrErr, "Flow123d compiled without support for Python, FieldPython can not be used.\n");
72 #endif // FLOW123D_HAVE_PYTHON
73 }
74 
75 
76 
77 template <int spacedim, class Value>
78 void FieldPython<spacedim, Value>::set_python_field_from_string(FMT_UNUSED const string &python_source, FMT_UNUSED const string &func_name)
79 {
80 #ifdef FLOW123D_HAVE_PYTHON
81  p_module_ = PythonLoader::load_module_from_string("python_field_"+func_name, python_source);
82  set_func(func_name);
83 #endif // FLOW123D_HAVE_PYTHON
84 }
85 
86 
87 
88 
89 
90 template <int spacedim, class Value>
92  this->init_unit_conversion_coefficient(rec, init_data);
93 
94  Input::Iterator<string> it = rec.find<string>("script_string");
95  if (it) {
96  set_python_field_from_string( *it, rec.val<string>("function") );
97  } else {
98  Input::Iterator<FilePath> it = rec.find<FilePath>("script_file");
99  if (! it) xprintf(UsrErr, "Either 'script_string' or 'script_file' has to be specified in PythonField initialization.");
100  try {
101  set_python_field_from_file( *it, rec.val<string>("function") );
102  } INPUT_CATCH(FilePath::ExcFileOpen, FilePath::EI_Address_String, rec)
103  }
104 }
105 
106 
107 
108 template <int spacedim, class Value>
110 {
111 #ifdef FLOW123D_HAVE_PYTHON
112  p_module_ = PythonLoader::load_module_from_file( string(file_name) );
113  set_func(func_name);
114 #endif // FLOW123D_HAVE_PYTHON
115 }
116 
117 
118 
119 
120 template <int spacedim, class Value>
122 {
123 #ifdef FLOW123D_HAVE_PYTHON
124  p_func_ = PythonLoader::get_callable(p_module_, func_name);
125 
126  p_args_ = PyTuple_New( spacedim );
127 
128  // try field call
129  for(unsigned int i = 0; i < spacedim; i++) {
130  p_value_ = PyFloat_FromDouble( double(i) );
131  PyTuple_SetItem(p_args_, i, p_value_);
132  }
133  p_value_ = PyObject_CallObject(p_func_, p_args_);
134  PythonLoader::check_error();
135 
136  if ( ! PyTuple_Check( p_value_)) {
137  stringstream ss;
138  ss << "Field '" << func_name << "' from the python module: " << PyModule_GetName(p_module_) << " doesn't return Tuple." << endl;
139  THROW( ExcMessage() << EI_Message( ss.str() ));
140  }
141 
142  unsigned int size = PyTuple_Size( p_value_);
143 
144  unsigned int value_size=this->value_.n_rows() * this->value_.n_cols();
145  if ( size != value_size) {
146  xprintf(UsrErr, "Field '%s' from the python module: %s returns %d components but should return %d components.\n"
147  ,func_name.c_str(), PyModule_GetName(p_module_), size, value_size);
148  }
149 
150 #endif // FLOW123D_HAVE_PYTHON
151 
152 }
153 
154 /**
155  * Returns one value in one given point. ResultType can be used to avoid some costly calculation if the result is trivial.
156  */
157 template <int spacedim, class Value>
158 typename Value::return_type const & FieldPython<spacedim, Value>::value(const Point &p, const ElementAccessor<spacedim> &elm)
159 {
160  set_value(p,elm, this->value_);
161  this->value_.scale(this->unit_conversion_coefficient_);
162  return this->r_value_;
163 }
164 
165 
166 /**
167  * Returns std::vector of scalar values in several points at once.
168  */
169 template <int spacedim, class Value>
172 {
173  OLD_ASSERT_EQUAL( point_list.size(), value_list.size() );
174  ASSERT_DBG( point_list.n_rows() == spacedim && point_list.n_cols() == 1 ).error("Invalid point size.\n");
175  for(unsigned int i=0; i< point_list.size(); i++) {
176  Value envelope(value_list[i]);
177  OLD_ASSERT( envelope.n_rows()==this->value_.n_rows(),
178  "value_list[%d] has wrong number of rows: %d; should match number of components: %d\n",
179  i, envelope.n_rows(),this->value_.n_rows());
180  set_value(point_list.vec<spacedim>(i), elm, envelope );
181  envelope.scale(this->unit_conversion_coefficient_);
182  }
183 }
184 
185 /**
186 * Returns one vector value in one given point.
187 */
188 template <int spacedim, class Value>
190 {
191 #ifdef FLOW123D_HAVE_PYTHON
192  for(unsigned int i = 0; i < spacedim; i++) {
193  p_value_ = PyFloat_FromDouble( p[i] );
194  PyTuple_SetItem(p_args_, i, p_value_);
195  }
196  p_value_ = PyObject_CallObject(p_func_, p_args_);
197  PythonLoader::check_error();
198 
199  unsigned int pos =0;
200  for(unsigned int row=0; row < value.n_rows(); row++)
201  for(unsigned int col=0; col < value.n_cols(); col++, pos++)
202  if ( std::is_integral< typename Value::element_type >::value ) value(row,col) = PyLong_AsLong( PyTuple_GetItem( p_value_, pos ) );
203  else value(row,col) = PyFloat_AsDouble( PyTuple_GetItem( p_value_, pos ) );
204 
205 #endif // FLOW123D_HAVE_PYTHON
206 }
207 
208 
209 
210 
211 template <int spacedim, class Value>
213 #ifdef FLOW123D_HAVE_PYTHON
214  Py_CLEAR(p_module_);
215  Py_CLEAR(p_func_);
216  Py_CLEAR(p_value_);
217  Py_CLEAR(p_args_);
218 #endif // FLOW123D_HAVE_PYTHON
219 }
220 
221 
222 #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.
unsigned int size() const
Definition: armor.hh:718
void set_func(const string &func_name)
void set_python_field_from_string(const string &python_source, const string &func_name)
Abstract linear system class.
Definition: balance.hh:40
#define INPUT_CATCH(ExceptionType, AddressEITag, input_accessor)
Definition: accessors.hh:63
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)
uint n_cols() const
Definition: armor.hh:710
ArmaVec< Type, nr > vec(uint mat_index) const
Definition: armor.hh:807
Value::return_type r_value_
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
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:196
#define OLD_ASSERT(...)
Definition: global_defs.h:131
#define FMT_UNUSED
Definition: posix.h:75
FieldPython(unsigned int n_comp=0)
static FileName input()
The factory function for declaring type FileName for input files.
Definition: type_base.cc:524
Accessor to the data with type Type::Record.
Definition: accessors.hh:291
const Ret val(const string &key) const
#define xprintf(...)
Definition: system.hh:93
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:503
uint n_rows() const
Definition: armor.hh:705
Space< spacedim >::Point Point
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:216
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
Definition: system.hh:65
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
bool is_constant_in_space_
Flag detects that field is only dependent on time.
Value value_
Last value, prevents passing large values (vectors) by value.
virtual ~FieldPython()
#define ASSERT_DBG(expr)
#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:582
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
virtual void value_list(const Armor::array &point_list, const ElementAccessor< spacedim > &elm, std::vector< typename Value::return_type > &value_list)
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