Salome HOME
d8f4ca7cb536811e257b42fa0a3f342755a0511d
[modules/med.git] / src / MEDCalc / cmp / MEDCalculator_i.cxx
1 // Copyright (C) 2011-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // Authors : Guillaume Boulant (EDF) - 01/06/2011
21
22 #include "MEDCalculator_i.hxx"
23 #include "SALOME_KernelServices.hxx"
24 #include "Basics_Utils.hxx"
25 #include <string>
26
27 #include "MEDCouplingFieldDouble.hxx"
28 using namespace MEDCoupling;
29
30 MEDCalculator_i * MEDCalculator_i::_instance = NULL;
31
32 MEDCalculator_i * MEDCalculator_i::getInstance() {
33   if ( _instance == NULL ) {
34     _instance = new MEDCalculator_i();
35   }
36   return _instance;
37 }
38
39 MEDCalculator_i::MEDCalculator_i()
40 {
41   LOG("Creating a MEDCalculator_i instance");
42   _medDataManager = MEDDataManager_i::getInstance();
43 }
44
45 MEDCalculator_i::~MEDCalculator_i()
46 {
47   LOG("Deleting MEDCalculator_i instance");
48 }
49
50 /*!
51  * This function realizes the addition of the MEDCoupling field
52  * objects identified by the FieldHandler objects passed in arguments.
53  *
54  * It returns a FieldHandler that identifies the resulting MEDCoupling
55  * field object. The resulting MEDCoupling field object is physically
56  * in the SALOME MED container and is automatically registered in the
57  * MEDDataManager.
58  */
59 MEDCALC::FieldHandler * MEDCalculator_i::add(const MEDCALC::FieldHandler & f1_hdl,
60              const MEDCALC::FieldHandler & f2_hdl)
61 {
62   // We first check that both operands share the same mesh id. Note
63   // that it's not strictly required because the MEDCoupling operation
64   // would raise an exception if the fields does not share the same
65   // mesh support.
66   if ( f1_hdl.meshid != f2_hdl.meshid ) {
67     std::string message =
68       std::string("ERROR: Mesh ids are different for the field operands ") +
69       std::string(f1_hdl.fieldname) + std::string(" and ") + std::string(f2_hdl.fieldname);
70     throw KERNEL::createSalomeException(message.c_str());
71   }
72
73   MEDCouplingFieldDouble* f1 = _medDataManager->getFieldDouble(&f1_hdl);
74   MEDCouplingFieldDouble* f2 = _medDataManager->getFieldDouble(&f2_hdl);
75
76   MEDCouplingFieldDouble* field_result;
77   // This operation could raise an INTERP_KERNEL exception, for
78   // example, if the fields are not defined on the same support.
79   try {
80     field_result = (*f1) + (*f2);
81   }
82   catch (INTERP_KERNEL::Exception &ex) {
83     throw KERNEL::createSalomeException(ex.what());
84   }
85
86   std::string name = std::string(f1->getName()) + "+" + std::string(f2->getName());
87   field_result->setName(name.c_str());
88
89   //
90   // The field must be registered in the dataManager structure so
91   // that it could be reused in a future operation (in particular for
92   // a manipulation that combine several operation as "r = f1+f2+f3",
93   // the operator will try to make the addition f1+f2 and then
94   // resultof(f1+f2) + f3. This last operation will fail if the field
95   // resultof(f1+f2) is not in the dataManager structure).
96   //
97   // Note that we choose arbitrary the first field operande to get the
98   // meshid (both have the same meshid).
99   //
100   long meshHandlerId = f1_hdl.meshid;
101   MEDCALC::FieldHandler * fieldResultHandler = _medDataManager->addField(field_result,
102                        meshHandlerId);
103
104   // >>>>>>>>>
105   // _GBO_ We should test here if the iteration and order of the input
106   // files are identical for both operands. A convention has to be
107   // defined here. By default, we let the iteration and order be
108   // determined by the resulting MEDCouplingFieldDouble instance (see
109   // function addField of the data manager).
110   // <<<<<<<<<
111
112   return fieldResultHandler;
113 }
114
115 /*!
116  * This function realizes the substraction of the MEDCoupling field
117  * objects identified by the FieldHandler objects passed in arguments.
118  *
119  * It returns a FieldHandler that identifies the resulting MEDCoupling
120  * field object. The resulting MEDCoupling field object is physically
121  * in the SALOME MED container and is automatically registered in the
122  * MEDDataManager.
123  */
124 MEDCALC::FieldHandler * MEDCalculator_i::sub(const MEDCALC::FieldHandler & f1_hdl,
125              const MEDCALC::FieldHandler & f2_hdl)
126 {
127   if ( f1_hdl.meshid != f2_hdl.meshid ) {
128     std::string message =
129       std::string("ERROR: Mesh ids are different for the field operands ") +
130       std::string(f1_hdl.fieldname) + std::string(" and ") + std::string(f2_hdl.fieldname);
131     throw KERNEL::createSalomeException(message.c_str());
132   }
133
134   MEDCouplingFieldDouble* f1 = _medDataManager->getFieldDouble(&f1_hdl);
135   MEDCouplingFieldDouble* f2 = _medDataManager->getFieldDouble(&f2_hdl);
136
137   MEDCouplingFieldDouble* field_result;
138   try {
139     field_result = (*f1) - (*f2);
140   }
141   catch (INTERP_KERNEL::Exception &ex) {
142     throw KERNEL::createSalomeException(ex.what());
143   }
144
145   std::string name = std::string(f1->getName()) + "-" + std::string(f2->getName());
146   field_result->setName(name.c_str());
147
148   long meshHandlerId = f1_hdl.meshid;
149   MEDCALC::FieldHandler * fieldResultHandler = _medDataManager->addField(field_result,
150                        meshHandlerId);
151   return fieldResultHandler;
152 }
153
154 /*!
155  * This function realizes the multiplication of the MEDCoupling field
156  * objects identified by the FieldHandler objects passed in arguments.
157  *
158  * It returns a FieldHandler that identifies the resulting MEDCoupling
159  * field object. The resulting MEDCoupling field object is physically
160  * in the SALOME MED container and is automatically registered in the
161  * MEDDataManager.
162  */
163 MEDCALC::FieldHandler * MEDCalculator_i::mul(const MEDCALC::FieldHandler & f1_hdl,
164              const MEDCALC::FieldHandler & f2_hdl)
165 {
166   if ( f1_hdl.meshid != f2_hdl.meshid ) {
167     std::string message =
168       std::string("ERROR: Mesh ids are different for the field operands ") +
169       std::string(f1_hdl.fieldname) + std::string(" and ") + std::string(f2_hdl.fieldname);
170     throw KERNEL::createSalomeException(message.c_str());
171   }
172
173   MEDCouplingFieldDouble* f1 = _medDataManager->getFieldDouble(&f1_hdl);
174   MEDCouplingFieldDouble* f2 = _medDataManager->getFieldDouble(&f2_hdl);
175
176   MEDCouplingFieldDouble* field_result;
177   try {
178     field_result = (*f1) * (*f2);
179   }
180   catch (INTERP_KERNEL::Exception &ex) {
181     throw KERNEL::createSalomeException(ex.what());
182   }
183   std::string name = std::string(f1->getName()) + "*" + std::string(f2->getName());
184   field_result->setName(name.c_str());
185
186   long meshHandlerId = f1_hdl.meshid;
187   MEDCALC::FieldHandler * fieldResultHandler = _medDataManager->addField(field_result,
188                        meshHandlerId);
189   return fieldResultHandler;
190 }
191
192 /*!
193  * This function realizes the division of the MEDCoupling field
194  * objects identified by the FieldHandler objects passed in arguments.
195  *
196  * It returns a FieldHandler that identifies the resulting MEDCoupling
197  * field object. The resulting MEDCoupling field object is physically
198  * in the SALOME MED container and is automatically registered in the
199  * MEDDataManager.
200  */
201 MEDCALC::FieldHandler * MEDCalculator_i::div(const MEDCALC::FieldHandler & f1_hdl,
202              const MEDCALC::FieldHandler & f2_hdl)
203 {
204   if ( f1_hdl.meshid != f2_hdl.meshid ) {
205     std::string message =
206       std::string("ERROR: Mesh ids are different for the field operands ") +
207       std::string(f1_hdl.fieldname) + std::string(" and ") + std::string(f2_hdl.fieldname);
208     throw KERNEL::createSalomeException(message.c_str());
209   }
210
211   MEDCouplingFieldDouble* f1 = _medDataManager->getFieldDouble(&f1_hdl);
212   MEDCouplingFieldDouble* f2 = _medDataManager->getFieldDouble(&f2_hdl);
213
214   MEDCouplingFieldDouble* field_result;
215   try {
216     field_result = (*f1) / (*f2);
217   }
218   catch (INTERP_KERNEL::Exception &ex) {
219     throw KERNEL::createSalomeException(ex.what());
220   }
221
222   std::string name = std::string(f1->getName()) + "/" + std::string(f2->getName());
223   field_result->setName(name.c_str());
224
225   long meshHandlerId = f1_hdl.meshid;
226   MEDCALC::FieldHandler * fieldResultHandler = _medDataManager->addField(field_result,
227                        meshHandlerId);
228   return fieldResultHandler;
229 }
230
231 /*!
232  * This function realizes the power of the MEDCoupling field
233  * object identified by the FieldHandler object passed in argument.
234  *
235  * It returns a FieldHandler that identifies the resulting MEDCoupling
236  * field object. The resulting MEDCoupling field object is physically
237  * in the SALOME MED container and is automatically registered in the
238  * MEDDataManager.
239  */
240 MEDCALC::FieldHandler * MEDCalculator_i::pow(const MEDCALC::FieldHandler & f_hdl, CORBA::Long power)
241 {
242   MEDCouplingFieldDouble* field = _medDataManager->getFieldDouble(&f_hdl);
243
244   // We use the applyFunc function to execute this operation. The
245   // applyFunc function modifies the original field (that is not what
246   // we want). So we have first to make a deep copy.
247   MEDCouplingFieldDouble* field_result;
248   try {
249     field_result = field->clone(true);
250     std::string functionToApply = "u^"+ToString(power);
251     field_result->applyFunc(functionToApply.c_str());
252   }
253   catch (INTERP_KERNEL::Exception &ex) {
254     throw KERNEL::createSalomeException(ex.what());
255   }
256
257   // Set the name (the default is the same as the original field)
258   std::string name(field_result->getName());
259   name.append("^");
260   name.append(ToString(power));
261   field_result->setName(name.c_str());
262
263   long meshHandlerId = f_hdl.meshid;
264   MEDCALC::FieldHandler * fieldResultHandler = _medDataManager->addField(field_result,
265                        meshHandlerId);
266   return fieldResultHandler;
267 }
268
269 /*!
270  * This function creates a new field as the linear transformation of
271  * the field object identified by the FieldHandler in argument. The
272  * transformation is y= factor*x + offset.
273  *
274  * It returns a FieldHandler that identifies the resulting MEDCoupling
275  * field object. The resulting MEDCoupling field object is physically
276  * in the SALOME MED container and is automatically registered in the
277  * MEDDataManager.
278  */
279 MEDCALC::FieldHandler * MEDCalculator_i::lin(const MEDCALC::FieldHandler & f_hdl, double factor, double offset)
280 {
281   MEDCouplingFieldDouble* field = _medDataManager->getFieldDouble(&f_hdl);
282
283   // We use the applyFunc function to execute this operation. The
284   // applyFunc function modifies the original field (that is not what
285   // we want). So we have first to make a deep copy.
286   MEDCouplingFieldDouble* field_result;
287   try {
288     field_result = field->clone(true);
289     std::string functionToApply = "u*"+ToString(factor)+"+"+ToString(offset);
290     field_result->applyFunc(functionToApply.c_str());
291   }
292   catch (INTERP_KERNEL::Exception &ex) {
293     throw KERNEL::createSalomeException(ex.what());
294   }
295
296   // Set the name (the default is the same as the original field)
297   std::string name = std::string("lin(");
298   name.append(field->getName());
299   name.append(",factor=");
300   name.append(ToString(factor));
301   name.append(",offset=");
302   name.append(ToString(offset));
303   name.append(")");
304   field_result->setName(name.c_str());
305
306   long meshHandlerId = f_hdl.meshid;
307   MEDCALC::FieldHandler * fieldResultHandler = _medDataManager->addField(field_result,
308                        meshHandlerId);
309   return fieldResultHandler;
310
311 }
312
313 /*!
314  * This function creates a new field as the duplicate of the field
315  * object identified by the FieldHandler in argument.
316  *
317  * It returns a FieldHandler that identifies the resulting MEDCoupling
318  * field object. The resulting MEDCoupling field object is physically
319  * in the SALOME MED container and is automatically registered in the
320  * MEDDataManager.
321  */
322 MEDCALC::FieldHandler * MEDCalculator_i::dup(const MEDCALC::FieldHandler & f_hdl)
323 {
324   MEDCouplingFieldDouble* field = _medDataManager->getFieldDouble(&f_hdl);
325
326   // We just make a deep copy of the input field
327   MEDCouplingFieldDouble* field_result;
328   try {
329     field_result = field->clone(true);
330   }
331   catch (INTERP_KERNEL::Exception &ex) {
332     throw KERNEL::createSalomeException(ex.what());
333   }
334
335   // Set the name (the default is the same as the original field)
336   std::string name = std::string("dup(");
337   name.append(field->getName());
338   name.append(")");
339   field_result->setName(name.c_str());
340
341   long meshHandlerId = f_hdl.meshid;
342   MEDCALC::FieldHandler * fieldResultHandler = _medDataManager->addField(field_result,
343                        meshHandlerId);
344   return fieldResultHandler;
345 }
346
347 /*!
348  * This creates a new field by applying a function on the specified
349  * field. The function is defined by a string of characters
350  * (function), that specifies the literal equation to apply, and an
351  * integer (nbcomponents), that specifies the number of components to
352  * consider in the resulting field. This is to mimic the interface of
353  * MEDCouplingFieldDouble::applyFunc.
354  * Note that if nbcomponents is not in the range 1..N where N is the
355  * number of components of the specified field, then the function is
356  * apply on the whole field (as if specified N=numberOfComponents).
357  */
358 MEDCALC::FieldHandler * MEDCalculator_i::fct(const MEDCALC::FieldHandler & f_hdl,
359              const char * function, CORBA::Long nbResComponents)
360 {
361   MEDCouplingFieldDouble* field = _medDataManager->getFieldDouble(&f_hdl);
362
363   // We first make a deep copy of the input field
364   MEDCouplingFieldDouble* field_result;
365   try {
366     field_result = field->clone(true);
367     if ( (nbResComponents == MEDCALC::NBCOMP_DEFAULT ) ||
368          (nbResComponents < 1) || (nbResComponents > (int)field_result->getNumberOfComponents()) ) {
369       field_result->applyFunc(function);
370     }
371     else {
372       field_result->applyFunc(nbResComponents,function);
373     }
374   }
375   catch (INTERP_KERNEL::Exception &ex) {
376     throw KERNEL::createSalomeException(ex.what());
377   }
378
379   std::string name = std::string("fct("); name.append(field->getName());
380   name.append(",\""); name.append(function);
381   name.append(",\""); name.append(ToString(nbResComponents)); name.append("\")");
382   field_result->setName(name.c_str());
383
384   long meshHandlerId = f_hdl.meshid;
385   MEDCALC::FieldHandler * fieldResultHandler = _medDataManager->addField(field_result,
386                        meshHandlerId);
387   return fieldResultHandler;
388 }