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