Salome HOME
Update copyrights
[modules/med.git] / src / MEDCalc / cmp / MEDDataManager_i.cxx
1 // Copyright (C) 2007-2019  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 "MEDDataManager_i.hxx"
23 #include "SALOME_KernelServices.hxx"
24 #include "Basics_DirUtils.hxx"
25 #include "Basics_Utils.hxx"
26
27 #include "MEDLoader.hxx"
28 using namespace MEDCoupling;
29
30 #include <string>
31 #include <vector>
32 using namespace std;
33
34 MEDDataManager_i * MEDDataManager_i::_instance = NULL;
35 long MEDDataManager_i::LONG_UNDEFINED = -1;
36
37 MEDDataManager_i * MEDDataManager_i::getInstance() {
38   // _GBO_ we will certainly need to define one single DataManager per
39   // SALOME study and not one singleton for the whole session
40   if ( _instance == NULL ) {
41     _instance = new MEDDataManager_i();
42   }
43   return _instance;
44 }
45
46 #define IOR_UNDEF "IOR UNDEFINED"
47 MEDDataManager_i::MEDDataManager_i()
48 {
49   LOG("Creating a MEDDataManager_i instance");
50   _fieldLastId = 0;
51   _sourceLastId = 0;
52   _meshLastId = 0;
53   _fieldseriesLastId = 0;
54 }
55
56 MEDDataManager_i::~MEDDataManager_i()
57 {
58   LOG("Deleting MEDDataManager_i instance");
59 }
60
61 void MEDDataManager_i::cleanUp()
62 {
63   _fieldLastId = 0;
64   _sourceLastId = 0;
65   _meshLastId = 0;
66   _fieldseriesLastId = 0;
67
68   // [ABN] Is it the proper way?
69   _datasourceHandlerMap.clear();
70   _meshHandlerMap.clear();
71   _fieldseriesHandlerMap.clear();
72   _fieldHandlerMap.clear();
73   _fieldDoubleMap.clear();
74   _meshMap.clear();
75   _fieldPersistencyMap.clear();
76 }
77
78
79 std::string MEDDataManager_i::file_to_source(const char * filepath)
80 {
81   string source("file://");
82   source.append(filepath);
83   return source;
84 }
85
86 std::string MEDDataManager_i::source_to_file(const char * source)
87 {
88   string filepath(source);
89   filepath.replace(0,7,"");
90   return filepath;
91 }
92
93 /*!
94  * This function loads the meta-data from the specified med file and
95  * returns the associated datasource handler. The data source handler
96  * is a key to retrieve all information concerning the data (meshes,
97  * fields).
98  */
99 MEDCALC::DatasourceHandler * MEDDataManager_i::loadDatasource(const char *filepath) {
100
101   // We first check that this datasource is not already registered
102   long sourceid = getDatasourceId(filepath);
103   if ( sourceid != LONG_UNDEFINED ) {
104       // The file is already registered under the identifier sourceid
105       LOG("WRN: The file "<<filepath<<" is already registered with id="<<ToString(sourceid));
106       return new MEDCALC::DatasourceHandler(*_datasourceHandlerMap[sourceid]);
107   }
108
109   // Then we check that the file is readable by MEDLoader
110   CheckFileForRead(filepath);
111
112   // Initialise the datasource handler
113   MEDCALC::DatasourceHandler * datasourceHandler = new MEDCALC::DatasourceHandler();
114   datasourceHandler->id = _sourceLastId; _sourceLastId++;
115   datasourceHandler->name = (Kernel_Utils::GetBaseName(filepath)).c_str();
116   std::string tmp(file_to_source(filepath));
117   datasourceHandler->uri = CORBA::string_dup(tmp.c_str());
118   _datasourceHandlerMap[datasourceHandler->id] = datasourceHandler;
119
120   // We start by read the list of meshes (spatial supports of fields)
121   vector<string> meshNames = GetMeshNames(filepath);
122   int nbOfMeshes = meshNames.size();
123   for (int iMesh = 0; iMesh < nbOfMeshes; iMesh++) {
124       const char * meshName = meshNames[iMesh].c_str();
125       LOG("name of mesh " << iMesh << " = " << meshName);
126
127       MEDCALC::MeshHandler * meshHandler = new MEDCALC::MeshHandler();
128       meshHandler->id       = _meshLastId; _meshLastId++;
129       meshHandler->name     = meshName;
130       meshHandler->sourceid = datasourceHandler->id;
131
132       _meshHandlerMap[meshHandler->id] = meshHandler;
133
134       // For each mesh, we can read the list of the names of the
135       // associated fields, i.e. fields whose spatial support is this
136       // mesh.
137       vector<string> fieldNames = GetAllFieldNamesOnMesh(filepath,
138           meshName);
139       int nbOfFields = fieldNames.size();
140       for (int iField = 0; iField < nbOfFields; iField++) {
141           const char * fieldName = fieldNames[iField].c_str();
142           LOG("-- name of field " << iField << " = " << fieldName);
143
144           // A field name could identify several MEDCoupling fields, that
145           // differ by their spatial discretization on the mesh (values on
146           // cells, values on nodes, ...). This spatial discretization is
147           // specified by the TypeOfField that is an integer value in this
148           // list:
149           // 0 = ON_CELLS
150           // 1 = ON_NODES
151           // 2 = ON_GAUSS_PT
152           // 3 = ON_GAUSS_NE
153
154           // As a consequence, before loading values of a field, we have
155           // to determine the types of spatial discretization defined for
156           // this field and to choose one.
157
158           vector<TypeOfField> listOfTypes = GetTypesOfField(filepath,
159               meshName,
160               fieldName);
161           int nbOfTypes = listOfTypes.size();
162           for (int iType = 0; iType < nbOfTypes; iType++) {
163               LOG("---- type "<<iType<<" of field "<<iField<< " = " << listOfTypes[iType]);
164
165               // Then, we can get the iterations associated to this field on
166               // this type of spatial discretization:
167               std::vector< std::pair<int,int> > fieldIterations;
168
169               if (listOfTypes[iType] == MEDCoupling::ON_CELLS || listOfTypes[iType] == MEDCoupling::ON_NODES)
170                 fieldIterations = GetFieldIterations(listOfTypes[iType],
171                       filepath, meshName, fieldName);
172               else
173                 {
174                   LOG("---- WARNING - field " << fieldName << " is not on CELLS or on NODES");
175                   typedef std::vector< std::pair< std::pair<int,int>, double> > TimeVec;
176                   TimeVec fieldIterTime = GetAllFieldIterations(filepath, fieldName);
177                   for (TimeVec::const_iterator it = fieldIterTime.begin(); it != fieldIterTime.end(); ++it)
178                     fieldIterations.push_back(it->first);
179                 }
180
181               int nbFieldIterations = fieldIterations.size();
182               LOG("---- nb. iterations = " << nbFieldIterations);
183
184               // We can define the timeseries of fields (fieldseries) for
185               // this type. A fieldseries is a macro object that handle the whole
186               // set of time iterations of a field.
187               MEDCALC::FieldseriesHandler * fieldseriesHandler = new MEDCALC::FieldseriesHandler();
188               fieldseriesHandler->id     = _fieldseriesLastId; _fieldseriesLastId++;
189               fieldseriesHandler->name   = fieldName;
190               fieldseriesHandler->type   = listOfTypes[iType];
191               fieldseriesHandler->meshid = meshHandler->id;
192               fieldseriesHandler->nbIter = nbFieldIterations;
193               _fieldseriesHandlerMap[fieldseriesHandler->id] = fieldseriesHandler;
194
195               // We can then load meta-data concerning all iterations
196               for (int iterationIdx=0; iterationIdx<nbFieldIterations; iterationIdx++) {
197
198                   int iteration = fieldIterations[iterationIdx].first;
199                   int order = fieldIterations[iterationIdx].second;
200
201                   const char * source = datasourceHandler->uri;
202                   MEDCALC::FieldHandler * fieldHandler = newFieldHandler(fieldName,
203                       meshName,
204                       listOfTypes[iType],
205                       iteration,
206                       order,
207                       source);
208
209                   fieldHandler->meshid = meshHandler->id;
210                   fieldHandler->fieldseriesId = fieldseriesHandler->id;
211                   _fieldHandlerMap[fieldHandler->id] = fieldHandler;
212                   //    LOG("=== Storing " << fieldName << " (" << fieldHandler->id << ")");
213               }
214           }
215       }
216   }
217
218   return new MEDCALC::DatasourceHandler(*datasourceHandler);
219 }
220
221 long MEDDataManager_i::getDatasourceId(const char *filepath) {
222   std::string uri(file_to_source(filepath));
223   DatasourceHandlerMapIterator it = _datasourceHandlerMap.begin();
224   while ( it != _datasourceHandlerMap.end() ) {
225     if ( strcmp(it->second->uri,uri.c_str()) == 0 ) {
226       return it->first;
227     }
228     ++it;
229   }
230   return LONG_UNDEFINED;
231 }
232
233 MEDCALC::DatasourceHandler*
234 MEDDataManager_i::getDatasourceHandler(const char *filepath)
235 {
236   std::string uri(file_to_source(filepath));
237   DatasourceHandlerMapIterator it = _datasourceHandlerMap.begin();
238   while ( it != _datasourceHandlerMap.end() ) {
239     if ( strcmp(it->second->uri,uri.c_str()) == 0 ) {
240       return it->second;
241     }
242     ++it;
243   }
244   return NULL;
245 }
246
247 MEDCALC::DatasourceHandler*
248 MEDDataManager_i::getDatasourceHandlerFromID(CORBA::Long sourceid)
249 {
250   DatasourceHandlerMapIterator it = _datasourceHandlerMap.find(sourceid);
251   if (it != _datasourceHandlerMap.end())
252     {
253       return it->second;
254     }
255   return NULL;
256 }
257
258 MEDCALC::MeshHandler * MEDDataManager_i::getMeshHandler(CORBA::Long meshId) {
259   if ( _meshHandlerMap.count(meshId) == 0 ) {
260     std::string message =
261       std::string("The mesh of id=") + ToString(meshId) +
262       std::string(" does not exist in the data manager");
263     LOG(message);
264     throw KERNEL::createSalomeException(message.c_str());
265   }
266   return new MEDCALC::MeshHandler(*(_meshHandlerMap[meshId]));
267 }
268
269
270 /*!
271  * This function returns the list of mesh handlers associated to the
272  * specified datasource. It corresponds to the list of meshes defined
273  * in the datasource.
274  */
275 MEDCALC::MeshHandlerList * MEDDataManager_i::getMeshHandlerList(CORBA::Long datasourceId) {
276
277   // We initiate a list with the maximum length
278   MEDCALC::MeshHandlerList_var meshHandlerList = new MEDCALC::MeshHandlerList();
279   meshHandlerList->length(_meshHandlerMap.size());
280
281   // Scan the map looking for meshes associated to the specified datasource
282   int itemIdx = 0;
283   MeshHandlerMapIterator meshIt;
284   for ( meshIt=_meshHandlerMap.begin(); meshIt != _meshHandlerMap.end(); meshIt++) {
285     if ( meshIt->second->sourceid == datasourceId ) {
286       meshHandlerList[itemIdx] = *(meshIt->second);
287       itemIdx++;
288     }
289   }
290
291   // Adjust the length to the real number of elements
292   meshHandlerList->length(itemIdx);
293   return meshHandlerList._retn();
294 }
295
296 /*!
297  * This function returns the list of fieldseries defined on the
298  * specified mesh.
299  */
300 MEDCALC::FieldseriesHandlerList * MEDDataManager_i::getFieldseriesListOnMesh(CORBA::Long meshId) {
301   // We initiate a list with the maximum length
302   MEDCALC::FieldseriesHandlerList_var
303     fieldseriesHandlerList = new MEDCALC::FieldseriesHandlerList();
304   fieldseriesHandlerList->length(_fieldseriesHandlerMap.size());
305
306   // Scan the map looking for fieldseries defined on the specified mesh
307   int itemIdx = 0;
308   FieldseriesHandlerMapIterator it;
309   for ( it=_fieldseriesHandlerMap.begin(); it != _fieldseriesHandlerMap.end(); it++) {
310     if ( it->second->meshid == meshId ) {
311       fieldseriesHandlerList[itemIdx] = *(it->second);
312       itemIdx++;
313     }
314   }
315
316   // Adjust the length to the real number of elements
317   fieldseriesHandlerList->length(itemIdx);
318   return fieldseriesHandlerList._retn();
319 }
320
321 /*!
322  * A fieldseries is a timeseries of fields. Then the list of fields is
323  * the different time iterations defined for the specified field id.
324  */
325 MEDCALC::FieldHandlerList * MEDDataManager_i::getFieldListInFieldseries(CORBA::Long fieldseriesId) {
326
327   // We initiate a list with the maximum length
328   MEDCALC::FieldHandlerList_var fieldHandlerList = new MEDCALC::FieldHandlerList();
329   fieldHandlerList->length(_fieldHandlerMap.size());
330
331   // Scan the map looking for field defined on the specified mesh
332   int itemIdx = 0;
333   FieldHandlerMapIterator it;
334   for ( it=_fieldHandlerMap.begin(); it != _fieldHandlerMap.end(); it++) {
335     if ( it->second->fieldseriesId == fieldseriesId ) {
336       fieldHandlerList[itemIdx] = *(it->second);
337       itemIdx++;
338     }
339   }
340
341   // Adjust the length to the real number of elements
342   fieldHandlerList->length(itemIdx);
343   return fieldHandlerList._retn();
344 }
345
346 /*!
347  * This returns the whole set of fields handlers for all datasource
348  * that have been loaded using loadDatasource.
349  */
350 MEDCALC::FieldHandlerList * MEDDataManager_i::getFieldHandlerList() {
351   MEDCALC::FieldHandlerList_var fieldHandlerSeq = new MEDCALC::FieldHandlerList();
352   fieldHandlerSeq->length(_fieldHandlerMap.size());
353
354   int sequenceId = 0;
355   FieldHandlerMapIterator fieldIt;
356   for ( fieldIt=_fieldHandlerMap.begin(); fieldIt != _fieldHandlerMap.end(); fieldIt++) {
357     fieldHandlerSeq[sequenceId] = *(fieldIt->second);
358     sequenceId++;
359   }
360   return fieldHandlerSeq._retn();
361 }
362
363 /*!
364  * This returns a copy of the fieldHandler associated to the specified id.
365  */
366 MEDCALC::FieldHandler * MEDDataManager_i::getFieldHandler(CORBA::Long fieldHandlerId) {
367 //  LOG("getFieldHandler: START")
368
369   FieldHandlerMapIterator fieldIt = _fieldHandlerMap.find(fieldHandlerId);
370   if ( fieldIt != _fieldHandlerMap.end() ) {
371     // >>> WARNING: CORBA struct specification indicates that the
372     // assignment acts as a destructor for the structure that its
373     // pointed to. The values of the fields are copied first in the new
374     // structure that receives the assignment and finally the initial
375     // structure is destroyed. In the present case, WE WANT to keep
376     // the initial fieldHandler in the map. We must then make a deep
377     // copy of the structure found in the map and return the copy. The
378     // CORBA struct specification indicates that a deep copy can be
379     // done using the copy constructor.  <<<
380     return new MEDCALC::FieldHandler(*(fieldIt->second));
381   }
382   return NULL;
383 }
384
385 /*!
386  * This returns a string representation of the field associated to the specified id.
387  */
388 char * MEDDataManager_i::getFieldRepresentation(CORBA::Long fieldHandlerId) {
389   LOG("getFieldRepresentation: START")
390   MEDCALC::FieldHandler * fieldHandler = getFieldHandler(fieldHandlerId);
391   MEDCouplingFieldDouble* fieldDouble = getFieldDouble(fieldHandler);
392   return CORBA::string_dup(fieldDouble->getArray()->repr().c_str());
393 }
394
395 void MEDDataManager_i::saveFields(const char * filepath,
396           const MEDCALC::FieldIdList & fieldIdList)
397 {
398   LOG("saveFields to : " << filepath);
399
400   // We first have to check if the target filepath is writable
401   // (segmentation fault in med otherwise)
402   if (!Kernel_Utils::IsWritable(Kernel_Utils::GetDirName(std::string(filepath)))) {
403     std::string message =
404       std::string("The target filepath ") +
405       std::string(filepath) +
406       std::string(" is not writable");
407     LOG(message);
408     throw KERNEL::createSalomeException(message.c_str());
409   }
410
411   if ( fieldIdList.length() == 0 ) {
412     throw KERNEL::createSalomeException("No fields to save");
413   }
414
415   // Consider the first field to initiate the med file
416   CORBA::Long fieldHandlerId = fieldIdList[0];
417   MEDCALC::FieldHandler * fieldHandler = getFieldHandler(fieldHandlerId);
418   MEDCouplingFieldDouble* fieldDouble = getFieldDouble(fieldHandler);
419
420   try {
421     bool writeFromScratch = true;
422     WriteField(filepath, fieldDouble, writeFromScratch);
423
424     writeFromScratch = false;
425     for(CORBA::ULong i=1; i<fieldIdList.length(); i++) {
426       fieldHandlerId = fieldIdList[i];
427       fieldHandler = getFieldHandler(fieldHandlerId);
428       fieldDouble = getFieldDouble(fieldHandler);
429       WriteField(filepath, fieldDouble, writeFromScratch);
430     }
431   }
432   catch (INTERP_KERNEL::Exception &ex) {
433     std::string message =
434       std::string("Error when saving file ") +
435       std::string(filepath) + std::string(" : ") + ex.what();
436     throw KERNEL::createSalomeException(message.c_str());
437   }
438   catch (const std::exception& ex) {
439     std::string message =
440       std::string("Error when saving file ") +
441       std::string(filepath) + std::string(" : ") + ex.what();
442     throw KERNEL::createSalomeException(message.c_str());
443   }
444
445 }
446
447 /*!
448  * This function must be used to indicate that the field with the
449  * specified id must be considered as persistent (if persistent is
450  * true) or not persistent (if persistent is false). If a field is
451  * marked as persistent, then it is automatically saved when the
452  * function savePersistentFields is called.
453  */
454 void MEDDataManager_i::markAsPersistent(CORBA::Long fieldHandlerId, bool persistent) {
455   LOG("mark as persistent : id="<<fieldHandlerId);
456   _fieldPersistencyMap[fieldHandlerId] = persistent;
457 }
458
459 void MEDDataManager_i::savePersistentFields(const char * filepath) {
460   LOG("savePersistentFields to : " << filepath);
461   std::vector<long> listId;
462
463   FieldPersistencyMapIterator mapIt;
464   for ( mapIt = _fieldPersistencyMap.begin(); mapIt != _fieldPersistencyMap.end(); mapIt++) {
465     if ( mapIt->second == true ) {
466       listId.push_back(mapIt->first);
467     }
468   }
469
470   MEDCALC::FieldIdList fieldIdList;
471   fieldIdList.length(listId.size());
472   for (int i=0; i<listId.size(); i++) {
473     fieldIdList[i] = CORBA::Long(listId[i]);
474   }
475
476   try {
477     this->saveFields(filepath, fieldIdList);
478   }
479   catch (const SALOME::SALOME_Exception & ex) {
480     throw ex;
481   }
482   catch (const std::exception& ex) {
483     std::string message =
484       std::string("Error when saving file ") +
485       std::string(filepath) + std::string(" : ") + ex.what();
486     throw KERNEL::createSalomeException(message.c_str());
487   }
488 }
489
490 /*!
491  * This function is responsible for creating the FieldHandler
492  * instances. You must use this function because it manages
493  * automatically the identifier value (autoincrementation of a static
494  * variable)
495  */
496 MEDCALC::FieldHandler * MEDDataManager_i::newFieldHandler(const char * fieldname,
497               const char * meshname,
498               TypeOfField  type,
499               long         iteration,
500               long         order,
501               const char * source)
502 {
503   MEDCALC::FieldHandler * fieldHandler = new MEDCALC::FieldHandler();
504   fieldHandler->id = _fieldLastId; _fieldLastId++;
505   fieldHandler->fieldname = fieldname;
506   fieldHandler->meshname  = meshname;
507   fieldHandler->type      = type;
508   fieldHandler->iteration = iteration;
509   fieldHandler->order     = order;
510   fieldHandler->source    = source;
511   return fieldHandler;
512 }
513
514 /*!
515  * This updates the metadata of the field identified by its id with
516  * the data of the given field handler. Returns a copy of the updated
517  * handler (that should be identical to the given field handler for
518  * all data but not for the id that is an invariant for all session
519  * long).
520  * WARN: you should be warned that this function could leave the data
521  * model in a non-coherent state, by example if you change the mesh
522  * name while the mesh has not been updated.
523  */
524 MEDCALC::FieldHandler * MEDDataManager_i::updateFieldHandler(CORBA::Long fieldHandlerId,
525                  const char * fieldname,
526                  long         iteration,
527                  long         order,
528                  const char * source) {
529   FieldHandlerMapIterator fieldIt = _fieldHandlerMap.find(fieldHandlerId);
530   if ( fieldIt != _fieldHandlerMap.end() ) {
531     // Update the attributes
532     // >>> WARN: note that the id of a handler registered in the map
533     // SHOULD NEVER be modified because it is the identifier used in
534     // the whole application for this field all the session long.
535     // <<<
536     fieldIt->second->fieldname = fieldname;
537     fieldIt->second->iteration = iteration;
538     fieldIt->second->order     = order;
539     fieldIt->second->source    = source;
540     // Return a copy
541     return new MEDCALC::FieldHandler(*fieldIt->second);
542   }
543   return NULL;
544 }
545
546 MEDCouplingUMesh * MEDDataManager_i::getUMesh(long meshHandlerId) {
547
548   LOG("getUMesh: START")
549
550   MEDCouplingUMesh * myMesh = NULL;
551   if ( _meshMap.count(meshHandlerId) > 0 ) {
552     // The mesh has been found in the map
553     myMesh = _meshMap[meshHandlerId];
554   } else {
555     // The mesh is not loaded yet ==> load it and register it in the map
556     LOG("getUMesh: the mesh must be loaded. meshid="<<meshHandlerId);
557     if ( _meshHandlerMap[meshHandlerId] == NULL ) {
558       std::string message =
559   std::string("No mesh for id=") + ToString(meshHandlerId);
560       LOG("getUMesh: "<<message);
561       throw KERNEL::createSalomeException(message.c_str());
562     }
563
564     long sourceid = _meshHandlerMap[meshHandlerId]->sourceid;
565     std::string filepath(source_to_file((_datasourceHandlerMap[sourceid])->uri));
566     const char * meshName = _meshHandlerMap[meshHandlerId]->name;
567     int meshDimRelToMax = 0;
568     myMesh = ReadUMeshFromFile(filepath,meshName,meshDimRelToMax);
569     _meshMap[meshHandlerId] = myMesh;
570   }
571   return myMesh;
572 }
573
574 /**
575  * Try to retrieve the id of the specified mesh, i.e. the key it is
576  * registered with in the internal meshes map.
577  */
578 long MEDDataManager_i::getUMeshId(const MEDCouplingMesh * mesh) {
579   bool found = false;
580   MeshMapIterator it = _meshMap.begin();
581   while ( it != _meshMap.end() ) {
582     found = (it->second == mesh);
583     if (found) {
584       return it->first;
585     }
586     ++it;
587   }
588   return LONG_UNDEFINED;
589 }
590
591 /*!
592  * This method returns the physical data of the specified field,
593  * i.e. the MEDCoupling field associated to the specified field
594  * handler. If the field source is a file and the data ar not loaded
595  * yet, the this function load the data from the file in a MEDCoupling
596  * field instance. Otherwise, it just returns the MEDCoupling field
597  * instance.
598  */
599 MEDCouplingFieldDouble * MEDDataManager_i::getFieldDouble(const MEDCALC::FieldHandler * fieldHandler)
600 {
601
602   LOG("getFieldDouble: START with id="<<fieldHandler->id);
603
604   if ( _fieldDoubleMap.count(fieldHandler->id) > 0 ) {
605   // The MEDCoupling field data are already loaded. Just return the
606   // reference of the MEDCouplingFieldDouble pointer
607     return _fieldDoubleMap[fieldHandler->id];
608   }
609
610   // The MEDCoupling field data are not loaded yet. Load the data and
611   // register the MEDCoupling field in our internal map an all the
612   // associated data if needed (i.e. the underlying mesh).
613
614   // At this step, the mesh handler needs a meshid correctly
615   // set. Normally, we should arrive at this step only in the case
616   // where the field is loaded from a file ==> the meshid is defined
617   // (see the loadDatasource function).
618   //
619   // >>>> __GBO__ TO BE CHECKED AND SERIOUSLY TESTED. There at least
620   // one case where we can arrive here with no previous call to
621   // loadDataSource: for example the field handler list can be obtained
622   // from a call to addFieldsFromFile instead of loadDataSource (see
623   // for example the getFieldRepresentation service of the
624   // dataManager, that comes here and then calls getUMesh where we
625   // need a map initialized only in loadDataSource) <<<<
626   long meshid = fieldHandler->meshid;
627
628   // We first have to check if the associated mesh is already loaded
629   // and to load it if needed. The loaded meshes are registered in a
630   // map whose key is the mesh handler id. This checking is
631   // automatically done by the function getUMesh. It's important to do
632   // it before the loading of field data to prevent from the case
633   // where the mesh would not have been loaded already (in the
634   // previous field loading).
635   MEDCouplingUMesh * myMesh =this->getUMesh(meshid);
636
637   long sourceid = _meshHandlerMap[meshid]->sourceid;
638
639   std::string filepath(source_to_file((_datasourceHandlerMap[sourceid])->uri));
640   std::string meshName(myMesh->getName());
641   LOG("getFieldDouble: field "<<fieldHandler->fieldname<<" loaded from file "<<filepath);
642   TypeOfField type = (TypeOfField)fieldHandler->type;
643   int meshDimRelToMax = 0;
644   MCAuto<MEDCouplingField> myFieldTmpp(ReadField(type,
645                 filepath,
646                 meshName,
647                 meshDimRelToMax,
648                 std::string(fieldHandler->fieldname),
649                 fieldHandler->iteration,
650                 fieldHandler->order));
651   MCAuto<MEDCouplingFieldDouble> myField(DynamicCast<MEDCouplingField,MEDCouplingFieldDouble>(myFieldTmpp));
652   myField->setMesh(myMesh);
653   _fieldDoubleMap[fieldHandler->id] = myField.retn();
654   return myField;
655 }
656
657 /*!
658  * This adds the specified MEDCoupling field in the collection managed
659  * by this DataManager. The associated FieldHandler is returned. This
660  * is typically used in a context where the MEDCoupling field is
661  * created from scratch, for example by operations in the
662  * MEDCalculator.
663  * @param[in] fieldDouble   the MEDCouplingFieldDouble instance to add
664  * @param[in] meshHandlerId the id of the meshHandler this filed is associated to.
665  * @return a copy of the FieldHandler registered in the internal map for this field.
666  */
667 MEDCALC::FieldHandler * MEDDataManager_i::addField(MEDCouplingFieldDouble * fieldDouble,
668              long meshHandlerId)
669 {
670   std::string fieldName(fieldDouble->getName());
671   std::string meshName(fieldDouble->getMesh()->getName());
672   TypeOfField  type      = fieldDouble->getTypeOfField();
673
674   int iteration, order;
675   // WARN: note that the variables "iteration" and "order" are passed
676   // by reference to the function getTime (see documentation of
677   // MEDCouplingField). As a consequence, the values of these
678   // variables are updated by this function call. This is the means to
679   // retrieve the iteration and order of the field.
680   double timestamp = fieldDouble->getTime(iteration, order);
681
682   // For the fields that are created in memory (by operations for
683   // example), the convention for the source attribute is to specify
684   // the fielddouble name, because this name describes the operation
685   // the field has been created with.
686   string * source = new string("mem://"); source->append(fieldName);
687   MEDCALC::FieldHandler * fieldHandler = newFieldHandler(fieldName.c_str(),
688                                                        meshName.c_str(),
689                                                        type,
690                                                        iteration,
691                                                        order,
692                                                        source->c_str());
693
694   if ( meshHandlerId == LONG_UNDEFINED ) {
695     // We have to guess the id of the underlying mesh to preserve data
696     // integrity (a fieldHandler must have an attribute that contains
697     // the id of its underlying mesh):
698     //
699     // WARNING: it's better to let the client code (the one who calls the
700     // function addField) to specify this meshid. This guess procedure is
701     // not reliable, it's just to have a second chance.
702     //
703     LOG("addField: The mesh id is not defined. Trying to guess from the mesh name "<<meshName);
704     long meshid = this->getUMeshId(fieldDouble->getMesh());
705     fieldHandler->meshid = meshid;
706     if ( meshid == LONG_UNDEFINED ) {
707       // No mesh has been found in the internal map
708       LOG("addField: The mesh id for the mesh "<<meshName<<" can't be retrieved from the field "<<fieldName);
709       // _GBO_ : Maybe it could be better to raise an exception
710     }
711   }
712   else {
713     fieldHandler->meshid = meshHandlerId;
714   }
715
716   _fieldHandlerMap[fieldHandler->id] = fieldHandler;
717   _fieldDoubleMap[fieldHandler->id] = fieldDouble;
718   // >>> WARNING: CORBA structure assignment specification ==> return
719   // >>> a deep copy to avoid the destruction of the fieldHandler
720   // >>> registered in the map (assignment acts as a destructor for
721   // >>> CORBA struct).
722   return new MEDCALC::FieldHandler(*fieldHandler);
723 }
724
725 /*!
726  * This function updates the meta-data "fieldname" associated to the
727  * specified field.
728  */
729 void MEDDataManager_i::updateFieldMetadata(CORBA::Long  fieldHandlerId,
730              const char * fieldname,
731              CORBA::Long  iteration,
732              CORBA::Long  order,
733              const char * source)
734 {
735   // We have to update the field handler registered in the internal
736   // map AND the associated fieldDouble loaded in memory.
737   MEDCALC::FieldHandler * fieldHandler = getFieldHandler(fieldHandlerId);
738   updateFieldHandler(fieldHandlerId,fieldname,iteration,order,source);
739
740   MEDCouplingFieldDouble* fieldDouble = getFieldDouble(fieldHandler);
741   fieldDouble->setName(fieldname);
742
743   // _GBO_ TO BE IMPLEMENTED: iteration and order
744 }
745
746 /**
747  * This can be used to associate to the specified field another mesh
748  * support than its current one. This is typically needed to operate 2
749  * fields defined on the same mesh but coming from different med
750  * files. In this case, the underlying meshes are different mesh
751  * objects (from the MEDCoupling point of view) and then no operation
752  * can be allowed by MEDCoupling. The operation of course fails if the
753  * new mesh is not identical to the old one.
754  */
755 void MEDDataManager_i::changeUnderlyingMesh(CORBA::Long fieldHandlerId, CORBA::Long meshHandlerId) {
756
757   MEDCALC::FieldHandler * fieldHandler = getFieldHandler(fieldHandlerId);
758   MEDCouplingFieldDouble* fieldDouble = getFieldDouble(fieldHandler);
759   MEDCouplingMesh * newMesh = getUMesh(meshHandlerId);
760
761   try {
762     fieldDouble->changeUnderlyingMesh(newMesh,10,1e-12);
763   }
764   catch (INTERP_KERNEL::Exception &ex) {
765     std::string * message = new std::string("Error when changing the underlying mesh : ");
766     message->append(ex.what());
767     throw KERNEL::createSalomeException(message->c_str());
768   }
769
770   // The change of mesh is OK, then we can update the meta-data
771   _fieldHandlerMap[fieldHandlerId]->meshid = meshHandlerId;
772   _fieldHandlerMap[fieldHandlerId]->meshname = _meshHandlerMap[meshHandlerId]->name;
773
774
775   // WARN: if this field has already been request by the tui for
776   // manipulation (in a fieldproxy), then the data should be
777   // synchronized
778 }
779
780 INTERP_KERNEL::IntersectionType MEDDataManager_i::_getIntersectionType(const char* intersType) {
781   std::string type(intersType);
782   if (type == "Triangulation") {
783     return INTERP_KERNEL::Triangulation;
784   }
785   else if (type == "Convex") {
786     return INTERP_KERNEL::Convex;
787   }
788   else if (type == "Geometric2D") {
789     return INTERP_KERNEL::Geometric2D;
790   }
791   else if (type == "PointLocator") {
792     return INTERP_KERNEL::PointLocator;
793   }
794   else if (type == "Barycentric") {
795     return INTERP_KERNEL::Barycentric;
796   }
797   else if (type == "BarycentricGeo2D") {
798     return INTERP_KERNEL::BarycentricGeo2D;
799   }
800
801   std::string message("Error when trying to interpolate field: ");
802   message.append("Unrecognized intersection type: ");
803   message.append(type);
804   throw KERNEL::createSalomeException(message.c_str());
805 }
806
807 MEDCoupling::NatureOfField MEDDataManager_i::_getNatureOfField(const char* fieldNature) {
808   std::string nature(fieldNature);
809   if (nature == "NoNature") {
810     return NoNature;
811   }
812   else if (nature == "IntensiveMaximum") {
813     return IntensiveMaximum;
814   }
815   else if (nature == "ExtensiveMaximum") {
816     return ExtensiveMaximum;
817   }
818   else if (nature == "ExtensiveConservation") {
819     return ExtensiveConservation;
820   }
821   else if (nature == "IntensiveConservation") {
822     return IntensiveConservation;
823   }
824
825   std::string message("Error when trying to interpolate field: ");
826   message.append("Unrecognized field nature: ");
827   message.append(nature);
828   throw KERNEL::createSalomeException(message.c_str());
829 }
830
831 MEDCALC::FieldHandler* MEDDataManager_i::interpolateField(CORBA::Long fieldHandlerId, CORBA::Long meshHandlerId, const MEDCALC::InterpolationParameters& params) {
832   MEDCALC::FieldHandler* fieldHandler = getFieldHandler(fieldHandlerId);
833   MEDCouplingFieldDouble* sourceField = getFieldDouble(fieldHandler);
834   MEDCouplingMesh* sourceMesh = getUMesh(fieldHandler->meshid);
835   MEDCouplingMesh* targetMesh = getUMesh(meshHandlerId);
836
837   double precision = params.precision;
838   INTERP_KERNEL::IntersectionType interpType = this->_getIntersectionType(params.intersectionType);
839   std::string method(params.method);
840   double defaultValue = params.defaultValue;
841   bool reverse = params.reverse;
842   MEDCoupling::NatureOfField nature = this->_getNatureOfField(params.nature);
843
844   // 1. Build remapper between sourceMesh and targetMesh (compute interpolation matrix)
845   MEDCouplingRemapper remapper;
846   remapper.setPrecision(precision);
847   remapper.setIntersectionType(interpType);
848   remapper.prepare(sourceMesh, targetMesh, method.c_str());
849
850   // 2. Apply interpolation to the field
851   sourceField->setNature(nature);
852   MEDCouplingFieldDouble* targetField = NULL;
853   if (reverse) {
854     targetField = remapper.reverseTransferField(sourceField, defaultValue);
855   } else {
856     targetField = remapper.transferField(sourceField, defaultValue);
857   }
858   targetField->setMesh(targetMesh);
859   targetField->setName(targetMesh->getName() + "_field");
860
861   // 3. Create and register field handler
862   MEDCALC::FieldHandler* fieldResultHandler = this->addField(targetField, this->getUMeshId(targetField->getMesh()));
863   return fieldResultHandler;
864 }
865
866
867
868 /*!
869  * This functions display the internal data of the MEDDataManager on
870  * the server side (data in the SALOME container).
871  */
872 void MEDDataManager_i::serverlog() {
873
874   LOG("==== Field Handler Map ====================================================");
875   LOG("Size = "<<_fieldHandlerMap.size());
876   FieldHandlerMapIterator fhmIt;
877   for ( fhmIt = _fieldHandlerMap.begin(); fhmIt != _fieldHandlerMap.end(); fhmIt++) {
878     long id = fhmIt->first;
879     LOG("------------------------------------- id = "<<ToString(id));
880     LOG("- id        \t= "<<fhmIt->second->id);
881     LOG("- fieldname \t= "<<fhmIt->second->fieldname);
882     LOG("- meshname  \t= "<<fhmIt->second->meshname);
883   }
884
885   LOG("==== Field Double Map ====================================================");
886   LOG("Size = "<<_fieldDoubleMap.size());
887   FieldDoubleMapIterator fdmIt;
888   for ( fdmIt = _fieldDoubleMap.begin(); fdmIt != _fieldDoubleMap.end(); fdmIt++) {
889     long id = (*fdmIt).first;
890     MEDCouplingFieldDouble * fieldDouble = (*fdmIt).second;
891     LOG("------------------------------------- id = "<<ToString(id));
892     LOG("- fieldname \t= "<<fieldDouble->getName());
893     LOG("- meshname  \t= "<<fieldDouble->getMesh()->getName());
894   }
895 }
896
897 /*!
898  * The event listener is created inside the GUI by the
899  * WorkspaceController. This function is called by the WorkspaceController to
900  * store the event listener IOR for the time of the session. Then this
901  * IOR can be available to any point of the application that can
902  * request the data manager (the python console for example).
903  */
904 void MEDDataManager_i::setEventListenerIOR(const char * ior) {
905   _medEventListenerIOR = ior;
906 }
907 /*!
908  * Return the IOR of the event listener that resides in the
909  * GUI. Having the IOR, you can restore the CORBA object by using:
910  *
911  * In a python SALOME context:
912  *
913  * >>> import salome
914  * >>> salome.salome_init()
915  * >>> myobject = salome.orb.string_to_object(ior)
916  *
917  * In a C++ SALOME context: (to do if needed)
918  */
919 char * MEDDataManager_i::getEventListenerIOR() {
920   if ( _medEventListenerIOR == "" ) {
921     throw KERNEL::createSalomeException("The event listener IOR is not defined");
922   }
923   // WARN: return a copy because the pointer memory will be released
924   // (CORBA specification)
925   return CORBA::string_dup( _medEventListenerIOR.c_str() );
926 }