Salome HOME
Copyright update 2021
[modules/smesh.git] / src / DriverMED / DriverMED_W_Field.cxx
1 // Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File      : DriverMED_W_Field.cxx
24 // Created   : Thu Feb 27 17:45:00 2014
25 // Author    : eap
26
27 #include "DriverMED_W_Field.h"
28
29 #include "DriverMED.hxx"
30 #include "DriverMED_W_SMESHDS_Mesh.h"
31 #include "MED_Factory.hxx"
32 #include "MED_Utilities.hxx"
33 #include "MED_Wrapper.hxx"
34 #include "SMDS_IteratorOnIterators.hxx"
35 #include "SMDS_MeshElement.hxx"
36 #include "SMDS_SetIterator.hxx"
37 #include "SMESHDS_Mesh.hxx"
38
39 //================================================================================
40 /*!
41  * \brief Constructor
42  */
43 //================================================================================
44
45 DriverMED_W_Field::DriverMED_W_Field():
46   //_medFileID( -1 ),
47   _elemType( SMDSAbs_All ),
48   _dt( -1 ),
49   _it( -1 )
50 {
51 }
52
53 //================================================================================
54 /*!
55  * \brief Sets basic data
56  *  \param [in] mesh - supporting mesh
57  *  \param [in] fieldName - name of a field
58  *  \param [in] type - type of supporting elements
59  *  \param [in] nbComps - number of components
60  *  \param [in] isIntData - type of data: double or integer
61  */
62 //================================================================================
63
64 bool DriverMED_W_Field::Set(SMESHDS_Mesh *      mesh,
65                             const std::string & fieldName,
66                             SMDSAbs_ElementType type,
67                             const int           nbComps,
68                             const bool          isIntData)
69 {
70   _fieldName = fieldName;
71   _compNames.resize( nbComps, "" );
72
73   if ( type == SMDSAbs_All )
74   {
75     if ( mesh->NbVolumes() > 0 )
76       type = SMDSAbs_Volume;
77     else if ( mesh->NbFaces() > 0 )
78       type = SMDSAbs_Face;
79     else if ( mesh->NbEdges() > 0 )
80       type = SMDSAbs_Edge;
81     else
82       type = SMDSAbs_Node;
83   }
84   if ( myMesh != mesh )
85   {
86     _nbElemsByGeom.clear();
87     for ( int iG = 0; iG < SMDSEntity_Last; ++iG )
88       _elemsByGeom[iG].clear();
89     SetMesh( mesh );
90   }
91
92   // find out "MED order" of elements - sort elements by geom type
93   int nbElems;
94   if ( _nbElemsByGeom.empty() || _elemType != type )
95   {
96     _elemType = type;
97     _nbElemsByGeom.resize( 1, std::make_pair( SMDSEntity_Last, 0 ));
98
99     // count nb of elems of each geometry
100     for ( int iG = 0; iG < SMDSEntity_Last; ++iG )
101     {
102       SMDSAbs_EntityType  geom = (SMDSAbs_EntityType) iG;
103       SMDSAbs_ElementType    t = SMDS_MeshCell::ElemType( geom );
104       if ( t != _elemType ) continue;
105
106       nbElems = mesh->GetMeshInfo().NbElements( geom );
107       if ( nbElems < 1 ) continue;
108
109       _nbElemsByGeom.push_back( std::make_pair( geom, nbElems + _nbElemsByGeom.back().second ));
110     }
111     // add nodes of missing 0D elements on VERTEXes
112     if ( _addODOnVertices && _elemType == SMDSAbs_0DElement )
113     {
114       std::vector< const SMDS_MeshElement* >& nodes = _elemsByGeom[SMDSEntity_Node];
115       if ( nodes.empty() )
116         DriverMED_W_SMESHDS_Mesh::getNodesOfMissing0DOnVert( myMesh, nodes );
117       if ( !nodes.empty() )
118       {
119         if ( _nbElemsByGeom.size() == 1 )
120           _nbElemsByGeom.push_back( std::make_pair( SMDSEntity_0D, 0));
121         _nbElemsByGeom.push_back( std::make_pair( SMDSEntity_Node,
122                                                   nodes.size() + _nbElemsByGeom.back().second ));
123       }
124     }
125
126     // sort elements by their geometry
127     int iGeoType, nbGeomTypes = _nbElemsByGeom.size() - 1;
128     if ( nbGeomTypes > 1 )
129     {
130       for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG )
131       {
132         iGeoType = _nbElemsByGeom[iG].first;
133         nbElems  = _nbElemsByGeom[iG].second - _nbElemsByGeom[iG-1].second;
134         _elemsByGeom[ iGeoType ].reserve( nbElems );
135       }
136       iGeoType = _nbElemsByGeom[1].first; // for missing 0D
137       if ( _elemsByGeom[ iGeoType ].empty() )
138       {
139         nbElems = mesh->GetMeshInfo().NbElements( _elemType );
140         SMDS_ElemIteratorPtr eIt = mesh->elementsIterator( _elemType );
141         for ( int iE = 0; iE < nbElems && eIt->more(); ++iE )
142         {
143           const SMDS_MeshElement* e = eIt->next();
144           _elemsByGeom[ e->GetEntityType() ].push_back( e );
145         }
146       }
147     }
148   }
149   _intValues.clear();
150   _dblValues.clear();
151
152   // allocate memory for values
153   nbElems = _nbElemsByGeom.empty() ? 0 : _nbElemsByGeom.back().second;
154   if ( isIntData )
155     _intValues.reserve( nbElems * nbComps );
156   else
157     _dblValues.reserve( nbElems * nbComps );
158
159   return nbElems && nbComps;
160 }
161
162 //================================================================================
163 /*!
164  * \brief Set a name of a component countered from zero
165  */
166 //================================================================================
167
168 void DriverMED_W_Field::SetCompName(const int iComp, const char* name)
169 {
170   if ( (int)_compNames.size() <= iComp )
171     _compNames.resize( iComp + 1 );
172   _compNames[ iComp ] = name;
173 }
174
175 //================================================================================
176 /*!
177  * \brief Sets numdt and numit field features. Call this fun before AddValue()!
178  */
179 //================================================================================
180
181 void DriverMED_W_Field::SetDtIt(const int dt, const int it)
182 {
183   _dt = dt;
184   _it = it;
185   _intValues.clear();
186   _dblValues.clear();
187 }
188
189 //================================================================================
190 /*!
191  * \brief Adds a float field value 
192  */
193 //================================================================================
194
195 void DriverMED_W_Field::AddValue( double val )
196 {
197   _dblValues.push_back( val );
198 }
199
200 //================================================================================
201 /*!
202  * \brief Adds an integer field value 
203  */
204 //================================================================================
205
206 void DriverMED_W_Field::AddValue( int    val )
207 {
208   _intValues.push_back( val );
209 }
210
211 //================================================================================
212 /*!
213  * Returns elements in the order they are written in MED file
214  */
215 //================================================================================
216
217 SMDS_ElemIteratorPtr DriverMED_W_Field::GetOrderedElems()
218 {
219   if ( _nbElemsByGeom.size() < 2 )
220     return SMDS_ElemIteratorPtr();
221
222   if ( _nbElemsByGeom.size() == 2 )
223     // sole geom type of elements
224     return myMesh->elementsIterator( _elemType );
225
226   std::vector< SMDS_ElemIteratorPtr > iterVec( _nbElemsByGeom.size()-1 );
227   for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG )
228   {
229     int iGeoType = _nbElemsByGeom[ iG ].first;
230     iterVec[ iG-1 ] = SMDS_ElemIteratorPtr
231       ( new SMDS_ElementVectorIterator( _elemsByGeom[ iGeoType ].begin(),
232                                         _elemsByGeom[ iGeoType ].end() ));
233   }
234   typedef SMDS_IteratorOnIterators
235     < const SMDS_MeshElement *, std::vector< SMDS_ElemIteratorPtr > > TItIterator;
236   return SMDS_ElemIteratorPtr( new TItIterator( iterVec ));
237 }
238
239 //================================================================================
240 /*!
241  * Writes a field to the file
242  */
243 //================================================================================
244
245 Driver_Mesh::Status DriverMED_W_Field::Perform()
246 {
247   if ( myFile.empty() )
248     return addMessage("File name not set", /*isFatal=*/true ); // 'fatal' means 'bug'
249   if ( myMeshId < 0 && myMeshName.empty() )
250     return addMessage("Mesh in file not specified", /*isFatal=*/true );
251   if ( _nbElemsByGeom.size() < 2 )
252     return addMessage("No values to write", /*isFatal=*/false );
253   if ( !myMesh )
254     return addMessage("Supporting mesh not set", /*isFatal=*/true );
255
256   int version = -1, major, minor, release;
257   if ( MED::GetMEDVersion( myFile, major, minor, release ))
258     version = major * 10 + minor;
259
260   MED::PWrapper medFile = MED::CrWrapperW( myFile, version );
261   MED::PMeshInfo meshInfo;
262   if ( myMeshId > 0 )
263   {
264     meshInfo = medFile->GetPMeshInfo( myMeshId );
265   }
266   else
267   {
268     // look for a mesh by name
269     int aNbMeshes = medFile->GetNbMeshes();
270     for ( int iMesh = aNbMeshes; iMesh > 0 && myMeshId < 1; --iMesh )
271     {
272       meshInfo = medFile->GetPMeshInfo( iMesh );
273       if ( !meshInfo || meshInfo->GetName() != myMeshName )
274         meshInfo.reset();
275       else
276         myMeshId = iMesh;
277     }
278   }
279   if (( !meshInfo ) ||
280       ( !myMeshName.empty() && meshInfo->GetName() != myMeshName ))
281   {
282     myMeshId = -1;
283     return addMessage("DriverMED_W_Field: Specified mesh not found in the file", /*isFatal=*/true );
284   }
285
286   // create a field
287   MED::ETypeChamp  dataType = _dblValues.empty() ? MED::eINT : MED::eFLOAT64;
288   MED::PFieldInfo fieldInfo = medFile->CrFieldInfo( meshInfo,
289                                                     _compNames.size(),
290                                                     dataType );
291   fieldInfo->SetName( _fieldName );
292   for ( size_t iC = 0; iC < _compNames.size(); ++iC )
293   {
294     fieldInfo->SetCompName( iC, _compNames[ iC ]);
295     fieldInfo->SetUnitName( iC, "");
296   }
297   if ( _compNames.size() > 1 )
298   {
299     for ( size_t i = 0; i < fieldInfo->myCompNames.size()-1; ++i )
300       if ( !fieldInfo->myCompNames[i] )
301         fieldInfo->myCompNames[i] = ' ';
302   }
303   medFile->SetFieldInfo( fieldInfo );
304
305   // specific treatment of added 0D elements
306   if ( _nbElemsByGeom.size()   == 3 &&
307        _nbElemsByGeom[1].first == SMDSEntity_0D )
308   {
309     _nbElemsByGeom[1].second += _nbElemsByGeom[2].second;
310     _nbElemsByGeom.resize( 2 );
311   }
312
313   // create a time stamp
314   MED::TGeom2Size type2nb;
315   for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG )
316   {
317     SMDSAbs_EntityType    smdsType = _nbElemsByGeom[iG].first;
318     MED::EGeometrieElement medType = (MED::EGeometrieElement) DriverMED::GetMedGeoType( smdsType );
319     int                    nbElems = _nbElemsByGeom[iG].second - _nbElemsByGeom[iG-1].second;
320     type2nb.insert( std::make_pair( medType, nbElems ));
321   }
322
323   MED::EEntiteMaillage       entity = ( _elemType == SMDSAbs_Node ? MED::eNOEUD : MED::eMAILLE );
324   MED::PTimeStampInfo timeStampInfo = medFile->CrTimeStampInfo( fieldInfo, entity, type2nb );
325   timeStampInfo->myNumDt  = _dt;
326   timeStampInfo->myNumOrd = _it;
327
328   MED::PTimeStampValueBase  timeStampVal = medFile->CrTimeStampValue( timeStampInfo, dataType );
329   MED::PFloatTimeStampValue timeStampFltVal = timeStampVal;
330   MED::PIntTimeStampValue   timeStampIntVal = timeStampVal;
331
332   // set values
333   int iVal = 0;
334   MED::TFloat* ptrDbl = 0;
335   MED::TInt*   ptrInt = 0;
336   for ( size_t iG = 1; iG < _nbElemsByGeom.size(); ++iG )
337   {
338     SMDSAbs_EntityType    smdsType = _nbElemsByGeom[iG].first;
339     MED::EGeometrieElement medType = (MED::EGeometrieElement) DriverMED::GetMedGeoType( smdsType );
340     int nbElems = ( _nbElemsByGeom[iG].second - _nbElemsByGeom[iG-1].second ) * _compNames.size();
341     if ( dataType == MED::eFLOAT64 )
342     {
343       ptrDbl = timeStampFltVal->GetMeshValue( medType ).GetPointer();
344       for ( int i = 0; i < nbElems; ++i, ++iVal )
345         ptrDbl[ i ] = _dblValues[ iVal ];
346     }
347     else
348     {
349       ptrInt = timeStampIntVal->GetMeshValue( medType ).GetPointer();
350       for ( int i = 0; i < nbElems; ++i, ++iVal )
351         ptrInt[ i ] = _intValues[ iVal ];
352     }
353   }
354
355   // write
356   medFile->SetTimeStampValue( timeStampVal );
357
358   _dblValues.clear();
359   _intValues.clear();
360
361   return DRS_OK;
362 }
363
364 namespace DriverMED // Implementation of functions declared in DriverMED.hxx
365 {
366   //================================================================================
367   /*!
368    * Returns a vector containing MED::EGeometrieElement for each SMDSAbs_EntityType
369    */
370   //================================================================================
371
372   const std::vector< MED::EGeometrieElement >& getMedTypesVec()
373   {
374     static std::vector< MED::EGeometrieElement > theVec;
375     if ( theVec.empty() )
376     {
377       theVec.resize( SMDSEntity_Last, MED::eAllGeoType );
378       theVec[ SMDSEntity_Node               ] = MED::eNONE    ;
379       theVec[ SMDSEntity_0D                 ] = MED::ePOINT1  ;
380       theVec[ SMDSEntity_Edge               ] = MED::eSEG2    ;
381       theVec[ SMDSEntity_Quad_Edge          ] = MED::eSEG3    ;
382       theVec[ SMDSEntity_Triangle           ] = MED::eTRIA3   ;
383       theVec[ SMDSEntity_Quad_Triangle      ] = MED::eTRIA6   ;
384       theVec[ SMDSEntity_BiQuad_Triangle    ] = MED::eTRIA7   ;
385       theVec[ SMDSEntity_Quadrangle         ] = MED::eQUAD4   ;
386       theVec[ SMDSEntity_Quad_Quadrangle    ] = MED::eQUAD8   ;
387       theVec[ SMDSEntity_BiQuad_Quadrangle  ] = MED::eQUAD9   ;
388       theVec[ SMDSEntity_Polygon            ] = MED::ePOLYGONE;
389       //theVec[ SMDSEntity_Quad_Polygon       ] = MED::ePOLYGONE; // !!
390       theVec[ SMDSEntity_Tetra              ] = MED::eTETRA4  ;
391       theVec[ SMDSEntity_Quad_Tetra         ] = MED::eTETRA10 ;
392       theVec[ SMDSEntity_Pyramid            ] = MED::ePYRA5   ;
393       theVec[ SMDSEntity_Quad_Pyramid       ] = MED::ePYRA13  ;
394       theVec[ SMDSEntity_Hexa               ] = MED::eHEXA8   ;
395       theVec[ SMDSEntity_Quad_Hexa          ] = MED::eHEXA20  ;
396       theVec[ SMDSEntity_TriQuad_Hexa       ] = MED::eHEXA27  ;
397       theVec[ SMDSEntity_Penta              ] = MED::ePENTA6  ;
398       theVec[ SMDSEntity_Quad_Penta         ] = MED::ePENTA15 ;
399       theVec[ SMDSEntity_BiQuad_Penta       ] = MED::ePENTA18 ;
400       theVec[ SMDSEntity_Hexagonal_Prism    ] = MED::eOCTA12  ;
401       theVec[ SMDSEntity_Polyhedra          ] = MED::ePOLYEDRE;
402       //theVec[ SMDSEntity_Quad_Polyhedra     ] = MED::ePOLYEDRE; // !!
403       theVec[ SMDSEntity_Ball               ] = MED::eBALL    ;
404     }
405     return theVec;
406   }
407
408   //================================================================================
409   /*!
410    * Returns MED element geom type (MED::EGeometrieElement) by SMDS type
411    */
412   //================================================================================
413
414   int GetMedGeoType( SMDSAbs_EntityType smdsType )
415   {
416     return getMedTypesVec()[ smdsType ];
417   }
418
419   //================================================================================
420   /*!
421    * Returns SMDS element geom type by MED type (MED::EGeometrieElement)
422    */
423   //================================================================================
424
425   SMDSAbs_EntityType GetSMDSType( int medType )
426   {
427     const std::vector< MED::EGeometrieElement >& theVec = getMedTypesVec();
428
429     std::vector< MED::EGeometrieElement >::const_iterator i =
430       std::find( theVec.begin(), theVec.end(), medType );
431
432     return SMDSAbs_EntityType( std::distance( theVec.begin(), i ));
433   }
434 }