Flow123d  3.9.0-3aaaea010
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>
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  THROW( ExcNoPythonSupport() );
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) THROW( ExcNoPythonInit() );
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  THROW( ExcInvalidCompNumber() << EI_FuncName(func_name) << EI_PModule(PyModule_GetName(p_module_)) << EI_Size(size) << EI_ValueSize(value_size) );
147  }
148 
149 #endif // FLOW123D_HAVE_PYTHON
150 
151 }
152 
153 /**
154  * Returns one value in one given point. ResultType can be used to avoid some costly calculation if the result is trivial.
155  */
156 template <int spacedim, class Value>
157 typename Value::return_type const & FieldPython<spacedim, Value>::value(const Point &p, const ElementAccessor<spacedim> &elm)
158 {
159  set_value(p,elm, this->value_);
160  this->value_.scale(this->unit_conversion_coefficient_);
161  return this->r_value_;
162 }
163 
164 
165 /**
166  * Returns std::vector of scalar values in several points at once.
167  */
168 template <int spacedim, class Value>
171 {
172  ASSERT_EQ( point_list.size(), value_list.size() );
173  ASSERT( point_list.n_rows() == spacedim && point_list.n_cols() == 1 ).error("Invalid point size.\n");
174  for(unsigned int i=0; i< point_list.size(); i++) {
175  Value envelope(value_list[i]);
176  ASSERT_EQ( envelope.n_rows(), this->value_.n_rows() )(i)
177  .error("value_list[i] has wrong number of rows\n");
178  set_value(point_list.vec<spacedim>(i), elm, envelope );
179  envelope.scale(this->unit_conversion_coefficient_);
180  }
181 }
182 
183 /**
184 * Returns one vector value in one given point.
185 */
186 template <int spacedim, class Value>
188 {
189 #ifdef FLOW123D_HAVE_PYTHON
190  for(unsigned int i = 0; i < spacedim; i++) {
191  p_value_ = PyFloat_FromDouble( p[i] );
192  PyTuple_SetItem(p_args_, i, p_value_);
193  }
194  p_value_ = PyObject_CallObject(p_func_, p_args_);
195  PythonLoader::check_error();
196 
197  unsigned int pos =0;
198  for(unsigned int row=0; row < value.n_rows(); row++)
199  for(unsigned int col=0; col < value.n_cols(); col++, pos++)
200  if ( std::is_integral< typename Value::element_type >::value ) value(row,col) = PyLong_AsLong( PyTuple_GetItem( p_value_, pos ) );
201  else value(row,col) = PyFloat_AsDouble( PyTuple_GetItem( p_value_, pos ) );
202 
203 #endif // FLOW123D_HAVE_PYTHON
204 }
205 
206 
207 
208 
209 template <int spacedim, class Value>
211 #ifdef FLOW123D_HAVE_PYTHON
212  Py_CLEAR(p_module_);
213  Py_CLEAR(p_func_);
214  Py_CLEAR(p_value_);
215  Py_CLEAR(p_args_);
216 #endif // FLOW123D_HAVE_PYTHON
217 }
218 
219 
220 #endif /* FIELD_PYTHON_IMPL_HH_ */
FieldPython::init_from_input
virtual void init_from_input(const Input::Record &rec, const struct FieldAlgoBaseInitData &init_data)
Definition: field_python.impl.hh:91
field_python.hh
ASSERT
#define ASSERT(expr)
Definition: asserts.hh:351
FieldPython::set_func
void set_func(const string &func_name)
Definition: field_python.impl.hh:121
FieldPython::set_python_field_from_string
void set_python_field_from_string(const string &python_source, const string &func_name)
Definition: field_python.impl.hh:78
Input::Record::val
const Ret val(const string &key) const
Definition: accessors_impl.hh:31
Armor::Array::vec
ArmaVec< Type, nr > vec(uint mat_index) const
Definition: armor.hh:821
value
static constexpr bool value
Definition: json.hpp:87
FilePath
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
FieldPython::set_value
void set_value(const Point &p, const ElementAccessor< spacedim > &elm, Value &value)
Definition: field_python.impl.hh:187
FLOW123D_FORCE_LINK_IN_CHILD
#define FLOW123D_FORCE_LINK_IN_CHILD(x)
Definition: global_defs.h:104
THROW
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
FieldAlgorithmBase::is_constant_in_space_
bool is_constant_in_space_
Flag detects that field is only dependent on time.
Definition: field_algo_base.hh:289
std::vector
Definition: doxy_dummy_defs.hh:7
Input::Type::Default::read_time
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
ElementAccessor
Definition: dh_cell_accessor.hh:32
FieldAlgorithmBase::Point
Space< spacedim >::Point Point
Definition: field_algo_base.hh:115
Armor::Array::n_rows
uint n_rows() const
Definition: armor.hh:715
Input::Iterator
Definition: accessors.hh:143
Input::Type::Record::derive_from
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:196
FieldPython::get_input_type
static const Input::Type::Record & get_input_type()
Implementation.
Definition: field_python.impl.hh:34
Input::Record
Accessor to the data with type Type::Record.
Definition: accessors.hh:291
FieldAlgoBaseInitData
Helper struct stores data for initizalize descentants of FieldAlgorithmBase.
Definition: field_algo_base.hh:81
INPUT_CATCH
#define INPUT_CATCH(ExceptionType, AddressEITag, input_accessor)
Definition: accessors.hh:63
Input::Type::Default::obligatory
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
ASSERT_EQ
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:333
Input::Type::Record::declare_key
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
FieldPython::FieldPython
FieldPython(unsigned int n_comp=0)
Definition: field_python.impl.hh:60
Input::Record::find
Iterator< Ret > find(const string &key) const
Definition: accessors_impl.hh:91
Armor::Array::n_cols
uint n_cols() const
Definition: armor.hh:720
Input::Type::FileName::input
static FileName input()
The factory function for declaring type FileName for input files.
Definition: type_base.cc:524
Input::Type::Record::close
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
Armor::Array::size
unsigned int size() const
Definition: armor.hh:728
Input::Type
Definition: balance.hh:41
Input::Type::Record
Record type proxy class.
Definition: type_record.hh:182
Value
@ Value
Definition: finite_element.hh:43
FieldPython
Definition: field_python.hh:46
Input::Type::Record::copy_keys
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:216
FieldAlgorithmBase
Definition: field_algo_base.hh:112
Input::Type::String
Class for declaration of the input data that are in string format.
Definition: type_base.hh:582
Armor::Array< double >
FieldPython::value
virtual const Value::return_type & value(const Point &p, const ElementAccessor< spacedim > &elm)
Definition: field_python.impl.hh:157
FieldPython::set_python_field_from_file
void set_python_field_from_file(const FilePath &file_name, const string &func_name)
Definition: field_python.impl.hh:109
FieldPython::value_list
virtual void value_list(const Armor::array &point_list, const ElementAccessor< spacedim > &elm, std::vector< typename Value::return_type > &value_list)
Definition: field_python.impl.hh:169
FieldPython::~FieldPython
virtual ~FieldPython()
Definition: field_python.impl.hh:210
FMT_UNUSED
#define FMT_UNUSED
Definition: posix.h:75