// Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File : DriverMED_W_Field.cxx // Created : Thu Feb 27 17:45:00 2014 // Author : eap #include "DriverMED_W_Field.h" #include "DriverMED.hxx" #include "DriverMED_W_SMESHDS_Mesh.h" #include "MED_Factory.hxx" #include "MED_Utilities.hxx" #include "MED_Wrapper.hxx" #include "SMDS_IteratorOnIterators.hxx" #include "SMDS_MeshElement.hxx" #include "SMDS_SetIterator.hxx" #include "SMESHDS_Mesh.hxx" //================================================================================ /*! * \brief Constructor */ //================================================================================ DriverMED_W_Field::DriverMED_W_Field(): //_medFileID( -1 ), _elemType( SMDSAbs_All ), _dt( -1 ), _it( -1 ) { } //================================================================================ /*! * \brief Sets basic data * \param [in] mesh - supporting mesh * \param [in] fieldName - name of a field * \param [in] type - type of supporting elements * \param [in] nbComps - number of components * \param [in] isIntData - type of data: double or integer */ //================================================================================ bool DriverMED_W_Field::Set(SMESHDS_Mesh * mesh, const std::string & fieldName, SMDSAbs_ElementType type, const int nbComps, const bool isIntData) { _fieldName = fieldName; _compNames.resize( nbComps, "" ); if ( type == SMDSAbs_All ) { if ( mesh->NbVolumes() > 0 ) type = SMDSAbs_Volume; else if ( mesh->NbFaces() > 0 ) type = SMDSAbs_Face; else if ( mesh->NbEdges() > 0 ) type = SMDSAbs_Edge; else type = SMDSAbs_Node; } if ( myMesh != mesh ) { _nbElemsByGeom.clear(); for ( int iG = 0; iG < SMDSEntity_Last; ++iG ) _elemsByGeom[iG].clear(); SetMesh( mesh ); } // find out "MED order" of elements - sort elements by geom type int nbElems; if ( _nbElemsByGeom.empty() || _elemType != type ) { _elemType = type; _nbElemsByGeom.resize( 1, std::make_pair( SMDSEntity_Last, 0 )); // count nb of elems of each geometry for ( int iG = 0; iG < SMDSEntity_Last; ++iG ) { SMDSAbs_EntityType geom = (SMDSAbs_EntityType) iG; SMDSAbs_ElementType t = SMDS_MeshCell::ElemType( geom ); if ( t != _elemType ) continue; nbElems = mesh->GetMeshInfo().NbElements( geom ); if ( nbElems < 1 ) continue; _nbElemsByGeom.push_back( std::make_pair( geom, nbElems + _nbElemsByGeom.back().second )); } // add nodes of missing 0D elements on VERTEXes if ( _addODOnVertices && _elemType == SMDSAbs_0DElement ) { std::vector< const SMDS_MeshElement* >& nodes = _elemsByGeom[SMDSEntity_Node]; if ( nodes.empty() ) DriverMED_W_SMESHDS_Mesh::getNodesOfMissing0DOnVert( myMesh, nodes ); if ( !nodes.empty() ) { if ( _nbElemsByGeom.size() == 1 ) _nbElemsByGeom.push_back( std::make_pair( SMDSEntity_0D, 0)); _nbElemsByGeom.push_back( std::make_pair( SMDSEntity_Node, nodes.size() + _nbElemsByGeom.back().second )); } } // sort elements by their geometry int iGeoType, nbGeomTypes = _nbElemsByGeom.size() - 1; if ( nbGeomTypes > 1 ) { for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG ) { iGeoType = _nbElemsByGeom[iG].first; nbElems = _nbElemsByGeom[iG].second - _nbElemsByGeom[iG-1].second; _elemsByGeom[ iGeoType ].reserve( nbElems ); } iGeoType = _nbElemsByGeom[1].first; // for missing 0D if ( _elemsByGeom[ iGeoType ].empty() ) { nbElems = mesh->GetMeshInfo().NbElements( _elemType ); SMDS_ElemIteratorPtr eIt = mesh->elementsIterator( _elemType ); for ( int iE = 0; iE < nbElems && eIt->more(); ++iE ) { const SMDS_MeshElement* e = eIt->next(); _elemsByGeom[ e->GetEntityType() ].push_back( e ); } } } } _intValues.clear(); _dblValues.clear(); // allocate memory for values nbElems = _nbElemsByGeom.empty() ? 0 : _nbElemsByGeom.back().second; if ( isIntData ) _intValues.reserve( nbElems * nbComps ); else _dblValues.reserve( nbElems * nbComps ); return nbElems && nbComps; } //================================================================================ /*! * \brief Set a name of a component countered from zero */ //================================================================================ void DriverMED_W_Field::SetCompName(const int iComp, const char* name) { if ( (int)_compNames.size() <= iComp ) _compNames.resize( iComp + 1 ); _compNames[ iComp ] = name; } //================================================================================ /*! * \brief Sets numdt and numit field features. Call this fun before AddValue()! */ //================================================================================ void DriverMED_W_Field::SetDtIt(const int dt, const int it) { _dt = dt; _it = it; _intValues.clear(); _dblValues.clear(); } //================================================================================ /*! * \brief Adds a float field value */ //================================================================================ void DriverMED_W_Field::AddValue( double val ) { _dblValues.push_back( val ); } //================================================================================ /*! * \brief Adds an integer field value */ //================================================================================ void DriverMED_W_Field::AddValue( int val ) { _intValues.push_back( val ); } //================================================================================ /*! * Returns elements in the order they are written in MED file */ //================================================================================ SMDS_ElemIteratorPtr DriverMED_W_Field::GetOrderedElems() { if ( _nbElemsByGeom.size() < 2 ) return SMDS_ElemIteratorPtr(); if ( _nbElemsByGeom.size() == 2 ) // sole geom type of elements return myMesh->elementsIterator( _elemType ); std::vector< SMDS_ElemIteratorPtr > iterVec( _nbElemsByGeom.size()-1 ); for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG ) { int iGeoType = _nbElemsByGeom[ iG ].first; iterVec[ iG-1 ] = SMDS_ElemIteratorPtr ( new SMDS_ElementVectorIterator( _elemsByGeom[ iGeoType ].begin(), _elemsByGeom[ iGeoType ].end() )); } typedef SMDS_IteratorOnIterators < const SMDS_MeshElement *, std::vector< SMDS_ElemIteratorPtr > > TItIterator; return SMDS_ElemIteratorPtr( new TItIterator( iterVec )); } //================================================================================ /*! * Writes a field to the file */ //================================================================================ Driver_Mesh::Status DriverMED_W_Field::Perform() { if ( myFile.empty() ) return addMessage("File name not set", /*isFatal=*/true ); // 'fatal' means 'bug' if ( myMeshId < 0 && myMeshName.empty() ) return addMessage("Mesh in file not specified", /*isFatal=*/true ); if ( _nbElemsByGeom.size() < 2 ) return addMessage("No values to write", /*isFatal=*/false ); if ( !myMesh ) return addMessage("Supporting mesh not set", /*isFatal=*/true ); int version = -1, major, minor, release; if ( MED::GetMEDVersion( myFile, major, minor, release )) version = major * 10 + minor; MED::PWrapper medFile = MED::CrWrapperW( myFile, version ); MED::PMeshInfo meshInfo; if ( myMeshId > 0 ) { meshInfo = medFile->GetPMeshInfo( myMeshId ); } else { // look for a mesh by name int aNbMeshes = medFile->GetNbMeshes(); for ( int iMesh = aNbMeshes; iMesh > 0 && myMeshId < 1; --iMesh ) { meshInfo = medFile->GetPMeshInfo( iMesh ); if ( !meshInfo || meshInfo->GetName() != myMeshName ) meshInfo.reset(); else myMeshId = iMesh; } } if (( !meshInfo ) || ( !myMeshName.empty() && meshInfo->GetName() != myMeshName )) { myMeshId = -1; return addMessage("DriverMED_W_Field: Specified mesh not found in the file", /*isFatal=*/true ); } // create a field MED::ETypeChamp dataType = _dblValues.empty() ? MED::eINT : MED::eFLOAT64; MED::PFieldInfo fieldInfo = medFile->CrFieldInfo( meshInfo, _compNames.size(), dataType ); fieldInfo->SetName( _fieldName ); for ( size_t iC = 0; iC < _compNames.size(); ++iC ) { fieldInfo->SetCompName( iC, _compNames[ iC ]); fieldInfo->SetUnitName( iC, ""); } if ( _compNames.size() > 1 ) { for ( size_t i = 0; i < fieldInfo->myCompNames.size()-1; ++i ) if ( !fieldInfo->myCompNames[i] ) fieldInfo->myCompNames[i] = ' '; } medFile->SetFieldInfo( fieldInfo ); // specific treatment of added 0D elements if ( _nbElemsByGeom.size() == 3 && _nbElemsByGeom[1].first == SMDSEntity_0D ) { _nbElemsByGeom[1].second += _nbElemsByGeom[2].second; _nbElemsByGeom.resize( 2 ); } // create a time stamp MED::TGeom2Size type2nb; for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG ) { SMDSAbs_EntityType smdsType = _nbElemsByGeom[iG].first; MED::EGeometrieElement medType = (MED::EGeometrieElement) DriverMED::GetMedGeoType( smdsType ); int nbElems = _nbElemsByGeom[iG].second - _nbElemsByGeom[iG-1].second; type2nb.insert( std::make_pair( medType, nbElems )); } MED::EEntiteMaillage entity = ( _elemType == SMDSAbs_Node ? MED::eNOEUD : MED::eMAILLE ); MED::PTimeStampInfo timeStampInfo = medFile->CrTimeStampInfo( fieldInfo, entity, type2nb ); timeStampInfo->myNumDt = _dt; timeStampInfo->myNumOrd = _it; MED::PTimeStampValueBase timeStampVal = medFile->CrTimeStampValue( timeStampInfo, dataType ); MED::PFloatTimeStampValue timeStampFltVal = timeStampVal; MED::PIntTimeStampValue timeStampIntVal = timeStampVal; // set values int iVal = 0; MED::TFloat* ptrDbl = 0; MED::TInt* ptrInt = 0; for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG ) { SMDSAbs_EntityType smdsType = _nbElemsByGeom[iG].first; MED::EGeometrieElement medType = (MED::EGeometrieElement) DriverMED::GetMedGeoType( smdsType ); int nbElems = ( _nbElemsByGeom[iG].second - _nbElemsByGeom[iG-1].second ) * _compNames.size(); if ( dataType == MED::eFLOAT64 ) { ptrDbl = timeStampFltVal->GetMeshValue( medType ).GetPointer(); for ( int i = 0; i < nbElems; ++i, ++iVal ) ptrDbl[ i ] = _dblValues[ iVal ]; } else { ptrInt = timeStampIntVal->GetMeshValue( medType ).GetPointer(); for ( int i = 0; i < nbElems; ++i, ++iVal ) ptrInt[ i ] = _intValues[ iVal ]; } } // write medFile->SetTimeStampValue( timeStampVal ); _dblValues.clear(); _intValues.clear(); return DRS_OK; } namespace DriverMED // Implementation of functions declared in DriverMED.hxx { //================================================================================ /*! * Returns a vector containing MED::EGeometrieElement for each SMDSAbs_EntityType */ //================================================================================ const std::vector< MED::EGeometrieElement >& getMedTypesVec() { static std::vector< MED::EGeometrieElement > theVec; if ( theVec.empty() ) { theVec.resize( SMDSEntity_Last, MED::eAllGeoType ); theVec[ SMDSEntity_Node ] = MED::eNONE ; theVec[ SMDSEntity_0D ] = MED::ePOINT1 ; theVec[ SMDSEntity_Edge ] = MED::eSEG2 ; theVec[ SMDSEntity_Quad_Edge ] = MED::eSEG3 ; theVec[ SMDSEntity_Triangle ] = MED::eTRIA3 ; theVec[ SMDSEntity_Quad_Triangle ] = MED::eTRIA6 ; theVec[ SMDSEntity_BiQuad_Triangle ] = MED::eTRIA7 ; theVec[ SMDSEntity_Quadrangle ] = MED::eQUAD4 ; theVec[ SMDSEntity_Quad_Quadrangle ] = MED::eQUAD8 ; theVec[ SMDSEntity_BiQuad_Quadrangle ] = MED::eQUAD9 ; theVec[ SMDSEntity_Polygon ] = MED::ePOLYGONE; //theVec[ SMDSEntity_Quad_Polygon ] = MED::ePOLYGONE; // !! theVec[ SMDSEntity_Tetra ] = MED::eTETRA4 ; theVec[ SMDSEntity_Quad_Tetra ] = MED::eTETRA10 ; theVec[ SMDSEntity_Pyramid ] = MED::ePYRA5 ; theVec[ SMDSEntity_Quad_Pyramid ] = MED::ePYRA13 ; theVec[ SMDSEntity_Hexa ] = MED::eHEXA8 ; theVec[ SMDSEntity_Quad_Hexa ] = MED::eHEXA20 ; theVec[ SMDSEntity_TriQuad_Hexa ] = MED::eHEXA27 ; theVec[ SMDSEntity_Penta ] = MED::ePENTA6 ; theVec[ SMDSEntity_Quad_Penta ] = MED::ePENTA15 ; theVec[ SMDSEntity_BiQuad_Penta ] = MED::ePENTA18 ; theVec[ SMDSEntity_Hexagonal_Prism ] = MED::eOCTA12 ; theVec[ SMDSEntity_Polyhedra ] = MED::ePOLYEDRE; //theVec[ SMDSEntity_Quad_Polyhedra ] = MED::ePOLYEDRE; // !! theVec[ SMDSEntity_Ball ] = MED::eBALL ; } return theVec; } //================================================================================ /*! * Returns MED element geom type (MED::EGeometrieElement) by SMDS type */ //================================================================================ int GetMedGeoType( SMDSAbs_EntityType smdsType ) { return getMedTypesVec()[ smdsType ]; } //================================================================================ /*! * Returns SMDS element geom type by MED type (MED::EGeometrieElement) */ //================================================================================ SMDSAbs_EntityType GetSMDSType( int medType ) { const std::vector< MED::EGeometrieElement >& theVec = getMedTypesVec(); std::vector< MED::EGeometrieElement >::const_iterator i = std::find( theVec.begin(), theVec.end(), medType ); return SMDSAbs_EntityType( std::distance( theVec.begin(), i )); } }