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