1 // -*- C++ -*-
2 /**
3 * @brief PythonPointToFieldFunction implementation
4 *
5 * Copyright 2005-2021 Airbus-EDF-IMACS-ONERA-Phimeca
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21 #include <Python.h>
22 #include "openturns/swig_runtime.hxx"
23
24 #include "openturns/PythonPointToFieldFunction.hxx"
25 #include "openturns/OSS.hxx"
26 #include "openturns/Description.hxx"
27 #include "openturns/PythonWrappingFunctions.hxx"
28 #include "openturns/PersistentObjectFactory.hxx"
29 #include "openturns/Exception.hxx"
30
31 BEGIN_NAMESPACE_OPENTURNS
32
33 CLASSNAMEINIT(PythonPointToFieldFunction)
34
35 static const Factory<PythonPointToFieldFunction> Factory_PythonPointToFieldFunction;
36
37 /* Default constructor */
PythonPointToFieldFunction()38 PythonPointToFieldFunction::PythonPointToFieldFunction()
39 : PointToFieldFunctionImplementation()
40 , pyObj_(0)
41 {
42 // Nothing to do
43 }
44
45
46 /* Constructor from Python object*/
PythonPointToFieldFunction(PyObject * pyCallable)47 PythonPointToFieldFunction::PythonPointToFieldFunction(PyObject * pyCallable)
48 : PointToFieldFunctionImplementation()
49 , pyObj_(pyCallable)
50 {
51 Py_XINCREF(pyCallable);
52
53 // Set the name of the object as its Python classname
54 ScopedPyObjectPointer cls(PyObject_GetAttrString ( pyObj_,
55 const_cast<char *>("__class__" )));
56 ScopedPyObjectPointer name(PyObject_GetAttrString( cls.get(),
57 const_cast<char *>("__name__" )));
58 setName(convert< _PyString_, String >(name.get()));
59
60
61
62 const UnsignedInteger inputDimension = getInputDimension();
63 const UnsignedInteger outputDimension = getOutputDimension();
64 Description description(inputDimension + outputDimension);
65
66 ScopedPyObjectPointer descIn(PyObject_CallMethod( pyObj_,
67 const_cast<char *>("getInputDescription"),
68 const_cast<char *>("()")));
69 if ( descIn.get()
70 && PySequence_Check(descIn.get())
71 && (PySequence_Size(descIn.get()) == (SignedInteger)inputDimension))
72 {
73 setInputDescription(convert< _PySequence_, Description >(descIn.get()));
74 }
75 else setInputDescription(Description::BuildDefault(inputDimension, "x"));
76
77
78 ScopedPyObjectPointer descOut(PyObject_CallMethod( pyObj_,
79 const_cast<char *>("getOutputDescription" ),
80 const_cast<char *>("()")));
81 if ( descOut.get()
82 && PySequence_Check(descOut.get())
83 && (PySequence_Size(descOut.get()) == (SignedInteger)outputDimension))
84 {
85 setOutputDescription(convert< _PySequence_, Description >(descOut.get()));
86 }
87 else setOutputDescription(Description::BuildDefault(outputDimension, "y"));
88
89 ScopedPyObjectPointer outputMesh(PyObject_CallMethod ( pyObj_,
90 const_cast<char *>("getOutputMesh"),
91 const_cast<char *>("()")));
92 void * ptr = 0;
93 if (SWIG_IsOK(SWIG_ConvertPtr(outputMesh.get(), &ptr, SWIG_TypeQuery("OT::Mesh *"), 0)))
94 {
95 outputMesh_ = *reinterpret_cast< OT::Mesh * >(ptr);
96 }
97 else
98 {
99 throw InvalidArgumentException(HERE) << "getOutputMesh() does not return a Mesh";
100 }
101 }
102
103 /* Virtual constructor */
clone() const104 PythonPointToFieldFunction * PythonPointToFieldFunction::clone() const
105 {
106 return new PythonPointToFieldFunction(*this);
107 }
108
109 /* Copy constructor */
PythonPointToFieldFunction(const PythonPointToFieldFunction & other)110 PythonPointToFieldFunction::PythonPointToFieldFunction(const PythonPointToFieldFunction & other)
111 : PointToFieldFunctionImplementation(other)
112 , pyObj_()
113 {
114 ScopedPyObjectPointer pyObjClone(deepCopy(other.pyObj_));
115 pyObj_ = pyObjClone.get();
116 Py_XINCREF(pyObj_);
117 }
118
119 /* Copy assignment operator */
operator =(const PythonPointToFieldFunction & rhs)120 PythonPointToFieldFunction & PythonPointToFieldFunction::operator=(const PythonPointToFieldFunction & rhs)
121 {
122 if (this != & rhs)
123 {
124 PointToFieldFunctionImplementation::operator=(rhs);
125 ScopedPyObjectPointer pyObjClone(deepCopy(rhs.pyObj_));
126 pyObj_ = pyObjClone.get();
127 Py_XINCREF(pyObj_);
128 }
129 return *this;
130 }
131
132 /* Destructor */
~PythonPointToFieldFunction()133 PythonPointToFieldFunction::~PythonPointToFieldFunction()
134 {
135 Py_XDECREF(pyObj_);
136 }
137
138 /* Comparison operator */
operator ==(const PythonPointToFieldFunction &) const139 Bool PythonPointToFieldFunction::operator ==(const PythonPointToFieldFunction & ) const
140 {
141 return true;
142 }
143
144 /* String converter */
__repr__() const145 String PythonPointToFieldFunction::__repr__() const
146 {
147 OSS oss;
148 oss << "class=" << PythonPointToFieldFunction::GetClassName()
149 << " name=" << getName()
150 << " input description=" << getInputDescription()
151 << " output description=" << getOutputDescription();
152 return oss;
153 }
154
155 /* String converter */
__str__(const String &) const156 String PythonPointToFieldFunction::__str__(const String & ) const
157 {
158 OSS oss;
159 oss << "class=" << PythonPointToFieldFunction::GetClassName()
160 << " name=" << getName();
161 return oss;
162 }
163
164
165
166 /* Here is the interface that all derived class must implement */
167
168 /* Operator () */
operator ()(const Point & inP) const169 Sample PythonPointToFieldFunction::operator() (const Point & inP) const
170 {
171 const UnsignedInteger inputDimension = getInputDimension();
172 if (inputDimension != inP.getDimension())
173 throw InvalidDimensionException(HERE) << "Input point has incorrect dimension. Got " << inP.getDimension() << ". Expected " << getInputDimension();
174
175 callsNumber_.increment();
176
177 ScopedPyObjectPointer pyInP(SWIG_NewPointerObj(new OT::Point(inP), SWIG_TypeQuery("OT::Point *"), SWIG_POINTER_OWN | 0));
178 ScopedPyObjectPointer result(PyObject_CallFunctionObjArgs(pyObj_, pyInP.get(), NULL));
179 if (result.isNull())
180 {
181 handleException();
182 }
183
184 Sample outF;
185 try
186 {
187 outF = convert< _PySequence_, Sample >(result.get());
188 }
189 catch (InvalidArgumentException &)
190 {
191 throw InvalidArgumentException(HERE) << "Output value for " << getName() << "._exec_sample() method is not a 2d-sequence object";
192 }
193
194 const UnsignedInteger outputSize = getOutputMesh().getVerticesNumber();
195
196 if (outF.getSize() != outputSize)
197 throw InvalidArgumentException(HERE) << "Python Field function returned a sequence object with incorrect size (got "
198 << outF.getSize() << ", expected " << outputSize << ")";
199 if (outF.getDimension() != getOutputDimension())
200 throw InvalidArgumentException(HERE) << "Python Field function returned a sequence object with incorrect dimension (got "
201 << outF.getDimension() << ", expected " << getOutputDimension() << ")";
202 outF.setDescription(getOutputDescription());
203 return outF;
204 }
205
206 /* Accessor for input point dimension */
getInputDimension() const207 UnsignedInteger PythonPointToFieldFunction::getInputDimension() const
208 {
209 ScopedPyObjectPointer result(PyObject_CallMethod ( pyObj_,
210 const_cast<char *>("getInputDimension"),
211 const_cast<char *>("()")));
212 UnsignedInteger dim = convert< _PyInt_, UnsignedInteger >(result.get());
213 return dim;
214 }
215
216
217 /* Accessor for output point dimension */
getOutputDimension() const218 UnsignedInteger PythonPointToFieldFunction::getOutputDimension() const
219 {
220 ScopedPyObjectPointer result(PyObject_CallMethod (pyObj_,
221 const_cast<char *>("getOutputDimension"),
222 const_cast<char *>("()")));
223 UnsignedInteger dim = convert< _PyInt_, UnsignedInteger >(result.get());
224 return dim;
225 }
226
227
228 /* Method save() stores the object through the StorageManager */
save(Advocate & adv) const229 void PythonPointToFieldFunction::save(Advocate & adv) const
230 {
231 PointToFieldFunctionImplementation::save( adv );
232
233 pickleSave(adv, pyObj_);
234 }
235
236
237 /* Method save() reloads the object from the StorageManager */
load(Advocate & adv)238 void PythonPointToFieldFunction::load(Advocate & adv)
239 {
240 PointToFieldFunctionImplementation::load( adv );
241
242 pickleLoad(adv, pyObj_);
243 }
244
245
246 END_NAMESPACE_OPENTURNS
247