1 // Copyright (C) 2007-2021 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // Authors : Guillaume Boulant (EDF) - 01/06/2011
22 #include "MEDDataManager_i.hxx"
23 #include "SALOME_KernelServices.hxx"
24 #include "Basics_DirUtils.hxx"
25 #include "Basics_Utils.hxx"
27 #include "MEDLoader.hxx"
28 using namespace MEDCoupling;
34 MEDDataManager_i * MEDDataManager_i::_instance = NULL;
35 long MEDDataManager_i::LONG_UNDEFINED = -1;
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();
46 #define IOR_UNDEF "IOR UNDEFINED"
47 MEDDataManager_i::MEDDataManager_i()
49 LOG("Creating a MEDDataManager_i instance");
53 _fieldseriesLastId = 0;
56 MEDDataManager_i::~MEDDataManager_i()
58 LOG("Deleting MEDDataManager_i instance");
61 void MEDDataManager_i::cleanUp()
66 _fieldseriesLastId = 0;
68 // [ABN] Is it the proper way?
69 _datasourceHandlerMap.clear();
70 _meshHandlerMap.clear();
71 _fieldseriesHandlerMap.clear();
72 _fieldHandlerMap.clear();
73 _fieldDoubleMap.clear();
75 _fieldPersistencyMap.clear();
79 std::string MEDDataManager_i::file_to_source(const char * filepath)
81 string source("file://");
82 source.append(filepath);
86 std::string MEDDataManager_i::source_to_file(const char * source)
88 string filepath(source);
89 filepath.replace(0,7,"");
94 * Check if a source (from its uri name) is in a file or in memory
96 bool MEDDataManager_i::isSourceInFile(const char * sourceName)
98 std::string sourceString(sourceName);
99 return (sourceString.substr(0, 7) == std::string("file://"));
105 * This function loads the meta-data from the specified med file and
106 * returns the associated datasource handler. The data source handler
107 * is a key to retrieve all information concerning the data (meshes,
110 MEDCALC::DatasourceHandler * MEDDataManager_i::loadDatasource(const char *filepath) {
112 // We first check that this datasource is not already registered
113 long sourceid = getDatasourceId(filepath);
114 if ( sourceid != LONG_UNDEFINED ) {
115 // The file is already registered under the identifier sourceid
116 LOG("WRN: The file "<<filepath<<" is already registered with id="<<ToString(sourceid));
117 return new MEDCALC::DatasourceHandler(*_datasourceHandlerMap[sourceid]);
120 // Then we check that the file is readable by MEDLoader
121 CheckFileForRead(filepath);
123 // Initialise the datasource handler
124 MEDCALC::DatasourceHandler * datasourceHandler = new MEDCALC::DatasourceHandler();
125 datasourceHandler->id = _sourceLastId; _sourceLastId++;
126 datasourceHandler->name = (Kernel_Utils::GetBaseName(filepath)).c_str();
127 std::string tmp(file_to_source(filepath));
128 datasourceHandler->uri = CORBA::string_dup(tmp.c_str());
129 _datasourceHandlerMap[datasourceHandler->id] = datasourceHandler;
131 // We start by read the list of meshes (spatial supports of fields)
132 vector<string> meshNames = GetMeshNames(filepath);
133 int nbOfMeshes = meshNames.size();
134 for (int iMesh = 0; iMesh < nbOfMeshes; iMesh++) {
135 const char * meshName = meshNames[iMesh].c_str();
136 LOG("name of mesh " << iMesh << " = " << meshName);
138 MEDCALC::MeshHandler * meshHandler = new MEDCALC::MeshHandler();
139 meshHandler->id = _meshLastId; _meshLastId++;
140 meshHandler->name = meshName;
141 meshHandler->sourceid = datasourceHandler->id;
143 _meshHandlerMap[meshHandler->id] = meshHandler;
145 // For each mesh, we can read the list of the names of the
146 // associated fields, i.e. fields whose spatial support is this
148 vector<string> fieldNames = GetAllFieldNamesOnMesh(filepath,
150 int nbOfFields = fieldNames.size();
151 for (int iField = 0; iField < nbOfFields; iField++) {
152 const char * fieldName = fieldNames[iField].c_str();
153 LOG("-- name of field " << iField << " = " << fieldName);
155 // A field name could identify several MEDCoupling fields, that
156 // differ by their spatial discretization on the mesh (values on
157 // cells, values on nodes, ...). This spatial discretization is
158 // specified by the TypeOfField that is an integer value in this
165 // As a consequence, before loading values of a field, we have
166 // to determine the types of spatial discretization defined for
167 // this field and to choose one.
169 vector<TypeOfField> listOfTypes = GetTypesOfField(filepath,
172 int nbOfTypes = listOfTypes.size();
173 for (int iType = 0; iType < nbOfTypes; iType++) {
174 LOG("---- type "<<iType<<" of field "<<iField<< " = " << listOfTypes[iType]);
176 // Then, we can get the iterations associated to this field on
177 // this type of spatial discretization:
178 std::vector< std::pair<int,int> > fieldIterations;
180 if (listOfTypes[iType] == MEDCoupling::ON_CELLS || listOfTypes[iType] == MEDCoupling::ON_NODES)
181 fieldIterations = GetFieldIterations(listOfTypes[iType],
182 filepath, meshName, fieldName);
185 LOG("---- WARNING - field " << fieldName << " is not on CELLS or on NODES");
186 typedef std::vector< std::pair< std::pair<int,int>, double> > TimeVec;
187 TimeVec fieldIterTime = GetAllFieldIterations(filepath, fieldName);
188 for (TimeVec::const_iterator it = fieldIterTime.begin(); it != fieldIterTime.end(); ++it)
189 fieldIterations.push_back(it->first);
192 int nbFieldIterations = fieldIterations.size();
193 LOG("---- nb. iterations = " << nbFieldIterations);
195 // We can define the timeseries of fields (fieldseries) for
196 // this type. A fieldseries is a macro object that handle the whole
197 // set of time iterations of a field.
198 MEDCALC::FieldseriesHandler * fieldseriesHandler = new MEDCALC::FieldseriesHandler();
199 fieldseriesHandler->id = _fieldseriesLastId; _fieldseriesLastId++;
200 fieldseriesHandler->name = fieldName;
201 fieldseriesHandler->type = listOfTypes[iType];
202 fieldseriesHandler->meshid = meshHandler->id;
203 fieldseriesHandler->nbIter = nbFieldIterations;
204 _fieldseriesHandlerMap[fieldseriesHandler->id] = fieldseriesHandler;
206 // We can then load meta-data concerning all iterations
207 for (int iterationIdx=0; iterationIdx<nbFieldIterations; iterationIdx++) {
209 int iteration = fieldIterations[iterationIdx].first;
210 int order = fieldIterations[iterationIdx].second;
212 const char * source = datasourceHandler->uri;
213 MEDCALC::FieldHandler * fieldHandler = newFieldHandler(fieldName,
220 fieldHandler->meshid = meshHandler->id;
221 fieldHandler->fieldseriesId = fieldseriesHandler->id;
222 _fieldHandlerMap[fieldHandler->id] = fieldHandler;
223 // LOG("=== Storing " << fieldName << " (" << fieldHandler->id << ")");
229 return new MEDCALC::DatasourceHandler(*datasourceHandler);
232 long MEDDataManager_i::getDatasourceId(const char *filepath) {
233 std::string uri(file_to_source(filepath));
234 DatasourceHandlerMapIterator it = _datasourceHandlerMap.begin();
235 while ( it != _datasourceHandlerMap.end() ) {
236 if ( strcmp(it->second->uri,uri.c_str()) == 0 ) {
241 return LONG_UNDEFINED;
244 MEDCALC::DatasourceHandler*
245 MEDDataManager_i::getDatasourceHandler(const char *filepath)
247 std::string uri(file_to_source(filepath));
248 DatasourceHandlerMapIterator it = _datasourceHandlerMap.begin();
249 while ( it != _datasourceHandlerMap.end() ) {
250 if ( strcmp(it->second->uri,uri.c_str()) == 0 ) {
258 MEDCALC::DatasourceHandler*
259 MEDDataManager_i::getDatasourceHandlerFromID(CORBA::Long sourceid)
261 DatasourceHandlerMapIterator it = _datasourceHandlerMap.find(sourceid);
262 if (it != _datasourceHandlerMap.end())
269 MEDCALC::MeshHandler * MEDDataManager_i::getMeshHandler(CORBA::Long meshId) {
270 if ( _meshHandlerMap.count(meshId) == 0 ) {
271 std::string message =
272 std::string("The mesh of id=") + ToString(meshId) +
273 std::string(" does not exist in the data manager");
275 throw KERNEL::createSalomeException(message.c_str());
277 return new MEDCALC::MeshHandler(*(_meshHandlerMap[meshId]));
282 * This function returns the list of mesh handlers associated to the
283 * specified datasource. It corresponds to the list of meshes defined
286 MEDCALC::MeshHandlerList * MEDDataManager_i::getMeshHandlerList(CORBA::Long datasourceId) {
288 // We initiate a list with the maximum length
289 MEDCALC::MeshHandlerList_var meshHandlerList = new MEDCALC::MeshHandlerList();
290 meshHandlerList->length(_meshHandlerMap.size());
292 // Scan the map looking for meshes associated to the specified datasource
294 MeshHandlerMapIterator meshIt;
295 for ( meshIt=_meshHandlerMap.begin(); meshIt != _meshHandlerMap.end(); meshIt++) {
296 if ( meshIt->second->sourceid == datasourceId ) {
297 meshHandlerList[itemIdx] = *(meshIt->second);
302 // Adjust the length to the real number of elements
303 meshHandlerList->length(itemIdx);
304 return meshHandlerList._retn();
308 * This function returns the list of fieldseries defined on the
311 MEDCALC::FieldseriesHandlerList * MEDDataManager_i::getFieldseriesListOnMesh(CORBA::Long meshId) {
312 // We initiate a list with the maximum length
313 MEDCALC::FieldseriesHandlerList_var
314 fieldseriesHandlerList = new MEDCALC::FieldseriesHandlerList();
315 fieldseriesHandlerList->length(_fieldseriesHandlerMap.size());
317 // Scan the map looking for fieldseries defined on the specified mesh
319 FieldseriesHandlerMapIterator it;
320 for ( it=_fieldseriesHandlerMap.begin(); it != _fieldseriesHandlerMap.end(); it++) {
321 if ( it->second->meshid == meshId ) {
322 fieldseriesHandlerList[itemIdx] = *(it->second);
327 // Adjust the length to the real number of elements
328 fieldseriesHandlerList->length(itemIdx);
329 return fieldseriesHandlerList._retn();
333 * A fieldseries is a timeseries of fields. Then the list of fields is
334 * the different time iterations defined for the specified field id.
336 MEDCALC::FieldHandlerList * MEDDataManager_i::getFieldListInFieldseries(CORBA::Long fieldseriesId) {
337 // We initiate a list with the maximum length
338 MEDCALC::FieldHandlerList_var fieldHandlerList = new MEDCALC::FieldHandlerList();
339 fieldHandlerList->length(_fieldHandlerMap.size());
341 // Scan the map looking for field defined on the specified mesh
343 FieldHandlerMapIterator it;
344 for ( it=_fieldHandlerMap.begin(); it != _fieldHandlerMap.end(); it++) {
345 if ( it->second->fieldseriesId == fieldseriesId ) {
346 fieldHandlerList[itemIdx] = *(it->second);
351 // Adjust the length to the real number of elements
352 fieldHandlerList->length(itemIdx);
353 return fieldHandlerList._retn();
357 * Get the field id of a field series at a given timestep
359 CORBA::Long MEDDataManager_i::getFieldIdAtTimestamp(CORBA::Long fieldseriesId, double timestampOfPvAnimation) {
360 // Scan the map looking for field defined on the specified mesh at given timestep
362 CORBA::Long fieldId = 0;
363 double timestampOfField;
364 FieldHandlerMapIterator it;
365 for ( it=_fieldHandlerMap.begin(); it != _fieldHandlerMap.end(); it++) {
366 if ( it->second->fieldseriesId == fieldseriesId ) {
368 // set the fieldId to the first one in case it is not found
369 fieldId = it->second->id;
371 timestampOfField = getFieldTimestamp(it->second->id);
372 if (timestampOfField == timestampOfPvAnimation) {
373 fieldId = it->second->id;
383 * This returns the whole set of fields handlers for all datasource
384 * that have been loaded using loadDatasource.
386 MEDCALC::FieldHandlerList * MEDDataManager_i::getFieldHandlerList() {
387 MEDCALC::FieldHandlerList_var fieldHandlerSeq = new MEDCALC::FieldHandlerList();
388 fieldHandlerSeq->length(_fieldHandlerMap.size());
391 FieldHandlerMapIterator fieldIt;
392 for ( fieldIt=_fieldHandlerMap.begin(); fieldIt != _fieldHandlerMap.end(); fieldIt++) {
393 fieldHandlerSeq[sequenceId] = *(fieldIt->second);
396 return fieldHandlerSeq._retn();
400 * This returns a copy of the fieldHandler associated to the specified id.
402 MEDCALC::FieldHandler * MEDDataManager_i::getFieldHandler(CORBA::Long fieldHandlerId) {
403 // LOG("getFieldHandler: START")
405 FieldHandlerMapIterator fieldIt = _fieldHandlerMap.find(fieldHandlerId);
406 if ( fieldIt != _fieldHandlerMap.end() ) {
407 // >>> WARNING: CORBA struct specification indicates that the
408 // assignment acts as a destructor for the structure that its
409 // pointed to. The values of the fields are copied first in the new
410 // structure that receives the assignment and finally the initial
411 // structure is destroyed. In the present case, WE WANT to keep
412 // the initial fieldHandler in the map. We must then make a deep
413 // copy of the structure found in the map and return the copy. The
414 // CORBA struct specification indicates that a deep copy can be
415 // done using the copy constructor. <<<
416 return new MEDCALC::FieldHandler(*(fieldIt->second));
422 * This returns a string representation of the field associated to the specified id.
424 char * MEDDataManager_i::getFieldRepresentation(CORBA::Long fieldHandlerId) {
425 LOG("getFieldRepresentation: START")
426 MEDCALC::FieldHandler * fieldHandler = getFieldHandler(fieldHandlerId);
427 MEDCouplingFieldDouble* fieldDouble = getFieldDouble(fieldHandler);
428 return CORBA::string_dup(fieldDouble->getArray()->repr().c_str());
431 void MEDDataManager_i::saveFields(const char * filepath,
432 const MEDCALC::FieldIdList & fieldIdList)
434 LOG("saveFields to : " << filepath);
436 // We first have to check if the target filepath is writable
437 // (segmentation fault in med otherwise)
438 if (!Kernel_Utils::IsWritable(Kernel_Utils::GetDirName(std::string(filepath)))) {
439 std::string message =
440 std::string("The target filepath ") +
441 std::string(filepath) +
442 std::string(" is not writable");
444 throw KERNEL::createSalomeException(message.c_str());
447 if ( fieldIdList.length() == 0 ) {
448 throw KERNEL::createSalomeException("No fields to save");
451 // Consider the first field to initiate the med file
452 CORBA::Long fieldHandlerId = fieldIdList[0];
453 MEDCALC::FieldHandler * fieldHandler = getFieldHandler(fieldHandlerId);
454 MEDCouplingFieldDouble* fieldDouble = getFieldDouble(fieldHandler);
457 bool writeFromScratch = true;
458 WriteField(filepath, fieldDouble, writeFromScratch);
460 writeFromScratch = false;
461 for(CORBA::ULong i=1; i<fieldIdList.length(); i++) {
462 fieldHandlerId = fieldIdList[i];
463 fieldHandler = getFieldHandler(fieldHandlerId);
464 fieldDouble = getFieldDouble(fieldHandler);
465 WriteField(filepath, fieldDouble, writeFromScratch);
468 catch (INTERP_KERNEL::Exception &ex) {
469 std::string message =
470 std::string("Error when saving file ") +
471 std::string(filepath) + std::string(" : ") + ex.what();
472 throw KERNEL::createSalomeException(message.c_str());
474 catch (const std::exception& ex) {
475 std::string message =
476 std::string("Error when saving file ") +
477 std::string(filepath) + std::string(" : ") + ex.what();
478 throw KERNEL::createSalomeException(message.c_str());
484 * This function must be used to indicate that the field with the
485 * specified id must be considered as persistent (if persistent is
486 * true) or not persistent (if persistent is false). If a field is
487 * marked as persistent, then it is automatically saved when the
488 * function savePersistentFields is called.
490 void MEDDataManager_i::markAsPersistent(CORBA::Long fieldHandlerId, bool persistent) {
491 LOG("mark as persistent : id="<<fieldHandlerId);
492 _fieldPersistencyMap[fieldHandlerId] = persistent;
495 void MEDDataManager_i::savePersistentFields(const char * filepath) {
496 LOG("savePersistentFields to : " << filepath);
497 std::vector<long> listId;
499 FieldPersistencyMapIterator mapIt;
500 for ( mapIt = _fieldPersistencyMap.begin(); mapIt != _fieldPersistencyMap.end(); mapIt++) {
501 if ( mapIt->second == true ) {
502 listId.push_back(mapIt->first);
506 MEDCALC::FieldIdList fieldIdList;
507 fieldIdList.length(listId.size());
508 for (int i=0; i<(int)listId.size(); i++) {
509 fieldIdList[i] = CORBA::Long(listId[i]);
513 this->saveFields(filepath, fieldIdList);
515 catch (const SALOME::SALOME_Exception & ex) {
518 catch (const std::exception& ex) {
519 std::string message =
520 std::string("Error when saving file ") +
521 std::string(filepath) + std::string(" : ") + ex.what();
522 throw KERNEL::createSalomeException(message.c_str());
527 * This function is responsible for creating the FieldHandler
528 * instances. You must use this function because it manages
529 * automatically the identifier value (autoincrementation of a static
532 MEDCALC::FieldHandler * MEDDataManager_i::newFieldHandler(const char * fieldname,
533 const char * meshname,
539 MEDCALC::FieldHandler * fieldHandler = new MEDCALC::FieldHandler();
540 fieldHandler->id = _fieldLastId; _fieldLastId++;
541 fieldHandler->fieldname = fieldname;
542 fieldHandler->meshname = meshname;
543 fieldHandler->type = type;
544 fieldHandler->iteration = iteration;
545 fieldHandler->order = order;
546 fieldHandler->source = source;
551 * This updates the metadata of the field identified by its id with
552 * the data of the given field handler. Returns a copy of the updated
553 * handler (that should be identical to the given field handler for
554 * all data but not for the id that is an invariant for all session
556 * WARN: you should be warned that this function could leave the data
557 * model in a non-coherent state, by example if you change the mesh
558 * name while the mesh has not been updated.
560 MEDCALC::FieldHandler * MEDDataManager_i::updateFieldHandler(CORBA::Long fieldHandlerId,
561 const char * fieldname,
564 const char * source) {
565 FieldHandlerMapIterator fieldIt = _fieldHandlerMap.find(fieldHandlerId);
566 if ( fieldIt != _fieldHandlerMap.end() ) {
567 // Update the attributes
568 // >>> WARN: note that the id of a handler registered in the map
569 // SHOULD NEVER be modified because it is the identifier used in
570 // the whole application for this field all the session long.
572 fieldIt->second->fieldname = fieldname;
573 fieldIt->second->iteration = iteration;
574 fieldIt->second->order = order;
575 fieldIt->second->source = source;
577 return new MEDCALC::FieldHandler(*fieldIt->second);
582 MEDCouplingUMesh * MEDDataManager_i::getUMesh(long meshHandlerId) {
584 LOG("getUMesh: START")
586 MEDCouplingUMesh * myMesh = NULL;
587 if ( _meshMap.count(meshHandlerId) > 0 ) {
588 // The mesh has been found in the map
589 myMesh = _meshMap[meshHandlerId];
591 // The mesh is not loaded yet ==> load it and register it in the map
592 LOG("getUMesh: the mesh must be loaded. meshid="<<meshHandlerId);
593 if ( _meshHandlerMap[meshHandlerId] == NULL ) {
594 std::string message =
595 std::string("No mesh for id=") + ToString(meshHandlerId);
596 LOG("getUMesh: "<<message);
597 throw KERNEL::createSalomeException(message.c_str());
600 long sourceid = _meshHandlerMap[meshHandlerId]->sourceid;
601 std::string filepath(source_to_file((_datasourceHandlerMap[sourceid])->uri));
602 const char * meshName = _meshHandlerMap[meshHandlerId]->name;
603 int meshDimRelToMax = 0;
604 myMesh = ReadUMeshFromFile(filepath,meshName,meshDimRelToMax);
605 _meshMap[meshHandlerId] = myMesh;
611 * Try to retrieve the id of the specified mesh, i.e. the key it is
612 * registered with in the internal meshes map.
614 long MEDDataManager_i::getUMeshId(const MEDCouplingMesh * mesh) {
616 MeshMapIterator it = _meshMap.begin();
617 while ( it != _meshMap.end() ) {
618 found = (it->second == mesh);
624 return LONG_UNDEFINED;
628 * Get the timestamp associated to a field
630 double MEDDataManager_i::getFieldTimestamp(CORBA::Long fieldHandlerId)
632 LOG("getFieldTimestamp(" << fieldHandlerId << ")");
634 MEDCALC::FieldHandler * fieldHandler = getFieldHandler(fieldHandlerId);
636 // if the field is in a file, get the timestamp by MEDLoader tiny information
637 long meshHandlerId = fieldHandler->meshid;
638 long sourceid = _meshHandlerMap[meshHandlerId]->sourceid;
639 if (isSourceInFile(fieldHandler->source))
641 const char * meshSourceUri = (_datasourceHandlerMap[sourceid])->uri;
642 std::string fileName(source_to_file(meshSourceUri));
643 const char * fieldName = fieldHandler->fieldname;
644 //const char * meshName = _meshHandlerMap[meshHandlerId]->name; // todo: unused
645 timestamp = GetTimeAttachedOnFieldIteration(fileName.c_str(), fieldName, fieldHandler->iteration, fieldHandler->order);
646 LOG("timestamp in med file is " << timestamp);
650 // else get the timestamp with MEDCouplingField
651 int iteration, order;
652 // WARN: note that the variables "iteration" and "order" are passed
653 // by reference to the function getTime (see documentation of
654 // MEDCouplingField). As a consequence, the values of these
655 // variables are updated by this function call. This is the means to
656 // retrieve the iteration and order of the field.
657 MEDCouplingFieldDouble* fieldDouble = getFieldDouble(fieldHandler);
658 timestamp = fieldDouble->getTime(iteration, order);
659 LOG("timestamp in MEDCouplingFieldDouble is " << timestamp);
665 * This method returns the physical data of the specified field,
666 * i.e. the MEDCoupling field associated to the specified field
667 * handler. If the field source is a file and the data ar not loaded
668 * yet, the this function load the data from the file in a MEDCoupling
669 * field instance. Otherwise, it just returns the MEDCoupling field
672 MEDCouplingFieldDouble * MEDDataManager_i::getFieldDouble(const MEDCALC::FieldHandler * fieldHandler)
675 LOG("getFieldDouble: START with id="<<fieldHandler->id);
677 if ( _fieldDoubleMap.count(fieldHandler->id) > 0 ) {
678 // The MEDCoupling field data are already loaded. Just return the
679 // reference of the MEDCouplingFieldDouble pointer
680 return _fieldDoubleMap[fieldHandler->id];
683 // The MEDCoupling field data are not loaded yet. Load the data and
684 // register the MEDCoupling field in our internal map an all the
685 // associated data if needed (i.e. the underlying mesh).
687 // At this step, the mesh handler needs a meshid correctly
688 // set. Normally, we should arrive at this step only in the case
689 // where the field is loaded from a file ==> the meshid is defined
690 // (see the loadDatasource function).
692 // >>>> __GBO__ TO BE CHECKED AND SERIOUSLY TESTED. There at least
693 // one case where we can arrive here with no previous call to
694 // loadDataSource: for example the field handler list can be obtained
695 // from a call to addFieldsFromFile instead of loadDataSource (see
696 // for example the getFieldRepresentation service of the
697 // dataManager, that comes here and then calls getUMesh where we
698 // need a map initialized only in loadDataSource) <<<<
699 long meshid = fieldHandler->meshid;
701 // We first have to check if the associated mesh is already loaded
702 // and to load it if needed. The loaded meshes are registered in a
703 // map whose key is the mesh handler id. This checking is
704 // automatically done by the function getUMesh. It's important to do
705 // it before the loading of field data to prevent from the case
706 // where the mesh would not have been loaded already (in the
707 // previous field loading).
708 MEDCouplingUMesh * myMesh =this->getUMesh(meshid);
710 long sourceid = _meshHandlerMap[meshid]->sourceid;
712 std::string filepath(source_to_file((_datasourceHandlerMap[sourceid])->uri));
713 std::string meshName(myMesh->getName());
714 LOG("getFieldDouble: field "<<fieldHandler->fieldname<<" loaded from file "<<filepath);
715 TypeOfField type = (TypeOfField)fieldHandler->type;
716 int meshDimRelToMax = 0;
717 MCAuto<MEDCouplingField> myFieldTmpp(ReadField(type,
721 std::string(fieldHandler->fieldname),
722 fieldHandler->iteration,
723 fieldHandler->order));
724 MCAuto<MEDCouplingFieldDouble> myField(DynamicCast<MEDCouplingField,MEDCouplingFieldDouble>(myFieldTmpp));
725 myField->setMesh(myMesh);
726 _fieldDoubleMap[fieldHandler->id] = myField.retn();
731 * This adds the specified MEDCoupling field in the collection managed
732 * by this DataManager. The associated FieldHandler is returned. This
733 * is typically used in a context where the MEDCoupling field is
734 * created from scratch, for example by operations in the
736 * @param[in] fieldDouble the MEDCouplingFieldDouble instance to add
737 * @param[in] meshHandlerId the id of the meshHandler this filed is associated to.
738 * @return a copy of the FieldHandler registered in the internal map for this field.
740 MEDCALC::FieldHandler * MEDDataManager_i::addField(MEDCouplingFieldDouble * fieldDouble,
743 std::string fieldName(fieldDouble->getName());
744 std::string meshName(fieldDouble->getMesh()->getName());
745 TypeOfField type = fieldDouble->getTypeOfField();
747 int iteration, order;
748 // WARN: note that the variables "iteration" and "order" are passed
749 // by reference to the function getTime (see documentation of
750 // MEDCouplingField). As a consequence, the values of these
751 // variables are updated by this function call. This is the means to
752 // retrieve the iteration and order of the field.
753 /*double timestamp = */fieldDouble->getTime(iteration, order); // todo: unused
755 // For the fields that are created in memory (by operations for
756 // example), the convention for the source attribute is to specify
757 // the fielddouble name, because this name describes the operation
758 // the field has been created with.
759 string * source = new string("mem://"); source->append(fieldName);
760 MEDCALC::FieldHandler * fieldHandler = newFieldHandler(fieldName.c_str(),
767 if ( meshHandlerId == LONG_UNDEFINED ) {
768 // We have to guess the id of the underlying mesh to preserve data
769 // integrity (a fieldHandler must have an attribute that contains
770 // the id of its underlying mesh):
772 // WARNING: it's better to let the client code (the one who calls the
773 // function addField) to specify this meshid. This guess procedure is
774 // not reliable, it's just to have a second chance.
776 LOG("addField: The mesh id is not defined. Trying to guess from the mesh name "<<meshName);
777 long meshid = this->getUMeshId(fieldDouble->getMesh());
778 fieldHandler->meshid = meshid;
779 if ( meshid == LONG_UNDEFINED ) {
780 // No mesh has been found in the internal map
781 LOG("addField: The mesh id for the mesh "<<meshName<<" can't be retrieved from the field "<<fieldName);
782 // _GBO_ : Maybe it could be better to raise an exception
786 fieldHandler->meshid = meshHandlerId;
789 _fieldHandlerMap[fieldHandler->id] = fieldHandler;
790 _fieldDoubleMap[fieldHandler->id] = fieldDouble;
791 // >>> WARNING: CORBA structure assignment specification ==> return
792 // >>> a deep copy to avoid the destruction of the fieldHandler
793 // >>> registered in the map (assignment acts as a destructor for
794 // >>> CORBA struct).
795 return new MEDCALC::FieldHandler(*fieldHandler);
799 * This function updates the meta-data "fieldname" associated to the
802 void MEDDataManager_i::updateFieldMetadata(CORBA::Long fieldHandlerId,
803 const char * fieldname,
804 CORBA::Long iteration,
808 // We have to update the field handler registered in the internal
809 // map AND the associated fieldDouble loaded in memory.
810 MEDCALC::FieldHandler * fieldHandler = getFieldHandler(fieldHandlerId);
811 updateFieldHandler(fieldHandlerId,fieldname,iteration,order,source);
813 MEDCouplingFieldDouble* fieldDouble = getFieldDouble(fieldHandler);
814 fieldDouble->setName(fieldname);
816 // _GBO_ TO BE IMPLEMENTED: iteration and order
820 * This can be used to associate to the specified field another mesh
821 * support than its current one. This is typically needed to operate 2
822 * fields defined on the same mesh but coming from different med
823 * files. In this case, the underlying meshes are different mesh
824 * objects (from the MEDCoupling point of view) and then no operation
825 * can be allowed by MEDCoupling. The operation of course fails if the
826 * new mesh is not identical to the old one.
828 void MEDDataManager_i::changeUnderlyingMesh(CORBA::Long fieldHandlerId, CORBA::Long meshHandlerId) {
830 MEDCALC::FieldHandler * fieldHandler = getFieldHandler(fieldHandlerId);
831 MEDCouplingFieldDouble* fieldDouble = getFieldDouble(fieldHandler);
832 MEDCouplingMesh * newMesh = getUMesh(meshHandlerId);
835 fieldDouble->changeUnderlyingMesh(newMesh,10,1e-12);
837 catch (INTERP_KERNEL::Exception &ex) {
838 std::string * message = new std::string("Error when changing the underlying mesh : ");
839 message->append(ex.what());
840 throw KERNEL::createSalomeException(message->c_str());
843 // The change of mesh is OK, then we can update the meta-data
844 _fieldHandlerMap[fieldHandlerId]->meshid = meshHandlerId;
845 _fieldHandlerMap[fieldHandlerId]->meshname = _meshHandlerMap[meshHandlerId]->name;
848 // WARN: if this field has already been request by the tui for
849 // manipulation (in a fieldproxy), then the data should be
853 INTERP_KERNEL::IntersectionType MEDDataManager_i::_getIntersectionType(const char* intersType) {
854 std::string type(intersType);
855 if (type == "Triangulation") {
856 return INTERP_KERNEL::Triangulation;
858 else if (type == "Convex") {
859 return INTERP_KERNEL::Convex;
861 else if (type == "Geometric2D") {
862 return INTERP_KERNEL::Geometric2D;
864 else if (type == "PointLocator") {
865 return INTERP_KERNEL::PointLocator;
867 else if (type == "Barycentric") {
868 return INTERP_KERNEL::Barycentric;
870 else if (type == "BarycentricGeo2D") {
871 return INTERP_KERNEL::BarycentricGeo2D;
874 std::string message("Error when trying to interpolate field: ");
875 message.append("Unrecognized intersection type: ");
876 message.append(type);
877 throw KERNEL::createSalomeException(message.c_str());
880 MEDCoupling::NatureOfField MEDDataManager_i::_getNatureOfField(const char* fieldNature) {
881 std::string nature(fieldNature);
882 if (nature == "NoNature") {
885 else if (nature == "IntensiveMaximum") {
886 return IntensiveMaximum;
888 else if (nature == "ExtensiveMaximum") {
889 return ExtensiveMaximum;
891 else if (nature == "ExtensiveConservation") {
892 return ExtensiveConservation;
894 else if (nature == "IntensiveConservation") {
895 return IntensiveConservation;
898 std::string message("Error when trying to interpolate field: ");
899 message.append("Unrecognized field nature: ");
900 message.append(nature);
901 throw KERNEL::createSalomeException(message.c_str());
904 MEDCALC::FieldHandler* MEDDataManager_i::interpolateField(CORBA::Long fieldHandlerId, CORBA::Long meshHandlerId, const MEDCALC::InterpolationParameters& params) {
905 MEDCALC::FieldHandler* fieldHandler = getFieldHandler(fieldHandlerId);
906 MEDCouplingFieldDouble* sourceField = getFieldDouble(fieldHandler);
907 MEDCouplingMesh* sourceMesh = getUMesh(fieldHandler->meshid);
908 MEDCouplingMesh* targetMesh = getUMesh(meshHandlerId);
910 double precision = params.precision;
911 INTERP_KERNEL::IntersectionType interpType = this->_getIntersectionType(params.intersectionType);
912 std::string method(params.method);
913 double defaultValue = params.defaultValue;
914 bool reverse = params.reverse;
915 MEDCoupling::NatureOfField nature = this->_getNatureOfField(params.nature);
917 // 1. Build remapper between sourceMesh and targetMesh (compute interpolation matrix)
918 MEDCouplingRemapper remapper;
919 remapper.setPrecision(precision);
920 remapper.setIntersectionType(interpType);
921 remapper.prepare(sourceMesh, targetMesh, method.c_str());
923 // 2. Apply interpolation to the field
924 sourceField->setNature(nature);
925 MEDCouplingFieldDouble* targetField = NULL;
927 targetField = remapper.reverseTransferField(sourceField, defaultValue);
929 targetField = remapper.transferField(sourceField, defaultValue);
931 targetField->setMesh(targetMesh);
932 targetField->setName(targetMesh->getName() + "_field");
934 // 3. Create and register field handler
935 MEDCALC::FieldHandler* fieldResultHandler = this->addField(targetField, this->getUMeshId(targetField->getMesh()));
936 return fieldResultHandler;
942 * This functions display the internal data of the MEDDataManager on
943 * the server side (data in the SALOME container).
945 void MEDDataManager_i::serverlog() {
947 LOG("==== Field Handler Map ====================================================");
948 LOG("Size = "<<_fieldHandlerMap.size());
949 FieldHandlerMapIterator fhmIt;
950 for ( fhmIt = _fieldHandlerMap.begin(); fhmIt != _fieldHandlerMap.end(); fhmIt++) {
951 LOG("------------------------------------- id = "<<ToString(fhmIt->first));
952 LOG("- id \t= "<<fhmIt->second->id);
953 LOG("- fieldname \t= "<<fhmIt->second->fieldname);
954 LOG("- meshname \t= "<<fhmIt->second->meshname);
957 LOG("==== Field Double Map ====================================================");
958 LOG("Size = "<<_fieldDoubleMap.size());
959 FieldDoubleMapIterator fdmIt;
960 for ( fdmIt = _fieldDoubleMap.begin(); fdmIt != _fieldDoubleMap.end(); fdmIt++) {
961 LOG("------------------------------------- id = "<<ToString(fdmIt->first));
962 LOG("- fieldname \t= "<<fdmIt->second->getName());
963 LOG("- meshname \t= "<<fdmIt->second->getMesh()->getName());
968 * The event listener is created inside the GUI by the
969 * WorkspaceController. This function is called by the WorkspaceController to
970 * store the event listener IOR for the time of the session. Then this
971 * IOR can be available to any point of the application that can
972 * request the data manager (the python console for example).
974 void MEDDataManager_i::setEventListenerIOR(const char * ior) {
975 _medEventListenerIOR = ior;
978 * Return the IOR of the event listener that resides in the
979 * GUI. Having the IOR, you can restore the CORBA object by using:
981 * In a python SALOME context:
984 * >>> salome.salome_init()
985 * >>> myobject = salome.orb.string_to_object(ior)
987 * In a C++ SALOME context: (to do if needed)
989 char * MEDDataManager_i::getEventListenerIOR() {
990 if ( _medEventListenerIOR == "" ) {
991 throw KERNEL::createSalomeException("The event listener IOR is not defined");
993 // WARN: return a copy because the pointer memory will be released
994 // (CORBA specification)
995 return CORBA::string_dup( _medEventListenerIOR.c_str() );