Salome HOME
Copyright update 2020
[tools/medcoupling.git] / src / MEDLoader / SauvMedConvertor.hxx
1 // Copyright (C) 2007-2020  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 // File      : SauvMedConvertor.hxx
20 // Created   : Tue Aug 16 14:14:02 2011
21 // Author    : Edward AGAPOV (eap)
22 //
23
24 #ifndef __SauvMedConvertor_HXX__
25 #define __SauvMedConvertor_HXX__
26
27 #include "InterpKernelException.hxx"
28 #include "NormalizedUnstructuredMesh.hxx"
29 #include "MEDCouplingRefCountObject.hxx"
30 #include "SauvUtilities.hxx"
31 #include "MCType.hxx"
32
33 #include <vector>
34 #include <set>
35 #include <map>
36 #include <list>
37 #include <algorithm>
38
39 namespace MEDCoupling
40 {
41   class DataArrayDouble;
42   class DataArrayInt;
43   class MEDFileData;
44   class MEDFileFields;
45   class MEDFileFieldMultiTS;
46   class MEDFileUMesh;
47 }
48
49 namespace SauvUtilities
50 {
51   struct IntermediateMED;
52
53   // ==============================================================================
54   typedef mcIdType           TID;  // an ID countered from 1
55   typedef std::pair<TID,TID> Link; // a pair of node numbers
56
57   typedef INTERP_KERNEL::NormalizedCellType TCellType;
58
59   // ==============================================================================
60   struct Node
61   {
62     TID    _number;
63     size_t _coordID;
64
65     Node():_number(0){}
66     bool isUsed() const { return _number != 0; }
67   };
68
69   // ==============================================================================
70   struct Cell
71   {
72     std::vector< Node* > _nodes;
73     mutable bool         _reverse; // to reverse orientation of a face only
74     mutable TID*         _sortedNodeIDs; // for comparison
75     mutable TID          _number;
76
77     Cell(size_t nnNodes=0) : _nodes(nnNodes),_reverse(false),_sortedNodeIDs(0),_number(0) {}
78     Cell(const Cell& ma);
79     void init() const { if ( _sortedNodeIDs ) delete [] _sortedNodeIDs; _sortedNodeIDs = 0; }
80     ~Cell() { init(); }
81
82     const TID* getSortedNodes() const; // creates if needed and return _sortedNodeIDs
83     bool operator < (const Cell& ma) const;
84     Link link(int i) const;
85
86   private:
87     Cell& operator=(const Cell& ma);
88   };
89   std::ostream& operator << (std::ostream& os, const Cell& ma);
90
91   // ==============================================================================
92   struct Group
93   {
94     TCellType                _cellType;
95     std::string              _name;
96     std::vector<const Cell*> _cells;
97     std::vector< Group* >    _groups;    // des sous-groupes composant le Group
98     bool                     _isProfile; // is a field support or not
99     std::vector<std::string> _refNames;  /* names of groups referring this one;
100                                             _refNames is resized according to nb of references
101                                             while reading a group (pile 1) and it is filled with
102                                             names while reading long names (pile 27); each named
103                                             reference is converted into a copy of the medGroup
104                                             (issue 0021311)
105                                          */
106     MEDCoupling::DataArrayIdType* _medGroup;   // result of conversion
107     std::vector< mcIdType >       _relocTable; // for _cells[i] gives its index in _medGroup
108
109     bool empty() const { return _cells.empty() && _groups.empty(); }
110     mcIdType  size()  const;
111     Group():_cellType(INTERP_KERNEL::NORM_ERROR), _isProfile(false), _medGroup(NULL) {}
112   };
113
114   // ==============================================================================
115   struct DoubleField
116   {
117     // a field contains several subcomponents each referring to its own support and
118     // having several named components
119     // ----------------------------------------------------------------------------
120     struct _Sub_data // a subcomponent
121     // --------------------------------
122     {
123       Group*                   _support;    // support
124       std::vector<std::string> _comp_names; // component names
125       std::vector<int>         _nb_gauss;   // nb values per element in a component
126
127       void setData( int nb_comp, Group* supp )
128       { _support = supp; _comp_names.resize(nb_comp); _nb_gauss.resize(nb_comp,1); }
129       int  nbComponents() const { return (int)_comp_names.size(); }
130       std::string & compName( int i_comp ) { return _comp_names[ i_comp ]; }
131       bool isSameNbGauss() const { return *std::max_element( _nb_gauss.begin(), _nb_gauss.end() ) ==
132           *std::min_element( _nb_gauss.begin(), _nb_gauss.end() ); }
133       int  nbGauss() const { return _nb_gauss[0] ? _nb_gauss[0] : 1; }
134       bool hasGauss() const { return nbGauss() > 1; }
135     };
136     // ----------------------------------------------------------------------------
137     TID                      _idInFile;
138     std::string              _name;
139     std::string              _description; // field description
140     std::vector< _Sub_data > _sub;
141     Group*                   _group; /* if _group == NULL then each subcomponent makes a
142                                         separate med field, else all subcomponents
143                                         are converted into timestamps of one med field.
144                                         The latter is possible only if nb of components in all subs
145                                         is the same and supports of subcomponents do not overlap
146                                      */
147     std::vector< std::vector< double > > _comp_values;
148     MEDCoupling::MEDFileFieldMultiTS*     _curMedField;
149
150     DoubleField( int nb_sub, int total_nb_comp )
151       : _sub(nb_sub), _group(NULL), _curMedField(NULL) { _comp_values.reserve( total_nb_comp ); }
152     ~DoubleField();
153     std::vector< double >& addComponent( int nb_values ); // return a vector ready to fill in
154     bool hasCommonSupport() const { return _group; } // true if there is one support for all subs
155     bool hasSameComponentsBySupport() const;
156
157     bool isMultiTimeStamps() const;
158     bool isMedCompatible(bool& sameNbGauss) const;
159     MEDCoupling::TypeOfField getMedType( const int iSub=0 ) const;
160     MEDCoupling::TypeOfTimeDiscretization getMedTimeDisc() const;
161     mcIdType getNbTuples( const int iSub=0 ) const;
162     int getNbValuesPerElement( const int iSub=0 ) const;
163     int getNbGauss( const int iSub=0 ) const;
164     const Group* getSupport( const int iSub=0 ) const;
165     mcIdType setValues( double * valPtr, const int iSub, const mcIdType elemShift=0 ) const;
166     void splitSubWithDiffNbGauss();
167
168     //virtual void dump(std::ostream&) const;
169     //virtual ~DoubleField() {}
170   };
171   // ==============================================================================
172   /*!
173    * \if developer
174    * Iterator on set of Cell's of given dimension
175    * \endif
176    */
177   class CellsByDimIterator
178   {
179   public:
180     CellsByDimIterator( const IntermediateMED & medi, int dim=-1); // dim=-1 - for all dimensions
181     void init(const int  dim=-1);
182
183     //!< return next set of Cell's of required dimension
184     const std::set<Cell > * nextType();
185     //!< return dimension of Cell's returned by the last or further next()
186     int dim(const bool last=true) const;
187     //!< return type of Cell's returned by the last next()
188     TCellType type() const { return TCellType( myCurType ); }
189
190   private:
191     const IntermediateMED* myImed;
192     int myCurType, myTypeEnd;
193     int myDim;
194   };
195
196   // ==============================================================================
197   /*!
198    * \if developer
199    * Container of Node's. Prevents re-allocation at addition of Node's
200    * \endif
201    */
202   class NodeContainer
203   {
204     std::vector< std::vector< Node > > _nodes;
205   public:
206     Node* getNode( const TID nID )
207     {
208       const size_t chunkSize = 1000;
209       const size_t chunkID = (nID-1) / chunkSize;
210       const size_t pos     = (nID-1) % chunkSize;
211       if ( _nodes.size() < chunkID+1 )
212       {
213         std::vector< std::vector< Node > > newNodes(chunkID+1);
214         for ( size_t i = 0; i < _nodes.size(); ++i )
215           newNodes[i].swap( _nodes[i] );
216         for ( size_t i = _nodes.size(); i < newNodes.size(); ++i )
217           newNodes[i].resize( chunkSize );
218         _nodes.swap( newNodes );
219       }
220       return & _nodes[chunkID][pos];
221     }
222     bool empty() const { return _nodes.empty(); }
223     size_t size() const { return empty() ? 0 : _nodes.size() * _nodes[0].size(); }
224     int numberNodes();
225   };
226
227   // ==============================================================================
228   /*!
229    * \if developer
230    * Intermediate structure used to store data read from the Sauve format file.
231    * The structure provides functions that transform the stored data to the MED format
232    *
233    * The elements inserted in maillage are ordered in order to avoid duplicated elements.
234    * \endif
235    */
236   struct IntermediateMED
237   {
238     unsigned                   _spaceDim;
239     unsigned                   _nbNodes;
240     NodeContainer              _points;
241     std::vector<double>        _coords;
242     std::vector<Group>         _groups;
243     std::vector<DoubleField* > _nodeFields;
244     std::vector<DoubleField* > _cellFields;
245
246     // IMP 0020434: mapping GIBI names to MED names
247     std::list<nameGIBItoMED>  _listGIBItoMED_mail; // to read from table "MED_MAIL" of PILE_TABLES
248     std::list<nameGIBItoMED>  _listGIBItoMED_cham; // to read from table "MED_CHAM" of PILE_TABLES
249     std::list<nameGIBItoMED>  _listGIBItoMED_comp; // to read from table "MED_COMP" of PILE_TABLES
250     std::map<int,std::string> _mapStrings;         // to read from PILE_STRINGS
251
252     IntermediateMED(): _spaceDim(0), _nbNodes(0) {}
253     ~IntermediateMED();
254
255     Node* getNode( TID nID ) { return _points.getNode( nID ); }
256     mcIdType getNbCellsOfType( TCellType type ) const { return ToIdType(_cellsByType[type].size()); }
257     const Cell* insert(TCellType type, const Cell& ma) { return &( *_cellsByType[type].insert( ma ).first ); }
258     Group* addNewGroup(std::vector<SauvUtilities::Group*>* groupsToFix=0);
259     MEDCoupling::MEDFileData* convertInMEDFileDS();
260
261   private:
262
263     MEDCoupling::MEDFileUMesh* makeMEDFileMesh();
264     MEDCoupling::DataArrayDouble * getCoords();
265     void setConnectivity( MEDCoupling::MEDFileUMesh* mesh, MEDCoupling::DataArrayDouble* coords );
266     void setGroups( MEDCoupling::MEDFileUMesh* mesh );
267     MEDCoupling::MEDFileFields * makeMEDFileFields(MEDCoupling::MEDFileUMesh* mesh);
268     void setFields( SauvUtilities::DoubleField*    fld,
269                     MEDCoupling::MEDFileFields*     medFields,
270                     MEDCoupling::MEDFileUMesh*      mesh,
271                     const TID                      castemID,
272                     std::set< std::string >&       usedNames);
273     void setTS( SauvUtilities::DoubleField*  fld,
274                 MEDCoupling::DataArrayDouble* values,
275                 MEDCoupling::MEDFileFields*   medFields,
276                 MEDCoupling::MEDFileUMesh*    mesh,
277                 const int                    iSub=0);
278     void checkDataAvailability() const;
279     void setGroupLongNames();
280     void setFieldLongNames(std::set< std::string >& usedNames);
281     void makeFieldNewName(std::set< std::string >&    usedNames,
282                           SauvUtilities::DoubleField* fld );
283     void decreaseHierarchicalDepthOfSubgroups();
284     void eraseUselessGroups();
285     void detectMixDimGroups();
286     void orientElements2D();
287     void orientElements3D();
288     void orientFaces3D();
289     void orientVolumes();
290     void numberElements();
291     bool isOnAll( const Group* grp, int & dimRel ) const;
292     const double* nodeCoords( const Node* n ) { return &_coords[ (n->_coordID-1) * _spaceDim ]; }
293
294     // IntermediateMED()
295     // { myNodesNumerated = myMaillesNumerated = myGroupsTreated = false; currentTypeMailles = 0; }
296     // ~IntermediateMED();
297
298     //bool myNodesNumerated, myMaillesNumerated;
299
300     // mailles groupped by geom type; use insert() for filling in and
301     // _CellsByDimIterator for exploring it
302     //std::set<_Cell> maillage;
303     std::set< Cell >  _cellsByType[ INTERP_KERNEL::NORM_HEXA20 + 1 ];
304     friend class CellsByDimIterator;
305   };
306
307 // ==============================================================================
308   /*!
309    * \brief ASCII sauve file reader
310    */
311   class ASCIIReader : public FileReader
312   {
313   public:
314     ASCIIReader(const char* fileName);
315     virtual ~ASCIIReader();
316     virtual bool isASCII() const;
317     virtual bool open();
318     virtual bool getNextLine (char* & line, bool raiseOEF = true );
319     virtual void initNameReading(int nbValues, int width = 8);
320     virtual void initIntReading(int nbValues);
321     virtual void initDoubleReading(int nbValues);
322     virtual bool more() const;
323     virtual void next();
324     virtual int    getInt() const;
325     virtual float  getFloat() const;
326     virtual double getDouble() const;
327     virtual std::string getName() const;
328     int lineNb() const { return _lineNb; }
329     std::string getClassName() const override { return std::string("ASCIIReader"); }
330   private:
331
332     bool getLine(char* & line);
333     void init( int nbToRead, int nbPosInLine, int width, int shift = 0 );
334
335     // getting a line from the file
336     int   _file;
337     char* _start; // working buffer beginning
338     char* _ptr;
339     char* _eptr;
340     int   _lineNb;
341
342     // line parsing
343     int _iPos, _nbPosInLine, _width, _shift;
344     char* _curPos;
345   };
346 // ==============================================================================
347   /*!
348    * \brief XDR (binary) sauve file reader
349    */
350   class XDRReader : public FileReader
351   {
352   public:
353     XDRReader(const char* fileName);
354     virtual ~XDRReader();
355     virtual bool isASCII() const;
356     virtual bool open();
357     virtual bool getNextLine (char* & line, bool raiseOEF = true );
358     virtual void initNameReading(int nbValues, int width = 8);
359     virtual void initIntReading(int nbValues);
360     virtual void initDoubleReading(int nbValues);
361     virtual bool more() const;
362     virtual void next();
363     virtual int    getInt() const;
364     virtual float  getFloat() const;
365     virtual double getDouble() const;
366     virtual std::string getName() const;
367     std::string getClassName() const override { return std::string("XDRReader"); }
368   private:
369
370     void init( int nbToRead, int width = 0 );
371
372     FILE* _xdrs_file;
373     void* _xdrs;
374     int* _xdr_ivals;
375     double* _xdr_dvals;
376     char* _xdr_cvals;
377     int _width;
378     int _xdr_kind;
379     enum
380       {
381         _xdr_kind_null,
382         _xdr_kind_char,
383         _xdr_kind_int,
384         _xdr_kind_double
385       };
386   };
387 }
388
389 #endif