Flow123d  last_with_con_2.0.0-4-g42e6930
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.")
38  .declare_key("script_string", it::String(), it::Default::read_time("Obligatory if 'script_file' is not given."),
39  "Python script given as in place string")
40  .declare_key("script_file", it::FileName::input(), it::Default::read_time("Obligatory if 'script_striong' is not given."),
41  "Python script given as external file")
43  "Function in the given script that returns tuple containing components of the return type.\n"
44  "For NxM tensor values: tensor(row,col) = tuple( M*row + col ).")
45  .close();
46 }
47 
48 
49 template <int spacedim, class Value>
51  Input::register_class< FieldPython<spacedim, Value>, unsigned int >("FieldPython") +
53 
54 
55 
56 template <int spacedim, class Value>
58 : FieldAlgorithmBase<spacedim, Value>( n_comp)
59 {
60 #ifdef FLOW123D_HAVE_PYTHON
61  p_func_=NULL;
62  p_module_=NULL;
63  p_args_=NULL;
64  p_value_=NULL;
65 #else
66  xprintf(UsrErr, "Flow123d compiled without support for Python, FieldPython can not be used.\n");
67 #endif // FLOW123D_HAVE_PYTHON
68 }
69 
70 
71 
72 template <int spacedim, class Value>
73 void FieldPython<spacedim, Value>::set_python_field_from_string(const string &python_source, const string &func_name)
74 {
75 #ifdef FLOW123D_HAVE_PYTHON
76  p_module_ = PythonLoader::load_module_from_string("python_field_"+func_name, python_source);
77  set_func(func_name);
78 #endif // FLOW123D_HAVE_PYTHON
79 }
80 
81 
82 
83 
84 
85 template <int spacedim, class Value>
87  Input::Iterator<string> it = rec.find<string>("script_string");
88  if (it) {
89  set_python_field_from_string( *it, rec.val<string>("function") );
90  } else {
91  Input::Iterator<FilePath> it = rec.find<FilePath>("script_file");
92  if (! it) xprintf(UsrErr, "Either 'script_string' or 'script_file' has to be specified in PythonField initialization.");
93  set_python_field_from_file( *it, rec.val<string>("function") );
94  }
95 }
96 
97 
98 
99 template <int spacedim, class Value>
100 void FieldPython<spacedim, Value>::set_python_field_from_file(const FilePath &file_name, const string &func_name)
101 {
102 #ifdef FLOW123D_HAVE_PYTHON
103  p_module_ = PythonLoader::load_module_from_file( string(file_name) );
104  set_func(func_name);
105 #endif // FLOW123D_HAVE_PYTHON
106 }
107 
108 
109 
110 
111 template <int spacedim, class Value>
112 void FieldPython<spacedim, Value>::set_func(const string &func_name)
113 {
114 #ifdef FLOW123D_HAVE_PYTHON
115  p_func_ = PythonLoader::get_callable(p_module_, func_name);
116 
117  p_args_ = PyTuple_New( spacedim );
118 
119  // try field call
120  for(unsigned int i = 0; i < spacedim; i++) {
121  p_value_ = PyFloat_FromDouble( double(i) );
122  PyTuple_SetItem(p_args_, i, p_value_);
123  }
124  p_value_ = PyObject_CallObject(p_func_, p_args_);
125  PythonLoader::check_error();
126 
127  if ( ! PyTuple_Check( p_value_)) {
128  stringstream ss;
129  ss << "Field '" << func_name << "' from the python module: " << PyModule_GetName(p_module_) << " doesn't return Tuple." << endl;
130  THROW( ExcMessage() << EI_Message( ss.str() ));
131  }
132 
133  unsigned int size = PyTuple_Size( p_value_);
134 
135  unsigned int value_size=this->value_.n_rows() * this->value_.n_cols();
136  if ( size != value_size) {
137  xprintf(UsrErr, "Field '%s' from the python module: %s returns %d components but should return %d components.\n"
138  ,func_name.c_str(), PyModule_GetName(p_module_), size, value_size);
139  }
140 
141 #endif // FLOW123D_HAVE_PYTHON
142 
143 }
144 
145 /**
146  * Returns one value in one given point. ResultType can be used to avoid some costly calculation if the result is trivial.
147  */
148 template <int spacedim, class Value>
149 typename Value::return_type const & FieldPython<spacedim, Value>::value(const Point &p, const ElementAccessor<spacedim> &elm)
150 {
151  set_value(p,elm, this->value_);
152  return this->r_value_;
153 }
154 
155 
156 /**
157  * Returns std::vector of scalar values in several points at once.
158  */
159 template <int spacedim, class Value>
162 {
163  OLD_ASSERT_EQUAL( point_list.size(), value_list.size() );
164  for(unsigned int i=0; i< point_list.size(); i++) {
165  Value envelope(value_list[i]);
166  OLD_ASSERT( envelope.n_rows()==this->value_.n_rows(),
167  "value_list[%d] has wrong number of rows: %d; should match number of components: %d\n",
168  i, envelope.n_rows(),this->value_.n_rows());
169  set_value(point_list[i], elm, envelope );
170  }
171 }
172 
173 /**
174 * Returns one vector value in one given point.
175 */
176 template <int spacedim, class Value>
178 {
179 #ifdef FLOW123D_HAVE_PYTHON
180  for(unsigned int i = 0; i < spacedim; i++) {
181  p_value_ = PyFloat_FromDouble( p[i] );
182  PyTuple_SetItem(p_args_, i, p_value_);
183  }
184  p_value_ = PyObject_CallObject(p_func_, p_args_);
185  PythonLoader::check_error();
186 
187  unsigned int pos =0;
188  for(unsigned int row=0; row < value.n_rows(); row++)
189  for(unsigned int col=0; col < value.n_cols(); col++, pos++)
190  if ( boost::is_integral< typename Value::element_type >::value ) value(row,col) = PyLong_AsLong( PyTuple_GetItem( p_value_, pos ) );
191  else value(row,col) = PyFloat_AsDouble( PyTuple_GetItem( p_value_, pos ) );
192 
193 #endif // FLOW123D_HAVE_PYTHON
194 }
195 
196 
197 
198 
199 template <int spacedim, class Value>
201 #ifdef FLOW123D_HAVE_PYTHON
202  Py_CLEAR(p_module_);
203  Py_CLEAR(p_func_);
204  Py_CLEAR(p_value_);
205  Py_CLEAR(p_args_);
206 #endif // FLOW123D_HAVE_PYTHON
207 }
208 
209 
210 #endif /* FIELD_PYTHON_IMPL_HH_ */
void set_python_field_from_file(const FilePath &file_name, const string &func_name)
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)
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:99
Iterator< Ret > find(const string &key) const
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:286
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
static FileName input()
The factory function for declaring type FileName for input files.
Definition: type_base.hh:606
FieldPython(unsigned int n_comp=0)
Accessor to the data with type Type::Record.
Definition: accessors.hh:277
const Ret val(const string &key) const
#define xprintf(...)
Definition: system.hh:87
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:468
Space< spacedim >::Point Point
Dedicated class for storing path to input and output files.
Definition: file_path.hh:48
Definition: system.hh:59
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:86
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:171
Class for declaration of the input data that are in string format.
Definition: type_base.hh:568
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:45
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
virtual void init_from_input(const Input::Record &rec)