1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // File : SauvMedConvertor.cxx
20 // Created : Tue Aug 16 14:43:20 2011
21 // Author : Edward AGAPOV (eap)
24 #include "SauvMedConvertor.hxx"
26 #include "CellModel.hxx"
27 #include "MEDFileMesh.hxx"
28 #include "MEDFileField.hxx"
29 #include "MEDFileData.hxx"
30 #include "MEDCouplingFieldDouble.hxx"
55 using namespace SauvUtilities;
56 using namespace ParaMEDMEM;
61 // for ASCII file reader
62 const int GIBI_MaxOutputLen = 150; // max length of a line in the sauve file
63 const int GIBI_BufferSize = 16184; // for buffered reading
65 using namespace INTERP_KERNEL;
67 const size_t MaxMedCellType = NORM_ERROR;
68 const size_t NbGibiCellTypes = 47;
69 const TCellType GibiTypeToMed[NbGibiCellTypes] =
71 /*1 */ NORM_POINT1 ,/*2 */ NORM_SEG2 ,/*3 */ NORM_SEG3 ,/*4 */ NORM_TRI3 ,/*5 */ NORM_ERROR ,
72 /*6 */ NORM_TRI6 ,/*7 */ NORM_ERROR ,/*8 */ NORM_QUAD4 ,/*9 */ NORM_ERROR ,/*10*/ NORM_QUAD8 ,
73 /*11*/ NORM_ERROR ,/*12*/ NORM_ERROR ,/*13*/ NORM_ERROR ,/*14*/ NORM_HEXA8 ,/*15*/ NORM_HEXA20 ,
74 /*16*/ NORM_PENTA6 ,/*17*/ NORM_PENTA15,/*18*/ NORM_ERROR ,/*19*/ NORM_ERROR ,/*20*/ NORM_ERROR ,
75 /*21*/ NORM_ERROR ,/*22*/ NORM_ERROR ,/*23*/ NORM_TETRA4 ,/*24*/ NORM_TETRA10,/*25*/ NORM_PYRA5 ,
76 /*26*/ NORM_PYRA13 ,/*27*/ NORM_ERROR ,/*28*/ NORM_ERROR ,/*29*/ NORM_ERROR ,/*30*/ NORM_ERROR ,
77 /*31*/ NORM_ERROR ,/*32*/ NORM_ERROR ,/*33*/ NORM_ERROR ,/*34*/ NORM_ERROR ,/*35*/ NORM_ERROR ,
78 /*36*/ NORM_ERROR ,/*37*/ NORM_ERROR ,/*38*/ NORM_ERROR ,/*39*/ NORM_ERROR ,/*40*/ NORM_ERROR ,
79 /*41*/ NORM_ERROR ,/*42*/ NORM_ERROR ,/*43*/ NORM_ERROR ,/*44*/ NORM_ERROR ,/*45*/ NORM_ERROR ,
80 /*46*/ NORM_ERROR ,/*47*/ NORM_ERROR
83 //================================================================================
85 * \brief Return dimension of a group
87 //================================================================================
89 unsigned getDim( const Group* grp )
91 return SauvUtilities::getDimension( grp->_groups.empty() ? grp->_cellType : grp->_groups[0]->_cellType );
94 //================================================================================
96 * \brief Converts connectivity of quadratic elements
98 //================================================================================
100 inline void ConvertQuadratic( const INTERP_KERNEL::NormalizedCellType type,
103 if ( const int * conn = getGibi2MedQuadraticInterlace( type ))
105 Cell* ma = const_cast<Cell*>(&aCell);
106 vector< Node* > new_nodes( ma->_nodes.size() );
107 for ( size_t i = 0; i < new_nodes.size(); ++i )
108 new_nodes[ i ] = ma->_nodes[ conn[ i ]];
109 ma->_nodes.swap( new_nodes );
113 //================================================================================
115 * \brief Returns a vector of pairs of node indices to inverse a med volume element
117 //================================================================================
119 void getReverseVector (const INTERP_KERNEL::NormalizedCellType type,
120 vector<pair<int,int> > & swapVec )
128 swapVec[0] = make_pair( 1, 2 );
132 swapVec[0] = make_pair( 1, 3 );
136 swapVec[0] = make_pair( 1, 2 );
137 swapVec[1] = make_pair( 4, 5 );
141 swapVec[0] = make_pair( 1, 3 );
142 swapVec[1] = make_pair( 5, 7 );
146 swapVec[0] = make_pair( 1, 2 );
147 swapVec[1] = make_pair( 4, 6 );
148 swapVec[2] = make_pair( 8, 9 );
152 swapVec[0] = make_pair( 1, 3 );
153 swapVec[1] = make_pair( 5, 8 );
154 swapVec[2] = make_pair( 6, 7 );
155 swapVec[3] = make_pair( 10, 12 );
159 swapVec[0] = make_pair( 1, 2 );
160 swapVec[1] = make_pair( 4, 5 );
161 swapVec[2] = make_pair( 6, 8 );
162 swapVec[3] = make_pair( 9, 11 );
166 swapVec[0] = make_pair( 1, 3 );
167 swapVec[1] = make_pair( 5, 7 );
168 swapVec[2] = make_pair( 8, 11 );
169 swapVec[3] = make_pair( 9, 10 );
170 swapVec[4] = make_pair( 12, 15 );
171 swapVec[5] = make_pair( 13, 14 );
172 swapVec[6] = make_pair( 17, 19 );
174 // case NORM_SEG3: no need to reverse edges
175 // swapVec.resize(1);
176 // swapVec[0] = make_pair( 1, 2 );
180 swapVec[0] = make_pair( 1, 2 );
181 swapVec[1] = make_pair( 3, 5 );
185 swapVec[0] = make_pair( 1, 3 );
186 swapVec[1] = make_pair( 4, 7 );
187 swapVec[2] = make_pair( 5, 6 );
193 //================================================================================
195 * \brief Inverses element orientation using vector of indices to swap
197 //================================================================================
199 inline void reverse(const Cell & aCell, const vector<pair<int,int> > & swapVec )
201 Cell* ma = const_cast<Cell*>(&aCell);
202 for ( unsigned i = 0; i < swapVec.size(); ++i )
203 std::swap( ma->_nodes[ swapVec[i].first ],
204 ma->_nodes[ swapVec[i].second ]);
205 if ( swapVec.empty() )
208 ma->_reverse = false;
210 //================================================================================
212 * \brief Comparator of cells by number used for ordering cells within a med group
214 struct TCellByIDCompare
216 bool operator () (const Cell* i1, const Cell* i2)
218 return i1->_number < i2->_number;
221 typedef map< const Cell*, unsigned, TCellByIDCompare > TCellToOrderMap;
223 //================================================================================
225 * \brief Fill Group::_relocTable if necessary
227 //================================================================================
229 void setRelocationTable( Group* grp, TCellToOrderMap& cell2order )
231 if ( !grp->_isProfile ) return;
233 // check if relocation table is necessary
234 bool isRelocated = false;
235 unsigned newOrder = 0;
236 TCellToOrderMap::iterator c2oIt = cell2order.begin(), c2oEnd = cell2order.end();
237 for ( ; !isRelocated && c2oIt != c2oEnd; ++c2oIt, ++newOrder )
238 isRelocated = ( c2oIt->second != newOrder );
242 grp->_relocTable.resize( cell2order.size() );
243 for ( newOrder = 0, c2oIt = cell2order.begin(); c2oIt != c2oEnd; ++c2oIt, ++newOrder )
244 grp->_relocTable[ c2oIt->second ] = newOrder;
249 //================================================================================
251 * \brief Return dimension for the given cell type
253 //================================================================================
255 unsigned SauvUtilities::getDimension( INTERP_KERNEL::NormalizedCellType type )
257 return type == NORM_ERROR ? -1 : INTERP_KERNEL::CellModel::GetCellModel( type ).getDimension();
260 //================================================================================
262 * \brief Returns interlace array to transform a quadratic GIBI element to a MED one.
263 * i-th array item gives node index in GIBI connectivity for i-th MED node
265 //================================================================================
267 const int * SauvUtilities::getGibi2MedQuadraticInterlace( INTERP_KERNEL::NormalizedCellType type )
269 static vector<const int*> conn;
270 static const int hexa20 [] = {0,6,4,2, 12,18,16,14, 7,5,3,1, 19,17,15,13, 8,11,10,9};
271 static const int penta15[] = {0,2,4, 9,11,13, 1,3,5, 10,12,14, 6,8,7};
272 static const int pyra13 [] = {0,2,4,6, 12, 1,3,5,7, 8,9,10,11};
273 static const int tetra10[] = {0,2,4, 9, 1,3,5, 6,7,8};
274 static const int quad8 [] = {0,2,4,6, 1,3,5,7};
275 static const int tria6 [] = {0,2,4, 1,3,5};
276 static const int seg3 [] = {0,2,1};
279 conn.resize( MaxMedCellType + 1, 0 );
280 conn[ NORM_HEXA20 ] = hexa20;
281 conn[ NORM_PENTA15] = penta15;
282 conn[ NORM_PYRA13 ] = pyra13;
283 conn[ NORM_TETRA10] = tetra10;
284 conn[ NORM_SEG3 ] = seg3;
285 conn[ NORM_TRI6 ] = tria6;
286 conn[ NORM_QUAD8 ] = quad8;
291 //================================================================================
293 * \brief Avoid coping sortedNodeIDs
295 //================================================================================
297 Cell::Cell(const Cell& ma)
298 : _nodes(ma._nodes), _reverse(ma._reverse), _sortedNodeIDs(0), _number(ma._number)
300 if ( ma._sortedNodeIDs )
302 _sortedNodeIDs = new int[ _nodes.size() ];
303 std::copy( ma._sortedNodeIDs, ma._sortedNodeIDs + _nodes.size(), _sortedNodeIDs );
307 //================================================================================
309 * \brief Rerturn the i-th link of face
311 //================================================================================
313 SauvUtilities::Link Cell::link(int i) const
315 int i2 = ( i + 1 ) % _nodes.size();
317 return make_pair( _nodes[i2]->_number, _nodes[i]->_number );
319 return make_pair( _nodes[i]->_number, _nodes[i2]->_number );
322 //================================================================================
324 * \brief creates if needed and return _sortedNodeIDs
326 //================================================================================
328 const TID* Cell::getSortedNodes() const
330 if ( !_sortedNodeIDs )
332 size_t l=_nodes.size();
333 _sortedNodeIDs = new int[ l ];
335 for (size_t i=0; i!=l; ++i)
336 _sortedNodeIDs[i]=_nodes[i]->_number;
337 std::sort( _sortedNodeIDs, _sortedNodeIDs + l );
339 return _sortedNodeIDs;
342 //================================================================================
344 * \brief Compare sorted ids of cell nodes
346 //================================================================================
348 bool Cell::operator< (const Cell& ma) const
350 if ( _nodes.size() == 1 )
351 return _nodes[0] < ma._nodes[0];
353 const int* v1 = getSortedNodes();
354 const int* v2 = ma.getSortedNodes();
355 for ( const int* vEnd = v1 + _nodes.size(); v1 < vEnd; ++v1, ++v2 )
361 //================================================================================
365 //================================================================================
367 std::ostream& SauvUtilities::operator<< (std::ostream& os, const SauvUtilities::Cell& ma)
369 os << "cell " << ma._number << " (" << ma._nodes.size() << " nodes) : < " << ma._nodes[0]->_number;
370 for( size_t i=1; i!=ma._nodes.size(); ++i)
371 os << ", " << ma._nodes[i]->_number;
373 os << " > sortedNodes: ";
374 if ( ma._sortedNodeIDs ) {
376 for( size_t i=0; i!=ma._nodes.size(); ++i)
377 os << ( i ? ", " : "" ) << ma._sortedNodeIDs[i];
387 //================================================================================
389 * \brief Return nb of elements in the group
391 //================================================================================
393 int Group::size() const
396 if ( !_relocTable.empty() )
397 sizze = _relocTable.size();
398 else if ( _medGroup )
399 sizze = _medGroup->getNumberOfTuples();
400 else if ( !_cells.empty() )
401 sizze = _cells.size();
403 for ( size_t i = 0; i < _groups.size(); ++i )
404 sizze += _groups[i]->size();
408 //================================================================================
410 * \brief Conver gibi element type to med one
412 //================================================================================
414 INTERP_KERNEL::NormalizedCellType SauvUtilities::gibi2medGeom( size_t gibiType )
416 if ( gibiType < 1 || gibiType > NbGibiCellTypes )
419 return GibiTypeToMed[ gibiType - 1 ];
422 //================================================================================
424 * \brief Conver med element type to gibi one
426 //================================================================================
428 int SauvUtilities::med2gibiGeom( INTERP_KERNEL::NormalizedCellType medGeomType )
430 for ( unsigned int i = 0; i < NbGibiCellTypes; i++ )
431 if ( GibiTypeToMed[ i ] == medGeomType )
437 //================================================================================
439 * \brief Remember the file name
441 //================================================================================
443 FileReader::FileReader(const char* fileName):_fileName(fileName),_iRead(0),_nbToRead(0)
447 //================================================================================
449 * \brief Constructor of ASCII sauve file reader
451 //================================================================================
453 ASCIIReader::ASCIIReader(const char* fileName)
454 :FileReader(fileName),
459 //================================================================================
463 //================================================================================
465 bool ASCIIReader::isASCII() const
470 //================================================================================
472 * \brief Try to open an ASCII file
474 //================================================================================
476 bool ASCIIReader::open()
479 _file = ::_open (_fileName.c_str(), _O_RDONLY|_O_BINARY);
481 _file = ::open (_fileName.c_str(), O_RDONLY);
485 _start = new char [GIBI_BufferSize]; // working buffer beginning
486 //_tmpBuf = new char [GIBI_MaxOutputLen];
493 //THROW_IK_EXCEPTION("Can't open file "<<_fileName << " fd: " << _file);
498 //================================================================================
500 * \brief Close the file
502 //================================================================================
504 ASCIIReader::~ASCIIReader()
519 //================================================================================
521 * \brief Return a next line of the file
523 //================================================================================
525 bool ASCIIReader::getNextLine (char* & line, bool raiseOEF /*= true*/ )
527 if ( getLine( line )) return true;
529 THROW_IK_EXCEPTION("Unexpected EOF on ln "<<_lineNb);
533 //================================================================================
535 * \brief Read a next line of the file if necessary
537 //================================================================================
539 bool ASCIIReader::getLine(char* & line)
542 // Check the state of the buffer;
543 // if there is too little left, read the next portion of data
544 int nBytesRest = _eptr - _ptr;
545 if (nBytesRest < GIBI_MaxOutputLen)
549 // move the remaining portion to the buffer beginning
550 for ( int i = 0; i < nBytesRest; ++i )
552 //memcpy (_tmpBuf, _ptr, nBytesRest);
553 //memcpy (_start, _tmpBuf, nBytesRest);
560 const int nBytesRead = ::read (_file,
561 &_start [nBytesRest],
562 GIBI_BufferSize - nBytesRest);
563 nBytesRest += nBytesRead;
564 _eptr = &_start [nBytesRest];
566 // Check the buffer for the end-of-line
570 // Check for end-of-the-buffer, the ultimate criterion for termination
579 // seek the line-feed character
598 //================================================================================
600 * \brief Prepare for iterating over given nb of values
601 * \param nbToRead - nb of fields to read
602 * \param nbPosInLine - nb of fields in one line
603 * \param width - field width
604 * \param shift - shift from line beginning to the field start
606 //================================================================================
608 void ASCIIReader::init( int nbToRead, int nbPosInLine, int width, int shift /*= 0*/ )
610 _nbToRead = nbToRead;
611 _nbPosInLine = nbPosInLine;
617 getNextLine( _curPos );
618 _curPos = _curPos + _shift;
627 //================================================================================
629 * \brief Prepare for iterating over given nb of string values
631 //================================================================================
633 void ASCIIReader::initNameReading(int nbValues, int width /*= 8*/)
635 init( nbValues, 72 / ( width + 1 ), width, 1 );
638 //================================================================================
640 * \brief Prepare for iterating over given nb of integer values
642 //================================================================================
644 void ASCIIReader::initIntReading(int nbValues)
646 init( nbValues, 10, 8 );
649 //================================================================================
651 * \brief Prepare for iterating over given nb of real values
653 //================================================================================
655 void ASCIIReader::initDoubleReading(int nbValues)
657 init( nbValues, 3, 22 );
659 // Correction 2 of getDouble(): set "C" numeric locale to read numbers
660 // with dot decimal point separator, as it is in SAUVE files
661 _curLocale = setlocale(LC_NUMERIC, "C");
664 //================================================================================
666 * \brief Return true if not all values have been read
668 //================================================================================
670 bool ASCIIReader::more() const
673 if ( _iRead < _nbToRead)
675 if ( _curPos ) result = true;
680 //================================================================================
682 * \brief Go to the nex value
684 //================================================================================
686 void ASCIIReader::next()
689 THROW_IK_EXCEPTION("SauvUtilities::ASCIIReader::next(): no more() values to read");
692 if ( _iRead < _nbToRead )
694 if ( _iPos >= _nbPosInLine )
696 getNextLine( _curPos );
697 _curPos = _curPos + _shift;
702 _curPos = _curPos + _width + _shift;
708 if ( !_curLocale.empty() )
710 setlocale(LC_NUMERIC, _curLocale.c_str());
716 //================================================================================
718 * \brief Return the current integer value
720 //================================================================================
722 int ASCIIReader::getInt() const
724 // fix for two glued ints (issue 0021009):
725 // Line nb | File contents
726 // ------------------------------------------------------------------------------------
727 // 53619905 | 1 2 6 8
728 // 53619906 | SCALAIRE
729 // 53619907 | -63312600499 1 0 0 0 -2 0 2
730 // where -63312600499 is actualy -633 and 12600499
731 char hold=_curPos[_width];
732 _curPos[_width] = '\0';
733 int result = atoi( _curPos );
734 _curPos[_width] = hold;
736 //return atoi(str());
739 //================================================================================
741 * \brief Return the current float value
743 //================================================================================
745 float ASCIIReader::getFloat() const
750 //================================================================================
752 * \brief Return the current double value
754 //================================================================================
756 double ASCIIReader::getDouble() const
758 //std::string aStr (_curPos);
760 // Correction: add missing 'E' specifier
761 // int aPosStart = aStr.find_first_not_of(" \t");
762 // if (aPosStart < (int)aStr.length()) {
763 // int aPosSign = aStr.find_first_of("+-", aPosStart + 1); // pass the leading symbol, as it can be a sign
764 // if (aPosSign < (int)aStr.length()) {
765 // if (aStr[aPosSign - 1] != 'e' && aStr[aPosSign - 1] != 'E')
766 // aStr.insert(aPosSign, "E", 1);
770 // Different Correction (more optimal)
772 // 0.00000000000000E+00 -2.37822406690632E+01 6.03062748797469E+01
773 // 7.70000000000000-100 7.70000000000000+100 7.70000000000000+100
774 //0123456789012345678901234567890123456789012345678901234567890123456789
775 const size_t posE = 18;
776 std::string aStr (_curPos);
777 if ( aStr.find('E') < 0 && aStr.find('e') < 0 )
779 if ( aStr.size() < posE+1 )
780 THROW_IK_EXCEPTION("No more doubles (line #" << lineNb() << ")");
781 aStr.insert( posE, "E", 1 );
782 return atof(aStr.c_str());
784 return atof( _curPos );
787 //================================================================================
789 * \brief Return the current string value
791 //================================================================================
793 string ASCIIReader::getName() const
796 while (( _curPos[len-1] == ' ' || _curPos[len-1] == 0) && len > 0 )
798 return string( _curPos, len );
801 //================================================================================
803 * \brief Constructor of a binary sauve file reader
805 //================================================================================
807 XDRReader::XDRReader(const char* fileName) :FileReader(fileName), _xdrs_file(NULL)
811 //================================================================================
813 * \brief Close the XDR sauve file
815 //================================================================================
817 XDRReader::~XDRReader()
822 xdr_destroy((XDR*)_xdrs);
824 ::fclose(_xdrs_file);
830 //================================================================================
832 * \brief Return false
834 //================================================================================
836 bool XDRReader::isASCII() const
841 //================================================================================
843 * \brief Try to open an XRD file
845 //================================================================================
847 bool XDRReader::open()
851 if ((_xdrs_file = ::fopen(_fileName.c_str(), "r")))
853 _xdrs = (XDR *)malloc(sizeof(XDR));
854 xdrstdio_create((XDR*)_xdrs, _xdrs_file, XDR_DECODE);
856 const int maxsize = 10;
857 char icha[maxsize+1];
859 if (( xdr_ok = xdr_string((XDR*)_xdrs, &icha2, maxsize)))
861 icha[maxsize] = '\0';
862 xdr_ok = (strcmp(icha, "CASTEM XDR") == 0);
866 xdr_destroy((XDR*)_xdrs);
876 //================================================================================
880 //================================================================================
882 bool XDRReader::getNextLine (char* &, bool )
887 //================================================================================
889 * \brief Prepare for iterating over given nb of values
890 * \param nbToRead - nb of fields to read
891 * \param width - field width
893 //================================================================================
895 void XDRReader::init( int nbToRead, int width/*=0*/ )
897 if(_iRead < _nbToRead)
899 cout << "_iRead, _nbToRead : " << _iRead << " " << _nbToRead << endl;
900 cout << "Unfinished iteration before new one !" << endl;
901 THROW_IK_EXCEPTION("SauvUtilities::XDRReader::init(): Unfinished iteration before new one !");
904 _nbToRead = nbToRead;
908 //================================================================================
910 * \brief Prepare for iterating over given nb of string values
912 //================================================================================
914 void XDRReader::initNameReading(int nbValues, int width)
916 init( nbValues, width );
917 _xdr_kind = _xdr_kind_char;
920 unsigned int nels = nbValues*width;
921 _xdr_cvals = (char*)malloc((nels+1)*sizeof(char));
923 xdr_string((XDR*)_xdrs, &_xdr_cvals, nels);
925 _xdr_cvals[nels] = '\0';
929 //================================================================================
931 * \brief Prepare for iterating over given nb of integer values
933 //================================================================================
935 void XDRReader::initIntReading(int nbValues)
938 _xdr_kind = _xdr_kind_int;
942 unsigned int nels = nbValues;
943 unsigned int actual_nels;
944 _xdr_ivals = (int*)malloc(nels*sizeof(int));
945 xdr_array((XDR*)_xdrs, (char **)&_xdr_ivals, &actual_nels, nels, sizeof(int), (xdrproc_t)xdr_int);
950 //================================================================================
952 * \brief Prepare for iterating over given nb of real values
954 //================================================================================
956 void XDRReader::initDoubleReading(int nbValues)
959 _xdr_kind = _xdr_kind_double;
963 unsigned int nels = nbValues;
964 unsigned int actual_nels;
965 _xdr_dvals = (double*)malloc(nels*sizeof(double));
966 xdr_array((XDR*)_xdrs, (char **)&_xdr_dvals, &actual_nels, nels, sizeof(double), (xdrproc_t)xdr_double);
971 //================================================================================
973 * \brief Return true if not all values have been read
975 //================================================================================
977 bool XDRReader::more() const
979 return _iRead < _nbToRead;
982 //================================================================================
984 * \brief Go to the nex value
986 //================================================================================
988 void XDRReader::next()
991 THROW_IK_EXCEPTION("SauvUtilities::XDRReader::next(): no more() values to read");
994 if ( _iRead < _nbToRead )
999 if(_xdr_kind == _xdr_kind_char) free(_xdr_cvals);
1000 if(_xdr_kind == _xdr_kind_int) free(_xdr_ivals);
1001 if(_xdr_kind == _xdr_kind_double) free(_xdr_dvals);
1002 _xdr_kind = _xdr_kind_null;
1006 //================================================================================
1008 * \brief Return the current integer value
1010 //================================================================================
1012 int XDRReader::getInt() const
1014 if(_iRead < _nbToRead)
1016 return _xdr_ivals[_iRead];
1022 xdr_int((XDR*)_xdrs, &result);
1028 //================================================================================
1030 * \brief Return the current float value
1032 //================================================================================
1034 float XDRReader::getFloat() const
1038 xdr_float((XDR*)_xdrs, &result);
1043 //================================================================================
1045 * \brief Return the current double value
1047 //================================================================================
1049 double XDRReader::getDouble() const
1051 if(_iRead < _nbToRead)
1053 return _xdr_dvals[_iRead];
1059 xdr_double((XDR*)_xdrs, &result);
1065 //================================================================================
1067 * \brief Return the current string value
1069 //================================================================================
1071 std::string XDRReader::getName() const
1074 char* s = _xdr_cvals + _iRead*_width;
1075 while (( s[len-1] == ' ' || s[len-1] == 0) && len > 0 )
1077 return string( s, len );
1080 //================================================================================
1082 * \brief Throw an exception if not all needed data is present
1084 //================================================================================
1086 void IntermediateMED::checkDataAvailability() const throw(INTERP_KERNEL::Exception)
1088 if ( _spaceDim == 0 )
1089 THROW_IK_EXCEPTION("Wrong file format"); // it is the first record in the sauve file
1091 if ( _groups.empty() )
1092 THROW_IK_EXCEPTION("No elements have been read");
1094 if ( _points.empty() || _nbNodes == 0 )
1095 THROW_IK_EXCEPTION("Nodes of elements are not filled");
1097 if ( _coords.empty() )
1098 THROW_IK_EXCEPTION("Node coordinates are missing");
1100 if ( _coords.size() < _nbNodes * _spaceDim )
1101 THROW_IK_EXCEPTION("Nodes and coordinates mismatch");
1104 //================================================================================
1106 * \brief Makes ParaMEDMEM::MEDFileData from self
1108 //================================================================================
1110 ParaMEDMEM::MEDFileData* IntermediateMED::convertInMEDFileDS()
1112 MEDCouplingAutoRefCountObjectPtr< MEDFileUMesh > mesh = makeMEDFileMesh();
1113 MEDCouplingAutoRefCountObjectPtr< MEDFileFields > fields = makeMEDFileFields(mesh);
1115 MEDCouplingAutoRefCountObjectPtr< MEDFileMeshes > meshes = MEDFileMeshes::New();
1116 MEDCouplingAutoRefCountObjectPtr< MEDFileData > medData = MEDFileData::New();
1117 meshes->pushMesh( mesh );
1118 medData->setMeshes( meshes );
1119 if ( fields ) medData->setFields( fields );
1121 return medData.retn();
1124 //================================================================================
1126 * \brief Creates ParaMEDMEM::MEDFileUMesh from its data
1128 //================================================================================
1130 ParaMEDMEM::MEDFileUMesh* IntermediateMED::makeMEDFileMesh()
1132 // check if all needed piles are present
1133 checkDataAvailability();
1136 setGroupLongNames();
1138 // fix element orientation
1139 if ( _spaceDim == 2 || _spaceDim == 1 )
1141 else if ( _spaceDim == 3 )
1145 decreaseHierarchicalDepthOfSubgroups();
1146 eraseUselessGroups();
1147 //detectMixDimGroups();
1150 _points.numberNodes();
1153 // make the med mesh
1155 MEDFileUMesh* mesh = MEDFileUMesh::New();
1157 DataArrayDouble *coords = getCoords();
1158 setConnectivity( mesh, coords );
1163 if ( !mesh->getName() || strlen( mesh->getName() ) == 0 )
1164 mesh->setName( "MESH" );
1169 //================================================================================
1171 * \brief Set long names to groups
1173 //================================================================================
1175 void IntermediateMED::setGroupLongNames()
1177 // IMP 0020434: mapping GIBI names to MED names
1178 // set med names to objects (mesh, fields, support, group or other)
1180 set<int> treatedGroups;
1182 list<nameGIBItoMED>::iterator itGIBItoMED = _listGIBItoMED_mail.begin();
1183 for (; itGIBItoMED != _listGIBItoMED_mail.end(); itGIBItoMED++)
1185 if ( (int)_groups.size() < itGIBItoMED->gibi_id ) continue;
1187 SauvUtilities::Group & grp = _groups[itGIBItoMED->gibi_id - 1];
1189 // if there are several names for grp then the 1st name is the name
1190 // of grp and the rest ones are names of groups referring grp (issue 0021311)
1191 const bool isRefName = !treatedGroups.insert( itGIBItoMED->gibi_id ).second;
1194 grp._name = _mapStrings[ itGIBItoMED->med_id ];
1196 else if ( !grp._refNames.empty() && grp._refNames.back().empty() )
1198 for ( unsigned i = 0; i < grp._refNames.size(); ++i )
1199 if ( grp._refNames[i].empty() )
1200 grp._refNames[i] = _mapStrings[ (*itGIBItoMED).med_id ];
1204 grp._refNames.push_back( _mapStrings[ (*itGIBItoMED).med_id ]);
1209 //================================================================================
1211 * \brief Set long names to fields
1213 //================================================================================
1215 void IntermediateMED::setFieldLongNames(set< string >& usedNames)
1217 list<nameGIBItoMED>::iterator itGIBItoMED = _listGIBItoMED_cham.begin();
1218 for (; itGIBItoMED != _listGIBItoMED_cham.end(); itGIBItoMED++)
1220 if (itGIBItoMED->gibi_pile == PILE_FIELD)
1222 _cellFields[itGIBItoMED->gibi_id - 1]->_name = _mapStrings[itGIBItoMED->med_id];
1224 else if (itGIBItoMED->gibi_pile == PILE_NODES_FIELD)
1226 _nodeFields[itGIBItoMED->gibi_id - 1]->_name = _mapStrings[itGIBItoMED->med_id];
1228 } // iterate on _listGIBItoMED_cham
1230 for (itGIBItoMED =_listGIBItoMED_comp.begin(); itGIBItoMED != _listGIBItoMED_comp.end(); itGIBItoMED++)
1232 string medName = _mapStrings[itGIBItoMED->med_id];
1233 string gibiName = _mapStrings[itGIBItoMED->gibi_id];
1235 bool name_found = false;
1236 for ( int isNodal = 0; isNodal < 2 && !name_found; ++isNodal )
1238 vector<DoubleField* > & fields = isNodal ? _nodeFields : _cellFields;
1239 for ( size_t ifi = 0; ifi < fields.size() && !name_found; ifi++)
1241 if (medName.find( fields[ifi]->_name + "." ) == 0 )
1243 vector<DoubleField::_Sub_data>& aSubDs = fields[ifi]->_sub;
1244 int nbSub = aSubDs.size();
1245 for (int isu = 0; isu < nbSub; isu++)
1246 for (int ico = 0; ico < aSubDs[isu].nbComponents(); ico++)
1248 if (aSubDs[isu].compName(ico) == gibiName)
1250 string medNameCompo = medName.substr( fields[ifi]->_name.size() + 1 );
1251 fields[ifi]->_sub[isu].compName(ico) = medNameCompo;
1257 } // iterate on _listGIBItoMED_comp
1259 for ( size_t i = 0; i < _nodeFields.size() ; i++)
1260 usedNames.insert( _nodeFields[i]->_name );
1261 for ( size_t i = 0; i < _cellFields.size() ; i++)
1262 usedNames.insert( _cellFields[i]->_name );
1265 //================================================================================
1267 * \brief Decrease hierarchical depth of subgroups
1269 //================================================================================
1271 void IntermediateMED::decreaseHierarchicalDepthOfSubgroups()
1273 for (size_t i=0; i!=_groups.size(); ++i)
1275 Group& grp = _groups[i];
1276 for (size_t j = 0; j < grp._groups.size(); ++j )
1278 Group & sub_grp = *grp._groups[j];
1279 if ( !sub_grp._groups.empty() )
1281 // replace j with its 1st subgroup
1282 grp._groups[j] = sub_grp._groups[0];
1283 // push back the rest subs
1284 grp._groups.insert( grp._groups.end(), ++sub_grp._groups.begin(), sub_grp._groups.end() );
1287 // remove empty sub-_groups
1288 vector< Group* > newSubGroups;
1289 newSubGroups.reserve( grp._groups.size() );
1290 for (size_t j = 0; j < grp._groups.size(); ++j )
1291 if ( !grp._groups[j]->empty() )
1292 newSubGroups.push_back( grp._groups[j] );
1293 if ( newSubGroups.size() < grp._groups.size() )
1294 grp._groups.swap( newSubGroups );
1298 //================================================================================
1300 * \brief Erase _groups that won't be converted
1302 //================================================================================
1304 void IntermediateMED::eraseUselessGroups()
1306 // propagate _isProfile=true to sub-groups of composite groups
1307 // for (size_t int i=0; i!=_groups.size(); ++i)
1309 // Group* grp = _groups[i];
1310 // if ( grp->_isProfile && !grp->_groups.empty() )
1311 // for (size_t j = 0; j < grp->_groups.size(); ++j )
1312 // grp->_groups[j]->_isProfile=true;
1314 std::set<Group*> groups2convert;
1315 // keep not named sub-groups of field supports
1316 for (size_t i=0; i!=_groups.size(); ++i)
1318 Group& grp = _groups[i];
1319 if ( grp._isProfile && !grp._groups.empty() )
1320 groups2convert.insert( grp._groups.begin(), grp._groups.end() );
1323 // keep named groups and their subgroups
1324 for (size_t i=0; i!=_groups.size(); ++i)
1326 Group& grp = _groups[i];
1327 if ( !grp._name.empty() && !grp.empty() )
1329 groups2convert.insert( &grp );
1330 groups2convert.insert( grp._groups.begin(), grp._groups.end() );
1333 // erase groups that are not in groups2convert and not _isProfile
1334 for (size_t i=0; i!=_groups.size(); ++i)
1336 Group* grp = &_groups[i];
1337 if ( !grp->_isProfile && !groups2convert.count( grp ) )
1339 grp->_cells.clear();
1340 grp->_groups.clear();
1345 //================================================================================
1347 * \brief Detect _groups of mixed dimension
1349 //================================================================================
1351 void IntermediateMED::detectMixDimGroups()
1353 //hasMixedCells = false;
1354 for ( size_t i=0; i < _groups.size(); ++i )
1356 Group& grp = _groups[i];
1357 if ( grp._groups.size() < 2 )
1360 // check if sub-groups have different dimension
1361 unsigned dim1 = getDim( &grp );
1362 for ( size_t j = 1; j < grp._groups.size(); ++j )
1364 unsigned dim2 = getDim( grp._groups[j] );
1368 grp._groups.clear();
1369 if ( !grp._name.empty() )
1370 cout << "Erase a group with elements of different dim |" << grp._name << "|"<< endl;
1377 //================================================================================
1379 * \brief Fix connectivity of elements in 2D space
1381 //================================================================================
1383 void IntermediateMED::orientElements2D()
1385 set<Cell>::const_iterator elemIt, elemEnd;
1386 vector< pair<int,int> > swapVec;
1388 // ------------------------------------
1389 // fix connectivity of quadratic edges
1390 // ------------------------------------
1391 set<Cell>& quadEdges = _cellsByType[ INTERP_KERNEL::NORM_SEG3 ];
1392 if ( !quadEdges.empty() )
1394 elemIt = quadEdges.begin(), elemEnd = quadEdges.end();
1395 for ( ; elemIt != elemEnd; ++elemIt )
1396 ConvertQuadratic( INTERP_KERNEL::NORM_SEG3, *elemIt );
1399 CellsByDimIterator faceIt( *this, 2 );
1400 while ( const set<Cell > * faces = faceIt.nextType() )
1402 TCellType cellType = faceIt.type();
1403 bool isQuadratic = getGibi2MedQuadraticInterlace( cellType );
1405 getReverseVector( cellType, swapVec );
1407 // ------------------------------------
1408 // fix connectivity of quadratic faces
1409 // ------------------------------------
1411 for ( elemIt = faces->begin(), elemEnd = faces->end(); elemIt != elemEnd; elemIt++ )
1412 ConvertQuadratic( cellType, *elemIt );
1414 // --------------------------
1415 // orient faces clockwise
1416 // --------------------------
1417 int iQuad = isQuadratic ? 2 : 1;
1418 for ( elemIt = faces->begin(), elemEnd = faces->end(); elemIt != elemEnd; elemIt++ )
1420 // look for index of the most left node
1421 int iLeft = 0, iNode, nbNodes = elemIt->_nodes.size() / iQuad;
1422 double x, minX = nodeCoords( elemIt->_nodes[0] )[0];
1423 for ( iNode = 1; iNode < nbNodes; ++iNode )
1424 if (( x = nodeCoords( elemIt->_nodes[ iNode ])[ 0 ]) < minX )
1425 minX = x, iLeft = iNode;
1427 // indeces of the nodes neighboring the most left one
1428 int iPrev = ( iLeft - 1 < 0 ) ? nbNodes - 1 : iLeft - 1;
1429 int iNext = ( iLeft + 1 == nbNodes ) ? 0 : iLeft + 1;
1430 // find components of prev-left and left-next vectors
1431 double xP = nodeCoords( elemIt->_nodes[ iPrev ])[ 0 ];
1432 double yP = nodeCoords( elemIt->_nodes[ iPrev ])[ 1 ];
1433 double xN = nodeCoords( elemIt->_nodes[ iNext ])[ 0 ];
1434 double yN = nodeCoords( elemIt->_nodes[ iNext ])[ 1 ];
1435 double xL = nodeCoords( elemIt->_nodes[ iLeft ])[ 0 ];
1436 double yL = nodeCoords( elemIt->_nodes[ iLeft ])[ 1 ];
1437 double xPL = xL - xP, yPL = yL - yP; // components of prev-left vector
1438 double xLN = xN - xL, yLN = yN - yL; // components of left-next vector
1439 // normalise y of the vectors
1440 double modPL = sqrt ( xPL * xPL + yPL * yPL );
1441 double modLN = sqrt ( xLN * xLN + yLN * yLN );
1442 if ( modLN > std::numeric_limits<double>::min() &&
1443 modPL > std::numeric_limits<double>::min() )
1447 // summary direction of neighboring links must be positive
1448 bool clockwise = ( yPL + yLN > 0 );
1450 reverse( *elemIt, swapVec );
1456 //================================================================================
1458 * \brief Fix connectivity of elements in 3D space
1460 //================================================================================
1462 void IntermediateMED::orientElements3D()
1464 // set _reverse flags of faces
1467 // -----------------
1469 // -----------------
1471 set<Cell>::const_iterator elemIt, elemEnd;
1472 vector< pair<int,int> > swapVec;
1474 for ( int dim = 1; dim <= 3; ++dim )
1476 CellsByDimIterator cellsIt( *this, dim );
1477 while ( const set<Cell > * elems = cellsIt.nextType() )
1479 TCellType cellType = cellsIt.type();
1480 bool isQuadratic = getGibi2MedQuadraticInterlace( cellType );
1481 getReverseVector( cellType, swapVec );
1483 elemIt = elems->begin(), elemEnd = elems->end();
1484 for ( ; elemIt != elemEnd; elemIt++ )
1486 // GIBI connectivity -> MED one
1488 ConvertQuadratic( cellType, *elemIt );
1491 if ( elemIt->_reverse )
1492 reverse ( *elemIt, swapVec );
1500 //================================================================================
1502 * \brief Orient equally (by setting _reverse flag) all connected faces in 3D space
1504 //================================================================================
1506 void IntermediateMED::orientFaces3D()
1508 // fill map of links and their faces
1509 set<const Cell*> faces;
1510 map<const Cell*, Group*> fgm;
1511 map<Link, list<const Cell*> > linkFacesMap;
1512 map<Link, list<const Cell*> >::iterator lfIt, lfIt2;
1514 for (size_t i=0; i!=_groups.size(); ++i)
1516 Group& grp = _groups[i];
1517 if ( !grp._cells.empty() && getDimension( grp._cellType ) == 2 )
1518 for ( size_t j = 0; j < grp._cells.size(); ++j )
1519 if ( faces.insert( grp._cells[j] ).second )
1521 for ( size_t k = 0; k < grp._cells[j]->_nodes.size(); ++k )
1522 linkFacesMap[ grp._cells[j]->link( k ) ].push_back( grp._cells[j] );
1523 fgm.insert( make_pair( grp._cells[j], &grp ));
1526 // dump linkFacesMap
1527 // for ( lfIt = linkFacesMap.begin(); lfIt!=linkFacesMap.end(); lfIt++) {
1528 // cout<< "LINK: " << lfIt->first.first << "-" << lfIt->first.second << endl;
1529 // list<const Cell*> & fList = lfIt->second;
1530 // list<const Cell*>::iterator fIt = fList.begin();
1531 // for ( ; fIt != fList.end(); fIt++ )
1532 // cout << "\t" << **fIt << fgm[*fIt]->nom << endl;
1535 // Each oriented link must appear in one face only, else a face is reversed.
1537 queue<const Cell*> faceQueue; /* the queue contains well oriented faces
1538 whose neighbors orientation is to be checked */
1539 bool manifold = true;
1540 while ( !linkFacesMap.empty() )
1542 if ( faceQueue.empty() )
1544 assert( !linkFacesMap.begin()->second.empty() );
1545 faceQueue.push( linkFacesMap.begin()->second.front() );
1547 while ( !faceQueue.empty() )
1549 const Cell* face = faceQueue.front();
1552 // loop on links of <face>
1553 for ( int i = 0; i < (int)face->_nodes.size(); ++i )
1555 Link link = face->link( i );
1556 // find the neighbor faces
1557 lfIt = linkFacesMap.find( link );
1558 int nbFaceByLink = 0;
1559 list< const Cell* > ml;
1560 if ( lfIt != linkFacesMap.end() )
1562 list<const Cell*> & fList = lfIt->second;
1563 list<const Cell*>::iterator fIt = fList.begin();
1564 assert( fIt != fList.end() );
1565 for ( ; fIt != fList.end(); fIt++, nbFaceByLink++ )
1567 ml.push_back( *fIt );
1568 if ( *fIt != face ) // wrongly oriented neighbor face
1570 const Cell* badFace = *fIt;
1571 // reverse and remove badFace from linkFacesMap
1572 for ( int j = 0; j < (int)badFace->_nodes.size(); ++j )
1574 Link badlink = badFace->link( j );
1575 if ( badlink == link ) continue;
1576 lfIt2 = linkFacesMap.find( badlink );
1577 if ( lfIt2 != linkFacesMap.end() )
1579 list<const Cell*> & ff = lfIt2->second;
1580 ff.erase( find( ff.begin(), ff.end(), badFace ));
1582 linkFacesMap.erase( lfIt2 );
1585 badFace->_reverse = true; // reverse
1586 //INFOS_MED( "REVERSE " << *badFace );
1587 faceQueue.push( badFace );
1590 linkFacesMap.erase( lfIt );
1592 // add good neighbors to the queue
1593 Link revLink( link.second, link.first );
1594 lfIt = linkFacesMap.find( revLink );
1595 if ( lfIt != linkFacesMap.end() )
1597 list<const Cell*> & fList = lfIt->second;
1598 list<const Cell*>::iterator fIt = fList.begin();
1599 for ( ; fIt != fList.end(); fIt++, nbFaceByLink++ )
1601 ml.push_back( *fIt );
1603 faceQueue.push( *fIt );
1605 linkFacesMap.erase( lfIt );
1607 if ( nbFaceByLink > 2 )
1611 list<const Cell*>::iterator ii = ml.begin();
1612 cout << nbFaceByLink << " faces by 1 link:" << endl;
1613 for( ; ii!= ml.end(); ii++ )
1614 cout << "in sub-mesh <" << fgm[ *ii ]->_name << "> " << **ii << endl;
1618 } // loop on links of the being checked face
1619 } // loop on the face queue
1620 } // while ( !linkFacesMap.empty() )
1623 cout << " -> Non manifold mesh, faces orientation may be incorrect" << endl;
1626 //================================================================================
1628 * \brief Orient volumes according to MED conventions:
1629 * normal of a bottom (first) face should be outside
1631 //================================================================================
1633 void IntermediateMED::orientVolumes()
1635 set<Cell>::const_iterator elemIt, elemEnd;
1636 vector< pair<int,int> > swapVec;
1638 CellsByDimIterator cellsIt( *this, 3 );
1639 while ( const set<Cell > * elems = cellsIt.nextType() )
1641 TCellType cellType = cellsIt.type();
1642 elemIt = elems->begin(), elemEnd = elems->end();
1643 int nbBottomNodes = 0;
1650 nbBottomNodes = 3; break;
1655 nbBottomNodes = 4; break;
1658 getReverseVector( cellType, swapVec );
1660 for ( ; elemIt != elemEnd; elemIt++ )
1662 // find a normal to the bottom face
1664 n[0] = nodeCoords( elemIt->_nodes[0]); // 3 bottom nodes
1665 n[1] = nodeCoords( elemIt->_nodes[1]);
1666 n[2] = nodeCoords( elemIt->_nodes[2]);
1667 n[3] = nodeCoords( elemIt->_nodes[nbBottomNodes]); // a top node
1668 double vec01[3]; // vector n[0]-n[1]
1669 vec01[0] = n[1][0] - n[0][0];
1670 vec01[1] = n[1][1] - n[0][1];
1671 vec01[2] = n[1][2] - n[0][2];
1672 double vec02 [3]; // vector n[0]-n[2]
1673 vec02[0] = n[2][0] - n[0][0];
1674 vec02[1] = n[2][1] - n[0][1];
1675 vec02[2] = n[2][2] - n[0][2];
1676 double normal [3]; // vec01 ^ vec02
1677 normal[0] = vec01[1] * vec02[2] - vec01[2] * vec02[1];
1678 normal[1] = vec01[2] * vec02[0] - vec01[0] * vec02[2];
1679 normal[2] = vec01[0] * vec02[1] - vec01[1] * vec02[0];
1680 // check if the 102 angle is convex
1681 if ( nbBottomNodes > 3 )
1683 const double* n3 = nodeCoords( elemIt->_nodes[nbBottomNodes-1] );// last bottom node
1684 double vec03 [3]; // vector n[0]-n3
1685 vec03[0] = n3[0] - n[0][0];
1686 vec03[1] = n3[1] - n[0][1];
1687 vec03[2] = n3[2] - n[0][2];
1688 if ( fabs( normal[0]+normal[1]+normal[2] ) <= numeric_limits<double>::max() ) // vec01 || vec02
1690 normal[0] = vec01[1] * vec03[2] - vec01[2] * vec03[1]; // vec01 ^ vec03
1691 normal[1] = vec01[2] * vec03[0] - vec01[0] * vec03[2];
1692 normal[2] = vec01[0] * vec03[1] - vec01[1] * vec03[0];
1696 double vec [3]; // normal ^ vec01
1697 vec[0] = normal[1] * vec01[2] - normal[2] * vec01[1];
1698 vec[1] = normal[2] * vec01[0] - normal[0] * vec01[2];
1699 vec[2] = normal[0] * vec01[1] - normal[1] * vec01[0];
1700 double dot2 = vec[0]*vec03[0] + vec[1]*vec03[1] + vec[2]*vec03[2]; // vec*vec03
1701 if ( dot2 < 0 ) // concave -> reverse normal
1709 // direction from top to bottom
1711 tbDir[0] = n[0][0] - n[3][0];
1712 tbDir[1] = n[0][1] - n[3][1];
1713 tbDir[2] = n[0][2] - n[3][2];
1715 // compare 2 directions: normal and top-bottom
1716 double dot = normal[0]*tbDir[0] + normal[1]*tbDir[1] + normal[2]*tbDir[2];
1717 if ( dot < 0. ) // need reverse
1718 reverse( *elemIt, swapVec );
1720 } // loop on volumes of one geometry
1721 } // loop on 3D geometry types
1725 //================================================================================
1727 * \brief Assign new IDs to nodes by skipping not used nodes and return their number
1729 //================================================================================
1731 int NodeContainer::numberNodes()
1734 for ( size_t i = 0; i < _nodes.size(); ++i )
1735 for ( size_t j = 0; j < _nodes[i].size(); ++j )
1736 if ( _nodes[i][j].isUsed() )
1737 _nodes[i][j]._number = id++;
1742 //================================================================================
1744 * \brief Assign new IDs to elements
1746 //================================================================================
1748 void IntermediateMED::numberElements()
1750 set<Cell>::const_iterator elemIt, elemEnd;
1752 // numbering _cells of type NORM_POINT1 by node number
1754 const set<Cell>& points = _cellsByType[ INTERP_KERNEL::NORM_POINT1 ];
1755 elemIt = points.begin(), elemEnd = points.end();
1756 for ( ; elemIt != elemEnd; ++elemIt )
1757 elemIt->_number = elemIt->_nodes[0]->_number;
1760 // numbering 1D-3D _cells
1761 for ( int dim = 1; dim <= 3; ++dim )
1763 // check if re-numeration is needed (to try to keep elem oreder as in sauve file )
1764 bool ok = true, renumEntity = false;
1765 CellsByDimIterator cellsIt( *this, dim );
1766 int prevNbElems = 0;
1767 while ( const set<Cell> * typeCells = cellsIt.nextType() )
1769 TID minNumber = std::numeric_limits<TID>::max(), maxNumber = 0;
1770 for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt)
1772 if ( elemIt->_number < minNumber ) minNumber = elemIt->_number;
1773 if ( elemIt->_number > maxNumber ) maxNumber = elemIt->_number;
1775 TID typeSize = typeCells->size();
1776 if ( typeSize != maxNumber - minNumber + 1 )
1778 if ( prevNbElems != 0 ) {
1779 if ( minNumber == 1 )
1781 else if ( prevNbElems+1 != (int)minNumber )
1784 prevNbElems += typeSize;
1787 if ( ok && renumEntity ) // each geom type was numerated separately
1789 cellsIt.init( dim );
1790 prevNbElems = cellsIt.nextType()->size(); // no need to renumber the first type
1791 while ( const set<Cell> * typeCells = cellsIt.nextType() )
1793 for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt)
1794 elemIt->_number += prevNbElems;
1795 prevNbElems += typeCells->size();
1801 cellsIt.init( dim );
1802 while ( const set<Cell> * typeCells = cellsIt.nextType() )
1803 for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt)
1804 elemIt->_number = cellID++;
1809 //================================================================================
1811 * \brief Creates coord array
1813 //================================================================================
1815 ParaMEDMEM::DataArrayDouble * IntermediateMED::getCoords()
1817 DataArrayDouble* coordArray = DataArrayDouble::New();
1818 coordArray->alloc( _nbNodes, _spaceDim );
1819 double * coordPrt = coordArray->getPointer();
1820 for ( int i = 0, nb = _points.size(); i < nb; ++i )
1822 Node* n = getNode( i+1 );
1825 const double* nCoords = nodeCoords( n );
1826 std::copy( nCoords, nCoords+_spaceDim, coordPrt );
1827 coordPrt += _spaceDim;
1833 //================================================================================
1835 * \brief Sets connectivity of elements to the mesh
1836 * \param mesh - mesh to fill in
1837 * \param coords - coordinates that must be shared by all meshes of different dim
1839 //================================================================================
1841 void IntermediateMED::setConnectivity( ParaMEDMEM::MEDFileUMesh* mesh,
1842 ParaMEDMEM::DataArrayDouble* coords )
1846 mesh->setCoords( coords );
1848 set<Cell>::const_iterator elemIt, elemEnd;
1849 for ( int dim = 3; dim > 0; --dim )
1851 CellsByDimIterator dimCells( *this, dim );
1854 while ( const std::set<Cell > * cells = dimCells.nextType() )
1855 nbOfCells += cells->size();
1856 if ( nbOfCells == 0 )
1859 if ( !meshDim ) meshDim = dim;
1861 MEDCouplingUMesh* dimMesh = MEDCouplingUMesh::New();
1862 dimMesh->setCoords( coords );
1863 dimMesh->setMeshDimension( dim );
1864 dimMesh->allocateCells( nbOfCells );
1866 int prevNbCells = 0;
1867 dimCells.init( dim );
1868 while ( const std::set<Cell > * cells = dimCells.nextType() )
1870 // fill connectivity array to take into account order of elements in the sauv file
1871 const int nbCellNodes = cells->begin()->_nodes.size();
1872 vector< TID > connectivity( cells->size() * nbCellNodes );
1873 int * nodalConnOfCell;
1874 for ( elemIt = cells->begin(), elemEnd = cells->end(); elemIt != elemEnd; ++elemIt )
1876 const Cell& cell = *elemIt;
1877 const int index = cell._number - 1 - prevNbCells;
1878 nodalConnOfCell = &connectivity[ index * nbCellNodes ];
1879 if ( cell._reverse )
1880 for ( int i = nbCellNodes-1; i >= 0; --i )
1881 *nodalConnOfCell++ = cell._nodes[i]->_number - 1;
1883 for ( int i = 0; i < nbCellNodes; ++i )
1884 *nodalConnOfCell++ = cell._nodes[i]->_number - 1;
1886 prevNbCells += cells->size();
1889 TCellType cellType = dimCells.type();
1890 nodalConnOfCell = &connectivity[0];
1891 for ( size_t i = 0; i < cells->size(); ++i, nodalConnOfCell += nbCellNodes )
1892 dimMesh->insertNextCell( cellType, nbCellNodes, nodalConnOfCell );
1894 dimMesh->finishInsertingCells();
1895 mesh->setMeshAtLevel( dim - meshDim, dimMesh );
1900 //================================================================================
1902 * \brief Fill in the mesh with groups
1903 * \param mesh - mesh to fill in
1905 //================================================================================
1907 void IntermediateMED::setGroups( ParaMEDMEM::MEDFileUMesh* mesh )
1909 bool isMeshNameSet = false;
1910 const int meshDim = mesh->getMeshDimension();
1911 for ( int dim = 0; dim <= meshDim; ++dim )
1913 const int meshDimRelToMaxExt = ( dim == 0 ? 1 : dim - meshDim );
1915 vector<const DataArrayInt *> medGroups;
1916 vector<MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > refGroups;
1917 for ( size_t i = 0; i < _groups.size(); ++i )
1919 Group& grp = _groups[i];
1920 if ( (int)getDim( &grp ) != dim &&
1921 grp._groups.empty() ) // to allow groups on diff dims
1923 // convert only named groups or field supports
1924 if ( grp.empty() || (grp._name.empty() && !grp._isProfile ))
1926 //if ( grp._medGroup ) continue; // already converted
1928 // sort cells by ID and remember their initial order in the group
1929 TCellToOrderMap cell2order;
1930 unsigned orderInGroup = 0;
1931 vector< Group* > groupVec;
1932 if ( grp._groups.empty() ) groupVec.push_back( & grp );
1933 else groupVec = grp._groups;
1934 for ( size_t iG = 0; iG < groupVec.size(); ++iG )
1936 Group* aG = groupVec[ iG ];
1937 if ( (int)getDim( aG ) != dim )
1939 for ( size_t iC = 0; iC < aG->_cells.size(); ++iC )
1940 cell2order.insert( cell2order.end(), make_pair( aG->_cells[iC], orderInGroup++ ));
1942 if ( cell2order.empty() )
1944 bool isSelfIntersect = ( orderInGroup != cell2order.size() );
1945 if ( isSelfIntersect ) // self intersecting group
1948 msg << "Self intersecting sub-mesh: id = " << i+1
1949 << ", name = |" << grp._name << "|" << endl
1950 << " nb unique elements = " << cell2order.size() << endl
1951 << " total nb elements = " << orderInGroup;
1952 if ( grp._isProfile )
1954 THROW_IK_EXCEPTION( msg.str() );
1958 cout << msg.str() << endl;
1961 // create a med group
1962 grp._medGroup = DataArrayInt::New();
1963 grp._medGroup->setName( grp._name.c_str() );
1964 grp._medGroup->alloc( cell2order.size(), /*nbOfCompo=*/1 );
1965 int * idsPrt = grp._medGroup->getPointer();
1966 TCellToOrderMap::iterator cell2orderIt, cell2orderEnd = cell2order.end();
1967 for ( cell2orderIt = cell2order.begin(); cell2orderIt != cell2orderEnd; ++cell2orderIt )
1968 *idsPrt++ = (*cell2orderIt).first->_number - 1;
1970 // try to set the mesh name
1971 if ( !isMeshNameSet &&
1973 !grp._name.empty() &&
1974 grp.size() == mesh->getSizeAtLevel( meshDimRelToMaxExt ))
1976 mesh->setName( grp._name.c_str() );
1977 isMeshNameSet = true;
1979 if ( !grp._name.empty() )
1981 medGroups.push_back( grp._medGroup );
1983 // set relocation table
1984 setRelocationTable( &grp, cell2order );
1986 // Issue 0021311. Use case: a gibi group has references (recorded in pile 1)
1987 // and several names (pile 27) refer (pile 10) to this group.
1988 // We create a copy of this group per each named reference
1989 for ( unsigned iRef = 0 ; iRef < grp._refNames.size(); ++iRef )
1990 if ( !grp._refNames[ iRef ].empty() )
1992 refGroups.push_back( grp._medGroup->deepCpy() );
1993 refGroups.back()->setName( grp._refNames[ iRef ].c_str() );
1994 medGroups.push_back( refGroups.back() );
1997 mesh->setGroupsAtLevel( meshDimRelToMaxExt, medGroups );
2001 //================================================================================
2003 * \brief Return true if the group is on all elements and return its relative dimension
2005 //================================================================================
2007 bool IntermediateMED::isOnAll( const Group* grp, int & dimRel ) const
2009 int dim = getDim( grp );
2012 CellsByDimIterator dimCells( *this, dim );
2013 while ( const set<Cell > * cells = dimCells.nextType() )
2014 nbElems += cells->size();
2016 const bool onAll = ( nbElems == grp->size() );
2023 for ( ; meshDim > 0; --meshDim )
2025 dimCells.init( meshDim );
2026 if ( dimCells.nextType() )
2029 dimRel = dim - meshDim;
2034 //================================================================================
2036 * \brief Makes fields from own data
2038 //================================================================================
2040 ParaMEDMEM::MEDFileFields * IntermediateMED::makeMEDFileFields(ParaMEDMEM::MEDFileUMesh* mesh)
2042 if ( _nodeFields.empty() && _cellFields.empty() ) return 0;
2045 set< string > usedFieldNames;
2046 setFieldLongNames(usedFieldNames);
2048 MEDFileFields* fields = MEDFileFields::New();
2050 for ( size_t i = 0; i < _nodeFields.size(); ++i )
2051 setFields( _nodeFields[i], fields, mesh, i+1, usedFieldNames );
2053 for ( size_t i = 0; i < _cellFields.size(); ++i )
2054 setFields( _cellFields[i], fields, mesh, i+1, usedFieldNames );
2059 //================================================================================
2061 * \brief Make med fields from a SauvUtilities::DoubleField
2063 //================================================================================
2065 void IntermediateMED::setFields( SauvUtilities::DoubleField* fld,
2066 ParaMEDMEM::MEDFileFields* medFields,
2067 ParaMEDMEM::MEDFileUMesh* mesh,
2069 set< string >& usedFieldNames)
2071 if ( !fld || !fld->isMedCompatible() ) return;
2073 // if ( !fld->hasCommonSupport() ):
2074 // each sub makes MEDFileFieldMultiTS
2076 // unite several subs into a MEDCouplingFieldDouble
2078 const bool uniteSubs = fld->hasCommonSupport();
2080 cout << "Castem field #" << castemID << " " << fld->_name
2081 << " is incompatible with MED format, so we split it into several fields" << endl;
2083 for ( size_t iSub = 0; iSub < fld->_sub.size(); )
2086 if ( !uniteSubs || fld->_name.empty() )
2087 makeFieldNewName( usedFieldNames, fld );
2090 DataArrayDouble * values = DataArrayDouble::New();
2091 values->alloc( fld->getNbTuples(iSub), fld->_sub[iSub].nbComponents() );
2094 double * valPtr = values->getPointer();
2097 int nbElems = fld->_group->size();
2098 for ( int elemShift = 0; elemShift < nbElems; )
2099 elemShift += fld->setValues( valPtr, iSub++, elemShift );
2100 setTS( fld, values, medFields, mesh );
2104 fld->setValues( valPtr, iSub++ );
2105 setTS( fld, values, medFields, mesh, iSub );
2110 //================================================================================
2112 * \brief Store value array of a field into med fields
2114 //================================================================================
2116 void IntermediateMED::setTS( SauvUtilities::DoubleField* fld,
2117 ParaMEDMEM::DataArrayDouble* values,
2118 ParaMEDMEM::MEDFileFields* medFields,
2119 ParaMEDMEM::MEDFileUMesh* mesh,
2122 // analyze a field support
2123 const Group* support = fld->getSupport();
2125 const bool onAll = isOnAll( support, dimRel );
2126 if ( !onAll && support->_name.empty() )
2128 const_cast<Group*>(support)->_name += "PFL_" + fld->_name;
2129 support->_medGroup->setName( support->_name.c_str() );
2132 // make a time-stamp
2133 MEDCouplingFieldDouble * timeStamp = MEDCouplingFieldDouble::New( fld->getMedType(),
2134 fld->getMedTimeDisc() );
2135 timeStamp->setName( fld->_name.c_str() );
2136 timeStamp->setDescription( fld->_description.c_str() );
2137 MEDCouplingAutoRefCountObjectPtr< MEDCouplingUMesh > dimMesh = mesh->getMeshAtLevel( dimRel );
2138 timeStamp->setMesh( dimMesh );
2139 for ( size_t i = 0; i < (size_t)fld->_sub[iSub].nbComponents(); ++i )
2140 values->setInfoOnComponent( i, fld->_sub[iSub]._comp_names[ i ].c_str() );
2141 timeStamp->setArray( values );
2144 // get a field to add the time-stamp
2145 bool isNewMedField = false;
2146 if ( !fld->_curMedField || fld->_name != fld->_curMedField->getName() )
2148 fld->_curMedField = MEDFileFieldMultiTS::New();
2149 isNewMedField = true;
2153 timeStamp->setOrder( fld->_curMedField->getNumberOfTS() );
2155 // add the time-stamp
2157 fld->_curMedField->appendFieldNoProfileSBT( timeStamp );
2159 fld->_curMedField->appendFieldProfile( timeStamp, mesh, dimRel, support->_medGroup );
2160 timeStamp->decrRef();
2162 if ( isNewMedField ) // timeStamp must be added before this
2164 medFields->pushField( fld->_curMedField );
2168 //================================================================================
2170 * \brief Make a new unique name for a field
2172 //================================================================================
2174 void IntermediateMED::makeFieldNewName(std::set< std::string >& usedNames,
2175 SauvUtilities::DoubleField* fld )
2177 string base = fld->_name;
2184 string::size_type pos = base.rfind('_');
2185 if ( pos != string::npos )
2186 base = base.substr( 0, pos+1 );
2194 fld->_name = base + SauvUtilities::toString( i++ );
2196 while( !usedNames.insert( fld->_name ).second );
2199 //================================================================================
2201 * \brief Return a vector ready to fill in
2203 //================================================================================
2205 std::vector< double >& DoubleField::addComponent( int nb_values )
2207 _comp_values.push_back( std::vector< double >() );
2208 std::vector< double >& res = _comp_values.back();
2209 res.resize( nb_values );
2213 DoubleField::~DoubleField()
2216 _curMedField->decrRef();
2219 //================================================================================
2221 * \brief Returns a supporting group
2223 //================================================================================
2225 const Group* DoubleField::getSupport( const int iSub ) const
2227 return _group ? _group : _sub[iSub]._support;
2230 //================================================================================
2232 * \brief Return true if each sub-component is a time stamp
2234 //================================================================================
2236 bool DoubleField::isMultiTimeStamps() const
2238 if ( _sub.size() < 2 )
2240 bool sameSupports = true;
2241 Group* grp1 = _sub[0]._support;
2242 for ( size_t i = 1; i < _sub.size() && sameSupports; ++i )
2243 sameSupports = ( grp1 == _sub[i]._support );
2245 return sameSupports;
2248 //================================================================================
2250 * \brief True if the field can be converted into the med field
2252 //================================================================================
2254 bool DoubleField::isMedCompatible() const
2256 for ( size_t iSub = 0; iSub < _sub.size(); ++iSub )
2258 if ( !getSupport(iSub) || !getSupport(iSub)->_medGroup )
2259 THROW_IK_EXCEPTION("SauvReader INTERNAL ERROR: NULL field support");
2261 if ( !_sub[iSub].isValidNbGauss() )
2263 cout << "Skip field <" << _name << "> : different nb of gauss points in components" <<endl;
2267 // check if there are no gauss or nbGauss() == nbCellNodes,
2268 // else we lack info on gauss point localization
2273 //================================================================================
2275 * \brief return true if all sub-components has same components and same nbGauss
2277 //================================================================================
2279 bool DoubleField::hasSameComponentsBySupport() const
2281 vector< _Sub_data >::const_iterator sub_data = _sub.begin();
2282 const _Sub_data& first_sub_data = *sub_data;
2283 for ( ++sub_data ; sub_data != _sub.end(); ++sub_data )
2285 if ( first_sub_data._comp_names != sub_data->_comp_names )
2286 return false; // diff names of components
2288 if ( first_sub_data._nb_gauss != sub_data->_nb_gauss &&
2289 first_sub_data._support->_cellType == sub_data->_support->_cellType)
2290 return false; // diff nb of gauss points on same cell type
2295 //================================================================================
2297 * \brief Return type of MEDCouplingFieldDouble
2299 //================================================================================
2301 ParaMEDMEM::TypeOfField DoubleField::getMedType( const int iSub ) const
2303 using namespace INTERP_KERNEL;
2305 const Group* grp = hasCommonSupport() ? _group : _sub[iSub]._support;
2306 if ( _sub[iSub].nbGauss() > 1 )
2308 const CellModel& cm = CellModel::GetCellModel( _sub[iSub]._support->_cellType );
2309 return (int) cm.getNumberOfNodes() == _sub[iSub].nbGauss() ? ON_GAUSS_NE : ON_GAUSS_PT;
2313 return getDim( grp ) == 0 ? ON_NODES : ON_CELLS;
2317 //================================================================================
2319 * \brief Return TypeOfTimeDiscretization
2321 //================================================================================
2323 ParaMEDMEM::TypeOfTimeDiscretization DoubleField::getMedTimeDisc() const
2329 // CONST_ON_TIME_INTERVAL = 7
2332 //================================================================================
2334 * \brief Return nb tuples to be used to allocate DataArrayDouble
2336 //================================================================================
2338 int DoubleField::getNbTuples( const int iSub ) const
2341 if ( hasCommonSupport() && !_group->_groups.empty() )
2342 for ( size_t i = 0; i < _group->_groups.size(); ++i )
2343 nb += _sub[i].nbGauss() * _sub[i]._support->size();
2345 nb = _sub[iSub].nbGauss() * getSupport(iSub)->size();
2349 //================================================================================
2351 * \brief Store values of a sub-component and return nb of elements in the iSub
2353 //================================================================================
2355 int DoubleField::setValues( double * valPtr, const int iSub, const int elemShift ) const
2357 // find values for iSub
2359 for ( int iS = 0; iS < iSub; ++iS )
2360 iComp += _sub[iS].nbComponents();
2361 const vector< double > * compValues = &_comp_values[ iComp ];
2363 const vector< unsigned >& relocTable = getSupport( iSub )->_relocTable;
2367 const int nbElems = _sub[iSub]._support->size();
2368 const int nbGauss = _sub[iSub].nbGauss();
2369 const int nbComponents = _sub[iSub].nbComponents();
2370 const int nbValsByElem = nbComponents * nbGauss;
2373 for ( iComp = 0; iComp < nbComponents; ++iComp )
2374 nbVals += compValues[iComp].size();
2375 if ( nbVals != nbElems * nbValsByElem )
2376 THROW_IK_EXCEPTION("SauvMedConvertor.cxx: support size mismatches field size");
2377 // compute nb values in previous subs
2379 for ( int iS = iSub-1, shift = elemShift; shift > 0; )
2381 int nbE = _sub[iS]._support->size();
2383 valsShift += nbE * _sub[iS].nbComponents() * _sub[iS].nbGauss();
2385 for ( int iE = 0; iE < nbElems; ++iE )
2387 int iMed = valsShift + nbValsByElem * ( relocTable.empty() ? iE : relocTable[iE+elemShift]-elemShift );
2388 for ( iComp = 0; iComp < nbComponents; ++iComp )
2389 for ( int iG = 0; iG < nbGauss; ++iG )
2390 valPtr[ iMed + iG * nbComponents + iComp ] = compValues[iComp][ iE * nbGauss + iG ];
2395 //================================================================================
2397 * \brief Destructor of IntermediateMED
2399 //================================================================================
2401 IntermediateMED::~IntermediateMED()
2403 for ( size_t i = 0; i < _nodeFields.size(); ++i )
2404 if ( _nodeFields[i] )
2405 delete _nodeFields[i];
2406 _nodeFields.clear();
2408 for ( size_t i = 0; i < _cellFields.size(); ++i )
2409 if ( _cellFields[i] )
2410 delete _cellFields[i];
2411 _cellFields.clear();
2413 for ( size_t i = 0; i < _groups.size(); ++i )
2414 if ( _groups[i]._medGroup )
2415 _groups[i]._medGroup->decrRef();
2418 //================================================================================
2420 * \brief CellsByDimIterator constructor
2422 CellsByDimIterator::CellsByDimIterator( const IntermediateMED & medi, int dimm)
2428 * \brief Initialize iteration on cells of given dimention
2430 void CellsByDimIterator::init(const int dimm)
2433 myTypeEnd = INTERP_KERNEL::NORM_HEXA20 + 1;
2437 * \brief return next set of Cell's of required dimension
2439 const std::set< Cell > * CellsByDimIterator::nextType()
2441 while ( ++myCurType < myTypeEnd )
2442 if ( !myImed->_cellsByType[myCurType].empty() && ( myDim < 0 || dim(false) == myDim ))
2443 return & myImed->_cellsByType[myCurType];
2447 * \brief return dimension of cells returned by the last or further next()
2449 int CellsByDimIterator::dim(const bool last) const
2451 int typp = myCurType;
2453 while ( typp < myTypeEnd && myImed->_cellsByType[typp].empty() )
2455 return typp < myTypeEnd ? getDimension( TCellType( typp )) : 4;
2457 // END CellsByDimIterator ========================================================