1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 #ifndef DRIVERTOOLS_HXX
23 #define DRIVERTOOLS_HXX
27 #include "MEDMEM_define.hxx"
28 #include "MEDMEM_Exception.hxx"
29 #include "MEDMEM_FieldForward.hxx"
30 #include "MEDMEM_ArrayInterface.hxx"
31 #include "MEDMEM_Group.hxx"
32 #include "MEDMEM_GaussLocalization.hxx"
43 // Way of storing values with gauss points by CASTEM: full/no interlace.
44 // Remove code switched by this symbol as soon as the way is found out,
45 // from here and from gibi driver
46 #define CASTEM_FULL_INTERLACE
56 class _intermediateMED;
58 // ==============================================================================
59 struct MEDMEM_EXPORT _noeud
61 mutable int number; // negative if node is merged
62 std::vector<double> coord;
65 // ==============================================================================
66 typedef pair<int,int> _link; // a pair of node numbers
68 // ==============================================================================
69 struct MEDMEM_EXPORT _maille
71 typedef std::map<int,_noeud>::iterator TNoeud; //iter;
72 std::vector< TNoeud > sommets;
73 MED_EN::medGeometryElement geometricType;
74 mutable bool reverse; // to reverse sommets of a face
75 mutable int* sortedNodeIDs; // for comparison and merge
76 //mutable list<unsigned> groupes; // the GROUPs maille belongs to, used to create families
78 _maille(MED_EN::medGeometryElement type=MED_EN::MED_NONE, size_t nelem=0)
79 : geometricType(type),reverse(false),sortedNodeIDs(0),_ordre(0) { sommets.reserve(nelem); }
81 _maille(const _maille& ma);
82 void init() const { if ( sortedNodeIDs ) delete [] sortedNodeIDs; sortedNodeIDs = 0; }
83 ~_maille() { init(); }
85 int dimension() const // retourne la dimension de la maille
86 { return geometricType/100; }
88 int dimensionWithPoly() const // retourne la dimension de la maille
89 { return geometricType >= MED_EN::MED_POLYGON ? dimension()-2 : dimension(); }
91 const int* getSortedNodes() const; // creates if needed and return sortedNodeIDs
92 bool operator < (const _maille& ma) const;
93 MED_EN::medEntityMesh getEntity(const int meshDimension) const throw (MEDEXCEPTION);
94 _link link(int i) const;
96 //bool isMerged(int i) const { return sommets[i]->second.number < 0; }
97 int nodeNum(int i) const { return abs( sommets[i]->second.number ); }
98 int nodeID (int i) const { return sommets[i]->first; } // key in points map
100 unsigned ordre() const { return abs( _ordre ); }
101 bool isMerged() const { return _ordre < 0; }
102 void setMergedOrdre(unsigned o) const { _ordre = -o; }
103 void setOrdre(int o) const { _ordre = o; }
106 mutable int _ordre; // l'ordre est fixé après insertion dans le set, et ne change ni l'état, ni l'ordre -> mutable
107 _maille& operator=(const _maille& ma);
110 // ==============================================================================
111 struct MEDMEM_EXPORT _mailleIteratorCompare // pour ordonner le set d'iterateurs sur mailles
113 // this operator is used for ordering mailles thinin a group, which happens when
114 // right numbers are already given to _maille's, so we can use _maille::ordre
115 // for comparison instead of a heavy _maille::operator <
116 bool operator () (std::set<_maille>::iterator i1, std::set<_maille>::iterator i2)
119 return i1->ordre() < i2->ordre();
123 // ==============================================================================
124 struct MEDMEM_EXPORT _groupe
126 typedef std::set<_maille>::iterator TMaille;
127 typedef std::vector< TMaille >::const_iterator TMailleIter;
129 std::vector< TMaille > mailles; // iterateurs sur les mailles composant le groupe
130 std::vector<int> groupes; // indices des sous-groupes composant le groupe
131 std::map<unsigned,int> relocMap; // map _maille::ordre() -> index in GROUP, built by getGroups()
134 const _maille& maille(int index) { return *mailles[index]; }
135 bool empty() const { return mailles.empty() && groupes.empty(); }
137 int size() const { return (mailles.size()>relocMap.size())?mailles.size():relocMap.size(); }
139 int size() const { return std::max( mailles.size(), relocMap.size() ); }
141 _groupe():medGroup(0) {}
144 // ==============================================================================
145 struct MEDMEM_EXPORT _fieldBase {
146 // a field contains several subcomponents each referring to its own support and
147 // having several named components
148 // ----------------------------------------------------------------------------
149 struct _sub_data // a subcomponent
150 // --------------------------------
152 int _supp_id; // group index within _intermediateMED::groupes
153 std::vector<std::string> _comp_names; // component names
154 std::vector<int> _nb_gauss; // nb values per element in a component
156 void setData( int nb_comp, int supp_id )
157 { _supp_id = supp_id - 1; _comp_names.resize(nb_comp); _nb_gauss.resize(nb_comp,1); }
158 int nbComponents() const { return _comp_names.size(); }
159 std::string & compName( int i_comp ) { return _comp_names[ i_comp ]; }
160 bool isValidNbGauss() const { return *std::max_element( _nb_gauss.begin(), _nb_gauss.end() ) ==
161 *std::min_element( _nb_gauss.begin(), _nb_gauss.end() ); }
163 int nbGauss() const { return (1>_nb_gauss[0])?1:_nb_gauss[0]; }
165 int nbGauss() const { return std::max( 1, _nb_gauss[0] ); }
167 bool hasGauss() const { return nbGauss() > 1; }
169 // ----------------------------------------------------------------------------
170 std::vector< _sub_data > _sub;
171 int _group_id; // group index within _intermediateMED::groupes
172 // if _group_id == -1 then each subcomponent makes a separate MEDMEM::FIELD, else all subcomponents
173 // are converted into one MEDMEM::FIELD. The latter is possible only if nb of components in all subs
174 // is the same and supports of subcomponents do not overlap
175 MED_EN::med_type_champ _type;
177 std::string _description;// field description
179 _fieldBase( MED_EN::med_type_champ theType, int nb_sub )
180 : _group_id(-1),_type(theType) { _sub.resize( nb_sub ); }
181 virtual std::list<std::pair< FIELD_*, int> > getField(std::vector<_groupe>& groupes) const = 0;
182 void getGroupIds( std::set<int> & ids, bool all ) const; // return ids of main and/or sub-groups
183 bool hasCommonSupport() const { return _group_id >= 0; } // true if there is one support for all subs
184 bool hasSameComponentsBySupport() const;
185 virtual void dump(std::ostream&) const;
186 virtual ~_fieldBase() {}
189 // ==============================================================================
190 template< class T > class _field: public _fieldBase
192 std::vector< std::vector< T > > comp_values;
194 _field< T > ( MED_EN::med_type_champ theType, int nb_sub, int total_nb_comp )
195 : _fieldBase( theType, nb_sub ) { comp_values.reserve( total_nb_comp ); }
196 std::vector< T >& addComponent( int nb_values ); // return a vector ready to fill in
197 std::list<std::pair< FIELD_*, int> > getField(std::vector<_groupe>& groupes) const;
198 virtual void dump(std::ostream&) const;
201 // ==============================================================================
204 * Iterator on set of _maille's of given dimension
207 class MEDMEM_EXPORT _maillageByDimIterator
210 // if (convertPoly) then treat poly as 2d and 3d, else as 4d and 5d (=medGeometryElement/100)
211 _maillageByDimIterator( const _intermediateMED & medi,
212 const int dim=-1, // dim=-1 - for all dimensions
213 const bool convertPoly = false )
214 { myImed = & medi; init( dim, convertPoly ); }
216 // if (convertPoly) then treat poly as 2d and 3d, else as 4d and 5d (=medGeometryElement/100)
217 void init(const int dim=-1, // dim=-1 - for all dimensions
218 const bool convertPoly = false );
220 //!< return next set of _maille's of required dimension
221 const std::set<_maille > * nextType() {
222 while ( myIt != myEnd )
223 if ( !myIt->second.empty() && ( myDim < 0 || dim(false) == myDim ))
224 return & (myIt++)->second;
229 //!< return dimension of mailles returned by the last or further next()
230 int dim(const bool last=true) const {
233 return myConvertPoly ?
234 it->second.begin()->dimensionWithPoly() :
235 it->second.begin()->dimension();
237 //!< return type of mailles returned by the last next()
238 MED_EN::medGeometryElement type() const { iterator it = myIt; return (--it)->first; }
240 //!< return number of mailles taking into account merged ones
241 int sizeWithoutMerged() const {
243 removed::const_iterator tNb = nbRemovedByType->find( (--it)->first );
244 return it->second.size() - ( tNb == nbRemovedByType->end() ? 0 : tNb->second );
247 typedef std::map<MED_EN::medGeometryElement, int > removed;
248 typedef std::map<MED_EN::medGeometryElement, std::set<_maille > > TMaillageByType;
249 typedef TMaillageByType::const_iterator iterator;
251 const _intermediateMED* myImed;
252 iterator myIt, myEnd;
253 int myDim, myConvertPoly;
254 const removed * nbRemovedByType;
257 // ==============================================================================
260 * Intermediate structure used by drivers to store data read from the other format file.
261 * The structure provides functions that transform the stored data to the MED format :
262 * getCoordinate(), getConnectivity(), getGroups().
263 * The elements inserted in maillage and points are automaticaly ordered.
264 * Renumbering are performed by getConnectivity & getGroups before writing the MED structures.
265 * Read the conception ducumentation for more details.
268 struct MEDMEM_EXPORT _intermediateMED
270 typedef std::map<MED_EN::medGeometryElement, std::set<_maille > > TMaillageByType;
271 typedef std::map<MED_EN::medGeometryElement, int > TNbByType;
272 typedef std::map< const _maille*, std::vector<int> > TPolyherdalNbFaceNodes;
274 TNbByType nbRemovedByType; // nb mailles removed by merge
275 std::vector<_groupe> groupes;
276 //std::vector<GROUP *> medGroupes;
277 std::map< int, _noeud > points;
278 std::list< _fieldBase* > fields;
279 bool hasMixedCells; // true if there are groups with mixed entity types
280 TPolyherdalNbFaceNodes polyherdalNbFaceNodes; // nb of nodes in faces for each polyhedron
282 inline _groupe::TMaille insert(const _maille& ma);
284 int getMeshDimension() const;
285 void mergeNodesAndElements(double tolerance); // optionally merge nodes and elements
286 CONNECTIVITY * getConnectivity(); // creates MED connectivity from the intermediate structure
287 COORDINATE * getCoordinate(const string & coordinateSystem="CARTESIAN"); // makes MED coordinate
288 // void getFamilies(std::vector<FAMILY *> & _famCell, std::vector<FAMILY *> & _famFace,
289 // std::vector<FAMILY *> & _famEdge, std::vector<FAMILY *> & _famNode,
291 void getGroups(std::vector<GROUP *> & _groupCell, std::vector<GROUP *> & _groupFace,
292 std::vector<GROUP *> & _groupEdge, std::vector<GROUP *> & _groupNode,
294 //GROUP * getGroup( int i );
296 void getFields(std::list< FIELD_* >& fields);
298 // used by previous functions to renumber points & mesh.
299 bool myGroupsTreated;
300 void treatGroupes(); // detect groupes of mixed dimension
301 void numerotationMaillage();
302 bool numerotationPoints(); // return true if renumeration done
303 int nbMerged(int geoType) const; //!< nb nodes removed by merge
306 { myNodesNumerated = myMaillesNumerated = myGroupsTreated = false; currentTypeMailles = 0; }
311 bool myNodesNumerated, myMaillesNumerated;
312 // mailles groupped by geom type; use insert() for filling in and
313 // _maillageByDimIterator for exploring it
314 //std::set<_maille> maillage;
315 TMaillageByType maillageByType;
316 TMaillageByType::value_type* currentTypeMailles; // for fast insertion
317 friend class _maillageByDimIterator;
319 //-----------------------------------------------------------------------
320 _groupe::TMaille _intermediateMED::insert(const _maille& ma)
322 if ( !currentTypeMailles || currentTypeMailles->first != ma.geometricType )
323 currentTypeMailles = & *maillageByType.insert
324 ( make_pair( ma.geometricType, std::set<_maille >())).first;
326 _groupe::TMaille res = currentTypeMailles->second.insert( ma ).first;
328 ((_maille&)ma).init(); // this method was added for the sake of this call which is needed to
329 // remove comparison key (sortedNodeIDs) from a temporary _maille ma
334 // ==============================================================================
336 std::ostream& operator << (std::ostream& , const _maille& );
337 std::ostream& operator << (std::ostream& , const _groupe& );
338 std::ostream& operator << (std::ostream& , const _noeud& );
339 std::ostream& operator << (std::ostream& , const _intermediateMED& );
340 std::ostream& operator << (std::ostream& , const _fieldBase* );
342 // ===========================================================
343 // field template implementation //
344 // ===========================================================
347 std::vector< T >& _field< T >::addComponent( int nb_values )
349 comp_values.push_back( std::vector< T >() );
350 std::vector< T >& res = comp_values.back();
351 res.resize( nb_values );
355 //=======================================================================
356 //function : getField
357 //purpose : return list of pairs< field, supporting_group_id >
358 //=======================================================================
361 std::list<std::pair< FIELD_*, int> > _field< T >::getField(std::vector<_groupe> & groupes) const
363 const char* LOC = "_field< T >::getField()";
365 std::list<std::pair< FIELD_*, int> > res;
369 vector<int> nbelgeoc(2,0), nbgaussgeo(2,0);
371 int i_comp_tot = 0, nb_fields = 0;
372 std::set<int> supp_id_set; // to create a new field when support repeats if hasCommonSupport()
373 std::vector< _sub_data >::const_iterator sub_data, sub_end = _sub.end();
377 if ( hasCommonSupport() ) // several subs are combined into one field
379 grp = & groupes[ _group_id ];
380 medGrp = grp->medGroup;
381 if ( !grp || grp->empty() || !medGrp || !medGrp->getNumberOfTypes())
384 // Make gauss array data
385 nbtypegeo = medGrp->getNumberOfTypes();
386 nbelgeoc .resize( nbtypegeo + 1, 0 );
387 nbgaussgeo.resize( nbtypegeo + 1, 0 );
388 const int * nbElemByType = medGrp->getNumberOfElements();
389 const MED_EN::medGeometryElement* types = medGrp->getTypes();
390 for (int iType = 0; iType < nbtypegeo; ++iType) {
392 nbelgeoc [ iType+1 ] = nbelgeoc[ iType ] + nbElemByType[ iType ];
393 // nb gauss by type; find a sub for a geo type
394 for ( sub_data = _sub.begin(); sub_data != sub_end; ++sub_data ) {
395 _groupe & sub_grp = groupes[ sub_data->_supp_id ];
396 if ( !sub_grp.empty() && sub_grp.mailles[0]->geometricType == types[ iType ])
399 ASSERT_MED( sub_data != sub_end );
400 nbgaussgeo[ iType+1 ] = sub_data->nbGauss();
403 typedef typename MEDMEM_ArrayInterface<T,FullInterlace,NoGauss>::Array TArrayNoGauss;
404 typedef typename MEDMEM_ArrayInterface<T,FullInterlace,Gauss>::Array TArrayGauss;
405 FIELD< T, FullInterlace > * f = 0;
406 TArrayNoGauss * arrayNoGauss = 0;
407 TArrayGauss * arrayGauss = 0;
409 // loop on subs of this field
411 for ( sub_data = _sub.begin(); sub_data != sub_end; ++sub_data, ++i_sub )
413 // nb values in a field
414 if ( !hasCommonSupport() ) {
415 grp = & groupes[ sub_data->_supp_id ];
416 medGrp = grp->medGroup;
418 int nb_val = grp->size();
420 // check validity of a sub_data
421 bool validSub = true;
423 INFOS_MED("Skip field <" << _name << ">: invalid supporting group "
424 << (hasCommonSupport() ? _group_id : sub_data->_supp_id )
425 << " of " << i_sub << "-th subcomponent" );
428 if ( !sub_data->isValidNbGauss() ) {
429 INFOS_MED("Skip field <" << _name << ">: different nb of gauss points in components ");
433 if ( hasCommonSupport() ) {
434 if ( !res.empty() ) {
440 i_comp_tot += sub_data->nbComponents();
446 if ( !f || !hasCommonSupport() || !supp_id_set.insert( sub_data->_supp_id ).second )
453 f = new FIELD< T, FullInterlace >();
455 f->setNumberOfComponents( sub_data->nbComponents() );
456 f->setComponentsNames( & sub_data->_comp_names[ 0 ] );
457 f->setNumberOfValues ( nb_val );
459 f->setDescription( _description );
460 vector<string> str( sub_data->nbComponents() );
461 f->setComponentsDescriptions( &str[0] );
462 f->setMEDComponentsUnits( &str[0] );
464 res.push_back( make_pair( f , hasCommonSupport() ? _group_id : sub_data->_supp_id ));
465 MESSAGE_MED(" MAKE " << nb_fields << "-th field <" << _name << "> on group_id " << _group_id );
468 if ( !sub_data->hasGauss() ) {
469 arrayNoGauss = new TArrayNoGauss( sub_data->nbComponents(), nb_val );
470 f->setArray( arrayNoGauss );
473 if ( !hasCommonSupport() ) {
475 nbelgeoc [1] = nb_val;
476 nbgaussgeo[1] = sub_data->nbGauss();
478 arrayGauss = new TArrayGauss(sub_data->nbComponents(), nb_val,
479 nbtypegeo, & nbelgeoc[0], & nbgaussgeo[0]);
480 f->setArray( arrayGauss );
482 // PAL11040 "GIBI driver for Castem fields with Gauss point values"
483 const MED_EN::medGeometryElement* types = medGrp->getTypes();
484 for (int iGeom = 0; iGeom < nbtypegeo; ++iGeom) {
486 name << "Gauss_" << nbgaussgeo[iGeom+1] << "points_on" << types[iGeom] << "geom";
487 GAUSS_LOCALIZATION_* loc = GAUSS_LOCALIZATION_::makeDefaultLocalization
488 (name.str(), types[iGeom], nbgaussgeo[iGeom+1]);
489 f->setGaussLocalization( types[iGeom], loc );
496 // get nb elements in a group
497 _groupe & sub_grp = groupes[ sub_data->_supp_id ];
498 int nb_supp_elems = sub_grp.mailles.size();
499 int nb_gauss = sub_data->nbGauss();
500 MESSAGE_MED("insert sub data, group_id: " << sub_data->_supp_id <<
501 ", nb values: " << comp_values[ i_comp_tot ].size() <<
502 ", relocMap size: " << sub_grp.relocMap.size() <<
503 ", nb mailles: " << nb_supp_elems);
505 #ifdef CASTEM_FULL_INTERLACE
506 const int gauss_step = 1;
507 const int elem_step = nb_gauss;
509 const int gauss_step = nb_supp_elems;
510 const int elem_step = 1;
513 // loop on components of a sub
514 for ( int i_comp = 1; i_comp <= sub_data->nbComponents(); ++i_comp )
517 const std::vector< T > & values = comp_values[ i_comp_tot++ ];
518 bool oneValue = ( values.size() == 1 );
519 ASSERT_MED( oneValue || values.size() == nb_supp_elems * nb_gauss );
520 for ( int k = 0; k < nb_supp_elems; ++k )
522 const T& val = oneValue ? values[ 0 ] : values[ k * elem_step ];
523 const _maille& ma = sub_grp.maille( k );
524 if ( medGrp->isOnAllElements() ) {
528 std::map<unsigned,int>::const_iterator ordre_i = grp->relocMap.find( ma.ordre() );
529 if ( ordre_i == grp->relocMap.end() )
530 throw MEDEXCEPTION (LOCALIZED(STRING(LOC) << ", cant find elem index. "
531 << k << "-th elem: " << ma));
534 if ( arrayNoGauss ) {
535 arrayNoGauss->setIJ( i, i_comp, val );
538 const T* pVal = & val;
539 for ( int iGauss = 1; iGauss <= nb_gauss; ++iGauss, pVal += gauss_step )
540 arrayGauss->setIJK( i, i_comp, iGauss, *pVal);
544 } // loop on subs of the field
550 // ==============================================================================
551 template <class T> void _field< T >::dump(std::ostream& os) const
552 // ==============================================================================
554 _fieldBase::dump(os);
556 for ( int i = 0 ; i < (int)comp_values.size(); ++i )
558 os << " " << i+1 << "-th component, nb values: " << comp_values[ i ].size() << endl;
562 } // namespace MEDMEM
564 #endif /* DRIVERTOOLS_HXX */