+// Copyright (C) 2007-2014 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 "MED_Factory.hxx"
+#include "MED_Utilities.hxx"
+#include "MED_Wrapper.hxx"
+#include "SMDS_IteratorOnIterators.hxx"
+#include "SMDS_MeshElement.hxx"
+#include "SMDS_PolyhedralVolumeOfNodes.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, 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::toSmdsType( geom );
+ if ( t != _elemType ) continue;
+
+ nbElems = mesh->GetMeshInfo().NbElements( geom );
+ if ( nbElems < 1 ) continue;
+
+ _nbElemsByGeom.push_back( make_pair( geom, nbElems + _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 );
+ }
+ 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 ( _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 );
+
+ MED::PWrapper medFile = MED::CrWrapper( myFile, MED::eV2_2 );
+ 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("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 );
+
+ // 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( 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, i, nbE;
+ 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();
+}
+
+namespace DriverMED // Implemetation of fuctions 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_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 ));
+ }
+}