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