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