]> SALOME platform Git repositories - modules/med.git/blob - src/MEDMEM/MEDMEM_DriverTools.hxx
Salome HOME
Merge from BR_V5_DEV 16Feb09
[modules/med.git] / src / MEDMEM / MEDMEM_DriverTools.hxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 #ifndef DRIVERTOOLS_HXX
23 #define DRIVERTOOLS_HXX
24
25 #include <MEDMEM.hxx>
26
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"
33
34 #include <string>
35 #include <vector>
36 #include <set>
37 #include <list>
38 #include <map>
39 #include <iostream>
40 #include <iomanip>
41 #include <algorithm>
42
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
47
48
49 namespace MEDMEM {
50 class MESH;
51 class CONNECTIVITY;
52 class COORDINATE;
53 class GROUP;
54 class FAMILY;
55 class FIELD_;
56 class _intermediateMED;
57
58 // ==============================================================================
59 struct MEDMEM_EXPORT _noeud
60 {
61   mutable int number; // negative if node is merged
62   std::vector<double> coord;
63 };
64
65 // ==============================================================================
66 typedef pair<int,int> _link; // a pair of node numbers
67
68 // ==============================================================================
69 struct MEDMEM_EXPORT _maille
70 {
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
77
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); }
80
81   _maille(const _maille& ma);
82   void init() const { if ( sortedNodeIDs ) delete [] sortedNodeIDs; sortedNodeIDs = 0; }
83   ~_maille() { init(); }
84
85   int dimension() const // retourne la dimension de la maille
86   { return geometricType/100; }
87
88   int dimensionWithPoly() const // retourne la dimension de la maille
89   { return geometricType >= MED_EN::MED_POLYGON ? dimension()-2 : dimension(); }
90
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;
95
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
99
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; }
104
105 private:
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);
108 };
109
110 // ==============================================================================
111 struct MEDMEM_EXPORT _mailleIteratorCompare // pour ordonner le set d'iterateurs sur mailles
112 {
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)
117   {
118     //return *i1<*i2;
119     return i1->ordre() < i2->ordre();
120   }
121 };
122
123 // ==============================================================================
124 struct MEDMEM_EXPORT _groupe
125 {
126   typedef std::set<_maille>::iterator            TMaille;
127   typedef std::vector< TMaille >::const_iterator TMailleIter;
128   std::string            nom;
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()
132   GROUP*                 medGroup;
133
134   const _maille& maille(int index) { return *mailles[index]; }
135   bool empty() const { return mailles.empty() && groupes.empty(); }
136 #ifdef WNT
137   int  size()  const { return (mailles.size()>relocMap.size())?mailles.size():relocMap.size(); }
138 #else
139   int  size()  const { return std::max( mailles.size(), relocMap.size() ); }
140 #endif
141   _groupe():medGroup(0) {}
142 };
143
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   // --------------------------------
151   {
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
155
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() ); }
162 #ifdef WNT
163     int nbGauss() const { return (1>_nb_gauss[0])?1:_nb_gauss[0]; }
164 #else
165     int nbGauss() const { return std::max( 1, _nb_gauss[0] ); }
166 #endif
167     bool hasGauss() const { return nbGauss() > 1; }
168   };
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;
176   std::string              _name;
177   std::string              _description;// field description
178
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() {}
187 };
188
189 // ==============================================================================
190 template< class T > class _field: public _fieldBase
191 {
192   std::vector< std::vector< T > > comp_values;
193  public:
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;
199 };
200
201 // ==============================================================================
202 /*!
203  * \if developper
204  * Iterator on set of _maille's of given dimension
205  * \endif
206  */
207 class MEDMEM_EXPORT _maillageByDimIterator
208 {
209 public:
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 ); }
215
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 );
219
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;
225       else
226         ++myIt;
227     return 0;
228   }
229   //!< return dimension of mailles returned by the last or further next()
230   int dim(const bool last=true) const {
231     iterator it = myIt;
232     if ( last ) --it;
233     return myConvertPoly ?
234       it->second.begin()->dimensionWithPoly() :
235       it->second.begin()->dimension();
236   }
237   //!< return type of mailles returned by the last next()
238   MED_EN::medGeometryElement type() const { iterator it = myIt; return (--it)->first; }
239
240   //!< return number of mailles taking into account merged ones
241   int sizeWithoutMerged() const {
242     iterator it = myIt;
243     removed::const_iterator tNb = nbRemovedByType->find( (--it)->first );
244     return it->second.size() - ( tNb == nbRemovedByType->end() ? 0 : tNb->second );
245   }
246 private:
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;
250
251   const _intermediateMED* myImed;
252   iterator myIt, myEnd;
253   int myDim, myConvertPoly;
254   const removed * nbRemovedByType;
255 };
256
257 // ==============================================================================
258 /*!
259  * \if developper
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.
266  * \endif
267  */
268 struct MEDMEM_EXPORT _intermediateMED
269 {
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;
273
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
281
282   inline _groupe::TMaille insert(const _maille& ma);
283
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,
290 //                    MESH * _ptrMesh);
291   void getGroups(std::vector<GROUP *> & _groupCell, std::vector<GROUP *> & _groupFace, 
292                  std::vector<GROUP *> & _groupEdge, std::vector<GROUP *> & _groupNode,
293                  MESH * _ptrMesh);
294   //GROUP * getGroup( int i );
295
296   void getFields(std::list< FIELD_* >& fields);
297
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
304
305   _intermediateMED()
306   { myNodesNumerated = myMaillesNumerated = myGroupsTreated = false; currentTypeMailles = 0; }
307   ~_intermediateMED();
308
309 private:
310
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;
318 };
319 //-----------------------------------------------------------------------
320 _groupe::TMaille _intermediateMED::insert(const _maille& ma)
321 {
322   if ( !currentTypeMailles || currentTypeMailles->first != ma.geometricType )
323     currentTypeMailles = & *maillageByType.insert
324       ( make_pair( ma.geometricType, std::set<_maille >())).first;
325
326   _groupe::TMaille res = currentTypeMailles->second.insert( ma ).first;
327
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
330
331   return res;
332 }
333
334 // ==============================================================================
335
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* );
341
342 // ===========================================================
343 //                 field template implementation           //
344 // ===========================================================
345
346 template <class T>
347   std::vector< T >& _field< T >::addComponent( int nb_values )
348 {
349   comp_values.push_back( std::vector< T >() );
350   std::vector< T >& res = comp_values.back();
351   res.resize( nb_values );
352   return res;
353 }
354
355 //=======================================================================
356 //function : getField
357 //purpose  : return list of pairs< field, supporting_group_id >
358 //=======================================================================
359
360 template <class T>
361 std::list<std::pair< FIELD_*, int> > _field< T >::getField(std::vector<_groupe> & groupes) const
362 {
363   const char* LOC = "_field< T >::getField()";
364
365   std::list<std::pair< FIELD_*, int> > res;
366
367   // gauss array data
368   int nbtypegeo = 0;
369   vector<int> nbelgeoc(2,0), nbgaussgeo(2,0);
370
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(); 
374
375   _groupe*  grp = 0;
376   GROUP* medGrp = 0;
377   if ( hasCommonSupport() ) // several subs are combined into one field
378   {
379     grp    = & groupes[ _group_id ];
380     medGrp = grp->medGroup;
381     if ( !grp || grp->empty() || !medGrp || !medGrp->getNumberOfTypes())
382       return res;
383
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) {
391       // nb elem by type
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 ])
397           break;
398       }
399       ASSERT_MED( sub_data != sub_end );
400       nbgaussgeo[ iType+1 ] = sub_data->nbGauss();
401     }
402   }
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;
408
409   // loop on subs of this field
410   int i_sub = 1;
411   for ( sub_data = _sub.begin(); sub_data != sub_end; ++sub_data, ++i_sub )
412   {
413     // nb values in a field
414     if ( !hasCommonSupport() ) {
415       grp    = & groupes[ sub_data->_supp_id ];
416       medGrp = grp->medGroup;
417     }
418     int nb_val = grp->size();
419
420     // check validity of a sub_data
421     bool validSub = true;
422     if ( !nb_val ) {
423       INFOS_MED("Skip field <" << _name << ">: invalid supporting group "
424             << (hasCommonSupport() ? _group_id : sub_data->_supp_id )
425             << " of " << i_sub << "-th subcomponent" );
426       validSub = false;
427     }
428     if ( !sub_data->isValidNbGauss() ) {
429       INFOS_MED("Skip field <" << _name << ">: different nb of gauss points in components ");
430       validSub = false;
431     }
432     if ( !validSub ) {
433       if ( hasCommonSupport() ) {
434         if ( !res.empty() ) {
435           delete f;
436           res.clear();
437         }
438         return res;
439       }
440       i_comp_tot += sub_data->nbComponents();
441       continue;
442     }
443
444     // Create a field
445
446     if ( !f || !hasCommonSupport() || !supp_id_set.insert( sub_data->_supp_id ).second )
447     {
448       ++nb_fields;
449       supp_id_set.clear();
450       arrayNoGauss = 0;
451       arrayGauss = 0;
452
453       f = new FIELD< T, FullInterlace >();
454
455       f->setNumberOfComponents( sub_data->nbComponents() );
456       f->setComponentsNames( & sub_data->_comp_names[ 0 ] );
457       f->setNumberOfValues ( nb_val );
458       f->setName( _name );
459       f->setDescription( _description );
460       vector<string> str( sub_data->nbComponents() );
461       f->setComponentsDescriptions( &str[0] );
462       f->setMEDComponentsUnits( &str[0] );
463
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 );
466
467       // make an array
468       if ( !sub_data->hasGauss() ) {
469         arrayNoGauss = new TArrayNoGauss( sub_data->nbComponents(), nb_val );
470         f->setArray( arrayNoGauss );
471       }
472       else {
473         if ( !hasCommonSupport() ) {
474           nbtypegeo = 1;
475           nbelgeoc  [1] = nb_val;
476           nbgaussgeo[1] = sub_data->nbGauss();
477         }
478         arrayGauss = new TArrayGauss(sub_data->nbComponents(), nb_val,
479                                      nbtypegeo, & nbelgeoc[0], & nbgaussgeo[0]);
480         f->setArray( arrayGauss );
481
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) {
485           ostringstream name;
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 );
490         }
491       }
492     }
493
494     // Set values
495     
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);
504
505 #ifdef CASTEM_FULL_INTERLACE
506     const int gauss_step = 1;
507     const int elem_step = nb_gauss;
508 #else
509     const int gauss_step = nb_supp_elems;
510     const int elem_step = 1;
511 #endif
512     int i; // elem index
513     // loop on components of a sub
514     for ( int i_comp = 1; i_comp <= sub_data->nbComponents(); ++i_comp )
515     {
516       // store values
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 )
521       {
522         const T& val = oneValue ? values[ 0 ] : values[ k * elem_step ];
523         const _maille& ma = sub_grp.maille( k );
524         if ( medGrp->isOnAllElements() ) {
525           i = ma.ordre();
526         }
527         else {
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));
532           i = ordre_i->second;
533         }
534         if ( arrayNoGauss ) {
535           arrayNoGauss->setIJ( i, i_comp, val );
536         }
537         else {
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);
541         }
542       }
543     }
544   } // loop on subs of the field
545
546   return res;
547 }
548
549
550 // ==============================================================================
551 template <class T> void _field< T >::dump(std::ostream& os) const
552 // ==============================================================================
553 {
554   _fieldBase::dump(os);
555   os << endl;
556   for ( int i = 0 ; i < (int)comp_values.size(); ++i )
557   {
558     os << "    " << i+1 << "-th component, nb values: " << comp_values[ i ].size() << endl;
559   }
560 }
561
562 } // namespace MEDMEM
563
564 #endif /* DRIVERTOOLS_HXX */