Salome HOME
3f58660fceef4369e1b2a012a2547dc64e92f6d7
[samples/calculator.git] / src / CALCULATOR / CALCULATOR.cxx
1 // Copyright (C) 2007-2019  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "CALCULATOR.hxx"
24 #include "CALCULATOR_version.h"
25
26 #include <MCAuto.hxx>
27 #include <MEDCouplingFieldDoubleClient.hxx>
28 #include <MEDCouplingFieldDoubleServant.hxx>
29 #include <MEDCouplingMemArray.hxx>
30 #include <MEDCouplingMeshClient.hxx>
31 #include <MEDCouplingMeshServant.hxx>
32
33 #include <iostream>
34
35 /*!
36   \brief Constructor
37   \param orb Reference to CORBA ORB 
38   \param poa Reference to Root POA
39   \param contId Parent SALOME container ID
40   \param instanceName Instance name of this engine
41   \param interfaceName Interface name of this engine
42 */
43 CALCULATOR::CALCULATOR( CORBA::ORB_ptr orb,
44                         PortableServer::POA_ptr poa,
45                         PortableServer::ObjectId* contId, 
46                         const char* instanceName, 
47                         const char* interfaceName )
48   : Engines_Component_i( orb, poa, contId, instanceName, interfaceName, true ),
49     _errorCode( CALCULATOR_ORB::RES_OK )
50 {
51   _thisObj = this;
52   _id = _poa->activate_object( _thisObj );
53 }
54
55 /*!
56   \brief Destructor
57 */
58 CALCULATOR::~CALCULATOR()
59 {
60 }
61
62 /*!
63   \brief Get Euclidian norm of field
64   \param field Input field
65   \return Euclidian norm value
66 */
67 CORBA::Double CALCULATOR::norm2( SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr field )
68 {
69   beginService( "CALCULATOR::norm2" );
70   _errorCode = CALCULATOR_ORB::RES_OK;
71         
72   if ( CORBA::is_nil( field ) )
73   {
74     _errorCode = CALCULATOR_ORB::INVALID_FIELD;
75     return 0.0;
76   }
77
78   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> f1 =
79     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
80
81   CORBA::Double norme = 0.0;
82
83   try
84   {
85     norme = f1->norm2();
86   }    
87   catch (...)
88   {
89     _errorCode = CALCULATOR_ORB::EXCEPTION_RAISED;
90   }
91   
92   endService( "CALCULATOR::norm2" );
93   return norme;
94 }
95
96 /*!
97   \brief Get L2 norm of field
98   \param field Input field
99   \return L2 norm value
100 */
101 CORBA::Double CALCULATOR::normL2( SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr field )
102 {
103   beginService( "CALCULATOR::normL2" );
104   _errorCode = CALCULATOR_ORB::RES_OK;
105
106   if ( CORBA::is_nil( field ) )
107   {
108     _errorCode = CALCULATOR_ORB::INVALID_FIELD;
109     return 0.0;
110   }
111
112   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> f1 =
113     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
114   
115   // Check that the source field is not on the nodes (a limitation of normL2)
116   if ( f1->getTypeOfField() == MEDCoupling::ON_NODES)
117   {
118     _errorCode = CALCULATOR_ORB::NOT_COMPATIBLE;
119     return 0.0;
120   }
121         
122   CORBA::Double norme = 0.0;
123
124   try
125   {
126     norme = f1->normL2( 0 );
127   }    
128   catch (...)
129   {
130     _errorCode = CALCULATOR_ORB::EXCEPTION_RAISED;
131   }
132   
133   endService( "CALCULATOR::normL2" );
134   return norme;
135 }
136
137 /*!
138   \brief Get max norm of field
139   \param field Input field
140   \return Max norm value
141 */
142 CORBA::Double CALCULATOR::normMax( SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr field )
143 {
144   beginService( "CALCULATOR::normMax" );
145   _errorCode = CALCULATOR_ORB::RES_OK;
146          
147   if ( CORBA::is_nil( field ) )
148   {
149     _errorCode = CALCULATOR_ORB::INVALID_FIELD;
150     return 0.0;
151   }
152   
153   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> f1 =
154     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
155
156   CORBA::Double norme = 0.0;
157
158   try
159   {
160     norme = f1->normMax( 0 );
161   }
162   catch (...)
163   {
164     _errorCode = CALCULATOR_ORB::EXCEPTION_RAISED;
165   }
166  
167   endService( "CALCULATOR::normMax" );
168   return norme;
169 }
170
171 /*!
172   \brief Get L1 norm of field
173   \param field Input field
174   \return L1 norm value
175 */
176 CORBA::Double CALCULATOR::normL1( SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr field )
177 {
178   beginService( "CALCULATOR::normL1" );
179   _errorCode = CALCULATOR_ORB::RES_OK;
180
181   if ( CORBA::is_nil( field ) )
182   {
183     _errorCode = CALCULATOR_ORB::INVALID_FIELD;
184     return 0.0;
185   }
186
187   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> f1 =
188     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
189
190   // Check that the source field is not on the nodes (a limitation of normL1)
191   if ( f1->getTypeOfField() == MEDCoupling::ON_NODES ) {
192     _errorCode = CALCULATOR_ORB::NOT_COMPATIBLE;
193     return 0.0;
194   }       
195   
196   CORBA::Double norme = 0.0;
197   try
198   {
199     norme = f1->normL1( 0 );
200   }
201   catch (...)
202   {
203     _errorCode = CALCULATOR_ORB::EXCEPTION_RAISED;
204   }
205
206   endService( "CALCULATOR::normL1" );
207   return norme;
208 }
209
210 /*!
211   \brief Apply to each (scalar) field component the linear function x -> ax+b
212   \param field Input field
213   \param a First coefficient of linear function
214   \param b Second coefficient of linear function
215   \return Resulting field
216 */
217 SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr CALCULATOR::applyLin( SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr field,
218                                                                            CORBA::Double a, CORBA::Double b )
219 {
220   beginService( "CALCULATOR::applyLin" );
221   _errorCode = CALCULATOR_ORB::RES_OK;
222     
223   if ( CORBA::is_nil( field ) )
224   {
225     _errorCode = CALCULATOR_ORB::INVALID_FIELD;
226     return NULL;
227   }
228
229   // Create a local field on the heap, because it has to remain after exiting the function
230   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> f1 =
231     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
232
233   int nbOfCompo = f1->getArray()->getNumberOfComponents();
234   f1->getArray()->rearrange(1);
235   MEDCoupling::MEDCouplingFieldDoubleServant* NewField = NULL;
236   SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr myFieldIOR;
237
238   try
239   {
240     f1->applyLin( a, b, 0 );
241     f1->getArray()->rearrange( nbOfCompo );
242     // Create servant from f1, give it the property of c++ field (parameter true).
243     // This implies that when the client will release it's field, it will delete NewField,
244     // and f1 too.
245     NewField = new MEDCoupling::MEDCouplingFieldDoubleServant( f1 );
246     // Activate servant
247     myFieldIOR = NewField->_this();
248   }
249   catch (...)
250   {
251     _errorCode = CALCULATOR_ORB::EXCEPTION_RAISED;
252   }
253   
254   endService( "CALCULATOR::applyLin" );
255   return myFieldIOR;
256 }
257
258 /*!
259   \brief Sum two fields
260   \param field1 First input field
261   \param field2 Second input field
262   \return Resulting field
263 */
264 SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr CALCULATOR::add( SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr field1,
265                                                                       SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr field2 )
266 {
267   beginService( "CALCULATOR::add" );
268   _errorCode = CALCULATOR_ORB::RES_OK;
269
270   if ( CORBA::is_nil( field1 ) || CORBA::is_nil( field2 ) )
271   {
272     _errorCode = CALCULATOR_ORB::INVALID_FIELD;
273     return NULL;
274   }
275   
276   // Create local fields from source corba fields
277   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> f1 =
278     MEDCoupling::MEDCouplingFieldDoubleClient::New( field1 );
279   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> f2 =
280     MEDCoupling::MEDCouplingFieldDoubleClient::New( field2 );
281     
282   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> fres;
283   
284   try
285   {
286     f2->changeUnderlyingMesh( f1->getMesh(), 0, 1e-12 );
287     fres = (*f1) + (*f2);
288   }
289   catch ( INTERP_KERNEL::Exception )
290   {
291     _errorCode = CALCULATOR_ORB::NOT_COMPATIBLE;
292     return NULL;
293   }
294
295   // Create CORBA field from c++ field fres; give property to servant (true).
296   MEDCoupling::MEDCouplingFieldDoubleServant* myFieldDoubleI = new MEDCoupling::MEDCouplingFieldDoubleServant( fres );
297   // Activate servant
298   SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr myFieldIOR = myFieldDoubleI->_this();
299
300   endService( "CALCULATOR::add" );
301   return myFieldIOR;
302 }
303
304 /*!
305   \brief Clone source field into four copies
306   \param field Input field
307   \param clone1 First resulting clone field
308   \param clone2 Second resulting clone field
309   \param clone3 Third resulting clone field
310   \param clone4 Fourth resulting clone field
311 */
312 void CALCULATOR::cloneField( SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr field,
313                              SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_out clone1,
314                              SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_out clone2,
315                              SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_out clone3,
316                              SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_out clone4 )
317 {
318   beginService( "CALCULATOR::cloneField" );
319   _errorCode = CALCULATOR_ORB::RES_OK;
320
321   if ( CORBA::is_nil( field ) )
322   {
323     _errorCode = CALCULATOR_ORB::INVALID_FIELD;
324     return;
325   }
326   
327   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> f =
328     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
329
330   // Create four c++ fields on the heap by copying source field.
331   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> fc1 =
332     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
333   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> fc2 =
334     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
335   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> fc3 =
336     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
337   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> fc4 =
338     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
339     
340   // Initialize out references: 
341   // Create CORBA clones from c++ fields - give property of c++ fields to servant (true)
342   MEDCoupling::MEDCouplingFieldDoubleServant* myClone1 = new MEDCoupling::MEDCouplingFieldDoubleServant( fc1 );
343   MEDCoupling::MEDCouplingFieldDoubleServant* myClone2 = new MEDCoupling::MEDCouplingFieldDoubleServant( fc2 );
344   MEDCoupling::MEDCouplingFieldDoubleServant* myClone3 = new MEDCoupling::MEDCouplingFieldDoubleServant( fc3 );
345   MEDCoupling::MEDCouplingFieldDoubleServant* myClone4 = new MEDCoupling::MEDCouplingFieldDoubleServant( fc4 );
346   // Activate servants
347   clone1 = myClone1->_this();
348   clone2 = myClone2->_this();
349   clone3 = myClone3->_this();
350   clone4 = myClone4->_this();
351
352   endService( "CALCULATOR::cloneField" );
353 }
354
355 /*!
356   \brief Print out the coordinates and field values to standard output
357   \param field Input field
358 */
359 void CALCULATOR::printField( SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr field )
360 {
361   beginService( "CALCULATOR::printField" );
362   _errorCode = CALCULATOR_ORB::RES_OK;
363
364   if ( CORBA::is_nil( field ) )
365   {
366     _errorCode = CALCULATOR_ORB::INVALID_FIELD;
367     return;
368   }
369
370   // Create a local field from source corba field.
371   // Use auto_ptr to perform automatic deletion after usage.
372   // The deletion of the client object will delete the remote corba object.
373   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> myField =
374     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
375
376   std::cout << myField->advancedRepr(); 
377   std::cout << std::endl;
378   std::cout << "Euclidian norm: " << myField->norm2() << std::endl;
379   std::cout << "Max norm:       " << myField->normMax( 0 ) << std::endl;
380   std::cout << "------------------------------------------------------------------------" << std::endl << std::endl;
381
382   endService( "CALCULATOR::printField" );
383 }
384
385 /*!
386   \brief Calculate maximum relative difference of field with the previous one
387   \param field Input field
388   \return Convergence criterion value
389 */
390 CORBA::Double CALCULATOR::convergenceCriteria( SALOME_MED::MEDCouplingFieldDoubleCorbaInterface_ptr field )
391 {
392   beginService( "CALCULATOR::convergenceCriteria" );
393   _errorCode = CALCULATOR_ORB::RES_OK;
394
395   if ( CORBA::is_nil( field ) )
396   {
397     _errorCode = CALCULATOR_ORB::INVALID_FIELD;
398     return 0.0;
399   }
400   
401   double criteria = 1;
402   static MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> fold;
403   MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> fnew =
404     MEDCoupling::MEDCouplingFieldDoubleClient::New( field );
405
406   try
407   {
408     if ( (MEDCoupling::MEDCouplingFieldDouble*)fold == NULL )
409     {
410       // if old field is not set, set it and return 1
411       fold = fnew;
412     }
413     else
414     {
415       // if size of fields are not equal, return 1
416       // catch exception for non compatible fields
417       MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> fres;
418       try
419       {
420         fnew->changeUnderlyingMesh( fold->getMesh(), 0, 1e-12 );
421         fres = (*fnew) - (*fold);
422         criteria = fres->normMax( 0 );
423       }
424       catch ( INTERP_KERNEL::Exception )
425       {
426         _errorCode = CALCULATOR_ORB::NOT_COMPATIBLE;
427       }
428     }
429   }
430   catch (...)
431   {
432     _errorCode = CALCULATOR_ORB::EXCEPTION_RAISED;
433   }
434   
435   endService( "CALCULATOR::convergenceCriteria" );
436   return criteria;
437 }
438
439 /*!
440   \brief Get last operation status
441   \return Last operation status: \c true if last operation succeded or \c false otherwise
442 */
443 CORBA::Boolean CALCULATOR::isDone()
444 {
445   return (_errorCode == CALCULATOR_ORB::RES_OK );
446 }
447
448 /*!
449   \brief Get last operation status
450   \return Last error code
451 */
452 CALCULATOR_ORB::ErrorCode CALCULATOR::getErrorCode()
453 {
454   return _errorCode;
455 }
456
457 /*!
458   \brief Get version information
459   \return Version of CALCULATOR engine
460 */
461 char* CALCULATOR::getVersion()
462 {
463 #if defined(CALCULATOR_DEVELOPMENT)
464   return CORBA::string_dup( CALCULATOR_VERSION_STR"dev" );
465 #else
466   return CORBA::string_dup( CALCULATOR_VERSION_STR );
467 #endif
468 }
469
470 extern "C"
471 {
472   CALCULATORENGINE_EXPORT
473   PortableServer::ObjectId* CALCULATOREngine_factory( CORBA::ORB_ptr orb,
474                                                       PortableServer::POA_ptr poa,
475                                                       PortableServer::ObjectId* contId,
476                                                       const char* instanceName,
477                                                       const char* interfaceName )
478   {
479     CALCULATOR* myCALCULATOR = new CALCULATOR( orb, poa, contId, instanceName, interfaceName );
480     return myCALCULATOR->getId();
481   }
482 }
483