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