Salome HOME
Fix clang compilation (template instanciations) + clang warnings
[tools/medcoupling.git] / src / MEDLoader / MEDFileMesh.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (CEA/DEN)
20
21 #include "MEDFileMesh.hxx"
22 #include "MEDFileFieldOverView.hxx"
23 #include "MEDFileField.hxx"
24 #include "MEDLoader.hxx"
25 #include "MEDLoaderNS.hxx"
26 #include "MEDFileSafeCaller.txx"
27 #include "MEDLoaderBase.hxx"
28
29 #include "MEDCouplingUMesh.hxx"
30 #include "MEDCouplingMappedExtrudedMesh.hxx"
31 #include "MEDCouplingMemArray.txx"
32
33 #include "InterpKernelAutoPtr.hxx"
34
35 #include <limits>
36 #include <cmath>
37
38 // From MEDLOader.cxx TU
39 extern med_geometry_type                 typmai[MED_N_CELL_FIXED_GEO];
40 extern INTERP_KERNEL::NormalizedCellType typmai2[MED_N_CELL_FIXED_GEO];
41 extern med_geometry_type typmai3[INTERP_KERNEL::NORM_MAXTYPE];
42
43 using namespace MEDCoupling;
44
45 const char MEDFileMesh::DFT_FAM_NAME[]="FAMILLE_ZERO";
46
47 const char MEDFileUMesh::SPE_FAM_STR_EXTRUDED_MESH[]="HIDDEN_FAM_EXT_MESH@";
48
49 MEDFileMesh::MEDFileMesh():_order(-1),_iteration(-1),_time(0.),_univ_wr_status(true),_axis_type(AX_CART)
50 {
51 }
52
53 std::size_t MEDFileMesh::getHeapMemorySizeWithoutChildren() const
54 {
55   std::size_t ret(_dt_unit.capacity()+_name.capacity()+_univ_name.capacity()+_desc_name.capacity());
56   for(std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.begin();it!=_groups.end();it++)
57     {
58       ret+=(*it).first.capacity()+(*it).second.capacity()*sizeof(std::string);
59       for(std::vector<std::string>::const_iterator it2=(*it).second.begin();it2!=(*it).second.end();it2++)
60         ret+=(*it2).capacity();
61     }
62   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
63     ret+=(*it).first.capacity()+sizeof(mcIdType);
64   return ret;
65 }
66
67 std::vector<const BigMemoryObject *> MEDFileMesh::getDirectChildrenWithNull() const
68 {
69   std::vector<const BigMemoryObject *> ret(1);
70   ret[0]=(const MEDFileEquivalences *)_equiv;
71   return ret;
72 }
73
74 /*!
75  * Returns a new MEDFileMesh holding the mesh data that has been read from a given MED
76  * file. The first mesh in the file is loaded.
77  *  \param [in] fileName - the name of MED file to read.
78  *  \return MEDFileMesh * - a new instance of MEDFileMesh. The caller is to delete this
79  *          mesh using decrRef() as it is no more needed. 
80  *  \throw If the file is not readable.
81  *  \throw If there is no meshes in the file.
82  *  \throw If the mesh in the file is of a not supported type.
83  */
84 MEDFileMesh *MEDFileMesh::New(const std::string& fileName, MEDFileMeshReadSelector *mrs)
85 {
86   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
87   return New(fid,mrs);
88 }
89
90 MEDFileMesh *MEDFileMesh::New(med_idt fid, MEDFileMeshReadSelector *mrs)
91 {
92   std::vector<std::string> ms(MEDLoaderNS::getMeshNamesFid(fid));
93   if(ms.empty())
94     {
95       std::ostringstream oss; oss << "MEDFileMesh::New : no meshes in file \"" << FileNameFromFID(fid) << "\" !";
96       throw INTERP_KERNEL::Exception(oss.str().c_str());
97     }
98   MEDCoupling::MEDCouplingMeshType meshType;
99   int dt,it;
100   std::string dummy2;
101   MEDCoupling::MEDCouplingAxisType dummy3;
102   MEDFileMeshL2::GetMeshIdFromName(fid,ms.front(),meshType,dummy3,dt,it,dummy2);
103   MCAuto<MEDFileMesh> ret;
104   switch(meshType)
105   {
106     case UNSTRUCTURED:
107       {
108         ret=MEDFileUMesh::New();
109         break;
110       }
111     case CARTESIAN:
112       {
113         ret=MEDFileCMesh::New();
114         break;
115       }
116     case CURVE_LINEAR:
117       {
118         ret=MEDFileCurveLinearMesh::New();
119         break;
120       }
121     default:
122       {
123         std::ostringstream oss; oss << "MEDFileMesh::New : MED file exists and has mesh '" << ms.front() << "' exists but unsupported type yet !";
124         throw INTERP_KERNEL::Exception(oss.str().c_str());
125       }
126   }
127   ret->loadLLWithAdditionalItems(fid,ms.front(),dt,it,mrs);
128   return ret.retn();
129 }
130
131 /*!
132  * Returns a new MEDFileMesh holding the mesh data that has been read from a given MED
133  * file. The mesh to load is specified by its name and numbers of a time step and an
134  * iteration.
135  *  \param [in] fileName - the name of MED file to read.
136  *  \param [in] mName - the name of the mesh to read.
137  *  \param [in] dt - the number of a time step.
138  *  \param [in] it - the number of an iteration.
139  *  \param [in] joints - the sub-domain joints to use instead of those that can be read
140  *          from the MED file. Usually this joints are those just read by another iteration
141  *          of mName mesh, when this method is called by MEDFileMeshMultiTS::New()
142  *  \return MEDFileMesh * - a new instance of MEDFileMesh. The caller is to delete this
143  *          mesh using decrRef() as it is no more needed. 
144  *  \throw If the file is not readable.
145  *  \throw If there is no mesh with given attributes in the file.
146  *  \throw If the mesh in the file is of a not supported type.
147  */
148 MEDFileMesh *MEDFileMesh::New(const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs, MEDFileJoints* joints)
149 {
150   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
151   return New(fid,mName,dt,it,mrs,joints);
152 }
153
154 MEDFileMesh *MEDFileMesh::New(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs, MEDFileJoints* joints)
155 {
156   MEDCoupling::MEDCouplingMeshType meshType;
157   int dummy0,dummy1;
158   std::string dummy2;
159   MEDCoupling::MEDCouplingAxisType dummy3;
160   MEDFileMeshL2::GetMeshIdFromName(fid,mName,meshType,dummy3,dummy0,dummy1,dummy2);
161   MCAuto<MEDFileMesh> ret;
162   switch(meshType)
163   {
164     case UNSTRUCTURED:
165       {
166         ret=MEDFileUMesh::New();
167         break;
168       }
169     case CARTESIAN:
170       {
171         ret=MEDFileCMesh::New();
172         break;
173       }
174     case CURVE_LINEAR:
175       {
176         ret=MEDFileCurveLinearMesh::New();
177         break;
178       }
179     default:
180       {
181         std::ostringstream oss; oss << "MEDFileMesh::New : MED file exists and has mesh '" << mName << "' exists but unsupported type yet !";
182         throw INTERP_KERNEL::Exception(oss.str().c_str());
183       }
184   }
185   ret->loadLLWithAdditionalItems(fid,mName,dt,it,mrs);
186   return ret.retn();
187 }
188
189 /*!
190  * Writes \a this mesh into an open MED file specified by its descriptor.
191  *  \param [in] fid - the MED file descriptor.
192  *  \throw If the mesh name is not set.
193  *  \throw If the file is open for reading only.
194  *  \throw If the writing mode == 1 and the same data is present in an existing file.
195  */
196 void MEDFileMesh::writeLL(med_idt fid) const
197 {
198   if(!existsFamily(0))
199     const_cast<MEDFileMesh *>(this)->addFamily(DFT_FAM_NAME,0);
200   if(_name.empty())
201     throw INTERP_KERNEL::Exception("MEDFileMesh : name is empty. MED file ask for a NON EMPTY name !");
202   writeMeshLL(fid);
203   writeJoints(fid);
204   const MEDFileEquivalences *eqs(_equiv);
205   if(eqs)
206     eqs->writeLL(fid);
207 }
208
209 /*!
210  * Checks if \a this and another mesh are equal.
211  *  \param [in] other - the mesh to compare with.
212  *  \param [in] eps - a precision used to compare real values.
213  *  \param [in,out] what - the string returning description of unequal data.
214  *  \return bool - \c true if the meshes are equal, \c false, else.
215  */
216 bool MEDFileMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const
217 {
218   if(_order!=other->_order)
219     {
220       what="Orders differ !";
221       return false;
222     }
223   if(_iteration!=other->_iteration)
224     {
225       what="Iterations differ !";
226       return false;
227     }
228   if(fabs(_time-other->_time)>eps)
229     {
230       what="Time values differ !";
231       return false;
232     }
233   if(_dt_unit!=other->_dt_unit)
234     {
235       what="Time units differ !";
236       return false;
237     }
238   if(_name!=other->_name)
239     {
240       what="Names differ !";
241       return false;
242     }
243   //univ_name has been ignored -> not a bug because it is a mutable attribute
244   if(_desc_name!=other->_desc_name)
245     {
246       what="Description names differ !";
247       return false;
248     }
249   if(!areGrpsEqual(other,what))
250     return false;
251   if(!areFamsEqual(other,what))
252     return false;
253   if(!areEquivalencesEqual(other,what))
254     return false;
255   return true;
256 }
257
258 void MEDFileMesh::setName(const std::string& name)
259 {
260   _name=name;
261 }
262
263 /*!
264  * Clears redundant attributes of incorporated data arrays.
265  */
266 void MEDFileMesh::clearNonDiscrAttributes() const
267 {
268
269 }
270
271 bool MEDFileMesh::changeNames(const std::vector< std::pair<std::string,std::string> >& modifTab)
272 {
273   for(std::vector< std::pair<std::string,std::string> >::const_iterator it=modifTab.begin();it!=modifTab.end();it++)
274     {
275       if((*it).first==_name)
276         {
277           _name=(*it).second;
278           return true;
279         }
280     }
281   return false;
282 }
283
284 /*!
285  * Copies data on groups and families from another mesh.
286  *  \param [in] other - the mesh to copy the data from.
287  */
288 void MEDFileMesh::copyFamGrpMapsFrom(const MEDFileMesh& other)
289 {
290   _groups=other._groups;
291   _families=other._families;
292 }
293
294
295 /*!
296  * This method clear all the groups in the map.
297  * So this method does not operate at all on arrays.
298  * So this method can lead to orphan families.
299  * 
300  * \sa MEDFileMesh::clearFamMap, MEDFileMesh::clearFamGrpMaps
301  */
302 void MEDFileMesh::clearGrpMap()
303 {
304   _groups.clear();
305 }
306
307 /*!
308  * This method clear all the families in the map.
309  * So this method does not operate at all on arrays.
310  * WARNING ! if there are some groups lying on cleared families, those groups will be impacted !
311  *
312  * \sa MEDFileMesh::clearFamMap, MEDFileMesh::clearFamGrpMaps
313  */
314 void MEDFileMesh::clearFamMap()
315 {
316   _families.clear();
317 }
318
319 /*!
320  * This method clear all the families and groups in the map.
321  * So this method does not operate at all on arrays.
322  * As all groups and families entry will be removed after 
323  * the call of MEDFileMesh::setFamilyFieldArr method with 0 or None (python) in the 2nd parameter can be useful to reduce the size of the object.
324  *
325  * \sa MEDFileMesh::clearFamMap, MEDFileMesh::clearFamMap
326  */
327 void MEDFileMesh::clearFamGrpMaps()
328 {
329   clearGrpMap();
330   clearFamMap();
331 }
332
333 /*!
334  * Returns names of families constituting a group.
335  *  \param [in] name - the name of the group of interest.
336  *  \return std::vector<std::string> - a sequence of names of the families.
337  *  \throw If the name of a nonexistent group is specified.
338  */
339 std::vector<std::string> MEDFileMesh::getFamiliesOnGroup(const std::string& name) const
340 {
341   std::string oname(name);
342   std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.find(oname);
343   if(it==_groups.end())
344     {
345       std::vector<std::string> grps=getGroupsNames();
346       std::ostringstream oss; oss << "No such groupname \"" << name << "\" !\nAvailable groups are :";
347       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
348       throw INTERP_KERNEL::Exception(oss.str().c_str());
349     }
350   return (*it).second;
351 }
352
353 /*!
354  * Returns names of families constituting some groups.
355  *  \param [in] grps - a sequence of names of groups of interest.
356  *  \return std::vector<std::string> - a sequence of names of the families.
357  *  \throw If a name of a nonexistent group is present in \a grps.
358  */
359 std::vector<std::string> MEDFileMesh::getFamiliesOnGroups(const std::vector<std::string>& grps) const
360 {
361   std::set<std::string> fams;
362   for(std::vector<std::string>::const_iterator it=grps.begin();it!=grps.end();it++)
363     {
364       std::map<std::string, std::vector<std::string> >::const_iterator it2=_groups.find(*it);
365       if(it2==_groups.end())
366         {
367           std::ostringstream oss; oss << "No such group in mesh \"" << _name << "\" : " << *it; 
368           std::vector<std::string> grps2=getGroupsNames(); oss << "\" !\nAvailable groups are :";
369           std::copy(grps2.begin(),grps2.end(),std::ostream_iterator<std::string>(oss," "));
370           throw INTERP_KERNEL::Exception(oss.str().c_str());
371         }
372       fams.insert((*it2).second.begin(),(*it2).second.end());
373     }
374   std::vector<std::string> fams2(fams.begin(),fams.end());
375   return fams2;
376 }
377
378 /*!
379  * Returns ids of families constituting a group.
380  *  \param [in] name - the name of the group of interest.
381  *  \return std::vector<int> - sequence of ids of the families.
382  *  \throw If the name of a nonexistent group is specified.
383  */
384 std::vector<mcIdType> MEDFileMesh::getFamiliesIdsOnGroup(const std::string& name) const
385 {
386   std::string oname(name);
387   std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.find(oname);
388   std::vector<std::string> grps=getGroupsNames();
389   if(it==_groups.end())
390     {
391       std::ostringstream oss; oss << "No such groupname \"" << name << "\" !\nAvailable groups are :";
392       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
393       throw INTERP_KERNEL::Exception(oss.str().c_str());
394     }
395   return getFamiliesIds((*it).second);
396 }
397
398 /*!
399  * Sets names of families constituting a group. If data on families of this group is
400  * already present, it is overwritten. Every family in \a fams is checked, and if a
401  family is not yet in \a this mesh, the default group id \c 0 is assigned to it.
402  *  \param [in] name - the name of the group of interest.
403  *  \param [in] fams - a sequence of names of families constituting the group.
404  */
405 void MEDFileMesh::setFamiliesOnGroup(const std::string& name, const std::vector<std::string>& fams)
406 {
407   std::string oname(name);
408   _groups[oname]=fams;
409   for(std::vector<std::string>::const_iterator it1=fams.begin();it1!=fams.end();it1++)
410     {
411       std::map<std::string,mcIdType>::iterator it2=_families.find(*it1);
412       if(it2==_families.end())
413         _families[*it1]=0;
414     }
415 }
416
417 /*!
418  * Sets families constituting a group. The families are specified by their ids.
419  * If a family name is not found by its id, an exception is thrown.
420  * If several families have same id, the first one in lexical order is taken.
421  *  \param [in] name - the name of the group of interest.
422  *  \param [in] famIds - a sequence of ids of families constituting the group.
423  *  \throw If a family name is not found by its id.
424  */
425 void MEDFileMesh::setFamiliesIdsOnGroup(const std::string& name, const std::vector<mcIdType>& famIds)
426 {
427   std::string oname(name);
428   std::vector<std::string> fams(famIds.size());
429   int i=0;
430   for(std::vector<mcIdType>::const_iterator it1=famIds.begin();it1!=famIds.end();it1++,i++)
431     {
432       std::string name2=getFamilyNameGivenId(*it1);
433       fams[i]=name2;
434     }
435   _groups[oname]=fams;
436 }
437
438 /*!
439  * Returns names of groups including a given family.
440  *  \param [in] name - the name of the family of interest.
441  *  \return std::vector<std::string> - a sequence of names of groups including the family.
442  */
443 std::vector<std::string> MEDFileMesh::getGroupsOnFamily(const std::string& name) const
444 {
445   std::vector<std::string> ret;
446   for(std::map<std::string, std::vector<std::string> >::const_iterator it1=_groups.begin();it1!=_groups.end();it1++)
447     {
448       for(std::vector<std::string>::const_iterator it2=(*it1).second.begin();it2!=(*it1).second.end();it2++)
449         if((*it2)==name)
450           {
451             ret.push_back((*it1).first);
452             break;
453           }
454     }
455   return ret;
456 }
457
458 /*!
459  * Adds an existing family to groups.
460  *  \param [in] famName - a name of family to add to \a grps.
461  *  \param [in] grps - a sequence of group names to add the family in.
462  *  \throw If a family named \a famName not yet exists.
463  */
464 void MEDFileMesh::setGroupsOnFamily(const std::string& famName, const std::vector<std::string>& grps)
465 {
466   std::string fName(famName);
467   const std::map<std::string,mcIdType>::const_iterator it=_families.find(fName);
468   if(it==_families.end())
469     {
470       std::vector<std::string> fams=getFamiliesNames();
471       std::ostringstream oss; oss << "No such familyname \"" << fName << "\" !\nAvailable families are :";
472       std::copy(fams.begin(),fams.end(),std::ostream_iterator<std::string>(oss," "));
473       throw INTERP_KERNEL::Exception(oss.str().c_str());
474     }
475   for(std::vector<std::string>::const_iterator it3=grps.begin();it3!=grps.end();it3++)
476     {
477       std::map< std::string, std::vector<std::string> >::iterator it2=_groups.find(*it3);
478       if(it2!=_groups.end())
479         (*it2).second.push_back(fName);
480       else
481         {
482           std::vector<std::string> grps2(1,fName);
483           _groups[*it3]=grps2;
484         }
485     }
486 }
487
488 /*!
489  * Returns names of all groups of \a this mesh.
490  *  \return std::vector<std::string> - a sequence of group names.
491  */
492 std::vector<std::string> MEDFileMesh::getGroupsNames() const
493 {
494   std::vector<std::string> ret(_groups.size());
495   int i=0;
496   for(std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.begin();it!=_groups.end();it++,i++)
497     ret[i]=(*it).first;
498   return ret;
499 }
500
501 /*!
502  * Returns names of all families of \a this mesh.
503  *  \return std::vector<std::string> - a sequence of family names.
504  */
505 std::vector<std::string> MEDFileMesh::getFamiliesNames() const
506 {
507   std::vector<std::string> ret(_families.size());
508   int i=0;
509   for(std::map<std::string, mcIdType >::const_iterator it=_families.begin();it!=_families.end();it++,i++)
510     ret[i]=(*it).first;
511   return ret;
512 }
513
514 /*!
515  * Returns names of all families of \a this mesh but like they would be in file.
516  * This method is here only for MED file families gurus. If you are a kind user forget this method :-)
517  * This method is only useful for aggressive users that want to have in their file a same family lying both on cells and on nodes. This is not a good idea for lisibility !
518  * For your information internally in memory such families are renamed to have a nicer API.
519  */
520 std::vector<std::string> MEDFileMesh::getFamiliesNamesWithFilePointOfView() const
521 {
522   std::vector<std::string> ret(getFamiliesNames());
523   MEDFileMeshL2::RenameFamiliesFromMemToFile(ret);
524   return ret;
525 }
526
527 /*!
528  * Returns names of groups that partly or fully appear on the level \a meshDimRelToMaxExt.
529  *  \param [in] meshDimRelToMaxExt - a relative dimension of interest.
530  *  \return std::vector<std::string> - a sequence of group names at \a meshDimRelToMaxExt
531  *          level. 
532  */
533 std::vector<std::string> MEDFileMesh::getGroupsOnSpecifiedLev(int meshDimRelToMaxExt) const
534 {
535   std::vector<std::string> ret;
536   std::vector<std::string> allGrps(getGroupsNames());
537   for(std::vector<std::string>::const_iterator it=allGrps.begin();it!=allGrps.end();it++)
538     {
539       std::vector<mcIdType> levs(getGrpNonEmptyLevelsExt((*it)));
540       if(std::find(levs.begin(),levs.end(),meshDimRelToMaxExt)!=levs.end())
541         ret.push_back(*it);
542     }
543   return ret;
544 }
545
546 /*!
547  * Returns all relative mesh levels (including nodes) where a given group is defined.
548  *  \param [in] grp - the name of the group of interest.
549  *  \return std::vector<mcIdType> - a sequence of the relative dimensions.
550  */
551 std::vector<mcIdType> MEDFileMesh::getGrpNonEmptyLevelsExt(const std::string& grp) const
552 {
553   std::vector<std::string> fams(getFamiliesOnGroup(grp));
554   return getFamsNonEmptyLevelsExt(fams);
555 }
556
557 /*!
558  * Returns all relative mesh levels (**excluding nodes**) where given groups are defined.
559  * To include nodes, call getGrpsNonEmptyLevelsExt() method.
560  *  \param [in] grps - a sequence of names of the groups of interest.
561  *  \return std::vector<mcIdType> - a sequence of the relative dimensions.
562  */
563 std::vector<mcIdType> MEDFileMesh::getGrpsNonEmptyLevels(const std::vector<std::string>& grps) const
564 {
565   std::vector<std::string> fams(getFamiliesOnGroups(grps));
566   return getFamsNonEmptyLevels(fams);
567 }
568
569 /*!
570  * Returns all relative mesh levels (including nodes) where given groups are defined.
571  *  \param [in] grps - a sequence of names of the groups of interest.
572  *  \return std::vector<mcIdType> - a sequence of the relative dimensions.
573  */
574 std::vector<mcIdType> MEDFileMesh::getGrpsNonEmptyLevelsExt(const std::vector<std::string>& grps) const
575 {
576   std::vector<std::string> fams(getFamiliesOnGroups(grps));
577   return getFamsNonEmptyLevelsExt(fams);
578 }
579
580 /*!
581  * Returns all relative mesh levels (**excluding nodes**) where a given group is defined.
582  * To include nodes, call getGrpNonEmptyLevelsExt() method.
583  *  \param [in] grp - the name of the group of interest.
584  *  \return std::vector<mcIdType> - a sequence of the relative dimensions.
585  */
586 std::vector<mcIdType> MEDFileMesh::getGrpNonEmptyLevels(const std::string& grp) const
587 {
588   std::vector<std::string> fams(getFamiliesOnGroup(grp));
589   return getFamsNonEmptyLevels(fams);
590 }
591
592 /*!
593  * Returns all relative mesh levels (**excluding nodes**) where a given family is defined.
594  * To include nodes, call getFamNonEmptyLevelsExt() method.
595  *  \param [in] fam - the name of the family of interest.
596  *  \return std::vector<mcIdType> - a sequence of the relative dimensions.
597  */
598 std::vector<mcIdType> MEDFileMesh::getFamNonEmptyLevels(const std::string& fam) const
599 {
600   std::vector<std::string> fams(1,std::string(fam));
601   return getFamsNonEmptyLevels(fams);
602 }
603
604 /*!
605  * Returns all relative mesh levels (including nodes) where a given family is defined.
606  *  \param [in] fam - the name of the family of interest.
607  *  \return std::vector<mcIdType> - a sequence of the relative dimensions.
608  */
609 std::vector<mcIdType> MEDFileMesh::getFamNonEmptyLevelsExt(const std::string& fam) const
610 {
611   std::vector<std::string> fams(1,std::string(fam));
612   return getFamsNonEmptyLevelsExt(fams);
613 }
614
615 std::string MEDFileMesh::GetMagicFamilyStr()
616 {
617   return std::string(MEDFileMeshL2::ZE_SEP_FOR_FAMILY_KILLERS);
618 }
619
620 /*!
621  * Changes a name of every family, included in one group only, to be same as the group name.
622  *  \throw If there are families with equal names in \a this mesh.
623  */
624 void MEDFileMesh::assignFamilyNameWithGroupName()
625 {
626   std::map<std::string, std::vector<std::string> > groups(_groups);
627   std::map<std::string,mcIdType> newFams;
628   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
629     {
630       std::vector<std::string> grps=getGroupsOnFamily((*it).first);
631       if(grps.size()==1 && groups[grps[0]].size()==1)
632         {
633           if(newFams.find(grps[0])!=newFams.end())
634             {
635               std::ostringstream oss; oss << "MEDFileMesh::assignFamilyNameWithGroupName : Family \"" << grps[0] << "\" already exists !";
636               throw INTERP_KERNEL::Exception(oss.str().c_str());
637             }
638           newFams[grps[0]]=(*it).second;
639           std::vector<std::string>& grps2=groups[grps[0]];
640           std::size_t pos=std::distance(grps2.begin(),std::find(grps2.begin(),grps2.end(),(*it).first));
641           grps2[pos]=grps[0];
642         }
643       else
644         {
645           if(newFams.find((*it).first)!=newFams.end())
646             {
647               std::ostringstream oss; oss << "MEDFileMesh::assignFamilyNameWithGroupName : Family \"" << (*it).first << "\" already exists !";
648               throw INTERP_KERNEL::Exception(oss.str().c_str());
649             }
650           newFams[(*it).first]=(*it).second;
651         }
652     }
653   _families=newFams;
654   _groups=groups;
655 }
656
657 /*!
658  * Removes all groups lying on no family. If there is no empty groups, \a this is let untouched.
659  * 
660  * \return the removed groups.
661  */
662 std::vector<std::string> MEDFileMesh::removeEmptyGroups()
663 {
664   std::vector<std::string> ret;
665   std::map<std::string, std::vector<std::string> > newGrps;
666   for(std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.begin();it!=_groups.end();it++)
667     {
668       if((*it).second.empty())
669         ret.push_back((*it).first);
670       else
671         newGrps[(*it).first]=(*it).second;
672     }
673   if(!ret.empty())
674     _groups=newGrps;
675   return ret;
676 }
677
678 void MEDFileMesh::removeGroupAtLevel(int meshDimRelToMaxExt, const std::string& name)
679 {
680   std::map<std::string, std::vector<std::string> >::iterator it(_groups.find(name));
681   std::vector<std::string> grps(getGroupsNames());
682   if(it==_groups.end())
683     {
684       std::ostringstream oss; oss << "No such groupname \"" << name << "\" !\nAvailable groups are :";
685       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
686       throw INTERP_KERNEL::Exception(oss.str().c_str());
687     }
688   const std::vector<std::string> &famsOnGrp((*it).second);
689   std::vector<mcIdType> famIds(getFamiliesIdsOnGroup(name));
690   const DataArrayIdType *famArr(getFamilyFieldAtLevel(meshDimRelToMaxExt));
691   if(!famArr)
692     return ;
693   MCAuto<DataArrayIdType> vals(famArr->getDifferentValues());
694   MCAuto<DataArrayIdType> famIds2(DataArrayIdType::NewFromStdVector(famIds));
695   MCAuto<DataArrayIdType> idsToKill(famIds2->buildIntersection(vals));
696   if(idsToKill->empty())
697     return ;
698   std::vector<std::string> newFamsOnGrp;
699   for(std::vector<std::string>::const_iterator itt=famsOnGrp.begin();itt!=famsOnGrp.end();itt++)
700     {
701       if(!idsToKill->presenceOfValue(getFamilyId(*itt)))
702          newFamsOnGrp.push_back(*itt);
703     }
704   (*it).second=newFamsOnGrp;
705 }
706
707 /*!
708  * Removes a group from \a this mesh.
709  *  \param [in] name - the name of the group to remove.
710  *  \throw If no group with such a \a name exists.
711  */
712 void MEDFileMesh::removeGroup(const std::string& name)
713 {
714   std::map<std::string, std::vector<std::string> >::iterator it=_groups.find(name);
715   std::vector<std::string> grps(getGroupsNames());
716   if(it==_groups.end())
717     {
718       std::ostringstream oss; oss << "No such groupname \"" << name << "\" !\nAvailable groups are :";
719       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
720       throw INTERP_KERNEL::Exception(oss.str().c_str());
721     }
722   _groups.erase(it);
723 }
724
725 /*!
726  * Removes a family from \a this mesh.
727  *  \param [in] name - the name of the family to remove.
728  *  \throw If no family with such a \a name exists.
729  */
730 void MEDFileMesh::removeFamily(const std::string& name)
731 {
732   std::string oname(name);
733   std::map<std::string, mcIdType >::iterator it=_families.find(oname);
734   std::vector<std::string> fams=getFamiliesNames();
735   if(it==_families.end())
736     {
737       std::ostringstream oss; oss << "No such familyname \"" << name << "\" !\nAvailable families are :";
738       std::copy(fams.begin(),fams.end(),std::ostream_iterator<std::string>(oss," "));
739       throw INTERP_KERNEL::Exception(oss.str().c_str());
740     }
741   _families.erase(it);
742   for(std::map<std::string, std::vector<std::string> >::iterator it3=_groups.begin();it3!=_groups.end();it3++)
743     {
744       std::vector<std::string>& v=(*it3).second;
745       std::vector<std::string>::iterator it4=std::find(v.begin(),v.end(),oname);
746       if(it4!=v.end())
747         v.erase(it4);
748     }
749 }
750
751 /*!
752  * Removes all groups in \a this that are orphan. A group is orphan if this group lies on
753  * a set of families, themselves orphan. A family is said orphan if its id appears nowhere in
754  * family field whatever its level. This method also suppresses the orphan families.
755  * 
756  * \return - The list of removed groups names. 
757  *
758  * \sa MEDFileMesh::removeOrphanFamilies.
759  */
760 std::vector<std::string> MEDFileMesh::removeOrphanGroups()
761 {
762   removeOrphanFamilies();
763   return removeEmptyGroups();
764 }
765
766 /*!
767  * Removes all families in \a this that are orphan. A family is said orphan if its id appears nowhere in
768  * family field whatever its level. Groups are updated in consequence, that is to say all groups lying on orphan family, will see their families list modified.
769  * 
770  * \return - The list of removed families names.
771  * \sa MEDFileMesh::removeOrphanGroups , MEDFileMesh::removeFamiliesReferedByNoGroups
772  */
773 std::vector<std::string> MEDFileMesh::removeOrphanFamilies()
774 {
775   MCAuto<DataArrayIdType> allFamIdsInUse=computeAllFamilyIdsInUse();
776   std::vector<std::string> ret;
777   if(!((DataArrayIdType*)allFamIdsInUse))
778     {
779       ret=getFamiliesNames();
780       _families.clear(); _groups.clear();
781       return ret;
782     }
783   std::map<std::string,mcIdType> famMap;
784   std::map<std::string, std::vector<std::string> > grps(_groups);
785   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
786     {
787       if(allFamIdsInUse->presenceOfValue((*it).second))
788         famMap[(*it).first]=(*it).second;
789       else
790         {
791           ret.push_back((*it).first);
792           std::vector<std::string> grpsOnEraseFam=getGroupsOnFamily((*it).first);
793           for(std::vector<std::string>::const_iterator it2=grpsOnEraseFam.begin();it2!=grpsOnEraseFam.end();it2++)
794             {
795               std::map<std::string, std::vector<std::string> >::iterator it3=grps.find(*it2);//it3!=grps.empty() thanks to copy
796               std::vector<std::string>& famv=(*it3).second;
797               std::vector<std::string>::iterator it4=std::find(famv.begin(),famv.end(),(*it).first);//it4!=famv.end() thanks to copy
798               famv.erase(it4);
799             }
800         }
801     }
802   if(!ret.empty())
803     { _families=famMap; _groups=grps; }
804   return ret;
805 }
806
807 /*!
808  * This method operates only on maps in \a this. The arrays are not considered here. So this method will remove a family (except "FAMILLE_ZERO" family) if no group lies on it whatever
809  * this family is orphan or not.
810  *
811  * \warning this method is different from removeOrphanFamilies that scans family field array to find orphan families.
812  * \sa MEDFileMesh::removeOrphanFamilies
813  */
814 void MEDFileMesh::removeFamiliesReferedByNoGroups()
815 {
816   std::map<std::string,mcIdType> fams;
817   std::set<std::string> sfams;
818   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
819     sfams.insert((*it).first);
820   for(std::map<std::string, std::vector<std::string> >::const_iterator it0=_groups.begin();it0!=_groups.end();it0++)
821     for(std::vector<std::string>::const_iterator it1=(*it0).second.begin();it1!=(*it0).second.end();it1++)
822       sfams.erase(*it1);
823   for(std::set<std::string>::const_iterator it=sfams.begin();it!=sfams.end();it++)
824     if(*it!=DFT_FAM_NAME)
825       _families.erase(*it);
826 }
827
828 /*!
829  * This method has no impact on groups. This method only works on families. This method firstly removes families not referred by any groups in \a this, then all unused entities
830  * are put as belonging to family 0 ("FAMILLE_ZERO"). Finally, all orphanFamilies are killed.
831  * This method raises an exception if "FAMILLE_ZERO" is already belonging to a group.
832  * 
833  * This method also raises an exception if a family belonging to a group has also id 0 (which is not right in MED file format). You should never encounter this case using addGroup method.
834  *
835  * \sa MEDFileMesh::removeOrphanFamilies, MEDFileMesh::zipFamilies
836  */
837 void MEDFileMesh::rearrangeFamilies()
838 {
839   checkOrphanFamilyZero();
840   removeFamiliesReferedByNoGroups();
841   //
842   std::vector<int> levels(getNonEmptyLevelsExt());
843   std::set<mcIdType> idsRefed;
844   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
845     {
846       idsRefed.insert((*it).second);
847       if((*it).second==0)
848         {
849           if(!getGroupsOnFamily((*it).first).empty())
850             {
851               std::ostringstream oss; oss << "MEDFileMesh::rearrangeFamilies : Not orphan family \"" << (*it).first << "\" has id 0 ! This method may alterate groups in this for such a case !";
852               throw INTERP_KERNEL::Exception(oss.str());
853             }
854         }
855     }
856   for(std::vector<int>::const_iterator it=levels.begin();it!=levels.end();it++)
857     {
858       const DataArrayIdType *fams(0);
859       try
860       {
861           fams=getFamilyFieldAtLevel(*it);
862       }
863       catch(INTERP_KERNEL::Exception& ) { }
864       if(!fams)
865         continue;
866       std::vector<bool> v(fams->getNumberOfTuples(),false);
867       for(std::set<mcIdType>::const_iterator pt=idsRefed.begin();pt!=idsRefed.end();pt++)
868         fams->switchOnTupleEqualTo(*pt,v);
869       MCAuto<DataArrayIdType> unfetchedIds(DataArrayIdType::BuildListOfSwitchedOff(v));
870       if(!unfetchedIds->empty())
871         {
872           MCAuto<DataArrayIdType> newFams(fams->deepCopy());
873           newFams->setPartOfValuesSimple3(0,unfetchedIds->begin(),unfetchedIds->end(),0,1,1);
874           setFamilyFieldArr(*it,newFams);
875         }
876     }
877   removeOrphanFamilies();
878 }
879
880 /*!
881  * This method has no impact on existing groups. This method has only impact on families behind the groups.
882  * This method is especially useful for MED file structures having used too much families to define their groups and that need to be merged without modification of their groups.
883  * To zip families, firstly this method first removes families refered by no groups (see MEDFileMesh::removeFamiliesReferedByNoGroups), then this method puts together families lying on a same set of groups. If the set of families having same groups has a length higher than 1, the families are merged into a single family
884  * having the name of the first family appearing in family definition and with the corresponding family ID.
885  */
886 void MEDFileMesh::zipFamilies()
887 {
888   checkOrphanFamilyZero();
889   removeFamiliesReferedByNoGroups();
890   std::map< std::set<std::string> , std::vector<std::string> > setOfFamilies;
891   // firstly, store in setOfFamilies as key the common set of groups, and as value the families having such same set of groups
892   for(auto fam : _families)
893     {
894       std::vector<std::string> grps( this->getGroupsOnFamily( fam.first ) );
895       std::set<std::string> sgrps(grps.begin(),grps.end());
896       setOfFamilies[sgrps].push_back(fam.first);
897     }
898   //
899   std::map<std::string, std::vector<std::string> > newGroups(_groups);
900   std::map<std::string,mcIdType> newFams(_families);
901   std::vector<int> levels(getNonEmptyLevelsExt());
902   std::map<mcIdType, std::vector<mcIdType> > famIdsToSubstitute;
903   // iterate on all different set of groups
904   std::set<std::string> familiesToKill;
905   for(auto setOfCommonGrp : setOfFamilies)
906     {
907       if( setOfCommonGrp.second.size()<=1 )
908         continue;
909       for(auto fam=setOfCommonGrp.second.begin()+1 ; fam != setOfCommonGrp.second.end() ; fam++)
910         familiesToKill.insert(*fam);
911     }
912   // iterate on all different set of groups
913   for(auto setOfCommonGrp : setOfFamilies)
914     {
915       if( setOfCommonGrp.second.size()<=1 )
916         continue;
917       std::string newFamName(setOfCommonGrp.second[0]);
918       auto newFamID(_families[newFamName]);
919       for(auto grpToBeModified : setOfCommonGrp.first)
920         {
921           std::vector<std::string> newFamiliesForCurGrp(1,newFamName);
922           const std::vector<std::string>& familiesOnCurGrp(_groups[grpToBeModified]);
923           const std::vector<std::string>& familiesToZip(setOfCommonGrp.second);
924           std::for_each(familiesToZip.begin(),familiesToZip.end(),[&famIdsToSubstitute,this,newFamID](const std::string& elt) { famIdsToSubstitute[newFamID].push_back(this->getFamilyId(elt)); });
925           // for each family shared by the current group only keep those not sharing setOfCommonGrp.second
926           std::for_each(familiesOnCurGrp.begin(),familiesOnCurGrp.end(),[&familiesToKill,&newFamiliesForCurGrp](const std::string& elt)
927                         { if( familiesToKill.find(elt) == familiesToKill.end() ) { newFamiliesForCurGrp.push_back(elt); } });
928           newGroups[grpToBeModified] = newFamiliesForCurGrp;
929         }
930       for(auto familyToKill = setOfCommonGrp.second.begin()+1 ; familyToKill != setOfCommonGrp.second.end(); ++familyToKill)
931         {
932           newFams.erase( newFams.find(*familyToKill) );
933         }
934       
935     }
936   // apply modifications in datastructure
937   for(auto famIdsSubstSession : famIdsToSubstitute)
938     {
939       for(std::vector<int>::const_iterator it=levels.begin();it!=levels.end();it++)
940         {
941           DataArrayIdType *fams(nullptr);
942           try
943             {
944               fams=getFamilyFieldAtLevel(*it);
945             }
946           catch(INTERP_KERNEL::Exception& ) { }
947           if(!fams)
948             continue;
949           MCAuto<DataArrayIdType> idsToModif(fams->findIdsEqualList(famIdsSubstSession.second.data(),famIdsSubstSession.second.data()+famIdsSubstSession.second.size()));
950           fams->setPartOfValuesSimple3(famIdsSubstSession.first,idsToModif->begin(),idsToModif->end(),0,1,1);
951         }
952     }
953   _groups = newGroups;
954   _families = newFams;
955 }
956
957 /*!
958  * This method only checks that "FAMILLE_ZERO" is orphan (not belonging to a group).
959  */
960 void MEDFileMesh::checkOrphanFamilyZero() const
961 {
962   for(std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.begin();it!=_groups.end();it++)
963     {
964       if(std::find((*it).second.begin(),(*it).second.end(),DFT_FAM_NAME)!=(*it).second.end())
965         {
966           std::ostringstream oss; oss << "MEDFileMesh::rearrangeFamilies : Groups \"" << (*it).first << "\" is lying on family \"" << DFT_FAM_NAME << "\" !";
967           throw INTERP_KERNEL::Exception(oss.str().c_str());
968         }
969     }
970 }
971
972 /*!
973  * Renames a group in \a this mesh.
974  *  \param [in] oldName - a current name of the group to rename.
975  *  \param [in] newName - a new group name.
976  *  \throw If no group named \a oldName exists in \a this mesh.
977  *  \throw If a group named \a newName already exists.
978  */
979 void MEDFileMesh::changeGroupName(const std::string& oldName, const std::string& newName)
980 {
981   std::string oname(oldName);
982   std::map<std::string, std::vector<std::string> >::iterator it=_groups.find(oname);
983   std::vector<std::string> grps=getGroupsNames();
984   if(it==_groups.end())
985     {
986       std::ostringstream oss; oss << "No such groupname \"" << oldName << "\" !\nAvailable groups are :";
987       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
988       throw INTERP_KERNEL::Exception(oss.str().c_str());
989     }
990   std::string nname(newName);
991   std::map<std::string, std::vector<std::string> >::iterator it2=_groups.find(nname);
992   if(it2!=_groups.end())
993     {
994       std::ostringstream oss; oss << "Such groupname \"" << newName << "\" already exists ! Kill it before !";
995       throw INTERP_KERNEL::Exception(oss.str().c_str());
996     }
997   std::vector<std::string> cpy=(*it).second;
998   _groups.erase(it);
999   _groups[newName]=cpy;
1000 }
1001
1002 /*!
1003  * Changes an id of a family in \a this mesh. 
1004  * This method calls changeFamilyIdArr().
1005  *  \param [in] oldId - a current id of the family.
1006  *  \param [in] newId - a new family id.
1007  */
1008 void MEDFileMesh::changeFamilyId(mcIdType oldId, mcIdType newId)
1009 {
1010   changeFamilyIdArr(oldId,newId);
1011   std::map<std::string,mcIdType> fam2;
1012   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1013     {
1014       if((*it).second==oldId)
1015         fam2[(*it).first]=newId;
1016       else
1017         fam2[(*it).first]=(*it).second;
1018     }
1019   _families=fam2;
1020 }
1021
1022 /*!
1023  * Renames a family in \a this mesh.
1024  *  \param [in] oldName - a current name of the family to rename.
1025  *  \param [in] newName - a new family name.
1026  *  \throw If no family named \a oldName exists in \a this mesh.
1027  *  \throw If a family named \a newName already exists.
1028  */
1029 void MEDFileMesh::changeFamilyName(const std::string& oldName, const std::string& newName)
1030 {
1031   std::string oname(oldName);
1032   std::map<std::string, mcIdType >::iterator it=_families.find(oname);
1033   std::vector<std::string> fams=getFamiliesNames();
1034   if(it==_families.end())
1035     {
1036       std::ostringstream oss; oss << "No such familyname \"" << oldName << "\" !\nAvailable families are :";
1037       std::copy(fams.begin(),fams.end(),std::ostream_iterator<std::string>(oss," "));
1038       throw INTERP_KERNEL::Exception(oss.str().c_str());
1039     }
1040   std::string nname(newName);
1041   std::map<std::string, mcIdType >::iterator it2=_families.find(nname);
1042   if(it2!=_families.end())
1043     {
1044       std::ostringstream oss; oss << "Such familyname \"" << newName << " already exists ! Kill it before !";
1045       throw INTERP_KERNEL::Exception(oss.str().c_str());
1046     }
1047   mcIdType cpy=(*it).second;
1048   _families.erase(it);
1049   _families[newName]=cpy;
1050   for(std::map<std::string, std::vector<std::string> >::iterator it3=_groups.begin();it3!=_groups.end();it3++)
1051     {
1052       std::vector<std::string>& v=(*it3).second;
1053       std::vector<std::string>::iterator it4=std::find(v.begin(),v.end(),oname);
1054       if(it4!=v.end())
1055         (*it4)=nname;
1056     }
1057 }
1058
1059 /*!
1060  * Checks if \a this and another mesh contains the same families.
1061  *  \param [in] other - the mesh to compare with \a this one.
1062  *  \param [in,out] what - an unused parameter.
1063  *  \return bool - \c true if number of families and their ids are the same in the two
1064  *          meshes. Families with the id == \c 0 are not considered.
1065  */
1066 bool MEDFileMesh::areFamsEqual(const MEDFileMesh *other, std::string& what) const
1067 {
1068   if(_families==other->_families)
1069     return true;
1070   std::map<std::string,mcIdType> fam0;
1071   std::map<std::string,mcIdType> fam1;
1072   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1073     if((*it).second!=0)
1074       fam0[(*it).first]=(*it).second;
1075   for(std::map<std::string,mcIdType>::const_iterator it=other->_families.begin();it!=other->_families.end();it++)
1076     if((*it).second!=0)
1077       fam1[(*it).first]=(*it).second;
1078   return fam0==fam1;
1079 }
1080
1081 /*!
1082  * Checks if \a this and another mesh contains the same groups.
1083  *  \param [in] other - the mesh to compare with \a this one.
1084  *  \param [in,out] what - a string describing a difference of groups of the two meshes
1085  *          in case if this method returns \c false.
1086  *  \return bool - \c true if number of groups and families constituting them are the
1087  *          same in the two meshes.
1088  */
1089 bool MEDFileMesh::areGrpsEqual(const MEDFileMesh *other, std::string& what) const
1090 {
1091   if(_groups==other->_groups)
1092     return true;
1093   bool ret=true;
1094   std::size_t sz=_groups.size();
1095   if(sz!=other->_groups.size())
1096     {
1097       what="Groups differ because not same number !\n";
1098       ret=false;
1099     }
1100   if(ret)
1101     {
1102       std::map<std::string, std::vector<std::string> >::const_iterator it1=_groups.begin();
1103       for(std::size_t i=0;i<sz && ret;i++,it1++)
1104         {
1105           std::map<std::string, std::vector<std::string> >::const_iterator it2=other->_groups.find((*it1).first);
1106           if(it2!=other->_groups.end())
1107             {
1108               std::set<std::string> s1((*it1).second.begin(),(*it1).second.end());
1109               std::set<std::string> s2((*it2).second.begin(),(*it2).second.end());
1110               ret=(s1==s2);
1111             }
1112           else
1113             {
1114               ret=false;
1115               what="A group in first mesh exists not in other !\n";
1116             }
1117         }
1118     }
1119   if(!ret)
1120     {
1121       std::ostringstream oss; oss << "Groups description differs :\n";
1122       oss << "First group description :\n";
1123       for(std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.begin();it!=_groups.end();it++)
1124         {
1125           oss << " Group \"" << (*it).first << "\" on following families :\n";
1126           for(std::vector<std::string>::const_iterator it2=(*it).second.begin();it2!=(*it).second.end();it2++)
1127             oss << "    \"" << *it2 << "\n";
1128         }
1129       oss << "Second group description :\n";
1130       for(std::map<std::string, std::vector<std::string> >::const_iterator it=other->_groups.begin();it!=other->_groups.end();it++)
1131         {
1132           oss << " Group \"" << (*it).first << "\" on following families :\n";
1133           for(std::vector<std::string>::const_iterator it2=(*it).second.begin();it2!=(*it).second.end();it2++)
1134             oss << "    \"" << *it2 << "\n";
1135         }
1136       what+=oss.str();
1137     }
1138   return ret;
1139 }
1140
1141 /*!
1142  * Checks if a group with a given name exists in \a this mesh.
1143  *  \param [in] groupName - the group name.
1144  *  \return bool - \c true the group \a groupName exists in \a this mesh.
1145  */
1146 bool MEDFileMesh::existsGroup(const std::string& groupName) const
1147 {
1148   std::string grpName(groupName);
1149   return _groups.find(grpName)!=_groups.end();
1150 }
1151
1152 /*!
1153  * Checks if a family with a given id exists in \a this mesh.
1154  *  \param [in] famId - the family id.
1155  *  \return bool - \c true the family with the id \a famId exists in \a this mesh.
1156  */
1157 bool MEDFileMesh::existsFamily(mcIdType famId) const
1158 {
1159   for(std::map<std::string,mcIdType>::const_iterator it2=_families.begin();it2!=_families.end();it2++)
1160     if((*it2).second==famId)
1161       return true;
1162   return false;
1163 }
1164
1165 /*!
1166  * Checks if a family with a given name exists in \a this mesh.
1167  *  \param [in] familyName - the family name.
1168  *  \return bool - \c true the family \a familyName exists in \a this mesh.
1169  */
1170 bool MEDFileMesh::existsFamily(const std::string& familyName) const
1171 {
1172   std::string fname(familyName);
1173   return _families.find(fname)!=_families.end();
1174 }
1175
1176 /*!
1177  * Sets an id of a family.
1178  *  \param [in] familyName - the family name.
1179  *  \param [in] id - a new id of the family.
1180  */
1181 void MEDFileMesh::setFamilyId(const std::string& familyName, mcIdType id)
1182 {
1183   std::string fname(familyName);
1184   _families[fname]=id;
1185 }
1186
1187 void MEDFileMesh::setFamilyIdUnique(const std::string& familyName, mcIdType id)
1188 {
1189   std::string fname(familyName);
1190   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1191     if((*it).second==id)
1192       {
1193         if((*it).first!=familyName)
1194           {
1195             std::ostringstream oss; oss << "MEDFileMesh::setFamilyIdUnique : Family id #" << id << " is already belonging to family with name \"" << (*it).first << "\" !";
1196             throw INTERP_KERNEL::Exception(oss.str().c_str());
1197           }
1198       }
1199   _families[fname]=id;
1200 }
1201
1202 /*!
1203  * Adds a family to \a this mesh.
1204  *  \param [in] familyName - a name of the family.
1205  *  \param [in] famId - an id of the family.
1206  *  \throw If a family with the same name or id already exists in \a this mesh.
1207  */
1208 void MEDFileMesh::addFamily(const std::string& familyName, mcIdType famId)
1209 {
1210   std::string fname(familyName);
1211   std::map<std::string,mcIdType>::const_iterator it=_families.find(fname);
1212   if(it==_families.end())
1213     {
1214       for(std::map<std::string,mcIdType>::const_iterator it2=_families.begin();it2!=_families.end();it2++)
1215         if((*it2).second==famId)
1216           {
1217             std::ostringstream oss;
1218             oss << "MEDFileMesh::addFamily : Family \"" << (*it2).first << "\" already exists with specified id : " << famId << " !";
1219             throw INTERP_KERNEL::Exception(oss.str().c_str());
1220           }
1221       _families[fname]=famId;
1222     }
1223   else
1224     {
1225       if((*it).second!=famId)
1226         {
1227           std::ostringstream oss;
1228           oss << "MEDFileMesh::addFamily : Family \"" << fname << "\" already exists but has id set to " << (*it).second << " different from asked famId " << famId << " !";
1229           throw INTERP_KERNEL::Exception(oss.str().c_str());
1230         }
1231     }
1232 }
1233
1234 /*!
1235  * Creates a group including all mesh entities of given dimension.
1236  * \warning This method does \b not guarantee that the created group includes mesh
1237  * entities of only \a meshDimRelToMaxExt dimension in the case if some family id is
1238  * present in family fields of different dimensions. To assure this, call
1239  * ensureDifferentFamIdsPerLevel() \b before calling this method.
1240  *  \param [in] meshDimRelToMaxExt - a relative dimension of mesh entities to include to
1241  *          the group.
1242  *  \param [in] groupName - a name of the new group.
1243  *  \throw If a group named \a groupName already exists.
1244  *  \throw If no mesh entities of dimension \a meshDimRelToMaxExt exist in \a this mesh.
1245  *  \throw If no family field of dimension \a meshDimRelToMaxExt is present in \a this mesh.
1246  */
1247 void MEDFileMesh::createGroupOnAll(int meshDimRelToMaxExt, const std::string& groupName)
1248 {
1249   std::string grpName(groupName);
1250   std::vector<int> levs=getNonEmptyLevelsExt();
1251   if(std::find(levs.begin(),levs.end(),meshDimRelToMaxExt)==levs.end())
1252     {
1253       std::ostringstream oss; oss << "MEDFileMesh::createGroupOnAll : The relative ext dimension " << meshDimRelToMaxExt << " is not available !" << std::endl;
1254       oss << "Available relative ext levels are : ";
1255       std::copy(levs.begin(),levs.end(),std::ostream_iterator<int>(oss," "));
1256       throw INTERP_KERNEL::Exception(oss.str().c_str());
1257     }
1258   if(existsGroup(groupName))
1259     {
1260       std::ostringstream oss; oss << "MEDFileMesh::createGroupOnAll : The groups \"" << grpName << "\" already exists in this !" << std::endl;
1261       oss << "Already existing groups are : ";
1262       std::copy(levs.begin(),levs.end(),std::ostream_iterator<int>(oss," "));
1263       oss << std::endl << "Please choose an another group name or call removeGroup(\"" << grpName << "\") method !";
1264       throw INTERP_KERNEL::Exception(oss.str().c_str());
1265     }
1266   const DataArrayIdType *fieldFamIds=getFamilyFieldAtLevel(meshDimRelToMaxExt);
1267   if(fieldFamIds==0)
1268     throw INTERP_KERNEL::Exception("MEDFileMesh::createGroupOnAll : Family field arr ids is not defined for this level !");
1269   MCAuto<DataArrayIdType> famIds=fieldFamIds->getDifferentValues();
1270   std::vector<std::string> familiesOnWholeGroup;
1271   for(const mcIdType *it=famIds->begin();it!=famIds->end();it++)
1272     {
1273       bool tmp;
1274       familiesOnWholeGroup.push_back(findOrCreateAndGiveFamilyWithId(*it,tmp));
1275     }
1276   _groups[grpName]=familiesOnWholeGroup;
1277 }
1278
1279 /*!
1280  * Ensures that given family ids do not present in family fields of dimensions different
1281  * than given ones. If a family id is present in the family fields of dimensions different
1282  * than the given ones, a new family is created and the whole data is updated accordingly.
1283  *  \param [in] famIds - a sequence of family ids to check.
1284  *  \param [in] vMeshDimRelToMaxExt - a sequence of relative dimensions to which the \a
1285  *          famIds should exclusively belong.
1286  *  \return bool - \c true if no modification is done in \a this mesh by this method.
1287  */
1288 bool MEDFileMesh::keepFamIdsOnlyOnLevs(const std::vector<mcIdType>& famIds, const std::vector<int>& vMeshDimRelToMaxExt)
1289 {
1290   std::set<int> levsInput(vMeshDimRelToMaxExt.begin(),vMeshDimRelToMaxExt.end());
1291   std::vector<int> levs=getNonEmptyLevelsExt();
1292   std::set<int> levs2(levs.begin(),levs.end());
1293   std::vector<int> levsToTest;
1294   std::set_difference(levs2.begin(),levs2.end(),levsInput.begin(),levsInput.end(),std::back_insert_iterator< std::vector<int> >(levsToTest));
1295   std::set<mcIdType> famIds2(famIds.begin(),famIds.end());
1296   bool ret=true;
1297   mcIdType maxFamId=1;
1298   if(!_families.empty())
1299     maxFamId=getMaxFamilyId()+1;
1300   std::vector<std::string> allFams=getFamiliesNames();
1301   for(std::vector<int>::const_iterator it=levsToTest.begin();it!=levsToTest.end();it++)
1302     {
1303       const DataArrayIdType *fieldFamIds=getFamilyFieldAtLevel(*it);
1304       if(fieldFamIds)
1305         {
1306           MCAuto<DataArrayIdType> famIds3=fieldFamIds->getDifferentValues();
1307           std::vector<mcIdType> tmp;
1308           std::set_intersection(famIds3->begin(),famIds3->end(),famIds2.begin(),famIds2.end(),std::back_insert_iterator< std::vector<mcIdType> >(tmp));
1309           for(std::vector<mcIdType>::const_iterator it2=tmp.begin();it2!=tmp.end();it2++)
1310             {
1311               ret=false;
1312               std::string famName=getFamilyNameGivenId(*it2);
1313               std::ostringstream oss; oss << "Family_" << maxFamId;
1314               std::string zeName=CreateNameNotIn(oss.str(),allFams);
1315               addFamilyOnAllGroupsHaving(famName,zeName);
1316               _families[zeName]=maxFamId;
1317               (const_cast<DataArrayIdType *>(fieldFamIds))->changeValue(*it2,maxFamId);
1318               maxFamId++;
1319             }
1320         }
1321     }
1322   return ret;
1323 }
1324
1325 /*!
1326  * Adds a family to a given group in \a this mesh. If the group with a given name does
1327  * not exist, it is created.
1328  *  \param [in] grpName - the name of the group to add the family in.
1329  *  \param [in] famName - the name of the family to add to the group named \a grpName.
1330  *  \throw If \a grpName or \a famName is an empty string.
1331  *  \throw If no family named \a famName is present in \a this mesh.
1332  */
1333 void MEDFileMesh::addFamilyOnGrp(const std::string& grpName, const std::string& famName)
1334 {
1335   std::string grpn(grpName);
1336   std::string famn(famName);
1337   if(grpn.empty() || famn.empty())
1338     throw INTERP_KERNEL::Exception("MEDFileMesh::addFamilyOnGrp : input strings must be non null !");
1339   std::vector<std::string> fams=getFamiliesNames();
1340   if(std::find(fams.begin(),fams.end(),famn)==fams.end())
1341     {
1342       std::ostringstream oss; oss << "MEDFileMesh::addFamilyOnGrp : Family \"" << famn << "\" does not exist !" << std::endl;
1343       oss << "Create this family or choose an existing one ! Existing fams are : ";
1344       std::copy(fams.begin(),fams.end(),std::ostream_iterator<std::string>(oss," ")); oss << ".";
1345       throw INTERP_KERNEL::Exception(oss.str().c_str());
1346     }
1347   std::map<std::string, std::vector<std::string> >::iterator it=_groups.find(grpn);
1348   if(it==_groups.end())
1349     {
1350       _groups[grpn].push_back(famn);
1351     }
1352   else
1353     {
1354       std::vector<std::string>::iterator it2=std::find((*it).second.begin(),(*it).second.end(),famn);
1355       if(it2==(*it).second.end())
1356         (*it).second.push_back(famn);
1357     }
1358 }
1359
1360 /*!
1361  * This method adds to all groups lying on family with name 'famName' the other family name 'otherFamName'.
1362  * This method is quite underground because it can lead to unconsistency because family 'otherFamName' is \b not added into _families.
1363  * This method is used by MEDFileMesh::keepFamIdsOnlyOnLevs method.
1364  */
1365 void MEDFileMesh::addFamilyOnAllGroupsHaving(const std::string& famName, const std::string& otherFamName)
1366 {
1367   std::string famNameCpp(famName);
1368   std::string otherCpp(otherFamName);
1369   for(std::map<std::string, std::vector<std::string> >::iterator it=_groups.begin();it!=_groups.end();it++)
1370     {
1371       std::vector<std::string>& v=(*it).second;
1372       if(std::find(v.begin(),v.end(),famNameCpp)!=v.end())
1373         {
1374           v.push_back(otherCpp);
1375         }
1376     }
1377 }
1378
1379 void MEDFileMesh::checkNoGroupClash(const DataArrayIdType *famArr, const std::string& grpName) const
1380 {
1381   std::vector<std::string> grpsNames(getGroupsNames());
1382   if(std::find(grpsNames.begin(),grpsNames.end(),grpName)==grpsNames.end())
1383     return ;
1384   std::vector<mcIdType> famIds(getFamiliesIdsOnGroup(grpName));
1385   if(famArr->presenceOfValue(famIds))
1386     {
1387       std::ostringstream oss; oss << "MEDFileUMesh::addGroup : Group with name \"" << grpName << "\" already exists at specified level ! Destroy it before calling this method !";
1388       throw INTERP_KERNEL::Exception(oss.str().c_str());
1389     }
1390 }
1391
1392 /*!
1393  * \param [in] ids ids and group name of the new group to add. The ids should be sorted and different each other (MED file norm).
1394  * \param [in,out] famArr family array on level of interest to be renumbered. The input pointer should be not \c NULL (no check of that will be performed)
1395  */
1396 void MEDFileMesh::addGroupUnderground(bool isNodeGroup, const DataArrayIdType *ids, DataArrayIdType *famArr)
1397 {
1398   if(!ids)
1399     throw INTERP_KERNEL::Exception("MEDFileUMesh::addGroup : NULL pointer in input !");
1400   std::string grpName(ids->getName());
1401   if(grpName.empty())
1402     throw INTERP_KERNEL::Exception("MEDFileUMesh::addGroup : empty group name ! MED file format do not accept empty group name !");
1403   ids->checkStrictlyMonotonic(true);
1404   checkNoGroupClash(famArr,grpName);
1405   MCAuto<DataArrayIdType> famArrTmp; famArrTmp.takeRef(famArr);
1406   std::list< MCAuto<DataArrayIdType> > allFamIds(getAllNonNullFamilyIds());
1407   allFamIds.erase(std::find(allFamIds.begin(),allFamIds.end(),famArrTmp));
1408   MCAuto<DataArrayIdType> famIds=famArr->selectByTupleIdSafe(ids->begin(),ids->end());
1409   MCAuto<DataArrayIdType> diffFamIds=famIds->getDifferentValues();
1410   std::vector<mcIdType> familyIds;
1411   std::vector< MCAuto<DataArrayIdType> > idsPerfamiliyIds;
1412   mcIdType maxVal=getTheMaxAbsFamilyId()+1;
1413   std::map<std::string,mcIdType> families(_families);
1414   std::map<std::string, std::vector<std::string> > groups(_groups);
1415   std::vector<std::string> fams;
1416   bool created(false);
1417   for(const mcIdType *famId=diffFamIds->begin();famId!=diffFamIds->end();famId++)
1418     {
1419       MCAuto<DataArrayIdType> ids2Tmp=famIds->findIdsEqual(*famId);
1420       MCAuto<DataArrayIdType> ids2=ids->selectByTupleId(ids2Tmp->begin(),ids2Tmp->end());
1421       MCAuto<DataArrayIdType> ids1=famArr->findIdsEqual(*famId);
1422       MCAuto<DataArrayIdType> ret0(ids1->buildSubstractionOptimized(ids2));
1423       if(ret0->empty())
1424         {
1425           bool isFamPresent=false;
1426           for(std::list< MCAuto<DataArrayIdType> >::const_iterator itl=allFamIds.begin();itl!=allFamIds.end() && !isFamPresent;itl++)
1427             isFamPresent=(*itl)->presenceOfValue(*famId);
1428           if(!isFamPresent && *famId!=0)
1429             { familyIds.push_back(*famId); idsPerfamiliyIds.push_back(ret0); fams.push_back(FindOrCreateAndGiveFamilyWithId(families,*famId,created)); } // adding *famId in grp
1430           else
1431             {
1432               familyIds.push_back(isNodeGroup?maxVal:-maxVal); idsPerfamiliyIds.push_back(ids2);
1433               std::string locFamName=FindOrCreateAndGiveFamilyWithId(families,isNodeGroup?maxVal:-maxVal,created);
1434               fams.push_back(locFamName);
1435               if(existsFamily(*famId))
1436                 {
1437                   std::string locFamName2=getFamilyNameGivenId(*famId); std::vector<std::string> v(2); v[0]=locFamName2; v[1]=locFamName;
1438                   ChangeAllGroupsContainingFamily(groups,getFamilyNameGivenId(*famId),v);
1439                 }
1440               maxVal++;
1441             } // modifying all other groups on *famId to lie on maxVal and lie the grp on maxVal
1442         }
1443       else
1444         {
1445           familyIds.push_back(isNodeGroup?maxVal:-maxVal); idsPerfamiliyIds.push_back(ret0); // modifying all other groups on *famId to lie on maxVal and on maxVal+1
1446           familyIds.push_back(isNodeGroup?maxVal+1:-maxVal-1); idsPerfamiliyIds.push_back(ids2);//grp lie only on maxVal+1
1447           std::string n2(FindOrCreateAndGiveFamilyWithId(families,isNodeGroup?maxVal+1:-maxVal-1,created)); fams.push_back(n2);
1448           if(existsFamily(*famId))
1449             {
1450               std::string n1(FindOrCreateAndGiveFamilyWithId(families,isNodeGroup?maxVal:-maxVal,created)); std::vector<std::string> v(2); v[0]=n1; v[1]=n2;
1451               ChangeAllGroupsContainingFamily(groups,getFamilyNameGivenId(*famId),v);
1452             }
1453           maxVal+=2;
1454         }
1455     }
1456   for(std::size_t i=0;i<familyIds.size();i++)
1457     {
1458       DataArrayIdType *da=idsPerfamiliyIds[i];
1459       famArr->setPartOfValuesSimple3(familyIds[i],da->begin(),da->end(),0,1,1);
1460     }
1461   _families=families;
1462   std::map<std::string, std::vector<std::string> >::iterator itt(groups.find(grpName));
1463   if(itt!=groups.end())
1464     {
1465       std::vector<std::string>& famsOnGrp((*itt).second);
1466       famsOnGrp.insert(famsOnGrp.end(),fams.begin(),fams.end());
1467     }
1468   else
1469     groups[grpName]=fams;
1470   _groups=groups;
1471 }
1472
1473 void MEDFileMesh::changeAllGroupsContainingFamily(const std::string& familyNameToChange, const std::vector<std::string>& newFamiliesNames)
1474 {
1475   ChangeAllGroupsContainingFamily(_groups,familyNameToChange,newFamiliesNames);
1476 }
1477
1478 void MEDFileMesh::ChangeAllGroupsContainingFamily(std::map<std::string, std::vector<std::string> >& groups, const std::string& familyNameToChange, const std::vector<std::string>& newFamiliesNames)
1479 {
1480   std::string fam(familyNameToChange);
1481   for(std::map<std::string, std::vector<std::string> >::iterator it=groups.begin();it!=groups.end();it++)
1482     {
1483       std::vector<std::string>& fams((*it).second);
1484       std::vector<std::string>::iterator it2=std::find(fams.begin(),fams.end(),fam);
1485       if(it2!=fams.end())
1486         {
1487           fams.erase(it2);
1488           fams.insert(fams.end(),newFamiliesNames.begin(),newFamiliesNames.end());
1489         }
1490     }
1491 }
1492
1493 /*!
1494  * Returns a name of the family having a given id or, if no such a family exists, creates
1495  * a new uniquely named family and returns its name.
1496  *  \param [in] id - the id of the family whose name is required.
1497  *  \param [out] created - returns \c true if the new family has been created, \c false, else.
1498  *  \return std::string - the name of the existing or the created family.
1499  *  \throw If it is not possible to create a unique family name.
1500  */
1501 std::string MEDFileMesh::findOrCreateAndGiveFamilyWithId(mcIdType id, bool& created)
1502 {
1503   return FindOrCreateAndGiveFamilyWithId(_families,id,created);
1504 }
1505
1506 /*!
1507  * If it exists a family whose family id is equal to 'id' this method behaves as MEDFileMesh::getFamilyNameGivenId.
1508  * In this case, 'this' internal states remains unchanged and 'created' out parameter will be set to false.
1509  * If there is no family whose family id is equal to 'id' a family is created with a name different from those
1510  * already existing. In this case 'created' will be returned with a value set to true, and internal state
1511  * will be modified.
1512  * This method will throws an exception if it is not possible to create a unique family name.
1513  */
1514 std::string MEDFileMesh::FindOrCreateAndGiveFamilyWithId(std::map<std::string,mcIdType>& families, mcIdType id, bool& created)
1515 {
1516   std::vector<std::string> famAlreadyExisting(families.size());
1517   int ii=0;
1518   for(std::map<std::string,mcIdType>::const_iterator it=families.begin();it!=families.end();it++,ii++)
1519     {
1520       if((*it).second!=id)
1521         {
1522           famAlreadyExisting[ii]=(*it).first;
1523         }
1524       else
1525         {
1526           created=false;
1527           return (*it).first;
1528         }
1529     }
1530   created=true;
1531   std::ostringstream oss; oss << "Family_" << id;
1532   std::string ret=CreateNameNotIn(oss.str(),famAlreadyExisting);
1533   families[ret]=id;
1534   return ret;
1535 }
1536
1537 /*!
1538  * Sets names and ids of all families in \a this mesh.
1539  *  \param [in] info - a map of a family name to a family id.
1540  */
1541 void MEDFileMesh::setFamilyInfo(const std::map<std::string,mcIdType>& info)
1542 {
1543   _families=info;
1544 }
1545
1546 /*!
1547  * Sets names of all groups and families constituting them in \a this mesh.
1548  *  \param [in] info - a map of a group name to a vector of names of families
1549  *          constituting the group.
1550  */
1551 void MEDFileMesh::setGroupInfo(const std::map<std::string, std::vector<std::string> >&info)
1552 {
1553   _groups=info;
1554 }
1555
1556 /*!
1557  * Returns an id of the family having a given name.
1558  *  \param [in] name - the name of the family of interest.
1559  *  \return mcIdType - the id of the family of interest.
1560  *  \throw If no family with such a \a name exists.
1561  */
1562 mcIdType MEDFileMesh::getFamilyId(const std::string& name) const
1563 {
1564   std::map<std::string, mcIdType>::const_iterator it=_families.find(name);
1565   if(it==_families.end())
1566     {
1567       std::vector<std::string> fams(getFamiliesNames());
1568       std::ostringstream oss; oss << "No such familyname \"" << name << "\" !\nAvailable families are :";
1569       std::copy(fams.begin(),fams.end(),std::ostream_iterator<std::string>(oss," "));
1570       throw INTERP_KERNEL::Exception(oss.str().c_str());
1571     }
1572   return (*it).second;
1573 }
1574
1575 /*!
1576  * Returns ids of the families having given names.
1577  *  \param [in] fams - a sequence of the names of families of interest.
1578  *  \return std::vector<mcIdType> - a sequence of the ids of families of interest.
1579  *  \throw If \a fams contains a name of an inexistent family.
1580  */
1581 std::vector<mcIdType> MEDFileMesh::getFamiliesIds(const std::vector<std::string>& fams) const
1582 {
1583   std::vector<mcIdType> ret(fams.size());
1584   int i=0;
1585   for(std::vector<std::string>::const_iterator it=fams.begin();it!=fams.end();it++,i++)
1586     {
1587       std::map<std::string, mcIdType>::const_iterator it2=_families.find(*it);
1588       if(it2==_families.end())
1589         {
1590           std::vector<std::string> fams2=getFamiliesNames();
1591           std::ostringstream oss; oss << "No such familyname \"" << *it << "\" in input list !\nAvailable families are :";
1592           std::copy(fams2.begin(),fams2.end(),std::ostream_iterator<std::string>(oss," "));
1593           throw INTERP_KERNEL::Exception(oss.str().c_str());
1594         }
1595       ret[i]=(*it2).second;
1596     }
1597   return ret;
1598 }
1599
1600 /*!
1601  * Returns a maximal abs(id) of families in \a this mesh.
1602  *  \return mcIdType - the maximal norm of family id.
1603  *  \throw If there are no families in \a this mesh.
1604  */
1605 mcIdType MEDFileMesh::getMaxAbsFamilyId() const
1606 {
1607   if(_families.empty())
1608     throw INTERP_KERNEL::Exception("MEDFileMesh::getMaxFamilyId : no families set !");
1609   mcIdType ret=-std::numeric_limits<mcIdType>::max();
1610   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1611     {
1612       ret=std::max(std::abs((*it).second),ret);
1613     }
1614   return ret;
1615 }
1616
1617 /*!
1618  * Returns a maximal id of families in \a this mesh.
1619  *  \return mcIdType - the maximal family id.
1620  *  \throw If there are no families in \a this mesh.
1621  */
1622 mcIdType MEDFileMesh::getMaxFamilyId() const
1623 {
1624   if(_families.empty())
1625     throw INTERP_KERNEL::Exception("MEDFileMesh::getMaxFamilyId : no families set !");
1626   mcIdType ret=-std::numeric_limits<mcIdType>::max();
1627   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1628     {
1629       ret=std::max((*it).second,ret);
1630     }
1631   return ret;
1632 }
1633
1634 /*!
1635  * Returns a minimal id of families in \a this mesh.
1636  *  \return mcIdType - the minimal family id.
1637  *  \throw If there are no families in \a this mesh.
1638  */
1639 mcIdType MEDFileMesh::getMinFamilyId() const
1640 {
1641   if(_families.empty())
1642     throw INTERP_KERNEL::Exception("MEDFileMesh::getMinFamilyId : no families set !");
1643   mcIdType ret=std::numeric_limits<mcIdType>::max();
1644   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1645     {
1646       ret=std::min((*it).second,ret);
1647     }
1648   return ret;
1649 }
1650
1651 /*!
1652  * Returns a maximal id of families in \a this mesh. Not only named families are
1653  * considered but all family fields as well.
1654  *  \return mcIdType - the maximal family id.
1655  */
1656 mcIdType MEDFileMesh::getTheMaxAbsFamilyId() const
1657 {
1658   mcIdType m1=-std::numeric_limits<mcIdType>::max();
1659   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1660     m1=std::max(std::abs((*it).second),m1);
1661   mcIdType m2=getMaxAbsFamilyIdInArrays();
1662   return std::max(m1,m2);
1663 }
1664
1665 /*!
1666  * Returns a maximal id of families in \a this mesh. Not only named families are
1667  * considered but all family fields as well.
1668  *  \return mcIdType - the maximal family id.
1669  */
1670 mcIdType MEDFileMesh::getTheMaxFamilyId() const
1671 {
1672   mcIdType m1=-std::numeric_limits<mcIdType>::max();
1673   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1674     m1=std::max((*it).second,m1);
1675   mcIdType m2=getMaxFamilyIdInArrays();
1676   return std::max(m1,m2);
1677 }
1678
1679 /*!
1680  * Returns a minimal id of families in \a this mesh. Not only named families are
1681  * considered but all family fields as well.
1682  *  \return mcIdType - the minimal family id.
1683  */
1684 mcIdType MEDFileMesh::getTheMinFamilyId() const
1685 {
1686   mcIdType m1=std::numeric_limits<mcIdType>::max();
1687   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1688     m1=std::min((*it).second,m1);
1689   mcIdType m2=getMinFamilyIdInArrays();
1690   return std::min(m1,m2);
1691 }
1692
1693 /*!
1694  * This method only considers the maps. The contain of family array is ignored here.
1695  * 
1696  * \sa MEDFileMesh::computeAllFamilyIdsInUse
1697  */
1698 DataArrayIdType *MEDFileMesh::getAllFamiliesIdsReferenced() const
1699 {
1700   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1701   std::set<mcIdType> v;
1702   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1703     v.insert((*it).second);
1704   ret->alloc((mcIdType)v.size(),1);
1705   std::copy(v.begin(),v.end(),ret->getPointer());
1706   return ret.retn();
1707 }
1708
1709 /*!
1710  * This method does not consider map of family name, family id. Only family field array on different levels is considered.
1711  * 
1712  * \sa MEDFileMesh::getAllFamiliesIdsReferenced
1713  */
1714 DataArrayIdType *MEDFileMesh::computeAllFamilyIdsInUse() const
1715 {
1716   std::vector<int> famLevs=getFamArrNonEmptyLevelsExt();
1717   MCAuto<DataArrayIdType> ret;
1718   for(std::vector<int>::const_iterator it=famLevs.begin();it!=famLevs.end();it++)
1719     {
1720       const DataArrayIdType *arr=getFamilyFieldAtLevel(*it);//arr not null due to spec of getFamArrNonEmptyLevelsExt
1721       MCAuto<DataArrayIdType> dv=arr->getDifferentValues();
1722       if((DataArrayIdType *) ret)
1723         ret=dv->buildUnion(ret);
1724       else
1725         ret=dv;
1726     }
1727   return ret.retn();
1728 }
1729
1730 /*!
1731  * true is returned if no modification has been needed. false if family
1732  * renumbering has been needed.       
1733  */
1734 bool MEDFileMesh::ensureDifferentFamIdsPerLevel()
1735 {
1736   std::vector<int> levs=getNonEmptyLevelsExt();
1737   std::set<mcIdType> allFamIds;
1738   mcIdType maxId=getMaxFamilyId()+1;
1739   std::map<int,std::vector<mcIdType> > famIdsToRenum;
1740   for(std::vector<int>::const_iterator it=levs.begin();it!=levs.end();it++)
1741     {
1742       const DataArrayIdType *fam=getFamilyFieldAtLevel(*it);
1743       if(fam)
1744         {
1745           MCAuto<DataArrayIdType> tmp=fam->getDifferentValues();
1746           std::set<mcIdType> r2;
1747           std::set_intersection(tmp->begin(),tmp->end(),allFamIds.begin(),allFamIds.end(),std::inserter(r2,r2.end()));
1748           if(!r2.empty())
1749             famIdsToRenum[*it].insert(famIdsToRenum[*it].end(),r2.begin(),r2.end());
1750           std::set<mcIdType> r3;
1751           std::set_union(tmp->begin(),tmp->end(),allFamIds.begin(),allFamIds.end(),std::inserter(r3,r3.end()));
1752         }
1753     }
1754   if(famIdsToRenum.empty())
1755     return true;
1756   MCAuto<DataArrayIdType> allIds=getAllFamiliesIdsReferenced();
1757   for(std::map<int,std::vector<mcIdType> >::const_iterator it2=famIdsToRenum.begin();it2!=famIdsToRenum.end();it2++)
1758     {
1759       DataArrayIdType *fam=const_cast<DataArrayIdType *>(getFamilyFieldAtLevel((*it2).first));
1760       mcIdType *famIdsToChange=fam->getPointer();
1761       std::map<mcIdType,mcIdType> ren;
1762       for(std::vector<mcIdType>::const_iterator it3=(*it2).second.begin();it3!=(*it2).second.end();it3++,maxId++)
1763         {
1764           if(allIds->presenceOfValue(*it3))
1765             {
1766               std::string famName=getFamilyNameGivenId(*it3);
1767               std::vector<std::string> grps=getGroupsOnFamily(famName);
1768               ren[*it3]=maxId;
1769               bool dummy;
1770               std::string newFam=findOrCreateAndGiveFamilyWithId(maxId,dummy);
1771               for(std::vector<std::string>::const_iterator it4=grps.begin();it4!=grps.end();it4++)
1772                 addFamilyOnGrp((*it4),newFam);
1773             }
1774         }
1775       MCAuto<DataArrayIdType> ids=fam->findIdsEqualList(&(*it2).second[0],&(*it2).second[0]+(*it2).second.size());
1776       for(const mcIdType *id=ids->begin();id!=ids->end();id++)
1777         famIdsToChange[*id]=ren[famIdsToChange[*id]];
1778     }
1779   return false;
1780 }
1781
1782 /*!
1783  * This method normalizes fam id with the policy explained underneath. This policy is close to those implemented in SMESH.
1784  * Level #0 famids > 0, Level #-1 famids < 0, Level #-2 famids=0, Level #1 famids=0
1785  * This policy is those used by SMESH and Trio and that is the opposite of those in MED file.
1786  * This method will throw an exception if a same family id is detected in different level.
1787  * \warning This policy is the opposite of those in MED file documentation ...
1788  */
1789 void MEDFileMesh::normalizeFamIdsTrio()
1790 {
1791   ensureDifferentFamIdsPerLevel();
1792   MCAuto<DataArrayIdType> allIds=getAllFamiliesIdsReferenced();
1793   std::vector<int> levs=getNonEmptyLevelsExt();
1794   std::set<int> levsS(levs.begin(),levs.end());
1795   std::set<std::string> famsFetched;
1796   std::map<std::string,mcIdType> families;
1797   if(std::find(levs.begin(),levs.end(),0)!=levs.end())
1798     {
1799       levsS.erase(0);
1800       const DataArrayIdType *fam=getFamilyFieldAtLevel(0);
1801       if(fam)
1802         {
1803           mcIdType refId=1;
1804           MCAuto<DataArrayIdType> tmp=fam->getDifferentValues();
1805           std::map<mcIdType,mcIdType> ren;
1806           for(const mcIdType *it=tmp->begin();it!=tmp->end();it++,refId++)
1807             ren[*it]=refId;
1808           mcIdType nbOfTuples=fam->getNumberOfTuples();
1809           mcIdType *start=const_cast<DataArrayIdType *>(fam)->getPointer();
1810           for(mcIdType *w=start;w!=start+nbOfTuples;w++)
1811             *w=ren[*w];
1812           for(const mcIdType *it=tmp->begin();it!=tmp->end();it++)
1813             {
1814               if(allIds->presenceOfValue(*it))
1815                 {
1816                   std::string famName=getFamilyNameGivenId(*it);
1817                   families[famName]=ren[*it];
1818                   famsFetched.insert(famName);
1819                 }
1820             }
1821         }
1822     }
1823   if(std::find(levs.begin(),levs.end(),-1)!=levs.end())
1824     {
1825       levsS.erase(-1);
1826       const DataArrayIdType *fam=getFamilyFieldAtLevel(-1);
1827       if(fam)
1828         {
1829           mcIdType refId=-1;
1830           MCAuto<DataArrayIdType> tmp=fam->getDifferentValues();
1831           std::map<mcIdType,mcIdType> ren;
1832           for(const mcIdType *it=tmp->begin();it!=tmp->end();it++,refId--)
1833             ren[*it]=refId;
1834           mcIdType nbOfTuples=fam->getNumberOfTuples();
1835           mcIdType *start=const_cast<DataArrayIdType *>(fam)->getPointer();
1836           for(mcIdType *w=start;w!=start+nbOfTuples;w++)
1837             *w=ren[*w];
1838           for(const mcIdType *it=tmp->begin();it!=tmp->end();it++)
1839             {
1840               if(allIds->presenceOfValue(*it))
1841                 {
1842                   std::string famName=getFamilyNameGivenId(*it);
1843                   families[famName]=ren[*it];
1844                   famsFetched.insert(famName);
1845                 }
1846             }
1847         }
1848     }
1849   for(std::set<int>::const_iterator it2=levsS.begin();it2!=levsS.end();it2++)
1850     {
1851       DataArrayIdType *fam=const_cast<DataArrayIdType*>(getFamilyFieldAtLevel(*it2));
1852       if(fam)
1853         {
1854           MCAuto<DataArrayIdType> tmp=fam->getDifferentValues();
1855           fam->fillWithZero();
1856           for(const mcIdType *it3=tmp->begin();it3!=tmp->end();it3++)
1857             if(allIds->presenceOfValue(*it3))
1858               {
1859                 std::string famName=getFamilyNameGivenId(*it3);
1860                 families[famName]=0;
1861                 famsFetched.insert(famName);
1862               }
1863         }
1864     }
1865   //
1866   std::vector<std::string> allFams=getFamiliesNames();
1867   std::set<std::string> allFamsS(allFams.begin(),allFams.end());
1868   std::set<std::string> unFetchedIds;
1869   std::set_difference(allFamsS.begin(),allFamsS.end(),famsFetched.begin(),famsFetched.end(),std::inserter(unFetchedIds,unFetchedIds.end()));
1870   for(std::set<std::string>::const_iterator it4=unFetchedIds.begin();it4!=unFetchedIds.end();it4++)
1871     families[*it4]=_families[*it4];
1872   _families=families;
1873 }
1874
1875 /*!
1876  * This method normalizes fam id with the following policy.
1877  * Level #0 famids < 0, Level #-1 famids < 0 and for Level #1 famids >= 0
1878  * This policy is those defined in the MED file format but is the opposite of those implemented in SMESH and Trio.
1879  * This method will throw an exception if a same family id is detected in different level.
1880  */
1881 void MEDFileMesh::normalizeFamIdsMEDFile()
1882 {
1883   ensureDifferentFamIdsPerLevel();
1884   MCAuto<DataArrayIdType> allIds=getAllFamiliesIdsReferenced();
1885   std::vector<int> levs=getNonEmptyLevelsExt();
1886   std::set<int> levsS(levs.begin(),levs.end());
1887   std::set<std::string> famsFetched;
1888   std::map<std::string,mcIdType> families;
1889   mcIdType refId=1;
1890   if(std::find(levs.begin(),levs.end(),1)!=levs.end())
1891     {
1892       levsS.erase(1);
1893       const DataArrayIdType *fam=getFamilyFieldAtLevel(1);
1894       if(fam)
1895         {
1896           MCAuto<DataArrayIdType> tmp=fam->getDifferentValues();
1897           std::map<mcIdType,mcIdType> ren;
1898           for(const mcIdType *it=tmp->begin();it!=tmp->end();it++,refId++)
1899             ren[*it]=refId;
1900           mcIdType nbOfTuples=fam->getNumberOfTuples();
1901           mcIdType *start=const_cast<DataArrayIdType *>(fam)->getPointer();
1902           for(mcIdType *w=start;w!=start+nbOfTuples;w++)
1903             *w=ren[*w];
1904           for(const mcIdType *it=tmp->begin();it!=tmp->end();it++)
1905             {
1906               if(allIds->presenceOfValue(*it))
1907                 {
1908                   std::string famName=getFamilyNameGivenId(*it);
1909                   families[famName]=ren[*it];
1910                   famsFetched.insert(famName);
1911                 }
1912             }
1913         }
1914     }
1915   refId=-1;
1916   for(std::set<int>::const_reverse_iterator it2=levsS.rbegin();it2!=levsS.rend();it2++)
1917     {
1918       const DataArrayIdType *fam=getFamilyFieldAtLevel(*it2);
1919       if(fam)
1920         {
1921           MCAuto<DataArrayIdType> tmp=fam->getDifferentValues();
1922           std::map<mcIdType,mcIdType> ren;
1923           for(const mcIdType *it=tmp->begin();it!=tmp->end();it++,refId--)
1924             ren[*it]=refId;
1925           mcIdType nbOfTuples=fam->getNumberOfTuples();
1926           mcIdType *start=const_cast<DataArrayIdType *>(fam)->getPointer();
1927           for(mcIdType *w=start;w!=start+nbOfTuples;w++)
1928             *w=ren[*w];
1929           for(const mcIdType *it=tmp->begin();it!=tmp->end();it++)
1930             {
1931               if(allIds->presenceOfValue(*it))
1932                 {
1933                   std::string famName=getFamilyNameGivenId(*it);
1934                   families[famName]=ren[*it];
1935                   famsFetched.insert(famName);
1936                 }
1937             }
1938         }
1939     }
1940   //
1941   std::vector<std::string> allFams=getFamiliesNames();
1942   std::set<std::string> allFamsS(allFams.begin(),allFams.end());
1943   std::set<std::string> unFetchedIds;
1944   std::set_difference(allFamsS.begin(),allFamsS.end(),famsFetched.begin(),famsFetched.end(),std::inserter(unFetchedIds,unFetchedIds.end()));
1945   for(std::set<std::string>::const_iterator it4=unFetchedIds.begin();it4!=unFetchedIds.end();it4++)
1946     families[*it4]=_families[*it4];
1947   _families=families;
1948 }
1949
1950 /*!
1951  * Returns a name of the family by its id. If there are several families having the given
1952  * id, the name first in lexical order is returned.
1953  *  \param [in] id - the id of the family whose name is required.
1954  *  \return std::string - the name of the found family.
1955  *  \throw If no family with the given \a id exists.
1956  */
1957 std::string MEDFileMesh::getFamilyNameGivenId(mcIdType id) const
1958 {
1959   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
1960     if((*it).second==id)
1961       return (*it).first;
1962   std::ostringstream oss; oss << "MEDFileUMesh::getFamilyNameGivenId : no such family id : " << id;
1963   throw INTERP_KERNEL::Exception(oss.str().c_str());
1964 }
1965
1966 /*!
1967  * Returns a string describing \a this mesh. This description includes the mesh name and
1968  * the mesh description string.
1969  *  \return std::string - the mesh information string.
1970  */
1971 std::string MEDFileMesh::simpleRepr() const
1972 {
1973   std::ostringstream oss;
1974   oss << "(*************************************)\n(* GENERAL INFORMATION ON THE MESH : *)\n(*************************************)\n";
1975   oss << "- Name of the mesh : <<" << getName() << ">>\n";
1976   oss << "- Description associated to the mesh : " << getDescription() << std::endl;
1977   return oss.str();
1978 }
1979
1980 /*!
1981  * This method is nearly like getFamilyFieldAtLevel method. Except that if the array does not exist at the specified level \a meshDimRelToMaxExt
1982  * an empty one is created.
1983  */
1984 DataArrayIdType *MEDFileMesh::getOrCreateAndGetFamilyFieldAtLevel(int meshDimRelToMaxExt)
1985 {
1986   DataArrayIdType *ret(getFamilyFieldAtLevel(meshDimRelToMaxExt));
1987   if(ret)
1988     return ret;
1989   MCAuto<DataArrayIdType> arr(DataArrayIdType::New());
1990   arr->alloc(getSizeAtLevel(meshDimRelToMaxExt),1);
1991   arr->fillWithZero();
1992   setFamilyFieldArr(meshDimRelToMaxExt,arr);
1993   return getFamilyFieldAtLevel(meshDimRelToMaxExt);
1994 }
1995
1996 /*!
1997  * Returns ids of mesh entities contained in a given group of a given dimension.
1998  *  \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids
1999  *          are required.
2000  *  \param [in] grp - the name of the group of interest.
2001  *  \param [in] renum - if \c true, the optional numbers of entities, if available, are
2002  *          returned instead of ids. 
2003  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding either ids or
2004  *          numbers, if available and required, of mesh entities of the group. The caller
2005  *          is to delete this array using decrRef() as it is no more needed. 
2006  *  \throw If the name of a nonexistent group is specified.
2007  *  \throw If the family field is missing for \a meshDimRelToMaxExt.
2008  */
2009 DataArrayIdType *MEDFileMesh::getGroupArr(int meshDimRelToMaxExt, const std::string& grp, bool renum) const
2010 {
2011   std::vector<std::string> tmp(1);
2012   tmp[0]=grp;
2013   DataArrayIdType *ret=getGroupsArr(meshDimRelToMaxExt,tmp,renum);
2014   ret->setName(grp);
2015   return ret;
2016 }
2017
2018 /*!
2019  * Returns ids of mesh entities contained in given groups of a given dimension.
2020  *  \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids
2021  *          are required.
2022  *  \param [in] grps - the names of the groups of interest.
2023  *  \param [in] renum - if \c true, the optional numbers of entities, if available, are
2024  *          returned instead of ids.
2025  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding either ids or
2026  *          numbers, if available and required, of mesh entities of the groups. The caller
2027  *          is to delete this array using decrRef() as it is no more needed. 
2028  *  \throw If the name of a nonexistent group is present in \a grps.
2029  *  \throw If the family field is missing for \a meshDimRelToMaxExt.
2030  */
2031 DataArrayIdType *MEDFileMesh::getGroupsArr(int meshDimRelToMaxExt, const std::vector<std::string>& grps, bool renum) const
2032 {
2033   std::vector<std::string> fams2=getFamiliesOnGroups(grps);
2034   return getFamiliesArr(meshDimRelToMaxExt,fams2,renum);
2035 }
2036
2037 /*!
2038  * Returns ids of mesh entities contained in a given family of a given dimension.
2039  *  \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids
2040  *          are required.
2041  *  \param [in] fam - the name of the family of interest.
2042  *  \param [in] renum - if \c true, the optional numbers of entities, if available, are
2043  *          returned instead of ids. 
2044  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding either ids or
2045  *          numbers, if available and required, of mesh entities of the family. The caller
2046  *          is to delete this array using decrRef() as it is no more needed. 
2047  *  \throw If the family field is missing for \a meshDimRelToMaxExt.
2048  */
2049 DataArrayIdType *MEDFileMesh::getFamilyArr(int meshDimRelToMaxExt, const std::string& fam, bool renum) const
2050 {
2051   std::vector<std::string> tmp(1);
2052   tmp[0]=fam;
2053   DataArrayIdType *ret=getFamiliesArr(meshDimRelToMaxExt,tmp,renum);
2054   ret->setName(fam);
2055   return ret;
2056 }
2057
2058 /*!
2059  * Returns ids of nodes contained in a given group.
2060  *  \param [in] grp - the name of the group of interest.
2061  *  \param [in] renum - if \c true, the optional numbers of nodes, if available, are
2062  *          returned instead of ids. 
2063  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding either ids or
2064  *          numbers, if available and required, of nodes of the group. The caller
2065  *          is to delete this array using decrRef() as it is no more needed. 
2066  *  \throw If the name of a nonexistent group is specified.
2067  *  \throw If the family field is missing for nodes.
2068  */
2069 DataArrayIdType *MEDFileMesh::getNodeGroupArr(const std::string& grp, bool renum) const
2070 {
2071   std::vector<std::string> tmp(1);
2072   tmp[0]=grp;
2073   DataArrayIdType *ret=getNodeGroupsArr(tmp,renum);
2074   ret->setName(grp);
2075   return ret;
2076 }
2077
2078 /*!
2079  * Returns ids of nodes contained in given groups.
2080  *  \param [in] grps - the names of the groups of interest.
2081  *  \param [in] renum - if \c true, the optional numbers of nodes, if available, are
2082  *          returned instead of ids. 
2083  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding either ids or
2084  *          numbers, if available and required, of nodes of the groups. The caller
2085  *          is to delete this array using decrRef() as it is no more needed. 
2086  *  \throw If the name of a nonexistent group is present in \a grps.
2087  *  \throw If the family field is missing for nodes.
2088  */
2089 DataArrayIdType *MEDFileMesh::getNodeGroupsArr(const std::vector<std::string>& grps, bool renum) const
2090 {
2091   return getGroupsArr(1,grps,renum);
2092 }
2093
2094 /*!
2095  * Returns ids of nodes contained in a given family.
2096  *  \param [in] fam - the name of the family of interest.
2097  *  \param [in] renum - if \c true, the optional numbers of nodes, if available, are
2098  *          returned instead of ids. 
2099  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding either ids or
2100  *          numbers, if available and required, of nodes of the family. The caller
2101  *          is to delete this array using decrRef() as it is no more needed. 
2102  *  \throw If the name of a nonexistent family is specified.
2103  *  \throw If the family field is missing for nodes.
2104  */
2105 DataArrayIdType *MEDFileMesh::getNodeFamilyArr(const std::string& fam, bool renum) const
2106 {
2107   std::vector<std::string> tmp(1);
2108   tmp[0]=fam;
2109   DataArrayIdType *ret=getNodeFamiliesArr(tmp,renum);
2110   ret->setName(fam);
2111   return ret;
2112 }
2113
2114 /*!
2115  * Returns ids of nodes contained in given families.
2116  *  \param [in] fams - the names of the families of interest.
2117  *  \param [in] renum - if \c true, the optional numbers of nodes, if available, are
2118  *          returned instead of ids. 
2119  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding either ids or
2120  *          numbers, if available and required, of nodes of the families. The caller
2121  *          is to delete this array using decrRef() as it is no more needed. 
2122  *  \throw If the family field is missing for nodes.
2123  */
2124 DataArrayIdType *MEDFileMesh::getNodeFamiliesArr(const std::vector<std::string>& fams, bool renum) const
2125 {
2126   return getFamiliesArr(1,fams,renum);
2127 }
2128
2129 /*!
2130  * Adds groups of given dimension and creates corresponding families and family fields
2131  * given ids of mesh entities of each group.
2132  *  \param [in] meshDimRelToMaxExt - the relative mesh dimension of given mesh entities.
2133  *  \param [in] grps - a sequence of arrays of ids each describing a group.
2134  *  \param [in] renum - \c true means that \a grps contains not ids but optional numbers
2135  *          of mesh entities.
2136  *  \throw If names of some groups in \a grps are equal.
2137  *  \throw If \a grps includes a group with an empty name.
2138  *  \throw If \a grps includes invalid ids (or numbers if \a renum == \c true ).
2139  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
2140  */
2141 void MEDFileMesh::setGroupsAtLevel(int meshDimRelToMaxExt, const std::vector<const DataArrayIdType *>& grps, bool renum)
2142 {
2143   if(grps.empty())
2144     return ;
2145   std::set<std::string> grpsName;
2146   std::vector<std::string> grpsName2(grps.size());
2147   int i=0;
2148
2149   for(std::vector<const DataArrayIdType *>::const_iterator it=grps.begin();it!=grps.end();it++,i++)
2150     {
2151       grpsName.insert((*it)->getName());
2152       grpsName2[i]=(*it)->getName();
2153     }
2154   if(grpsName.size()!=grps.size())
2155     throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsAtLevel : groups name must be different each other !");
2156   if(grpsName.find(std::string(""))!=grpsName.end())
2157     throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsAtLevel : groups name must be different empty string !");
2158   mcIdType sz=getSizeAtLevel(meshDimRelToMaxExt);
2159   MCAuto<DataArrayIdType> fam;
2160   std::vector< std::vector<mcIdType> > fidsOfGroups;
2161   if(!renum)
2162     {
2163       fam=DataArrayIdType::MakePartition(grps,sz,fidsOfGroups);
2164     }
2165   else
2166     {
2167       std::vector< MCAuto<DataArrayIdType> > grps2(grps.size());
2168       for(unsigned int ii=0;ii<grps.size();ii++)
2169         {
2170           grps2[ii]=MEDFileUMeshSplitL1::Renumber(getRevNumberFieldAtLevel(meshDimRelToMaxExt),grps[ii]);
2171           grps2[ii]->setName(grps[ii]->getName());
2172         }
2173       std::vector<const DataArrayIdType *> grps3(grps2.begin(),grps2.end());
2174       fam=DataArrayIdType::MakePartition(grps3,sz,fidsOfGroups);
2175     }
2176   mcIdType offset=1;
2177   if(!_families.empty())
2178     offset=getMaxAbsFamilyId()+1;
2179   TranslateFamilyIds(meshDimRelToMaxExt==1?offset:-offset,fam,fidsOfGroups);
2180   MCAuto<DataArrayIdType> ids=fam->getDifferentValues();
2181   appendFamilyEntries(ids,fidsOfGroups,grpsName2);
2182   setFamilyFieldArr(meshDimRelToMaxExt,fam);
2183 }
2184
2185 /*!
2186  * This method append into '_families' attribute the families whose ids are in 'famIds'. Warning 'famIds' are expected to be ids
2187  * not in '_families'. Groups information are given in parameters in order to give to families representative names.
2188  * For the moment, the two last input parameters are not taken into account.
2189  */
2190 void MEDFileMesh::appendFamilyEntries(const DataArrayIdType *famIds, const std::vector< std::vector<mcIdType> >& fidsOfGrps, const std::vector<std::string>& grpNames)
2191 {
2192   std::map<mcIdType,std::string> famInv;
2193   for(const mcIdType *it=famIds->begin();it!=famIds->end();it++)
2194     {
2195       std::ostringstream oss;
2196       oss << "Family_" << (*it);
2197       _families[oss.str()]=(*it);
2198       famInv[*it]=oss.str();
2199     }
2200   int i=0;
2201   for(std::vector< std::vector<mcIdType> >::const_iterator it1=fidsOfGrps.begin();it1!=fidsOfGrps.end();it1++,i++)
2202     {
2203       for(std::vector<mcIdType>::const_iterator it2=(*it1).begin();it2!=(*it1).end();it2++)
2204         {
2205           _groups[grpNames[i]].push_back(famInv[*it2]);
2206         }
2207     }
2208 }
2209
2210 std::vector<INTERP_KERNEL::NormalizedCellType> MEDFileMesh::getAllGeoTypes() const
2211 {
2212   std::vector<int> levs(getNonEmptyLevels());
2213   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
2214   for(std::vector<int>::const_iterator it=levs.begin();it!=levs.end();it++)
2215     {
2216       std::vector<INTERP_KERNEL::NormalizedCellType> elts(getGeoTypesAtLevel(*it));
2217       ret.insert(ret.end(),elts.begin(),elts.end());
2218     }
2219   return ret;
2220 }
2221
2222 /*!
2223  * \sa getAllDistributionOfTypes
2224  */
2225 std::vector<mcIdType> MEDFileMesh::getDistributionOfTypes(int meshDimRelToMax) const
2226 {
2227   MCAuto<MEDCouplingMesh> mLev(getMeshAtLevel(meshDimRelToMax));
2228   return mLev->getDistributionOfTypes();
2229 }
2230
2231 void MEDFileMesh::loadLLWithAdditionalItems(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
2232 {
2233   loadLL(fid,mName,dt,it,mrs);
2234   loadJointsFromFile(fid);
2235   loadEquivalences(fid);
2236 }
2237
2238 void MEDFileMesh::TranslateFamilyIds(mcIdType offset, DataArrayIdType *famArr, std::vector< std::vector<mcIdType> >& famIdsPerGrp)
2239 {
2240   famArr->applyLin(offset>0?1:-1,offset,0);
2241   for(std::vector< std::vector<mcIdType> >::iterator it1=famIdsPerGrp.begin();it1!=famIdsPerGrp.end();it1++)
2242     {
2243       if(offset<0)
2244         std::transform((*it1).begin(),(*it1).end(),(*it1).begin(),std::negate<mcIdType>());
2245       std::transform((*it1).begin(),(*it1).end(),(*it1).begin(),std::bind2nd(std::plus<mcIdType>(),offset));
2246     }
2247 }
2248
2249 /*!
2250  * Warning no check is done on 'nameTry' in parameter. It should be non empty.
2251  * This method returns a name close to 'nameTry' so that it is not already into 'namesToAvoid'.
2252  * If this method fails to find such a name it will throw an exception.
2253  */
2254 std::string MEDFileMesh::CreateNameNotIn(const std::string& nameTry, const std::vector<std::string>& namesToAvoid)
2255 {
2256   //attempt #0
2257   if(std::find(namesToAvoid.begin(),namesToAvoid.end(),nameTry)==namesToAvoid.end())
2258     return nameTry;
2259   //attempt #1
2260   std::size_t len=nameTry.length();
2261   for(std::size_t ii=1;ii<len;ii++)
2262     {
2263       std::string tmp=nameTry.substr(ii,len-ii);
2264       if(std::find(namesToAvoid.begin(),namesToAvoid.end(),tmp)==namesToAvoid.end())
2265         return tmp;
2266     }
2267   //attempt #2
2268   if(len>=1)
2269     {
2270       for(char i=1;i<30;i++)
2271         {
2272           std::string tmp1(nameTry.at(0),i);
2273           tmp1+=nameTry;
2274           if(std::find(namesToAvoid.begin(),namesToAvoid.end(),tmp1)==namesToAvoid.end())
2275             return tmp1;
2276         }
2277     }
2278   //attempt #3
2279   std::string tmp2;
2280   for(std::vector<std::string>::const_iterator it2=namesToAvoid.begin();it2!=namesToAvoid.end();it2++)
2281     tmp2+=(*it2);
2282   if(std::find(namesToAvoid.begin(),namesToAvoid.end(),tmp2)==namesToAvoid.end())
2283     return tmp2;
2284   throw INTERP_KERNEL::Exception("MEDFileMesh::CreateNameNotIn : impossible to find a not already used name !");
2285 }
2286
2287 mcIdType MEDFileMesh::PutInThirdComponentOfCodeOffset(std::vector<mcIdType>& code, mcIdType strt)
2288 {
2289   std::size_t nbOfChunks=code.size()/3;
2290   if(code.size()%3!=0)
2291     throw INTERP_KERNEL::Exception("MEDFileMesh::PutInThirdComponentOfCodeOffset : code has invalid size : should be of size 3*x !");
2292   mcIdType ret=strt;
2293   for(std::size_t i=0;i<nbOfChunks;i++)
2294     {
2295       code[3*i+2]=ret;
2296       ret+=code[3*i+1];
2297     }
2298   return ret;
2299 }
2300
2301 /*!
2302  * This method should be called by any set* method of subclasses to deal automatically with _name attribute.
2303  * If _name attribute is empty the name of 'm' if taken as _name attribute.
2304  * If _name is not empty and that 'm' has the same name nothing is done.
2305  * If _name is not emplt and that 'm' has \b NOT the same name an exception is thrown.
2306  */
2307 void MEDFileMesh::dealWithTinyInfo(const MEDCouplingMesh *m)
2308 {
2309   if(!m)
2310     throw INTERP_KERNEL::Exception("MEDFileMesh::dealWithTinyInfo : input mesh in NULL !");
2311   if(_name.empty())
2312     _name=m->getName();
2313   else
2314     {
2315       std::string name(m->getName());
2316       if(!name.empty())
2317         {
2318           if(_name!=name)
2319             {
2320               std::ostringstream oss; oss << "MEDFileMesh::dealWithTinyInfo : name of current MEDfile mesh is '" << _name << "' whereas name of input mesh is : '";
2321               oss << name << "' ! Names must match !";
2322               throw INTERP_KERNEL::Exception(oss.str().c_str());
2323             }
2324         }
2325     }
2326   if(_desc_name.empty())
2327     _desc_name=m->getDescription();
2328   else
2329     {
2330       std::string name(m->getDescription());
2331       if(!name.empty())
2332         {
2333           if(_desc_name!=name)
2334             {
2335               std::ostringstream oss; oss << "MEDFileMesh::dealWithTinyInfo : description of current MEDfile mesh is '" << _desc_name << "' whereas name of input mesh is : '";
2336               oss << name << "' ! Names must match !";
2337               throw INTERP_KERNEL::Exception(oss.str().c_str());
2338             }
2339         }
2340     }
2341 }
2342
2343 void MEDFileMesh::getFamilyRepr(std::ostream& oss) const
2344 {
2345   oss << "(**************************)\n(* FAMILIES OF THE MESH : *)\n(**************************)\n";
2346   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
2347     {
2348       oss << "- Family with name \"" << (*it).first << "\" with number " << (*it).second << std::endl;
2349       oss << "  - Groups lying on this family : ";
2350       std::vector<std::string> grps=getGroupsOnFamily((*it).first);
2351       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
2352       oss << std::endl << std::endl;
2353     }
2354 }
2355
2356 /*!
2357  * Returns a new MEDFileUMesh holding the mesh data that has been read from a given MED
2358  * file. The mesh to load is specified by its name and numbers of a time step and an
2359  * iteration.
2360  *  \param [in] fileName - the name of MED file to read.
2361  *  \param [in] mName - the name of the mesh to read.
2362  *  \param [in] dt - the number of a time step.
2363  *  \param [in] it - the number of an iteration.
2364  *  \return MEDFileUMesh * - a new instance of MEDFileUMesh. The caller is to delete this
2365  *          mesh using decrRef() as it is no more needed. 
2366  *  \throw If the file is not readable.
2367  *  \throw If there is no mesh with given attributes in the file.
2368  *  \throw If the mesh in the file is not an unstructured one.
2369  */
2370 MEDFileUMesh *MEDFileUMesh::New(const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
2371 {
2372   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
2373   return New(fid,mName,dt,it,mrs);
2374 }
2375
2376 MEDFileUMesh *MEDFileUMesh::New(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
2377 {
2378   return new MEDFileUMesh(fid,mName,dt,it,mrs);
2379 }
2380
2381 /*!
2382  * Returns a new MEDFileUMesh holding the mesh data that has been read from a given MED
2383  * file. The first mesh in the file is loaded.
2384  *  \param [in] fileName - the name of MED file to read.
2385  *  \return MEDFileUMesh * - a new instance of MEDFileUMesh. The caller is to delete this
2386  *          mesh using decrRef() as it is no more needed. 
2387  *  \throw If the file is not readable.
2388  *  \throw If there is no meshes in the file.
2389  *  \throw If the mesh in the file is not an unstructured one.
2390  */
2391 MEDFileUMesh *MEDFileUMesh::New(const std::string& fileName, MEDFileMeshReadSelector *mrs)
2392 {
2393   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
2394   return New(fid,mrs);
2395 }
2396
2397 template<class T>
2398 T *NewForTheFirstMeshInFile(med_idt fid, MEDFileMeshReadSelector *mrs)
2399 {
2400   std::vector<std::string> ms(MEDLoaderNS::getMeshNamesFid(fid));
2401   if(ms.empty())
2402     {
2403       std::ostringstream oss; oss << MLMeshTraits<T>::ClassName << "::New : no meshes in file \"" << MEDFileWritable::FileNameFromFID(fid) << "\" !";
2404       throw INTERP_KERNEL::Exception(oss.str().c_str());
2405     }
2406   int dt,it;
2407   MEDCoupling::MEDCouplingMeshType meshType;
2408   std::string dummy2;
2409   MEDCoupling::MEDCouplingAxisType dummy3;
2410   MEDFileMeshL2::GetMeshIdFromName(fid,ms.front(),meshType,dummy3,dt,it,dummy2);
2411   return T::New(fid,ms.front(),dt,it,mrs);
2412 }
2413
2414 MEDFileUMesh *MEDFileUMesh::New(med_idt fid, MEDFileMeshReadSelector *mrs)
2415 {
2416   return NewForTheFirstMeshInFile<MEDFileUMesh>(fid,mrs);
2417 }
2418
2419 /*!
2420  * \b WARNING this implementation is dependent from MEDCouplingMappedExtrudedMesh::buildUnstructured !
2421  * \sa MEDCouplingMappedExtrudedMesh::buildUnstructured , MEDCouplingMappedExtrudedMesh::build3DUnstructuredMesh
2422  */
2423 MEDFileUMesh *MEDFileUMesh::New(const MEDCouplingMappedExtrudedMesh *mem)
2424 {
2425   if(!mem)
2426     throw INTERP_KERNEL::Exception("MEDFileUMesh::New : null input vector !");
2427   MCAuto<MEDFileUMesh> ret(MEDFileUMesh::New());
2428   MCAuto<MEDCouplingUMesh> m3D(mem->buildUnstructured());
2429   MCAuto<MEDCouplingUMesh> m2D(mem->getMesh2D()->deepCopy());
2430   m2D->zipCoords();
2431   m2D->setCoords(m3D->getCoords());
2432   ret->setMeshAtLevel(0,m3D);
2433   ret->setMeshAtLevel(-1,m2D);
2434   ret->setFamilyId(GetSpeStr4ExtMesh(),std::numeric_limits<med_int>::max()-mem->get2DCellIdForExtrusion());
2435   return ret.retn();
2436 }
2437
2438 /*!
2439  * Returns an empty instance of MEDFileUMesh.
2440  *  \return MEDFileUMesh * - a new instance of MEDFileUMesh. The caller is to delete this
2441  *          mesh using decrRef() as it is no more needed. 
2442  */
2443 MEDFileUMesh *MEDFileUMesh::New()
2444 {
2445   return new MEDFileUMesh;
2446 }
2447
2448 /*!
2449  * This method loads from file with name \a fileName the mesh called \a mName as New does. The difference is that
2450  * here only a part of cells contained in the file will be loaded. The selection of cell is specified using the two consecutive parameters
2451  * \a types and \a slicPerTyp. This method allows to load from a mesh (typically huge) in a MED file a part of cells of that mesh.
2452  * The part of cells is specified using triplet (start,stop,step) for each geometric type. Only nodes lying on selected cells will be loaded to reduce
2453  * at most the memory consumtion.
2454  *
2455  * \param [in] fileName - the name of the file.
2456  * \param [in] mName - the name of the mesh to be read.
2457  * \param [in] types - the list of the geo types of which some part will be taken. A geometric type in \a types must appear only once at most.
2458  * \param [in] slicPerTyp - an array of size 3 times larger than \a types that specifies for each type in \a types (in the same order) resp the start, the stop and the step.
2459  * \param [in] dt - the iteration, that is to say the first element of the pair that locates the asked time step.
2460  * \param [in] it - the order, that is to say the second element of the pair that locates the asked time step.
2461  * \param [in] mrs - the request for what to be loaded.
2462  * \return MEDFileUMesh * - a new instance of MEDFileUMesh. The caller is to delete this mesh using decrRef() as it is no more needed.
2463  */
2464 MEDFileUMesh *MEDFileUMesh::LoadPartOf(const std::string& fileName, const std::string& mName, const std::vector<INTERP_KERNEL::NormalizedCellType>& types, const std::vector<mcIdType>& slicPerTyp, int dt, int it, MEDFileMeshReadSelector *mrs)
2465 {
2466   MEDFileUtilities::CheckFileForRead(fileName);
2467   MEDFileUtilities::AutoFid fid(MEDfileOpen(fileName.c_str(),MED_ACC_RDONLY));
2468   return MEDFileUMesh::LoadPartOf(fid,mName,types,slicPerTyp,dt,it,mrs);
2469 }
2470
2471 /*!
2472  * Please refer to the other MEDFileUMesh::LoadPartOf method that has the same semantic and the same parameter (excepted the first).
2473  * This method is \b NOT wrapped into python.
2474  */
2475 MEDFileUMesh *MEDFileUMesh::LoadPartOf(med_idt fid, const std::string& mName, const std::vector<INTERP_KERNEL::NormalizedCellType>& types, const std::vector<mcIdType>& slicPerTyp, int dt, int it, MEDFileMeshReadSelector *mrs)
2476 {
2477   MCAuto<MEDFileUMesh> ret(MEDFileUMesh::New());
2478   ret->loadPartUMeshFromFile(fid,mName,types,slicPerTyp,dt,it,mrs);
2479   return ret.retn();
2480 }
2481
2482 /*!
2483  * This method is an helper to load only consecutive nodes chunk of data of MED file pointed by \a fileName.
2484  * Consecutive chunk is specified classicaly by start (included) stop (excluded) format with \a startNodeId and \a stopNodeId respectively.
2485  * This method returns 5 elements.
2486  * 
2487  * \param [in] fileName - Name of file nodes to be read of.
2488  * \param [in] mName - Name of the mesh inside file pointed be \a fileName nodes to be read of.
2489  * \param [in] dt - Time iteration inside file pointed be \a fileName nodes to be read of.
2490  * \param [in] it - Time order inside file pointed be \a fileName nodes to be read of.
2491  * \param [in] infosOnComp - Components info of nodes to be read of. The size of string vector should be equal to space dimension of mesh to be read.
2492  * \param [in] startNodeId - Start Node Id (included) of chunk of data to be read
2493  * \param [in] stopNodeId - Start Node Id (included) of chunk of data to be read
2494  * \param [out] coords - output coordinates of requested chunk (DataArrayDouble)
2495  * \param [out] partCoords - output PartDefinition object of chunk
2496  * \param [out] famCoords - output family id field of requested chunk (DataArrayIdType)
2497  * \param [out] numCoords - output num id field of requested chunk (DataArrayIdType)
2498  * \param [out] nameCoords - output names on nodes of requested chunk (DataArrayAsciiChar)
2499  * 
2500  * \sa MEDLoaderUMesh::LoadPartOf
2501  */
2502 void MEDFileUMesh::LoadPartCoords(const std::string& fileName, const std::string& mName, int dt, int it, const std::vector<std::string>& infosOnComp, mcIdType startNodeId, mcIdType stopNodeId,
2503 MCAuto<DataArrayDouble>& coords, MCAuto<PartDefinition>& partCoords, MCAuto<DataArrayIdType>& famCoords, MCAuto<DataArrayIdType>& numCoords, MCAuto<DataArrayAsciiChar>& nameCoords)
2504 {
2505   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
2506   MEDFileUMeshL2::LoadPartCoords(fid,infosOnComp,mName,dt,it,startNodeId,stopNodeId,coords,partCoords,famCoords,numCoords,nameCoords);
2507 }
2508
2509 std::size_t MEDFileUMesh::getHeapMemorySizeWithoutChildren() const
2510 {
2511   std::size_t ret(MEDFileMesh::getHeapMemorySizeWithoutChildren());
2512   ret+=_ms.capacity()*(sizeof(MCAuto<MEDFileUMeshSplitL1>))+_elt_str.capacity()*sizeof(MCAuto<MEDFileEltStruct4Mesh>);
2513   return ret;
2514 }
2515
2516 std::vector<const BigMemoryObject *> MEDFileUMesh::getDirectChildrenWithNull() const
2517 {
2518   std::vector<const BigMemoryObject *> ret(MEDFileMesh::getDirectChildrenWithNull());
2519   ret.push_back((const DataArrayDouble*)_coords);
2520   ret.push_back((const DataArrayIdType *)_fam_coords);
2521   ret.push_back((const DataArrayIdType *)_num_coords);
2522   ret.push_back((const DataArrayIdType *)_global_num_coords);
2523   ret.push_back((const DataArrayIdType *)_rev_num_coords);
2524   ret.push_back((const DataArrayAsciiChar *)_name_coords);
2525   ret.push_back((const PartDefinition *)_part_coords);
2526   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
2527     ret.push_back((const MEDFileUMeshSplitL1*) *it);
2528   for(std::vector< MCAuto<MEDFileEltStruct4Mesh> >::const_iterator it=_elt_str.begin();it!=_elt_str.end();it++)
2529     ret.push_back((const MEDFileEltStruct4Mesh *)*it);
2530   return ret;
2531 }
2532
2533 MEDFileUMesh *MEDFileUMesh::shallowCpy() const
2534 {
2535   MCAuto<MEDFileUMesh> ret(new MEDFileUMesh(*this));
2536   return ret.retn();
2537 }
2538
2539 MEDFileMesh *MEDFileUMesh::createNewEmpty() const
2540 {
2541   return new MEDFileUMesh;
2542 }
2543
2544 MEDFileUMesh *MEDFileUMesh::deepCopy() const
2545 {
2546   MCAuto<MEDFileUMesh> ret(new MEDFileUMesh(*this));
2547   ret->deepCpyEquivalences(*this);
2548   if(_coords.isNotNull())
2549     ret->_coords=_coords->deepCopy();
2550   if(_fam_coords.isNotNull())
2551     ret->_fam_coords=_fam_coords->deepCopy();
2552   if(_num_coords.isNotNull())
2553     ret->_num_coords=_num_coords->deepCopy();
2554   if(_global_num_coords.isNotNull())
2555     ret->_global_num_coords=_global_num_coords->deepCopy();
2556   if(_rev_num_coords.isNotNull())
2557     ret->_rev_num_coords=_rev_num_coords->deepCopy();
2558   if(_name_coords.isNotNull())
2559     ret->_name_coords=_name_coords->deepCopy();
2560   std::size_t i=0;
2561   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,i++)
2562     {
2563       if((const MEDFileUMeshSplitL1 *)(*it))
2564         ret->_ms[i]=(*it)->deepCopy(ret->_coords);
2565     }
2566   if((const PartDefinition*)_part_coords)
2567     ret->_part_coords=_part_coords->deepCopy();
2568   return ret.retn();
2569 }
2570
2571 /*!
2572  * Checks if \a this and another mesh are equal.
2573  *  \param [in] other - the mesh to compare with.
2574  *  \param [in] eps - a precision used to compare real values.
2575  *  \param [in,out] what - the string returning description of unequal data.
2576  *  \return bool - \c true if the meshes are equal, \c false, else.
2577  */
2578 bool MEDFileUMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const
2579 {
2580   if(!MEDFileMesh::isEqual(other,eps,what))
2581     return false;
2582   const MEDFileUMesh *otherC=dynamic_cast<const MEDFileUMesh *>(other);
2583   if(!otherC)
2584     {
2585       what="Mesh types differ ! This is unstructured and other is NOT !";
2586       return false;
2587     }
2588   clearNonDiscrAttributes();
2589   otherC->clearNonDiscrAttributes();
2590   const DataArrayDouble *coo1=_coords;
2591   const DataArrayDouble *coo2=otherC->_coords;
2592   if((coo1==0 && coo2!=0) || (coo1!=0 && coo2==0))
2593     {
2594       what="Mismatch of coordinates ! One is defined and not other !";
2595       return false;
2596     }
2597   if(coo1)
2598     {
2599       bool ret=coo1->isEqual(*coo2,eps);
2600       if(!ret)
2601         {
2602           what="Coords differ !";
2603           return false;
2604         }
2605     }
2606   {
2607     const DataArrayIdType *famc1(_fam_coords),*famc2(otherC->_fam_coords);
2608     if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
2609       {
2610         what="Mismatch of families arr on nodes ! One is defined and not other !";
2611         return false;
2612       }
2613     if(famc1)
2614       {
2615         bool ret=famc1->isEqual(*famc2);
2616         if(!ret)
2617           {
2618             what="Families arr on node differ !";
2619             return false;
2620           }
2621       }
2622   }
2623   {
2624     const DataArrayIdType *numc1(_num_coords),*numc2(otherC->_num_coords);
2625     if((numc1==0 && numc2!=0) || (numc1!=0 && numc2==0))
2626       {
2627         what="Mismatch of numbering arr on nodes ! One is defined and not other !";
2628         return false;
2629       }
2630     if(numc1)
2631       {
2632         bool ret=numc1->isEqual(*numc2);
2633         if(!ret)
2634           {
2635             what="Numbering arr on node differ !";
2636             return false;
2637           }
2638       }
2639   }
2640   {
2641     const DataArrayIdType *gnumc1(_global_num_coords),*gnumc2(otherC->_global_num_coords);
2642     if((gnumc1==0 && gnumc2!=0) || (gnumc1!=0 && gnumc2==0))
2643       {
2644         what="Mismatch of numbering arr on nodes ! One is defined and not other !";
2645         return false;
2646       }
2647     if(gnumc1)
2648       {
2649         bool ret=gnumc1->isEqual(*gnumc2);
2650         if(!ret)
2651           {
2652             what="Global numbering arr on node differ !";
2653             return false;
2654           }
2655       }
2656   }
2657   {
2658     const DataArrayAsciiChar *namec1(_name_coords),*namec2(otherC->_name_coords);
2659     if((namec1==0 && namec2!=0) || (namec1!=0 && namec2==0))
2660       {
2661         what="Mismatch of naming arr on nodes ! One is defined and not other !";
2662         return false;
2663       }
2664     if(namec1)
2665       {
2666         bool ret=namec1->isEqual(*namec2);
2667         if(!ret)
2668           {
2669             what="Names arr on node differ !";
2670             return false;
2671           }
2672       }
2673   }
2674   if(_ms.size()!=otherC->_ms.size())
2675     {
2676       what="Number of levels differs !";
2677       return false;
2678     }
2679   std::size_t sz=_ms.size();
2680   for(std::size_t i=0;i<sz;i++)
2681     {
2682       const MEDFileUMeshSplitL1 *s1=_ms[i];
2683       const MEDFileUMeshSplitL1 *s2=otherC->_ms[i];
2684       if((s1==0 && s2!=0) || (s1!=0 && s2==0))
2685         {
2686           what="Mismatch of presence of sub levels !";
2687           return false;
2688         }
2689       if(s1)
2690         {
2691           bool ret=s1->isEqual(s2,eps,what);
2692           if(!ret)
2693             return false;
2694         }
2695     }
2696   const PartDefinition *pd0(_part_coords),*pd1(otherC->_part_coords);
2697   if(!pd0 && !pd1)
2698     return true;
2699   if((!pd0 && pd1) || (pd0 && !pd1))
2700     {
2701       what=std::string("node part def is defined only for one among this or other !");
2702       return false;
2703     }
2704   return pd0->isEqual(pd1,what);
2705 }
2706
2707 /*!
2708  * Check that the current object MEDFileUMesh is consistent. This does not check the optional renumbering of
2709  * nodes and cells. This last item is important for SMESH, see checkSMESHConsistency().
2710  * \throw if any internal part (i.e. mesh sub-levels and single geometric-type meshes) are inconsistent
2711  * \throw if internal family array is inconsistent
2712  * \sa checkSMESHConsistency()
2713  */
2714 void MEDFileUMesh::checkConsistency() const
2715 {
2716   if(!_coords || !_coords->isAllocated())
2717     {
2718       if(!_ms.size())
2719         throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): coords are null but some mesh parts are present!");
2720       if (!_fam_coords)
2721         throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): coords are null but not the internal node family array!");
2722       if (_num_coords.isNotNull() || _rev_num_coords.isNotNull() || _global_num_coords.isNotNull())
2723         throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): coords are null but not the internal node numbering array!");
2724     }
2725   else
2726     {
2727       mcIdType nbCoo = _coords->getNumberOfTuples();
2728       if (_fam_coords.isNotNull())
2729         _fam_coords->checkNbOfTuplesAndComp(nbCoo,1,"MEDFileUMesh::checkConsistency(): inconsistent internal node family array!");
2730       if (_num_coords.isNotNull())
2731         {
2732           _num_coords->checkNbOfTuplesAndComp(nbCoo,1,"MEDFileUMesh::checkConsistency(): inconsistent internal node numbering array!");
2733           mcIdType pos;
2734           mcIdType maxValue=_num_coords->getMaxValue(pos);
2735           if (!_rev_num_coords || _rev_num_coords->getNumberOfTuples() != (maxValue+1))
2736             throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): inconsistent internal revert node numbering array!");
2737         }
2738       if (_global_num_coords.isNotNull())
2739         {
2740           _global_num_coords->checkNbOfTuplesAndComp(nbCoo,1,"MEDFileUMesh::checkConsistency(): inconsistent global node numbering array!");
2741         }
2742       if ((_num_coords && !_rev_num_coords) || (!_num_coords && _rev_num_coords))
2743         throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): inconsistent internal numbering arrays (one is null)!");
2744       if (_num_coords && !_num_coords->hasUniqueValues())
2745         throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): inconsistent internal node numbering array: duplicates found!");
2746       if (_name_coords)
2747         _name_coords->checkNbOfTuplesAndComp(nbCoo,MED_SNAME_SIZE,"MEDFileUMesh::checkConsistency(): inconsistent internal coord name array!");
2748       // Now sub part check:
2749       for (std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();
2750           it != _ms.end(); it++)
2751         (*it)->checkConsistency();
2752     }
2753 }
2754
2755 /**
2756  * Same as checkConsistency() but also checks that optional entities (edges, faces, volumes) numbers are
2757  * consistent, i.e. the numbering is either set to null for all sub-levels (thus letting SMESH numbers the
2758  * entities as it likes), or non overlapping between all sub-levels.
2759  * \throw if the condition above is not respected
2760  */
2761 void MEDFileUMesh::checkSMESHConsistency() const
2762 {
2763   checkConsistency();
2764   // For all sub-levels, numbering is either always null or with void intersection:
2765   if (_ms.size())
2766     {
2767       std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();
2768       std::vector< const DataArrayIdType * > v;
2769       bool voidOrNot = ((*it)->_num == 0);
2770       for (it++; it != _ms.end(); it++)
2771         if( ((*it)->_num == 0) != voidOrNot )
2772           throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): inconsistent numbering between mesh sub-levels!");
2773         else if (!voidOrNot)
2774           v.push_back((*it)->_num);
2775       if (!voidOrNot)
2776         {
2777           // don't forget the 1st one:
2778           v.push_back(_ms[0]->_num);
2779           MCAuto<DataArrayIdType> inter = DataArrayIdType::BuildIntersection(v);
2780           if (inter->getNumberOfTuples())
2781             throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): overlapping entity numbering between mesh sub-levels!");
2782         }
2783     }
2784 }
2785
2786 /**
2787  * Reset optional node and cell numbering for all sub levels in this. This particularly useful to make
2788  * sure SMESH will handle the mesh correctly, as it tries to use those numbers if given.
2789  */
2790 void MEDFileUMesh::clearNodeAndCellNumbers()
2791 {
2792   _num_coords.nullify();
2793   _rev_num_coords.nullify();
2794   _global_num_coords.nullify();
2795   for (std::vector< MCAuto<MEDFileUMeshSplitL1> >::iterator it=_ms.begin(); it != _ms.end(); it++)
2796     {
2797       (*it)->_num.nullify();
2798       (*it)->_rev_num.nullify();
2799       (*it)->_global_num.nullify();
2800     }
2801 }
2802
2803 /*!
2804  * Clears redundant attributes of incorporated data arrays.
2805  */
2806 void MEDFileUMesh::clearNonDiscrAttributes() const
2807 {
2808   MEDFileMesh::clearNonDiscrAttributes();
2809   if(_coords.isNotNull())
2810     _coords.iAmATrollConstCast()->setName("");//This parameter is not discriminant for comparison
2811   if(_fam_coords.isNotNull())
2812     _fam_coords.iAmATrollConstCast()->setName("");//This parameter is not discriminant for comparison
2813   if(_num_coords.isNotNull())
2814     _num_coords.iAmATrollConstCast()->setName("");//This parameter is not discriminant for comparison
2815   if(_name_coords.isNotNull())
2816     _name_coords.iAmATrollConstCast()->setName("");//This parameter is not discriminant for comparison
2817   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
2818     {
2819       if((*it).isNotNull())
2820         (*it)->clearNonDiscrAttributes();
2821     }
2822 }
2823
2824 void MEDFileUMesh::setName(const std::string& name)
2825 {
2826   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::iterator it=_ms.begin();it!=_ms.end();it++)
2827     if((*it).isNotNull())
2828       (*it)->setName(name);
2829   MEDFileMesh::setName(name);
2830 }
2831
2832 MEDFileUMesh::MEDFileUMesh()
2833 {
2834 }
2835
2836 MEDFileUMesh::MEDFileUMesh(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
2837 try
2838 {
2839     loadLLWithAdditionalItems(fid,mName,dt,it,mrs);
2840 }
2841 catch(INTERP_KERNEL::Exception& e)
2842 {
2843     throw e;
2844 }
2845
2846 /*!
2847  * This method loads only a part of specified cells (given by range of cell ID per geometric type)
2848  * See MEDFileUMesh::LoadPartOf for detailed description.
2849  *
2850  * \sa loadLL
2851  */
2852 void MEDFileUMesh::loadPartUMeshFromFile(med_idt fid, const std::string& mName, const std::vector<INTERP_KERNEL::NormalizedCellType>& types, const std::vector<mcIdType>& slicPerTyp, int dt, int it, MEDFileMeshReadSelector *mrs)
2853 {
2854   MEDFileUMeshL2 loaderl2;
2855   MEDCoupling::MEDCouplingMeshType meshType;
2856   int dummy0,dummy1;
2857   std::string dummy2;
2858   MEDCoupling::MEDCouplingAxisType dummy3;
2859   INTERP_KERNEL::AutoCppPtr<MeshOrStructMeshCls> mid(MEDFileUMeshL2::GetMeshIdFromName(fid,mName,meshType,dummy3,dummy0,dummy1,dummy2));
2860   if(meshType!=UNSTRUCTURED)
2861     {
2862       std::ostringstream oss; oss << "loadPartUMeshFromFile : Trying to load as unstructured an existing mesh with name '" << mName << "' !";
2863       throw INTERP_KERNEL::Exception(oss.str().c_str());
2864     }
2865   loaderl2.loadPart(fid,mid,mName,types,slicPerTyp,dt,it,mrs);
2866   dispatchLoadedPart(fid,loaderl2,mName,mrs);
2867 }
2868
2869 /*!
2870  * \brief Write joints in a file
2871  */
2872 void MEDFileMesh::writeJoints(med_idt fid) const
2873 {
2874   if ( _joints.isNotNull() )
2875     _joints->writeLL(fid);
2876 }
2877
2878 /*!
2879  * \brief Load joints in a file or use provided ones
2880  */
2881 //================================================================================
2882 /*!
2883  * \brief Load joints in a file or use provided ones
2884  *  \param [in] fid - MED file descriptor
2885  *  \param [in] toUseInstedOfReading - optional joints to use instead of reading,
2886  *          Usually this joints are those just read by another iteration
2887  *          of namesake mesh, when this method is called by MEDFileMeshMultiTS::New()
2888  */
2889 //================================================================================
2890
2891 void MEDFileMesh::loadJointsFromFile(med_idt fid, MEDFileJoints* toUseInstedOfReading)
2892 {
2893   if ( toUseInstedOfReading )
2894     setJoints( toUseInstedOfReading );
2895   else
2896     _joints = MEDFileJoints::New( fid, _name );
2897 }
2898
2899 void MEDFileMesh::loadEquivalences(med_idt fid)
2900 {
2901   int nbOfEq(MEDFileEquivalences::PresenceOfEquivalences(fid,_name));
2902   if(nbOfEq>0)
2903     _equiv=MEDFileEquivalences::Load(fid,nbOfEq,this);
2904 }
2905
2906 void MEDFileMesh::deepCpyEquivalences(const MEDFileMesh& other)
2907 {
2908   const MEDFileEquivalences *equiv(other._equiv);
2909   if(equiv)
2910     _equiv=equiv->deepCopy(this);
2911 }
2912
2913 bool MEDFileMesh::areEquivalencesEqual(const MEDFileMesh *other, std::string& what) const
2914 {
2915   const MEDFileEquivalences *thisEq(_equiv),*otherEq(other->_equiv);
2916   if(!thisEq && !otherEq)
2917     return true;
2918   if(thisEq && otherEq)
2919     return thisEq->isEqual(otherEq,what);
2920   else
2921     {
2922       what+="Equivalence differs : defined in this and not in other (or reversely) !";
2923       return false;
2924     }
2925 }
2926
2927 void MEDFileMesh::getEquivalencesRepr(std::ostream& oss) const
2928 {
2929   const MEDFileEquivalences *equiv(_equiv);
2930   if(!equiv)
2931     return ;
2932   oss << "(******************************)\n(* EQUIVALENCES OF THE MESH : *)\n(******************************)\n";
2933   _equiv->getRepr(oss);
2934 }
2935
2936 void MEDFileMesh::checkCartesian() const
2937 {
2938   if(getAxisType()!=AX_CART)
2939     {
2940       std::ostringstream oss; oss << "MEDFileMesh::checkCartesian : request for method that is dedicated to a cartesian convention ! But you are not in cartesian convention (" << DataArray::GetAxisTypeRepr(getAxisType()) << ").";
2941       oss << std::endl << "To perform operation you have two possibilities :" << std::endl;
2942       oss << " - call setAxisType(AX_CART)" << std::endl;
2943       oss << " - call cartesianize()";
2944       throw INTERP_KERNEL::Exception(oss.str().c_str());
2945     }
2946 }
2947
2948 /*!
2949  * \brief Return number of joints, which is equal to number of adjacent mesh domains
2950  */
2951 int MEDFileMesh::getNumberOfJoints() const
2952 {
2953   return ( (const MEDFileJoints *) _joints ) ? _joints->getNumberOfJoints() : 0;
2954 }
2955
2956 /*!
2957  * \brief Return joints with all adjacent mesh domains
2958  */
2959 MEDFileJoints * MEDFileMesh::getJoints() const
2960 {
2961   return const_cast<MEDFileJoints*>(& (*_joints));
2962 }
2963
2964 void MEDFileMesh::setJoints( MEDFileJoints* joints )
2965 {
2966   if ( joints != _joints )
2967     {
2968       _joints = joints;
2969       if ( joints )
2970         joints->incrRef();
2971     }
2972 }
2973
2974 /*!
2975  * This method loads \b all \b the \b mesh \a mName in the file with \a fid descriptor.
2976  *
2977  * \sa loadPartUMeshFromFile
2978  */
2979 void MEDFileUMesh::loadLL(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
2980 {
2981   MEDFileUMeshL2 loaderl2;
2982   MEDCoupling::MEDCouplingMeshType meshType;
2983   int dummy0,dummy1;
2984   std::string dummy2;
2985   MEDCoupling::MEDCouplingAxisType axType;
2986   INTERP_KERNEL::AutoCppPtr<MeshOrStructMeshCls> mid(MEDFileUMeshL2::GetMeshIdFromName(fid,mName,meshType,axType,dummy0,dummy1,dummy2));
2987   setAxisType(axType);
2988   if(meshType!=UNSTRUCTURED)
2989     {
2990       std::ostringstream oss; oss << "Trying to load as unstructured an existing mesh with name '" << mName << "' !";
2991       throw INTERP_KERNEL::Exception(oss.str().c_str());
2992     }
2993   loaderl2.loadAll(fid,mid,mName,dt,it,mrs);
2994   dispatchLoadedPart(fid,loaderl2,mName,mrs);
2995   // Structure element part...
2996   med_int nModels(-1);
2997   {
2998     med_bool chgt=MED_FALSE,trsf=MED_FALSE;
2999     nModels=MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_STRUCT_ELEMENT,MED_GEO_ALL,MED_CONNECTIVITY,MED_NODAL,&chgt,&trsf);
3000   }
3001   if(nModels<=0)
3002     return ;
3003   _elt_str.resize(nModels);
3004   for(int i=0;i<nModels;i++)
3005     _elt_str[i]=MEDFileEltStruct4Mesh::New(fid,mName,dt,it,i,mrs);
3006 }
3007
3008 void MEDFileUMesh::dispatchLoadedPart(med_idt fid, const MEDFileUMeshL2& loaderl2, const std::string& mName, MEDFileMeshReadSelector *mrs)
3009 {
3010   int lev=loaderl2.getNumberOfLevels();
3011   _ms.resize(lev);
3012   for(int i=0;i<lev;i++)
3013     {
3014       if(!loaderl2.emptyLev(i))
3015         _ms[i]=new MEDFileUMeshSplitL1(loaderl2,mName,i);
3016       else
3017         _ms[i]=0;
3018     }
3019   MEDFileMeshL2::ReadFamiliesAndGrps(fid,mName,_families,_groups,mrs);
3020   //
3021   setName(loaderl2.getName());
3022   setDescription(loaderl2.getDescription());
3023   setUnivName(loaderl2.getUnivName());
3024   setIteration(loaderl2.getIteration());
3025   setOrder(loaderl2.getOrder());
3026   setTimeValue(loaderl2.getTime());
3027   setTimeUnit(loaderl2.getTimeUnit());
3028   _coords=loaderl2.getCoords();
3029   if(!mrs || mrs->isNodeFamilyFieldReading())
3030     _fam_coords=loaderl2.getCoordsFamily();
3031   if(!mrs || mrs->isNodeNumFieldReading())
3032     _num_coords=loaderl2.getCoordsNum();
3033   if(!mrs || mrs->isNodeNameFieldReading())
3034     _name_coords=loaderl2.getCoordsName();
3035   if(!mrs || mrs->isGlobalNodeNumFieldReading())
3036     _global_num_coords=loaderl2.getCoordsGlobalNum();
3037   _part_coords=loaderl2.getPartDefOfCoo();
3038   computeRevNum();
3039 }
3040
3041 MEDFileUMesh::~MEDFileUMesh()
3042 {
3043 }
3044
3045 void MEDFileUMesh::writeMeshLL(med_idt fid) const
3046 {
3047   const DataArrayDouble *coo=_coords;
3048   INTERP_KERNEL::AutoPtr<char> maa=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE);
3049   INTERP_KERNEL::AutoPtr<char> desc=MEDLoaderBase::buildEmptyString(MED_COMMENT_SIZE);
3050   MEDLoaderBase::safeStrCpy(_name.c_str(),MED_NAME_SIZE,maa,_too_long_str);
3051   MEDLoaderBase::safeStrCpy(_desc_name.c_str(),MED_COMMENT_SIZE,desc,_too_long_str);
3052   int spaceDim=(int)(coo?coo->getNumberOfComponents():0);
3053   int mdim(0);
3054   if(!_ms.empty())
3055     mdim=getMeshDimension();
3056   INTERP_KERNEL::AutoPtr<char> comp=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
3057   INTERP_KERNEL::AutoPtr<char> unit=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
3058   for(int i=0;i<spaceDim;i++)
3059     {
3060       std::string info=coo->getInfoOnComponent(i);
3061       std::string c,u;
3062       MEDLoaderBase::splitIntoNameAndUnit(info,c,u);
3063       MEDLoaderBase::safeStrCpy2(c.c_str(),MED_SNAME_SIZE,comp+i*MED_SNAME_SIZE,_too_long_str);//MED_TAILLE_PNOM-1 to avoid to write '\0' on next compo
3064       MEDLoaderBase::safeStrCpy2(u.c_str(),MED_SNAME_SIZE,unit+i*MED_SNAME_SIZE,_too_long_str);//MED_TAILLE_PNOM-1 to avoid to write '\0' on next compo
3065     }
3066   MEDFILESAFECALLERWR0(MEDmeshCr,(fid,maa,spaceDim,mdim,MED_UNSTRUCTURED_MESH,desc,"",MED_SORT_DTIT,MEDFileMeshL2::TraduceAxisTypeRev(getAxisType()),comp,unit));
3067   if(_univ_wr_status)
3068     MEDFILESAFECALLERWR0(MEDmeshUniversalNameWr,(fid,maa));
3069   std::string meshName(MEDLoaderBase::buildStringFromFortran(maa,MED_NAME_SIZE));
3070   MEDFileUMeshL2::WriteCoords(fid,meshName,_iteration,_order,_time,_coords,_fam_coords,_num_coords,_name_coords,_global_num_coords);
3071   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
3072     if((const MEDFileUMeshSplitL1 *)(*it)!=0)
3073       (*it)->write(fid,meshName,mdim);
3074   MEDFileUMeshL2::WriteFamiliesAndGrps(fid,meshName,_families,_groups,_too_long_str);
3075 }
3076
3077 /*!
3078  * Returns relative dimensions of mesh entities (excluding nodes) present in \a this mesh.
3079  *  \return std::vector<int> - a sequence of the relative dimensions.
3080  */
3081 std::vector<int> MEDFileUMesh::getNonEmptyLevels() const
3082 {
3083   std::vector<int> ret;
3084   int lev=0;
3085   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev--)
3086     if((const MEDFileUMeshSplitL1 *)(*it)!=0)
3087       if(!(*it)->empty())
3088         ret.push_back(lev);
3089   return ret;
3090 }
3091
3092 /*!
3093  * Returns relative dimensions of mesh entities (including nodes) present in \a this mesh.
3094  *  \return std::vector<int> - a sequence of the relative dimensions.
3095  */
3096 std::vector<int> MEDFileUMesh::getNonEmptyLevelsExt() const
3097 {
3098   std::vector<int> ret0=getNonEmptyLevels();
3099   if((const DataArrayDouble *) _coords)
3100     {
3101       std::vector<int> ret(ret0.size()+1);
3102       ret[0]=1;
3103       std::copy(ret0.begin(),ret0.end(),ret.begin()+1);
3104       return ret;
3105     }
3106   return ret0;
3107 }
3108
3109 std::vector<int> MEDFileUMesh::getFamArrNonEmptyLevelsExt() const
3110 {
3111   std::vector<int> ret;
3112   const DataArrayIdType *famCoo(_fam_coords);
3113   if(famCoo)
3114     ret.push_back(1);
3115   int lev=0;
3116   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev--)
3117     {
3118       const MEDFileUMeshSplitL1 *cur(*it);
3119       if(cur)
3120         if(cur->getFamilyField())
3121           ret.push_back(lev);
3122     }
3123   return ret;
3124 }
3125
3126 std::vector<int> MEDFileUMesh::getNumArrNonEmptyLevelsExt() const
3127 {
3128   std::vector<int> ret;
3129   if(_num_coords.isNotNull())
3130     ret.push_back(1);
3131   int lev=0;
3132   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev--)
3133     {
3134       const MEDFileUMeshSplitL1 *cur(*it);
3135       if(cur)
3136         if(cur->getNumberField())
3137           ret.push_back(lev);
3138     }
3139   return ret;
3140 }
3141
3142 std::vector<int> MEDFileUMesh::getNameArrNonEmptyLevelsExt() const
3143 {
3144   std::vector<int> ret;
3145   const DataArrayAsciiChar *nameCoo(_name_coords);
3146   if(nameCoo)
3147     ret.push_back(1);
3148   int lev=0;
3149   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev--)
3150     {
3151       const MEDFileUMeshSplitL1 *cur(*it);
3152       if(cur)
3153         if(cur->getNameField())
3154           ret.push_back(lev);
3155     }
3156   return ret;
3157 }
3158
3159 /*!
3160  * Returns all relative mesh levels (**excluding nodes**) where given families are defined.
3161  * To include nodes, call getFamsNonEmptyLevelsExt() method.
3162  *  \param [in] fams - the name of the family of interest.
3163  *  \return std::vector<int> - a sequence of the relative dimensions.
3164  */
3165 std::vector<mcIdType> MEDFileUMesh::getFamsNonEmptyLevels(const std::vector<std::string>& fams) const
3166 {
3167   std::vector<mcIdType> ret;
3168   std::vector<int> levs(getNonEmptyLevels());
3169   std::vector<mcIdType> famIds(getFamiliesIds(fams));
3170   for(std::vector<int>::const_iterator it=levs.begin();it!=levs.end();it++)
3171     if(_ms[-(*it)]->presenceOfOneFams(famIds))
3172       ret.push_back(*it);
3173   return ret;
3174 }
3175
3176 /*!
3177  * Returns all relative mesh levels (including nodes) where given families are defined.
3178  *  \param [in] fams - the names of the families of interest.
3179  *  \return std::vector<int> - a sequence of the relative dimensions.
3180  */
3181 std::vector<mcIdType> MEDFileUMesh::getFamsNonEmptyLevelsExt(const std::vector<std::string>& fams) const
3182 {
3183   std::vector<mcIdType> ret0(getFamsNonEmptyLevels(fams));
3184   const DataArrayIdType *famCoords(_fam_coords);
3185   if(!famCoords)
3186     return ret0;
3187   std::vector<mcIdType> famIds(getFamiliesIds(fams));
3188   if(famCoords->presenceOfValue(famIds))
3189     {
3190       std::vector<mcIdType> ret(ret0.size()+1);
3191       ret[0]=1;
3192       std::copy(ret0.begin(),ret0.end(),ret.begin()+1);
3193       return ret;
3194     }
3195   else
3196     return ret0;
3197 }
3198
3199 mcIdType MEDFileUMesh::getMaxAbsFamilyIdInArrays() const
3200 {
3201   mcIdType ret=-std::numeric_limits<mcIdType>::max(),tmp=-1;
3202   if((const DataArrayIdType *)_fam_coords)
3203     {
3204       mcIdType val=_fam_coords->getMaxValue(tmp);
3205       ret=std::max(ret,std::abs(val));
3206     }
3207   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
3208     {
3209       if((const MEDFileUMeshSplitL1 *)(*it))
3210         {
3211           const DataArrayIdType *da=(*it)->getFamilyField();
3212           if(da)
3213             {
3214               mcIdType val=da->getMaxValue(tmp);
3215               ret=std::max(ret,std::abs(val));
3216             }
3217         }
3218     }
3219   return ret;
3220 }
3221
3222 mcIdType MEDFileUMesh::getMaxFamilyIdInArrays() const
3223 {
3224   mcIdType ret=-std::numeric_limits<mcIdType>::max(),tmp=-1;
3225   if((const DataArrayIdType *)_fam_coords)
3226     {
3227       mcIdType val=_fam_coords->getMaxValue(tmp);
3228       ret=std::max(ret,val);
3229     }
3230   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
3231     {
3232       if((const MEDFileUMeshSplitL1 *)(*it))
3233         {
3234           const DataArrayIdType *da=(*it)->getFamilyField();
3235           if(da)
3236             {
3237               mcIdType val=da->getMaxValue(tmp);
3238               ret=std::max(ret,val);
3239             }
3240         }
3241     }
3242   return ret;
3243 }
3244
3245 mcIdType MEDFileUMesh::getMinFamilyIdInArrays() const
3246 {
3247   mcIdType ret=std::numeric_limits<mcIdType>::max(),tmp=-1;
3248   if((const DataArrayIdType *)_fam_coords)
3249     {
3250       mcIdType val=_fam_coords->getMinValue(tmp);
3251       ret=std::min(ret,val);
3252     }
3253   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
3254     {
3255       if((const MEDFileUMeshSplitL1 *)(*it))
3256         {
3257           const DataArrayIdType *da=(*it)->getFamilyField();
3258           if(da)
3259             {
3260               mcIdType val=da->getMinValue(tmp);
3261               ret=std::min(ret,val);
3262             }
3263         }
3264     }
3265   return ret;
3266 }
3267
3268 /*!
3269  * Returns the dimension on cells in \a this mesh.
3270  *  \return int - the mesh dimension.
3271  *  \throw If there are no cells in this mesh.
3272  */
3273 int MEDFileUMesh::getMeshDimension() const
3274 {
3275   int lev=0;
3276   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev++)
3277     if((const MEDFileUMeshSplitL1 *)(*it)!=0)
3278       return (*it)->getMeshDimension()+lev;
3279   throw INTERP_KERNEL::Exception("MEDFileUMesh::getMeshDimension : impossible to find a mesh dimension !");
3280 }
3281
3282 /*!
3283  * Returns the space dimension of \a this mesh that is equal to number of components in
3284  * the node coordinates array.
3285  *  \return int - the space dimension of \a this mesh.
3286  *  \throw If the node coordinates array is not available.
3287  */
3288 int MEDFileUMesh::getSpaceDimension() const
3289 {
3290   const DataArrayDouble *coo=_coords;
3291   if(!coo)
3292     throw INTERP_KERNEL::Exception(" MEDFileUMesh::getSpaceDimension : no coords set !");
3293   return (int)coo->getNumberOfComponents();
3294 }
3295
3296 /*!
3297  * Returns a string describing \a this mesh.
3298  *  \return std::string - the mesh information string.
3299  */
3300 std::string MEDFileUMesh::simpleRepr() const
3301 {
3302   std::ostringstream oss;
3303   oss << MEDFileMesh::simpleRepr();
3304   const DataArrayDouble *coo=_coords;
3305   oss << "- The dimension of the space is ";
3306   static const char MSG1[]= "*** NO COORDS SET ***";
3307   static const char MSG2[]= "*** NO CONNECTIVITY SET FOR THIS LEVEL***";
3308   if(coo)
3309     oss << _coords->getNumberOfComponents() << std::endl;
3310   else
3311     oss << MSG1 << std::endl;
3312   oss << "- Type of the mesh : UNSTRUCTURED\n";
3313   oss << "- Number of nodes : ";
3314   if(coo)
3315     oss << _coords->getNumberOfTuples() << std::endl;
3316   else
3317     oss << MSG1 << std::endl;
3318   std::size_t nbOfLev=_ms.size();
3319   oss << "- Number of levels allocated : " << nbOfLev << std::endl;
3320   for(std::size_t i=0;i<nbOfLev;i++)
3321     {
3322       const MEDFileUMeshSplitL1 *lev=_ms[i];
3323       oss << "  - Level #" << -((int) i) << " has dimension : ";
3324       if(lev)
3325         {
3326           oss << lev->getMeshDimension() << std::endl;
3327           lev->simpleRepr(oss);
3328         }
3329       else
3330         oss << MSG2 << std::endl;
3331     }
3332   oss << "- Number of families : " << _families.size() << std::endl << std::endl;
3333   if(coo)
3334     {
3335       oss << "(***********************)\n(* NODES OF THE MESH : *)\n(***********************)\n";
3336       oss << "- Names of coordinates :" << std::endl;
3337       std::vector<std::string> vars=coo->getVarsOnComponent();
3338       std::copy(vars.begin(),vars.end(),std::ostream_iterator<std::string>(oss," "));
3339       oss << std::endl << "- Units of coordinates : " << std::endl;
3340       std::vector<std::string> units=coo->getUnitsOnComponent();
3341       std::copy(units.begin(),units.end(),std::ostream_iterator<std::string>(oss," "));
3342     }
3343   oss << std::endl << std::endl;
3344   getFamilyRepr(oss);
3345   getEquivalencesRepr(oss);
3346   return oss.str();
3347 }
3348
3349 /*!
3350  * Returns a full textual description of \a this mesh.
3351  *  \return std::string - the string holding the mesh description.
3352  */
3353 std::string MEDFileUMesh::advancedRepr() const
3354 {
3355   return simpleRepr();
3356 }
3357
3358 /*!
3359  * Returns number of mesh entities of a given relative dimension in \a this mesh.
3360  *  \param [in] meshDimRelToMaxExt - the relative dimension of interest.
3361  *  \return mcIdType - the number of entities.
3362  *  \throw If no mesh entities of dimension \a meshDimRelToMaxExt are available in \a this mesh.
3363  */
3364 mcIdType MEDFileUMesh::getSizeAtLevel(int meshDimRelToMaxExt) const
3365 {
3366   if(meshDimRelToMaxExt==1)
3367     {
3368       if(!((const DataArrayDouble *)_coords))
3369         throw INTERP_KERNEL::Exception("MEDFileUMesh::getSizeAtLevel : no coordinates specified !");
3370       return _coords->getNumberOfTuples();
3371     }
3372   return getMeshAtLevSafe(meshDimRelToMaxExt)->getSize();
3373 }
3374
3375 /*!
3376  * Returns the family field for mesh entities of a given dimension.
3377  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
3378  *  \return const DataArrayIdType * - the family field. It is an array of ids of families
3379  *          each mesh entity belongs to. It can be \c NULL.
3380  */
3381 const DataArrayIdType *MEDFileUMesh::getFamilyFieldAtLevel(int meshDimRelToMaxExt) const
3382 {
3383   if(meshDimRelToMaxExt==1)
3384     return _fam_coords;
3385   const MEDFileUMeshSplitL1 *l1(getMeshAtLevSafe(meshDimRelToMaxExt));
3386   return l1->getFamilyField();
3387 }
3388
3389 DataArrayIdType *MEDFileUMesh::getFamilyFieldAtLevel(int meshDimRelToMaxExt)
3390 {
3391   if(meshDimRelToMaxExt==1)
3392     return _fam_coords;
3393   MEDFileUMeshSplitL1 *l1(getMeshAtLevSafe(meshDimRelToMaxExt));
3394   return l1->getFamilyField();
3395 }
3396
3397 /*!
3398  * Returns the optional numbers of mesh entities of a given dimension.
3399  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
3400  *  \return const DataArrayIdType * - the array of the entity numbers.
3401  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3402  */
3403 const DataArrayIdType *MEDFileUMesh::getNumberFieldAtLevel(int meshDimRelToMaxExt) const
3404 {
3405   if(meshDimRelToMaxExt==1)
3406     return _num_coords;
3407   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
3408   return l1->getNumberField();
3409 }
3410
3411 const DataArrayAsciiChar *MEDFileUMesh::getNameFieldAtLevel(int meshDimRelToMaxExt) const
3412 {
3413   if(meshDimRelToMaxExt==1)
3414     return _name_coords;
3415   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
3416   return l1->getNameField();
3417 }
3418
3419 MCAuto<DataArrayIdType> MEDFileUMesh::getGlobalNumFieldAtLevel(int meshDimRelToMaxExt) const
3420 {
3421   if(meshDimRelToMaxExt!=1)
3422     throw INTERP_KERNEL::Exception("MEDFileUMesh::getGlobalNumFieldAtLevel : not implemented yet for structured mesh !");
3423   return _global_num_coords;
3424 }
3425
3426 /*!
3427  * This method returns for a specified relative level \a meshDimRelToMaxExt the part effectively read (if the instance is the result of the read of a file).
3428  *
3429  * \param [in] meshDimRelToMaxExt - the extended relative level for which the part definition is requested.
3430  * \param [in] gt - The input geometric type for which the part definition is requested.
3431  * \return the part definition owned by \a this. So no need to deallocate the returned instance.
3432  */
3433 const PartDefinition *MEDFileUMesh::getPartDefAtLevel(int meshDimRelToMaxExt, INTERP_KERNEL::NormalizedCellType gt) const
3434 {
3435   if(meshDimRelToMaxExt==1)
3436     return _part_coords;
3437   const MEDFileUMeshSplitL1 *l1(getMeshAtLevSafe(meshDimRelToMaxExt));
3438   return l1->getPartDef(gt);
3439 }
3440
3441 mcIdType MEDFileUMesh::getNumberOfNodes() const
3442 {
3443   const DataArrayDouble *coo(_coords);
3444   if(!coo)
3445     throw INTERP_KERNEL::Exception(" MEDFileUMesh::getNumberOfNodes : no coords set !");
3446   return coo->getNumberOfTuples();
3447 }
3448
3449 mcIdType MEDFileUMesh::getNumberOfCellsAtLevel(int meshDimRelToMaxExt) const
3450 {
3451   const MEDFileUMeshSplitL1 *l1(getMeshAtLevSafe(meshDimRelToMaxExt));
3452   return l1->getNumberOfCells();
3453 }
3454
3455 bool MEDFileUMesh::hasImplicitPart() const
3456 {
3457   return false;
3458 }
3459
3460 mcIdType MEDFileUMesh::buildImplicitPartIfAny(INTERP_KERNEL::NormalizedCellType gt) const
3461 {
3462   throw INTERP_KERNEL::Exception("MEDFileUMesh::buildImplicitPartIfAny : unstructured meshes do not have implicit part !");
3463 }
3464
3465 void MEDFileUMesh::releaseImplicitPartIfAny() const
3466 {
3467 }
3468
3469 void MEDFileUMesh::whichAreNodesFetched(const MEDFileField1TSStructItem& st, const MEDFileFieldGlobsReal *globs, std::vector<bool>& nodesFetched) const
3470 {
3471   std::size_t sz(st.getNumberOfItems());
3472   for(std::size_t i=0;i<sz;i++)
3473     {
3474       INTERP_KERNEL::NormalizedCellType curGt(st[i].getGeo());
3475       const MEDCoupling1GTUMesh *m(getDirectUndergroundSingleGeoTypeMesh(curGt));
3476       if(st[i].getPflName().empty())
3477         m->computeNodeIdsAlg(nodesFetched);
3478       else
3479         {
3480           const DataArrayIdType *arr(globs->getProfile(st[i].getPflName()));
3481           MCAuto<MEDCoupling1GTUMesh> m2(dynamic_cast<MEDCoupling1GTUMesh *>(m->buildPartOfMySelf(arr->begin(),arr->end(),true)));
3482           m2->computeNodeIdsAlg(nodesFetched);
3483         }
3484     }
3485 }
3486
3487 MEDFileMesh *MEDFileUMesh::cartesianize() const
3488 {
3489   if(getAxisType()==AX_CART)
3490     {
3491       incrRef();
3492       return const_cast<MEDFileUMesh *>(this);
3493     }
3494   else
3495     {
3496       MCAuto<MEDFileUMesh> ret(new MEDFileUMesh(*this));
3497       const DataArrayDouble *coords(_coords);
3498       if(!coords)
3499         throw INTERP_KERNEL::Exception("MEDFileUMesh::cartesianize : coordinates are null !");
3500       MCAuto<DataArrayDouble> coordsCart(_coords->cartesianize(getAxisType()));
3501       for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::iterator it=ret->_ms.begin();it!=ret->_ms.end();it++)
3502         if((const MEDFileUMeshSplitL1 *)(*it))
3503           *it=(*it)->shallowCpyUsingCoords(coordsCart);
3504       ret->_coords=coordsCart;
3505       ret->setAxisType(AX_CART);
3506       return ret.retn();
3507     }
3508 }
3509
3510 bool MEDFileUMesh::presenceOfStructureElements() const
3511 {
3512   for(std::vector< MCAuto<MEDFileEltStruct4Mesh> >::const_iterator it=_elt_str.begin();it!=_elt_str.end();it++)
3513     if((*it).isNotNull())
3514       return true;
3515   return false;
3516 }
3517
3518 void MEDFileUMesh::killStructureElements()
3519 {
3520   _elt_str.clear();
3521 }
3522
3523 /*!
3524  * Returns the optional numbers of mesh entities of a given dimension transformed using
3525  * DataArrayIdType::invertArrayN2O2O2N().
3526  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
3527  *  \return const DataArrayIdType * - the array of the entity numbers transformed using
3528  *          DataArrayIdType::invertArrayN2O2O2N().
3529  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3530  */
3531 const DataArrayIdType *MEDFileUMesh::getRevNumberFieldAtLevel(int meshDimRelToMaxExt) const
3532 {
3533   if(meshDimRelToMaxExt==1)
3534     {
3535       if(_num_coords.isNull())
3536         throw INTERP_KERNEL::Exception("MEDFileUMesh::getRevNumberFieldAtLevel : no coordinates renum specified !");
3537       return _rev_num_coords;
3538     }
3539   const MEDFileUMeshSplitL1 *l1(getMeshAtLevSafe(meshDimRelToMaxExt));
3540   return l1->getRevNumberField();
3541 }
3542
3543 /*!
3544  * Returns a pointer to the node coordinates array of \a this mesh \b without
3545  * incrementing its reference counter, thus there is no need to decrRef() it by the caller.
3546  */
3547 DataArrayDouble *MEDFileUMesh::getCoords() const
3548 {
3549   checkCartesian();
3550   MCAuto<DataArrayDouble> tmp(_coords);
3551   if((DataArrayDouble *)tmp)
3552     {
3553       return tmp;
3554     }
3555   return 0;
3556 }
3557
3558 /*!
3559  * Returns a new MEDCouplingUMesh corresponding to mesh entities included in a given
3560  * group of \a this mesh. Only mesh entities of a given dimension are included in the
3561  * new mesh.
3562  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities of interest.
3563  *  \param [in] grp - the name of the group whose mesh entities are included in the
3564  *          new mesh.
3565  *  \param [in] renum - if \c true, cells and nodes of the result mesh are permuted
3566  *          according to the optional numbers of entities, if available.
3567  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
3568  *          delete this mesh using decrRef() as it is no more needed.
3569  *  \throw If the name of a nonexistent group is specified.
3570  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3571  */
3572 MEDCouplingUMesh *MEDFileUMesh::getGroup(int meshDimRelToMaxExt, const std::string& grp, bool renum) const
3573 {
3574   checkCartesian();
3575   synchronizeTinyInfoOnLeaves();
3576   std::vector<std::string> tmp(1);
3577   tmp[0]=grp;
3578   return getGroups(meshDimRelToMaxExt,tmp,renum);
3579 }
3580
3581 /*!
3582  * Returns a new MEDCouplingUMesh corresponding to mesh entities included in given
3583  * groups of \a this mesh. Only mesh entities of a given dimension are included in the
3584  * new mesh.
3585  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities of interest.
3586  *  \param [in] grps - a sequence of group names whose mesh entities are included in the
3587  *          new mesh.
3588  *  \param [in] renum - if \c true, cells and nodes of the result mesh are permuted
3589  *          according to the optional numbers of entities, if available.
3590  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
3591  *          delete this mesh using decrRef() as it is no more needed.
3592  *  \throw If a name of a nonexistent group is present in \a grps.
3593  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3594  */
3595 MEDCouplingUMesh *MEDFileUMesh::getGroups(int meshDimRelToMaxExt, const std::vector<std::string>& grps, bool renum) const
3596 {
3597   checkCartesian();
3598   synchronizeTinyInfoOnLeaves();
3599   std::vector<std::string> fams2=getFamiliesOnGroups(grps);
3600   MCAuto<MEDCouplingUMesh> zeRet=getFamilies(meshDimRelToMaxExt,fams2,renum);
3601   if(grps.size()==1 && ((MEDCouplingUMesh *)zeRet))
3602     zeRet->setName(grps[0]);
3603   return zeRet.retn();
3604 }
3605
3606 /*!
3607  * Returns a new MEDCouplingUMesh corresponding to mesh entities included in a given
3608  * family of \a this mesh. Only mesh entities of a given dimension are included in the
3609  * new mesh.
3610  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities of interest.
3611  *  \param [in] fam - the name of the family whose mesh entities are included in the
3612  *          new mesh.
3613  *  \param [in] renum - if \c true, cells and nodes of the result mesh are permuted
3614  *          according to the optional numbers of entities, if available.
3615  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
3616  *          delete this mesh using decrRef() as it is no more needed.
3617  *  \throw If a name of a nonexistent family is present in \a grps.
3618  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3619  */
3620 MEDCouplingUMesh *MEDFileUMesh::getFamily(int meshDimRelToMaxExt, const std::string& fam, bool renum) const
3621 {
3622   checkCartesian();
3623   synchronizeTinyInfoOnLeaves();
3624   std::vector<std::string> tmp(1);
3625   tmp[0]=fam;
3626   return getFamilies(meshDimRelToMaxExt,tmp,renum);
3627 }
3628
3629 /*!
3630  * Returns a new MEDCouplingUMesh corresponding to mesh entities included in given
3631  * families of \a this mesh. Only mesh entities of a given dimension are included in the
3632  * new mesh.
3633  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities of interest.
3634  *  \param [in] fams - a sequence of family names whose mesh entities are included in the
3635  *          new mesh.
3636  *  \param [in] renum - if \c true, cells and nodes of the result mesh are permuted
3637  *          according to the optional numbers of entities, if available.
3638  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
3639  *          delete this mesh using decrRef() as it is no more needed.
3640  *  \throw If a name of a nonexistent family is present in \a fams.
3641  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3642  */
3643 MEDCouplingUMesh *MEDFileUMesh::getFamilies(int meshDimRelToMaxExt, const std::vector<std::string>& fams, bool renum) const
3644 {
3645   checkCartesian();
3646   synchronizeTinyInfoOnLeaves();
3647   if(meshDimRelToMaxExt==1)
3648     {
3649       MCAuto<DataArrayIdType> arr=getFamiliesArr(1,fams,renum);
3650       MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3651       MCAuto<DataArrayDouble> c=_coords->selectByTupleId(arr->getConstPointer(),arr->getConstPointer()+arr->getNbOfElems());
3652       ret->setCoords(c);
3653       return ret.retn();
3654     }
3655   std::vector<mcIdType> famIds=getFamiliesIds(fams);
3656   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
3657   MCAuto<MEDCouplingUMesh> zeRet;
3658   if(!famIds.empty())
3659     zeRet=l1->getFamilyPart(&famIds[0],&famIds[0]+famIds.size(),renum);
3660   else
3661     zeRet=l1->getFamilyPart(0,0,renum);
3662   if(fams.size()==1 && ((MEDCouplingUMesh *)zeRet))
3663     zeRet->setName(fams[0]);
3664   return zeRet.retn();
3665 }
3666
3667 /*!
3668  * Returns ids of mesh entities contained in given families of a given dimension.
3669  *  \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids
3670  *          are required.
3671  *  \param [in] fams - the names of the families of interest.
3672  *  \param [in] renum - if \c true, the optional numbers of entities, if available, are
3673  *          returned instead of ids.
3674  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding either ids or
3675  *          numbers, if available and required, of mesh entities of the families. The caller
3676  *          is to delete this array using decrRef() as it is no more needed. 
3677  *  \throw If the family field is missing for \a meshDimRelToMaxExt.
3678  */
3679 DataArrayIdType *MEDFileUMesh::getFamiliesArr(int meshDimRelToMaxExt, const std::vector<std::string>& fams, bool renum) const
3680 {
3681   std::vector<mcIdType> famIds=getFamiliesIds(fams);
3682   if(meshDimRelToMaxExt==1)
3683     {
3684       if((const DataArrayIdType *)_fam_coords)
3685         {
3686           MCAuto<DataArrayIdType> da;
3687           if(!famIds.empty())
3688             da=_fam_coords->findIdsEqualList(&famIds[0],&famIds[0]+famIds.size());
3689           else
3690             da=_fam_coords->findIdsEqualList(0,0);
3691           if(renum)
3692             return MEDFileUMeshSplitL1::Renumber(_num_coords,da);
3693           else
3694             return da.retn();
3695         }
3696       else
3697         throw INTERP_KERNEL::Exception("MEDFileUMesh::getFamiliesArr : no family array specified on nodes !");
3698     }
3699   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
3700   if(!famIds.empty())
3701     return l1->getFamilyPartArr(&famIds[0],&famIds[0]+famIds.size(),renum);
3702   else
3703     return l1->getFamilyPartArr(0,0,renum);
3704 }
3705
3706 /*!
3707  * Returns a MEDCouplingUMesh of a given relative dimension.
3708  * \warning If \a meshDimRelToMaxExt == 1 (which means nodes), the returned mesh **is not
3709  * valid**. This is a feature, because MEDLoader does not create cells that do not exist! 
3710  * To build a valid MEDCouplingUMesh from the returned one in this case,
3711  * call MEDCouplingUMesh::Build0DMeshFromCoords().
3712  *  \param [in] meshDimRelToMaxExt - the relative dimension of interest.
3713  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
3714  *          optional numbers of mesh entities.
3715  *  \return MEDCouplingUMesh * - a pointer to MEDCouplingUMesh that the caller is to
3716  *          delete using decrRef() as it is no more needed. 
3717  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3718  */
3719 MEDCouplingUMesh *MEDFileUMesh::getMeshAtLevel(int meshDimRelToMaxExt, bool renum) const
3720 {
3721   checkCartesian();
3722   synchronizeTinyInfoOnLeaves();
3723   if(meshDimRelToMaxExt==1)
3724     {
3725       if(!renum)
3726         {
3727           MEDCouplingUMesh *umesh=MEDCouplingUMesh::New();
3728           MCAuto<DataArrayDouble> cc=_coords->deepCopy();
3729           umesh->setCoords(cc);
3730           MEDFileUMeshSplitL1::ClearNonDiscrAttributes(umesh);
3731           umesh->setName(getName());
3732           return umesh;
3733         }
3734     }
3735   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
3736   return l1->getWholeMesh(renum);
3737 }
3738
3739 std::vector<mcIdType> MEDFileUMesh::getDistributionOfTypes(int meshDimRelToMax) const
3740 {
3741   const MEDFileUMeshSplitL1 *l1(getMeshAtLevSafe(meshDimRelToMax));
3742   return l1->getDistributionOfTypes();
3743 }
3744
3745 /*!
3746  * Returns a MEDCouplingUMesh of a relative dimension == 0.
3747  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
3748  *          optional numbers of mesh entities.
3749  *  \return MEDCouplingUMesh * - a pointer to MEDCouplingUMesh that the caller is to
3750  *          delete using decrRef() as it is no more needed. 
3751  *  \throw If there are no mesh entities of the relative dimension == 0 in \a this mesh.
3752  */
3753 MEDCouplingUMesh *MEDFileUMesh::getLevel0Mesh(bool renum) const
3754 {
3755   return getMeshAtLevel(0,renum);
3756 }
3757
3758 /*!
3759  * Returns a MEDCouplingUMesh of a relative dimension == -1.
3760  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
3761  *          optional numbers of mesh entities.
3762  *  \return MEDCouplingUMesh * - a pointer to MEDCouplingUMesh that the caller is to
3763  *          delete using decrRef() as it is no more needed. 
3764  *  \throw If there are no mesh entities of the relative dimension == -1 in \a this mesh.
3765  */
3766 MEDCouplingUMesh *MEDFileUMesh::getLevelM1Mesh(bool renum) const
3767 {
3768   return getMeshAtLevel(-1,renum);
3769 }
3770
3771 /*!
3772  * Returns a MEDCouplingUMesh of a relative dimension == -2.
3773  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
3774  *          optional numbers of mesh entities.
3775  *  \return MEDCouplingUMesh * - a pointer to MEDCouplingUMesh that the caller is to
3776  *          delete using decrRef() as it is no more needed. 
3777  *  \throw If there are no mesh entities of the relative dimension == -2 in \a this mesh.
3778  */
3779 MEDCouplingUMesh *MEDFileUMesh::getLevelM2Mesh(bool renum) const
3780 {
3781   return getMeshAtLevel(-2,renum);
3782 }
3783
3784 /*!
3785  * Returns a MEDCouplingUMesh of a relative dimension == -3.
3786  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
3787  *          optional numbers of mesh entities.
3788  *  \return MEDCouplingUMesh * - a pointer to MEDCouplingUMesh that the caller is to
3789  *          delete using decrRef() as it is no more needed. 
3790  *  \throw If there are no mesh entities of the relative dimension == -3 in \a this mesh.
3791  */
3792 MEDCouplingUMesh *MEDFileUMesh::getLevelM3Mesh(bool renum) const
3793 {
3794   return getMeshAtLevel(-3,renum);
3795 }
3796
3797 /*!
3798  * This method is for advanced users. There is two storing strategy of mesh in \a this.
3799  * Either MEDCouplingUMesh, or vector of MEDCoupling1GTUMesh instances.
3800  * When assignment is done the first one is done, which is not optimal in write mode for MED file.
3801  * This method allows to switch from MEDCouplingUMesh mode to MEDCoupling1GTUMesh mode.
3802  */
3803 void MEDFileUMesh::forceComputationOfParts() const
3804 {
3805   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
3806     {
3807       const MEDFileUMeshSplitL1 *elt(*it);
3808       if(elt)
3809         elt->forceComputationOfParts();
3810     }
3811 }
3812
3813 /*!
3814  * This method returns a vector of mesh parts containing each exactly one geometric type.
3815  * This method will never launch an automatic computation of split by type (an INTERP_KERNEL::Exception will be then thrown).
3816  * This method is only for memory aware users.
3817  * The returned pointers are **NOT** new object pointer. No need to mange them.
3818  */
3819 std::vector<MEDCoupling1GTUMesh *> MEDFileUMesh::getDirectUndergroundSingleGeoTypeMeshes(int meshDimRelToMax) const
3820 {
3821   checkCartesian();
3822   const MEDFileUMeshSplitL1 *sp(getMeshAtLevSafe(meshDimRelToMax));
3823   return sp->getDirectUndergroundSingleGeoTypeMeshes();
3824 }
3825
3826 /*!
3827  * This method returns the part of \a this having the geometric type \a gt.
3828  * If such part is not existing an exception will be thrown.
3829  * The returned pointer is **NOT** new object pointer. No need to mange it.
3830  */
3831 MEDCoupling1GTUMesh *MEDFileUMesh::getDirectUndergroundSingleGeoTypeMesh(INTERP_KERNEL::NormalizedCellType gt) const
3832 {
3833   checkCartesian();
3834   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(gt));
3835   int lev=(int)cm.getDimension()-getMeshDimension();
3836   const MEDFileUMeshSplitL1 *sp(getMeshAtLevSafe(lev));
3837   return sp->getDirectUndergroundSingleGeoTypeMesh(gt);
3838 }
3839
3840 /*!
3841  * This method returns for each geo types in \a this number of cells with this geo type.
3842  * This method returns info as a vector of pair. The first element of pair is geo type and the second the number of cells associated.
3843  * This method also returns the number of nodes of \a this (key associated is NORM_ERROR)
3844  *
3845  * \sa getDistributionOfTypes
3846  */
3847 std::vector< std::pair<int,mcIdType> > MEDFileUMesh::getAllDistributionOfTypes() const
3848 {
3849   std::vector< std::pair<int,mcIdType> > ret;
3850   std::vector<int> nel(getNonEmptyLevels());
3851   for(std::vector<int>::reverse_iterator it=nel.rbegin();it!=nel.rend();it++)
3852     {
3853       std::vector<INTERP_KERNEL::NormalizedCellType> gt(getGeoTypesAtLevel(*it));
3854       for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it1=gt.begin();it1!=gt.end();it1++)
3855         {
3856           mcIdType nbCells(getNumberOfCellsWithType(*it1));
3857           ret.push_back(std::pair<int,mcIdType>(*it1,nbCells));
3858         }
3859     }
3860   ret.push_back(std::pair<int,mcIdType>(INTERP_KERNEL::NORM_ERROR,getNumberOfNodes()));
3861   return ret;
3862 }
3863
3864 /*!
3865  * Given a relative level \a meshDimRelToMax it returns the sorted vector of geometric types present in \a this.
3866  * \throw if the reqsuested \a meshDimRelToMax does not exist.
3867  */
3868 std::vector<INTERP_KERNEL::NormalizedCellType> MEDFileUMesh::getGeoTypesAtLevel(int meshDimRelToMax) const
3869 {
3870   const MEDFileUMeshSplitL1 *sp(getMeshAtLevSafe(meshDimRelToMax));
3871   return sp->getGeoTypes();
3872 }
3873
3874 mcIdType MEDFileUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType ct) const
3875 {
3876   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(ct);
3877   const MEDFileUMeshSplitL1 *sp(getMeshAtLevSafe( ((int)cm.getDimension())-getMeshDimension() ));
3878   return sp->getNumberOfCellsWithType(ct);
3879 }
3880
3881 /*!
3882  * This method extracts from whole family field ids the part relative to the input parameter \a gt.
3883  * \param [in] gt - the geometric type for which the family field is asked.
3884  * \return DataArrayIdType * - a pointer to DataArrayIdType that the caller is to
3885  *          delete using decrRef() as it is no more needed.
3886  * \sa MEDFileUMesh::extractNumberFieldOnGeoType
3887  */
3888 DataArrayIdType *MEDFileUMesh::extractFamilyFieldOnGeoType(INTERP_KERNEL::NormalizedCellType gt) const
3889 {
3890   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(gt);
3891   int lev=(int)cm.getDimension()-getMeshDimension();
3892   const MEDFileUMeshSplitL1 *sp(getMeshAtLevSafe(lev));
3893   return sp->extractFamilyFieldOnGeoType(gt);
3894 }
3895
3896 /*!
3897  * This method extracts from whole number field ids the part relative to the input parameter \a gt.
3898  * \param [in] gt - the geometric type for which the number field is asked.
3899  * \return DataArrayIdType * - a pointer to DataArrayIdType that the caller is to
3900  *          delete using decrRef() as it is no more needed.
3901  * \sa MEDFileUMesh::extractFamilyFieldOnGeoType
3902  */
3903 DataArrayIdType *MEDFileUMesh::extractNumberFieldOnGeoType(INTERP_KERNEL::NormalizedCellType gt) const
3904 {
3905   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(gt);
3906   int lev=(int)cm.getDimension()-getMeshDimension();
3907   const MEDFileUMeshSplitL1 *sp(getMeshAtLevSafe(lev));
3908   return sp->extractNumberFieldOnGeoType(gt);
3909 }
3910
3911 /*!
3912  * This method returns for specified geometric type \a gt the relative level to \a this.
3913  * If the relative level is empty an exception will be thrown.
3914  */
3915 int MEDFileUMesh::getRelativeLevOnGeoType(INTERP_KERNEL::NormalizedCellType gt) const
3916 {
3917   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(gt);
3918   int ret((int)cm.getDimension()-getMeshDimension());
3919   getMeshAtLevSafe(ret);//To test that returned value corresponds to a valid level.
3920   return ret;
3921 }
3922
3923 const MEDFileUMeshSplitL1 *MEDFileUMesh::getMeshAtLevSafe(int meshDimRelToMaxExt) const
3924 {
3925   if(meshDimRelToMaxExt==1)
3926     throw INTERP_KERNEL::Exception("Dimension request is invalid : asking for node level (1) !");
3927   if(meshDimRelToMaxExt>1)
3928     throw INTERP_KERNEL::Exception("Dimension request is invalid (>1) !");
3929   int tracucedRk=-meshDimRelToMaxExt;
3930   if(tracucedRk>=(int)_ms.size())
3931     throw INTERP_KERNEL::Exception("Invalid mesh dim relative to max given ! Too low !");
3932   if((const MEDFileUMeshSplitL1 *)_ms[tracucedRk]==0)
3933     throw INTERP_KERNEL::Exception("On specified lev (or entity) no cells exists !");
3934   return _ms[tracucedRk];
3935 }
3936
3937 MEDFileUMeshSplitL1 *MEDFileUMesh::getMeshAtLevSafe(int meshDimRelToMaxExt)
3938 {
3939   if(meshDimRelToMaxExt==1)
3940     throw INTERP_KERNEL::Exception("Dimension request is invalid : asking for node level (1) !");
3941   if(meshDimRelToMaxExt>1)
3942     throw INTERP_KERNEL::Exception("Dimension request is invalid (>1) !");
3943   int tracucedRk=-meshDimRelToMaxExt;
3944   if(tracucedRk>=(int)_ms.size())
3945     throw INTERP_KERNEL::Exception("Invalid mesh dim relative to max given ! Too low !");
3946   if((const MEDFileUMeshSplitL1 *)_ms[tracucedRk]==0)
3947     throw INTERP_KERNEL::Exception("On specified lev (or entity) no cells exists !");
3948   return _ms[tracucedRk];
3949 }
3950
3951 void MEDFileUMesh::checkMeshDimCoherency(int meshDim, int meshDimRelToMax) const
3952 {
3953   if(-meshDimRelToMax>=(int)_ms.size())
3954     throw INTERP_KERNEL::Exception("MEDFileUMesh::checkMeshDimCoherency : The meshdim of mesh is not managed by 'this' !");
3955   int i=0;
3956   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,i++)
3957     {
3958       if(((const MEDFileUMeshSplitL1*) (*it))!=0)
3959         {
3960           int ref=(*it)->getMeshDimension();
3961           if(ref+i!=meshDim-meshDimRelToMax)
3962             throw INTERP_KERNEL::Exception("MEDFileUMesh::checkMeshDimCoherency : no coherency between levels !");
3963         }
3964     }
3965 }
3966
3967 /*!
3968  * Sets the node coordinates array of \a this mesh.
3969  *  \param [in] coords - the new node coordinates array.
3970  *  \throw If \a coords == \c NULL.
3971  */
3972 void MEDFileUMesh::setCoords(DataArrayDouble *coords)
3973 {
3974   if(!coords)
3975     throw INTERP_KERNEL::Exception("MEDFileUMesh::setCoords : null pointer in input !");
3976   if(coords==(DataArrayDouble *)_coords)
3977     return ;
3978   coords->checkAllocated();
3979   mcIdType nbOfTuples(coords->getNumberOfTuples());
3980   _coords.takeRef(coords);
3981   _fam_coords=DataArrayIdType::New();
3982   _fam_coords->alloc(nbOfTuples,1);
3983   _fam_coords->fillWithZero();
3984   _num_coords.nullify(); _rev_num_coords.nullify(); _name_coords.nullify(); _global_num_coords.nullify();
3985   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::iterator it=_ms.begin();it!=_ms.end();it++)
3986     if((MEDFileUMeshSplitL1 *)(*it))
3987       (*it)->setCoords(coords);
3988 }
3989
3990 /*!
3991  * Change coords without changing anything concerning families and numbering on nodes.
3992  */
3993 void MEDFileUMesh::setCoordsForced(DataArrayDouble *coords)
3994 {
3995   if(!coords)
3996     throw INTERP_KERNEL::Exception("MEDFileUMesh::setCoordsForced : null pointer in input !");
3997   if(coords==(DataArrayDouble *)_coords)
3998     return ;
3999   coords->checkAllocated();
4000   mcIdType nbOfTuples(coords->getNumberOfTuples());
4001   if(_coords.isNull())
4002     {
4003       _coords=coords;
4004       coords->incrRef();
4005     }
4006   else
4007     {
4008       mcIdType oldNbTuples(_coords->getNumberOfTuples());
4009       if(oldNbTuples!=nbOfTuples)
4010         throw INTERP_KERNEL::Exception("MEDFileUMesh::setCoordsForced : number of tuples is not the same -> invoke setCoords instead !");
4011       _coords=coords;
4012       coords->incrRef();
4013     }
4014   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::iterator it=_ms.begin();it!=_ms.end();it++)
4015     if((MEDFileUMeshSplitL1 *)(*it))
4016       (*it)->setCoords(coords);
4017 }
4018
4019 /*!
4020  * Removes all groups of a given dimension in \a this mesh.
4021  *  \param [in] meshDimRelToMaxExt - the relative dimension of interest.
4022  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
4023  */
4024 void MEDFileUMesh::eraseGroupsAtLevel(int meshDimRelToMaxExt)
4025 {
4026   if(meshDimRelToMaxExt==1)
4027     {
4028       if((DataArrayIdType *)_fam_coords)
4029         _fam_coords->fillWithZero();
4030       return ;
4031     }
4032   MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
4033   l1->eraseFamilyField();
4034   optimizeFamilies();
4035 }
4036
4037 /*!
4038  * Removes all families with ids not present in the family fields of \a this mesh.
4039  */
4040 void MEDFileUMesh::optimizeFamilies()
4041 {
4042   std::vector<int> levs=getNonEmptyLevelsExt();
4043   std::set<mcIdType> allFamsIds;
4044   for(std::vector<int>::const_iterator it=levs.begin();it!=levs.end();it++)
4045     {
4046       const DataArrayIdType *ffield=getFamilyFieldAtLevel(*it);
4047       MCAuto<DataArrayIdType> ids=ffield->getDifferentValues();
4048       std::set<mcIdType> res;
4049       std::set_union(ids->begin(),ids->end(),allFamsIds.begin(),allFamsIds.end(),std::inserter(res,res.begin()));
4050       allFamsIds=res;
4051     }
4052   std::set<std::string> famNamesToKill;
4053   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
4054     {
4055       if(allFamsIds.find((*it).second)!=allFamsIds.end())
4056         famNamesToKill.insert((*it).first);
4057     }
4058   for(std::set<std::string>::const_iterator it=famNamesToKill.begin();it!=famNamesToKill.end();it++)
4059     _families.erase(*it);
4060   std::vector<std::string> grpNamesToKill;
4061   for(std::map<std::string, std::vector<std::string> >::iterator it=_groups.begin();it!=_groups.end();it++)
4062     {
4063       std::vector<std::string> tmp;
4064       for(std::vector<std::string>::const_iterator it2=(*it).second.begin();it2!=(*it).second.end();it2++)
4065         {
4066           if(famNamesToKill.find(*it2)==famNamesToKill.end())
4067             tmp.push_back(*it2);
4068         }
4069       if(!tmp.empty())
4070         (*it).second=tmp;
4071       else
4072         tmp.push_back((*it).first);
4073     }
4074   for(std::vector<std::string>::const_iterator it=grpNamesToKill.begin();it!=grpNamesToKill.end();it++)
4075     _groups.erase(*it);
4076 }
4077
4078 /**
4079  * \b this must be filled at level 0 and -1, typically the -1 level being (part of) the descending connectivity
4080  * of the top level. This method build a "crack", or an inner boundary, in \b this along the group of level -1 named grpNameM1.
4081  * The boundary is built according to the following method:
4082  *  - all nodes along the boundary which are not lying on an internal extremity of the (-1)-level group are duplicated (so the
4083  * coordinates array is extended).
4084  *  - new (-1)-level cells are built lying on those new nodes. So the edges/faces along the group are duplicated. A new group
4085  *  called "<grpNameM1>_dup" containing the effectively duplicated cells is created. Note that in 3D some cells of the group
4086  *  might not be duplicated at all.
4087  *  After this operation a top-level cell bordering the group will loose some neighbors (typically the cell which is  on the
4088  *  other side of the group is no more a neighbor)
4089  *   - finally, the connectivity of (part of) the top level-cells bordering the group is also modified so that some cells
4090  *  bordering the newly created boundary use the newly computed nodes.
4091  *  Finally note that optional cell numbers are also affected by this method and might become invalid for SMESH.
4092  *  Use clearNodeAndCellNumbers() afterwards to ensure a proper SMESH loading.
4093  *
4094  *  \param[in] grpNameM1 name of the (-1)-level group defining the boundary
4095  *  \param[out] nodesDuplicated ids of the initial nodes which have been duplicated (and whose copy is put at the end of
4096  *  the coord array)
4097  *  \param[out] cellsModified ids of the cells whose connectivity has been modified (to use the newly created nodes)
4098  *  \param[out] cellsNotModified ids of the rest of cells bordering the new boundary whose connectivity remains unchanged.
4099  *  \sa clearNodeAndCellNumbers()
4100  */
4101 void MEDFileUMesh::buildInnerBoundaryAlongM1Group(const std::string& grpNameM1, DataArrayIdType *&nodesDuplicated,
4102                                            DataArrayIdType *&cellsModified, DataArrayIdType *&cellsNotModified)
4103 {
4104   typedef MCAuto<MEDCouplingUMesh> MUMesh;
4105   typedef MCAuto<DataArrayIdType> DAInt;
4106
4107   std::vector<int> levs=getNonEmptyLevels();
4108   if(std::find(levs.begin(),levs.end(),0)==levs.end() || std::find(levs.begin(),levs.end(),-1)==levs.end())
4109     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group : This method works only for mesh defined on level 0 and -1 !");
4110   MUMesh m0=getMeshAtLevel(0);
4111   MUMesh m1=getMeshAtLevel(-1);
4112   mcIdType nbNodes=m0->getNumberOfNodes();
4113   MUMesh m11=getGroup(-1,grpNameM1);
4114   DataArrayIdType *tmp00=0,*tmp11=0,*tmp22=0;
4115   m0->findNodesToDuplicate(*m11,tmp00,tmp11,tmp22);
4116   DAInt nodeIdsToDuplicate(tmp00);
4117   DAInt cellsToModifyConn0(tmp11);
4118   DAInt cellsToModifyConn1(tmp22);
4119   MUMesh tmp0=static_cast<MEDCouplingUMesh *>(m0->buildPartOfMySelf(cellsToModifyConn0->begin(),cellsToModifyConn0->end(),true));
4120   // node renumbering of cells in m1 impacted by duplication of node but not in group 'grpNameM1' on level -1
4121   DAInt descTmp0=DataArrayIdType::New(),descITmp0=DataArrayIdType::New(),revDescTmp0=DataArrayIdType::New(),revDescITmp0=DataArrayIdType::New();
4122   MUMesh tmp0Desc=tmp0->buildDescendingConnectivity(descTmp0,descITmp0,revDescTmp0,revDescITmp0);
4123   descTmp0=0; descITmp0=0; revDescTmp0=0; revDescITmp0=0;
4124   DAInt cellsInM1ToRenumW2=tmp0Desc->getCellIdsLyingOnNodes(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end(),false);
4125   MUMesh cellsInM1ToRenumW3=static_cast<MEDCouplingUMesh *>(tmp0Desc->buildPartOfMySelf(cellsInM1ToRenumW2->begin(),cellsInM1ToRenumW2->end(),true));
4126   DataArrayIdType *cellsInM1ToRenumW4Tmp=0;
4127   m1->areCellsIncludedIn(cellsInM1ToRenumW3,2,cellsInM1ToRenumW4Tmp);
4128   DAInt cellsInM1ToRenumW4(cellsInM1ToRenumW4Tmp);
4129   DAInt cellsInM1ToRenumW5=cellsInM1ToRenumW4->findIdsInRange(0,m1->getNumberOfCells());
4130   cellsInM1ToRenumW5->transformWithIndArr(cellsInM1ToRenumW4->begin(),cellsInM1ToRenumW4->end());
4131   DAInt grpIds=getGroupArr(-1,grpNameM1);
4132   DAInt cellsInM1ToRenum=cellsInM1ToRenumW5->buildSubstraction(grpIds);
4133   MUMesh m1Part=static_cast<MEDCouplingUMesh *>(m1->buildPartOfMySelf(cellsInM1ToRenum->begin(),cellsInM1ToRenum->end(),true));
4134   m1Part->duplicateNodesInConn(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end(),nbNodes);
4135   m1->setPartOfMySelf(cellsInM1ToRenum->begin(),cellsInM1ToRenum->end(),*m1Part);
4136   // end of node renumbering of cells in m1 impacted by duplication of node but not in group of level -1 'grpNameM1'
4137   tmp0->duplicateNodes(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end());
4138   m0->setCoords(tmp0->getCoords());
4139   m0->setPartOfMySelf(cellsToModifyConn0->begin(),cellsToModifyConn0->end(),*tmp0);
4140   _ms[0]->forceComputationOfParts();  // necessary because we modify the connectivity of some internal part
4141   m1->setCoords(m0->getCoords());
4142   _coords=m0->getCoords(); _coords->incrRef();
4143   // duplication of cells in group 'grpNameM1' on level -1, but not duplicating cells for which nothing has changed
4144   m11->duplicateNodesInConn(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end(),nbNodes); m11->setCoords(m0->getCoords());
4145   DataArrayIdType * duplCells;
4146   m1->areCellsIncludedIn(m11, 0, duplCells);
4147   DAInt zeIds = duplCells->findIdsNotInRange(-1, m1->getNumberOfCells()-1); duplCells->decrRef();
4148   MUMesh m11Part=static_cast<MEDCouplingUMesh *>(m11->buildPartOfMySelf(zeIds->begin(),zeIds->end(),true));
4149   std::vector<const MEDCouplingUMesh *> v(2); v[0]=m1; v[1]=m11Part;
4150   MUMesh newm1=MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(v,tmp00,tmp11);
4151   DAInt szOfCellGrpOfSameType(tmp00);
4152   DAInt idInMsOfCellGrpOfSameType(tmp11);
4153   //
4154   newm1->setName(getName());
4155   const DataArrayIdType *fam=getFamilyFieldAtLevel(-1);
4156   if(!fam)
4157     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group(): internal error no family field !");
4158   DAInt newFam=DataArrayIdType::New();
4159   newFam->alloc(newm1->getNumberOfCells(),1);
4160   // Get a new family ID: care must be taken if we need a positive ID or a negative one:
4161   // Positive ID for family of nodes, negative for all the rest.
4162   mcIdType idd;
4163   if (m1->getMeshDimension() == 0)
4164     idd=getMaxFamilyId()+1;
4165   else
4166     idd=getMinFamilyId()-1;
4167   mcIdType globStart=0,start=0,end,globEnd;
4168   mcIdType nbOfChunks=szOfCellGrpOfSameType->getNumberOfTuples();
4169   for(mcIdType i=0;i<nbOfChunks;i++)
4170     {
4171       globEnd=globStart+szOfCellGrpOfSameType->getIJ(i,0);
4172       if(idInMsOfCellGrpOfSameType->getIJ(i,0)==0)
4173         {
4174           end=start+szOfCellGrpOfSameType->getIJ(i,0);
4175           DAInt part=fam->selectByTupleIdSafeSlice(start,end,1);
4176           newFam->setPartOfValues1(part,globStart,globEnd,1,0,1,1,true);
4177           start=end;
4178         }
4179       else
4180         {
4181           newFam->setPartOfValuesSimple1(idd,globStart,globEnd,1,0,1,1);
4182         }
4183       globStart=globEnd;
4184     }
4185   newm1->setCoords(getCoords());
4186   setMeshAtLevel(-1,newm1);
4187   setFamilyFieldArr(-1,newFam);
4188   std::string grpName2(grpNameM1); grpName2+="_dup";
4189   addFamily(grpName2,idd);
4190   addFamilyOnGrp(grpName2,grpName2);
4191   //
4192   fam=_fam_coords;
4193   if(fam)
4194     {
4195       mcIdType newNbOfNodes=getCoords()->getNumberOfTuples();
4196       newFam=DataArrayIdType::New(); newFam->alloc(newNbOfNodes,1);
4197       newFam->setPartOfValues1(fam,0,nbNodes,1,0,1,1,true);
4198       newFam->setPartOfValuesSimple1(0,nbNodes,newNbOfNodes,1,0,1,1);
4199       _fam_coords=newFam;
4200     }
4201
4202   _num_coords.nullify(); _rev_num_coords.nullify(); _global_num_coords.nullify();
4203   
4204   for (std::vector< MCAuto<MEDFileUMeshSplitL1> >::iterator it=_ms.begin();
4205       it != _ms.end(); it++)
4206     {
4207       (*it)->_num = 0;
4208       (*it)->_rev_num = 0;
4209     }
4210   nodesDuplicated=nodeIdsToDuplicate.retn();
4211   cellsModified=cellsToModifyConn0.retn();
4212   cellsNotModified=cellsToModifyConn1.retn();
4213 }
4214
4215 /*! Similar to MEDCouplingUMesh::unPolyze():  converts all polygons (if \a this is a 2D mesh) or polyhedrons
4216  * (if \a this is a 3D mesh) to cells of classical types. The cells remain correctly sorted by geometric type
4217  * in this method.
4218  *
4219  * \param [out] oldCode retrieves the distribution of types before the call if true is returned
4220  * \param [out] newCode retrieves the distribution of types after the call if true is returned
4221  * \param [out] o2nRenumCell tells for **all levels** the old 2 new renumbering of cells.
4222  * 
4223  * \return false if no modification has been performed linked to the unpolyzation. Neither cell type, not cell numbers. When false is returned no need of field on cells or on gauss renumbering.
4224  * Inversely, if true is returned, it means that distribution of cell by geometric type has changed and field on cell and field on gauss point must be renumbered.
4225  */
4226 bool MEDFileUMesh::unPolyze(std::vector<mcIdType>& oldCode, std::vector<mcIdType>& newCode, DataArrayIdType *& o2nRenumCell)
4227 {
4228   o2nRenumCell=0; oldCode.clear(); newCode.clear();
4229   std::vector<int> levs=getNonEmptyLevels();
4230   bool ret=false;
4231   std::vector< const DataArrayIdType* > renumCellsSplited;//same than memorySaverIfThrow
4232   std::vector< MCAuto<DataArrayIdType> > memorySaverIfThrow;//same than renumCellsSplited only in case of throw
4233   mcIdType start=0;
4234   mcIdType end=0;
4235   for(std::vector<int>::reverse_iterator it=levs.rbegin();it!=levs.rend();it++)
4236     {
4237       MCAuto<MEDCouplingUMesh> m=getMeshAtLevel(*it);
4238       std::vector<mcIdType> code1=m->getDistributionOfTypes();
4239       end=PutInThirdComponentOfCodeOffset(code1,start);
4240       oldCode.insert(oldCode.end(),code1.begin(),code1.end());
4241       bool hasChanged=m->unPolyze();
4242       DataArrayIdType *fake=0;
4243       MCAuto<DataArrayIdType> o2nCellsPart=m->getLevArrPerCellTypes(MEDCouplingUMesh::MEDMEM_ORDER,
4244           MEDCouplingUMesh::MEDMEM_ORDER+MEDCouplingUMesh::N_MEDMEM_ORDER,fake);
4245       fake->decrRef();
4246       renumCellsSplited.push_back(o2nCellsPart); memorySaverIfThrow.push_back(o2nCellsPart);
4247       if(hasChanged)
4248         {
4249           MCAuto<DataArrayIdType> o2nCellsPart2=o2nCellsPart->buildPermArrPerLevel();
4250           m->renumberCells(o2nCellsPart2->getConstPointer(),false);
4251           ret=true;
4252           MCAuto<DataArrayIdType> famField2,numField2;
4253           const DataArrayIdType *famField=getFamilyFieldAtLevel(*it); if(famField) { famField->incrRef(); famField2=const_cast<DataArrayIdType *>(famField); }
4254           const DataArrayIdType *numField=getNumberFieldAtLevel(*it); if(numField) { numField->incrRef(); numField2=const_cast<DataArrayIdType *>(numField); }
4255           setMeshAtLevel(*it,m);
4256           std::vector<mcIdType> code2=m->getDistributionOfTypes();
4257           end=PutInThirdComponentOfCodeOffset(code2,start);
4258           newCode.insert(newCode.end(),code2.begin(),code2.end());
4259           //
4260           if(o2nCellsPart2->isIota(o2nCellsPart2->getNumberOfTuples()))
4261             continue;
4262           if(famField)
4263             {
4264               MCAuto<DataArrayIdType> newFamField=famField->renumber(o2nCellsPart2->getConstPointer());
4265               setFamilyFieldArr(*it,newFamField);
4266             }
4267           if(numField)
4268             {
4269               MCAuto<DataArrayIdType> newNumField=numField->renumber(o2nCellsPart2->getConstPointer());
4270               setRenumFieldArr(*it,newNumField);
4271             }
4272         }
4273       else
4274         {
4275           newCode.insert(newCode.end(),code1.begin(),code1.end());
4276         }
4277       start=end;
4278     }
4279   if(ret)
4280     {
4281       MCAuto<DataArrayIdType> renumCells=DataArrayIdType::Aggregate(renumCellsSplited);
4282       MCAuto<DataArrayIdType> o2nRenumCellRet=renumCells->buildPermArrPerLevel();
4283       o2nRenumCell=o2nRenumCellRet.retn();
4284     }
4285   return ret;
4286 }
4287
4288 /*! \cond HIDDEN_ITEMS */
4289 struct MEDLoaderAccVisit1
4290 {
4291   MEDLoaderAccVisit1():_new_nb_of_nodes(0) { }
4292   mcIdType operator()(bool val) { return val?_new_nb_of_nodes++:-1; }
4293   mcIdType _new_nb_of_nodes;
4294 };
4295 /*! \endcond */
4296
4297 /*!
4298  * Array returned is the correspondence in \b old \b to \b new format. The returned array is newly created and should be dealt by the caller.
4299  * The maximum value stored in returned array is the number of nodes of \a this minus 1 after call of this method.
4300  * The size of returned array is the number of nodes of the old (previous to the call of this method) number of nodes.
4301  * -1 values in returned array means that the corresponding old node is no more used.
4302  *
4303  * \return newly allocated array containing correspondence in \b old \b to \b new format. If all nodes in \a this are fetched \c NULL pointer is returned and nothing
4304  *         is modified in \a this.
4305  * \throw If no coordinates are set in \a this or if there is in any available mesh in \a this a cell having a nodal connectivity containing a node id not in the range of
4306  *  set coordinates.
4307  */
4308 DataArrayIdType *MEDFileUMesh::zipCoords()
4309 {
4310   const DataArrayDouble *coo(getCoords());
4311   if(!coo)
4312     throw INTERP_KERNEL::Exception("MEDFileUMesh::zipCoords : no coordinates set in this !");
4313   mcIdType nbOfNodes(coo->getNumberOfTuples());
4314   std::vector<bool> nodeIdsInUse(nbOfNodes,false);
4315   std::vector<int> neLevs(getNonEmptyLevels());
4316   for(std::vector<int>::const_iterator lev=neLevs.begin();lev!=neLevs.end();lev++)
4317     {
4318       const MEDFileUMeshSplitL1 *zeLev(getMeshAtLevSafe(*lev));
4319       if(zeLev->isMeshStoredSplitByType())
4320         {
4321           std::vector<MEDCoupling1GTUMesh *> ms(zeLev->getDirectUndergroundSingleGeoTypeMeshes());
4322           for(std::vector<MEDCoupling1GTUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
4323             if(*it)
4324               (*it)->computeNodeIdsAlg(nodeIdsInUse);
4325         }
4326       else
4327         {
4328           MCAuto<MEDCouplingUMesh> mesh(zeLev->getWholeMesh(false));
4329           mesh->computeNodeIdsAlg(nodeIdsInUse);
4330         }
4331     }
4332   mcIdType nbrOfNodesInUse((mcIdType)std::count(nodeIdsInUse.begin(),nodeIdsInUse.end(),true));
4333   if(nbrOfNodesInUse==nbOfNodes)
4334     return 0;//no need to update _part_coords
4335   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfNodes,1);
4336   std::transform(nodeIdsInUse.begin(),nodeIdsInUse.end(),ret->getPointer(),MEDLoaderAccVisit1());
4337   MCAuto<DataArrayIdType> ret2(ret->invertArrayO2N2N2OBis(nbrOfNodesInUse));
4338   MCAuto<DataArrayDouble> newCoords(coo->selectByTupleIdSafe(ret2->begin(),ret2->end()));
4339   MCAuto<DataArrayIdType> newFamCoords;
4340   MCAuto<DataArrayAsciiChar> newNameCoords;
4341   if((const DataArrayIdType *)_fam_coords)
4342     newFamCoords=_fam_coords->selectByTupleIdSafe(ret2->begin(),ret2->end());
4343   MCAuto<DataArrayIdType> newNumCoords,newGlobalNumCoords;
4344   if(_num_coords.isNotNull())
4345     newNumCoords=_num_coords->selectByTupleIdSafe(ret2->begin(),ret2->end());
4346   if(_global_num_coords.isNotNull())
4347     newGlobalNumCoords=_global_num_coords->selectByTupleIdSafe(ret2->begin(),ret2->end());
4348   if(_name_coords.isNotNull())
4349     newNameCoords=static_cast<DataArrayAsciiChar *>(_name_coords->selectByTupleIdSafe(ret2->begin(),ret2->end()));
4350   _coords=newCoords; _fam_coords=newFamCoords; _num_coords=newNumCoords; _global_num_coords=newGlobalNumCoords; _name_coords=newNameCoords; _rev_num_coords.nullify();
4351   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::iterator it=_ms.begin();it!=_ms.end();it++)
4352     {
4353       if((MEDFileUMeshSplitL1*)*it)
4354         {
4355           (*it)->renumberNodesInConn(ret->begin());
4356           (*it)->setCoords(_coords);
4357         }
4358     }
4359   // updates _part_coords
4360   const PartDefinition *pc(_part_coords);
4361   if(pc)
4362     {
4363       MCAuto<PartDefinition> tmpPD(DataArrayPartDefinition::New(ret2));
4364       _part_coords=tmpPD->composeWith(pc);
4365     }
4366   return ret.retn();
4367 }
4368
4369 /*!
4370  * This method is the extension of MEDCouplingUMesh::computeFetchedNodeIds. Except that here all levels are considered here.
4371  * 
4372  * \return newly allocated array containing all nodes in \a this that are part of nodal connectivity of at least one cell in \a this whatever its level.
4373  */
4374 DataArrayIdType *MEDFileUMesh::computeFetchedNodeIds() const
4375 {
4376   std::vector<int> neLevs(this->getNonEmptyLevels());
4377   std::vector<bool> nodesHighlighted(this->getNumberOfNodes(),false);
4378   for(auto lev : neLevs)
4379   {
4380     const MEDFileUMeshSplitL1 *zeLev(this->getMeshAtLevSafe(lev));
4381     zeLev->highlightUsedNodes(nodesHighlighted);
4382   }
4383   return DataArrayIdType::BuildListOfSwitchedOn(nodesHighlighted);
4384 }
4385
4386 /*!
4387  * This method is a const method. It computes the minimal set of node ids covered by the cell extraction of \a this.
4388  * The extraction of \a this is specified by the extractDef \a input map.
4389  * This map tells for each level of cells, the cells kept in the extraction.
4390  * 
4391  * \return - a new reference of DataArrayIdType that represents sorted node ids, the extraction is lying on.
4392  * \sa MEDFileField1TS::extractPart, MEDFileUMesh::extractPart
4393  */
4394 DataArrayIdType *MEDFileUMesh::deduceNodeSubPartFromCellSubPart(const std::map<int, MCAuto<DataArrayIdType> >& extractDef) const
4395 {
4396   std::vector<int> levs(getNonEmptyLevels());
4397   std::vector<bool> fetchedNodes(getNumberOfNodes(),false);
4398   for(std::map<int, MCAuto<DataArrayIdType> >::const_iterator it=extractDef.begin();it!=extractDef.end();it++)
4399     {
4400       if((*it).first>1)
4401         throw INTERP_KERNEL::Exception("MEDFileUMesh::deduceNodeSubPartFromCellSubPart : invalid key ! Must be <=1 !");
4402       if((*it).second.isNull())
4403         throw INTERP_KERNEL::Exception("MEDFileUMesh::deduceNodeSubPartFromCellSubPart : presence of a value with null pointer !");
4404       if((*it).first==1)
4405         continue;
4406       if(std::find(levs.begin(),levs.end(),(*it).first)==levs.end())
4407         {
4408           std::ostringstream oss; oss << "MEDFileUMesh::deduceNodeSubPartFromCellSubPart : invalid level " << (*it).first << " ! Not present in this !";
4409           throw INTERP_KERNEL::Exception(oss.str());
4410         }
4411       MCAuto<MEDCouplingUMesh> m(getMeshAtLevel((*it).first));
4412       MCAuto<MEDCouplingUMesh> mPart(m->buildPartOfMySelf((*it).second->begin(),(*it).second->end(),true));
4413       mPart->computeNodeIdsAlg(fetchedNodes);
4414     }
4415   return DataArrayIdType::BuildListOfSwitchedOn(fetchedNodes);
4416 }
4417
4418 /*!
4419  * This method returns a new MEDFileUMesh that is the result of the extraction of cells/nodes in \a this.
4420  * 
4421  * \return - a new reference of MEDFileUMesh
4422  * \sa MEDFileUMesh::deduceNodeSubPartFromCellSubPart, MEDFileFields::extractPart
4423  */
4424 MEDFileUMesh *MEDFileUMesh::extractPart(const std::map<int, MCAuto<DataArrayIdType> >& extractDef) const
4425 {
4426   MCAuto<MEDFileUMesh> ret(MEDFileUMesh::New()); ret->setName(getName()); ret->copyFamGrpMapsFrom(*this);
4427   std::vector<int> levs(getNonEmptyLevels());
4428   for(std::map<int, MCAuto<DataArrayIdType> >::const_iterator it=extractDef.begin();it!=extractDef.end();it++)
4429     {
4430       if((*it).first>1)
4431         throw INTERP_KERNEL::Exception("MEDFileUMesh::extractPart : invalid key ! Must be <=1 !");
4432       if((*it).second.isNull())
4433         throw INTERP_KERNEL::Exception("MEDFileUMesh::extractPart : presence of a value with null pointer !");
4434       if((*it).first==1)
4435         continue;
4436       if(std::find(levs.begin(),levs.end(),(*it).first)==levs.end())
4437         {
4438           std::ostringstream oss; oss << "MEDFileUMesh::extractPart : invalid level " << (*it).first << " ! Not present in this !";
4439           throw INTERP_KERNEL::Exception(oss.str());
4440         }
4441       MCAuto<MEDCouplingUMesh> m(getMeshAtLevel((*it).first));
4442       MCAuto<MEDCouplingUMesh> mPart(m->buildPartOfMySelf((*it).second->begin(),(*it).second->end(),true));
4443       ret->setMeshAtLevel((*it).first,mPart);
4444       const DataArrayIdType *fam(getFamilyFieldAtLevel((*it).first)),*num(getNumberFieldAtLevel((*it).first));
4445       if(fam)
4446         {
4447           MCAuto<DataArrayIdType> famPart(fam->selectByTupleIdSafe((*it).second->begin(),(*it).second->end()));
4448           ret->setFamilyFieldArr((*it).first,famPart);
4449         }
4450       if(num)
4451         {
4452           MCAuto<DataArrayIdType> numPart(num->selectByTupleIdSafe((*it).second->begin(),(*it).second->end()));
4453           ret->setFamilyFieldArr((*it).first,numPart);
4454         }
4455     }
4456   std::map<int, MCAuto<DataArrayIdType> >::const_iterator it2(extractDef.find(1));
4457   if(it2!=extractDef.end())
4458     {
4459       const DataArrayDouble *coo(ret->getCoords());
4460       if(!coo)
4461         throw INTERP_KERNEL::Exception("MEDFileUMesh::extractPart : trying to extract nodes whereas there is no nodes !");
4462       MCAuto<DataArrayIdType> o2nNodes(((*it2).second)->invertArrayN2O2O2N(coo->getNumberOfTuples()));
4463       MCAuto<DataArrayDouble> cooPart(coo->selectByTupleIdSafe((*it2).second->begin(),(*it2).second->end()));
4464       ret->setCoords(cooPart);
4465       const DataArrayIdType *fam(getFamilyFieldAtLevel(1)),*num(getNumberFieldAtLevel(1));
4466       if(fam)
4467         {
4468           MCAuto<DataArrayIdType> famPart(fam->selectByTupleIdSafe((*it2).second->begin(),(*it2).second->end()));
4469           ret->setFamilyFieldArr(1,famPart);
4470         }
4471       if(num)
4472         {
4473           MCAuto<DataArrayIdType> numPart(num->selectByTupleIdSafe((*it2).second->begin(),(*it2).second->end()));
4474           ret->setFamilyFieldArr(1,numPart);
4475         }
4476       for(std::map<int, MCAuto<DataArrayIdType> >::const_iterator it3=extractDef.begin();it3!=extractDef.end();it3++)
4477         {
4478           if((*it3).first==1)
4479             continue;
4480           MCAuto<MEDCouplingUMesh> m(ret->getMeshAtLevel((*it3).first));
4481           m->renumberNodesInConn(o2nNodes->begin());
4482           ret->setMeshAtLevel((*it3).first,m);
4483         }
4484     }
4485   return ret.retn();
4486 }
4487
4488 /*!
4489  * This method performs an extrusion along a path defined by \a m1D.
4490  * \a this is expected to be a mesh with max mesh dimension equal to 2.
4491  * \a m1D is expected to be a mesh with space dimesion equal to 3 and mesh dimension equal to 1.
4492  * Mesh dimensions of returned mesh is incremented by one compared to thoose in \a this.
4493  * This method scans all levels in \a this
4494  * and put them in the returned mesh. All groups in \a this are also put in the returned mesh.
4495  *
4496  * \param [in] m1D - the mesh defining the extrusion path.
4497  * \param [in] policy - defines the policy of extrusion (see MEDCouplingUMesh::buildExtrudedMesh for more details)
4498  * \return - a new reference on mesh (you have to deal with using decrRef). The returned mesh will have the same name than \a this.
4499  *
4500  * \sa MEDCouplingUMesh::buildExtrudedMesh
4501  */
4502 MEDFileUMesh *MEDFileUMesh::buildExtrudedMesh(const MEDCouplingUMesh *m1D, int policy) const
4503 {
4504   checkCartesian();
4505   if(getMeshDimension()!=2)
4506     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildExtrudedMesh : this is expected to be with mesh dimension equal to 2 !");
4507   MCAuto<MEDFileUMesh> ret(MEDFileUMesh::New());
4508   m1D->checkConsistencyLight();
4509   if(m1D->getMeshDimension()!=1)
4510     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildExtrudedMesh : input mesh must have a mesh dimension equal to one !");
4511   mcIdType nbRep(m1D->getNumberOfCells());
4512   std::vector<int> levs(getNonEmptyLevels());
4513   std::vector<std::string> grps(getGroupsNames());
4514   std::vector< MCAuto<MEDCouplingUMesh> > zeList;
4515   DataArrayDouble *coords(0);
4516   std::size_t nbOfLevsOut(levs.size()+1);
4517   std::vector< MCAuto<DataArrayIdType> > o2ns(nbOfLevsOut);
4518   for(std::vector<int>::const_iterator lev=levs.begin();lev!=levs.end();lev++)
4519     {
4520       MCAuto<MEDCouplingUMesh> item(getMeshAtLevel(*lev));
4521       item=item->clone(false);
4522       item->changeSpaceDimension(3+(*lev),0.);//no problem non const but change DataArrayDouble for coordinates do not alter data
4523       MCAuto<MEDCouplingUMesh> tmp(static_cast<MEDCouplingUMesh *>(m1D->deepCopy()));
4524       tmp->changeSpaceDimension(3+(*lev),0.);
4525       MCAuto<MEDCouplingUMesh> elt(item->buildExtrudedMesh(tmp,policy));
4526       zeList.push_back(elt);
4527       if(*lev==0)
4528         coords=elt->getCoords();
4529     }
4530   if(!coords)
4531     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildExtrudedMesh : internal error !");
4532   for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator it=zeList.begin();it!=zeList.end();it++)
4533     {
4534       (*it)->setName(getName());
4535       (*it)->setCoords(coords);
4536     }
4537   for(std::size_t ii=0;ii!=zeList.size();ii++)
4538     {
4539       int lev(levs[ii]);
4540       MCAuto<MEDCouplingUMesh> elt(zeList[ii]);
4541       if(lev<=-1)
4542         {
4543           MCAuto<MEDCouplingUMesh> elt1(getMeshAtLevel(lev+1));
4544           MCAuto<MEDCouplingUMesh> elt2(elt1->clone(false));
4545           MCAuto<DataArrayIdType> tmp(elt2->getNodalConnectivity()->deepCopy());
4546           elt2->setConnectivity(tmp,elt2->getNodalConnectivityIndex());
4547           elt2->shiftNodeNumbersInConn(nbRep*elt1->getNumberOfNodes());
4548           elt1->setCoords(elt->getCoords()); elt2->setCoords(elt->getCoords());
4549           std::vector<const MEDCouplingUMesh *> elts(3);
4550           elts[0]=elt; elts[1]=elt1; elts[2]=elt2;
4551           elt=MEDCouplingUMesh::MergeUMeshesOnSameCoords(elts);
4552           elt->setName(getName());
4553         }
4554       //
4555       o2ns[ii]=elt->sortCellsInMEDFileFrmt();
4556       ret->setMeshAtLevel(lev,elt);
4557     }
4558   MCAuto<MEDCouplingUMesh> endLev(getMeshAtLevel(levs.back())),endLev2;
4559   endLev=endLev->clone(false); endLev->setCoords(coords);
4560   MCAuto<DataArrayIdType> tmp(endLev->getNodalConnectivity()->deepCopy());
4561   endLev2=endLev->clone(false); endLev2->setConnectivity(tmp,endLev->getNodalConnectivityIndex());
4562   endLev2->shiftNodeNumbersInConn(nbRep*getNumberOfNodes());
4563   endLev=MEDCouplingUMesh::MergeUMeshesOnSameCoords(endLev,endLev2);
4564   o2ns[levs.size()]=endLev->sortCellsInMEDFileFrmt();
4565   endLev->setName(getName());
4566   ret->setMeshAtLevel(levs.back()-1,endLev);
4567   //
4568   for(std::size_t ii=0;ii!=zeList.size();ii++)
4569     {
4570       int lev(levs[ii]);
4571       std::vector< MCAuto<DataArrayIdType> > outGrps;
4572       std::vector< const DataArrayIdType * > outGrps2;
4573       if(lev<=-1)
4574         {
4575           for(std::vector<std::string>::const_iterator grp=grps.begin();grp!=grps.end();grp++)
4576             {
4577               MCAuto<DataArrayIdType> grpArr(getGroupArr(lev+1,*grp));
4578               if(!grpArr->empty())
4579                 {
4580                   MCAuto<DataArrayIdType> grpArr1(grpArr->deepCopy()),grpArr2(grpArr->deepCopy());
4581                   mcIdType offset0(zeList[ii]->getNumberOfCells());
4582                   mcIdType offset1(offset0+getNumberOfCellsAtLevel(lev+1));
4583                   grpArr1->applyLin(1,offset0); grpArr2->applyLin(1,offset1);
4584                   std::ostringstream oss; oss << grpArr2->getName() << "_top";
4585                   grpArr2->setName(oss.str());
4586                   grpArr1->transformWithIndArr(o2ns[ii]->begin(),o2ns[ii]->end());
4587                   grpArr2->transformWithIndArr(o2ns[ii]->begin(),o2ns[ii]->end());
4588                   outGrps.push_back(grpArr1); outGrps.push_back(grpArr2);
4589                   outGrps2.push_back(grpArr1); outGrps2.push_back(grpArr2);
4590                 }
4591             }
4592         }
4593       //
4594       for(std::vector<std::string>::const_iterator grp=grps.begin();grp!=grps.end();grp++)
4595         {
4596           MCAuto<DataArrayIdType> grpArr(getGroupArr(lev,*grp));
4597           if(!grpArr->empty())
4598             {
4599               mcIdType nbCellsB4Extrusion(getNumberOfCellsAtLevel(lev));
4600               std::vector< MCAuto<DataArrayIdType> > grpArrs(nbRep);
4601               std::vector< const DataArrayIdType *> grpArrs2(nbRep);
4602               for(int iii=0;iii<nbRep;iii++)
4603                 {
4604                   grpArrs[iii]=grpArr->deepCopy(); grpArrs[iii]->applyLin(1,iii*nbCellsB4Extrusion);
4605                   grpArrs2[iii]=grpArrs[iii];
4606                 }
4607               MCAuto<DataArrayIdType> grpArrExt(DataArrayIdType::Aggregate(grpArrs2));
4608               grpArrExt->transformWithIndArr(o2ns[ii]->begin(),o2ns[ii]->end());
4609               std::ostringstream grpName; grpName << *grp << "_extruded";
4610               grpArrExt->setName(grpName.str());
4611               outGrps.push_back(grpArrExt);
4612               outGrps2.push_back(grpArrExt);
4613             }
4614         }
4615       ret->setGroupsAtLevel(lev,outGrps2);
4616     }
4617   std::vector< MCAuto<DataArrayIdType> > outGrps;
4618   std::vector< const DataArrayIdType * > outGrps2;
4619   for(std::vector<std::string>::const_iterator grp=grps.begin();grp!=grps.end();grp++)
4620     {
4621       MCAuto<DataArrayIdType> grpArr1(getGroupArr(levs.back(),*grp));
4622       if(grpArr1->empty())
4623         continue;
4624       MCAuto<DataArrayIdType> grpArr2(grpArr1->deepCopy());
4625       std::ostringstream grpName; grpName << *grp << "_top";
4626       grpArr2->setName(grpName.str());
4627       grpArr2->applyLin(1,getNumberOfCellsAtLevel(levs.back()));
4628       outGrps.push_back(grpArr1); outGrps.push_back(grpArr2);
4629       outGrps2.push_back(grpArr1); outGrps2.push_back(grpArr2);
4630     }
4631   ret->setGroupsAtLevel(levs.back()-1,outGrps2);
4632   return ret.retn();
4633 }
4634
4635 /*!
4636  * This method converts all linear cells in \a this into quadratic cells (following the \a conversionType policy).
4637  * All the cells converted are put in the returned instance. This method applies all the groups and families in \a this to returned instance.
4638  * Groups on nodes and families on nodes are copied directly to the returned instance without transformation.
4639  *
4640  * \param [in] conversionType - conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4641  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4642  * \param [in] eps - detection threshold for coordinates.
4643  * \return A new instance that is the result of the conversion. The caller has the ownership of this returned instance.
4644  *
4645  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic , quadraticToLinear
4646  */
4647 MEDFileUMesh *MEDFileUMesh::linearToQuadratic(int conversionType, double eps) const
4648 {
4649   checkCartesian();
4650   MCAuto<MEDFileUMesh> ret(MEDFileUMesh::New());
4651   mcIdType initialNbNodes(getNumberOfNodes());
4652   MCAuto<MEDCouplingUMesh> m0Tmp(getMeshAtLevel(0));
4653   MCAuto<MEDCouplingUMesh> m0(dynamic_cast<MEDCouplingUMesh *>(m0Tmp->deepCopy()));
4654   {
4655     MCAuto<DataArrayIdType> notUsed(m0->convertLinearCellsToQuadratic(conversionType));
4656   }
4657   DataArrayDouble *zeCoords(m0->getCoords());
4658   ret->setMeshAtLevel(0,m0);
4659   std::vector<int> levs(getNonEmptyLevels());
4660   const DataArrayIdType *famField(getFamilyFieldAtLevel(0));
4661   if(famField)
4662     {
4663       MCAuto<DataArrayIdType> famFieldCpy(famField->deepCopy());
4664       ret->setFamilyFieldArr(0,famFieldCpy);
4665     }
4666   famField=getFamilyFieldAtLevel(1);
4667   if(famField)
4668     {
4669       MCAuto<DataArrayIdType> fam(DataArrayIdType::New()); fam->alloc(zeCoords->getNumberOfTuples(),1);
4670       fam->fillWithZero();
4671       fam->setPartOfValues1(famField,0,initialNbNodes,1,0,1,1);
4672       ret->setFamilyFieldArr(1,fam);
4673     }
4674   ret->copyFamGrpMapsFrom(*this);
4675   MCAuto<DataArrayDouble> partZeCoords(zeCoords->selectByTupleIdSafeSlice(initialNbNodes,zeCoords->getNumberOfTuples(),1));
4676   for(std::vector<int>::const_iterator lev=levs.begin();lev!=levs.end();lev++)
4677     {
4678       if(*lev==0)
4679         continue;
4680       MCAuto<MEDCouplingUMesh> m1Tmp(getMeshAtLevel(*lev));
4681       MCAuto<MEDCouplingUMesh> m1(dynamic_cast<MEDCouplingUMesh *>(m1Tmp->deepCopy()));
4682       if(m1->getMeshDimension()!=0)
4683         {
4684           {
4685             MCAuto<DataArrayIdType> notUsed(m1->convertLinearCellsToQuadratic(conversionType));
4686           }//kill unused notUsed var
4687           MCAuto<DataArrayDouble> m1Coords(m1->getCoords()->selectByTupleIdSafeSlice(initialNbNodes,m1->getNumberOfNodes(),1));
4688           DataArrayIdType *b(0);
4689           bool a(partZeCoords->areIncludedInMe(m1Coords,eps,b));
4690           MCAuto<DataArrayIdType> bSafe(b);
4691           if(!a)
4692             {
4693               std::ostringstream oss; oss << "MEDFileUMesh::linearCellsToQuadratic : for level " << *lev << " problem to identify nodes generated !";
4694               throw INTERP_KERNEL::Exception(oss.str().c_str());
4695             }
4696           b->applyLin(1,initialNbNodes);
4697           MCAuto<DataArrayIdType> l0(DataArrayIdType::New()); l0->alloc(initialNbNodes,1); l0->iota();
4698           std::vector<const DataArrayIdType *> v(2); v[0]=l0; v[1]=b;
4699           MCAuto<DataArrayIdType> renum(DataArrayIdType::Aggregate(v));
4700           m1->renumberNodesInConn(renum->begin());
4701         }
4702       m1->setCoords(zeCoords);
4703       ret->setMeshAtLevel(*lev,m1);
4704       famField=getFamilyFieldAtLevel(*lev);
4705       if(famField)
4706         {
4707           MCAuto<DataArrayIdType> famFieldCpy(famField->deepCopy());
4708           ret->setFamilyFieldArr(*lev,famFieldCpy);
4709         }
4710     }
4711   return ret.retn();
4712 }
4713
4714 /*!
4715  * This method converts all quadratic cells in \a this into linear cells.
4716  * All the cells converted are put in the returned instance. This method applies all the groups and families in \a this to returned instance.
4717  * Groups on nodes and families on nodes are copied directly to the returned instance without transformation.
4718  *
4719  * \param [in] eps - detection threshold for coordinates.
4720  * \return A new instance that is the result of the conversion. The caller has the ownership of this returned instance.
4721  *
4722  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic , linearToQuadratic
4723  */
4724 MEDFileUMesh *MEDFileUMesh::quadraticToLinear(double eps) const
4725 {
4726   checkCartesian();
4727   MCAuto<MEDFileUMesh> ret(MEDFileUMesh::New());
4728   MCAuto<MEDCouplingUMesh> m0Tmp(getMeshAtLevel(0));
4729   MCAuto<MEDCouplingUMesh> m0(dynamic_cast<MEDCouplingUMesh *>(m0Tmp->deepCopy()));
4730   m0->convertQuadraticCellsToLinear();
4731   m0->zipCoords();
4732   DataArrayDouble *zeCoords(m0->getCoords());
4733   ret->setMeshAtLevel(0,m0);
4734   std::vector<int> levs(getNonEmptyLevels());
4735   const DataArrayIdType *famField(getFamilyFieldAtLevel(0));
4736   if(famField)
4737     {
4738       MCAuto<DataArrayIdType> famFieldCpy(famField->deepCopy());
4739       ret->setFamilyFieldArr(0,famFieldCpy);
4740     }
4741   famField=getFamilyFieldAtLevel(1);
4742   if(famField)
4743     {
4744       MCAuto<DataArrayIdType> fam(famField->selectByTupleIdSafeSlice(0,zeCoords->getNumberOfTuples(),1));
4745       ret->setFamilyFieldArr(1,fam);
4746     }
4747   ret->copyFamGrpMapsFrom(*this);
4748   for(std::vector<int>::const_iterator lev=levs.begin();lev!=levs.end();lev++)
4749     {
4750       if(*lev==0)
4751         continue;
4752       MCAuto<MEDCouplingUMesh> m1Tmp(getMeshAtLevel(*lev));
4753       MCAuto<MEDCouplingUMesh> m1(dynamic_cast<MEDCouplingUMesh *>(m1Tmp->deepCopy()));
4754       m1->convertQuadraticCellsToLinear();
4755       m1->zipCoords();
4756       DataArrayIdType *b(0);
4757       bool a(zeCoords->areIncludedInMe(m1->getCoords(),eps,b));
4758       MCAuto<DataArrayIdType> bSafe(b);
4759       if(!a)
4760         {
4761           std::ostringstream oss; oss << "MEDFileUMesh::quadraticToLinear : for level " << *lev << " problem to identify nodes generated !";
4762           throw INTERP_KERNEL::Exception(oss.str().c_str());
4763         }
4764       m1->renumberNodesInConn(b->begin());
4765       m1->setCoords(zeCoords);
4766       ret->setMeshAtLevel(*lev,m1);
4767       famField=getFamilyFieldAtLevel(*lev);
4768       if(famField)
4769         {
4770           MCAuto<DataArrayIdType> famFieldCpy(famField->deepCopy());
4771           ret->setFamilyFieldArr(*lev,famFieldCpy);
4772         }
4773     }
4774   return ret.retn();
4775 }
4776
4777 /*!
4778  * Computes the symmetry of \a this.
4779  * \return a new object.
4780  */
4781 MCAuto<MEDFileUMesh> MEDFileUMesh::symmetry3DPlane(const double point[3], const double normalVector[3]) const
4782 {
4783   MCAuto<MEDFileUMesh> ret(deepCopy());
4784   DataArrayDouble *myCoo(getCoords());
4785   if(myCoo)
4786     {
4787       MCAuto<DataArrayDouble> newCoo(myCoo->symmetry3DPlane(point,normalVector));
4788       ret->setCoordsForced(newCoo);
4789     }
4790   return ret;
4791 }
4792
4793 /*!
4794  * Aggregate the given MEDFileUMesh objects into a single mesh. When groups are present, those are
4795  * merged in such a way that the final mesh contain all of them.
4796  * \return a new object.
4797  */
4798 MCAuto<MEDFileUMesh> MEDFileUMesh::Aggregate(const std::vector<const MEDFileUMesh *>& meshes)
4799 {
4800   if(meshes.empty())
4801     throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : empty input vector !");
4802   std::size_t sz(meshes.size()),i(0);
4803   std::vector<const DataArrayDouble *> coos(sz);
4804   std::vector<const DataArrayIdType *> fam_coos(sz),num_coos(sz);
4805   for(auto it=meshes.begin();it!=meshes.end();it++,i++)
4806     {
4807       if(!(*it))
4808         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : presence of NULL pointer in input vector !");
4809       coos[i]=(*it)->getCoords();
4810       fam_coos[i]=(*it)->getFamilyFieldAtLevel(1);
4811       num_coos[i]=(*it)->getNumberFieldAtLevel(1);
4812     }
4813   const MEDFileUMesh *ref(meshes[0]);
4814   int spaceDim(ref->getSpaceDimension()),meshDim(ref->getMeshDimension());
4815   std::vector<int> levs(ref->getNonEmptyLevels());
4816   std::map<int, std::vector<const DataArrayIdType *> > m_fam,m_renum;
4817   std::map<int, std::vector< MCAuto< MEDCouplingUMesh > > > m_mesh2;
4818   std::map<int, std::vector<const MEDCouplingUMesh *> > m_mesh;
4819   std::map<std::string,mcIdType> famNumMap;
4820   std::map<mcIdType, std::string> famNumMap_rev;
4821   std::map<std::string, std::vector<std::string> > grpFamMap;
4822   std::set< MCAuto<DataArrayIdType> > mem_cleanup;   // Memory clean-up. At set deletion (end of method), arrays will be deallocated.
4823
4824   // Identify min family number used:
4825   mcIdType min_fam_num(0);
4826   for(const auto& msh : meshes)
4827     {
4828       const std::map<std::string,mcIdType>& locMap1(msh->getFamilyInfo());
4829       for(const auto& it3 : locMap1)
4830         if(it3.second < min_fam_num)
4831           min_fam_num = it3.second;
4832     }
4833
4834   for(const auto& msh : meshes)
4835     {
4836       if(msh->getSpaceDimension()!=spaceDim)
4837         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : space dimension must be homogeneous !");
4838       if(msh->getMeshDimension()!=meshDim)
4839         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : mesh dimension must be homogeneous !");
4840       if(msh->getNonEmptyLevels()!=levs)
4841         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : levels must be the same for elements in input vector !");
4842
4843       const std::map<std::string,mcIdType>& locMap1(msh->getFamilyInfo());
4844       std::map<std::string, std::string> substitute;
4845       std::map<mcIdType, mcIdType> substituteN;
4846       bool fam_conflict(false);
4847       for(const auto& it3 : locMap1)
4848         {
4849           const std::string& famName = it3.first;
4850           mcIdType famNum = it3.second;
4851           if (famNumMap_rev.find(famNum) != famNumMap_rev.end()) // Family number is already used!
4852             {
4853               // Is it used by a group of the current mesh or a group from a previous mesh?
4854               // If not, this is OK (typically -1 familly).
4855               bool used = false;
4856               //    Current mesh
4857               const std::map<std::string, std::vector<std::string> >& locMap2(msh->getGroupInfo());
4858               for(const auto& it4 : locMap2)
4859                 {
4860                   const auto& famLst = it4.second;
4861                   if (std::find(famLst.begin(), famLst.end(), famName) != famLst.end())
4862                     { used = true; break; }
4863                 }
4864               //    Previous meshes ...
4865               if (!used)
4866                 for(const auto& it4 : grpFamMap)
4867                   {
4868                     const auto& famLst = it4.second;
4869                     if (std::find(famLst.begin(), famLst.end(), famName) != famLst.end())
4870                       { used = true; break; }
4871                   }
4872
4873               if(used)
4874                 { // Generate a new family name, and a new family number
4875                   fam_conflict = true;
4876                   std::ostringstream oss;
4877                   oss << "Family_" << --min_fam_num;  // New ID
4878                   std::string new_name(oss.str());
4879                   substitute[famName] = new_name;
4880                   substituteN[famNum] = min_fam_num;
4881                   famNumMap[new_name] = min_fam_num;
4882                   famNumMap_rev[min_fam_num] = new_name;
4883                 }
4884             }
4885           famNumMap[famName] = famNum;
4886           famNumMap_rev[famNum] = famName;
4887         }
4888
4889       for(const auto& level : levs)
4890         {
4891           MCAuto<MEDCouplingUMesh> locMesh(msh->getMeshAtLevel(level));
4892           m_mesh[level].push_back(locMesh); m_mesh2[level].push_back(locMesh);
4893           m_renum[level].push_back(msh->getNumberFieldAtLevel(level));
4894
4895           // Family field - substitute new family number if needed:
4896           if(fam_conflict)
4897             {
4898               DataArrayIdType* dai(msh->getFamilyFieldAtLevel(level)->deepCopy());  // Need a copy
4899               mem_cleanup.insert(MCAuto<DataArrayIdType>(dai));      // Make sure array will decrRef() at end of method
4900               for (const auto& subN : substituteN)
4901                 dai->changeValue(subN.first, subN.second);
4902               m_fam[level].push_back(dai);
4903             }
4904           else
4905             m_fam[level].push_back(msh->getFamilyFieldAtLevel(level));      // No copy needed
4906         }
4907
4908       const std::map<std::string, std::vector<std::string> >& locMap2(msh->getGroupInfo());
4909       for(const auto& grpItem : locMap2)
4910         {
4911           const std::string& grpName = grpItem.first;
4912           std::vector<std::string> famLst;
4913           // Substitute family name in group description if needed:
4914           if (fam_conflict)
4915             {
4916               famLst = grpItem.second;
4917               for (const auto& sub : substitute)
4918                 std::replace(famLst.begin(), famLst.end(), sub.first, sub.second);
4919             }
4920           else
4921             famLst = grpItem.second;
4922
4923           // Potentially merge groups (if same name):
4924           const auto& it = grpFamMap.find(grpName);
4925           if (it != grpFamMap.end())
4926             {
4927               // Group already exists, merge should be done. Normally we whould never
4928               // have twice the same family name in famLstCur and famLst since we dealt with family number
4929               // conflict just above ...
4930               std::vector<std::string>& famLstCur = (*it).second;
4931               famLstCur.insert(famLstCur.end(), famLst.begin(), famLst.end());
4932             }
4933           else
4934             grpFamMap[grpName] = famLst;
4935         }
4936     }
4937   // Easy part : nodes
4938   MCAuto<MEDFileUMesh> ret(MEDFileUMesh::New());
4939   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coos));
4940   ret->setCoords(coo);
4941   if(std::find(fam_coos.begin(),fam_coos.end(),(const DataArrayIdType *)0)==fam_coos.end())
4942     {
4943       MCAuto<DataArrayIdType> fam_coo(DataArrayIdType::Aggregate(fam_coos));
4944       ret->setFamilyFieldArr(1,fam_coo);
4945     }
4946   if(std::find(num_coos.begin(),num_coos.end(),(const DataArrayIdType *)0)==num_coos.end())
4947     {
4948       MCAuto<DataArrayIdType> num_coo(DataArrayIdType::Aggregate(num_coos));
4949       ret->setRenumFieldArr(1,num_coo);
4950     }
4951   // cells
4952   for(const auto& level : levs)
4953     {
4954       auto it2(m_mesh.find(level));
4955       if(it2==m_mesh.end())
4956         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : internal error 1 !");
4957       MCAuto<MEDCouplingUMesh> mesh(MEDCouplingUMesh::MergeUMeshes((*it2).second));
4958       mesh->setCoords(coo); mesh->setName(ref->getName());
4959       MCAuto<DataArrayIdType> renum(mesh->sortCellsInMEDFileFrmt());
4960       ret->setMeshAtLevel(level,mesh);
4961       auto it3(m_fam.find(level)),it4(m_renum.find(level));
4962       if(it3==m_fam.end()) // Should never happen (all levels exist for all meshes)
4963         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : internal error 2!");
4964       if(it4==m_renum.end())
4965         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : internal error 3!");
4966       // Set new family field if it was defined for all input meshes
4967       const std::vector<const DataArrayIdType *>& fams((*it3).second);
4968       if(std::find(fams.begin(),fams.end(),(const DataArrayIdType *)0)==fams.end())
4969         {
4970           MCAuto<DataArrayIdType> famm(DataArrayIdType::Aggregate(fams));
4971           famm->renumberInPlace(renum->begin());
4972           ret->setFamilyFieldArr(level,famm);
4973         }
4974       // Set optional number field if defined for all input meshes:
4975       const std::vector<const DataArrayIdType *>& renums((*it4).second);
4976       if(std::find(renums.begin(),renums.end(),(const DataArrayIdType *)0)==renums.end())
4977         {
4978           MCAuto<DataArrayIdType> renumm(DataArrayIdType::Aggregate(renums));
4979           renumm->renumberInPlace(renum->begin());
4980           ret->setRenumFieldArr(level,renumm);
4981         }
4982     }
4983   //
4984   ret->setFamilyInfo(famNumMap);
4985   ret->setGroupInfo(grpFamMap);
4986   ret->setName(ref->getName());
4987   return ret;
4988 }
4989
4990 MEDCouplingMappedExtrudedMesh *MEDFileUMesh::convertToExtrudedMesh() const
4991 {
4992   if(getMeshDimension()!=3)
4993     throw INTERP_KERNEL::Exception("MEDFileUMesh::convertToExtrudedMesh : works only for 3D mesh !");
4994   MCAuto<MEDCouplingUMesh> m3D(getMeshAtLevel(0)),m2D(getMeshAtLevel(-1));
4995   if(m3D.isNull() || m2D.isNull())
4996     throw INTERP_KERNEL::Exception("MEDFileUMesh::convertToExtrudedMesh : this must be defined both at level 0 and level -1 !");
4997   mcIdType zeId(std::numeric_limits<med_int>::max()-getFamilyId(GetSpeStr4ExtMesh()));
4998   MCAuto<MEDCouplingMappedExtrudedMesh> ret(MEDCouplingMappedExtrudedMesh::New(m3D,m2D,zeId));
4999   return ret.retn();
5000 }
5001
5002 void MEDFileUMesh::serialize(std::vector<double>& tinyDouble, std::vector<mcIdType>& tinyInt, std::vector<std::string>& tinyStr, std::vector< MCAuto<DataArrayIdType> >& bigArraysI, MCAuto<DataArrayDouble>& bigArrayD)
5003 {
5004   clearNonDiscrAttributes();
5005   forceComputationOfParts();
5006   tinyDouble.clear(); tinyInt.clear(); tinyStr.clear(); bigArraysI.clear(); bigArrayD=0;
5007   std::vector<mcIdType> layer0;
5008   layer0.push_back(getAxisType());//0 i
5009   layer0.push_back(_order); //1 i
5010   layer0.push_back(_iteration);//2 i
5011   layer0.push_back(getSpaceDimension());//3 i
5012   tinyDouble.push_back(_time);//0 d
5013   tinyStr.push_back(_name);//0 s
5014   tinyStr.push_back(_desc_name);//1 s
5015   for(int i=0;i<getSpaceDimension();i++)
5016     tinyStr.push_back(_coords->getInfoOnComponent(i));
5017   layer0.push_back(ToIdType(_families.size()));//4 i <- key info aa layer#0
5018   for(std::map<std::string,mcIdType>::const_iterator it=_families.begin();it!=_families.end();it++)
5019     {
5020       tinyStr.push_back((*it).first);
5021       layer0.push_back((*it).second);
5022     }
5023   layer0.push_back((mcIdType)_groups.size());//4+aa i <- key info bb layer#0
5024   for(std::map<std::string, std::vector<std::string> >::const_iterator it0=_groups.begin();it0!=_groups.end();it0++)
5025     {
5026       layer0.push_back(ToIdType((*it0).second.size()));
5027       tinyStr.push_back((*it0).first);
5028       for(std::vector<std::string>::const_iterator it1=((*it0).second).begin();it1!=((*it0).second).end();it1++)
5029         tinyStr.push_back(*it1);
5030     }
5031   // sizeof(layer0)==4+aa+1+bb layer#0
5032   bigArrayD=_coords;// 0 bd
5033   bigArraysI.push_back(_fam_coords);// 0 bi
5034   bigArraysI.push_back(_num_coords);// 1 bi
5035   const PartDefinition *pd(_part_coords);
5036   if(!pd)
5037     layer0.push_back(-1);
5038   else
5039     {
5040       std::vector<mcIdType> tmp0;
5041       pd->serialize(tmp0,bigArraysI);
5042       tinyInt.push_back(ToIdType(tmp0.size()));
5043       tinyInt.insert(tinyInt.end(),tmp0.begin(),tmp0.end());
5044     }
5045   //
5046   std::vector<mcIdType> layer1;
5047   std::vector<int> levs(getNonEmptyLevels());
5048   layer1.push_back((mcIdType)levs.size());// 0 i <- key
5049   layer1.insert(layer1.end(),levs.begin(),levs.end());
5050   for(std::vector<int>::const_iterator it=levs.begin();it!=levs.end();it++)
5051     {
5052       const MEDFileUMeshSplitL1 *lev(getMeshAtLevSafe(*it));
5053       lev->serialize(layer1,bigArraysI);
5054     }
5055   // put layers all together.
5056   tinyInt.push_back(ToIdType(layer0.size()));
5057   tinyInt.insert(tinyInt.end(),layer0.begin(),layer0.end());
5058   tinyInt.push_back(ToIdType(layer1.size()));
5059   tinyInt.insert(tinyInt.end(),layer1.begin(),layer1.end());
5060 }
5061
5062 void MEDFileUMesh::unserialize(std::vector<double>& tinyDouble, std::vector<mcIdType>& tinyInt, std::vector<std::string>& tinyStr,
5063                                std::vector< MCAuto<DataArrayIdType> >& bigArraysI, MCAuto<DataArrayDouble>& bigArrayD)
5064 {
5065   mcIdType sz0(tinyInt[0]);
5066   std::vector<mcIdType> layer0(tinyInt.begin()+1,tinyInt.begin()+1+sz0);
5067   mcIdType sz1(tinyInt[sz0+1]);
5068   std::vector<mcIdType> layer1(tinyInt.begin()+2+sz0,tinyInt.begin()+2+sz0+sz1);
5069   //
5070   std::reverse(layer0.begin(),layer0.end());
5071   std::reverse(layer1.begin(),layer1.end());
5072   std::reverse(tinyDouble.begin(),tinyDouble.end());
5073   std::reverse(tinyStr.begin(),tinyStr.end());
5074   std::reverse(bigArraysI.begin(),bigArraysI.end());
5075   //
5076   setAxisType((MEDCouplingAxisType)layer0.back()); layer0.pop_back();
5077   _order=FromIdType<int>(layer0.back()); layer0.pop_back();
5078   _iteration=FromIdType<int>(layer0.back()); layer0.pop_back();
5079   mcIdType spaceDim(layer0.back()); layer0.pop_back();
5080   _time=tinyDouble.back(); tinyDouble.pop_back();
5081   _name=tinyStr.back(); tinyStr.pop_back();
5082   _desc_name=tinyStr.back(); tinyStr.pop_back();
5083   _coords=bigArrayD; _coords->rearrange(spaceDim);
5084   for(int i=0;i<spaceDim;i++)
5085     {
5086       _coords->setInfoOnComponent(i,tinyStr.back());
5087       tinyStr.pop_back();
5088     }
5089   mcIdType nbOfFams(layer0.back()); layer0.pop_back();
5090   _families.clear();
5091   for(mcIdType i=0;i<nbOfFams;i++)
5092     {
5093       _families[tinyStr.back()]=layer0.back();
5094       tinyStr.pop_back(); layer0.pop_back();
5095     }
5096   mcIdType nbGroups(layer0.back()); layer0.pop_back();
5097   _groups.clear();
5098   for(mcIdType i=0;i<nbGroups;i++)
5099     {
5100       std::string grpName(tinyStr.back()); tinyStr.pop_back();
5101       mcIdType nbOfFamsOnGrp(layer0.back()); layer0.pop_back();
5102       std::vector<std::string> fams(nbOfFamsOnGrp);
5103       for(mcIdType j=0;j<nbOfFamsOnGrp;j++)
5104         {
5105           fams[j]=tinyStr.back(); tinyStr.pop_back();
5106         }
5107       _groups[grpName]=fams;
5108     }
5109   _fam_coords=bigArraysI.back(); bigArraysI.pop_back();
5110   _num_coords=bigArraysI.back(); bigArraysI.pop_back();
5111   _part_coords=0;
5112   mcIdType isPd(layer0.back()); layer0.pop_back();
5113   if(isPd!=-1)
5114     {
5115       std::vector<mcIdType> tmp0(layer0.begin(),layer0.begin()+isPd);
5116       layer0.erase(layer0.begin(),layer0.begin()+isPd);
5117       _part_coords=PartDefinition::Unserialize(tmp0,bigArraysI);
5118     }
5119   if(!layer0.empty())
5120     throw INTERP_KERNEL::Exception("MEDFileUMesh::unserialize : something wrong during unserialization #1 !");
5121   //
5122   mcIdType nbLevs(layer1.back()); layer1.pop_back();
5123   std::vector<mcIdType> levs(layer1.rbegin(),layer1.rbegin()+nbLevs); layer1.erase(layer1.end()-nbLevs,layer1.end());
5124   _ms.clear();
5125   mcIdType maxLev(-(*std::min_element(levs.begin(),levs.end())));
5126   _ms.resize(maxLev+1);
5127   for(mcIdType i=0;i<nbLevs;i++)
5128     {
5129       mcIdType lev(levs[i]);
5130       mcIdType pos(-lev);
5131       _ms[pos]=MEDFileUMeshSplitL1::Unserialize(_name,_coords,layer1,bigArraysI);
5132     }
5133 }
5134
5135 /*!
5136  * Adds a group of nodes to \a this mesh.
5137  *  \param [in] ids - a DataArrayIdType providing ids and a name of the group to add.
5138  *          The ids should be sorted and different each other (MED file norm).
5139  *
5140  *  \warning this method can alter default "FAMILLE_ZERO" family.
5141  *  For users sensitive to this a call to MEDFileMesh::rearrangeFamilies will be necessary after addGroup session.
5142  *
5143  *  \throw If the node coordinates array is not set.
5144  *  \throw If \a ids == \c NULL.
5145  *  \throw If \a ids->getName() == "".
5146  *  \throw If \a ids does not respect the MED file norm.
5147  *  \throw If a group with name \a ids->getName() already exists.
5148  */
5149 void MEDFileUMesh::addNodeGroup(const DataArrayIdType *ids)
5150 {
5151   const DataArrayDouble *coords(_coords);
5152   if(!coords)
5153     throw INTERP_KERNEL::Exception("MEDFileUMesh::addNodeGroup : no coords set !");
5154   mcIdType nbOfNodes(coords->getNumberOfTuples());
5155   if(_fam_coords.isNull())
5156     { _fam_coords=DataArrayIdType::New(); _fam_coords->alloc(nbOfNodes,1); _fam_coords->fillWithZero(); }
5157   //
5158   addGroupUnderground(true,ids,_fam_coords);
5159 }
5160
5161 /*!
5162  * Adds a group of nodes/cells/faces/edges to \a this mesh.
5163  *
5164  *  \param [in] ids - a DataArrayIdType providing ids and a name of the group to add.
5165  *          The ids should be sorted and different each other (MED file norm).
5166  *
5167  * \warning this method can alter default "FAMILLE_ZERO" family.
5168  * For users sensitive to this a call to MEDFileMesh::rearrangeFamilies will be necessary after addGroup session.
5169  *
5170  *  \throw If the node coordinates array is not set.
5171  *  \throw If \a ids == \c NULL.
5172  *  \throw If \a ids->getName() == "".
5173  *  \throw If \a ids does not respect the MED file norm.
5174  *  \throw If a group with name \a ids->getName() already exists.
5175  */
5176 void MEDFileUMesh::addGroup(int meshDimRelToMaxExt, const DataArrayIdType *ids)
5177 {
5178   std::vector<int> levs(getNonEmptyLevelsExt());
5179   if(std::find(levs.begin(),levs.end(),meshDimRelToMaxExt)==levs.end())
5180     { 
5181       std::ostringstream oss; oss << "MEDFileUMesh::addGroup : level " << meshDimRelToMaxExt << " not available ! Should be in ";
5182       std::copy(levs.begin(),levs.end(),std::ostream_iterator<int>(oss," ")); oss << " !"; throw INTERP_KERNEL::Exception(oss.str().c_str());
5183     }
5184   if(meshDimRelToMaxExt==1)
5185     { addNodeGroup(ids); return ; }
5186   MEDFileUMeshSplitL1 *lev(getMeshAtLevSafe(meshDimRelToMaxExt));
5187   DataArrayIdType *fam(lev->getOrCreateAndGetFamilyField());
5188   addGroupUnderground(false,ids,fam);
5189 }
5190
5191 /*!
5192  * Changes a name of a family specified by its id.
5193  *  \param [in] id - the id of the family of interest.
5194  *  \param [in] newFamName - the new family name.
5195  *  \throw If no family with the given \a id exists.
5196  */
5197 void MEDFileUMesh::setFamilyNameAttachedOnId(mcIdType id, const std::string& newFamName)
5198 {
5199   std::string oldName=getFamilyNameGivenId(id);
5200   _families.erase(oldName);
5201   _families[newFamName]=id;
5202 }
5203
5204 /*!
5205  * Removes a mesh of a given dimension.
5206  *  \param [in] meshDimRelToMax - the relative dimension of interest.
5207  *  \throw If there is no mesh at level \a meshDimRelToMax in \a this mesh.
5208  */
5209 void MEDFileUMesh::removeMeshAtLevel(int meshDimRelToMax)
5210 {
5211   std::vector<int> levSet=getNonEmptyLevels();
5212   std::vector<int>::const_iterator it=std::find(levSet.begin(),levSet.end(),meshDimRelToMax);
5213   if(it==levSet.end())
5214     throw INTERP_KERNEL::Exception("MEDFileUMesh::removeMeshAtLevel : the requested level is not existing !");
5215   int pos=(-meshDimRelToMax);
5216   _ms[pos]=0;
5217 }
5218
5219 /*!
5220  * Sets a new MEDCoupling1GTUMesh at a given level in \a this mesh.
5221  *  \param [in] meshDimRelToMax - a relative level to set the mesh at.
5222  *  \param [in] m - the new mesh to set.
5223  *  \throw If the name or the description of \a this mesh and \a m are not empty and are
5224  *         different. 
5225  *  \throw If the node coordinates array is set \a this in mesh and \a m refers to
5226  *         another node coordinates array.
5227  *  \throw If the mesh dimension of \a m does not correspond to \a meshDimRelToMax or
5228  *         to the existing meshes of other levels of \a this mesh.
5229  */
5230 void MEDFileUMesh::setMeshAtLevel(int meshDimRelToMax, MEDCoupling1GTUMesh *m)
5231 {
5232   MCAuto<MEDFileUMeshSplitL1> elt(new MEDFileUMeshSplitL1(m));
5233   checkAndGiveEntryInSplitL1(meshDimRelToMax,m)=elt;
5234 }
5235
5236 /*!
5237  * Sets a new MEDCouplingUMesh at a given level in \a this mesh.
5238  *  \param [in] meshDimRelToMax - a relative level to set the mesh at.
5239  *  \param [in] m - the new mesh to set.
5240  *  \param [in] newOrOld - if \c true, cells in \a m are sorted by type to be ready for 
5241  *         writing \a this mesh in a MED file.
5242  *  \throw If the name or the description of \a this mesh and \a m are not empty and are
5243  *         different. 
5244  *  \throw If the node coordinates array is set \a this in mesh and \a m refers to
5245  *         another node coordinates array.
5246  *  \throw If the mesh dimension of \a m does not correspond to \a meshDimRelToMax or
5247  *         to the existing meshes of other levels of \a this mesh.
5248  */
5249 void MEDFileUMesh::setMeshAtLevel(int meshDimRelToMax, MEDCouplingUMesh *m, bool newOrOld)
5250 {
5251   MCAuto<MEDFileUMeshSplitL1> elt(new MEDFileUMeshSplitL1(m,newOrOld));
5252   checkAndGiveEntryInSplitL1(meshDimRelToMax,m)=elt;
5253 }
5254
5255 MCAuto<MEDFileUMeshSplitL1>& MEDFileUMesh::checkAndGiveEntryInSplitL1(int meshDimRelToMax, MEDCouplingPointSet *m)
5256 {
5257   dealWithTinyInfo(m);
5258   std::vector<int> levSet=getNonEmptyLevels();
5259   if(std::find(levSet.begin(),levSet.end(),meshDimRelToMax)==levSet.end())
5260     {
5261       if((DataArrayDouble *)_coords==0)
5262         {
5263           DataArrayDouble *c=m->getCoords();
5264           if(c)
5265             c->incrRef();
5266           _coords=c;
5267         }
5268       if(m->getCoords()!=_coords)
5269         throw INTERP_KERNEL::Exception("MEDFileUMesh::setMeshAtLevel : Invalid Given Mesh ! The coordinates are not the same ! try to use tryToShareSameCoords !");
5270       int sz=(-meshDimRelToMax)+1;
5271       if(sz>=(int)_ms.size())
5272         _ms.resize(sz);
5273       checkMeshDimCoherency(m->getMeshDimension(),meshDimRelToMax);
5274       return _ms[sz-1];
5275     }
5276   else
5277     return _ms[-meshDimRelToMax];
5278 }
5279
5280 /*!
5281  * This method allows to set at once the content of different levels in \a this.
5282  * This method is equivalent to a series of call to MEDFileUMesh::setMeshAtLevel.
5283  *
5284  * \param [in] ms - List of unstructured meshes lying on the same coordinates and having different mesh dimesnion.
5285  * \param [in] renum - the parameter (set to false by default) that tells the beheviour if there is a mesh on \a ms that is not geo type sorted.
5286  *                     If false, an exception is thrown. If true the mesh is reordered automatically. It is highly recommended to let this parameter to false.
5287  *
5288  * \throw If \a there is a null pointer in \a ms.
5289  * \sa MEDFileUMesh::setMeshAtLevel
5290  */
5291 void MEDFileUMesh::setMeshes(const std::vector<const MEDCouplingUMesh *>& ms, bool renum)
5292 {
5293   if(ms.empty())
5294     return ;
5295   const MEDCouplingUMesh *mRef=ms[0];
5296   if(!mRef)
5297     throw INTERP_KERNEL::Exception("MEDFileUMesh::setMeshes : null instance in the first element of input meshes !");
5298   std::string name(mRef->getName());
5299   const DataArrayDouble *coo(mRef->getCoords());
5300   std::set<int> s;
5301   int zeDim=-1;
5302   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
5303     {
5304       const MEDCouplingUMesh *cur(*it);
5305       if(!cur)
5306         throw INTERP_KERNEL::Exception("MEDFileUMesh::setMeshes : null instance in input vector of meshes !");
5307       if(coo!=cur->getCoords())
5308         throw INTERP_KERNEL::Exception("MEDFileUMesh::setMeshes : The input meshes do not share the same coordinates !");
5309       int mdim=cur->getMeshDimension();
5310       zeDim=std::max(zeDim,mdim);
5311       if(s.find(mdim)!=s.end())
5312         throw INTERP_KERNEL::Exception("MEDFileUMesh::setMeshes : The input meshes must share the same coordinates pointer, and should have different mesh dimension each other !");
5313     }
5314   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
5315     {
5316       int mdim=(*it)->getMeshDimension();
5317       setName((*it)->getName());
5318       setMeshAtLevel(mdim-zeDim,const_cast<MEDCouplingUMesh *>(*it),renum);
5319     }
5320   setName(name);
5321 }
5322
5323 /*!
5324  * Creates one MEDCouplingUMesh at a given level in \a this mesh from a sequence of
5325  * meshes each representing a group, and creates corresponding groups in \a this mesh.
5326  * The given meshes must share the same node coordinates array.
5327  *  \param [in] meshDimRelToMax - the relative dimension to create the mesh and groups at.
5328  *  \param [in] ms - the sequence of meshes. Each mesh in \a ms represents a group to
5329  *          create in \a this mesh.
5330  *  \throw If \a ms is empty.
5331  *  \throw If dimension of meshes in \a ms does not correspond to \a meshDimRelToMax or
5332  *         to the existing meshes of other levels of \a this mesh.
5333  *  \throw If the meshes in \a ms do not share the same node coordinates array.
5334  *  \throw If the node coordinates array of \a this mesh (if any) is not the same as that
5335  *         of the given meshes.
5336  *  \throw If \a ms[ i ] is not well defined (MEDCouplingUMesh::checkConsistencyLight()).
5337  *  \throw If names of some meshes in \a ms are equal.
5338  *  \throw If \a ms includes a mesh with an empty name.
5339  */
5340 void MEDFileUMesh::setGroupsFromScratch(int meshDimRelToMax, const std::vector<const MEDCouplingUMesh *>& ms, bool renum)
5341 {
5342   if(ms.empty())
5343     throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsFromScratch : expecting a non empty vector !");
5344   int sz=(-meshDimRelToMax)+1;
5345   if(sz>=(int)_ms.size())
5346     _ms.resize(sz);
5347   checkMeshDimCoherency(ms[0]->getMeshDimension(),meshDimRelToMax);
5348   DataArrayDouble *coo=checkMultiMesh(ms);
5349   if((DataArrayDouble *)_coords==0)
5350     {
5351       coo->incrRef();
5352       _coords=coo;
5353     }
5354   else
5355     if((DataArrayDouble *)_coords!=coo)
5356       throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsFromScratch : coordinates mismatches !");
5357   std::vector<DataArrayIdType *> corr;
5358   MCAuto<MEDCouplingUMesh> m=MEDCouplingUMesh::FuseUMeshesOnSameCoords(ms,_zipconn_pol,corr);
5359   std::vector< MCAuto<DataArrayIdType> > corr3(corr.begin(),corr.end());
5360   setMeshAtLevel(meshDimRelToMax,m,renum);
5361   std::vector<const DataArrayIdType *> corr2(corr.begin(),corr.end());
5362   setGroupsAtLevel(meshDimRelToMax,corr2,true);
5363 }
5364
5365 /*!
5366  * Creates groups at a given level in \a this mesh from a sequence of
5367  * meshes each representing a group.
5368  * The given meshes must share the same node coordinates array.
5369  *  \param [in] meshDimRelToMax - the relative dimension to create the groups at.
5370  *  \param [in] ms - the sequence of meshes. Each mesh in \a ms represents a group to
5371  *         create in \a this mesh.
5372  *  \param [in] renum - if \c true, then the optional numbers of entities are taken into
5373  *         account. 
5374  *  \throw If \a ms is empty.
5375  *  \throw If dimension of meshes in \a ms does not correspond to \a meshDimRelToMax or
5376  *         to the existing meshes of other levels of \a this mesh.
5377  *  \throw If the meshes in \a ms do not share the same node coordinates array.
5378  *  \throw If the node coordinates array of \a this mesh (if any) is not the same as that
5379  *         of the given meshes.
5380  *  \throw If \a ms[ i ] is not well defined (MEDCouplingUMesh::checkConsistencyLight()).
5381  *  \throw If names of some meshes in \a ms are equal.
5382  *  \throw If \a ms includes a mesh with an empty name.
5383  */
5384 void MEDFileUMesh::setGroupsOnSetMesh(int meshDimRelToMax, const std::vector<const MEDCouplingUMesh *>& ms, bool renum)
5385 {
5386   if(ms.empty())
5387     throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsOnSetMesh : expecting a non empty vector !");
5388   int sz=(-meshDimRelToMax)+1;
5389   if(sz>=(int)_ms.size())
5390     _ms.resize(sz);
5391   checkMeshDimCoherency(ms[0]->getMeshDimension(),meshDimRelToMax);
5392   DataArrayDouble *coo=checkMultiMesh(ms);
5393   if((DataArrayDouble *)_coords==0)
5394     {
5395       coo->incrRef();
5396       _coords=coo;
5397     }
5398   else
5399     if((DataArrayDouble *)_coords!=coo)
5400       throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsOnSetMesh : coordinates mismatches !");
5401   MEDCouplingUMesh *m=getMeshAtLevel(meshDimRelToMax,renum);
5402   std::vector< MCAuto<DataArrayIdType> > corr(ms.size());
5403   int i=0;
5404   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++,i++)
5405     {
5406       DataArrayIdType *arr=0;
5407       bool test=m->areCellsIncludedIn(*it,_zipconn_pol,arr);
5408       corr[i]=arr;
5409       if(!test)
5410         {
5411           std::ostringstream oss; oss << "MEDFileUMesh::setGroupsOnSetMesh : mesh #" << i << " is not part of whole mesh !";
5412           throw INTERP_KERNEL::Exception(oss.str().c_str());
5413         }
5414     }
5415   std::vector<const DataArrayIdType *> corr2(corr.begin(),corr.end());
5416   setGroupsAtLevel(meshDimRelToMax,corr2,renum);
5417 }
5418
5419 DataArrayDouble *MEDFileUMesh::checkMultiMesh(const std::vector<const MEDCouplingUMesh *>& ms) const
5420 {
5421   const DataArrayDouble *ret=ms[0]->getCoords();
5422   int mdim=ms[0]->getMeshDimension();
5423   for(unsigned int i=1;i<ms.size();i++)
5424     {
5425       ms[i]->checkConsistencyLight();
5426       if(ms[i]->getCoords()!=ret)
5427         throw INTERP_KERNEL::Exception("MEDFileUMesh::checkMultiMesh : meshes must share the same coords !");
5428       if(ms[i]->getMeshDimension()!=mdim)
5429         throw INTERP_KERNEL::Exception("MEDFileUMesh::checkMultiMesh : meshes have not same mesh dimension !");
5430     }
5431   return const_cast<DataArrayDouble *>(ret);
5432 }
5433
5434 /*!
5435  * Sets the family field of a given relative dimension.
5436  *  \param [in] meshDimRelToMaxExt - the relative dimension of entities for which
5437  *          the family field is set.
5438  *  \param [in] famArr - the array of the family field.
5439  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
5440  *  \throw If \a famArr has an invalid size.
5441  */
5442 void MEDFileUMesh::setFamilyFieldArr(int meshDimRelToMaxExt, DataArrayIdType *famArr)
5443 {
5444   if(meshDimRelToMaxExt==1)
5445     {
5446       if(!famArr)
5447         {
5448           _fam_coords=0;
5449           return ;
5450         }
5451       DataArrayDouble *coo(_coords);
5452       if(!coo)
5453         throw INTERP_KERNEL::Exception("MEDFileUMesh::setFamilyFieldArr : the coordinates have not been set !");
5454       famArr->checkNbOfTuplesAndComp(coo->getNumberOfTuples(),1,"MEDFileUMesh::setFamilyFieldArr : Problem in size of node family arr ! ");
5455       _fam_coords.takeRef(famArr);
5456       return ;
5457     }
5458   if(meshDimRelToMaxExt>1)
5459     throw INTERP_KERNEL::Exception("MEDFileUMesh::setFamilyFieldArr : Dimension request is invalid (>1) !");
5460   int traducedRk=-meshDimRelToMaxExt;
5461   if(traducedRk>=(int)_ms.size())
5462     throw INTERP_KERNEL::Exception("Invalid mesh dim relative to max given ! Too low !");
5463   if((MEDFileUMeshSplitL1 *)_ms[traducedRk]==0)
5464     throw INTERP_KERNEL::Exception("On specified lev (or entity) no cells exists !");
5465   return _ms[traducedRk]->setFamilyArr(famArr);
5466 }
5467
5468 /*!
5469  * Sets the optional numbers of mesh entities of a given dimension.
5470  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
5471  *  \param [in] renumArr - the array of the numbers.
5472  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
5473  *  \throw If \a renumArr has an invalid size.
5474  */
5475 void MEDFileUMesh::setRenumFieldArr(int meshDimRelToMaxExt, DataArrayIdType *renumArr)
5476 {
5477   if(meshDimRelToMaxExt==1)
5478     {
5479       if(!renumArr)
5480         {
5481           _num_coords.nullify();
5482           _rev_num_coords.nullify();
5483           return ;
5484         }
5485       if(_coords.isNull())
5486         throw INTERP_KERNEL::Exception("MEDFileUMesh::setRenumFieldArr : the coordinates have not been set !");
5487       renumArr->checkNbOfTuplesAndComp(_coords->getNumberOfTuples(),1,"MEDFileUMesh::setRenumArr : Problem in size of node numbering arr ! ");
5488       _num_coords.takeRef(renumArr);
5489       computeRevNum();
5490       return ;
5491     }
5492   if(meshDimRelToMaxExt>1)
5493     throw INTERP_KERNEL::Exception("MEDFileUMesh::setRenumArr : Dimension request is invalid (>1) !");
5494   int traducedRk=-meshDimRelToMaxExt;
5495   if(traducedRk>=(int)_ms.size())
5496     throw INTERP_KERNEL::Exception("Invalid mesh dim relative to max given ! Too low !");
5497   if((MEDFileUMeshSplitL1 *)_ms[traducedRk]==0)
5498     throw INTERP_KERNEL::Exception("On specified lev (or entity) no cells exists !");
5499   return _ms[traducedRk]->setRenumArr(renumArr);
5500 }
5501
5502 /*!
5503  * Sets the optional names of mesh entities of a given dimension.
5504  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
5505  *  \param [in] nameArr - the array of the names.
5506  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
5507  *  \throw If \a nameArr has an invalid size.
5508  */
5509 void MEDFileUMesh::setNameFieldAtLevel(int meshDimRelToMaxExt, DataArrayAsciiChar *nameArr)
5510 {
5511   if(meshDimRelToMaxExt==1)
5512     {
5513       if(!nameArr)
5514         {
5515           _name_coords=0;
5516           return ;
5517         }
5518       DataArrayDouble *coo(_coords);
5519       if(!coo)
5520         throw INTERP_KERNEL::Exception("MEDFileUMesh::setNameFieldAtLevel : the coordinates have not been set !");
5521       nameArr->checkNbOfTuplesAndComp(coo->getNumberOfTuples(),MED_SNAME_SIZE,"MEDFileUMesh::setNameFieldAtLevel : Problem in size of node numbering arr ! ");
5522       _name_coords.takeRef(nameArr);
5523       return ;
5524     }
5525   if(meshDimRelToMaxExt>1)
5526     throw INTERP_KERNEL::Exception("MEDFileUMesh::setNameFieldAtLevel : Dimension request is invalid (>1) !");
5527   int traducedRk=-meshDimRelToMaxExt;
5528   if(traducedRk>=(int)_ms.size())
5529     throw INTERP_KERNEL::Exception("Invalid mesh dim relative to max given ! Too low !");
5530   if((MEDFileUMeshSplitL1 *)_ms[traducedRk]==0)
5531     throw INTERP_KERNEL::Exception("On specified lev (or entity) no cells exists !");
5532   return _ms[traducedRk]->setNameArr(nameArr);
5533 }
5534
5535 void MEDFileUMesh::setGlobalNumFieldAtLevel(int meshDimRelToMaxExt, DataArrayIdType *globalNumArr)
5536 {
5537   if(meshDimRelToMaxExt!=1)
5538     throw INTERP_KERNEL::Exception("MEDFileUMesh::setGlobalNumFieldAtLevel : Only implemented for meshDimRelToMaxExt==1 for the moment !");
5539   if(globalNumArr)
5540     globalNumArr->checkNbOfTuplesAndComp(_coords->getNumberOfTuples(),1,"MEDFileUMesh::setGlobalNumFieldAtLevel : Problem in size of node global numbering arr ! ");
5541   _global_num_coords.takeRef(globalNumArr);
5542 }
5543
5544 void MEDFileUMesh::synchronizeTinyInfoOnLeaves() const
5545 {
5546   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
5547     if((const MEDFileUMeshSplitL1 *)(*it))
5548       (*it)->synchronizeTinyInfo(*this);
5549 }
5550
5551 /*!
5552  * This method is called by MEDFileMesh::changeFamilyId. It performs only one part of the family id modification.
5553  */
5554 void MEDFileUMesh::changeFamilyIdArr(mcIdType oldId, mcIdType newId)
5555 {
5556   DataArrayIdType *arr=_fam_coords;
5557   if(arr)
5558     arr->changeValue(oldId,newId);
5559   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::iterator it=_ms.begin();it!=_ms.end();it++)
5560     {
5561       MEDFileUMeshSplitL1 *sp=(*it);
5562       if(sp)
5563         {
5564           sp->changeFamilyIdArr(oldId,newId);
5565         }
5566     }
5567 }
5568
5569 std::list< MCAuto<DataArrayIdType> > MEDFileUMesh::getAllNonNullFamilyIds() const
5570 {
5571   std::list< MCAuto<DataArrayIdType> > ret;
5572   const DataArrayIdType *da(_fam_coords);
5573   if(da)
5574     { da->incrRef(); ret.push_back(MCAuto<DataArrayIdType>(const_cast<DataArrayIdType *>(da))); }
5575   for(std::vector< MCAuto<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
5576     {
5577       const MEDFileUMeshSplitL1 *elt(*it);
5578       if(elt)
5579         {
5580           da=elt->getFamilyField();
5581           if(da)
5582             { da->incrRef(); ret.push_back(MCAuto<DataArrayIdType>(const_cast<DataArrayIdType *>(da))); }
5583         }
5584     }
5585   return ret;
5586 }
5587
5588 void MEDFileUMesh::computeRevNum() const
5589 {
5590   if(_num_coords.isNotNull())
5591     {
5592       mcIdType pos;
5593       mcIdType maxValue=_num_coords->getMaxValue(pos);
5594       _rev_num_coords=_num_coords->invertArrayN2O2O2N(maxValue+1);
5595     }
5596 }
5597
5598 std::size_t MEDFileStructuredMesh::getHeapMemorySizeWithoutChildren() const
5599 {
5600   return MEDFileMesh::getHeapMemorySizeWithoutChildren();
5601 }
5602
5603 std::vector<const BigMemoryObject *> MEDFileStructuredMesh::getDirectChildrenWithNull() const
5604 {
5605   std::vector<const BigMemoryObject *> ret(MEDFileMesh::getDirectChildrenWithNull());
5606   ret.push_back((const DataArrayIdType *)_fam_nodes);
5607   ret.push_back((const DataArrayIdType *)_num_nodes);
5608   ret.push_back((const DataArrayAsciiChar *)_names_nodes);
5609   ret.push_back((const DataArrayIdType *)_fam_cells);
5610   ret.push_back((const DataArrayIdType *)_num_cells);
5611   ret.push_back((const DataArrayAsciiChar *)_names_cells);
5612   ret.push_back((const DataArrayIdType *)_fam_faces);
5613   ret.push_back((const DataArrayIdType *)_num_faces);
5614   ret.push_back((const DataArrayIdType *)_rev_num_nodes);
5615   ret.push_back((const DataArrayAsciiChar *)_names_faces);
5616   ret.push_back((const DataArrayIdType *)_rev_num_cells);
5617   ret.push_back((const MEDCoupling1SGTUMesh*)_faces_if_necessary);
5618   return ret;
5619 }
5620
5621 mcIdType MEDFileStructuredMesh::getMaxAbsFamilyIdInArrays() const
5622 {
5623   mcIdType ret=-std::numeric_limits<mcIdType>::max(),tmp=-1;
5624   if((const DataArrayIdType *)_fam_nodes)
5625     {
5626       mcIdType val=_fam_nodes->getMaxValue(tmp);
5627       ret=std::max(ret,std::abs(val));
5628     }
5629   if((const DataArrayIdType *)_fam_cells)
5630     {
5631       mcIdType val=_fam_cells->getMaxValue(tmp);
5632       ret=std::max(ret,std::abs(val));
5633     }
5634   if((const DataArrayIdType *)_fam_faces)
5635     {
5636       mcIdType val=_fam_faces->getMaxValue(tmp);
5637       ret=std::max(ret,std::abs(val));
5638     }
5639   return ret;
5640 }
5641
5642 mcIdType MEDFileStructuredMesh::getMaxFamilyIdInArrays() const
5643 {
5644   mcIdType ret=-std::numeric_limits<mcIdType>::max(),tmp=-1;
5645   if((const DataArrayIdType *)_fam_nodes)
5646     {
5647       mcIdType val=_fam_nodes->getMaxValue(tmp);
5648       ret=std::max(ret,val);
5649     }
5650   if((const DataArrayIdType *)_fam_cells)
5651     {
5652       mcIdType val=_fam_cells->getMaxValue(tmp);
5653       ret=std::max(ret,val);
5654     }
5655   if((const DataArrayIdType *)_fam_faces)
5656     {
5657       mcIdType val=_fam_faces->getMaxValue(tmp);
5658       ret=std::max(ret,val);
5659     }
5660   return ret;
5661 }
5662
5663 mcIdType MEDFileStructuredMesh::getMinFamilyIdInArrays() const
5664 {
5665   mcIdType ret=std::numeric_limits<mcIdType>::max(),tmp=-1;
5666   if((const DataArrayIdType *)_fam_nodes)
5667     {
5668       mcIdType val=_fam_nodes->getMinValue(tmp);
5669       ret=std::min(ret,val);
5670     }
5671   if((const DataArrayIdType *)_fam_cells)
5672     {
5673       mcIdType val=_fam_cells->getMinValue(tmp);
5674       ret=std::min(ret,val);
5675     }
5676   if((const DataArrayIdType *)_fam_faces)
5677     {
5678       mcIdType val=_fam_faces->getMinValue(tmp);
5679       ret=std::min(ret,val);
5680     }
5681   return ret;
5682 }
5683
5684 bool MEDFileStructuredMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const
5685 {
5686   if(!MEDFileMesh::isEqual(other,eps,what))
5687     return false;
5688   const MEDFileStructuredMesh *otherC=dynamic_cast<const  MEDFileStructuredMesh *>(other);
5689   if(!otherC)
5690     {
5691       what="Mesh types differ ! This is structured and other is NOT !";
5692       return false;
5693     }
5694   const DataArrayIdType *famc1=_fam_nodes;
5695   const DataArrayIdType *famc2=otherC->_fam_nodes;
5696   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
5697     {
5698       what="Mismatch of families arr on nodes ! One is defined and not other !";
5699       return false;
5700     }
5701   if(famc1)
5702     {
5703       bool ret=famc1->isEqual(*famc2);
5704       if(!ret)
5705         {
5706           what="Families arr on nodes differ !";
5707           return false;
5708         }
5709     }
5710   famc1=_fam_cells;
5711   famc2=otherC->_fam_cells;
5712   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
5713     {
5714       what="Mismatch of families arr on cells ! One is defined and not other !";
5715       return false;
5716     }
5717   if(famc1)
5718     {
5719       bool ret=famc1->isEqual(*famc2);
5720       if(!ret)
5721         {
5722           what="Families arr on cells differ !";
5723           return false;
5724         }
5725     }
5726   famc1=_fam_faces;
5727   famc2=otherC->_fam_faces;
5728   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
5729     {
5730       what="Mismatch of families arr on faces ! One is defined and not other !";
5731       return false;
5732     }
5733   if(famc1)
5734     {
5735       bool ret=famc1->isEqual(*famc2);
5736       if(!ret)
5737         {
5738           what="Families arr on faces differ !";
5739           return false;
5740         }
5741     }
5742   famc1=_num_nodes;
5743   famc2=otherC->_num_nodes;
5744   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
5745     {
5746       what="Mismatch of numbering arr on nodes ! One is defined and not other !";
5747       return false;
5748     }
5749   if(famc1)
5750     {
5751       bool ret=famc1->isEqual(*famc2);
5752       if(!ret)
5753         {
5754           what="Numbering arr on nodes differ !";
5755           return false;
5756         }
5757     }
5758   famc1=_num_cells;
5759   famc2=otherC->_num_cells;
5760   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
5761     {
5762       what="Mismatch of numbering arr on cells ! One is defined and not other !";
5763       return false;
5764     }
5765   if(famc1)
5766     {
5767       bool ret=famc1->isEqual(*famc2);
5768       if(!ret)
5769         {
5770           what="Numbering arr on cells differ !";
5771           return false;
5772         }
5773     }
5774   famc1=_num_faces;
5775   famc2=otherC->_num_faces;
5776   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
5777     {
5778       what="Mismatch of numbering arr on faces ! One is defined and not other !";
5779       return false;
5780     }
5781   if(famc1)
5782     {
5783       bool ret=famc1->isEqual(*famc2);
5784       if(!ret)
5785         {
5786           what="Numbering arr on faces differ !";
5787           return false;
5788         }
5789     }
5790   const DataArrayAsciiChar *d1=_names_cells;
5791   const DataArrayAsciiChar *d2=otherC->_names_cells;
5792   if((d1==0 && d2!=0) || (d1!=0 && d2==0))
5793     {
5794       what="Mismatch of naming arr on cells ! One is defined and not other !";
5795       return false;
5796     }
5797   if(d1)
5798     {
5799       bool ret=d1->isEqual(*d2);
5800       if(!ret)
5801         {
5802           what="Naming arr on cells differ !";
5803           return false;
5804         }
5805     }
5806   d1=_names_faces;
5807   d2=otherC->_names_faces;
5808   if((d1==0 && d2!=0) || (d1!=0 && d2==0))
5809     {
5810       what="Mismatch of naming arr on faces ! One is defined and not other !";
5811       return false;
5812     }
5813   if(d1)
5814     {
5815       bool ret=d1->isEqual(*d2);
5816       if(!ret)
5817         {
5818           what="Naming arr on faces differ !";
5819           return false;
5820         }
5821     }
5822   d1=_names_nodes;
5823   d2=otherC->_names_nodes;
5824   if((d1==0 && d2!=0) || (d1!=0 && d2==0))
5825     {
5826       what="Mismatch of naming arr on nodes ! One is defined and not other !";
5827       return false;
5828     }
5829   if(d1)
5830     {
5831       bool ret=d1->isEqual(*d2);
5832       if(!ret)
5833         {
5834           what="Naming arr on nodes differ !";
5835           return false;
5836         }
5837     }
5838   return true;
5839 }
5840
5841 void MEDFileStructuredMesh::clearNonDiscrAttributes() const
5842 {
5843   MEDFileMesh::clearNonDiscrAttributes();
5844   const DataArrayIdType *tmp=_fam_nodes;
5845   if(tmp)
5846     (const_cast<DataArrayIdType *>(tmp))->setName("");
5847   tmp=_num_nodes;
5848   if(tmp)
5849     (const_cast<DataArrayIdType *>(tmp))->setName("");
5850   tmp=_fam_cells;
5851   if(tmp)
5852     (const_cast<DataArrayIdType *>(tmp))->setName("");
5853   tmp=_num_cells;
5854   if(tmp)
5855     (const_cast<DataArrayIdType *>(tmp))->setName("");
5856   tmp=_fam_faces;
5857   if(tmp)
5858     (const_cast<DataArrayIdType *>(tmp))->setName("");
5859   tmp=_num_faces;
5860   if(tmp)
5861     (const_cast<DataArrayIdType *>(tmp))->setName("");
5862 }
5863
5864 /*!
5865  * Returns ids of mesh entities contained in given families of a given dimension.
5866  *  \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids
5867  *          are required.
5868  *  \param [in] fams - the names of the families of interest.
5869  *  \param [in] renum - if \c true, the optional numbers of entities, if available, are
5870  *          returned instead of ids.
5871  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding either ids or
5872  *          numbers, if available and required, of mesh entities of the families. The caller
5873  *          is to delete this array using decrRef() as it is no more needed. 
5874  *  \throw If the family field is missing for \a meshDimRelToMaxExt.
5875  */
5876 DataArrayIdType *MEDFileStructuredMesh::getFamiliesArr(int meshDimRelToMaxExt, const std::vector<std::string>& fams, bool renum) const
5877 {
5878   std::vector<mcIdType> famIds(getFamiliesIds(fams));
5879   switch(meshDimRelToMaxExt)
5880   {
5881     case 1:
5882       {
5883         if((const DataArrayIdType *)_fam_nodes)
5884           {
5885             MCAuto<DataArrayIdType> da;
5886             if(!famIds.empty())
5887               da=_fam_nodes->findIdsEqualList(&famIds[0],&famIds[0]+famIds.size());
5888             else
5889               da=_fam_nodes->findIdsEqualList(0,0);
5890             if(renum)
5891               return MEDFileUMeshSplitL1::Renumber(_num_nodes,da);
5892             else
5893               return da.retn();
5894           }
5895         else
5896           throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamiliesArr : no family array specified on nodes !");
5897         break;
5898       }
5899     case 0:
5900       {
5901         if((const DataArrayIdType *)_fam_cells)
5902           {
5903             MCAuto<DataArrayIdType> da;
5904             if(!famIds.empty())
5905               da=_fam_cells->findIdsEqualList(&famIds[0],&famIds[0]+famIds.size());
5906             else
5907               da=_fam_cells->findIdsEqualList(0,0);
5908             if(renum)
5909               return MEDFileUMeshSplitL1::Renumber(_num_cells,da);
5910             else
5911               return da.retn();
5912           }
5913         else
5914           throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamiliesArr : no family array specified on cells !");
5915         break;
5916       }
5917     case -1:
5918       {
5919         if((const DataArrayIdType *)_fam_faces)
5920           {
5921             MCAuto<DataArrayIdType> da;
5922             if(!famIds.empty())
5923               da=_fam_faces->findIdsEqualList(&famIds[0],&famIds[0]+famIds.size());
5924             else
5925               da=_fam_faces->findIdsEqualList(0,0);
5926             if(renum)
5927               return MEDFileUMeshSplitL1::Renumber(_num_faces,da);
5928             else
5929               return da.retn();
5930           }
5931         else
5932           throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamiliesArr : no family array specified on faces !");
5933         break;
5934       }
5935     default:
5936       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamiliesArr : input meshDimRelative must be in [0,1,-1] !");
5937   }
5938   throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamiliesArr : unmanaged case !");
5939 }
5940
5941 /*!
5942  * Sets the family field of a given relative dimension.
5943  *  \param [in] meshDimRelToMaxExt - the relative dimension of entities for which
5944  *          the family field is set.
5945  *  \param [in] famArr - the array of the family field.
5946  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
5947  *  \throw If \a famArr has an invalid size.
5948  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1 and \a meshDimRelToMaxExt != -1.
5949  */
5950 void MEDFileStructuredMesh::setFamilyFieldArr(int meshDimRelToMaxExt, DataArrayIdType *famArr)
5951 {
5952   const MEDCouplingStructuredMesh *mesh(getStructuredMesh());
5953   if(!mesh)
5954     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setFamilyFieldArr : no structured mesh specified ! Impossible to set family array !");
5955   switch(meshDimRelToMaxExt)
5956   {
5957     case 0:
5958       {
5959         mcIdType nbCells(mesh->getNumberOfCells());
5960         if(famArr)
5961           famArr->checkNbOfTuplesAndComp(nbCells,1,"MEDFileStructuredMesh::setFamilyFieldArr : Problem in size of Family arr ! Mismatch with number of cells of mesh !");
5962         _fam_cells=famArr;
5963         break;
5964       }
5965     case 1:
5966       {
5967         mcIdType nbNodes(mesh->getNumberOfNodes());
5968         if(famArr)
5969           famArr->checkNbOfTuplesAndComp(nbNodes,1,"MEDFileStructuredMesh::setFamilyFieldArr : Problem in size of Family arr ! Mismatch with number of nodes of mesh !");
5970         _fam_nodes=famArr;
5971         break;
5972       }
5973     case -1:
5974       {
5975         mcIdType nbCells(mesh->getNumberOfCellsOfSubLevelMesh());
5976         if(famArr)
5977           famArr->checkNbOfTuplesAndComp(nbCells,1,"MEDFileStructuredMesh::setFamilyFieldArr : Problem in size of Family arr ! Mismatch with number of faces of mesh !");
5978         _fam_faces=famArr;
5979         break;
5980       }
5981     default:
5982       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setFamilyFieldArr : Only available for levels 0 or 1 or -1 !");
5983   }
5984   if(famArr)
5985     famArr->incrRef();
5986 }
5987
5988 /*!
5989  * Sets the optional numbers of mesh entities of a given dimension.
5990  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
5991  *  \param [in] renumArr - the array of the numbers.
5992  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
5993  *  \throw If \a renumArr has an invalid size.
5994  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1.
5995  */
5996 void MEDFileStructuredMesh::setRenumFieldArr(int meshDimRelToMaxExt, DataArrayIdType *renumArr)
5997 {
5998   const MEDCouplingStructuredMesh *mesh=getStructuredMesh();
5999   if(!mesh)
6000     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setRenumFieldArr : no structured mesh specified ! Impossible to set number array !");
6001   switch(meshDimRelToMaxExt)
6002   {
6003     case 0:
6004       {
6005         mcIdType nbCells=mesh->getNumberOfCells();
6006         renumArr->checkNbOfTuplesAndComp(nbCells,1,"MEDFileStructuredMesh::setRenumFieldArr : Problem in size of Renum arr ! Mismatch with number of cells of mesh !");
6007         _num_cells=renumArr;
6008         break;
6009       }
6010     case 1:
6011       {
6012         mcIdType nbNodes=mesh->getNumberOfNodes();
6013         renumArr->checkNbOfTuplesAndComp(nbNodes,1,"MEDFileStructuredMesh::setRenumFieldArr : Problem in size of Family arr ! Mismatch with number of nodes of mesh !");
6014         _num_nodes=renumArr;
6015         break;
6016       }
6017     case -1:
6018       {
6019         mcIdType nbCells=mesh->getNumberOfCellsOfSubLevelMesh();
6020         renumArr->checkNbOfTuplesAndComp(nbCells,1,"MEDFileStructuredMesh::setRenumFieldArr : Problem in size of Renum arr ! Mismatch with number of faces of mesh !");
6021         _num_faces=renumArr;
6022         break;
6023       }
6024     default:
6025       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setRenumFieldArr : Only available for levels 0 or 1 or -1 !");
6026   }
6027   if(renumArr)
6028     renumArr->incrRef();
6029 }
6030
6031 /*!
6032  * Sets the optional names of mesh entities of a given dimension.
6033  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
6034  *  \param [in] nameArr - the array of the names.
6035  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
6036  *  \throw If \a nameArr has an invalid size.
6037  */
6038 void MEDFileStructuredMesh::setNameFieldAtLevel(int meshDimRelToMaxExt, DataArrayAsciiChar *nameArr)
6039 {
6040   const MEDCouplingStructuredMesh *mesh(getStructuredMesh());
6041   if(!mesh)
6042     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setNameFieldAtLevel : no structured mesh specified ! Impossible to set names array !");
6043   switch(meshDimRelToMaxExt)
6044   {
6045     case 0:
6046       {
6047         mcIdType nbCells=mesh->getNumberOfCells();
6048         nameArr->checkNbOfTuplesAndComp(nbCells,MED_SNAME_SIZE,"MEDFileStructuredMesh::setNameFieldAtLevel : Problem in size of names arr ! Mismatch with number of cells of mesh !");
6049         _names_cells=nameArr;
6050         break;
6051       }
6052     case 1:
6053       {
6054         mcIdType nbNodes=mesh->getNumberOfNodes();
6055         nameArr->checkNbOfTuplesAndComp(nbNodes,MED_SNAME_SIZE,"MEDFileStructuredMesh::setNameFieldAtLevel : Problem in size of names arr ! Mismatch with number of nodes of mesh !");
6056         _names_nodes=nameArr;
6057         break;
6058       }
6059     case -1:
6060       {
6061         mcIdType nbCells=mesh->getNumberOfCellsOfSubLevelMesh();
6062         nameArr->checkNbOfTuplesAndComp(nbCells,MED_SNAME_SIZE,"MEDFileStructuredMesh::setNameFieldAtLevel : Problem in size of names arr ! Mismatch with number of faces of mesh !");
6063         _names_faces=nameArr;
6064         break;
6065       }
6066     default:
6067       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setNameFieldAtLevel : Only available for levels 0 or 1 or -1 !");
6068   }
6069   if(nameArr)
6070     nameArr->incrRef();
6071 }
6072
6073 void MEDFileStructuredMesh::setGlobalNumFieldAtLevel(int meshDimRelToMaxExt, DataArrayIdType *globalNumArr)
6074 {
6075   throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setGlobalNumFieldAtLevel : not implemented yet !");
6076 }
6077
6078 /*!
6079  * Adds a group of nodes to \a this mesh.
6080  *  \param [in] ids - a DataArrayIdType providing ids and a name of the group to add.
6081  *          The ids should be sorted and different each other (MED file norm).
6082  *
6083  *  \warning this method can alter default "FAMILLE_ZERO" family.
6084  *  For users sensitive to this a call to MEDFileMesh::rearrangeFamilies will be necessary after addGroup session.
6085  *
6086  *  \throw If the node coordinates array is not set.
6087  *  \throw If \a ids == \c NULL.
6088  *  \throw If \a ids->getName() == "".
6089  *  \throw If \a ids does not respect the MED file norm.
6090  *  \throw If a group with name \a ids->getName() already exists.
6091  */
6092 void MEDFileStructuredMesh::addNodeGroup(const DataArrayIdType *ids)
6093 {
6094   addGroup(1,ids);
6095 }
6096
6097 /*!
6098  * Adds a group of nodes/cells/faces/edges to \a this mesh.
6099  *
6100  *  \param [in] ids - a DataArrayIdType providing ids and a name of the group to add.
6101  *          The ids should be sorted and different each other (MED file norm).
6102  *
6103  * \warning this method can alter default "FAMILLE_ZERO" family.
6104  * For users sensitive to this a call to MEDFileMesh::rearrangeFamilies will be necessary after addGroup session.
6105  *
6106  *  \throw If the node coordinates array is not set.
6107  *  \throw If \a ids == \c NULL.
6108  *  \throw If \a ids->getName() == "".
6109  *  \throw If \a ids does not respect the MED file norm.
6110  *  \throw If a group with name \a ids->getName() already exists.
6111  */
6112 void MEDFileStructuredMesh::addGroup(int meshDimRelToMaxExt, const DataArrayIdType *ids)
6113 {
6114   DataArrayIdType *fam(getOrCreateAndGetFamilyFieldAtLevel(meshDimRelToMaxExt));
6115   addGroupUnderground(false,ids,fam);
6116   return ;
6117 }
6118
6119 /*!
6120  * Returns the family field for mesh entities of a given dimension.
6121  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
6122  *  \return const DataArrayIdType * - the family field. It is an array of ids of families
6123  *          each mesh entity belongs to. It can be \c NULL.
6124  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1.
6125  */
6126 const DataArrayIdType *MEDFileStructuredMesh::getFamilyFieldAtLevel(int meshDimRelToMaxExt) const
6127 {
6128   switch(meshDimRelToMaxExt)
6129   {
6130     case 0:
6131       return _fam_cells;
6132     case 1:
6133       return _fam_nodes;
6134     case -1:
6135       return _fam_faces;
6136     default:
6137       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamilyFieldAtLevel : Only available for levels 0 or 1 or -1 !");
6138   }
6139 }
6140
6141 /*!
6142  * Returns the family field for mesh entities of a given dimension.
6143  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
6144  *  \return const DataArrayIdType * - the family field. It is an array of ids of families
6145  *          each mesh entity belongs to. It can be \c NULL.
6146  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1.
6147  */
6148 DataArrayIdType *MEDFileStructuredMesh::getFamilyFieldAtLevel(int meshDimRelToMaxExt)
6149 {
6150   switch(meshDimRelToMaxExt)
6151   {
6152     case 0:
6153       return _fam_cells;
6154     case 1:
6155       return _fam_nodes;
6156     case -1:
6157       return _fam_faces;
6158     default:
6159       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamilyFieldAtLevel : Only available for levels 0 or 1 or -1 !");
6160   }
6161 }
6162
6163 /*!
6164  * Returns the optional numbers of mesh entities of a given dimension.
6165  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
6166  *  \return const DataArrayIdType * - the array of the entity numbers.
6167  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
6168  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1.
6169  */
6170 const DataArrayIdType *MEDFileStructuredMesh::getNumberFieldAtLevel(int meshDimRelToMaxExt) const
6171 {
6172   switch(meshDimRelToMaxExt)
6173   {
6174     case 0:
6175       return _num_cells;
6176     case 1:
6177       return _num_nodes;
6178     case -1:
6179       return _num_faces;
6180     default:
6181       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getNumberFieldAtLevel : Only available for levels 0 or 1 or -1 !");
6182   }
6183 }
6184
6185 /*!
6186  * Returns the optional numbers of mesh entities of a given dimension transformed using
6187  * DataArrayIdType::invertArrayN2O2O2N().
6188  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
6189  *  \return const DataArrayIdType * - the array of the entity numbers transformed using
6190  *          DataArrayIdType::invertArrayN2O2O2N().
6191  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1.
6192  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
6193  */
6194 const DataArrayIdType *MEDFileStructuredMesh::getRevNumberFieldAtLevel(int meshDimRelToMaxExt) const
6195 {
6196   if(meshDimRelToMaxExt!=0 && meshDimRelToMaxExt!=1)
6197     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getRevNumberFieldAtLevel : Only available for levels 0 or 1 !");
6198   if(meshDimRelToMaxExt==0)
6199     {
6200       if((const DataArrayIdType *)_num_cells)
6201         {
6202           mcIdType pos;
6203           mcIdType maxValue=_num_cells->getMaxValue(pos);
6204           _rev_num_cells=_num_cells->invertArrayN2O2O2N(maxValue+1);
6205           return _rev_num_cells;
6206         }
6207       else
6208         throw INTERP_KERNEL::Exception("MEDFileCMesh::getRevNumberFieldAtLevel : no cell renumbering for a request on reverse numbering !");
6209     }
6210   else
6211     {
6212       if((const DataArrayIdType *)_num_nodes)
6213         {
6214           mcIdType pos;
6215           mcIdType maxValue=_num_nodes->getMaxValue(pos);
6216           _rev_num_nodes=_num_nodes->invertArrayN2O2O2N(maxValue+1);
6217           return _rev_num_nodes;
6218         }
6219       else
6220         throw INTERP_KERNEL::Exception("MEDFileCMesh::getRevNumberFieldAtLevel : no node renumbering for a request on reverse numbering !");
6221     }
6222 }
6223
6224 const DataArrayAsciiChar *MEDFileStructuredMesh::getNameFieldAtLevel(int meshDimRelToMaxExt) const
6225 {
6226   switch(meshDimRelToMaxExt)
6227   {
6228     case 0:
6229       return _names_cells;
6230     case 1:
6231       return _names_nodes;
6232     case -1:
6233       return _names_faces;
6234     default:
6235       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getNameFieldAtLevel : Only available for levels 0 or 1 or -1 !");
6236   }
6237 }
6238
6239 MCAuto<DataArrayIdType> MEDFileStructuredMesh::getGlobalNumFieldAtLevel(int meshDimRelToMaxExt) const
6240 {
6241   throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getGlobalNumFieldAtLevel : not implemented yet for structured mesh !");
6242 }
6243
6244 /*!
6245  * Returns relative dimensions of mesh entities (excluding nodes) present in \a this mesh.
6246  *  \return std::vector<int> - a sequence of the relative dimensions: [0].
6247  */
6248 std::vector<int> MEDFileStructuredMesh::getNonEmptyLevels() const
6249 {
6250   std::vector<int> ret(1);
6251   return ret;
6252 }
6253
6254 /*!
6255  * Returns relative dimensions of mesh entities (including nodes) present in \a this mesh.
6256  *  \return std::vector<int> - a sequence of the relative dimensions: [1,0].
6257  */
6258 std::vector<int> MEDFileStructuredMesh::getNonEmptyLevelsExt() const
6259 {
6260   std::vector<int> ret(2);
6261   ret[0]=1;
6262   return ret;
6263 }
6264
6265 /*!
6266  * Returns the set of extensive levels (nodes included) where not NULL family arr are defined.
6267  */
6268 std::vector<int> MEDFileStructuredMesh::getFamArrNonEmptyLevelsExt() const
6269 {
6270   std::vector<int> ret;
6271   const DataArrayIdType *famNodes(_fam_nodes),*famCells(_fam_cells),*famFaces(_fam_faces);
6272   if(famNodes)
6273     ret.push_back(1);
6274   if(famCells)
6275     ret.push_back(0);
6276   if(famFaces)
6277     ret.push_back(-1);
6278   return ret;
6279 }
6280
6281 /*!
6282  * Returns the set of extensive levels (nodes included) where not NULL numbering arr are defined.
6283  */
6284 std::vector<int> MEDFileStructuredMesh::getNumArrNonEmptyLevelsExt() const
6285 {
6286   std::vector<int> ret;
6287   const DataArrayIdType *numNodes(_num_nodes),*numCells(_num_cells),*numFaces(_num_faces);
6288   if(numNodes)
6289     ret.push_back(1);
6290   if(numCells)
6291     ret.push_back(0);
6292   if(numFaces)
6293     ret.push_back(-1);
6294   return ret;
6295 }
6296
6297 /*!
6298  * Returns the set of extensive levels (nodes included) where not NULL naming arr are defined.
6299  */
6300 std::vector<int> MEDFileStructuredMesh::getNameArrNonEmptyLevelsExt() const
6301 {
6302   std::vector<int> ret;
6303   const DataArrayAsciiChar *namesNodes(_names_nodes),*namesCells(_names_cells),*namesFaces(_names_faces);
6304   if(namesNodes)
6305     ret.push_back(1);
6306   if(namesCells)
6307     ret.push_back(0);
6308   if(namesFaces)
6309     ret.push_back(-1);
6310   return ret;
6311 }
6312
6313 /*!
6314  * no implementation here, it is not a bug, but intresically no polyhedra in \a this.
6315  */
6316 bool MEDFileStructuredMesh::unPolyze(std::vector<mcIdType>& oldCode, std::vector<mcIdType>& newCode, DataArrayIdType *& o2nRenumCell)
6317 {
6318   oldCode.clear(); newCode.clear(); o2nRenumCell=0;
6319   return false;
6320 }
6321
6322 void MEDFileStructuredMesh::changeFamilyIdArr(mcIdType oldId, mcIdType newId)
6323 {
6324   DataArrayIdType *arr=_fam_nodes;
6325   if(arr)
6326     arr->changeValue(oldId,newId);
6327   arr=_fam_cells;
6328   if(arr)
6329     arr->changeValue(oldId,newId);
6330   arr=_fam_faces;
6331   if(arr)
6332     arr->changeValue(oldId,newId);
6333 }
6334
6335 std::list< MCAuto<DataArrayIdType> > MEDFileStructuredMesh::getAllNonNullFamilyIds() const
6336 {
6337   std::list< MCAuto<DataArrayIdType> > ret;
6338   const DataArrayIdType *da(_fam_nodes);
6339   if(da)
6340     { da->incrRef(); ret.push_back(MCAuto<DataArrayIdType>(const_cast<DataArrayIdType *>(da))); }
6341   da=_fam_cells;
6342   if(da)
6343     { da->incrRef(); ret.push_back(MCAuto<DataArrayIdType>(const_cast<DataArrayIdType *>(da))); }
6344   da=_fam_faces;
6345   if(da)
6346     { da->incrRef(); ret.push_back(MCAuto<DataArrayIdType>(const_cast<DataArrayIdType *>(da))); }
6347   return ret;
6348 }
6349
6350 void MEDFileStructuredMesh::deepCpyAttributes()
6351 {
6352   if((const DataArrayIdType*)_fam_nodes)
6353     _fam_nodes=_fam_nodes->deepCopy();
6354   if((const DataArrayIdType*)_num_nodes)
6355     _num_nodes=_num_nodes->deepCopy();
6356   if((const DataArrayAsciiChar*)_names_nodes)
6357     _names_nodes=_names_nodes->deepCopy();
6358   if((const DataArrayIdType*)_fam_cells)
6359     _fam_cells=_fam_cells->deepCopy();
6360   if((const DataArrayIdType*)_num_cells)
6361     _num_cells=_num_cells->deepCopy();
6362   if((const DataArrayAsciiChar*)_names_cells)
6363     _names_cells=_names_cells->deepCopy();
6364   if((const DataArrayIdType*)_fam_faces)
6365     _fam_faces=_fam_faces->deepCopy();
6366   if((const DataArrayIdType*)_num_faces)
6367     _num_faces=_num_faces->deepCopy();
6368   if((const DataArrayAsciiChar*)_names_faces)
6369     _names_faces=_names_faces->deepCopy();
6370   if((const DataArrayIdType*)_rev_num_nodes)
6371     _rev_num_nodes=_rev_num_nodes->deepCopy();
6372   if((const DataArrayIdType*)_rev_num_cells)
6373     _rev_num_cells=_rev_num_cells->deepCopy();
6374 }
6375
6376 /*!
6377  * Returns a pointer to mesh at the specified level (here 0 is compulsory for cartesian mesh).
6378  * 
6379  * \return a pointer to cartesian mesh that need to be managed by the caller.
6380  * \warning the returned pointer has to be managed by the caller.
6381  */
6382
6383 /*!
6384  * Returns a pointer to MEDCouplingStructuredMesh held by \a this. 
6385  *  \param [in] meshDimRelToMax - it must be \c 0 or \c -1.
6386  *  \param [in] renum - it must be \c false.
6387  *  \return MEDCouplingMesh * - a pointer to MEDCouplingMesh that the caller is to
6388  *          delete using decrRef() as it is no more needed. 
6389  */
6390 MEDCouplingMesh *MEDFileStructuredMesh::getMeshAtLevel(int meshDimRelToMax, bool renum) const
6391 {
6392   checkCartesian();
6393   if(renum)
6394     throw INTERP_KERNEL::Exception("MEDFileCurveLinearMesh does not support renumbering ! To do it perform request of renum array directly !");
6395   const MEDCouplingStructuredMesh *m(getStructuredMesh());
6396   switch(meshDimRelToMax)
6397   {
6398     case 0:
6399       {
6400         if(m)
6401           m->incrRef();
6402         return const_cast<MEDCouplingStructuredMesh *>(m);
6403       }
6404     case -1:
6405       {
6406         if(!m)
6407           throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getMeshAtLevel : level -1 requested must be non empty to be able to compute unstructured sub mesh !");
6408         buildMinusOneImplicitPartIfNeeded();
6409         MEDCoupling1SGTUMesh *ret(_faces_if_necessary);
6410         if(ret)
6411           ret->incrRef();
6412         return ret;
6413       }
6414     default:
6415       throw INTERP_KERNEL::Exception("MEDFileCurveLinearMesh does not support multi level for mesh 0 expected as input !");
6416   }
6417 }
6418
6419 std::vector<mcIdType> MEDFileStructuredMesh::getFamsNonEmptyLevels(const std::vector<std::string>& fams) const
6420 {
6421   std::vector<mcIdType> ret;
6422   const DataArrayIdType *famCells(_fam_cells),*famFaces(_fam_faces);
6423   if(famCells && famCells->presenceOfValue(ret))
6424     ret.push_back(0);
6425   if(famFaces && famFaces->presenceOfValue(ret))
6426     ret.push_back(-1);
6427   return ret;  
6428 }
6429
6430 std::vector<mcIdType> MEDFileStructuredMesh::getFamsNonEmptyLevelsExt(const std::vector<std::string>& fams) const
6431 {
6432   std::vector<mcIdType> ret(getFamsNonEmptyLevels(fams));
6433   const DataArrayIdType *famNodes(_fam_nodes);
6434   if(famNodes && famNodes->presenceOfValue(ret))
6435     ret.push_back(1);
6436   return ret;  
6437 }
6438
6439 /*!
6440  * Returns number of mesh entities of a given relative dimension in \a this mesh.
6441  *  \param [in] meshDimRelToMaxExt - the relative dimension of interest.
6442  *  \return mcIdType - the number of entities.
6443  *  \throw If no mesh entities of dimension \a meshDimRelToMaxExt are available in \a this mesh.
6444  */
6445 mcIdType MEDFileStructuredMesh::getSizeAtLevel(int meshDimRelToMaxExt) const
6446 {
6447   const MEDCouplingStructuredMesh *cmesh(getStructuredMesh());
6448   if(!cmesh)
6449     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getSizeAtLevel : No structured mesh set !");
6450   switch(meshDimRelToMaxExt)
6451   {
6452     case 0:
6453       return cmesh->getNumberOfCells();
6454     case 1:
6455       return cmesh->getNumberOfNodes();
6456     case -1:
6457       return cmesh->getNumberOfCellsOfSubLevelMesh();
6458     default:
6459       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getSizeAtLevel : Only available for levels 0 or 1 or -1 !");
6460   }
6461 }
6462
6463 mcIdType MEDFileStructuredMesh::getNumberOfNodes() const
6464 {
6465   const MEDCouplingStructuredMesh *cmesh(getStructuredMesh());
6466   if(!cmesh)
6467     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getNumberOfNodes : no cartesian mesh set !");
6468   return cmesh->getNumberOfNodes();
6469 }
6470
6471 mcIdType MEDFileStructuredMesh::getNumberOfCellsAtLevel(int meshDimRelToMaxExt) const
6472 {
6473   const MEDCouplingStructuredMesh *cmesh(getStructuredMesh());
6474   if(!cmesh)
6475     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getNumberOfNodes : no cartesian mesh set !");
6476   switch(meshDimRelToMaxExt)
6477   {
6478     case 0:
6479       return cmesh->getNumberOfCells();
6480     case -1:
6481       return cmesh->getNumberOfCellsOfSubLevelMesh();
6482     default:
6483       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getNumberOfNodes : only meshDimRelToMax=0 and meshDimRelToMax=-1 supported !");
6484     }
6485 }
6486
6487 bool MEDFileStructuredMesh::hasImplicitPart() const
6488 {
6489   return true;
6490 }
6491
6492 /*!
6493  * \sa MEDFileStructuredMesh::getImplicitFaceMesh
6494  */
6495 mcIdType MEDFileStructuredMesh::buildImplicitPartIfAny(INTERP_KERNEL::NormalizedCellType gt) const
6496 {
6497   static const char MSG[]="MEDFileStructuredMesh::buildImplicitPartIfAny : the given geo type is not manageable by a structured mesh !";
6498   const MEDCoupling1SGTUMesh *zeFaceMesh(_faces_if_necessary);
6499   if(!zeFaceMesh)
6500     {
6501       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(MEDCouplingStructuredMesh::GetGeoTypeGivenMeshDimension(getMeshDimension())));
6502       if(cm.getReverseExtrudedType()!=gt)
6503         throw INTERP_KERNEL::Exception(MSG);
6504       buildImplicitPart();
6505       return getStructuredMesh()->getNumberOfCellsOfSubLevelMesh();
6506     }
6507   else
6508     {
6509       if(gt!=zeFaceMesh->getCellModelEnum())
6510         throw INTERP_KERNEL::Exception(MSG);
6511       return zeFaceMesh->getNumberOfCells();
6512     }
6513 }
6514
6515 void MEDFileStructuredMesh::buildMinusOneImplicitPartIfNeeded() const
6516 {
6517   const MEDCoupling1SGTUMesh *zeFaceMesh(_faces_if_necessary);
6518   if(!zeFaceMesh)
6519     buildImplicitPart();
6520 }
6521
6522 void MEDFileStructuredMesh::buildImplicitPart() const
6523 {
6524   const MEDCouplingStructuredMesh *mcmesh(getStructuredMesh());
6525   if(!mcmesh)
6526     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::buildImplicitPart : Unable to build the implicit part of structured mesh because no structured mesh at level 0 defined !");
6527   _faces_if_necessary=mcmesh->build1SGTSubLevelMesh();
6528 }
6529
6530 void MEDFileStructuredMesh::releaseImplicitPartIfAny() const
6531 {
6532   _faces_if_necessary=0;
6533 }
6534
6535 /*!
6536  * Retrieves the internal pointer (no decrRef requested) of the implicit face mesh if any.
6537  * To force to build it you can invoke MEDFileStructuredMesh::buildImplicitPartIfAny method.
6538  * 
6539  * \sa MEDFileStructuredMesh::buildImplicitPartIfAny
6540  */
6541 MEDCoupling1SGTUMesh *MEDFileStructuredMesh::getImplicitFaceMesh() const
6542 {
6543   checkCartesian();
6544   return _faces_if_necessary;
6545 }
6546
6547 std::vector<INTERP_KERNEL::NormalizedCellType> MEDFileStructuredMesh::getGeoTypesAtLevel(int meshDimRelToMax) const
6548 {
6549   const MEDCouplingStructuredMesh *cmesh(getStructuredMesh());
6550   if(!cmesh)
6551     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getGeoTypesAtLevel : No structured mesh set !");
6552   switch(meshDimRelToMax)
6553   {
6554     case 0:
6555       {
6556         std::vector<INTERP_KERNEL::NormalizedCellType> ret(1,cmesh->getTypeOfCell(0));
6557         return ret;
6558       }
6559     case -1:
6560       {
6561         int mdim(cmesh->getMeshDimension());
6562         if(mdim<1)
6563           throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getGeoTypesAtLevel : only one level available for structured meshes ! Input 0 is mandatory or 0D mesh !");
6564         std::vector<INTERP_KERNEL::NormalizedCellType> ret(1,MEDCouplingStructuredMesh::GetGeoTypeGivenMeshDimension(mdim-1));
6565         return ret;
6566       }
6567     default:
6568       throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getGeoTypesAtLevel : only 2 levels available at most : 0 and -1 !");
6569   }
6570 }
6571
6572 mcIdType MEDFileStructuredMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType ct) const
6573 {
6574   if(ct!=MEDCouplingStructuredMesh::GetGeoTypeGivenMeshDimension(getMeshDimension()))
6575     return 0;
6576   else
6577     return getNumberOfCellsAtLevel(0);
6578 }
6579
6580 void MEDFileStructuredMesh::whichAreNodesFetched(const MEDFileField1TSStructItem& st, const MEDFileFieldGlobsReal *globs, std::vector<bool>& nodesFetched) const
6581 {
6582   if(st.getNumberOfItems()!=1)
6583     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::whichAreNodesFetched : The sturture of field is not lying on single geo type ! it is not managed yet for structured mesh !");
6584   if(st[0].getGeo()!=MEDCouplingStructuredMesh::GetGeoTypeGivenMeshDimension(getMeshDimension()))
6585     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::whichAreNodesFetched : The sturture of field is not lying on expected geo type !");
6586   if(getNumberOfNodes()!=(mcIdType)nodesFetched.size())
6587     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::whichAreNodesFetched : invalid size of array !");
6588   if(st[0].getPflName().empty())
6589     {
6590       std::fill(nodesFetched.begin(),nodesFetched.end(),true);
6591       return ;
6592     }
6593   const DataArrayIdType *arr(globs->getProfile(st[0].getPflName()));
6594   const MEDCouplingStructuredMesh *cmesh=getStructuredMesh();//cmesh not null because getNumberOfNodes called before
6595   mcIdType sz(ToIdType(nodesFetched.size()));
6596   for(const mcIdType *work=arr->begin();work!=arr->end();work++)
6597     {
6598       std::vector<mcIdType> conn;
6599       cmesh->getNodeIdsOfCell(*work,conn);
6600       for(std::vector<mcIdType>::const_iterator it=conn.begin();it!=conn.end();it++)
6601         if(*it>=0 && *it<sz)
6602           nodesFetched[*it]=true;
6603         else
6604           throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::whichAreNodesFetched : internal error !");
6605     }
6606 }
6607
6608 med_geometry_type MEDFileStructuredMesh::GetGeoTypeFromMeshDim(int meshDim)
6609 {
6610   INTERP_KERNEL::NormalizedCellType ct(MEDCouplingStructuredMesh::GetGeoTypeGivenMeshDimension(meshDim));
6611   return typmai3[ct];
6612 }
6613
6614 void MEDFileStructuredMesh::LoadStrMeshDAFromFile(med_idt fid, int meshDim, int dt, int it, const std::string& mName, MEDFileMeshReadSelector *mrs,
6615                                                   MCAuto<DataArrayIdType>& famCells, MCAuto<DataArrayIdType>& numCells, MCAuto<DataArrayAsciiChar>& namesCells)
6616 {
6617   med_bool chgt=MED_FALSE,trsf=MED_FALSE;
6618   med_geometry_type geoTypeReq=MEDFileStructuredMesh::GetGeoTypeFromMeshDim(meshDim);
6619   mcIdType nbOfElt(0);
6620   nbOfElt=MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_CELL,geoTypeReq,MED_FAMILY_NUMBER,MED_NODAL,&chgt,&trsf);
6621   if(nbOfElt>0)
6622     {
6623       if(!mrs || mrs->isCellFamilyFieldReading())
6624         {
6625           MCAuto<DataArrayMedInt> miFamCells=DataArrayMedInt::New();
6626           miFamCells->alloc(nbOfElt,1);
6627           MEDFILESAFECALLERRD0(MEDmeshEntityFamilyNumberRd,(fid,mName.c_str(),dt,it,MED_CELL,geoTypeReq,miFamCells->getPointer()));
6628           famCells = FromMedIntArray<mcIdType>( miFamCells );
6629         }
6630     }
6631   nbOfElt=MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_CELL,geoTypeReq,MED_NUMBER,MED_NODAL,&chgt,&trsf);
6632   if(nbOfElt>0)
6633     {
6634       if(!mrs || mrs->isCellNumFieldReading())
6635         {
6636           MCAuto<DataArrayMedInt> miNumCells=DataArrayMedInt::New();
6637           miNumCells->alloc(nbOfElt,1);
6638           MEDFILESAFECALLERRD0(MEDmeshEntityNumberRd,(fid,mName.c_str(),dt,it,MED_CELL,geoTypeReq,miNumCells->getPointer()));
6639           numCells = FromMedIntArray<mcIdType>( miNumCells );
6640         }
6641     }
6642   nbOfElt=MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_CELL,geoTypeReq,MED_NAME,MED_NODAL,&chgt,&trsf);
6643   if(nbOfElt>0)
6644     {
6645       if(!mrs || mrs->isCellNameFieldReading())
6646         {
6647           namesCells=DataArrayAsciiChar::New();
6648           namesCells->alloc(nbOfElt+1,MED_SNAME_SIZE);//not a bug to avoid the memory corruption due to last \0 at the end
6649           MEDFILESAFECALLERRD0(MEDmeshEntityNameRd,(fid,mName.c_str(),dt,it,MED_CELL,geoTypeReq,namesCells->getPointer()));
6650           namesCells->reAlloc(nbOfElt);//not a bug to avoid the memory corruption due to last \0 at the end
6651         }
6652     }
6653 }
6654
6655 void MEDFileStructuredMesh::loadStrMeshFromFile(MEDFileStrMeshL2 *strm, med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
6656 {
6657   setName(strm->getName());
6658   setDescription(strm->getDescription());
6659   setUnivName(strm->getUnivName());
6660   setIteration(strm->getIteration());
6661   setOrder(strm->getOrder());
6662   setTimeValue(strm->getTime());
6663   setTimeUnit(strm->getTimeUnit());
6664   MEDFileMeshL2::ReadFamiliesAndGrps(fid,mName,_families,_groups,mrs);
6665   med_bool chgt=MED_FALSE,trsf=MED_FALSE;
6666   mcIdType nbOfElt(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,MED_FAMILY_NUMBER,MED_NODAL,&chgt,&trsf));
6667   if(nbOfElt>0)
6668     {
6669       if(!mrs || mrs->isNodeFamilyFieldReading())
6670         {
6671           mcIdType nbNodes(getNumberOfNodes());
6672           if(nbOfElt>nbNodes)
6673             throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::loadStrMeshFromFile : invalid size of family node array regarding number of nodes in this ! File seems to be corrupted !");
6674           MCAuto<DataArrayMedInt> miFamNodes=DataArrayMedInt::New();
6675           miFamNodes->alloc(nbNodes,1);//yes nbNodes and not nbOfElt see next line.
6676           if(nbNodes>nbOfElt)//yes it appends some times... It explains surely the mdump implementation. Bug revealed by PARAVIS EDF #2475 on structured.med file where only 12 first nodes are !=0 so nbOfElt=12 and nbOfNodes=378...
6677             miFamNodes->fillWithZero();
6678           MEDFILESAFECALLERRD0(MEDmeshEntityFamilyNumberRd,(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,miFamNodes->getPointer()));
6679           _fam_nodes = FromMedIntArray<mcIdType>( miFamNodes );
6680         }
6681     }
6682   nbOfElt=MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,MED_NUMBER,MED_NODAL,&chgt,&trsf);
6683   if(nbOfElt>0)
6684     {
6685       if(!mrs || mrs->isNodeNumFieldReading())
6686         {
6687           MCAuto<DataArrayMedInt> miNumNodes=DataArrayMedInt::New();
6688           miNumNodes->alloc(nbOfElt,1);
6689           MEDFILESAFECALLERRD0(MEDmeshEntityNumberRd,(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,miNumNodes->getPointer()));
6690           _num_nodes = FromMedIntArray<mcIdType>( miNumNodes );
6691         }
6692     }
6693   nbOfElt=MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,MED_NAME,MED_NODAL,&chgt,&trsf);
6694   if(nbOfElt>0)
6695     {
6696       if(!mrs || mrs->isNodeNameFieldReading())
6697         {
6698           _names_nodes=DataArrayAsciiChar::New();
6699           _names_nodes->alloc(nbOfElt+1,MED_SNAME_SIZE);//not a bug to avoid the memory corruption due to last \0 at the end
6700           MEDFILESAFECALLERRD0(MEDmeshEntityNameRd,(fid,mName.c_str(),dt,it,MED_NODE,MED_NONE,_names_nodes->getPointer()));
6701           _names_nodes->reAlloc(nbOfElt);//not a bug to avoid the memory corruption due to last \0 at the end
6702         }
6703     }
6704   int meshDim(getStructuredMesh()->getMeshDimension());
6705   LoadStrMeshDAFromFile(fid,meshDim,dt,it,mName,mrs,_fam_cells,_num_cells,_names_cells);
6706   if(meshDim>=1)
6707     LoadStrMeshDAFromFile(fid,meshDim-1,dt,it,mName,mrs,_fam_faces,_num_faces,_names_faces);
6708 }
6709
6710 void MEDFileStructuredMesh::writeStructuredLL(med_idt fid, const std::string& maa) const
6711 {
6712   int meshDim(getStructuredMesh()->getMeshDimension());
6713   med_geometry_type geoTypeReq(GetGeoTypeFromMeshDim(meshDim)),geoTypeReq2(GetGeoTypeFromMeshDim(meshDim-1));
6714   //
6715   if((const DataArrayIdType *)_fam_cells)
6716     MEDFILESAFECALLERWR0(MEDmeshEntityFamilyNumberWr,(fid,maa.c_str(),_iteration,_order,MED_CELL,geoTypeReq,ToMedInt(_fam_cells->getNumberOfTuples()),ToMedIntArray(_fam_cells)->getConstPointer()));
6717   if((const DataArrayIdType *)_fam_faces)
6718     MEDFILESAFECALLERWR0(MEDmeshEntityFamilyNumberWr,(fid,maa.c_str(),_iteration,_order,MED_CELL,geoTypeReq2,ToMedInt(_fam_faces->getNumberOfTuples()),ToMedIntArray(_fam_faces)->getConstPointer()));
6719   if((const DataArrayIdType *)_fam_nodes)
6720     MEDFILESAFECALLERWR0(MEDmeshEntityFamilyNumberWr,(fid,maa.c_str(),_iteration,_order,MED_NODE,MED_NONE,ToMedInt(_fam_nodes->getNumberOfTuples()),ToMedIntArray(_fam_nodes)->getConstPointer()));
6721   if((const DataArrayIdType *)_num_cells)
6722     MEDFILESAFECALLERWR0(MEDmeshEntityNumberWr,(fid,maa.c_str(),_iteration,_order,MED_CELL,geoTypeReq,ToMedInt(_num_cells->getNumberOfTuples()),ToMedIntArray(_num_cells)->getConstPointer()));
6723   if((const DataArrayIdType *)_num_faces)
6724     MEDFILESAFECALLERWR0(MEDmeshEntityNumberWr,(fid,maa.c_str(),_iteration,_order,MED_CELL,geoTypeReq2,ToMedInt(_num_faces->getNumberOfTuples()),ToMedIntArray(_num_faces)->getConstPointer()));
6725   if((const DataArrayIdType *)_num_nodes)
6726     MEDFILESAFECALLERWR0(MEDmeshEntityNumberWr,(fid,maa.c_str(),_iteration,_order,MED_NODE,MED_NONE,ToMedInt(_num_nodes->getNumberOfTuples()),ToMedIntArray(_num_nodes)->getConstPointer()));
6727   if((const DataArrayAsciiChar *)_names_cells)
6728     {
6729       if(_names_cells->getNumberOfComponents()!=MED_SNAME_SIZE)
6730         {
6731           std::ostringstream oss; oss << "MEDFileStructuredMesh::writeStructuredLL : expected a name field on cells with number of components set to " << MED_SNAME_SIZE;
6732           oss << " ! The array has " << _names_cells->getNumberOfComponents() << " components !";
6733           throw INTERP_KERNEL::Exception(oss.str().c_str());
6734         }
6735       MEDFILESAFECALLERWR0(MEDmeshEntityNameWr,(fid,maa.c_str(),_iteration,_order,MED_CELL,geoTypeReq,ToMedInt(_names_cells->getNumberOfTuples()),_names_cells->getConstPointer()));
6736     }
6737   if((const DataArrayAsciiChar *)_names_faces)
6738     {
6739       if(_names_faces->getNumberOfComponents()!=MED_SNAME_SIZE)
6740         {
6741           std::ostringstream oss; oss << "MEDFileStructuredMesh::writeStructuredLL : expected a name field on faces with number of components set to " << MED_SNAME_SIZE;
6742           oss << " ! The array has " << _names_faces->getNumberOfComponents() << " components !";
6743           throw INTERP_KERNEL::Exception(oss.str().c_str());
6744         }
6745       MEDFILESAFECALLERWR0(MEDmeshEntityNameWr,(fid,maa.c_str(),_iteration,_order,MED_CELL,geoTypeReq2,ToMedInt(_names_faces->getNumberOfTuples()),_names_faces->getConstPointer()));
6746     }
6747   if((const DataArrayAsciiChar *)_names_nodes)
6748     {
6749       if(_names_nodes->getNumberOfComponents()!=MED_SNAME_SIZE)
6750         {
6751           std::ostringstream oss; oss << "MEDFileStructuredMesh::writeStructuredLL : expected a name field on nodes with number of components set to " << MED_SNAME_SIZE;
6752           oss << " ! The array has " << _names_cells->getNumberOfComponents() << " components !";
6753           throw INTERP_KERNEL::Exception(oss.str().c_str());
6754         }
6755       MEDFILESAFECALLERWR0(MEDmeshEntityNameWr,(fid,maa.c_str(),_iteration,_order,MED_NODE,MED_NONE,ToMedInt(_names_nodes->getNumberOfTuples()),_names_nodes->getConstPointer()));
6756     }
6757   //
6758   MEDFileUMeshL2::WriteFamiliesAndGrps(fid,maa.c_str(),_families,_groups,_too_long_str);
6759 }
6760
6761 /*!
6762  * Returns an empty instance of MEDFileCMesh.
6763  *  \return MEDFileCMesh * - a new instance of MEDFileCMesh. The caller is to delete this
6764  *          mesh using decrRef() as it is no more needed. 
6765  */
6766 MEDFileCMesh *MEDFileCMesh::New()
6767 {
6768   return new MEDFileCMesh;
6769 }
6770
6771 /*!
6772  * Returns a new MEDFileCMesh holding the mesh data that has been read from a given MED
6773  * file. The first mesh in the file is loaded.
6774  *  \param [in] fileName - the name of MED file to read.
6775  *  \return MEDFileCMesh * - a new instance of MEDFileCMesh. The caller is to delete this
6776  *          mesh using decrRef() as it is no more needed. 
6777  *  \throw If the file is not readable.
6778  *  \throw If there is no meshes in the file.
6779  *  \throw If the mesh in the file is not a Cartesian one.
6780  */
6781 MEDFileCMesh *MEDFileCMesh::New(const std::string& fileName, MEDFileMeshReadSelector *mrs)
6782 {
6783   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
6784   return New(fid,mrs);
6785 }
6786
6787 MEDFileCMesh *MEDFileCMesh::New(med_idt fid, MEDFileMeshReadSelector *mrs)
6788 {
6789   return NewForTheFirstMeshInFile<MEDFileCMesh>(fid,mrs);
6790 }
6791
6792 /*!
6793  * Returns a new MEDFileCMesh holding the mesh data that has been read from a given MED
6794  * file. The mesh to load is specified by its name and numbers of a time step and an
6795  * iteration.
6796  *  \param [in] fileName - the name of MED file to read.
6797  *  \param [in] mName - the name of the mesh to read.
6798  *  \param [in] dt - the number of a time step.
6799  *  \param [in] it - the number of an iteration.
6800  *  \return MEDFileCMesh * - a new instance of MEDFileCMesh. The caller is to delete this
6801  *          mesh using decrRef() as it is no more needed. 
6802  *  \throw If the file is not readable.
6803  *  \throw If there is no mesh with given attributes in the file.
6804  *  \throw If the mesh in the file is not a Cartesian one.
6805  */
6806 MEDFileCMesh *MEDFileCMesh::New(const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
6807 {
6808   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
6809   return New(fid,mName,dt,it,mrs);
6810 }
6811
6812 MEDFileCMesh *MEDFileCMesh::New(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
6813 {
6814   return new MEDFileCMesh(fid,mName,dt,it,mrs);
6815 }
6816
6817 std::size_t MEDFileCMesh::getHeapMemorySizeWithoutChildren() const
6818 {
6819   return MEDFileStructuredMesh::getHeapMemorySizeWithoutChildren();
6820 }
6821
6822 std::vector<const BigMemoryObject *> MEDFileCMesh::getDirectChildrenWithNull() const
6823 {
6824   std::vector<const BigMemoryObject *> ret(MEDFileStructuredMesh::getDirectChildrenWithNull());
6825   ret.push_back((const MEDCouplingCMesh *)_cmesh);
6826   return ret;
6827 }
6828
6829 /*!
6830  * Returns the dimension on cells in \a this mesh.
6831  *  \return int - the mesh dimension.
6832  *  \throw If there are no cells in this mesh.
6833  */
6834 int MEDFileCMesh::getMeshDimension() const
6835 {
6836   if(!((const MEDCouplingCMesh*)_cmesh))
6837     throw INTERP_KERNEL::Exception("MEDFileCMesh::getMeshDimension : unable to get meshdimension because no mesh set !");
6838   return _cmesh->getMeshDimension();
6839 }
6840
6841 /*!
6842  * Returns the dimension on nodes in \a this mesh.
6843  *  \return int - the space dimension.
6844  *  \throw If there are no cells in this mesh.
6845  */
6846 int MEDFileCMesh::getSpaceDimension() const
6847 {
6848   if(!((const MEDCouplingCMesh*)_cmesh))
6849     throw INTERP_KERNEL::Exception("MEDFileCMesh::getSpaceDimension : unable to get spacedimension because no mesh set !");
6850   return _cmesh->getSpaceDimension();
6851 }
6852
6853 /*!
6854  * Returns a string describing \a this mesh.
6855  *  \return std::string - the mesh information string.
6856  */
6857 std::string MEDFileCMesh::simpleRepr() const
6858 {
6859   return MEDFileStructuredMesh::simpleRepr();
6860 }
6861
6862 /*!
6863  * Returns a full textual description of \a this mesh.
6864  *  \return std::string - the string holding the mesh description.
6865  */
6866 std::string MEDFileCMesh::advancedRepr() const
6867 {
6868   return simpleRepr();
6869 }
6870
6871 MEDFileCMesh *MEDFileCMesh::shallowCpy() const
6872 {
6873   MCAuto<MEDFileCMesh> ret(new MEDFileCMesh(*this));
6874   return ret.retn();
6875 }
6876
6877 MEDFileMesh *MEDFileCMesh::createNewEmpty() const
6878 {
6879   return new MEDFileCMesh;
6880 }
6881
6882 MEDFileCMesh *MEDFileCMesh::deepCopy() const
6883 {
6884   MCAuto<MEDFileCMesh> ret(new MEDFileCMesh(*this));
6885   ret->deepCpyEquivalences(*this);
6886   if((const MEDCouplingCMesh*)_cmesh)
6887     ret->_cmesh=static_cast<MEDCouplingCMesh*>(_cmesh->deepCopy());
6888   ret->deepCpyAttributes();
6889   return ret.retn();
6890 }
6891
6892 /*!
6893  * Checks if \a this and another mesh are equal.
6894  *  \param [in] other - the mesh to compare with.
6895  *  \param [in] eps - a precision used to compare real values.
6896  *  \param [in,out] what - the string returning description of unequal data.
6897  *  \return bool - \c true if the meshes are equal, \c false, else.
6898  */
6899 bool MEDFileCMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const
6900 {
6901   if(!MEDFileStructuredMesh::isEqual(other,eps,what))
6902     return false;
6903   const MEDFileCMesh *otherC=dynamic_cast<const MEDFileCMesh *>(other);
6904   if(!otherC)
6905     {
6906       what="Mesh types differ ! This is cartesian and other is NOT !";
6907       return false;
6908     }
6909   clearNonDiscrAttributes();
6910   otherC->clearNonDiscrAttributes();
6911   const MEDCouplingCMesh *coo1=_cmesh;
6912   const MEDCouplingCMesh *coo2=otherC->_cmesh;
6913   if((coo1==0 && coo2!=0) || (coo1!=0 && coo2==0))
6914     {
6915       what="Mismatch of cartesian meshes ! One is defined and not other !";
6916       return false;
6917     }
6918   if(coo1)
6919     {
6920       bool ret=coo1->isEqual(coo2,eps);
6921       if(!ret)
6922         {
6923           what="cartesian meshes differ !";
6924           return false;
6925         }
6926     }
6927   return true;
6928 }
6929
6930 /*!
6931  * Clears redundant attributes of incorporated data arrays.
6932  */
6933 void MEDFileCMesh::clearNonDiscrAttributes() const
6934 {
6935   MEDFileStructuredMesh::clearNonDiscrAttributes();
6936   MEDFileUMeshSplitL1::ClearNonDiscrAttributes(_cmesh);//to it is not a bug umeshsplit have already the method implemented
6937 }
6938
6939 MEDFileCMesh::MEDFileCMesh()
6940 {
6941 }
6942
6943 MEDFileCMesh::MEDFileCMesh(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
6944 try
6945 {
6946     loadLLWithAdditionalItems(fid,mName,dt,it,mrs);
6947 }
6948 catch(INTERP_KERNEL::Exception& e)
6949 {
6950     throw e;
6951 }
6952
6953 void MEDFileCMesh::loadLL(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
6954 {
6955   MEDCoupling::MEDCouplingMeshType meshType;
6956   int dummy0,dummy1;
6957   std::string dtunit;
6958   MEDCoupling::MEDCouplingAxisType axType;
6959   INTERP_KERNEL::AutoCppPtr<MeshOrStructMeshCls> mid(MEDFileMeshL2::GetMeshIdFromName(fid,mName,meshType,axType,dummy0,dummy1,dtunit));
6960   if(meshType!=CARTESIAN)
6961     {
6962       std::ostringstream oss; oss << "Trying to load as cartesian an existing mesh with name '" << mName << "' that is NOT cartesian !";
6963       throw INTERP_KERNEL::Exception(oss.str().c_str());
6964     }
6965   MEDFileCMeshL2 loaderl2;
6966   loaderl2.loadAll(fid,mid,mName,dt,it);
6967   setAxisType(axType);
6968   MEDCouplingCMesh *mesh=loaderl2.getMesh();
6969   mesh->incrRef();
6970   _cmesh=mesh;
6971   loadStrMeshFromFile(&loaderl2,fid,mName,dt,it,mrs);
6972 }
6973
6974 /*!
6975  * Returns a const pointer to MEDCouplingCMesh held by \a this mesh.
6976  *  \return const MEDCouplingCMesh * - a pointer to the held MEDCouplingCMesh.
6977  */
6978 const MEDCouplingCMesh *MEDFileCMesh::getMesh() const
6979 {
6980   synchronizeTinyInfoOnLeaves();
6981   return _cmesh;
6982 }
6983
6984 const MEDCouplingStructuredMesh *MEDFileCMesh::getStructuredMesh() const
6985 {
6986   synchronizeTinyInfoOnLeaves();
6987   return _cmesh;
6988 }
6989
6990 /*!
6991  * Sets the MEDCouplingCMesh holding the data of \a this mesh.
6992  *  \param [in] m - the new MEDCouplingCMesh to refer to.
6993  *  \throw If the name or the description of \a this mesh and \a m are not empty and are
6994  *         different. 
6995  */
6996 void MEDFileCMesh::setMesh(MEDCouplingCMesh *m)
6997 {
6998   dealWithTinyInfo(m);
6999   if(m)
7000     m->incrRef();
7001   _cmesh=m;
7002 }
7003
7004 MEDFileMesh *MEDFileCMesh::cartesianize() const
7005 {
7006   if(getAxisType()==AX_CART)
7007     {
7008       incrRef();
7009       return const_cast<MEDFileCMesh *>(this);
7010     }
7011   else
7012     {
7013       const MEDCouplingCMesh *cmesh(getMesh());
7014       if(!cmesh)
7015         throw INTERP_KERNEL::Exception("MEDFileCMesh::cartesianize : impossible to turn into cartesian because the mesh is null !");
7016       MCAuto<MEDCouplingCurveLinearMesh> clmesh(cmesh->buildCurveLinear());
7017       MCAuto<DataArrayDouble> coords(clmesh->getCoords()->cartesianize(getAxisType()));
7018       clmesh->setCoords(coords);
7019       MCAuto<MEDFileCurveLinearMesh> ret(MEDFileCurveLinearMesh::New());
7020       ret->MEDFileStructuredMesh::operator=(*this);
7021       ret->setMesh(clmesh);
7022       ret->setAxisType(AX_CART);
7023       return ret.retn();
7024     }
7025 }
7026
7027 void MEDFileCMesh::writeMeshLL(med_idt fid) const
7028 {
7029   INTERP_KERNEL::AutoPtr<char> maa=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE);
7030   INTERP_KERNEL::AutoPtr<char> desc=MEDLoaderBase::buildEmptyString(MED_COMMENT_SIZE);
7031   INTERP_KERNEL::AutoPtr<char> dtunit=MEDLoaderBase::buildEmptyString(MED_LNAME_SIZE);
7032   MEDLoaderBase::safeStrCpy(_name.c_str(),MED_NAME_SIZE,maa,_too_long_str);
7033   MEDLoaderBase::safeStrCpy(_desc_name.c_str(),MED_COMMENT_SIZE,desc,_too_long_str);
7034   MEDLoaderBase::safeStrCpy(_dt_unit.c_str(),MED_LNAME_SIZE,dtunit,_too_long_str);
7035   int spaceDim(_cmesh->getSpaceDimension());
7036   INTERP_KERNEL::AutoPtr<char> comp=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
7037   INTERP_KERNEL::AutoPtr<char> unit=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
7038   for(int i=0;i<spaceDim;i++)
7039     {
7040       std::string info(_cmesh->getCoordsAt(i)->getInfoOnComponent(0));
7041       std::string c,u;
7042       MEDLoaderBase::splitIntoNameAndUnit(info,c,u);
7043       MEDLoaderBase::safeStrCpy2(c.c_str(),MED_SNAME_SIZE-1,comp+i*MED_SNAME_SIZE,_too_long_str);//MED_TAILLE_PNOM-1 to avoid to write '\0' on next compo
7044       MEDLoaderBase::safeStrCpy2(u.c_str(),MED_SNAME_SIZE-1,unit+i*MED_SNAME_SIZE,_too_long_str);//MED_TAILLE_PNOM-1 to avoid to write '\0' on next compo
7045     }
7046   MEDFILESAFECALLERWR0(MEDmeshCr,(fid,maa,spaceDim,spaceDim,MED_STRUCTURED_MESH,desc,dtunit,MED_SORT_DTIT,MEDFileMeshL2::TraduceAxisTypeRev(getAxisType()),comp,unit));
7047   if(_univ_wr_status)
7048     MEDFILESAFECALLERWR0(MEDmeshUniversalNameWr,(fid,maa));
7049   MEDFILESAFECALLERWR0(MEDmeshGridTypeWr,(fid,maa,MEDFileMeshL2::TraduceAxisTypeRevStruct(getAxisType())));
7050   for(int i=0;i<spaceDim;i++)
7051     {
7052       const DataArrayDouble *da=_cmesh->getCoordsAt(i);
7053       MEDFILESAFECALLERWR0(MEDmeshGridIndexCoordinateWr,(fid,maa,_iteration,_order,_time,i+1,ToMedInt(da->getNumberOfTuples()),da->getConstPointer()));
7054     }
7055   //
7056   std::string meshName(MEDLoaderBase::buildStringFromFortran(maa,MED_NAME_SIZE));
7057   MEDFileStructuredMesh::writeStructuredLL(fid,meshName);
7058 }
7059
7060 void MEDFileCMesh::synchronizeTinyInfoOnLeaves() const
7061 {
7062   const MEDCouplingCMesh *cmesh=_cmesh;
7063   if(!cmesh)
7064     return;
7065   (const_cast<MEDCouplingCMesh *>(cmesh))->setName(_name);
7066   (const_cast<MEDCouplingCMesh *>(cmesh))->setDescription(_desc_name);
7067   (const_cast<MEDCouplingCMesh *>(cmesh))->setTime(_time,_iteration,_order);
7068   (const_cast<MEDCouplingCMesh *>(cmesh))->setTimeUnit(_dt_unit);
7069 }
7070
7071 MEDFileCurveLinearMesh *MEDFileCurveLinearMesh::New()
7072 {
7073   return new MEDFileCurveLinearMesh;
7074 }
7075
7076 MEDFileCurveLinearMesh *MEDFileCurveLinearMesh::New(med_idt fid, MEDFileMeshReadSelector *mrs)
7077 {
7078   return NewForTheFirstMeshInFile<MEDFileCurveLinearMesh>(fid,mrs);
7079 }
7080
7081 MEDFileCurveLinearMesh *MEDFileCurveLinearMesh::New(const std::string& fileName, MEDFileMeshReadSelector *mrs)
7082 {
7083   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
7084   return New(fid,mrs);
7085 }
7086
7087 MEDFileCurveLinearMesh *MEDFileCurveLinearMesh::New(const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
7088 {
7089   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
7090   return New(fid,mName,dt,it,mrs);
7091 }
7092
7093 MEDFileCurveLinearMesh *MEDFileCurveLinearMesh::New(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
7094 {
7095   return new MEDFileCurveLinearMesh(fid,mName,dt,it,mrs);
7096 }
7097
7098 std::size_t MEDFileCurveLinearMesh::getHeapMemorySizeWithoutChildren() const
7099 {
7100   return MEDFileStructuredMesh::getHeapMemorySizeWithoutChildren();
7101 }
7102
7103 std::vector<const BigMemoryObject *> MEDFileCurveLinearMesh::getDirectChildrenWithNull() const
7104 {
7105   std::vector<const BigMemoryObject *> ret(MEDFileStructuredMesh::getDirectChildrenWithNull());
7106   ret.push_back((const MEDCouplingCurveLinearMesh *)_clmesh);
7107   return ret;
7108 }
7109
7110 MEDFileCurveLinearMesh *MEDFileCurveLinearMesh::shallowCpy() const
7111 {
7112   MCAuto<MEDFileCurveLinearMesh> ret(new MEDFileCurveLinearMesh(*this));
7113   return ret.retn();
7114 }
7115
7116 MEDFileMesh *MEDFileCurveLinearMesh::createNewEmpty() const
7117 {
7118   return new MEDFileCurveLinearMesh;
7119 }
7120
7121 MEDFileCurveLinearMesh *MEDFileCurveLinearMesh::deepCopy() const
7122 {
7123   MCAuto<MEDFileCurveLinearMesh> ret(new MEDFileCurveLinearMesh(*this));
7124   ret->deepCpyEquivalences(*this);
7125   if((const MEDCouplingCurveLinearMesh*)_clmesh)
7126     ret->_clmesh=static_cast<MEDCouplingCurveLinearMesh*>(_clmesh->deepCopy());
7127   ret->deepCpyAttributes();
7128   return ret.retn();
7129 }
7130
7131 int MEDFileCurveLinearMesh::getMeshDimension() const
7132 {
7133   if(!((const MEDCouplingCurveLinearMesh*)_clmesh))
7134     throw INTERP_KERNEL::Exception("MEDFileCurveLinearMesh::getMeshDimension : unable to get meshdimension because no mesh set !");
7135   return _clmesh->getMeshDimension();
7136 }
7137
7138 std::string MEDFileCurveLinearMesh::simpleRepr() const
7139 {
7140   return MEDFileStructuredMesh::simpleRepr();
7141 }
7142
7143 std::string MEDFileCurveLinearMesh::advancedRepr() const
7144 {
7145   return simpleRepr();
7146 }
7147
7148 bool MEDFileCurveLinearMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const
7149 {
7150   if(!MEDFileStructuredMesh::isEqual(other,eps,what))
7151     return false;
7152   const MEDFileCurveLinearMesh *otherC=dynamic_cast<const MEDFileCurveLinearMesh *>(other);
7153   if(!otherC)
7154     {
7155       what="Mesh types differ ! This is curve linear and other is NOT !";
7156       return false;
7157     }
7158   clearNonDiscrAttributes();
7159   otherC->clearNonDiscrAttributes();
7160   const MEDCouplingCurveLinearMesh *coo1=_clmesh;
7161   const MEDCouplingCurveLinearMesh *coo2=otherC->_clmesh;
7162   if((coo1==0 && coo2!=0) || (coo1!=0 && coo2==0))
7163     {
7164       what="Mismatch of curve linear meshes ! One is defined and not other !";
7165       return false;
7166     }
7167   if(coo1)
7168     {
7169       bool ret=coo1->isEqual(coo2,eps);
7170       if(!ret)
7171         {
7172           what="curve linear meshes differ !";
7173           return false;
7174         }
7175     }
7176   return true;
7177 }
7178
7179 void MEDFileCurveLinearMesh::clearNonDiscrAttributes() const
7180 {
7181   MEDFileStructuredMesh::clearNonDiscrAttributes();
7182   MEDFileUMeshSplitL1::ClearNonDiscrAttributes(_clmesh);//to it is not a bug umeshsplit have already the method implemented
7183 }
7184
7185 void MEDFileCurveLinearMesh::synchronizeTinyInfoOnLeaves() const
7186 {
7187   const MEDCouplingCurveLinearMesh *clmesh=_clmesh;
7188   if(!clmesh)
7189     return;
7190   (const_cast<MEDCouplingCurveLinearMesh *>(clmesh))->setName(_name);
7191   (const_cast<MEDCouplingCurveLinearMesh *>(clmesh))->setDescription(_desc_name);
7192   (const_cast<MEDCouplingCurveLinearMesh *>(clmesh))->setTime(_time,_iteration,_order);
7193   (const_cast<MEDCouplingCurveLinearMesh *>(clmesh))->setTimeUnit(_dt_unit);
7194 }
7195
7196 const MEDCouplingCurveLinearMesh *MEDFileCurveLinearMesh::getMesh() const
7197 {
7198   synchronizeTinyInfoOnLeaves();
7199   return _clmesh;
7200 }
7201
7202 void MEDFileCurveLinearMesh::setMesh(MEDCouplingCurveLinearMesh *m)
7203 {
7204   dealWithTinyInfo(m);
7205   if(m)
7206     m->incrRef();
7207   _clmesh=m;
7208 }
7209
7210 MEDFileMesh *MEDFileCurveLinearMesh::cartesianize() const
7211 {
7212   if(getAxisType()==AX_CART)
7213     {
7214       incrRef();
7215       return const_cast<MEDFileCurveLinearMesh *>(this);
7216     }
7217   else
7218     {
7219       const MEDCouplingCurveLinearMesh *mesh(getMesh());
7220       if(!mesh)
7221         throw INTERP_KERNEL::Exception("MEDFileCurveLinearMesh::cartesianize : impossible to turn into cartesian because the mesh is null !");
7222       const DataArrayDouble *coords(mesh->getCoords());
7223       if(!coords)
7224         throw INTERP_KERNEL::Exception("MEDFileCurveLinearMesh::cartesianize : coordinate pointer in mesh is null !");
7225       MCAuto<MEDFileCurveLinearMesh> ret(new MEDFileCurveLinearMesh(*this));
7226       MCAuto<MEDCouplingCurveLinearMesh> mesh2(mesh->clone(false));
7227       MCAuto<DataArrayDouble> coordsCart(coords->cartesianize(getAxisType()));
7228       mesh2->setCoords(coordsCart);
7229       ret->setMesh(mesh2);
7230       ret->setAxisType(AX_CART);
7231       return ret.retn();
7232     }
7233 }
7234
7235 const MEDCouplingStructuredMesh *MEDFileCurveLinearMesh::getStructuredMesh() const
7236 {
7237   synchronizeTinyInfoOnLeaves();
7238   return _clmesh;
7239 }
7240
7241 MEDFileCurveLinearMesh::MEDFileCurveLinearMesh()
7242 {
7243 }
7244
7245 MEDFileCurveLinearMesh::MEDFileCurveLinearMesh(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
7246 try
7247 {
7248     loadLLWithAdditionalItems(fid,mName,dt,it,mrs);
7249 }
7250 catch(INTERP_KERNEL::Exception& e)
7251 {
7252     throw e;
7253 }
7254
7255 void MEDFileCurveLinearMesh::writeMeshLL(med_idt fid) const
7256 {
7257   INTERP_KERNEL::AutoPtr<char> maa=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE);
7258   INTERP_KERNEL::AutoPtr<char> desc=MEDLoaderBase::buildEmptyString(MED_COMMENT_SIZE);
7259   INTERP_KERNEL::AutoPtr<char> dtunit=MEDLoaderBase::buildEmptyString(MED_LNAME_SIZE);
7260   MEDLoaderBase::safeStrCpy(_name.c_str(),MED_NAME_SIZE,maa,_too_long_str);
7261   MEDLoaderBase::safeStrCpy(_desc_name.c_str(),MED_COMMENT_SIZE,desc,_too_long_str);
7262   MEDLoaderBase::safeStrCpy(_dt_unit.c_str(),MED_LNAME_SIZE,dtunit,_too_long_str);
7263   int spaceDim=_clmesh->getSpaceDimension();
7264   int meshDim=_clmesh->getMeshDimension();
7265   INTERP_KERNEL::AutoPtr<char> comp=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
7266   INTERP_KERNEL::AutoPtr<char> unit=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
7267   const DataArrayDouble *coords=_clmesh->getCoords();
7268   if(!coords)
7269     throw INTERP_KERNEL::Exception("MEDFileCurveLinearMesh::writeMeshLL : no coordinates set !");
7270   for(int i=0;i<spaceDim;i++)
7271     {
7272       std::string info(_clmesh->getCoords()->getInfoOnComponent(i));
7273       std::string c,u;
7274       MEDLoaderBase::splitIntoNameAndUnit(info,c,u);
7275       MEDLoaderBase::safeStrCpy2(c.c_str(),MED_SNAME_SIZE-1,comp+i*MED_SNAME_SIZE,_too_long_str);//MED_TAILLE_PNOM-1 to avoid to write '\0' on next compo
7276       MEDLoaderBase::safeStrCpy2(u.c_str(),MED_SNAME_SIZE-1,unit+i*MED_SNAME_SIZE,_too_long_str);//MED_TAILLE_PNOM-1 to avoid to write '\0' on next compo
7277     }
7278   MEDFILESAFECALLERWR0(MEDmeshCr,(fid,maa,spaceDim,meshDim,MED_STRUCTURED_MESH,desc,dtunit,MED_SORT_DTIT,MEDFileMeshL2::TraduceAxisTypeRev(getAxisType()),comp,unit));
7279   if(_univ_wr_status)
7280     MEDFILESAFECALLERWR0(MEDmeshUniversalNameWr,(fid,maa));
7281   MEDFILESAFECALLERWR0(MEDmeshGridTypeWr,(fid,maa,MED_CURVILINEAR_GRID));
7282   std::vector<mcIdType> nodeGridSt=_clmesh->getNodeGridStructure();
7283   MEDFILESAFECALLERWR0(MEDmeshGridStructWr,(fid,maa,_iteration,_order,_time,ToMedIntArray(nodeGridSt)->getConstPointer()));
7284
7285   MEDFILESAFECALLERWR0(MEDmeshNodeCoordinateWr,(fid,maa,_iteration,_order,_time,MED_FULL_INTERLACE,ToMedInt(coords->getNumberOfTuples()),coords->begin()));
7286   //
7287   std::string meshName(MEDLoaderBase::buildStringFromFortran(maa,MED_NAME_SIZE));
7288   MEDFileStructuredMesh::writeStructuredLL(fid,meshName);
7289 }
7290
7291 void MEDFileCurveLinearMesh::loadLL(med_idt fid, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
7292 {
7293   MEDCoupling::MEDCouplingMeshType meshType;
7294   int dummy0,dummy1;
7295   std::string dtunit;
7296   MEDCoupling::MEDCouplingAxisType axType;
7297   INTERP_KERNEL::AutoCppPtr<MeshOrStructMeshCls> mid(MEDFileMeshL2::GetMeshIdFromName(fid,mName,meshType,axType,dummy0,dummy1,dtunit));
7298   setAxisType(axType);
7299   if(meshType!=CURVE_LINEAR)
7300     {
7301       std::ostringstream oss; oss << "Trying to load as curve linear an existing mesh with name '" << mName << "' that is NOT curve linear !";
7302       throw INTERP_KERNEL::Exception(oss.str().c_str());
7303     }
7304   MEDFileCLMeshL2 loaderl2;
7305   loaderl2.loadAll(fid,mid,mName,dt,it);
7306   MEDCouplingCurveLinearMesh *mesh=loaderl2.getMesh();
7307   mesh->incrRef();
7308   _clmesh=mesh;
7309   loadStrMeshFromFile(&loaderl2,fid,mName,dt,it,mrs);
7310 }
7311
7312 MEDFileMeshMultiTS *MEDFileMeshMultiTS::New()
7313 {
7314   return new MEDFileMeshMultiTS;
7315 }
7316
7317 MEDFileMeshMultiTS *MEDFileMeshMultiTS::New(med_idt fid)
7318 {
7319   return new MEDFileMeshMultiTS(fid);
7320 }
7321
7322 MEDFileMeshMultiTS *MEDFileMeshMultiTS::New(const std::string& fileName)
7323 {
7324   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
7325   return New(fid);
7326 }
7327
7328 MEDFileMeshMultiTS *MEDFileMeshMultiTS::New(med_idt fid, const std::string& mName)
7329 {
7330   return new MEDFileMeshMultiTS(fid,mName);
7331 }
7332
7333 MEDFileMeshMultiTS *MEDFileMeshMultiTS::New(const std::string& fileName, const std::string& mName)
7334 {
7335   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
7336   return New(fid,mName);
7337 }
7338
7339 MEDFileMeshMultiTS *MEDFileMeshMultiTS::deepCopy() const
7340 {
7341   MCAuto<MEDFileMeshMultiTS> ret(MEDFileMeshMultiTS::New());
7342   std::vector< MCAuto<MEDFileMesh> > meshOneTs(_mesh_one_ts.size());
7343   std::size_t i(0);
7344   for(std::vector< MCAuto<MEDFileMesh> >::const_iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++,i++)
7345     if((const MEDFileMesh *)*it)
7346       meshOneTs[i]=(*it)->deepCopy();
7347   ret->_mesh_one_ts=meshOneTs;
7348   return ret.retn();
7349 }
7350
7351 std::size_t MEDFileMeshMultiTS::getHeapMemorySizeWithoutChildren() const
7352 {
7353   return _mesh_one_ts.capacity()*sizeof(MCAuto<MEDFileMesh>);
7354 }
7355
7356 std::vector<const BigMemoryObject *> MEDFileMeshMultiTS::getDirectChildrenWithNull() const
7357 {
7358   std::vector<const BigMemoryObject *> ret;
7359   for(std::vector< MCAuto<MEDFileMesh> >::const_iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++)
7360     ret.push_back((const MEDFileMesh *)*it);
7361   return ret;
7362 }
7363
7364 std::string MEDFileMeshMultiTS::getName() const
7365 {
7366   if(_mesh_one_ts.empty())
7367     throw INTERP_KERNEL::Exception("MEDFileMeshMultiTS::getName : no time steps set !");
7368   return _mesh_one_ts[0]->getName();
7369 }
7370
7371 void MEDFileMeshMultiTS::setName(const std::string& newMeshName)
7372 {
7373   std::string oldName(getName());
7374   std::vector< std::pair<std::string,std::string> > v(1);
7375   v[0].first=oldName; v[0].second=newMeshName;
7376   changeNames(v);
7377 }
7378
7379 bool MEDFileMeshMultiTS::changeNames(const std::vector< std::pair<std::string,std::string> >& modifTab)
7380 {
7381   bool ret=false;
7382   for(std::vector< MCAuto<MEDFileMesh> >::iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++)
7383     {
7384       MEDFileMesh *cur(*it);
7385       if(cur)
7386         ret=cur->changeNames(modifTab) || ret;
7387     }
7388   return ret;
7389 }
7390
7391 void MEDFileMeshMultiTS::cartesianizeMe()
7392 {
7393   for(std::vector< MCAuto<MEDFileMesh> >::iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++)
7394     {
7395       MEDFileMesh *cur(*it);
7396       if(cur)
7397         {
7398           MCAuto<MEDFileMesh> ccur(cur->cartesianize());// Attention ! Do not wrap these two lines because memory leak !
7399           *it=ccur;
7400         }
7401     }
7402 }
7403
7404 MEDFileMesh *MEDFileMeshMultiTS::getOneTimeStep() const
7405 {
7406   if(_mesh_one_ts.empty())
7407     throw INTERP_KERNEL::Exception("MEDFileMeshMultiTS::getOneTimeStep : empty time step set !");
7408   return const_cast<MEDFileMesh *>(static_cast<const MEDFileMesh *>(_mesh_one_ts[0]));
7409 }
7410
7411 void MEDFileMeshMultiTS::setOneTimeStep(MEDFileMesh *mesh1TimeStep)
7412 {
7413   if(!mesh1TimeStep)
7414     throw INTERP_KERNEL::Exception("MEDFileMeshMultiTS::setOneTimeStep : input pointer should be different from 0 !");
7415   _mesh_one_ts.resize(1);
7416   mesh1TimeStep->incrRef();
7417   //MCAuto<MEDFileMesh> toto=mesh1TimeStep;
7418   _mesh_one_ts[0]=mesh1TimeStep;
7419 }
7420
7421 MEDFileJoints * MEDFileMeshMultiTS::getJoints() const
7422 {
7423   if ( MEDFileMesh* m = getOneTimeStep() )
7424     return m->getJoints();
7425   return 0;
7426 }
7427
7428 /*!
7429  * \brief Set Joints that are common to all time-stamps
7430  */
7431 void MEDFileMeshMultiTS::setJoints( MEDFileJoints* joints )
7432 {
7433   for(std::vector< MCAuto<MEDFileMesh> >::iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++)
7434     {
7435       (*it)->setJoints( joints );
7436     }
7437 }
7438
7439 bool MEDFileMeshMultiTS::presenceOfStructureElements() const
7440 {
7441   for(std::vector< MCAuto<MEDFileMesh> >::const_iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++)
7442     if((*it).isNotNull())
7443       if((*it)->presenceOfStructureElements())
7444         return true;
7445   return false;
7446 }
7447
7448 void MEDFileMeshMultiTS::killStructureElements()
7449 {
7450   for(std::vector< MCAuto<MEDFileMesh> >::iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++)
7451     if((*it).isNotNull())
7452       (*it)->killStructureElements();
7453 }
7454
7455 void MEDFileMeshMultiTS::writeLL(med_idt fid) const
7456 {
7457   MEDFileJoints *joints(getJoints());
7458   bool jointsWritten(false);
7459
7460   for(std::vector< MCAuto<MEDFileMesh> >::const_iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++)
7461     {
7462       if ( jointsWritten )
7463         const_cast<MEDFileMesh&>(**it).setJoints( 0 );
7464       else
7465         jointsWritten = true;
7466
7467       (*it)->copyOptionsFrom(*this);
7468       (*it)->writeLL(fid);
7469     }
7470
7471   (const_cast<MEDFileMeshMultiTS*>(this))->setJoints( joints ); // restore joints
7472 }
7473
7474 void MEDFileMeshMultiTS::loadFromFile(med_idt fid, const std::string& mName)
7475 {
7476   MEDFileJoints *joints(0);
7477   if ( !_mesh_one_ts.empty() && getOneTimeStep() )
7478     {
7479       // joints of mName already read, pass them to MEDFileMesh::New() to prevent repeated reading
7480       joints = getOneTimeStep()->getJoints();
7481     }
7482   _mesh_one_ts.clear();  //for the moment to be improved
7483   _mesh_one_ts.push_back( MEDFileMesh::New(fid,mName,-1,-1,0, joints ));
7484 }
7485
7486 MEDFileMeshMultiTS::MEDFileMeshMultiTS()
7487 {
7488 }
7489
7490 MEDFileMeshMultiTS::MEDFileMeshMultiTS(med_idt fid)
7491 try
7492 {
7493   std::vector<std::string> ms(MEDLoaderNS::getMeshNamesFid(fid));
7494     if(ms.empty())
7495       {
7496         std::ostringstream oss; oss << "MEDFileMeshMultiTS : no meshes in file \"" << FileNameFromFID(fid) << "\" !";
7497         throw INTERP_KERNEL::Exception(oss.str().c_str());
7498       }
7499     int dt,it;
7500     MEDCoupling::MEDCouplingMeshType meshType;
7501     std::string dummy2;
7502     MEDCoupling::MEDCouplingAxisType dummy3;
7503     MEDFileMeshL2::GetMeshIdFromName(fid,ms.front(),meshType,dummy3,dt,it,dummy2);
7504     loadFromFile(fid,ms.front());
7505 }
7506 catch(INTERP_KERNEL::Exception& e)
7507 {
7508     throw e;
7509 }
7510
7511 MEDFileMeshMultiTS::MEDFileMeshMultiTS(med_idt fid, const std::string& mName)
7512 try
7513 {
7514     loadFromFile(fid,mName);
7515 }
7516 catch(INTERP_KERNEL::Exception& e)
7517 {
7518     throw e;
7519 }
7520
7521 MEDFileMeshes *MEDFileMeshes::New()
7522 {
7523   return new MEDFileMeshes;
7524 }
7525
7526 MEDFileMeshes *MEDFileMeshes::New(med_idt fid)
7527 {
7528   return new MEDFileMeshes(fid);
7529 }
7530
7531 MEDFileMeshes *MEDFileMeshes::New(const std::string& fileName)
7532 {
7533   MEDFileUtilities::AutoFid fid(OpenMEDFileForRead(fileName));
7534   return New(fid);
7535 }
7536
7537 void MEDFileMeshes::writeLL(med_idt fid) const
7538 {
7539   checkConsistencyLight();
7540   for(std::vector< MCAuto<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++)
7541     {
7542       (*it)->copyOptionsFrom(*this);
7543       (*it)->writeLL(fid);
7544     }
7545 }
7546
7547 //  MEDFileMeshes::writ checkConsistencyLight();
7548
7549 int MEDFileMeshes::getNumberOfMeshes() const
7550 {
7551   return (int)_meshes.size();
7552 }
7553
7554 MEDFileMeshesIterator *MEDFileMeshes::iterator()
7555 {
7556   return new MEDFileMeshesIterator(this);
7557 }
7558
7559 /** Return a borrowed reference (caller is not responsible) */
7560 MEDFileMesh *MEDFileMeshes::getMeshAtPos(int i) const
7561 {
7562   if(i<0 || i>=(int)_meshes.size())
7563     {
7564       std::ostringstream oss; oss << "MEDFileMeshes::getMeshAtPos : invalid mesh id given in parameter ! Should be in [0;" << _meshes.size() << ") !";
7565       throw INTERP_KERNEL::Exception(oss.str().c_str());
7566     }
7567   return _meshes[i]->getOneTimeStep();
7568 }
7569
7570 /** Return a borrowed reference (caller is not responsible) */
7571 MEDFileMesh *MEDFileMeshes::getMeshWithName(const std::string& mname) const
7572 {
7573   std::vector<std::string> ms=getMeshesNames();
7574   std::vector<std::string>::iterator it=std::find(ms.begin(),ms.end(),mname);
7575   if(it==ms.end())
7576     {
7577       std::ostringstream oss; oss << "MEDFileMeshes::getMeshWithName : Mesh  \"" << mname << "\" does not exist in this ! Existing are : ";
7578       std::copy(ms.begin(),ms.end(),std::ostream_iterator<std::string>(oss," "));
7579       throw INTERP_KERNEL::Exception(oss.str().c_str());
7580     }
7581   return getMeshAtPos((int)std::distance(ms.begin(),it));
7582 }
7583
7584 std::vector<std::string> MEDFileMeshes::getMeshesNames() const
7585 {
7586   std::vector<std::string> ret(_meshes.size());
7587   int i=0;
7588   for(std::vector< MCAuto<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++,i++)
7589     {
7590       const MEDFileMeshMultiTS *f=(*it);
7591       if(f)
7592         {
7593           ret[i]=f->getName();
7594         }
7595       else
7596         {
7597           std::ostringstream oss; oss << "MEDFileMeshes::getMeshesNames : At rank #" << i << " mesh is not defined !";
7598           throw INTERP_KERNEL::Exception(oss.str().c_str());
7599         }
7600     }
7601   return ret;
7602 }
7603
7604 bool MEDFileMeshes::changeNames(const std::vector< std::pair<std::string,std::string> >& modifTab)
7605 {
7606   bool ret=false;
7607   for(std::vector< MCAuto<MEDFileMeshMultiTS> >::iterator it=_meshes.begin();it!=_meshes.end();it++)
7608     {
7609       MEDFileMeshMultiTS *cur(*it);
7610       if(cur)
7611         ret=cur->changeNames(modifTab) || ret;
7612     }
7613   return ret;
7614 }
7615
7616 void MEDFileMeshes::cartesianizeMe()
7617 {
7618   for(std::vector< MCAuto<MEDFileMeshMultiTS> >::iterator it=_meshes.begin();it!=_meshes.end();it++)
7619     {
7620       MEDFileMeshMultiTS *cur(*it);
7621       if(cur)
7622         cur->cartesianizeMe();
7623     }
7624 }
7625
7626 void MEDFileMeshes::resize(int newSize)
7627 {
7628   _meshes.resize(newSize);
7629 }
7630
7631 void MEDFileMeshes::pushMesh(MEDFileMesh *mesh)
7632 {
7633   if(!mesh)
7634     throw INTERP_KERNEL::Exception("MEDFileMeshes::pushMesh : invalid input pointer ! should be different from 0 !");
7635   MEDFileMeshMultiTS *elt=MEDFileMeshMultiTS::New();
7636   elt->setOneTimeStep(mesh);
7637   _meshes.push_back(elt);
7638 }
7639
7640 void MEDFileMeshes::setMeshAtPos(int i, MEDFileMesh *mesh)
7641 {
7642   if(!mesh)
7643     throw INTERP_KERNEL::Exception("MEDFileMeshes::setMeshAtPos : invalid input pointer ! should be different from 0 !");
7644   if(i>=(int)_meshes.size())
7645     _meshes.resize(i+1);
7646   MEDFileMeshMultiTS *elt=MEDFileMeshMultiTS::New();
7647   elt->setOneTimeStep(mesh);
7648   _meshes[i]=elt;
7649 }
7650
7651 void MEDFileMeshes::destroyMeshAtPos(int i)
7652 {
7653   if(i<0 || i>=(int)_meshes.size())
7654     {
7655       std::ostringstream oss; oss << "MEDFileMeshes::destroyMeshAtPos : Invalid given id in input (" << i << ") should be in [0," << _meshes.size() << ") !";
7656       throw INTERP_KERNEL::Exception(oss.str().c_str());
7657     }
7658   _meshes.erase(_meshes.begin()+i);
7659 }
7660
7661 void MEDFileMeshes::loadFromFile(med_idt fid)
7662 {
7663   std::vector<std::string> ms(MEDLoaderNS::getMeshNamesFid(fid));
7664   int i=0;
7665   _meshes.resize(ms.size());
7666   for(std::vector<std::string>::const_iterator it=ms.begin();it!=ms.end();it++,i++)
7667     _meshes[i]=MEDFileMeshMultiTS::New(fid,(*it));
7668 }
7669
7670 MEDFileMeshes::MEDFileMeshes()
7671 {
7672 }
7673
7674 MEDFileMeshes::MEDFileMeshes(med_idt fid)
7675 try
7676 {
7677     loadFromFile(fid);
7678 }
7679 catch(INTERP_KERNEL::Exception& /*e*/)
7680 {
7681 }
7682
7683 MEDFileMeshes *MEDFileMeshes::deepCopy() const
7684 {
7685   std::vector< MCAuto<MEDFileMeshMultiTS> > meshes(_meshes.size());
7686   std::size_t i=0;
7687   for(std::vector< MCAuto<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++,i++)
7688     if((const MEDFileMeshMultiTS *)*it)
7689       meshes[i]=(*it)->deepCopy();
7690   MCAuto<MEDFileMeshes> ret(MEDFileMeshes::New());
7691   ret->_meshes=meshes;
7692   return ret.retn();
7693 }
7694
7695 std::size_t MEDFileMeshes::getHeapMemorySizeWithoutChildren() const
7696 {
7697   return _meshes.capacity()*(sizeof(MCAuto<MEDFileMeshMultiTS>));
7698 }
7699
7700 std::vector<const BigMemoryObject *> MEDFileMeshes::getDirectChildrenWithNull() const
7701 {
7702   std::vector<const BigMemoryObject *> ret;
7703   for(std::vector< MCAuto<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++)
7704     ret.push_back((const MEDFileMeshMultiTS *)*it);
7705   return ret;
7706 }
7707
7708 std::string MEDFileMeshes::simpleRepr() const
7709 {
7710   std::ostringstream oss;
7711   oss << "(*****************)\n(* MEDFileMeshes *)\n(*****************)\n\n";
7712   simpleReprWithoutHeader(oss);
7713   return oss.str();
7714 }
7715
7716 void MEDFileMeshes::simpleReprWithoutHeader(std::ostream& oss) const
7717 {
7718   int nbOfMeshes=getNumberOfMeshes();
7719   oss << "There are " << nbOfMeshes << " meshes with the following names : \n";
7720   std::vector<std::string> mns=getMeshesNames();
7721   for(int i=0;i<nbOfMeshes;i++)
7722     oss << "  - #" << i << " \"" << mns[i] << "\"\n";
7723 }
7724
7725 void MEDFileMeshes::checkConsistencyLight() const
7726 {
7727   static const char MSG[]="MEDFileMeshes::checkConsistencyLight : mesh at rank ";
7728   int i=0;
7729   std::set<std::string> s;
7730   for(std::vector< MCAuto<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++,i++)
7731     {
7732       const MEDFileMeshMultiTS *elt=(*it);
7733       if(!elt)
7734         {
7735           std::ostringstream oss; oss << MSG << i << "/" << _meshes.size() << " is empty !";
7736           throw INTERP_KERNEL::Exception(oss.str().c_str());
7737         }
7738       std::size_t sz=s.size();
7739       s.insert(std::string((*it)->getName()));
7740       if(s.size()==sz)
7741         {
7742           std::ostringstream oss; oss << MSG << i << " has a name (\"" << (*it)->getName() << "\") already used by an another mesh in list !";
7743           throw INTERP_KERNEL::Exception(oss.str().c_str());
7744         }
7745     }
7746 }
7747
7748 bool MEDFileMeshes::presenceOfStructureElements() const
7749 {
7750   for(std::vector< MCAuto<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++)
7751     if((*it).isNotNull())
7752       if((*it)->presenceOfStructureElements())
7753         return true;
7754   return false;
7755 }
7756
7757 void MEDFileMeshes::killStructureElements()
7758 {
7759   for(std::vector< MCAuto<MEDFileMeshMultiTS> >::iterator it=_meshes.begin();it!=_meshes.end();it++)
7760     if((*it).isNotNull())
7761       (*it)->killStructureElements();
7762 }
7763
7764 MEDFileMeshesIterator::MEDFileMeshesIterator(MEDFileMeshes *ms):_ms(ms),_iter_id(0),_nb_iter(0)
7765 {
7766   if(ms)
7767     {
7768       ms->incrRef();
7769       _nb_iter=ms->getNumberOfMeshes();
7770     }
7771 }
7772
7773 MEDFileMeshesIterator::~MEDFileMeshesIterator()
7774 {
7775 }
7776
7777 MEDFileMesh *MEDFileMeshesIterator::nextt()
7778 {
7779   if(_iter_id<_nb_iter)
7780     {
7781       MEDFileMeshes *ms(_ms);
7782       if(ms)
7783         return ms->getMeshAtPos(_iter_id++);
7784       else
7785         return 0;
7786     }
7787   else
7788     return 0;
7789 }
7790
7791 INTERP_KERNEL::NormalizedCellType MEDFileMesh::ConvertFromMEDFileGeoType(med_geometry_type geoType)
7792 {
7793   med_geometry_type *pos(std::find(typmai,typmai+MED_N_CELL_FIXED_GEO,geoType));
7794   if(pos==typmai+MED_N_CELL_FIXED_GEO)
7795     {
7796       if(geoType==MED_NO_GEOTYPE)
7797         return INTERP_KERNEL::NORM_ERROR;
7798       std::ostringstream oss; oss << "MEDFileMesh::ConvertFromMEDFileGeoType : no entry with " << geoType << " !"; 
7799       throw INTERP_KERNEL::Exception(oss.str());
7800     }
7801   return typmai2[std::distance(typmai,pos)];
7802 }
7803
7804 TypeOfField MEDFileMesh::ConvertFromMEDFileEntity(med_entity_type etype)
7805 {
7806   switch(etype)
7807     {
7808     case MED_NODE:
7809       return ON_NODES;
7810     case MED_CELL:
7811       return ON_CELLS;
7812     case MED_NODE_ELEMENT:
7813       return ON_GAUSS_NE;
7814     default:
7815       {
7816         std::ostringstream oss; oss << "MEDFileMesh::ConvertFromMEDFileEntity : not recognized entity " << etype << " !";
7817         throw INTERP_KERNEL::Exception(oss.str());
7818       }
7819     }
7820 }
7821
7822