Salome HOME
22612: [CEA 1189] sauv2med should not change faces orientation
[tools/medcoupling.git] / src / MEDLoader / SauvMedConvertor.hxx
1 // Copyright (C) 2007-2014  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
32 #include <vector>
33 #include <set>
34 #include <map>
35 #include <list>
36 #include <algorithm>
37
38 namespace ParaMEDMEM
39 {
40   class DataArrayDouble;
41   class DataArrayInt;
42   class MEDFileData;
43   class MEDFileFields;
44   class MEDFileFieldMultiTS;
45   class MEDFileUMesh;
46 }
47
48 namespace SauvUtilities
49 {
50   struct IntermediateMED;
51
52   // ==============================================================================
53   typedef int                TID;  // an ID countered from 1
54   typedef std::pair<TID,TID> Link; // a pair of node numbers
55
56   typedef INTERP_KERNEL::NormalizedCellType TCellType;
57
58   // ==============================================================================
59   struct Node
60   {
61     TID    _number;
62     size_t _coordID;
63
64     Node():_number(0){}
65     bool isUsed() const { return _number != 0; }
66   };
67
68   // ==============================================================================
69   struct Cell
70   {
71     std::vector< Node* > _nodes;
72     mutable bool         _reverse; // to reverse orienation of a face only
73     mutable TID*         _sortedNodeIDs; // for comparison
74     mutable TID          _number;
75
76     Cell(size_t nnNodes=0) : _nodes(nnNodes),_reverse(false),_sortedNodeIDs(0),_number(0) {}
77     Cell(const Cell& ma);
78     void init() const { if ( _sortedNodeIDs ) delete [] _sortedNodeIDs; _sortedNodeIDs = 0; }
79     ~Cell() { init(); }
80
81     const TID* getSortedNodes() const; // creates if needed and return _sortedNodeIDs
82     bool operator < (const Cell& ma) const;
83     Link link(int i) const;
84
85   private:
86     Cell& operator=(const Cell& ma);
87   };
88   std::ostream& operator << (std::ostream& os, const Cell& ma);
89
90   // ==============================================================================
91   struct Group
92   {
93     TCellType                _cellType;
94     std::string              _name;
95     std::vector<const Cell*> _cells;
96     std::vector< Group* >    _groups;    // des sous-groupes composant le Group
97     bool                     _isProfile; // is a field support or not
98     std::vector<std::string> _refNames;  /* names of groups referring this one;
99                                             _refNames is resized according to nb of references
100                                             while reading a group (pile 1) and it is filled with
101                                             names while reading long names (pile 27); each named
102                                             reference is converted into a copy of the medGroup
103                                             (issue 0021311)
104                                          */
105     ParaMEDMEM::DataArrayInt* _medGroup;   // result of conversion
106     std::vector< unsigned >   _relocTable; // for _cells[i] gives its index in _medGroup
107
108     bool empty() const { return _cells.empty() && _groups.empty(); }
109     int  size()  const;
110     Group():_cellType(INTERP_KERNEL::NORM_ERROR), _isProfile(false), _medGroup(NULL) {}
111   };
112
113   // ==============================================================================
114   struct DoubleField
115   {
116     // a field contains several subcomponents each referring to its own support and
117     // having several named components
118     // ----------------------------------------------------------------------------
119     struct _Sub_data // a subcomponent
120     // --------------------------------
121     {
122       Group*                   _support;    // support
123       std::vector<std::string> _comp_names; // component names
124       std::vector<int>         _nb_gauss;   // nb values per element in a component
125
126       void setData( int nb_comp, Group* supp )
127       { _support = supp; _comp_names.resize(nb_comp); _nb_gauss.resize(nb_comp,1); }
128       int  nbComponents() const { return _comp_names.size(); }
129       std::string & compName( int i_comp ) { return _comp_names[ i_comp ]; }
130       bool isSameNbGauss() const { return *std::max_element( _nb_gauss.begin(), _nb_gauss.end() ) ==
131           *std::min_element( _nb_gauss.begin(), _nb_gauss.end() ); }
132       int  nbGauss() const { return _nb_gauss[0] ? _nb_gauss[0] : 1; }
133       bool hasGauss() const { return nbGauss() > 1; }
134     };
135     // ----------------------------------------------------------------------------
136     TID                      _idInFile;
137     std::string              _name;
138     std::string              _description; // field description
139     std::vector< _Sub_data > _sub;
140     Group*                   _group; /* if _group == NULL then each subcomponent makes a
141                                         separate med field, else all subcomponents
142                                         are converted into timestamps of one med field.
143                                         The latter is possible only if nb of components in all subs
144                                         is the same and supports of subcomponents do not overlap
145                                      */
146     std::vector< std::vector< double > > _comp_values;
147     ParaMEDMEM::MEDFileFieldMultiTS*     _curMedField;
148
149     DoubleField( int nb_sub, int total_nb_comp )
150       : _sub(nb_sub), _group(NULL), _curMedField(NULL) { _comp_values.reserve( total_nb_comp ); }
151     ~DoubleField();
152     std::vector< double >& addComponent( int nb_values ); // return a vector ready to fill in
153     bool hasCommonSupport() const { return _group; } // true if there is one support for all subs
154     bool hasSameComponentsBySupport() const;
155
156     bool isMultiTimeStamps() const;
157     bool isMedCompatible(bool& sameNbGauss) const;
158     ParaMEDMEM::TypeOfField getMedType( const int iSub=0 ) const;
159     ParaMEDMEM::TypeOfTimeDiscretization getMedTimeDisc() const;
160     int getNbTuples( const int iSub=0 ) const;
161     int getNbValuesPerElement( const int iSub=0 ) const;
162     int getNbGauss( const int iSub=0 ) const;
163     const Group* getSupport( const int iSub=0 ) const;
164     int setValues( double * valPtr, const int iSub, const int elemShift=0 ) const;
165     void splitSubWithDiffNbGauss();
166
167     //virtual void dump(std::ostream&) const;
168     //virtual ~DoubleField() {}
169   };
170   // ==============================================================================
171   /*!
172    * \if developper
173    * Iterator on set of Cell's of given dimension
174    * \endif
175    */
176   class CellsByDimIterator
177   {
178   public:
179     CellsByDimIterator( const IntermediateMED & medi, int dim=-1); // dim=-1 - for all dimensions
180     void init(const int  dim=-1);
181
182     //!< return next set of Cell's of required dimension
183     const std::set<Cell > * nextType();
184     //!< return dimension of Cell's returned by the last or further next()
185     int dim(const bool last=true) const;
186     //!< return type of Cell's returned by the last next()
187     TCellType type() const { return TCellType( myCurType ); }
188
189   private:
190     const IntermediateMED* myImed;
191     int myCurType, myTypeEnd;
192     int myDim;
193   };
194
195   // ==============================================================================
196   /*!
197    * \if developper
198    * Container of Node's. Prevents re-allocation at addition of Node's
199    * \endif
200    */
201   class NodeContainer
202   {
203     std::vector< std::vector< Node > > _nodes;
204   public:
205     Node* getNode( const TID nID )
206     {
207       const size_t chunkSize = 1000;
208       const size_t chunkID = (nID-1) / chunkSize;
209       const size_t pos     = (nID-1) % chunkSize;
210       if ( _nodes.size() < chunkID+1 )
211       {
212         std::vector< std::vector< Node > > newNodes(chunkID+1);
213         for ( size_t i = 0; i < _nodes.size(); ++i )
214           newNodes[i].swap( _nodes[i] );
215         for ( size_t i = _nodes.size(); i < newNodes.size(); ++i )
216           newNodes[i].resize( chunkSize );
217         _nodes.swap( newNodes );
218       }
219       return & _nodes[chunkID][pos];
220     }
221     bool empty() const { return _nodes.empty(); }
222     size_t size() const { return empty() ? 0 : _nodes.size() * _nodes[0].size(); }
223     int numberNodes();
224   };
225
226   // ==============================================================================
227   /*!
228    * \if developper
229    * Intermediate structure used to store data read from the Sauve format file.
230    * The structure provides functions that transform the stored data to the MED format
231    *
232    * The elements inserted in maillage are ordered in order to avoid duplicated elements.
233    * \endif
234    */
235   struct IntermediateMED
236   {
237     unsigned                   _spaceDim;
238     unsigned                   _nbNodes;
239     NodeContainer              _points;
240     std::vector<double>        _coords;
241     std::vector<Group>         _groups;
242     std::vector<DoubleField* > _nodeFields;
243     std::vector<DoubleField* > _cellFields;
244
245     // IMP 0020434: mapping GIBI names to MED names
246     std::list<nameGIBItoMED>  _listGIBItoMED_mail; // to read from table "MED_MAIL" of PILE_TABLES
247     std::list<nameGIBItoMED>  _listGIBItoMED_cham; // to read from table "MED_CHAM" of PILE_TABLES
248     std::list<nameGIBItoMED>  _listGIBItoMED_comp; // to read from table "MED_COMP" of PILE_TABLES
249     std::map<int,std::string> _mapStrings;         // to read from PILE_STRINGS
250
251     IntermediateMED(): _spaceDim(0), _nbNodes(0) {}
252     ~IntermediateMED();
253
254     Node* getNode( TID nID ) { return _points.getNode( nID ); }
255     int getNbCellsOfType( TCellType type ) const { return _cellsByType[type].size(); }
256     const Cell* insert(TCellType type, const Cell& ma) { return &( *_cellsByType[type].insert( ma ).first ); }
257     Group* addNewGroup(std::vector<SauvUtilities::Group*>* groupsToFix=0);
258
259     ParaMEDMEM::MEDFileData* convertInMEDFileDS(bool fix2DOri);
260
261   private:
262
263     ParaMEDMEM::MEDFileUMesh* makeMEDFileMesh(bool fix2DOri);
264     ParaMEDMEM::DataArrayDouble * getCoords();
265     void setConnectivity( ParaMEDMEM::MEDFileUMesh* mesh, ParaMEDMEM::DataArrayDouble* coords );
266     void setGroups( ParaMEDMEM::MEDFileUMesh* mesh );
267     ParaMEDMEM::MEDFileFields * makeMEDFileFields(ParaMEDMEM::MEDFileUMesh* mesh);
268     void setFields( SauvUtilities::DoubleField*    fld,
269                     ParaMEDMEM::MEDFileFields*     medFields,
270                     ParaMEDMEM::MEDFileUMesh*      mesh,
271                     const TID                      castemID,
272                     std::set< std::string >&       usedNames);
273     void setTS( SauvUtilities::DoubleField*  fld,
274                 ParaMEDMEM::DataArrayDouble* values,
275                 ParaMEDMEM::MEDFileFields*   medFields,
276                 ParaMEDMEM::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(bool fix2DOri);
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
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
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