Salome HOME
MED file mesh loading on demand.
[modules/med.git] / src / MEDLoader / MEDFileMesh.cxx
1 // Copyright (C) 2007-2013  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.
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 "MEDFileUtilities.hxx"
23 #include "MEDLoader.hxx"
24 #include "MEDLoaderBase.hxx"
25
26 #include "MEDCouplingUMesh.hxx"
27
28 #include "InterpKernelAutoPtr.hxx"
29
30 #include <limits>
31 #include <cmath>
32
33 using namespace ParaMEDMEM;
34
35 const char MEDFileMesh::DFT_FAM_NAME[]="FAMILLE_ZERO";
36
37 MEDFileMesh::MEDFileMesh():_order(-1),_iteration(-1),_time(0.),_univ_wr_status(true)
38 {
39 }
40
41 std::size_t MEDFileMesh::getHeapMemorySize() const
42 {
43   std::size_t ret=_dt_unit.capacity()+_name.capacity()+_univ_name.capacity()+_desc_name.capacity();
44   for(std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.begin();it!=_groups.end();it++)
45     {
46       ret+=(*it).first.capacity()+(*it).second.capacity()*sizeof(std::string);
47       for(std::vector<std::string>::const_iterator it2=(*it).second.begin();it2!=(*it).second.end();it2++)
48         ret+=(*it2).capacity();
49     }
50   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
51     ret+=(*it).first.capacity()+sizeof(int);
52   return ret;
53 }
54
55 /*!
56  * Returns a new MEDFileMesh holding the mesh data that has been read from a given MED
57  * file. The first mesh in the file is loaded.
58  *  \param [in] fileName - the name of MED file to read.
59  *  \return MEDFileMesh * - a new instance of MEDFileMesh. The caller is to delete this
60  *          mesh using decrRef() as it is no more needed. 
61  *  \throw If the file is not readable.
62  *  \throw If there is no meshes in the file.
63  *  \throw If the mesh in the file is of a not supported type.
64  */
65 MEDFileMesh *MEDFileMesh::New(const char *fileName, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
66 {
67   std::vector<std::string> ms=MEDLoader::GetMeshNames(fileName);
68   if(ms.empty())
69     {
70       std::ostringstream oss; oss << "MEDFileMesh::New : no meshes in file \"" << fileName << "\" !";
71       throw INTERP_KERNEL::Exception(oss.str().c_str());
72     }
73   MEDFileUtilities::CheckFileForRead(fileName);
74   ParaMEDMEM::MEDCouplingMeshType meshType;
75   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,MED_ACC_RDONLY);
76   int dt,it;
77   std::string dummy2;
78   MEDFileMeshL2::GetMeshIdFromName(fid,ms.front().c_str(),meshType,dt,it,dummy2);
79   switch(meshType)
80     {
81     case UNSTRUCTURED:
82       {
83         MEDCouplingAutoRefCountObjectPtr<MEDFileUMesh> ret=MEDFileUMesh::New();
84         ret->loadUMeshFromFile(fid,ms.front().c_str(),dt,it,mrs);
85         return (MEDFileUMesh *)ret.retn();
86       }
87     case CARTESIAN:
88       {
89         MEDCouplingAutoRefCountObjectPtr<MEDFileCMesh> ret=MEDFileCMesh::New();
90         ret->loadCMeshFromFile(fid,ms.front().c_str(),dt,it,mrs);
91         return (MEDFileCMesh *)ret.retn();
92       }
93     case CURVE_LINEAR:
94       {
95         MEDCouplingAutoRefCountObjectPtr<MEDFileCurveLinearMesh> ret=MEDFileCurveLinearMesh::New();
96         ret->loadCLMeshFromFile(fid,ms.front().c_str(),dt,it,mrs);
97         return (MEDFileCurveLinearMesh *)ret.retn();
98       }
99     default:
100       {
101         std::ostringstream oss; oss << "MEDFileMesh::New : MED file exists and has mesh '" << ms.front() << "' exists but unsupported type yet !";
102         throw INTERP_KERNEL::Exception(oss.str().c_str());
103       }
104     }
105 }
106
107 /*!
108  * Returns a new MEDFileMesh holding the mesh data that has been read from a given MED
109  * file. The mesh to load is specified by its name and numbers of a time step and an
110  * iteration.
111  *  \param [in] fileName - the name of MED file to read.
112  *  \param [in] mName - the name of the mesh to read.
113  *  \param [in] dt - the number of a time step.
114  *  \param [in] it - the number of an iteration.
115  *  \return MEDFileMesh * - a new instance of MEDFileMesh. The caller is to delete this
116  *          mesh using decrRef() as it is no more needed. 
117  *  \throw If the file is not readable.
118  *  \throw If there is no mesh with given attributes in the file.
119  *  \throw If the mesh in the file is of a not supported type.
120  */
121 MEDFileMesh *MEDFileMesh::New(const char *fileName, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
122 {
123   MEDFileUtilities::CheckFileForRead(fileName);
124   ParaMEDMEM::MEDCouplingMeshType meshType;
125   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,MED_ACC_RDONLY);
126   int dummy0,dummy1;
127   std::string dummy2;
128   MEDFileMeshL2::GetMeshIdFromName(fid,mName,meshType,dummy0,dummy1,dummy2);
129   switch(meshType)
130     {
131     case UNSTRUCTURED:
132       {
133         MEDCouplingAutoRefCountObjectPtr<MEDFileUMesh> ret=MEDFileUMesh::New();
134         ret->loadUMeshFromFile(fid,mName,dt,it,mrs);
135         return (MEDFileUMesh *)ret.retn();
136       }
137     case CARTESIAN:
138       {
139         MEDCouplingAutoRefCountObjectPtr<MEDFileCMesh> ret=MEDFileCMesh::New();
140         ret->loadCMeshFromFile(fid,mName,dt,it,mrs);
141         return (MEDFileCMesh *)ret.retn();
142       }
143     case CURVE_LINEAR:
144       {
145         MEDCouplingAutoRefCountObjectPtr<MEDFileCurveLinearMesh> ret=MEDFileCurveLinearMesh::New();
146         ret->loadCLMeshFromFile(fid,mName,dt,it,mrs);
147         return (MEDFileCurveLinearMesh *)ret.retn();
148       }
149     default:
150       {
151         std::ostringstream oss; oss << "MEDFileMesh::New : MED file exists and has mesh '" << mName << "' exists but unsupported type yet !";
152         throw INTERP_KERNEL::Exception(oss.str().c_str());
153       }
154     }
155 }
156
157 /*!
158  * Writes \a this mesh into an open MED file specified by its descriptor.
159  *  \param [in] fid - the MED file descriptor.
160  *  \throw If the mesh name is not set.
161  *  \throw If the file is open for reading only.
162  *  \throw If the writing mode == 1 and the same data is present in an existing file.
163  */
164 void MEDFileMesh::write(med_idt fid) const throw(INTERP_KERNEL::Exception)
165 {
166   if(!existsFamily(0))
167     const_cast<MEDFileMesh *>(this)->addFamily(DFT_FAM_NAME,0);
168   if(_name.empty())
169     throw INTERP_KERNEL::Exception("MEDFileMesh : name is empty. MED file ask for a NON EMPTY name !");
170   writeLL(fid);
171 }
172
173 /*!
174  * Writes \a this mesh into a MED file specified by its name.
175  *  \param [in] fileName - the MED file name.
176  *  \param [in] mode - the writing mode. For more on \a mode, see \ref AdvMEDLoaderBasics.
177  * - 2 - erase; an existing file is removed.
178  * - 1 - append; same data should not be present in an existing file.
179  * - 0 - overwrite; same data present in an existing file is overwritten.
180  *  \throw If the mesh name is not set.
181  *  \throw If \a mode == 1 and the same data is present in an existing file.
182  */
183 void MEDFileMesh::write(const char *fileName, int mode) const throw(INTERP_KERNEL::Exception)
184 {
185   med_access_mode medmod=MEDFileUtilities::TraduceWriteMode(mode);
186   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,medmod);
187   std::ostringstream oss; oss << "MEDFileMesh : error on attempt to write in file : \"" << fileName << "\""; 
188   MEDFileUtilities::CheckMEDCode(fid,fid,oss.str().c_str());
189   write(fid);
190 }
191
192 /*!
193  * Checks if \a this and another mesh are equal.
194  *  \param [in] other - the mesh to compare with.
195  *  \param [in] eps - a precision used to compare real values.
196  *  \param [in,out] what - the string returning description of unequal data.
197  *  \return bool - \c true if the meshes are equal, \c false, else.
198  */
199 bool MEDFileMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const
200 {
201   if(_order!=other->_order)
202     {
203       what="Orders differ !";
204       return false;
205     }
206   if(_iteration!=other->_iteration)
207     {
208       what="Iterations differ !";
209       return false;
210     }
211   if(fabs(_time-other->_time)>eps)
212     {
213       what="Time values differ !";
214       return false;
215     }
216   if(_dt_unit!=other->_dt_unit)
217     {
218       what="Time units differ !";
219       return false;
220     }
221   if(_name!=other->_name)
222     {
223       what="Names differ !";
224       return false;
225     }
226   //univ_name has been ignored -> not a bug because it is a mutable attribute
227   if(_desc_name!=other->_desc_name)
228     {
229       what="Description names differ !";
230       return false;
231     }
232   if(!areGrpsEqual(other,what))
233     return false;
234   if(!areFamsEqual(other,what))
235     return false;
236   return true;
237 }
238
239 /*!
240  * Clears redundant attributes of incorporated data arrays.
241  */
242 void MEDFileMesh::clearNonDiscrAttributes() const
243 {
244   
245 }
246
247 bool MEDFileMesh::changeNames(const std::vector< std::pair<std::string,std::string> >& modifTab) throw(INTERP_KERNEL::Exception)
248 {
249   for(std::vector< std::pair<std::string,std::string> >::const_iterator it=modifTab.begin();it!=modifTab.end();it++)
250     {
251       if((*it).first==_name)
252         {
253           _name=(*it).second;
254           return true;
255         }
256     }
257   return false;
258 }
259
260 /*!
261  * Copies data on groups and families from another mesh.
262  *  \param [in] other - the mesh to copy the data from.
263  */
264 void MEDFileMesh::copyFamGrpMapsFrom(const MEDFileMesh& other)
265 {
266   _groups=other._groups;
267   _families=other._families;
268 }
269
270 /*!
271  * Returns names of families constituting a group.
272  *  \param [in] name - the name of the group of interest.
273  *  \return std::vector<std::string> - a sequence of names of the families.
274  *  \throw If the name of a nonexistent group is specified.
275  */
276 std::vector<std::string> MEDFileMesh::getFamiliesOnGroup(const char *name) const throw(INTERP_KERNEL::Exception)
277 {
278   std::string oname(name);
279   std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.find(oname);
280   if(it==_groups.end())
281     {
282       std::vector<std::string> grps=getGroupsNames();
283       std::ostringstream oss; oss << "No such groupname \"" << name << "\" !\nAvailable groups are :";
284       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
285       throw INTERP_KERNEL::Exception(oss.str().c_str());
286     }
287   return (*it).second;
288 }
289
290 /*!
291  * Returns names of families constituting some groups.
292  *  \param [in] grps - a sequence of names of groups of interest.
293  *  \return std::vector<std::string> - a sequence of names of the families.
294  *  \throw If a name of a nonexistent group is present in \a grps.
295  */
296 std::vector<std::string> MEDFileMesh::getFamiliesOnGroups(const std::vector<std::string>& grps) const throw(INTERP_KERNEL::Exception)
297 {
298   std::set<std::string> fams;
299   for(std::vector<std::string>::const_iterator it=grps.begin();it!=grps.end();it++)
300     {
301       std::map<std::string, std::vector<std::string> >::const_iterator it2=_groups.find(*it);
302       if(it2==_groups.end())
303         {
304           std::ostringstream oss; oss << "No such group in mesh \"" << _name << "\" : " << *it; 
305           std::vector<std::string> grps2=getGroupsNames(); oss << "\" !\nAvailable groups are :";
306           std::copy(grps2.begin(),grps2.end(),std::ostream_iterator<std::string>(oss," "));
307           throw INTERP_KERNEL::Exception(oss.str().c_str());
308         }
309       fams.insert((*it2).second.begin(),(*it2).second.end());
310     }
311   std::vector<std::string> fams2(fams.begin(),fams.end());
312   return fams2;
313 }
314
315 /*!
316  * Returns ids of families constituting a group.
317  *  \param [in] name - the name of the group of interest.
318  *  \return std::vector<int> - sequence of ids of the families.
319  *  \throw If the name of a nonexistent group is specified.
320  */
321 std::vector<int> MEDFileMesh::getFamiliesIdsOnGroup(const char *name) const throw(INTERP_KERNEL::Exception)
322 {
323   std::string oname(name);
324   std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.find(oname);
325   std::vector<std::string> grps=getGroupsNames();
326   if(it==_groups.end())
327     {
328       std::ostringstream oss; oss << "No such groupname \"" << name << "\" !\nAvailable groups are :";
329       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
330       throw INTERP_KERNEL::Exception(oss.str().c_str());
331     }
332   return getFamiliesIds((*it).second);
333 }
334
335 /*!
336  * Sets names of families constituting a group. If data on families of this group is
337  * already present, it is overwritten. Every family in \a fams is checked, and if a
338  family is not yet in \a this mesh, the default group id \c 0 is assigned to it.
339  *  \param [in] name - the name of the group of interest.
340  *  \param [in] fams - a sequence of names of families constituting the group.
341  */
342 void MEDFileMesh::setFamiliesOnGroup(const char *name, const std::vector<std::string>& fams) throw(INTERP_KERNEL::Exception)
343 {
344   std::string oname(name);
345   _groups[oname]=fams;
346   for(std::vector<std::string>::const_iterator it1=fams.begin();it1!=fams.end();it1++)
347     {
348       std::map<std::string,int>::iterator it2=_families.find(*it1);
349       if(it2==_families.end())
350         _families[*it1]=0;
351     }
352 }
353
354 /*!
355  * Sets families constituting a group. The families are specified by their ids.
356  * If a family name is not found by its id, an exception is thrown.
357  * If several families have same id, the first one in lexical order is taken.
358  *  \param [in] name - the name of the group of interest.
359  *  \param [in] famIds - a sequence of ids of families constituting the group.
360  *  \throw If a family name is not found by its id.
361  */
362 void MEDFileMesh::setFamiliesIdsOnGroup(const char *name, const std::vector<int>& famIds) throw(INTERP_KERNEL::Exception)
363 {
364   std::string oname(name);
365   std::vector<std::string> fams(famIds.size());
366   int i=0;
367   for(std::vector<int>::const_iterator it1=famIds.begin();it1!=famIds.end();it1++,i++)
368     {
369       std::string name2=getFamilyNameGivenId(*it1);
370       fams[i]=name2;
371     }
372   _groups[oname]=fams;
373 }
374
375 /*!
376  * Returns names of groups including a given family.
377  *  \param [in] name - the name of the family of interest.
378  *  \return std::vector<std::string> - a sequence of names of groups including the family.
379  */
380 std::vector<std::string> MEDFileMesh::getGroupsOnFamily(const char *name) const throw(INTERP_KERNEL::Exception)
381 {
382   std::vector<std::string> ret;
383   for(std::map<std::string, std::vector<std::string> >::const_iterator it1=_groups.begin();it1!=_groups.end();it1++)
384     {
385       for(std::vector<std::string>::const_iterator it2=(*it1).second.begin();it2!=(*it1).second.end();it2++)
386         if((*it2)==name)
387           {
388             ret.push_back((*it1).first);
389             break;
390           }
391     }
392   return ret;
393 }
394
395 /*!
396  * Adds an existing family to groups.
397  *  \param [in] famName - a name of family to add to \a grps.
398  *  \param [in] grps - a sequence of group names to add the family in.
399  *  \throw If a family named \a famName not yet exists.
400  */
401 void MEDFileMesh::setGroupsOnFamily(const char *famName, const std::vector<std::string>& grps) throw(INTERP_KERNEL::Exception)
402 {
403   std::string fName(famName);
404   const std::map<std::string,int>::const_iterator it=_families.find(fName);
405   if(it==_families.end())
406     {
407       std::vector<std::string> fams=getFamiliesNames();
408       std::ostringstream oss; oss << "No such familyname \"" << fName << "\" !\nAvailable families are :";
409       std::copy(fams.begin(),fams.end(),std::ostream_iterator<std::string>(oss," "));
410       throw INTERP_KERNEL::Exception(oss.str().c_str());
411     }
412   for(std::vector<std::string>::const_iterator it3=grps.begin();it3!=grps.end();it3++)
413     {
414       std::map< std::string, std::vector<std::string> >::iterator it2=_groups.find(*it3);
415       if(it2!=_groups.end())
416         (*it2).second.push_back(fName);
417       else
418         {
419           std::vector<std::string> grps2(1,fName);
420           _groups[*it3]=grps2;
421         }
422     }
423 }
424
425 /*!
426  * Returns names of all groups of \a this mesh.
427  *  \return std::vector<std::string> - a sequence of group names.
428  */
429 std::vector<std::string> MEDFileMesh::getGroupsNames() const
430 {
431   std::vector<std::string> ret(_groups.size());
432   int i=0;
433   for(std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.begin();it!=_groups.end();it++,i++)
434     ret[i]=(*it).first;
435   return ret;
436 }
437
438 /*!
439  * Returns names of all families of \a this mesh.
440  *  \return std::vector<std::string> - a sequence of family names.
441  */
442 std::vector<std::string> MEDFileMesh::getFamiliesNames() const
443 {
444   std::vector<std::string> ret(_families.size());
445   int i=0;
446   for(std::map<std::string, int >::const_iterator it=_families.begin();it!=_families.end();it++,i++)
447     ret[i]=(*it).first;
448   return ret;
449 }
450
451 /*!
452  * Changes a name of every family, included in one group only, to be same as the group name.
453  *  \throw If there are families with equal names in \a this mesh.
454  */
455 void MEDFileMesh::assignFamilyNameWithGroupName() throw(INTERP_KERNEL::Exception)
456 {
457   std::map<std::string, std::vector<std::string> > groups(_groups);
458   std::map<std::string,int> newFams;
459   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
460     {
461       std::vector<std::string> grps=getGroupsOnFamily((*it).first.c_str());
462       if(grps.size()==1 && groups[grps[0]].size()==1)
463         {
464           if(newFams.find(grps[0])!=newFams.end())
465             {
466               std::ostringstream oss; oss << "MEDFileMesh::assignFamilyNameWithGroupName : Family \"" << grps[0] << "\" already exists !";
467               throw INTERP_KERNEL::Exception(oss.str().c_str());
468             }
469           newFams[grps[0]]=(*it).second;
470           std::vector<std::string>& grps2=groups[grps[0]];
471           std::size_t pos=std::distance(grps2.begin(),std::find(grps2.begin(),grps2.end(),(*it).first));
472           grps2[pos]=grps[0];
473         }
474       else
475         {
476           if(newFams.find((*it).first)!=newFams.end())
477             {
478               std::ostringstream oss; oss << "MEDFileMesh::assignFamilyNameWithGroupName : Family \"" << (*it).first << "\" already exists !";
479               throw INTERP_KERNEL::Exception(oss.str().c_str());
480             }
481           newFams[(*it).first]=(*it).second;
482         }
483     }
484   _families=newFams;
485   _groups=groups;
486 }
487
488 /*!
489  * Removes all groups lying on no family. If there is no empty groups, \a this is let untouched.
490  * 
491  * \return the removed groups.
492  */
493 std::vector<std::string> MEDFileMesh::removeEmptyGroups() throw(INTERP_KERNEL::Exception)
494 {
495   std::vector<std::string> ret;
496   std::map<std::string, std::vector<std::string> > newGrps;
497   for(std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.begin();it!=_groups.end();it++)
498     {
499       if((*it).second.empty())
500         ret.push_back((*it).first);
501       else
502         newGrps[(*it).first]=(*it).second;
503     }
504   if(!ret.empty())
505     _groups=newGrps;
506   return ret;
507 }
508
509 /*!
510  * Removes a group from \a this mesh.
511  *  \param [in] name - the name of the group to remove.
512  *  \throw If no group with such a \a name exists.
513  */
514 void MEDFileMesh::removeGroup(const char *name) throw(INTERP_KERNEL::Exception)
515 {
516   std::string oname(name);
517   std::map<std::string, std::vector<std::string> >::iterator it=_groups.find(oname);
518   std::vector<std::string> grps=getGroupsNames();
519   if(it==_groups.end())
520     {
521       std::ostringstream oss; oss << "No such groupname \"" << name << "\" !\nAvailable groups are :";
522       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
523       throw INTERP_KERNEL::Exception(oss.str().c_str());
524     }
525   _groups.erase(it);
526 }
527
528 /*!
529  * Removes a family from \a this mesh.
530  *  \param [in] name - the name of the family to remove.
531  *  \throw If no family with such a \a name exists.
532  */
533 void MEDFileMesh::removeFamily(const char *name) throw(INTERP_KERNEL::Exception)
534 {
535   std::string oname(name);
536   std::map<std::string, int >::iterator it=_families.find(oname);
537   std::vector<std::string> fams=getFamiliesNames();
538   if(it==_families.end())
539     {
540       std::ostringstream oss; oss << "No such familyname \"" << name << "\" !\nAvailable families are :";
541       std::copy(fams.begin(),fams.end(),std::ostream_iterator<std::string>(oss," "));
542       throw INTERP_KERNEL::Exception(oss.str().c_str());
543     }
544   _families.erase(it);
545   for(std::map<std::string, std::vector<std::string> >::iterator it3=_groups.begin();it3!=_groups.end();it3++)
546     {
547       std::vector<std::string>& v=(*it3).second;
548       std::vector<std::string>::iterator it4=std::find(v.begin(),v.end(),oname);
549       if(it4!=v.end())
550         v.erase(it4);
551     }
552 }
553
554 /*!
555  * Removes all groups in \a this that are orphan. A group is orphan if this group lies on
556  * a set of families, themselves orphan. A family is said orphan if its id appears nowhere in
557  * family field whatever its level. This method also suppresses the orphan families.
558  * 
559  * \return - The list of removed groups names. 
560  *
561  * \sa MEDFileMesh::removeOrphanFamilies.
562  */
563 std::vector<std::string> MEDFileMesh::removeOrphanGroups() throw(INTERP_KERNEL::Exception)
564 {
565   removeOrphanFamilies();
566   return removeEmptyGroups();
567 }
568
569 /*!
570  * Removes all families in \a this that are orphan. A family is said orphan if its id appears nowhere in
571  * 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.
572  * 
573  * \return - The list of removed families names.
574  * \sa MEDFileMesh::removeOrphanGroups.
575  */
576 std::vector<std::string> MEDFileMesh::removeOrphanFamilies() throw(INTERP_KERNEL::Exception)
577 {
578   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> allFamIdsInUse=computeAllFamilyIdsInUse();
579   std::vector<std::string> ret;
580   if(!((DataArrayInt*)allFamIdsInUse))
581     {
582       ret=getFamiliesNames();
583       _families.clear(); _groups.clear();
584       return ret;
585     }
586   std::map<std::string,int> famMap;
587   std::map<std::string, std::vector<std::string> > grps(_groups);
588   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
589     {
590       if(allFamIdsInUse->presenceOfValue((*it).second))
591         famMap[(*it).first]=(*it).second;
592       else
593         {
594           ret.push_back((*it).first);
595           std::vector<std::string> grpsOnEraseFam=getGroupsOnFamily((*it).first.c_str());
596           for(std::vector<std::string>::const_iterator it2=grpsOnEraseFam.begin();it2!=grpsOnEraseFam.end();it2++)
597             {
598               std::map<std::string, std::vector<std::string> >::iterator it3=grps.find(*it2);//it3!=grps.empty() thanks to copy
599               std::vector<std::string>& famv=(*it3).second;
600               std::vector<std::string>::iterator it4=std::find(famv.begin(),famv.end(),(*it).first);//it4!=famv.end() thanks to copy
601               famv.erase(it4);
602             }
603         }
604     }
605   if(!ret.empty())
606     { _families=famMap; _groups=grps; }
607   return ret;
608 }
609
610 /*!
611  * Renames a group in \a this mesh.
612  *  \param [in] oldName - a current name of the group to rename.
613  *  \param [in] newName - a new group name.
614  *  \throw If no group named \a oldName exists in \a this mesh.
615  *  \throw If a group named \a newName already exists.
616  */
617 void MEDFileMesh::changeGroupName(const char *oldName, const char *newName) throw(INTERP_KERNEL::Exception)
618 {
619   std::string oname(oldName);
620   std::map<std::string, std::vector<std::string> >::iterator it=_groups.find(oname);
621   std::vector<std::string> grps=getGroupsNames();
622   if(it==_groups.end())
623     {
624       std::ostringstream oss; oss << "No such groupname \"" << oldName << "\" !\nAvailable groups are :";
625       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
626       throw INTERP_KERNEL::Exception(oss.str().c_str());
627     }
628   std::string nname(newName);
629   std::map<std::string, std::vector<std::string> >::iterator it2=_groups.find(nname);
630   if(it2!=_groups.end())
631     {
632       std::ostringstream oss; oss << "Such groupname \"" << newName << "\" already exists ! Kill it before !";
633       throw INTERP_KERNEL::Exception(oss.str().c_str());
634     }
635   std::vector<std::string> cpy=(*it).second;
636   _groups.erase(it);
637   _groups[newName]=cpy;
638 }
639
640 /*!
641  * Changes an id of a family in \a this mesh. 
642  * This method calls changeFamilyIdArr().
643  *  \param [in] oldId - a current id of the family.
644  *  \param [in] newId - a new family id.
645  */
646 void MEDFileMesh::changeFamilyId(int oldId, int newId) throw(INTERP_KERNEL::Exception)
647 {
648   changeFamilyIdArr(oldId,newId);
649   std::map<std::string,int> fam2;
650   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
651     {
652       if((*it).second==oldId)
653         fam2[(*it).first]=newId;
654       else
655         fam2[(*it).first]=(*it).second;
656     }
657   _families=fam2;
658 }
659
660 /*!
661  * Renames a family in \a this mesh.
662  *  \param [in] oldName - a current name of the family to rename.
663  *  \param [in] newName - a new family name.
664  *  \throw If no family named \a oldName exists in \a this mesh.
665  *  \throw If a family named \a newName already exists.
666  */
667 void MEDFileMesh::changeFamilyName(const char *oldName, const char *newName) throw(INTERP_KERNEL::Exception)
668 {
669   std::string oname(oldName);
670   std::map<std::string, int >::iterator it=_families.find(oname);
671   std::vector<std::string> fams=getFamiliesNames();
672   if(it==_families.end())
673     {
674       std::ostringstream oss; oss << "No such familyname \"" << oldName << "\" !\nAvailable families are :";
675       std::copy(fams.begin(),fams.end(),std::ostream_iterator<std::string>(oss," "));
676       throw INTERP_KERNEL::Exception(oss.str().c_str());
677     }
678   std::string nname(newName);
679   std::map<std::string, int >::iterator it2=_families.find(nname);
680   if(it2!=_families.end())
681     {
682       std::ostringstream oss; oss << "Such familyname \"" << newName << " already exists ! Kill it before !";
683       throw INTERP_KERNEL::Exception(oss.str().c_str());
684     }
685   int cpy=(*it).second;
686   _families.erase(it);
687   _families[newName]=cpy;
688   for(std::map<std::string, std::vector<std::string> >::iterator it3=_groups.begin();it3!=_groups.end();it3++)
689     {
690       std::vector<std::string>& v=(*it3).second;
691       std::vector<std::string>::iterator it4=std::find(v.begin(),v.end(),oname);
692       if(it4!=v.end())
693         (*it4)=nname;
694     }
695 }
696
697 /*!
698  * Checks if \a this and another mesh contains the same families.
699  *  \param [in] other - the mesh to compare with \a this one.
700  *  \param [in,out] what - an unused parameter.
701  *  \return bool - \c true if number of families and their ids are the same in the two
702  *          meshes. Families with the id == \c 0 are not considered.
703  */
704 bool MEDFileMesh::areFamsEqual(const MEDFileMesh *other, std::string& what) const
705 {
706   if(_families==other->_families)
707     return true;
708   std::map<std::string,int> fam0;
709   std::map<std::string,int> fam1;
710   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
711     if((*it).second!=0)
712       fam0[(*it).first]=(*it).second;
713   for(std::map<std::string,int>::const_iterator it=other->_families.begin();it!=other->_families.end();it++)
714     if((*it).second!=0)
715       fam1[(*it).first]=(*it).second;
716   return fam0==fam1;
717 }
718
719 /*!
720  * Checks if \a this and another mesh contains the same groups.
721  *  \param [in] other - the mesh to compare with \a this one.
722  *  \param [in,out] what - a string describing a difference of groups of the two meshes
723  *          in case if this method returns \c false.
724  *  \return bool - \c true if number of groups and families constituting them are the
725  *          same in the two meshes.
726  */
727 bool MEDFileMesh::areGrpsEqual(const MEDFileMesh *other, std::string& what) const
728 {
729   if(_groups==other->_groups)
730     return true;
731   bool ret=true;
732   std::size_t sz=_groups.size();
733   if(sz!=other->_groups.size())
734     {
735       what="Groups differ because not same number !\n";
736       ret=false;
737     }
738   if(ret)
739     {
740       std::map<std::string, std::vector<std::string> >::const_iterator it1=_groups.begin();
741       for(std::size_t i=0;i<sz && ret;i++,it1++)
742         {
743           std::map<std::string, std::vector<std::string> >::const_iterator it2=other->_groups.find((*it1).first);
744           if(it2!=other->_groups.end())
745             {
746               std::set<std::string> s1((*it1).second.begin(),(*it1).second.end());
747               std::set<std::string> s2((*it2).second.begin(),(*it2).second.end());
748               ret=(s1==s2);
749             }
750           else
751             {
752               ret=false;
753               what="A group in first mesh exists not in other !\n";
754             }
755         }
756     }
757   if(!ret)
758     {
759       std::ostringstream oss; oss << "Groups description differs :\n";
760       oss << "First group description :\n";
761       for(std::map<std::string, std::vector<std::string> >::const_iterator it=_groups.begin();it!=_groups.end();it++)
762         {
763           oss << " Group \"" << (*it).first << "\" on following families :\n";
764           for(std::vector<std::string>::const_iterator it2=(*it).second.begin();it2!=(*it).second.end();it2++)
765         oss << "    \"" << *it2 << "\n";
766         }
767       oss << "Second group description :\n";
768       for(std::map<std::string, std::vector<std::string> >::const_iterator it=other->_groups.begin();it!=other->_groups.end();it++)
769         {
770           oss << " Group \"" << (*it).first << "\" on following families :\n";
771           for(std::vector<std::string>::const_iterator it2=(*it).second.begin();it2!=(*it).second.end();it2++)
772             oss << "    \"" << *it2 << "\n";
773         }
774       what+=oss.str();
775     }
776   return ret;
777 }
778
779 /*!
780  * Checks if a group with a given name exists in \a this mesh.
781  *  \param [in] groupName - the group name.
782  *  \return bool - \c true the group \a groupName exists in \a this mesh.
783  */
784 bool MEDFileMesh::existsGroup(const char *groupName) const
785 {
786   std::string grpName(groupName);
787   return _groups.find(grpName)!=_groups.end();
788 }
789
790 /*!
791  * Checks if a family with a given id exists in \a this mesh.
792  *  \param [in] famId - the family id.
793  *  \return bool - \c true the family with the id \a famId exists in \a this mesh.
794  */
795 bool MEDFileMesh::existsFamily(int famId) const
796 {
797   for(std::map<std::string,int>::const_iterator it2=_families.begin();it2!=_families.end();it2++)
798     if((*it2).second==famId)
799       return true;
800   return false;
801 }
802
803 /*!
804  * Checks if a family with a given name exists in \a this mesh.
805  *  \param [in] familyName - the family name.
806  *  \return bool - \c true the family \a familyName exists in \a this mesh.
807  */
808 bool MEDFileMesh::existsFamily(const char *familyName) const
809 {
810   std::string fname(familyName);
811   return _families.find(fname)!=_families.end();
812 }
813
814 /*!
815  * Sets an id of a family.
816  *  \param [in] familyName - the family name.
817  *  \param [in] id - a new id of the family.
818  */
819 void MEDFileMesh::setFamilyId(const char *familyName, int id)
820 {
821   std::string fname(familyName);
822   _families[fname]=id;
823 }
824
825 void MEDFileMesh::setFamilyIdUnique(const char *familyName, int id) throw(INTERP_KERNEL::Exception)
826 {
827   std::string fname(familyName);
828   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
829     if((*it).second==id)
830       {
831         if((*it).first!=familyName)
832           {
833             std::ostringstream oss; oss << "MEDFileMesh::setFamilyIdUnique : Family id #" << id << " is already belonging to family with name \"" << (*it).first << "\" !";
834             throw INTERP_KERNEL::Exception(oss.str().c_str());
835           }
836       }
837   _families[fname]=id;
838 }
839
840 /*!
841  * Adds a family to \a this mesh.
842  *  \param [in] familyName - a name of the family.
843  *  \param [in] famId - an id of the family.
844  *  \throw If a family with the same name or id already exists in \a this mesh.
845  */
846 void MEDFileMesh::addFamily(const char *familyName, int famId) throw(INTERP_KERNEL::Exception)
847 {
848   std::string fname(familyName);
849   std::map<std::string,int>::const_iterator it=_families.find(fname);
850   if(it==_families.end())
851     {
852        for(std::map<std::string,int>::const_iterator it2=_families.begin();it2!=_families.end();it2++)
853          if((*it2).second==famId)
854            {
855              std::ostringstream oss;
856              oss << "MEDFileMesh::addFamily : Family \"" << (*it2).first << "\" already exists with specified id : " << famId << " !";
857              throw INTERP_KERNEL::Exception(oss.str().c_str());
858            }
859        _families[fname]=famId;
860     }
861   else
862     {
863       if((*it).second!=famId)
864         {
865           std::ostringstream oss;
866           oss << "MEDFileMesh::addFamily : Family \"" << fname << "\" already exists but has id set to " << (*it).second << " different from asked famId " << famId << " !";
867           throw INTERP_KERNEL::Exception(oss.str().c_str());
868         }
869     }
870 }
871
872 /*!
873  * Creates a group including all mesh entities of given dimension.
874  * \warning This method does \b not guarantee that the created group includes mesh
875  * entities of only \a meshDimRelToMaxExt dimension in the case if some family id is
876  * present in family fields of different dimensions. To assure this, call
877  * ensureDifferentFamIdsPerLevel() \b before calling this method.
878  *  \param [in] meshDimRelToMaxExt - a relative dimension of mesh entities to include to
879  *          the group.
880  *  \param [in] groupName - a name of the new group.
881  *  \throw If a group named \a groupName already exists.
882  *  \throw If no mesh entities of dimension \a meshDimRelToMaxExt exist in \a this mesh.
883  *  \throw If no family field of dimension \a meshDimRelToMaxExt is present in \a this mesh.
884  */
885 void MEDFileMesh::createGroupOnAll(int meshDimRelToMaxExt, const char *groupName) throw(INTERP_KERNEL::Exception)
886 {
887   std::string grpName(groupName);
888   std::vector<int> levs=getNonEmptyLevelsExt();
889   if(std::find(levs.begin(),levs.end(),meshDimRelToMaxExt)==levs.end())
890     {
891       std::ostringstream oss; oss << "MEDFileMesh::createGroupOnAll : The relative ext dimension " << meshDimRelToMaxExt << " is not available !" << std::endl;
892       oss << "Available relative ext levels are : ";
893       std::copy(levs.begin(),levs.end(),std::ostream_iterator<int>(oss," "));
894       throw INTERP_KERNEL::Exception(oss.str().c_str());
895     }
896   if(existsGroup(groupName))
897     {
898       std::ostringstream oss; oss << "MEDFileMesh::createGroupOnAll : The groups \"" << grpName << "\" already exists in this !" << std::endl;
899       oss << "Already existing groups are : ";
900       std::copy(levs.begin(),levs.end(),std::ostream_iterator<int>(oss," "));
901       oss << std::endl << "Please choose an another group name or call removeGroup(\"" << grpName << "\") method !";
902       throw INTERP_KERNEL::Exception(oss.str().c_str());
903     }
904   const DataArrayInt *fieldFamIds=getFamilyFieldAtLevel(meshDimRelToMaxExt);
905   if(fieldFamIds==0)
906     throw INTERP_KERNEL::Exception("MEDFileMesh::createGroupOnAll : Family field arr ids is not defined for this level !");
907   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> famIds=fieldFamIds->getDifferentValues();
908   std::vector<std::string> familiesOnWholeGroup;
909   for(const int *it=famIds->begin();it!=famIds->end();it++)
910     {
911       bool tmp;
912       familiesOnWholeGroup.push_back(findOrCreateAndGiveFamilyWithId(*it,tmp));
913     }
914   _groups[grpName]=familiesOnWholeGroup;
915 }
916
917 /*!
918  * Ensures that given family ids do not present in family fields of dimensions different
919  * than given ones. If a family id is present in the family fields of dimensions different
920  * than the given ones, a new family is created and the whole data is updated accordingly.
921  *  \param [in] famIds - a sequence of family ids to check.
922  *  \param [in] vMeshDimRelToMaxExt - a sequence of relative dimensions to which the \a
923  *          famIds should exclusively belong.
924  *  \return bool - \c true if no modification is done in \a this mesh by this method.
925  */
926 bool MEDFileMesh::keepFamIdsOnlyOnLevs(const std::vector<int>& famIds, const std::vector<int>& vMeshDimRelToMaxExt) throw(INTERP_KERNEL::Exception)
927 {
928   std::set<int> levsInput(vMeshDimRelToMaxExt.begin(),vMeshDimRelToMaxExt.end());
929   std::vector<int> levs=getNonEmptyLevelsExt();
930   std::set<int> levs2(levs.begin(),levs.end());
931   std::vector<int> levsToTest;
932   std::set_difference(levs2.begin(),levs2.end(),levsInput.begin(),levsInput.end(),std::back_insert_iterator< std::vector<int> >(levsToTest));
933   std::set<int> famIds2(famIds.begin(),famIds.end());
934   bool ret=true;
935   int maxFamId=1;
936   if(!_families.empty())
937     maxFamId=getMaxFamilyId()+1;
938   std::vector<std::string> allFams=getFamiliesNames();
939   for(std::vector<int>::const_iterator it=levsToTest.begin();it!=levsToTest.end();it++)
940     {
941       const DataArrayInt *fieldFamIds=getFamilyFieldAtLevel(*it);
942       if(fieldFamIds)
943         {
944           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> famIds3=fieldFamIds->getDifferentValues();
945           std::vector<int> tmp;
946           std::set_intersection(famIds3->begin(),famIds3->end(),famIds2.begin(),famIds2.end(),std::back_insert_iterator< std::vector<int> >(tmp));
947           for(std::vector<int>::const_iterator it2=tmp.begin();it2!=tmp.end();it2++)
948             {
949               ret=false;
950               std::string famName=getFamilyNameGivenId(*it2);
951               std::ostringstream oss; oss << "Family_" << maxFamId;
952               std::string zeName=CreateNameNotIn(oss.str(),allFams);
953               addFamilyOnAllGroupsHaving(famName.c_str(),zeName.c_str());
954               _families[zeName]=maxFamId;
955               (const_cast<DataArrayInt *>(fieldFamIds))->changeValue(*it2,maxFamId);
956               maxFamId++;
957             }
958         }
959     }
960   return ret;
961 }
962
963 /*!
964  * Adds a family to a given group in \a this mesh. If the group with a given name does
965  * not exist, it is created.
966  *  \param [in] grpName - the name of the group to add the family in.
967  *  \param [in] famName - the name of the family to add to the group named \a grpName.
968  *  \throw If \a grpName or \a famName is an empty string.
969  *  \throw If no family named \a famName is present in \a this mesh.
970  */
971 void MEDFileMesh::addFamilyOnGrp(const char *grpName, const char *famName) throw(INTERP_KERNEL::Exception)
972 {
973   std::string grpn(grpName);
974   std::string famn(famName);
975   if(grpn.empty() || famn.empty())
976     throw INTERP_KERNEL::Exception("MEDFileMesh::addFamilyOnGrp : input strings must be non null !");
977   std::vector<std::string> fams=getFamiliesNames();
978   if(std::find(fams.begin(),fams.end(),famn)==fams.end())
979     {
980       std::ostringstream oss; oss << "MEDFileMesh::addFamilyOnGrp : Family \"" << famn << "\" does not exist !" << std::endl;
981       oss << "Create this family or choose an existing one ! Existing fams are : ";
982       std::copy(fams.begin(),fams.end(),std::ostream_iterator<std::string>(oss," ")); oss << ".";
983       throw INTERP_KERNEL::Exception(oss.str().c_str());
984     }
985   std::map<std::string, std::vector<std::string> >::iterator it=_groups.find(grpn);
986   if(it==_groups.end())
987     {
988       _groups[grpn].push_back(famn);
989     }
990   else
991     {
992       std::vector<std::string>::iterator it2=std::find((*it).second.begin(),(*it).second.end(),famn);
993       if(it2==(*it).second.end())
994         (*it).second.push_back(famn);
995     }
996 }
997
998 /*!
999  * This method adds to all groups lying on family with name 'famName' the other family name 'otherFamName'.
1000  * This method is quite underground because it can lead to unconsistency because family 'otherFamName' is \b not added into _families.
1001  * This method is used by MEDFileMesh::keepFamIdsOnlyOnLevs method.
1002  */
1003 void MEDFileMesh::addFamilyOnAllGroupsHaving(const char *famName, const char *otherFamName) throw(INTERP_KERNEL::Exception)
1004 {
1005   std::string famNameCpp(famName);
1006   std::string otherCpp(otherFamName);
1007   for(std::map<std::string, std::vector<std::string> >::iterator it=_groups.begin();it!=_groups.end();it++)
1008     {
1009       std::vector<std::string>& v=(*it).second;
1010       if(std::find(v.begin(),v.end(),famNameCpp)!=v.end())
1011         {
1012           v.push_back(otherCpp);
1013         }
1014     }
1015 }
1016
1017 void MEDFileMesh::changeAllGroupsContainingFamily(const char *familyNameToChange, const std::vector<std::string>& newFamiliesNames) throw(INTERP_KERNEL::Exception)
1018 {
1019   ChangeAllGroupsContainingFamily(_groups,familyNameToChange,newFamiliesNames);
1020 }
1021
1022 void MEDFileMesh::ChangeAllGroupsContainingFamily(std::map<std::string, std::vector<std::string> >& groups, const char *familyNameToChange, const std::vector<std::string>& newFamiliesNames) throw(INTERP_KERNEL::Exception)
1023 {
1024   std::string fam(familyNameToChange);
1025   for(std::map<std::string, std::vector<std::string> >::iterator it=groups.begin();it!=groups.end();it++)
1026     {
1027       std::vector<std::string>& fams((*it).second);
1028       std::vector<std::string>::iterator it2=std::find(fams.begin(),fams.end(),fam);
1029       if(it2!=fams.end())
1030         {
1031           fams.erase(it2);
1032           fams.insert(fams.end(),newFamiliesNames.begin(),newFamiliesNames.end());
1033         }
1034     }
1035 }
1036
1037 /*!
1038  * Returns a name of the family having a given id or, if no such a family exists, creates
1039  * a new uniquely named family and returns its name.
1040  *  \param [in] id - the id of the family whose name is required.
1041  *  \param [out] created - returns \c true if the new family has been created, \c false, else.
1042  *  \return std::string - the name of the existing or the created family.
1043  *  \throw If it is not possible to create a unique family name.
1044  */
1045 std::string MEDFileMesh::findOrCreateAndGiveFamilyWithId(int id, bool& created) throw(INTERP_KERNEL::Exception)
1046 {
1047   return FindOrCreateAndGiveFamilyWithId(_families,id,created);
1048 }
1049
1050 /*!
1051  * If it exists a family whose family id is equal to 'id' this method behaves as MEDFileMesh::getFamilyNameGivenId.
1052  * In this case, 'this' internal states remains unchanged and 'created' out parameter will be set to false.
1053  * If there is no family whose family id is equal to 'id' a family is created with a name different from those
1054  * already existing. In this case 'created' will be returned with a value set to true, and internal state
1055  * will be modified.
1056  * This method will throws an exception if it is not possible to create a unique family name.
1057  */
1058 std::string MEDFileMesh::FindOrCreateAndGiveFamilyWithId(std::map<std::string,int>& families, int id, bool& created) throw(INTERP_KERNEL::Exception)
1059 {
1060   std::vector<std::string> famAlreadyExisting(families.size());
1061   int ii=0;
1062   for(std::map<std::string,int>::const_iterator it=families.begin();it!=families.end();it++,ii++)
1063     {
1064       if((*it).second!=id)
1065         {
1066           famAlreadyExisting[ii]=(*it).first;
1067         }
1068       else
1069         {
1070           created=false;
1071           return (*it).first;
1072         }
1073     }
1074   created=true;
1075   std::ostringstream oss; oss << "Family_" << id;
1076   std::string ret=CreateNameNotIn(oss.str(),famAlreadyExisting);
1077   families[ret]=id;
1078   return ret;
1079 }
1080
1081 /*!
1082  * Sets names and ids of all families in \a this mesh.
1083  *  \param [in] info - a map of a family name to a family id.
1084  */
1085 void MEDFileMesh::setFamilyInfo(const std::map<std::string,int>& info)
1086 {
1087   _families=info;
1088 }
1089
1090 /*!
1091  * Sets names of all groups and families constituting them in \a this mesh.
1092  *  \param [in] info - a map of a group name to a vector of names of families
1093  *          constituting the group.
1094  */
1095 void MEDFileMesh::setGroupInfo(const std::map<std::string, std::vector<std::string> >&info)
1096 {
1097   _groups=info;
1098 }
1099
1100 /*!
1101  * Returns an id of the family having a given name.
1102  *  \param [in] name - the name of the family of interest.
1103  *  \return int - the id of the family of interest.
1104  *  \throw If no family with such a \a name exists.
1105  */
1106 int MEDFileMesh::getFamilyId(const char *name) const throw(INTERP_KERNEL::Exception)
1107 {
1108   std::string oname(name);
1109   std::map<std::string, int>::const_iterator it=_families.find(oname);
1110   std::vector<std::string> fams=getFamiliesNames();
1111   if(it==_families.end())
1112     {
1113       std::ostringstream oss; oss << "No such familyname \"" << name << "\" !\nAvailable families are :";
1114       std::copy(fams.begin(),fams.end(),std::ostream_iterator<std::string>(oss," "));
1115       throw INTERP_KERNEL::Exception(oss.str().c_str());
1116     }
1117   return (*it).second;
1118 }
1119
1120 /*!
1121  * Returns ids of the families having given names.
1122  *  \param [in] fams - a sequence of the names of families of interest.
1123  *  \return std::vector<int> - a sequence of the ids of families of interest.
1124  *  \throw If \a fams contains a name of an inexistent family.
1125  */
1126 std::vector<int> MEDFileMesh::getFamiliesIds(const std::vector<std::string>& fams) const throw(INTERP_KERNEL::Exception)
1127 {
1128   std::vector<int> ret(fams.size());
1129   int i=0;
1130   for(std::vector<std::string>::const_iterator it=fams.begin();it!=fams.end();it++,i++)
1131     {
1132       std::map<std::string, int>::const_iterator it2=_families.find(*it);
1133       if(it2==_families.end())
1134         {
1135           std::vector<std::string> fams2=getFamiliesNames();
1136           std::ostringstream oss; oss << "No such familyname \"" << *it << "\" in input list !\nAvailable families are :";
1137           std::copy(fams2.begin(),fams2.end(),std::ostream_iterator<std::string>(oss," "));
1138           throw INTERP_KERNEL::Exception(oss.str().c_str());
1139         }
1140       ret[i]=(*it2).second;
1141     }
1142   return ret;
1143 }
1144
1145 /*!
1146  * Returns a maximal abs(id) of families in \a this mesh.
1147  *  \return int - the maximal norm of family id.
1148  *  \throw If there are no families in \a this mesh.
1149  */
1150 int MEDFileMesh::getMaxAbsFamilyId() const throw(INTERP_KERNEL::Exception)
1151 {
1152   if(_families.empty())
1153     throw INTERP_KERNEL::Exception("MEDFileMesh::getMaxFamilyId : no families set !");
1154   int ret=-std::numeric_limits<int>::max();
1155   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
1156     {
1157       ret=std::max(std::abs((*it).second),ret);
1158     }
1159   return ret;
1160 }
1161
1162 /*!
1163  * Returns a maximal id of families in \a this mesh.
1164  *  \return int - the maximal family id.
1165  *  \throw If there are no families in \a this mesh.
1166  */
1167 int MEDFileMesh::getMaxFamilyId() const throw(INTERP_KERNEL::Exception)
1168 {
1169   if(_families.empty())
1170     throw INTERP_KERNEL::Exception("MEDFileMesh::getMaxFamilyId : no families set !");
1171   int ret=-std::numeric_limits<int>::max();
1172   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
1173     {
1174       ret=std::max((*it).second,ret);
1175     }
1176   return ret;
1177 }
1178
1179 /*!
1180  * Returns a minimal id of families in \a this mesh.
1181  *  \return int - the minimal family id.
1182  *  \throw If there are no families in \a this mesh.
1183  */
1184 int MEDFileMesh::getMinFamilyId() const throw(INTERP_KERNEL::Exception)
1185 {
1186   if(_families.empty())
1187     throw INTERP_KERNEL::Exception("MEDFileMesh::getMinFamilyId : no families set !");
1188   int ret=std::numeric_limits<int>::max();
1189   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
1190     {
1191       ret=std::min((*it).second,ret);
1192     }
1193   return ret;
1194 }
1195
1196 /*!
1197  * Returns a maximal id of families in \a this mesh. Not only named families are
1198  * considered but all family fields as well.
1199  *  \return int - the maximal family id.
1200  */
1201 int MEDFileMesh::getTheMaxAbsFamilyId() const throw(INTERP_KERNEL::Exception)
1202 {
1203   int m1=-std::numeric_limits<int>::max();
1204   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
1205     m1=std::max(std::abs((*it).second),m1);
1206   int m2=getMaxAbsFamilyIdInArrays();
1207   return std::max(m1,m2);
1208 }
1209
1210 /*!
1211  * Returns a maximal id of families in \a this mesh. Not only named families are
1212  * considered but all family fields as well.
1213  *  \return int - the maximal family id.
1214  */
1215 int MEDFileMesh::getTheMaxFamilyId() const throw(INTERP_KERNEL::Exception)
1216 {
1217   int m1=-std::numeric_limits<int>::max();
1218   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
1219     m1=std::max((*it).second,m1);
1220   int m2=getMaxFamilyIdInArrays();
1221   return std::max(m1,m2);
1222 }
1223
1224 /*!
1225  * Returns a minimal id of families in \a this mesh. Not only named families are
1226  * considered but all family fields as well.
1227  *  \return int - the minimal family id.
1228  */
1229 int MEDFileMesh::getTheMinFamilyId() const throw(INTERP_KERNEL::Exception)
1230 {
1231   int m1=std::numeric_limits<int>::max();
1232   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
1233     m1=std::min((*it).second,m1);
1234   int m2=getMinFamilyIdInArrays();
1235   return std::min(m1,m2);
1236 }
1237
1238 /*!
1239  * This method only considers the maps. The contain of family array is ignored here.
1240  * 
1241  * \sa MEDFileMesh::computeAllFamilyIdsInUse
1242  */
1243 DataArrayInt *MEDFileMesh::getAllFamiliesIdsReferenced() const throw(INTERP_KERNEL::Exception)
1244 {
1245   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
1246   std::set<int> v;
1247   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
1248     v.insert((*it).second);
1249   ret->alloc((int)v.size(),1);
1250   std::copy(v.begin(),v.end(),ret->getPointer());
1251   return ret.retn();
1252 }
1253
1254 /*!
1255  * This method does not consider map of family name, family id. Only family field array on different levels is considered.
1256  * 
1257  * \sa MEDFileMesh::getAllFamiliesIdsReferenced
1258  */
1259 DataArrayInt *MEDFileMesh::computeAllFamilyIdsInUse() const throw(INTERP_KERNEL::Exception)
1260 {
1261   std::vector<int> famLevs=getFamArrNonEmptyLevelsExt();
1262   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret;
1263   for(std::vector<int>::const_iterator it=famLevs.begin();it!=famLevs.end();it++)
1264     {
1265       const DataArrayInt *arr=getFamilyFieldAtLevel(*it);//arr not null due to spec of getFamArrNonEmptyLevelsExt
1266       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dv=arr->getDifferentValues();
1267       if((DataArrayInt *) ret)
1268         ret=dv->buildUnion(ret);
1269       else
1270         ret=dv;
1271     }
1272   return ret.retn();
1273 }
1274
1275 /*!
1276  * true is returned if no modification has been needed. false if family
1277  * renumbering has been needed.       
1278  */
1279 bool MEDFileMesh::ensureDifferentFamIdsPerLevel() throw(INTERP_KERNEL::Exception)
1280 {
1281   std::vector<int> levs=getNonEmptyLevelsExt();
1282   std::set<int> allFamIds;
1283   int maxId=getMaxFamilyId()+1;
1284   std::map<int,std::vector<int> > famIdsToRenum;
1285   for(std::vector<int>::const_iterator it=levs.begin();it!=levs.end();it++)
1286     {
1287       const DataArrayInt *fam=getFamilyFieldAtLevel(*it);
1288       if(fam)
1289         {
1290           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp=fam->getDifferentValues();
1291           std::set<int> r2;
1292           std::set_intersection(tmp->begin(),tmp->end(),allFamIds.begin(),allFamIds.end(),std::inserter(r2,r2.end()));
1293           if(!r2.empty())
1294             famIdsToRenum[*it].insert(famIdsToRenum[*it].end(),r2.begin(),r2.end());
1295           std::set<int> r3;
1296           std::set_union(tmp->begin(),tmp->end(),allFamIds.begin(),allFamIds.end(),std::inserter(r3,r3.end()));
1297         }
1298     }
1299   if(famIdsToRenum.empty())
1300     return true;
1301   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> allIds=getAllFamiliesIdsReferenced();
1302   for(std::map<int,std::vector<int> >::const_iterator it2=famIdsToRenum.begin();it2!=famIdsToRenum.end();it2++)
1303     {
1304       DataArrayInt *fam=const_cast<DataArrayInt *>(getFamilyFieldAtLevel((*it2).first));
1305       int *famIdsToChange=fam->getPointer();
1306       std::map<int,int> ren;
1307       for(std::vector<int>::const_iterator it3=(*it2).second.begin();it3!=(*it2).second.end();it3++,maxId++)
1308         {
1309           if(allIds->presenceOfValue(*it3))
1310             {
1311               std::string famName=getFamilyNameGivenId(*it3);
1312               std::vector<std::string> grps=getGroupsOnFamily(famName.c_str());
1313               ren[*it3]=maxId;
1314               bool dummy;
1315               std::string newFam=findOrCreateAndGiveFamilyWithId(maxId,dummy);
1316               for(std::vector<std::string>::const_iterator it4=grps.begin();it4!=grps.end();it4++)
1317                 addFamilyOnGrp((*it4).c_str(),newFam.c_str());
1318             }
1319         }
1320       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids=fam->getIdsEqualList(&(*it2).second[0],&(*it2).second[0]+(*it2).second.size());
1321       for(const int *id=ids->begin();id!=ids->end();id++)
1322         famIdsToChange[*id]=ren[famIdsToChange[*id]];
1323     }
1324   return false;
1325 }
1326
1327 /*!
1328  * This method normalizes fam id with the policy explained underneath. This policy is close to those implemented in SMESH.
1329  * Level #0 famids > 0, Level #-1 famids < 0, Level #-2 famids=0, Level #1 famids=0
1330  * This policy is those used by SMESH and Trio and that is the opposite of those in MED file.
1331  * This method will throw an exception if a same family id is detected in different level.
1332  * \warning This policy is the opposite of those in MED file documentation ...
1333  */
1334 void MEDFileMesh::normalizeFamIdsTrio() throw(INTERP_KERNEL::Exception)
1335 {
1336   ensureDifferentFamIdsPerLevel();
1337   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> allIds=getAllFamiliesIdsReferenced();
1338   std::vector<int> levs=getNonEmptyLevelsExt();
1339   std::set<int> levsS(levs.begin(),levs.end());
1340   std::set<std::string> famsFetched;
1341   std::map<std::string,int> families;
1342   if(std::find(levs.begin(),levs.end(),0)!=levs.end())
1343     {
1344       levsS.erase(0);
1345       const DataArrayInt *fam=getFamilyFieldAtLevel(0);
1346       if(fam)
1347         {
1348           int refId=1;
1349           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp=fam->getDifferentValues();
1350           std::map<int,int> ren;
1351           for(const int *it=tmp->begin();it!=tmp->end();it++,refId++)
1352             ren[*it]=refId;
1353           int nbOfTuples=fam->getNumberOfTuples();
1354           int *start=const_cast<DataArrayInt *>(fam)->getPointer();
1355           for(int *w=start;w!=start+nbOfTuples;w++)
1356             *w=ren[*w];
1357           for(const int *it=tmp->begin();it!=tmp->end();it++)
1358             {
1359               if(allIds->presenceOfValue(*it))
1360                 {
1361                   std::string famName=getFamilyNameGivenId(*it);
1362                   families[famName]=ren[*it];
1363                   famsFetched.insert(famName);
1364                 }
1365             }
1366         }
1367     }
1368   if(std::find(levs.begin(),levs.end(),-1)!=levs.end())
1369     {
1370       levsS.erase(-1);
1371       const DataArrayInt *fam=getFamilyFieldAtLevel(-1);
1372       if(fam)
1373         {
1374           int refId=-1;
1375           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp=fam->getDifferentValues();
1376           std::map<int,int> ren;
1377           for(const int *it=tmp->begin();it!=tmp->end();it++,refId--)
1378             ren[*it]=refId;
1379           int nbOfTuples=fam->getNumberOfTuples();
1380           int *start=const_cast<DataArrayInt *>(fam)->getPointer();
1381           for(int *w=start;w!=start+nbOfTuples;w++)
1382             *w=ren[*w];
1383           for(const int *it=tmp->begin();it!=tmp->end();it++)
1384             {
1385               if(allIds->presenceOfValue(*it))
1386                 {
1387                   std::string famName=getFamilyNameGivenId(*it);
1388                   families[famName]=ren[*it];
1389                   famsFetched.insert(famName);
1390                 }
1391             }
1392         }
1393     }
1394   for(std::set<int>::const_iterator it2=levsS.begin();it2!=levsS.end();it2++)
1395     {
1396       DataArrayInt *fam=const_cast<DataArrayInt*>(getFamilyFieldAtLevel(*it2));
1397       if(fam)
1398         {
1399           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp=fam->getDifferentValues();
1400           fam->fillWithZero();
1401           for(const int *it3=tmp->begin();it3!=tmp->end();it3++)
1402             if(allIds->presenceOfValue(*it3))
1403               {
1404                 std::string famName=getFamilyNameGivenId(*it3);
1405                 families[famName]=0;
1406                 famsFetched.insert(famName);
1407               }
1408         }
1409     }
1410   //
1411   std::vector<std::string> allFams=getFamiliesNames();
1412   std::set<std::string> allFamsS(allFams.begin(),allFams.end());
1413   std::set<std::string> unFetchedIds;
1414   std::set_difference(allFamsS.begin(),allFamsS.end(),famsFetched.begin(),famsFetched.end(),std::inserter(unFetchedIds,unFetchedIds.end()));
1415   for(std::set<std::string>::const_iterator it4=unFetchedIds.begin();it4!=unFetchedIds.end();it4++)
1416     families[*it4]=_families[*it4];
1417   _families=families;
1418 }
1419
1420 /*!
1421  * This method normalizes fam id with the following policy.
1422  * Level #0 famids < 0, Level #-1 famids < 0 and for Level #1 famids >= 0
1423  * This policy is those defined in the MED file format but is the opposite of those implemented in SMESH and Trio.
1424  * This method will throw an exception if a same family id is detected in different level.
1425  */
1426 void MEDFileMesh::normalizeFamIdsMEDFile() throw(INTERP_KERNEL::Exception)
1427 {
1428   ensureDifferentFamIdsPerLevel();
1429   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> allIds=getAllFamiliesIdsReferenced();
1430   std::vector<int> levs=getNonEmptyLevelsExt();
1431   std::set<int> levsS(levs.begin(),levs.end());
1432   std::set<std::string> famsFetched;
1433   std::map<std::string,int> families;
1434   int refId=1;
1435   if(std::find(levs.begin(),levs.end(),1)!=levs.end())
1436     {
1437       levsS.erase(1);
1438       const DataArrayInt *fam=getFamilyFieldAtLevel(1);
1439       if(fam)
1440         {
1441           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp=fam->getDifferentValues();
1442           std::map<int,int> ren;
1443           for(const int *it=tmp->begin();it!=tmp->end();it++,refId++)
1444             ren[*it]=refId;
1445           int nbOfTuples=fam->getNumberOfTuples();
1446           int *start=const_cast<DataArrayInt *>(fam)->getPointer();
1447           for(int *w=start;w!=start+nbOfTuples;w++)
1448             *w=ren[*w];
1449           for(const int *it=tmp->begin();it!=tmp->end();it++)
1450             {
1451               if(allIds->presenceOfValue(*it))
1452                 {
1453                   std::string famName=getFamilyNameGivenId(*it);
1454                   families[famName]=ren[*it];
1455                   famsFetched.insert(famName);
1456                 }
1457             }
1458         }
1459     }
1460   refId=-1;
1461   for(std::set<int>::const_reverse_iterator it2=levsS.rbegin();it2!=levsS.rend();it2++)
1462     {
1463       const DataArrayInt *fam=getFamilyFieldAtLevel(*it2);
1464       if(fam)
1465         {
1466           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp=fam->getDifferentValues();
1467           std::map<int,int> ren;
1468           for(const int *it=tmp->begin();it!=tmp->end();it++,refId--)
1469             ren[*it]=refId;
1470           int nbOfTuples=fam->getNumberOfTuples();
1471           int *start=const_cast<DataArrayInt *>(fam)->getPointer();
1472           for(int *w=start;w!=start+nbOfTuples;w++)
1473             *w=ren[*w];
1474           for(const int *it=tmp->begin();it!=tmp->end();it++)
1475             {
1476               if(allIds->presenceOfValue(*it))
1477                 {
1478                   std::string famName=getFamilyNameGivenId(*it);
1479                   families[famName]=ren[*it];
1480                   famsFetched.insert(famName);
1481                 }
1482             }
1483         }
1484     }
1485   //
1486   std::vector<std::string> allFams=getFamiliesNames();
1487   std::set<std::string> allFamsS(allFams.begin(),allFams.end());
1488   std::set<std::string> unFetchedIds;
1489   std::set_difference(allFamsS.begin(),allFamsS.end(),famsFetched.begin(),famsFetched.end(),std::inserter(unFetchedIds,unFetchedIds.end()));
1490   for(std::set<std::string>::const_iterator it4=unFetchedIds.begin();it4!=unFetchedIds.end();it4++)
1491     families[*it4]=_families[*it4];
1492   _families=families;
1493 }
1494
1495 /*!
1496  * Returns a name of the family by its id. If there are several families having the given
1497  * id, the name first in lexical order is returned.
1498  *  \param [in] id - the id of the family whose name is required.
1499  *  \return std::string - the name of the found family.
1500  *  \throw If no family with the given \a id exists.
1501  */
1502 std::string MEDFileMesh::getFamilyNameGivenId(int id) const throw(INTERP_KERNEL::Exception)
1503 {
1504   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
1505     if((*it).second==id)
1506       return (*it).first;
1507   std::ostringstream oss; oss << "MEDFileUMesh::getFamilyNameGivenId : no such family id : " << id;
1508   throw INTERP_KERNEL::Exception(oss.str().c_str());
1509 }
1510
1511 /*!
1512  * Returns a string describing \a this mesh. This description includes the mesh name and
1513  * the mesh description string.
1514  *  \return std::string - the mesh information string.
1515  */
1516 std::string MEDFileMesh::simpleRepr() const
1517 {
1518   std::ostringstream oss;
1519   oss << "(*************************************)\n(* GENERAL INFORMATION ON THE MESH : *)\n(*************************************)\n";
1520   oss << "- Name of the mesh : <<" << getName() << ">>\n";
1521   oss << "- Description associated to the mesh : " << getDescription() << std::endl;
1522   return oss.str();
1523 }
1524
1525 /*!
1526  * Returns ids of mesh entities contained in a given group of a given dimension.
1527  *  \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids
1528  *          are required.
1529  *  \param [in] grp - the name of the group of interest.
1530  *  \param [in] renum - if \c true, the optional numbers of entities, if available, are
1531  *          returned instead of ids. 
1532  *  \return DataArrayInt * - a new instance of DataArrayInt holding either ids or
1533  *          numbers, if available and required, of mesh entities of the group. The caller
1534  *          is to delete this array using decrRef() as it is no more needed. 
1535  *  \throw If the name of a nonexistent group is specified.
1536  *  \throw If the family field is missing for \a meshDimRelToMaxExt.
1537  */
1538 DataArrayInt *MEDFileMesh::getGroupArr(int meshDimRelToMaxExt, const char *grp, bool renum) const throw(INTERP_KERNEL::Exception)
1539 {
1540   std::vector<std::string> tmp(1);
1541   tmp[0]=grp;
1542   DataArrayInt *ret=getGroupsArr(meshDimRelToMaxExt,tmp,renum);
1543   ret->setName(grp);
1544   return ret;
1545 }
1546
1547 /*!
1548  * Returns ids of mesh entities contained in given groups of a given dimension.
1549  *  \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids
1550  *          are required.
1551  *  \param [in] grps - the names of the groups of interest.
1552  *  \param [in] renum - if \c true, the optional numbers of entities, if available, are
1553  *          returned instead of ids.
1554  *  \return DataArrayInt * - a new instance of DataArrayInt holding either ids or
1555  *          numbers, if available and required, of mesh entities of the groups. The caller
1556  *          is to delete this array using decrRef() as it is no more needed. 
1557  *  \throw If the name of a nonexistent group is present in \a grps.
1558  *  \throw If the family field is missing for \a meshDimRelToMaxExt.
1559  */
1560 DataArrayInt *MEDFileMesh::getGroupsArr(int meshDimRelToMaxExt, const std::vector<std::string>& grps, bool renum) const throw(INTERP_KERNEL::Exception)
1561 {
1562   std::vector<std::string> fams2=getFamiliesOnGroups(grps);
1563   return getFamiliesArr(meshDimRelToMaxExt,fams2,renum);
1564 }
1565
1566 /*!
1567  * Returns ids of mesh entities contained in a given family of a given dimension.
1568  *  \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids
1569  *          are required.
1570  *  \param [in] fam - the name of the family of interest.
1571  *  \param [in] renum - if \c true, the optional numbers of entities, if available, are
1572  *          returned instead of ids. 
1573  *  \return DataArrayInt * - a new instance of DataArrayInt holding either ids or
1574  *          numbers, if available and required, of mesh entities of the family. The caller
1575  *          is to delete this array using decrRef() as it is no more needed. 
1576  *  \throw If the family field is missing for \a meshDimRelToMaxExt.
1577  */
1578 DataArrayInt *MEDFileMesh::getFamilyArr(int meshDimRelToMaxExt, const char *fam, bool renum) const throw(INTERP_KERNEL::Exception)
1579 {
1580   std::vector<std::string> tmp(1);
1581   tmp[0]=fam;
1582   DataArrayInt *ret=getFamiliesArr(meshDimRelToMaxExt,tmp,renum);
1583   ret->setName(fam);
1584   return ret;
1585 }
1586
1587 /*!
1588  * Returns ids of nodes contained in a given group.
1589  *  \param [in] grp - the name of the group of interest.
1590  *  \param [in] renum - if \c true, the optional numbers of nodes, if available, are
1591  *          returned instead of ids. 
1592  *  \return DataArrayInt * - a new instance of DataArrayInt holding either ids or
1593  *          numbers, if available and required, of nodes of the group. The caller
1594  *          is to delete this array using decrRef() as it is no more needed. 
1595  *  \throw If the name of a nonexistent group is specified.
1596  *  \throw If the family field is missing for nodes.
1597  */
1598 DataArrayInt *MEDFileMesh::getNodeGroupArr(const char *grp, bool renum) const throw(INTERP_KERNEL::Exception)
1599 {
1600   std::vector<std::string> tmp(1);
1601   tmp[0]=grp;
1602   DataArrayInt *ret=getNodeGroupsArr(tmp,renum);
1603   ret->setName(grp);
1604   return ret;
1605 }
1606
1607 /*!
1608  * Returns ids of nodes contained in given groups.
1609  *  \param [in] grps - the names of the groups of interest.
1610  *  \param [in] renum - if \c true, the optional numbers of nodes, if available, are
1611  *          returned instead of ids. 
1612  *  \return DataArrayInt * - a new instance of DataArrayInt holding either ids or
1613  *          numbers, if available and required, of nodes of the groups. The caller
1614  *          is to delete this array using decrRef() as it is no more needed. 
1615  *  \throw If the name of a nonexistent group is present in \a grps.
1616  *  \throw If the family field is missing for nodes.
1617  */
1618 DataArrayInt *MEDFileMesh::getNodeGroupsArr(const std::vector<std::string>& grps, bool renum) const throw(INTERP_KERNEL::Exception)
1619 {
1620   return getGroupsArr(1,grps,renum);
1621 }
1622
1623 /*!
1624  * Returns ids of nodes contained in a given group.
1625  *  \param [in] grp - the name of the group of interest.
1626  *  \param [in] renum - if \c true, the optional numbers of nodes, if available, are
1627  *          returned instead of ids. 
1628  *  \return DataArrayInt * - a new instance of DataArrayInt holding either ids or
1629  *          numbers, if available and required, of nodes of the group. The caller
1630  *          is to delete this array using decrRef() as it is no more needed. 
1631  *  \throw If the name of a nonexistent group is specified.
1632  *  \throw If the family field is missing for nodes.
1633  */
1634 DataArrayInt *MEDFileMesh::getNodeFamilyArr(const char *fam, bool renum) const throw(INTERP_KERNEL::Exception)
1635 {
1636   std::vector<std::string> tmp(1);
1637   tmp[0]=fam;
1638   DataArrayInt *ret=getNodeFamiliesArr(tmp,renum);
1639   ret->setName(fam);
1640   return ret;
1641 }
1642
1643 /*!
1644  * Returns ids of nodes contained in given families.
1645  *  \param [in] fams - the names of the families of interest.
1646  *  \param [in] renum - if \c true, the optional numbers of nodes, if available, are
1647  *          returned instead of ids. 
1648  *  \return DataArrayInt * - a new instance of DataArrayInt holding either ids or
1649  *          numbers, if available and required, of nodes of the families. The caller
1650  *          is to delete this array using decrRef() as it is no more needed. 
1651  *  \throw If the family field is missing for nodes.
1652  */
1653 DataArrayInt *MEDFileMesh::getNodeFamiliesArr(const std::vector<std::string>& fams, bool renum) const throw(INTERP_KERNEL::Exception)
1654 {
1655   return getFamiliesArr(1,fams,renum);
1656 }
1657
1658 /*!
1659  * Adds groups of given dimension and creates corresponding families and family fields
1660  * given ids of mesh entities of each group.
1661  *  \param [in] meshDimRelToMaxExt - the relative mesh dimension of given mesh entities.
1662  *  \param [in] grps - a sequence of arrays of ids each describing a group.
1663  *  \param [in] renum - \c true means that \a grps contains not ids but optional numbers
1664  *          of mesh entities.
1665  *  \throw If names of some groups in \a grps are equal.
1666  *  \throw If \a grps includes a group with an empty name.
1667  *  \throw If \a grps includes invalid ids (or numbers if \a renum == \c true ).
1668  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
1669  */
1670 void MEDFileMesh::setGroupsAtLevel(int meshDimRelToMaxExt, const std::vector<const DataArrayInt *>& grps, bool renum) throw(INTERP_KERNEL::Exception)
1671 {
1672   if(grps.empty())
1673     return ;
1674   std::set<std::string> grpsName;
1675   std::vector<std::string> grpsName2(grps.size());
1676   int i=0;
1677
1678   for(std::vector<const DataArrayInt *>::const_iterator it=grps.begin();it!=grps.end();it++,i++)
1679     {
1680       grpsName.insert((*it)->getName());
1681       grpsName2[i]=(*it)->getName();
1682     }
1683   if(grpsName.size()!=grps.size())
1684     throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsAtLevel : groups name must be different each other !");
1685   if(grpsName.find(std::string(""))!=grpsName.end())
1686     throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsAtLevel : groups name must be different empty string !");
1687   int sz=getSizeAtLevel(meshDimRelToMaxExt);
1688   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> fam;
1689   std::vector< std::vector<int> > fidsOfGroups;
1690   if(!renum)
1691     {
1692       fam=DataArrayInt::MakePartition(grps,sz,fidsOfGroups);
1693     }
1694   else
1695     {
1696       std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > grps2(grps.size());
1697       for(unsigned int ii=0;ii<grps.size();ii++)
1698         {
1699           grps2[ii]=MEDFileUMeshSplitL1::Renumber(getRevNumberFieldAtLevel(meshDimRelToMaxExt),grps[ii]);
1700           grps2[ii]->setName(grps[ii]->getName().c_str());
1701         }
1702       std::vector<const DataArrayInt *> grps3(grps2.begin(),grps2.end());
1703       fam=DataArrayInt::MakePartition(grps3,sz,fidsOfGroups);
1704     }
1705   int offset=1;
1706   if(!_families.empty())
1707     offset=getMaxAbsFamilyId()+1;
1708   TranslateFamilyIds(meshDimRelToMaxExt==1?offset:-offset,fam,fidsOfGroups);
1709   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids=fam->getDifferentValues();
1710   appendFamilyEntries(ids,fidsOfGroups,grpsName2);
1711   setFamilyFieldArr(meshDimRelToMaxExt,fam);
1712 }
1713
1714 /*!
1715  * This method append into '_families' attribute the families whose ids are in 'famIds'. Warning 'famIds' are expected to be ids
1716  * not in '_families'. Groups information are given in parameters in order to give to families representative names.
1717  * For the moment, the two last input parameters are not taken into account.
1718  */
1719 void MEDFileMesh::appendFamilyEntries(const DataArrayInt *famIds, const std::vector< std::vector<int> >& fidsOfGrps, const std::vector<std::string>& grpNames)
1720 {
1721   std::map<int,std::string> famInv;
1722   for(const int *it=famIds->begin();it!=famIds->end();it++)
1723     {
1724       std::ostringstream oss;
1725       oss << "Family_" << (*it);
1726       _families[oss.str()]=(*it);
1727       famInv[*it]=oss.str();
1728     }
1729   int i=0;
1730   for(std::vector< std::vector<int> >::const_iterator it1=fidsOfGrps.begin();it1!=fidsOfGrps.end();it1++,i++)
1731     {
1732       for(std::vector<int>::const_iterator it2=(*it1).begin();it2!=(*it1).end();it2++)
1733         {
1734           _groups[grpNames[i]].push_back(famInv[*it2]);
1735         }
1736     }
1737 }
1738
1739 void MEDFileMesh::TranslateFamilyIds(int offset, DataArrayInt *famArr, std::vector< std::vector<int> >& famIdsPerGrp)
1740 {
1741   famArr->applyLin(offset>0?1:-1,offset,0);
1742   for(std::vector< std::vector<int> >::iterator it1=famIdsPerGrp.begin();it1!=famIdsPerGrp.end();it1++)
1743     {
1744       if(offset<0)
1745         std::transform((*it1).begin(),(*it1).end(),(*it1).begin(),std::negate<int>());
1746       std::transform((*it1).begin(),(*it1).end(),(*it1).begin(),std::bind2nd(std::plus<int>(),offset));
1747     }
1748 }
1749
1750 /*!
1751  * Warning no check is done on 'nameTry' in parameter. It should be non empty.
1752  * This method returns a name close to 'nameTry' so that it is not already into 'namesToAvoid'.
1753  * If this method fails to find such a name it will throw an exception.
1754  */
1755 std::string MEDFileMesh::CreateNameNotIn(const std::string& nameTry, const std::vector<std::string>& namesToAvoid) throw(INTERP_KERNEL::Exception)
1756 {
1757   //attempt #0
1758   if(std::find(namesToAvoid.begin(),namesToAvoid.end(),nameTry)==namesToAvoid.end())
1759     return nameTry;
1760   //attempt #1
1761   std::size_t len=nameTry.length();
1762   for(std::size_t ii=1;ii<len;ii++)
1763     {
1764       std::string tmp=nameTry.substr(ii,len-ii);
1765       if(std::find(namesToAvoid.begin(),namesToAvoid.end(),tmp)==namesToAvoid.end())
1766         return tmp;
1767     }
1768   //attempt #2
1769   if(len>=1)
1770     {
1771       for(std::size_t i=1;i<30;i++)
1772         {
1773           std::string tmp1(nameTry.at(0),i);
1774           tmp1+=nameTry;
1775           if(std::find(namesToAvoid.begin(),namesToAvoid.end(),tmp1)==namesToAvoid.end())
1776             return tmp1;
1777         }
1778     }
1779   //attempt #3
1780   std::string tmp2;
1781   for(std::vector<std::string>::const_iterator it2=namesToAvoid.begin();it2!=namesToAvoid.end();it2++)
1782     tmp2+=(*it2);
1783   if(std::find(namesToAvoid.begin(),namesToAvoid.end(),tmp2)==namesToAvoid.end())
1784     return tmp2;
1785   throw INTERP_KERNEL::Exception("MEDFileMesh::CreateNameNotIn : impossible to find a not already used name !");
1786 }
1787
1788 int MEDFileMesh::PutInThirdComponentOfCodeOffset(std::vector<int>& code, int strt) throw(INTERP_KERNEL::Exception)
1789 {
1790   std::size_t nbOfChunks=code.size()/3;
1791   if(code.size()%3!=0)
1792     throw INTERP_KERNEL::Exception("MEDFileMesh::PutInThirdComponentOfCodeOffset : code has invalid size : should be of size 3*x !");
1793   int ret=strt;
1794   for(std::size_t i=0;i<nbOfChunks;i++)
1795     {
1796       code[3*i+2]=ret;
1797       ret+=code[3*i+1];
1798     }
1799   return ret;
1800 }
1801
1802 /*!
1803  * This method should be called by any set* method of subclasses to deal automatically with _name attribute.
1804  * If _name attribute is empty the name of 'm' if taken as _name attribute.
1805  * If _name is not empty and that 'm' has the same name nothing is done.
1806  * If _name is not emplt and that 'm' has \b NOT the same name an exception is thrown.
1807  */
1808 void MEDFileMesh::dealWithTinyInfo(const MEDCouplingMesh *m) throw(INTERP_KERNEL::Exception)
1809 {
1810   if(!m)
1811     throw INTERP_KERNEL::Exception("MEDFileMesh::dealWithTinyInfo : input mesh in NULL !");
1812   if(_name.empty())
1813     _name=m->getName();
1814   else
1815     {
1816       std::string name(m->getName());
1817       if(!name.empty())
1818         {
1819           if(_name!=name)
1820             {
1821               std::ostringstream oss; oss << "MEDFileMesh::dealWithTinyInfo : name of current MEDfile mesh is '" << _name << "' whereas name of input mesh is : '";
1822               oss << name << "' ! Names must match !";
1823               throw INTERP_KERNEL::Exception(oss.str().c_str());
1824             }
1825         }
1826     }
1827   if(_desc_name.empty())
1828     _desc_name=m->getDescription();
1829   else
1830     {
1831       std::string name(m->getDescription());
1832       if(!name.empty())
1833         {
1834           if(_desc_name!=name)
1835             {
1836               std::ostringstream oss; oss << "MEDFileMesh::dealWithTinyInfo : description of current MEDfile mesh is '" << _desc_name << "' whereas name of input mesh is : '";
1837               oss << name << "' ! Names must match !";
1838               throw INTERP_KERNEL::Exception(oss.str().c_str());
1839             }
1840         }
1841     }
1842 }
1843
1844 void MEDFileMesh::getFamilyRepr(std::ostream& oss) const
1845 {
1846   oss << "(**************************)\n(* FAMILIES OF THE MESH : *)\n(**************************)\n";
1847   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
1848     {
1849       oss << "- Family with name \"" << (*it).first << "\" with number " << (*it).second << std::endl;
1850       oss << "  - Groups lying on this family : ";
1851       std::vector<std::string> grps=getGroupsOnFamily((*it).first.c_str());
1852       std::copy(grps.begin(),grps.end(),std::ostream_iterator<std::string>(oss," "));
1853       oss << std::endl << std::endl;
1854     }
1855 }
1856
1857 /*!
1858  * Returns a new MEDFileUMesh holding the mesh data that has been read from a given MED
1859  * file. The mesh to load is specified by its name and numbers of a time step and an
1860  * iteration.
1861  *  \param [in] fileName - the name of MED file to read.
1862  *  \param [in] mName - the name of the mesh to read.
1863  *  \param [in] dt - the number of a time step.
1864  *  \param [in] it - the number of an iteration.
1865  *  \return MEDFileUMesh * - a new instance of MEDFileUMesh. The caller is to delete this
1866  *          mesh using decrRef() as it is no more needed. 
1867  *  \throw If the file is not readable.
1868  *  \throw If there is no mesh with given attributes in the file.
1869  *  \throw If the mesh in the file is not an unstructured one.
1870  */
1871 MEDFileUMesh *MEDFileUMesh::New(const char *fileName, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
1872 {
1873   MEDFileUtilities::CheckFileForRead(fileName);
1874   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,MED_ACC_RDONLY);
1875   return new MEDFileUMesh(fid,mName,dt,it,mrs);
1876 }
1877
1878 /*!
1879  * Returns a new MEDFileUMesh holding the mesh data that has been read from a given MED
1880  * file. The first mesh in the file is loaded.
1881  *  \param [in] fileName - the name of MED file to read.
1882  *  \return MEDFileUMesh * - a new instance of MEDFileUMesh. The caller is to delete this
1883  *          mesh using decrRef() as it is no more needed. 
1884  *  \throw If the file is not readable.
1885  *  \throw If there is no meshes in the file.
1886  *  \throw If the mesh in the file is not an unstructured one.
1887  */
1888 MEDFileUMesh *MEDFileUMesh::New(const char *fileName, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
1889 {
1890   std::vector<std::string> ms=MEDLoader::GetMeshNames(fileName);
1891   if(ms.empty())
1892     {
1893       std::ostringstream oss; oss << "MEDFileUMesh::New : no meshes in file \"" << fileName << "\" !";
1894       throw INTERP_KERNEL::Exception(oss.str().c_str());
1895     }
1896   MEDFileUtilities::CheckFileForRead(fileName);
1897   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,MED_ACC_RDONLY);
1898   int dt,it;
1899   ParaMEDMEM::MEDCouplingMeshType meshType;
1900   std::string dummy2;
1901   MEDFileMeshL2::GetMeshIdFromName(fid,ms.front().c_str(),meshType,dt,it,dummy2);
1902   return new MEDFileUMesh(fid,ms.front().c_str(),dt,it,mrs);
1903 }
1904
1905 /*!
1906  * Returns an empty instance of MEDFileUMesh.
1907  *  \return MEDFileUMesh * - a new instance of MEDFileUMesh. The caller is to delete this
1908  *          mesh using decrRef() as it is no more needed. 
1909  */
1910 MEDFileUMesh *MEDFileUMesh::New()
1911 {
1912   return new MEDFileUMesh;
1913 }
1914
1915 std::size_t MEDFileUMesh::getHeapMemorySize() const
1916 {
1917   std::size_t ret=MEDFileMesh::getHeapMemorySize();
1918   if((const DataArrayDouble*)_coords)
1919     ret+=_coords->getHeapMemorySize();
1920   if((const DataArrayInt *)_fam_coords)
1921     ret+=_fam_coords->getHeapMemorySize();
1922   if((const DataArrayInt *)_num_coords)
1923     ret+=_num_coords->getHeapMemorySize();
1924   if((const DataArrayInt *)_rev_num_coords)
1925     ret+=_rev_num_coords->getHeapMemorySize();
1926   if((const DataArrayAsciiChar *)_name_coords)
1927     ret+=_name_coords->getHeapMemorySize();
1928   ret+=_ms.capacity()*(sizeof(MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1>));
1929   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
1930     if((const MEDFileUMeshSplitL1*) *it)
1931       ret+=(*it)->getHeapMemorySize();
1932   return ret;
1933 }
1934
1935 MEDFileMesh *MEDFileUMesh::shallowCpy() const throw(INTERP_KERNEL::Exception)
1936 {
1937   MEDCouplingAutoRefCountObjectPtr<MEDFileUMesh> ret=new MEDFileUMesh(*this);
1938   return ret.retn();
1939 }
1940
1941 MEDFileMesh *MEDFileUMesh::createNewEmpty() const throw(INTERP_KERNEL::Exception)
1942 {
1943   return new MEDFileUMesh;
1944 }
1945
1946 MEDFileMesh *MEDFileUMesh::deepCpy() const throw(INTERP_KERNEL::Exception)
1947 {
1948   MEDCouplingAutoRefCountObjectPtr<MEDFileUMesh> ret=new MEDFileUMesh(*this);
1949   if((const DataArrayDouble*)_coords)
1950     ret->_coords=_coords->deepCpy();
1951   if((const DataArrayInt*)_fam_coords)
1952     ret->_fam_coords=_fam_coords->deepCpy();
1953   if((const DataArrayInt*)_num_coords)
1954     ret->_num_coords=_num_coords->deepCpy();
1955   if((const DataArrayInt*)_rev_num_coords)
1956     ret->_rev_num_coords=_rev_num_coords->deepCpy();
1957   if((const DataArrayAsciiChar*)_name_coords)
1958     ret->_name_coords=_name_coords->deepCpy();
1959   std::size_t i=0;
1960   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,i++)
1961     {
1962       if((const MEDFileUMeshSplitL1 *)(*it))
1963         ret->_ms[i]=(*it)->deepCpy();
1964     }
1965   return ret.retn();
1966 }
1967
1968 /*!
1969  * Checks if \a this and another mesh are equal.
1970  *  \param [in] other - the mesh to compare with.
1971  *  \param [in] eps - a precision used to compare real values.
1972  *  \param [in,out] what - the string returning description of unequal data.
1973  *  \return bool - \c true if the meshes are equal, \c false, else.
1974  */
1975 bool MEDFileUMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const
1976 {
1977   if(!MEDFileMesh::isEqual(other,eps,what))
1978     return false;
1979   const MEDFileUMesh *otherC=dynamic_cast<const MEDFileUMesh *>(other);
1980   if(!otherC)
1981     {
1982       what="Mesh types differ ! This is unstructured and other is NOT !";
1983       return false;
1984     }
1985   clearNonDiscrAttributes();
1986   otherC->clearNonDiscrAttributes();
1987   const DataArrayDouble *coo1=_coords;
1988   const DataArrayDouble *coo2=otherC->_coords;
1989   if((coo1==0 && coo2!=0) || (coo1!=0 && coo2==0))
1990     {
1991       what="Mismatch of coordinates ! One is defined and not other !";
1992       return false;
1993     }
1994   if(coo1)
1995     {
1996       bool ret=coo1->isEqual(*coo2,eps);
1997       if(!ret)
1998         {
1999           what="Coords differ !";
2000           return false;
2001         }
2002     }
2003   const DataArrayInt *famc1=_fam_coords;
2004   const DataArrayInt *famc2=otherC->_fam_coords;
2005   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
2006     {
2007       what="Mismatch of families arr on nodes ! One is defined and not other !";
2008       return false;
2009     }
2010   if(famc1)
2011     {
2012       bool ret=famc1->isEqual(*famc2);
2013       if(!ret)
2014         {
2015           what="Families arr on node differ !";
2016           return false;
2017         }
2018     }
2019   const DataArrayInt *numc1=_num_coords;
2020   const DataArrayInt *numc2=otherC->_num_coords;
2021   if((numc1==0 && numc2!=0) || (numc1!=0 && numc2==0))
2022     {
2023       what="Mismatch of numbering arr on nodes ! One is defined and not other !";
2024       return false;
2025     }
2026   if(numc1)
2027     {
2028       bool ret=numc1->isEqual(*numc2);
2029       if(!ret)
2030         {
2031           what="Numbering arr on node differ !";
2032           return false;
2033         }
2034     }
2035   const DataArrayAsciiChar *namec1=_name_coords;
2036   const DataArrayAsciiChar *namec2=otherC->_name_coords;
2037   if((namec1==0 && namec2!=0) || (namec1!=0 && namec2==0))
2038     {
2039       what="Mismatch of naming arr on nodes ! One is defined and not other !";
2040       return false;
2041     }
2042   if(namec1)
2043     {
2044       bool ret=namec1->isEqual(*namec2);
2045       if(!ret)
2046         {
2047           what="Names arr on node differ !";
2048           return false;
2049         }
2050     }
2051   if(_ms.size()!=otherC->_ms.size())
2052     {
2053       what="Number of levels differs !";
2054       return false;
2055     }
2056   std::size_t sz=_ms.size();
2057   for(std::size_t i=0;i<sz;i++)
2058     {
2059       const MEDFileUMeshSplitL1 *s1=_ms[i];
2060       const MEDFileUMeshSplitL1 *s2=otherC->_ms[i];
2061       if((s1==0 && s2!=0) || (s1!=0 && s2==0))
2062         {
2063           what="Mismatch of presence of sub levels !";
2064           return false;
2065         }
2066       if(s1)
2067         {
2068           bool ret=s1->isEqual(s2,eps,what);
2069           if(!ret)
2070             return false;
2071         }
2072     }
2073   return true;
2074 }
2075
2076 /*!
2077  * Clears redundant attributes of incorporated data arrays.
2078  */
2079 void MEDFileUMesh::clearNonDiscrAttributes() const
2080 {
2081   MEDFileMesh::clearNonDiscrAttributes();
2082   const DataArrayDouble *coo1=_coords;
2083   if(coo1)
2084     (const_cast<DataArrayDouble *>(coo1))->setName("");//This parameter is not discriminant for comparison
2085   const DataArrayInt *famc1=_fam_coords;
2086   if(famc1)
2087     (const_cast<DataArrayInt *>(famc1))->setName("");//This parameter is not discriminant for comparison
2088   const DataArrayInt *numc1=_num_coords;
2089   if(numc1)
2090     (const_cast<DataArrayInt *>(numc1))->setName("");//This parameter is not discriminant for comparison
2091   const DataArrayAsciiChar *namc1=_name_coords;
2092   if(namc1)
2093     (const_cast<DataArrayAsciiChar *>(namc1))->setName("");//This parameter is not discriminant for comparison
2094   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
2095     {
2096       const MEDFileUMeshSplitL1 *tmp=(*it);
2097       if(tmp)
2098         tmp->clearNonDiscrAttributes();
2099     }
2100 }
2101
2102 MEDFileUMesh::MEDFileUMesh()
2103 {
2104 }
2105
2106 MEDFileUMesh::MEDFileUMesh(med_idt fid, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
2107 try
2108   {
2109     loadUMeshFromFile(fid,mName,dt,it,mrs);
2110   }
2111 catch(INTERP_KERNEL::Exception& e)
2112   {
2113     throw e;
2114   }
2115
2116 void MEDFileUMesh::loadUMeshFromFile(med_idt fid, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
2117 {
2118   MEDFileUMeshL2 loaderl2;
2119   ParaMEDMEM::MEDCouplingMeshType meshType;
2120   int dummy0,dummy1;
2121   std::string dummy2;
2122   int mid=MEDFileUMeshL2::GetMeshIdFromName(fid,mName,meshType,dummy0,dummy1,dummy2);
2123   if(meshType!=UNSTRUCTURED)
2124     {
2125       std::ostringstream oss; oss << "Trying to load as unstructured an existing mesh with name '" << mName << "' !";
2126       throw INTERP_KERNEL::Exception(oss.str().c_str());
2127     }
2128   loaderl2.loadAll(fid,mid,mName,dt,it,mrs);
2129   int lev=loaderl2.getNumberOfLevels();
2130   _ms.resize(lev);
2131   for(int i=0;i<lev;i++)
2132     {
2133       if(!loaderl2.emptyLev(i))
2134         _ms[i]=new MEDFileUMeshSplitL1(loaderl2,mName,i);
2135       else
2136         _ms[i]=0;
2137     }
2138   MEDFileMeshL2::ReadFamiliesAndGrps(fid,mName,_families,_groups,mrs);
2139   //
2140   setName(loaderl2.getName());
2141   setDescription(loaderl2.getDescription());
2142   setUnivName(loaderl2.getUnivName());
2143   setIteration(loaderl2.getIteration());
2144   setOrder(loaderl2.getOrder());
2145   setTimeValue(loaderl2.getTime());
2146   setTimeUnit(loaderl2.getTimeUnit());
2147   _coords=loaderl2.getCoords();
2148   if(!mrs || mrs->isNodeFamilyFieldReading())
2149     _fam_coords=loaderl2.getCoordsFamily();
2150   if(!mrs || mrs->isNodeNumFieldReading())
2151     _num_coords=loaderl2.getCoordsNum();
2152   if(!mrs || mrs->isNodeNameFieldReading())
2153     _name_coords=loaderl2.getCoordsName();
2154   computeRevNum();
2155 }
2156
2157 MEDFileUMesh::~MEDFileUMesh()
2158 {
2159 }
2160
2161 void MEDFileUMesh::writeLL(med_idt fid) const throw(INTERP_KERNEL::Exception)
2162 {
2163   const DataArrayDouble *coo=_coords;
2164   INTERP_KERNEL::AutoPtr<char> maa=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE);
2165   INTERP_KERNEL::AutoPtr<char> desc=MEDLoaderBase::buildEmptyString(MED_COMMENT_SIZE);
2166   MEDLoaderBase::safeStrCpy(_name.c_str(),MED_NAME_SIZE,maa,_too_long_str);
2167   MEDLoaderBase::safeStrCpy(_desc_name.c_str(),MED_COMMENT_SIZE,desc,_too_long_str);
2168   int spaceDim=coo?coo->getNumberOfComponents():0;
2169   int mdim=getMeshDimension();
2170   INTERP_KERNEL::AutoPtr<char> comp=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
2171   INTERP_KERNEL::AutoPtr<char> unit=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
2172   for(int i=0;i<spaceDim;i++)
2173     {
2174       std::string info=coo->getInfoOnComponent(i);
2175       std::string c,u;
2176       MEDLoaderBase::splitIntoNameAndUnit(info,c,u);
2177       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
2178       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
2179     }
2180   MEDmeshCr(fid,maa,spaceDim,mdim,MED_UNSTRUCTURED_MESH,desc,"",MED_SORT_DTIT,MED_CARTESIAN,comp,unit);
2181   MEDmeshUniversalNameWr(fid,maa);
2182   MEDFileUMeshL2::WriteCoords(fid,maa,_iteration,_order,_time,_coords,_fam_coords,_num_coords,_name_coords);
2183   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
2184     if((const MEDFileUMeshSplitL1 *)(*it)!=0)
2185       (*it)->write(fid,maa,mdim);
2186   MEDFileUMeshL2::WriteFamiliesAndGrps(fid,maa,_families,_groups,_too_long_str);
2187 }
2188
2189 /*!
2190  * Returns relative dimensions of mesh entities (excluding nodes) present in \a this mesh.
2191  *  \return std::vector<int> - a sequence of the relative dimensions.
2192  */
2193 std::vector<int> MEDFileUMesh::getNonEmptyLevels() const
2194 {
2195   std::vector<int> ret;
2196   int lev=0;
2197   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev--)
2198     if((const MEDFileUMeshSplitL1 *)(*it)!=0)
2199       if(!(*it)->empty())
2200         ret.push_back(lev);
2201   return ret;
2202 }
2203
2204 /*!
2205  * Returns relative dimensions of mesh entities (including nodes) present in \a this mesh.
2206  *  \return std::vector<int> - a sequence of the relative dimensions.
2207  */
2208 std::vector<int> MEDFileUMesh::getNonEmptyLevelsExt() const
2209 {
2210   std::vector<int> ret0=getNonEmptyLevels();
2211   if((const DataArrayDouble *) _coords)
2212     {
2213       std::vector<int> ret(ret0.size()+1);
2214       ret[0]=1;
2215       std::copy(ret0.begin(),ret0.end(),ret.begin()+1);
2216       return ret;
2217     }
2218   return ret0;
2219 }
2220
2221 std::vector<int> MEDFileUMesh::getFamArrNonEmptyLevelsExt() const
2222 {
2223   std::vector<int> ret;
2224   const DataArrayInt *famCoo(_fam_coords);
2225   if(famCoo)
2226     ret.push_back(1);
2227   int lev=0;
2228   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev--)
2229     {
2230       const MEDFileUMeshSplitL1 *cur(*it);
2231       if(cur)
2232         if(cur->getFamilyField())
2233           ret.push_back(lev);
2234     }
2235   return ret;
2236 }
2237
2238 std::vector<int> MEDFileUMesh::getNumArrNonEmptyLevelsExt() const
2239 {
2240   std::vector<int> ret;
2241   const DataArrayInt *numCoo(_num_coords);
2242   if(numCoo)
2243     ret.push_back(1);
2244   int lev=0;
2245   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev--)
2246     {
2247       const MEDFileUMeshSplitL1 *cur(*it);
2248       if(cur)
2249         if(cur->getNumberField())
2250           ret.push_back(lev);
2251     }
2252   return ret;
2253 }
2254
2255 std::vector<int> MEDFileUMesh::getNameArrNonEmptyLevelsExt() const
2256 {
2257   std::vector<int> ret;
2258   const DataArrayAsciiChar *nameCoo(_name_coords);
2259   if(nameCoo)
2260     ret.push_back(1);
2261   int lev=0;
2262   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev--)
2263     {
2264       const MEDFileUMeshSplitL1 *cur(*it);
2265       if(cur)
2266         if(cur->getNameField())
2267           ret.push_back(lev);
2268     }
2269   return ret;
2270 }
2271
2272 /*!
2273  * Returns all relative mesh levels (**excluding nodes**) where a given group is defined.
2274  * To include nodes, call getGrpNonEmptyLevelsExt() method.
2275  *  \param [in] grp - the name of the group of interest.
2276  *  \return std::vector<int> - a sequence of the relative dimensions.
2277  */
2278 std::vector<int> MEDFileUMesh::getGrpNonEmptyLevels(const char *grp) const throw(INTERP_KERNEL::Exception)
2279 {
2280   std::vector<std::string> fams=getFamiliesOnGroup(grp);
2281   return getFamsNonEmptyLevels(fams);
2282 }
2283
2284 /*!
2285  * Returns all relative mesh levels (including nodes) where a given group is defined.
2286  *  \param [in] grp - the name of the group of interest.
2287  *  \return std::vector<int> - a sequence of the relative dimensions.
2288  */
2289 std::vector<int> MEDFileUMesh::getGrpNonEmptyLevelsExt(const char *grp) const throw(INTERP_KERNEL::Exception)
2290 {
2291   std::vector<std::string> fams=getFamiliesOnGroup(grp);
2292   return getFamsNonEmptyLevelsExt(fams);
2293 }
2294
2295 /*!
2296  * Returns all relative mesh levels (**excluding nodes**) where a given family is defined.
2297  * To include nodes, call getFamNonEmptyLevelsExt() method.
2298  *  \param [in] fam - the name of the family of interest.
2299  *  \return std::vector<int> - a sequence of the relative dimensions.
2300  */
2301 std::vector<int> MEDFileUMesh::getFamNonEmptyLevels(const char *fam) const throw(INTERP_KERNEL::Exception)
2302 {
2303   std::vector<std::string> fams(1,std::string(fam));
2304   return getFamsNonEmptyLevels(fams);
2305 }
2306
2307 /*!
2308  * Returns all relative mesh levels (including nodes) where a given family is defined.
2309  *  \param [in] fam - the name of the family of interest.
2310  *  \return std::vector<int> - a sequence of the relative dimensions.
2311  */
2312 std::vector<int> MEDFileUMesh::getFamNonEmptyLevelsExt(const char *fam) const throw(INTERP_KERNEL::Exception)
2313 {
2314   std::vector<std::string> fams(1,std::string(fam));
2315   return getFamsNonEmptyLevelsExt(fams);
2316 }
2317
2318 /*!
2319  * Returns all relative mesh levels (**excluding nodes**) where given groups are defined.
2320  * To include nodes, call getGrpsNonEmptyLevelsExt() method.
2321  *  \param [in] grps - a sequence of names of the groups of interest.
2322  *  \return std::vector<int> - a sequence of the relative dimensions.
2323  */
2324 std::vector<int> MEDFileUMesh::getGrpsNonEmptyLevels(const std::vector<std::string>& grps) const throw(INTERP_KERNEL::Exception)
2325 {
2326   std::vector<std::string> fams=getFamiliesOnGroups(grps);
2327   return getFamsNonEmptyLevels(fams);
2328 }
2329
2330 /*!
2331  * Returns all relative mesh levels (including nodes) where given groups are defined.
2332  *  \param [in] grps - a sequence of names of the groups of interest.
2333  *  \return std::vector<int> - a sequence of the relative dimensions.
2334  */
2335 std::vector<int> MEDFileUMesh::getGrpsNonEmptyLevelsExt(const std::vector<std::string>& grps) const throw(INTERP_KERNEL::Exception)
2336 {
2337   std::vector<std::string> fams=getFamiliesOnGroups(grps);
2338   return getFamsNonEmptyLevelsExt(fams);
2339 }
2340
2341 /*!
2342  * Returns all relative mesh levels (**excluding nodes**) where given families are defined.
2343  * To include nodes, call getFamsNonEmptyLevelsExt() method.
2344  *  \param [in] fams - the name of the family of interest.
2345  *  \return std::vector<int> - a sequence of the relative dimensions.
2346  */
2347 std::vector<int> MEDFileUMesh::getFamsNonEmptyLevels(const std::vector<std::string>& fams) const throw(INTERP_KERNEL::Exception)
2348 {
2349   std::vector<int> ret;
2350   std::vector<int> levs=getNonEmptyLevels();
2351   std::vector<int> famIds=getFamiliesIds(fams);
2352   for(std::vector<int>::const_iterator it=levs.begin();it!=levs.end();it++)
2353     if(_ms[-(*it)]->presenceOfOneFams(famIds))
2354       ret.push_back(*it);
2355   return ret;
2356 }
2357
2358 /*!
2359  * Returns all relative mesh levels (including nodes) where given families are defined.
2360  *  \param [in] fams - the names of the families of interest.
2361  *  \return std::vector<int> - a sequence of the relative dimensions.
2362  */
2363 std::vector<int> MEDFileUMesh::getFamsNonEmptyLevelsExt(const std::vector<std::string>& fams) const throw(INTERP_KERNEL::Exception)
2364 {
2365   std::vector<int> ret0=getFamsNonEmptyLevels(fams);
2366   const DataArrayInt *famCoords=_fam_coords;
2367   if(!famCoords)
2368     return ret0;
2369   std::vector<int> famIds=getFamiliesIds(fams);
2370   if(famCoords->presenceOfValue(famIds))
2371     {
2372       std::vector<int> ret(ret0.size()+1);
2373       ret[0]=1;
2374       std::copy(ret0.begin(),ret0.end(),ret.begin()+1);
2375       return ret;
2376     }
2377   else
2378     return ret0;
2379 }
2380
2381 /*!
2382  * Returns names of groups that partly or fully appear on the level \a meshDimRelToMaxExt.
2383  *  \param [in] meshDimRelToMaxExt - a relative dimension of interest.
2384  *  \return std::vector<std::string> - a sequence of group names at \a meshDimRelToMaxExt
2385  *          level. 
2386  */
2387 std::vector<std::string> MEDFileUMesh::getGroupsOnSpecifiedLev(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
2388 {
2389   std::vector<std::string> ret;
2390   std::vector<std::string> allGrps=getGroupsNames();
2391   for(std::vector<std::string>::const_iterator it=allGrps.begin();it!=allGrps.end();it++)
2392     {
2393       std::vector<int> levs=getGrpNonEmptyLevelsExt((*it).c_str());
2394       if(std::find(levs.begin(),levs.end(),meshDimRelToMaxExt)!=levs.end())
2395         ret.push_back(*it);
2396     }
2397   return ret;
2398 }
2399
2400 int MEDFileUMesh::getMaxAbsFamilyIdInArrays() const throw(INTERP_KERNEL::Exception)
2401 {
2402   int ret=-std::numeric_limits<int>::max(),tmp=-1;
2403   if((const DataArrayInt *)_fam_coords)
2404     {
2405       int val=_fam_coords->getMaxValue(tmp);
2406       ret=std::max(ret,std::abs(val));
2407     }
2408   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
2409     {
2410       if((const MEDFileUMeshSplitL1 *)(*it))
2411         {
2412           const DataArrayInt *da=(*it)->getFamilyField();
2413           if(da)
2414             {
2415               int val=da->getMaxValue(tmp);
2416               ret=std::max(ret,std::abs(val));
2417             }
2418         }
2419     }
2420   return ret;
2421 }
2422
2423 int MEDFileUMesh::getMaxFamilyIdInArrays() const throw(INTERP_KERNEL::Exception)
2424 {
2425   int ret=-std::numeric_limits<int>::max(),tmp=-1;
2426   if((const DataArrayInt *)_fam_coords)
2427     {
2428       int val=_fam_coords->getMaxValue(tmp);
2429       ret=std::max(ret,val);
2430     }
2431   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
2432     {
2433       if((const MEDFileUMeshSplitL1 *)(*it))
2434         {
2435           const DataArrayInt *da=(*it)->getFamilyField();
2436           if(da)
2437             {
2438               int val=da->getMaxValue(tmp);
2439               ret=std::max(ret,val);
2440             }
2441         }
2442     }
2443   return ret;
2444 }
2445
2446 int MEDFileUMesh::getMinFamilyIdInArrays() const throw(INTERP_KERNEL::Exception)
2447 {
2448   int ret=std::numeric_limits<int>::max(),tmp=-1;
2449   if((const DataArrayInt *)_fam_coords)
2450     {
2451       int val=_fam_coords->getMinValue(tmp);
2452       ret=std::min(ret,val);
2453     }
2454   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
2455     {
2456       if((const MEDFileUMeshSplitL1 *)(*it))
2457         {
2458           const DataArrayInt *da=(*it)->getFamilyField();
2459           if(da)
2460             {
2461               int val=da->getMinValue(tmp);
2462               ret=std::min(ret,val);
2463             }
2464         }
2465     }
2466   return ret;
2467 }
2468
2469 /*!
2470  * Returns the dimension on cells in \a this mesh.
2471  *  \return int - the mesh dimension.
2472  *  \throw If there are no cells in this mesh.
2473  */
2474 int MEDFileUMesh::getMeshDimension() const throw(INTERP_KERNEL::Exception)
2475 {
2476   int lev=0;
2477   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev++)
2478     if((const MEDFileUMeshSplitL1 *)(*it)!=0)
2479       return (*it)->getMeshDimension()+lev;
2480   throw INTERP_KERNEL::Exception("MEDFileUMesh::getMeshDimension : impossible to find a mesh dimension !");
2481 }
2482
2483 /*!
2484  * Returns the space dimension of \a this mesh that is equal to number of components in
2485  * the node coordinates array.
2486  *  \return int - the space dimension of \a this mesh.
2487  *  \throw If the node coordinates array is not available.
2488  */
2489 int MEDFileUMesh::getSpaceDimension() const throw(INTERP_KERNEL::Exception)
2490 {
2491   const DataArrayDouble *coo=_coords;
2492   if(!coo)
2493     throw INTERP_KERNEL::Exception(" MEDFileUMesh::getSpaceDimension : no coords set !");
2494   return coo->getNumberOfComponents();
2495 }
2496
2497 /*!
2498  * Returns a string describing \a this mesh.
2499  *  \return std::string - the mesh information string.
2500  */
2501 std::string MEDFileUMesh::simpleRepr() const
2502 {
2503   std::ostringstream oss;
2504   oss << MEDFileMesh::simpleRepr();
2505   const DataArrayDouble *coo=_coords;
2506   oss << "- The dimension of the space is ";
2507   static const char MSG1[]= "*** NO COORDS SET ***";
2508   static const char MSG2[]= "*** NO CONNECTIVITY SET FOR THIS LEVEL***";
2509   if(coo)
2510     oss << _coords->getNumberOfComponents() << std::endl;
2511   else
2512     oss << MSG1 << std::endl;
2513   oss << "- Type of the mesh : UNSTRUCTURED\n";
2514   oss << "- Number of nodes : ";
2515   if(coo)
2516     oss << _coords->getNumberOfTuples() << std::endl;
2517   else
2518     oss << MSG1 << std::endl;
2519   std::size_t nbOfLev=_ms.size();
2520   oss << "- Number of levels allocated : " << nbOfLev << std::endl;
2521   for(std::size_t i=0;i<nbOfLev;i++)
2522     {
2523       const MEDFileUMeshSplitL1 *lev=_ms[i];
2524       oss << "  - Level #" << -((int) i) << " has dimension : ";
2525       if(lev)
2526         {
2527           oss << lev->getMeshDimension() << std::endl;
2528           lev->simpleRepr(oss);
2529         }
2530       else
2531         oss << MSG2 << std::endl;
2532     }
2533   oss << "- Number of families : " << _families.size() << std::endl << std::endl;
2534   if(coo)
2535     {
2536       oss << "(***********************)\n(* NODES OF THE MESH : *)\n(***********************)\n";
2537       oss << "- Names of coordinates :" << std::endl;
2538       std::vector<std::string> vars=coo->getVarsOnComponent();
2539       std::copy(vars.begin(),vars.end(),std::ostream_iterator<std::string>(oss," "));
2540       oss << std::endl << "- Units of coordinates : " << std::endl;
2541       std::vector<std::string> units=coo->getUnitsOnComponent();
2542       std::copy(units.begin(),units.end(),std::ostream_iterator<std::string>(oss," "));
2543     }
2544   oss << std::endl << std::endl;
2545   getFamilyRepr(oss);
2546   return oss.str();
2547 }
2548
2549 /*!
2550  * Returns a full textual description of \a this mesh.
2551  *  \return std::string - the string holding the mesh description.
2552  */
2553 std::string MEDFileUMesh::advancedRepr() const
2554 {
2555   return simpleRepr();
2556 }
2557
2558 /*!
2559  * Returns number of mesh entities of a given relative dimension in \a this mesh.
2560  *  \param [in] meshDimRelToMaxExt - the relative dimension of interest.
2561  *  \return int - the number of entities.
2562  *  \throw If no mesh entities of dimension \a meshDimRelToMaxExt are available in \a this mesh.
2563  */
2564 int MEDFileUMesh::getSizeAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
2565 {
2566   if(meshDimRelToMaxExt==1)
2567     {
2568       if(!((const DataArrayDouble *)_coords))
2569         throw INTERP_KERNEL::Exception("MEDFileUMesh::getSizeAtLevel : no coordinates specified !");
2570       return _coords->getNumberOfTuples();
2571     }
2572   return getMeshAtLevSafe(meshDimRelToMaxExt)->getSize();
2573 }
2574
2575 /*!
2576  * Returns the family field for mesh entities of a given dimension.
2577  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
2578  *  \return const DataArrayInt * - the family field. It is an array of ids of families
2579  *          each mesh entity belongs to. It can be \c NULL.
2580  */
2581 const DataArrayInt *MEDFileUMesh::getFamilyFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
2582 {
2583   if(meshDimRelToMaxExt==1)
2584     return _fam_coords;
2585   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
2586   return l1->getFamilyField();
2587 }
2588
2589 /*!
2590  * Returns the optional numbers of mesh entities of a given dimension.
2591  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
2592  *  \return const DataArrayInt * - the array of the entity numbers.
2593  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
2594  */
2595 const DataArrayInt *MEDFileUMesh::getNumberFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
2596 {
2597   if(meshDimRelToMaxExt==1)
2598     return _num_coords;
2599   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
2600   return l1->getNumberField();
2601 }
2602
2603 const DataArrayAsciiChar *MEDFileUMesh::getNameFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
2604 {
2605   if(meshDimRelToMaxExt==1)
2606     return _name_coords;
2607   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
2608   return l1->getNameField();
2609 }
2610
2611 int MEDFileUMesh::getNumberOfNodes() const throw(INTERP_KERNEL::Exception)
2612 {
2613   const DataArrayDouble *coo=_coords;
2614   if(!coo)
2615     throw INTERP_KERNEL::Exception(" MEDFileUMesh::getNumberOfNodes : no coords set !");
2616   return coo->getNumberOfTuples();
2617 }
2618
2619 /*!
2620  * Returns the optional numbers of mesh entities of a given dimension transformed using
2621  * DataArrayInt::invertArrayN2O2O2N().
2622  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
2623  *  \return const DataArrayInt * - the array of the entity numbers transformed using
2624  *          DataArrayInt::invertArrayN2O2O2N().
2625  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
2626  */
2627 const DataArrayInt *MEDFileUMesh::getRevNumberFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
2628 {
2629   if(meshDimRelToMaxExt==1)
2630     {
2631       if(!((const DataArrayInt *)_num_coords))
2632         throw INTERP_KERNEL::Exception("MEDFileUMesh::getRevNumberFieldAtLevel : no coordinates renum specified !");
2633       return _rev_num_coords;
2634     }
2635   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
2636   return l1->getRevNumberField();
2637 }
2638
2639 /*!
2640  * Returns a pointer to the node coordinates array of \a this mesh \b without
2641  * incrementing its reference counter, thus there is no need to decrRef() it by the caller.
2642  */
2643 DataArrayDouble *MEDFileUMesh::getCoords() const
2644 {
2645   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> tmp(_coords);
2646   if((DataArrayDouble *)tmp)
2647     {
2648       return tmp;
2649     }
2650   return 0;
2651 }
2652
2653 /*!
2654  * Returns a new MEDCouplingUMesh corresponding to mesh entities included in a given
2655  * group of \a this mesh. Only mesh entities of a given dimension are included in the
2656  * new mesh.
2657  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities of interest.
2658  *  \param [in] grp - the name of the group whose mesh entities are included in the
2659  *          new mesh.
2660  *  \param [in] renum - if \c true, cells and nodes of the result mesh are permuted
2661  *          according to the optional numbers of entities, if available.
2662  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
2663  *          delete this mesh using decrRef() as it is no more needed.
2664  *  \throw If the name of a nonexistent group is specified.
2665  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
2666  */
2667 MEDCouplingUMesh *MEDFileUMesh::getGroup(int meshDimRelToMaxExt, const char *grp, bool renum) const throw(INTERP_KERNEL::Exception)
2668 {
2669   synchronizeTinyInfoOnLeaves();
2670   std::vector<std::string> tmp(1);
2671   tmp[0]=grp;
2672   return getGroups(meshDimRelToMaxExt,tmp,renum);
2673 }
2674
2675 /*!
2676  * Returns a new MEDCouplingUMesh corresponding to mesh entities included in given
2677  * groups of \a this mesh. Only mesh entities of a given dimension are included in the
2678  * new mesh.
2679  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities of interest.
2680  *  \param [in] grps - a sequence of group names whose mesh entities are included in the
2681  *          new mesh.
2682  *  \param [in] renum - if \c true, cells and nodes of the result mesh are permuted
2683  *          according to the optional numbers of entities, if available.
2684  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
2685  *          delete this mesh using decrRef() as it is no more needed.
2686  *  \throw If a name of a nonexistent group is present in \a grps.
2687  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
2688  */
2689 MEDCouplingUMesh *MEDFileUMesh::getGroups(int meshDimRelToMaxExt, const std::vector<std::string>& grps, bool renum) const throw(INTERP_KERNEL::Exception)
2690 {
2691   synchronizeTinyInfoOnLeaves();
2692   std::vector<std::string> fams2=getFamiliesOnGroups(grps);
2693   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> zeRet=getFamilies(meshDimRelToMaxExt,fams2,renum);
2694   if(grps.size()==1 && ((MEDCouplingUMesh *)zeRet))
2695     zeRet->setName(grps[0].c_str());
2696   return zeRet.retn();
2697 }
2698
2699 /*!
2700  * Returns a new MEDCouplingUMesh corresponding to mesh entities included in a given
2701  * family of \a this mesh. Only mesh entities of a given dimension are included in the
2702  * new mesh.
2703  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities of interest.
2704  *  \param [in] fam - the name of the family whose mesh entities are included in the
2705  *          new mesh.
2706  *  \param [in] renum - if \c true, cells and nodes of the result mesh are permuted
2707  *          according to the optional numbers of entities, if available.
2708  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
2709  *          delete this mesh using decrRef() as it is no more needed.
2710  *  \throw If a name of a nonexistent family is present in \a grps.
2711  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
2712  */
2713 MEDCouplingUMesh *MEDFileUMesh::getFamily(int meshDimRelToMaxExt, const char *fam, bool renum) const throw(INTERP_KERNEL::Exception)
2714 {
2715   synchronizeTinyInfoOnLeaves();
2716   std::vector<std::string> tmp(1);
2717   tmp[0]=fam;
2718   return getFamilies(meshDimRelToMaxExt,tmp,renum);
2719 }
2720
2721 /*!
2722  * Returns a new MEDCouplingUMesh corresponding to mesh entities included in given
2723  * families of \a this mesh. Only mesh entities of a given dimension are included in the
2724  * new mesh.
2725  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities of interest.
2726  *  \param [in] fams - a sequence of family names whose mesh entities are included in the
2727  *          new mesh.
2728  *  \param [in] renum - if \c true, cells and nodes of the result mesh are permuted
2729  *          according to the optional numbers of entities, if available.
2730  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
2731  *          delete this mesh using decrRef() as it is no more needed.
2732  *  \throw If a name of a nonexistent family is present in \a fams.
2733  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
2734  */
2735 MEDCouplingUMesh *MEDFileUMesh::getFamilies(int meshDimRelToMaxExt, const std::vector<std::string>& fams, bool renum) const throw(INTERP_KERNEL::Exception)
2736 {
2737   synchronizeTinyInfoOnLeaves();
2738   if(meshDimRelToMaxExt==1)
2739     {
2740       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arr=getFamiliesArr(1,fams,renum);
2741       MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
2742       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> c=_coords->selectByTupleId(arr->getConstPointer(),arr->getConstPointer()+arr->getNbOfElems());
2743       ret->setCoords(c);
2744       return ret.retn();
2745     }
2746   std::vector<int> famIds=getFamiliesIds(fams);
2747   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
2748   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> zeRet;
2749   if(!famIds.empty())
2750     zeRet=l1->getFamilyPart(&famIds[0],&famIds[0]+famIds.size(),renum);
2751   else
2752     zeRet=l1->getFamilyPart(0,0,renum);
2753   if(fams.size()==1 && ((MEDCouplingUMesh *)zeRet))
2754     zeRet->setName(fams[0].c_str());
2755   return zeRet.retn();
2756 }
2757
2758 /*!
2759  * Returns ids of mesh entities contained in given families of a given dimension.
2760  *  \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids
2761  *          are required.
2762  *  \param [in] fams - the names of the families of interest.
2763  *  \param [in] renum - if \c true, the optional numbers of entities, if available, are
2764  *          returned instead of ids.
2765  *  \return DataArrayInt * - a new instance of DataArrayInt holding either ids or
2766  *          numbers, if available and required, of mesh entities of the families. The caller
2767  *          is to delete this array using decrRef() as it is no more needed. 
2768  *  \throw If the family field is missing for \a meshDimRelToMaxExt.
2769  */
2770 DataArrayInt *MEDFileUMesh::getFamiliesArr(int meshDimRelToMaxExt, const std::vector<std::string>& fams, bool renum) const throw(INTERP_KERNEL::Exception)
2771 {
2772   std::vector<int> famIds=getFamiliesIds(fams);
2773   if(meshDimRelToMaxExt==1)
2774     {
2775       if((const DataArrayInt *)_fam_coords)
2776         {
2777           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da;
2778           if(!famIds.empty())
2779             da=_fam_coords->getIdsEqualList(&famIds[0],&famIds[0]+famIds.size());
2780           else
2781             da=_fam_coords->getIdsEqualList(0,0);
2782           if(renum)
2783             return MEDFileUMeshSplitL1::Renumber(_num_coords,da);
2784           else
2785             return da.retn();
2786         }
2787       else
2788         throw INTERP_KERNEL::Exception("MEDFileUMesh::getFamiliesArr : no family array specified on nodes !");
2789     }
2790   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
2791   if(!famIds.empty())
2792     return l1->getFamilyPartArr(&famIds[0],&famIds[0]+famIds.size(),renum);
2793   else
2794     return l1->getFamilyPartArr(0,0,renum);
2795 }
2796
2797 /*!
2798  * Returns a MEDCouplingUMesh of a given relative dimension.
2799  * \warning If \a meshDimRelToMaxExt == 1 (which means nodes), the returned mesh **is not
2800  * valid**. This is a feature, because MEDLoader does not create cells that do not exist! 
2801  * To build a valid MEDCouplingUMesh from the returned one in this case,
2802  * call MEDCouplingUMesh::Build0DMeshFromCoords().
2803  *  \param [in] meshDimRelToMax - the relative dimension of interest.
2804  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
2805  *          optional numbers of mesh entities.
2806  *  \return MEDCouplingUMesh * - a pointer to MEDCouplingUMesh that the caller is to
2807  *          delete using decrRef() as it is no more needed. 
2808  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
2809  * \sa getGenMeshAtLevel()
2810  */
2811 MEDCouplingUMesh *MEDFileUMesh::getMeshAtLevel(int meshDimRelToMaxExt, bool renum) const throw(INTERP_KERNEL::Exception)
2812 {
2813   synchronizeTinyInfoOnLeaves();
2814   if(meshDimRelToMaxExt==1)
2815     {
2816       if(!renum)
2817         {
2818           MEDCouplingUMesh *umesh=MEDCouplingUMesh::New();
2819           MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> cc=_coords->deepCpy();
2820           umesh->setCoords(cc);
2821           MEDFileUMeshSplitL1::ClearNonDiscrAttributes(umesh);
2822           umesh->setName(getName());
2823           return umesh;
2824         }
2825     }
2826   const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
2827   return l1->getWholeMesh(renum);
2828 }
2829
2830 /*!
2831  * Returns a MEDCouplingUMesh of a given relative dimension.
2832  * \warning If \a meshDimRelToMaxExt == 1 (which means nodes), the returned mesh **is not
2833  * valid**. This is a feature, because MEDLoader does not create cells that do not exist! 
2834  * To build a valid MEDCouplingUMesh from the returned one in this case,
2835  * call MEDCouplingUMesh::Build0DMeshFromCoords().
2836  *  \param [in] meshDimRelToMax - the relative dimension of interest.
2837  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
2838  *          optional numbers of mesh entities.
2839  *  \return MEDCouplingMesh * - a pointer to MEDCouplingUMesh that the caller is to
2840  *          delete using decrRef() as it is no more needed. 
2841  *  \throw If there are no mesh entities of \a meshDimRelToMax dimension in \a this mesh.
2842  * \sa getMeshAtLevel()
2843  */
2844 MEDCouplingMesh *MEDFileUMesh::getGenMeshAtLevel(int meshDimRelToMax, bool renum) const throw(INTERP_KERNEL::Exception)
2845 {
2846   return getMeshAtLevel(meshDimRelToMax,renum);
2847 }
2848
2849 /*!
2850  * Returns a MEDCouplingUMesh of a relative dimension == 0.
2851  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
2852  *          optional numbers of mesh entities.
2853  *  \return MEDCouplingUMesh * - a pointer to MEDCouplingUMesh that the caller is to
2854  *          delete using decrRef() as it is no more needed. 
2855  *  \throw If there are no mesh entities of the relative dimension == 0 in \a this mesh.
2856  */
2857 MEDCouplingUMesh *MEDFileUMesh::getLevel0Mesh(bool renum) const throw(INTERP_KERNEL::Exception)
2858 {
2859   return getMeshAtLevel(0,renum);
2860 }
2861
2862 /*!
2863  * Returns a MEDCouplingUMesh of a relative dimension == -1.
2864  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
2865  *          optional numbers of mesh entities.
2866  *  \return MEDCouplingUMesh * - a pointer to MEDCouplingUMesh that the caller is to
2867  *          delete using decrRef() as it is no more needed. 
2868  *  \throw If there are no mesh entities of the relative dimension == -1 in \a this mesh.
2869  */
2870 MEDCouplingUMesh *MEDFileUMesh::getLevelM1Mesh(bool renum) const throw(INTERP_KERNEL::Exception)
2871 {
2872   return getMeshAtLevel(-1,renum);
2873 }
2874
2875 /*!
2876  * Returns a MEDCouplingUMesh of a relative dimension == -2.
2877  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
2878  *          optional numbers of mesh entities.
2879  *  \return MEDCouplingUMesh * - a pointer to MEDCouplingUMesh that the caller is to
2880  *          delete using decrRef() as it is no more needed. 
2881  *  \throw If there are no mesh entities of the relative dimension == -2 in \a this mesh.
2882  */
2883 MEDCouplingUMesh *MEDFileUMesh::getLevelM2Mesh(bool renum) const throw(INTERP_KERNEL::Exception)
2884 {
2885   return getMeshAtLevel(-2,renum);
2886 }
2887
2888 /*!
2889  * Returns a MEDCouplingUMesh of a relative dimension == -3.
2890  *  \param [in] renum - if \c true, the returned mesh is permuted according to the
2891  *          optional numbers of mesh entities.
2892  *  \return MEDCouplingUMesh * - a pointer to MEDCouplingUMesh that the caller is to
2893  *          delete using decrRef() as it is no more needed. 
2894  *  \throw If there are no mesh entities of the relative dimension == -3 in \a this mesh.
2895  */
2896 MEDCouplingUMesh *MEDFileUMesh::getLevelM3Mesh(bool renum) const throw(INTERP_KERNEL::Exception)
2897 {
2898   return getMeshAtLevel(-3,renum);
2899 }
2900
2901 const MEDFileUMeshSplitL1 *MEDFileUMesh::getMeshAtLevSafe(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
2902 {
2903   if(meshDimRelToMaxExt==1)
2904     throw INTERP_KERNEL::Exception("Dimension request is invalid : asking for node level (1) !");
2905   if(meshDimRelToMaxExt>1)
2906     throw INTERP_KERNEL::Exception("Dimension request is invalid (>1) !");
2907   int tracucedRk=-meshDimRelToMaxExt;
2908   if(tracucedRk>=(int)_ms.size())
2909     throw INTERP_KERNEL::Exception("Invalid mesh dim relative to max given ! To low !");
2910   if((const MEDFileUMeshSplitL1 *)_ms[tracucedRk]==0)
2911     throw INTERP_KERNEL::Exception("On specified lev (or entity) no cells exists !");
2912   return _ms[tracucedRk];
2913 }
2914
2915 MEDFileUMeshSplitL1 *MEDFileUMesh::getMeshAtLevSafe(int meshDimRelToMaxExt) throw(INTERP_KERNEL::Exception)
2916 {
2917    if(meshDimRelToMaxExt==1)
2918     throw INTERP_KERNEL::Exception("Dimension request is invalid : asking for node level (1) !");
2919   if(meshDimRelToMaxExt>1)
2920     throw INTERP_KERNEL::Exception("Dimension request is invalid (>1) !");
2921   int tracucedRk=-meshDimRelToMaxExt;
2922   if(tracucedRk>=(int)_ms.size())
2923     throw INTERP_KERNEL::Exception("Invalid mesh dim relative to max given ! To low !");
2924   if((const MEDFileUMeshSplitL1 *)_ms[tracucedRk]==0)
2925     throw INTERP_KERNEL::Exception("On specified lev (or entity) no cells exists !");
2926   return _ms[tracucedRk];
2927 }
2928
2929 void MEDFileUMesh::checkMeshDimCoherency(int meshDim, int meshDimRelToMax) const throw(INTERP_KERNEL::Exception)
2930 {
2931   if(-meshDimRelToMax>=(int)_ms.size())
2932     throw INTERP_KERNEL::Exception("MEDFileUMesh::checkMeshDimCoherency : The meshdim of mesh is not managed by 'this' !");
2933   int i=0;
2934   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++,i++)
2935     {
2936       if(((const MEDFileUMeshSplitL1*) (*it))!=0)
2937         {
2938           int ref=(*it)->getMeshDimension();
2939           if(ref+i!=meshDim-meshDimRelToMax)
2940             throw INTERP_KERNEL::Exception("MEDFileUMesh::checkMeshDimCoherency : no coherency between levels !");
2941         }
2942     }
2943 }
2944
2945 /*!
2946  * Sets the node coordinates array of \a this mesh.
2947  *  \param [in] coords - the new node coordinates array.
2948  *  \throw If \a coords == \c NULL.
2949  */
2950
2951 void MEDFileUMesh::setCoords(DataArrayDouble *coords) throw(INTERP_KERNEL::Exception)
2952 {
2953   if(!coords)
2954     throw INTERP_KERNEL::Exception("MEDFileUMesh::setCoords : null pointer in input !");
2955   coords->checkAllocated();
2956   int nbOfTuples=coords->getNumberOfTuples();
2957   _coords=coords;
2958   coords->incrRef();
2959   _fam_coords=DataArrayInt::New();
2960   _fam_coords->alloc(nbOfTuples,1);
2961   _fam_coords->fillWithZero();
2962 }
2963
2964 /*!
2965  * Removes all groups of a given dimension in \a this mesh.
2966  *  \param [in] meshDimRelToMaxExt - the relative dimension of interest.
2967  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
2968  */
2969 void MEDFileUMesh::eraseGroupsAtLevel(int meshDimRelToMaxExt) throw(INTERP_KERNEL::Exception)
2970 {
2971   if(meshDimRelToMaxExt==1)
2972     {
2973       if((DataArrayInt *)_fam_coords)
2974         _fam_coords->fillWithZero();
2975       return ;
2976     }
2977   MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt);
2978   l1->eraseFamilyField();
2979   optimizeFamilies();
2980 }
2981
2982 /*!
2983  * Removes all families with ids not present in the family fields of \a this mesh.
2984  */
2985 void MEDFileUMesh::optimizeFamilies() throw(INTERP_KERNEL::Exception)
2986 {
2987   std::vector<int> levs=getNonEmptyLevelsExt();
2988   std::set<int> allFamsIds;
2989   for(std::vector<int>::const_iterator it=levs.begin();it!=levs.end();it++)
2990     {
2991       const DataArrayInt *ffield=getFamilyFieldAtLevel(*it);
2992       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids=ffield->getDifferentValues();
2993       std::set<int> res;
2994       std::set_union(ids->begin(),ids->end(),allFamsIds.begin(),allFamsIds.end(),std::inserter(res,res.begin()));
2995       allFamsIds=res;
2996     }
2997   std::set<std::string> famNamesToKill;
2998   for(std::map<std::string,int>::const_iterator it=_families.begin();it!=_families.end();it++)
2999     {
3000       if(allFamsIds.find((*it).second)!=allFamsIds.end())
3001         famNamesToKill.insert((*it).first);
3002     }
3003   for(std::set<std::string>::const_iterator it=famNamesToKill.begin();it!=famNamesToKill.end();it++)
3004     _families.erase(*it);
3005   std::vector<std::string> grpNamesToKill;
3006   for(std::map<std::string, std::vector<std::string> >::iterator it=_groups.begin();it!=_groups.end();it++)
3007     {
3008       std::vector<std::string> tmp;
3009       for(std::vector<std::string>::const_iterator it2=(*it).second.begin();it2!=(*it).second.end();it2++)
3010         {
3011           if(famNamesToKill.find(*it2)==famNamesToKill.end())
3012             tmp.push_back(*it2);
3013         }
3014       if(!tmp.empty())
3015         (*it).second=tmp;
3016       else
3017         tmp.push_back((*it).first);
3018     }
3019   for(std::vector<std::string>::const_iterator it=grpNamesToKill.begin();it!=grpNamesToKill.end();it++)
3020     _groups.erase(*it);
3021 }
3022
3023 void MEDFileUMesh::duplicateNodesOnM1Group(const char *grpNameM1, DataArrayInt *&nodesDuplicated, DataArrayInt *&cellsModified, DataArrayInt *&cellsNotModified) throw(INTERP_KERNEL::Exception)
3024 {
3025   std::vector<int> levs=getNonEmptyLevels();
3026   if(std::find(levs.begin(),levs.end(),0)==levs.end() || std::find(levs.begin(),levs.end(),-1)==levs.end())
3027     throw INTERP_KERNEL::Exception("MEDFileUMesh::duplicateNodesOnM1Group : This method works only for mesh definied on level 0 and -1 !");
3028   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m0=getMeshAtLevel(0);
3029   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m1=getMeshAtLevel(-1);
3030   int nbNodes=m0->getNumberOfNodes();
3031   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m11=getGroup(-1,grpNameM1);
3032   DataArrayInt *tmp00=0,*tmp11=0,*tmp22=0;
3033   m0->findNodesToDuplicate(*m11,tmp00,tmp11,tmp22);
3034   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodeIdsToDuplicate(tmp00);
3035   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsToModifyConn0(tmp11);
3036   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsToModifyConn1(tmp22);
3037   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> tmp0=static_cast<MEDCouplingUMesh *>(m0->buildPartOfMySelf(cellsToModifyConn0->begin(),cellsToModifyConn0->end(),true));
3038   // node renumbering of cells in m1 impacted by duplication of node but not in group 'grpNameM1' on level -1
3039   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descTmp0=DataArrayInt::New(),descITmp0=DataArrayInt::New(),revDescTmp0=DataArrayInt::New(),revDescITmp0=DataArrayInt::New();
3040   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> tmp0Desc=tmp0->buildDescendingConnectivity(descTmp0,descITmp0,revDescTmp0,revDescITmp0);
3041   descTmp0=0; descITmp0=0; revDescTmp0=0; revDescITmp0=0;
3042   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsInM1ToRenumW2=tmp0Desc->getCellIdsLyingOnNodes(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end(),false);
3043   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> cellsInM1ToRenumW3=static_cast<MEDCouplingUMesh *>(tmp0Desc->buildPartOfMySelf(cellsInM1ToRenumW2->begin(),cellsInM1ToRenumW2->end(),true));
3044   DataArrayInt *cellsInM1ToRenumW4Tmp=0;
3045   m1->areCellsIncludedIn(cellsInM1ToRenumW3,2,cellsInM1ToRenumW4Tmp);
3046   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsInM1ToRenumW4(cellsInM1ToRenumW4Tmp);
3047   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsInM1ToRenumW5=cellsInM1ToRenumW4->getIdsInRange(0,m1->getNumberOfCells());
3048   cellsInM1ToRenumW5->transformWithIndArr(cellsInM1ToRenumW4->begin(),cellsInM1ToRenumW4->end());
3049   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> grpIds=getGroupArr(-1,grpNameM1);
3050   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsInM1ToRenum=cellsInM1ToRenumW5->buildSubstraction(grpIds);
3051   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m1Part=static_cast<MEDCouplingUMesh *>(m1->buildPartOfMySelf(cellsInM1ToRenum->begin(),cellsInM1ToRenum->end(),true));
3052   m1Part->duplicateNodesInConn(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end(),nbNodes);
3053   m1->setPartOfMySelf(cellsInM1ToRenum->begin(),cellsInM1ToRenum->end(),*m1Part);
3054   // end of node renumbering of cells in m1 impacted by duplication of node but not in group of level -1 'grpNameM1'
3055   tmp0->duplicateNodes(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end());
3056   m0->setCoords(tmp0->getCoords());
3057   m0->setPartOfMySelf(cellsToModifyConn0->begin(),cellsToModifyConn0->end(),*tmp0);
3058   m1->setCoords(m0->getCoords());
3059   _coords=m0->getCoords(); _coords->incrRef();
3060   // duplication of cells in group 'grpNameM1' on level -1
3061   m11->duplicateNodesInConn(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end(),nbNodes); m11->setCoords(m0->getCoords());
3062   std::vector<const MEDCouplingUMesh *> v(2); v[0]=m1; v[1]=m11;
3063   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> newm1=MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(v,tmp00,tmp11);
3064   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> szOfCellGrpOfSameType(tmp00);
3065   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idInMsOfCellGrpOfSameType(tmp11);
3066   //
3067   newm1->setName(getName());
3068   const DataArrayInt *fam=getFamilyFieldAtLevel(-1);
3069   if(!fam)
3070     throw INTERP_KERNEL::Exception("MEDFileUMesh::duplicateNodesOnM1Group : internal problem !");
3071   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newFam=DataArrayInt::New();
3072   newFam->alloc(newm1->getNumberOfCells(),1);
3073   int idd=getMaxFamilyId()+1;
3074   int globStart=0,start=0,end,globEnd;
3075   int nbOfChunks=szOfCellGrpOfSameType->getNumberOfTuples();
3076   for(int i=0;i<nbOfChunks;i++)
3077     {
3078       globEnd=globStart+szOfCellGrpOfSameType->getIJ(i,0);
3079       if(idInMsOfCellGrpOfSameType->getIJ(i,0)==0)
3080         {
3081           end=start+szOfCellGrpOfSameType->getIJ(i,0);
3082           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> part=fam->selectByTupleId2(start,end,1);
3083           newFam->setPartOfValues1(part,globStart,globEnd,1,0,1,1,true);
3084           start=end;
3085         }
3086       else
3087         {
3088           newFam->setPartOfValuesSimple1(idd,globStart,globEnd,1,0,1,1);
3089         }
3090       globStart=globEnd;
3091     }
3092   newm1->setCoords(getCoords());
3093   setMeshAtLevel(-1,newm1);
3094   setFamilyFieldArr(-1,newFam);
3095   std::string grpName2(grpNameM1); grpName2+="_dup";
3096   addFamily(grpName2.c_str(),idd);
3097   addFamilyOnGrp(grpName2.c_str(),grpName2.c_str());
3098   //
3099   fam=_fam_coords;
3100   if(fam)
3101     {
3102       int newNbOfNodes=getCoords()->getNumberOfTuples();
3103       newFam=DataArrayInt::New(); newFam->alloc(newNbOfNodes,1);
3104       newFam->setPartOfValues1(fam,0,nbNodes,1,0,1,1,true);
3105       newFam->setPartOfValuesSimple1(0,nbNodes,newNbOfNodes,1,0,1,1);
3106       _fam_coords=newFam;
3107     }
3108   nodesDuplicated=nodeIdsToDuplicate.retn();
3109   cellsModified=cellsToModifyConn0.retn();
3110   cellsNotModified=cellsToModifyConn1.retn();
3111 }
3112
3113 /*!
3114  * \param [out] oldCode retrieves the distribution of types before the call if true is returned
3115  * \param [out] newCode etrieves the distribution of types after the call if true is returned
3116  * \param [out] o2nRenumCell tells for **all levels** the old 2 new renumbering of cells.
3117  * 
3118  * \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.
3119  * 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.
3120  */
3121 bool MEDFileUMesh::unPolyze(std::vector<int>& oldCode, std::vector<int>& newCode, DataArrayInt *& o2nRenumCell) throw(INTERP_KERNEL::Exception)
3122 {
3123   o2nRenumCell=0; oldCode.clear(); newCode.clear();
3124   std::vector<int> levs=getNonEmptyLevels();
3125   bool ret=false;
3126   std::vector< const DataArrayInt* > renumCellsSplited;//same than memorySaverIfThrow
3127   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > memorySaverIfThrow;//same than renumCellsSplited only in case of throw
3128   int start=0;
3129   int end=0;
3130   for(std::vector<int>::reverse_iterator it=levs.rbegin();it!=levs.rend();it++)
3131     {
3132       MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=getMeshAtLevel(*it);
3133       std::vector<int> code1=m->getDistributionOfTypes();
3134       end=PutInThirdComponentOfCodeOffset(code1,start);
3135       oldCode.insert(oldCode.end(),code1.begin(),code1.end());
3136       bool hasChanged=m->unPolyze();
3137       DataArrayInt *fake=0;
3138       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2nCellsPart=m->getLevArrPerCellTypes(MEDCouplingUMesh::MEDMEM_ORDER,
3139                                                                                            MEDCouplingUMesh::MEDMEM_ORDER+MEDCouplingUMesh::N_MEDMEM_ORDER,fake);
3140       fake->decrRef();
3141       renumCellsSplited.push_back(o2nCellsPart); memorySaverIfThrow.push_back(o2nCellsPart);
3142       if(hasChanged)
3143         {
3144           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2nCellsPart2=o2nCellsPart->buildPermArrPerLevel();
3145           m->renumberCells(o2nCellsPart2->getConstPointer(),false);
3146           ret=true;
3147           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> famField2,numField2;
3148           const DataArrayInt *famField=getFamilyFieldAtLevel(*it); if(famField) { famField->incrRef(); famField2=const_cast<DataArrayInt *>(famField); }
3149           const DataArrayInt *numField=getNumberFieldAtLevel(*it); if(numField) { numField->incrRef(); numField2=const_cast<DataArrayInt *>(numField); }
3150           setMeshAtLevel(*it,m);
3151           std::vector<int> code2=m->getDistributionOfTypes();
3152           end=PutInThirdComponentOfCodeOffset(code2,start);
3153           newCode.insert(newCode.end(),code2.begin(),code2.end());
3154           //
3155           if(o2nCellsPart2->isIdentity())
3156             continue;
3157           if(famField)
3158             {
3159               MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newFamField=famField->renumber(o2nCellsPart2->getConstPointer());
3160               setFamilyFieldArr(*it,newFamField);
3161             }
3162           if(numField)
3163             {
3164               MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newNumField=numField->renumber(o2nCellsPart2->getConstPointer());
3165               setRenumFieldArr(*it,newNumField);
3166             }
3167         }
3168       else
3169         {
3170           newCode.insert(newCode.end(),code1.begin(),code1.end());
3171         }
3172       start=end;
3173     }
3174   if(ret)
3175     {
3176       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> renumCells=DataArrayInt::Aggregate(renumCellsSplited);
3177       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2nRenumCellRet=renumCells->buildPermArrPerLevel();
3178       o2nRenumCell=o2nRenumCellRet.retn();
3179     }
3180   return ret;
3181 }
3182
3183 struct MEDLoaderAccVisit1
3184 {
3185   MEDLoaderAccVisit1():_new_nb_of_nodes(0) { }
3186   int operator()(bool val) { return val?_new_nb_of_nodes++:-1; }
3187   int _new_nb_of_nodes;
3188 };
3189
3190 /*!
3191  * Array returned is the correspondance in \b old \b to \b new format. The returned array is newly created and should be dealt by the caller.
3192  * The maximum value stored in returned array is the number of nodes of \a this minus 1 after call of this method.
3193  * The size of returned array is the number of nodes of the old (previous to the call of this method) number of nodes.
3194  * -1 values in returned array means that the corresponding old node is no more used.
3195  *
3196  * \return newly allocated array containing correspondance in \b old \b to \b new format. If all nodes in \a this are fetched \c NULL pointer is returned and nothing
3197  *         is modified in \a this.
3198  * \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
3199  *  set coordinates.
3200  */
3201 DataArrayInt *MEDFileUMesh::zipCoords() throw(INTERP_KERNEL::Exception)
3202 {
3203   const DataArrayDouble *coo=getCoords();
3204   if(!coo)
3205     throw INTERP_KERNEL::Exception("MEDFileUMesh::zipCoords : no coordinates set in this !");
3206   int nbOfNodes=coo->getNumberOfTuples();
3207   std::vector<bool> nodeIdsInUse(nbOfNodes,false);
3208   std::vector<int> neLevs=getNonEmptyLevels();
3209   for(std::vector<int>::const_iterator lev=neLevs.begin();lev!=neLevs.end();lev++)
3210     {
3211       MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=getMeshAtLevel(*lev);
3212       m->computeNodeIdsAlg(nodeIdsInUse);
3213     }
3214   int nbrOfNodesInUse=(int)std::count(nodeIdsInUse.begin(),nodeIdsInUse.end(),true);
3215   if(nbrOfNodesInUse==nbOfNodes)
3216     return 0;
3217   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(nbOfNodes,1);
3218   std::transform(nodeIdsInUse.begin(),nodeIdsInUse.end(),ret->getPointer(),MEDLoaderAccVisit1());
3219   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret2=ret->invertArrayO2N2N2OBis(nbrOfNodesInUse);
3220   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> newCoords=coo->selectByTupleIdSafe(ret2->begin(),ret2->end());
3221   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newFamCoords;
3222   MEDCouplingAutoRefCountObjectPtr<DataArrayAsciiChar> newNameCoords;
3223   if((const DataArrayInt *)_fam_coords)
3224     newFamCoords=_fam_coords->selectByTupleIdSafe(ret2->begin(),ret2->end());
3225   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newNumCoords;
3226   if((const DataArrayInt *)_num_coords)
3227     newNumCoords=_num_coords->selectByTupleIdSafe(ret2->begin(),ret2->end());
3228   if((const DataArrayAsciiChar *)_name_coords)
3229     newNameCoords=static_cast<DataArrayAsciiChar *>(_name_coords->selectByTupleIdSafe(ret2->begin(),ret2->end()));
3230   _coords=newCoords; _fam_coords=newFamCoords; _num_coords=newNumCoords; _name_coords=newNameCoords; _rev_num_coords=0;
3231   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::iterator it=_ms.begin();it!=_ms.end();it++)
3232     {
3233       if((MEDFileUMeshSplitL1*)*it)
3234         (*it)->renumberNodesInConn(ret->begin());
3235     }
3236   return ret.retn();
3237 }
3238
3239 /*!
3240  * Adds a group of nodes to \a this mesh.
3241  *  \param [in] ids - a DataArrayInt providing ids and a name of the group to add.
3242  *          The ids should be sorted and different each other (MED file norm).
3243  *  \throw If the node coordinates array is not set.
3244  *  \throw If \a ids == \c NULL.
3245  *  \throw If \a ids->getName() == "".
3246  *  \throw If \a ids does not respect the MED file norm.
3247  *  \throw If a group with name \a ids->getName() already exists.
3248  */
3249 void MEDFileUMesh::addNodeGroup(const DataArrayInt *ids) throw(INTERP_KERNEL::Exception)
3250 {
3251   const DataArrayDouble *coords=_coords;
3252   if(!coords)
3253     throw INTERP_KERNEL::Exception("MEDFileUMesh::addNodeGroup : no coords set !");
3254   int nbOfNodes=coords->getNumberOfTuples();
3255   if(!((DataArrayInt *)_fam_coords))
3256     { _fam_coords=DataArrayInt::New(); _fam_coords->alloc(nbOfNodes,1); _fam_coords->fillWithZero(); }
3257   //
3258   addGroupUnderground(true,ids,_fam_coords);
3259 }
3260
3261 /*!
3262  * Adds a group of nodes/cells/faces/edges to \a this mesh.
3263  *  \param [in] ids - a DataArrayInt providing ids and a name of the group to add.
3264  *          The ids should be sorted and different each other (MED file norm).
3265  *  \throw If the node coordinates array is not set.
3266  *  \throw If \a ids == \c NULL.
3267  *  \throw If \a ids->getName() == "".
3268  *  \throw If \a ids does not respect the MED file norm.
3269  *  \throw If a group with name \a ids->getName() already exists.
3270  */
3271 void MEDFileUMesh::addGroup(int meshDimRelToMaxExt, const DataArrayInt *ids) throw(INTERP_KERNEL::Exception)
3272 {
3273   std::vector<int> levs=getNonEmptyLevelsExt();
3274   if(std::find(levs.begin(),levs.end(),meshDimRelToMaxExt)==levs.end())
3275     { 
3276       std::ostringstream oss; oss << "MEDFileUMesh::addGroup : level " << meshDimRelToMaxExt << " not available ! Should be in ";
3277       std::copy(levs.begin(),levs.end(),std::ostream_iterator<int>(oss," ")); oss << " !"; throw INTERP_KERNEL::Exception(oss.str().c_str());
3278     }
3279   if(meshDimRelToMaxExt==1)
3280     { addNodeGroup(ids); return ; }
3281   MEDFileUMeshSplitL1 *lev=getMeshAtLevSafe(meshDimRelToMaxExt);
3282   DataArrayInt *fam=lev->getOrCreateAndGetFamilyField();
3283   addGroupUnderground(false,ids,fam);
3284 }
3285
3286 /*!
3287  * \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).
3288  * \parma [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)
3289  */
3290 void MEDFileUMesh::addGroupUnderground(bool isNodeGroup, const DataArrayInt *ids, DataArrayInt *famArr) throw(INTERP_KERNEL::Exception)
3291 {
3292   if(!ids)
3293     throw INTERP_KERNEL::Exception("MEDFileUMesh::addGroup : NULL pointer in input !");
3294   std::string grpName(ids->getName());
3295   if(grpName.empty())
3296     throw INTERP_KERNEL::Exception("MEDFileUMesh::addGroup : empty group name ! MED file format do not accept empty group name !");
3297   ids->checkStrictlyMonotonic(true);
3298   famArr->incrRef(); MEDCouplingAutoRefCountObjectPtr<DataArrayInt> famArrTmp(famArr);
3299   std::vector<std::string> grpsNames=getGroupsNames();
3300   if(std::find(grpsNames.begin(),grpsNames.end(),grpName)!=grpsNames.end())
3301     {
3302       std::ostringstream oss; oss << "MEDFileUMesh::addGroup : Group with name \"" << grpName << "\" already exists ! Destroy it before calling this method !";
3303       throw INTERP_KERNEL::Exception(oss.str().c_str());
3304     }
3305   std::list< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > allFamIds=getAllNonNullFamilyIds();
3306   allFamIds.erase(std::find(allFamIds.begin(),allFamIds.end(),famArrTmp));
3307   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> famIds=famArr->selectByTupleIdSafe(ids->begin(),ids->end());
3308   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> diffFamIds=famIds->getDifferentValues();
3309   std::vector<int> familyIds;
3310   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > idsPerfamiliyIds;
3311   int maxVal=getTheMaxAbsFamilyId()+1;
3312   std::map<std::string,int> families(_families);
3313   std::map<std::string, std::vector<std::string> > groups(_groups);
3314   std::vector<std::string> fams;
3315   bool created(false);
3316   for(const int *famId=diffFamIds->begin();famId!=diffFamIds->end();famId++)
3317     {
3318       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids2Tmp=famIds->getIdsEqual(*famId);
3319       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids2=ids->selectByTupleId(ids2Tmp->begin(),ids2Tmp->end());
3320       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids1=famArr->getIdsEqual(*famId);
3321       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret0(ids1->buildSubstractionOptimized(ids2));
3322       if(ret0->empty())
3323         {
3324           bool isFamPresent=false;
3325           for(std::list< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> >::const_iterator itl=allFamIds.begin();itl!=allFamIds.end() && !isFamPresent;itl++)
3326             isFamPresent=(*itl)->presenceOfValue(*famId);
3327           if(!isFamPresent)
3328             { familyIds.push_back(*famId); idsPerfamiliyIds.push_back(ret0); fams.push_back(FindOrCreateAndGiveFamilyWithId(families,*famId,created)); } // adding *famId in grp
3329           else
3330             {
3331               familyIds.push_back(isNodeGroup?maxVal:-maxVal); idsPerfamiliyIds.push_back(ids2);
3332               std::string locFamName=FindOrCreateAndGiveFamilyWithId(families,isNodeGroup?maxVal:-maxVal,created);
3333               fams.push_back(locFamName);
3334               if(existsFamily(*famId))
3335                 {
3336                   std::string locFamName2=getFamilyNameGivenId(*famId); std::vector<std::string> v(2); v[0]=locFamName2; v[1]=locFamName;
3337                   ChangeAllGroupsContainingFamily(groups,getFamilyNameGivenId(*famId).c_str(),v);
3338                 }
3339               maxVal++;
3340             } // modifying all other groups on *famId to lie on maxVal and lie the grp on maxVal
3341         }
3342       else
3343         {
3344           familyIds.push_back(isNodeGroup?maxVal:-maxVal); idsPerfamiliyIds.push_back(ret0); // modifying all other groups on *famId to lie on maxVal and on maxVal+1
3345           familyIds.push_back(isNodeGroup?maxVal+1:-maxVal-1); idsPerfamiliyIds.push_back(ids2);//grp lie only on maxVal+1
3346           std::string n2(FindOrCreateAndGiveFamilyWithId(families,isNodeGroup?maxVal+1:-maxVal-1,created)); fams.push_back(n2);
3347           if(existsFamily(*famId))
3348             {
3349               std::string n1(FindOrCreateAndGiveFamilyWithId(families,isNodeGroup?maxVal:-maxVal,created)); std::vector<std::string> v(2); v[0]=n1; v[1]=n2;
3350               ChangeAllGroupsContainingFamily(groups,getFamilyNameGivenId(*famId).c_str(),v);
3351             }
3352           maxVal+=2;
3353         }
3354     }
3355   for(std::size_t i=0;i<familyIds.size();i++)
3356     {
3357       DataArrayInt *da=idsPerfamiliyIds[i];
3358       famArr->setPartOfValuesSimple3(familyIds[i],da->begin(),da->end(),0,1,1);
3359     }
3360   _families=families;
3361   _groups=groups;
3362   _groups[grpName]=fams;
3363 }
3364
3365 /*!
3366  * Changes a name of a family specified by its id.
3367  *  \param [in] id - the id of the family of interest.
3368  *  \param [in] newFamName - the new family name.
3369  *  \throw If no family with the given \a id exists.
3370  */
3371 void MEDFileUMesh::setFamilyNameAttachedOnId(int id, const std::string& newFamName) throw(INTERP_KERNEL::Exception)
3372 {
3373   std::string oldName=getFamilyNameGivenId(id);
3374   _families.erase(oldName);
3375   _families[newFamName]=id;
3376 }
3377
3378 /*!
3379  * Removes a mesh of a given dimension.
3380  *  \param [in] meshDimRelToMax - the relative dimension of interest.
3381  *  \throw If there is no mesh at level \a meshDimRelToMax in \a this mesh.
3382  */
3383 void MEDFileUMesh::removeMeshAtLevel(int meshDimRelToMax) throw(INTERP_KERNEL::Exception)
3384 {
3385   std::vector<int> levSet=getNonEmptyLevels();
3386   std::vector<int>::const_iterator it=std::find(levSet.begin(),levSet.end(),meshDimRelToMax);
3387   if(it==levSet.end())
3388     throw INTERP_KERNEL::Exception("MEDFileUMesh::removeMeshAtLevel : the requested level is not existing !");
3389   int pos=(-meshDimRelToMax);
3390   _ms[pos]=0;
3391 }
3392
3393 /*!
3394  * Sets a new MEDCouplingUMesh at a given level in \a this mesh.
3395  *  \param [in] meshDimRelToMax - a relative level to set the mesh at.
3396  *  \param [in] m - the new mesh to set.
3397  *  \param [in] newOrOld - if \c true, cells in \a m are sorted by type to be ready for 
3398  *         writing \a this mesh in a MED file.
3399  *  \throw If the name or the description of \a this mesh and \a m are not empty and are
3400  *         different. 
3401  *  \throw If the node coordinates array is set \a this in mesh and \a m refers to
3402  *         another node coordinates array.
3403  *  \throw If the mesh dimension of \a m does not correspond to \a meshDimRelToMax or
3404  *         to the existing meshes of other levels of \a this mesh.
3405  */
3406 void MEDFileUMesh::setMeshAtLevel(int meshDimRelToMax, MEDCouplingUMesh *m, bool newOrOld) throw(INTERP_KERNEL::Exception)
3407 {
3408   dealWithTinyInfo(m);
3409   std::vector<int> levSet=getNonEmptyLevels();
3410   if(std::find(levSet.begin(),levSet.end(),meshDimRelToMax)==levSet.end())
3411     {
3412       if((DataArrayDouble *)_coords==0)
3413         {
3414           DataArrayDouble *c=m->getCoords();
3415           if(c)
3416             c->incrRef();
3417           _coords=c;
3418         }
3419       if(m->getCoords()!=_coords)
3420         throw INTERP_KERNEL::Exception("MEDFileUMesh::setMeshAtLevel : Invalid Given Mesh ! The coordinates are not the same ! try to use tryToShareSameCoords !");
3421       int sz=(-meshDimRelToMax)+1;
3422       if(sz>=(int)_ms.size())
3423         _ms.resize(sz);
3424       checkMeshDimCoherency(m->getMeshDimension(),meshDimRelToMax);
3425       _ms[sz-1]=new MEDFileUMeshSplitL1(m,newOrOld);
3426     }
3427   else
3428     _ms[-meshDimRelToMax]=new MEDFileUMeshSplitL1(m,newOrOld);
3429 }
3430
3431 /*!
3432  * This method allows to set at once the content of different levels in \a this.
3433  * This method is equivalent to a series of call to MEDFileUMesh::setMeshAtLevel.
3434  *
3435  * \param [in] ms - List of unstructured meshes lying on the same coordinates and having different mesh dimesnion.
3436  * \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.
3437  *                     If false, an exception ois thrown. If true the mesh is reordered automatically. It is highly recommanded to let this parameter to false.
3438  *
3439  * \throw If \a there is a null pointer in \a ms.
3440  * \sa MEDFileUMesh::setMeshAtLevel
3441  */
3442 void MEDFileUMesh::setMeshes(const std::vector<const MEDCouplingUMesh *>& ms, bool renum) throw(INTERP_KERNEL::Exception)
3443 {
3444   if(ms.empty())
3445     return ;
3446   const MEDCouplingUMesh *mRef=ms[0];
3447   if(!mRef)
3448     throw INTERP_KERNEL::Exception("MEDFileUMesh::setMeshes : null instance in the first element of input meshes !");
3449   std::string name(mRef->getName());
3450   const DataArrayDouble *coo(mRef->getCoords());
3451   std::set<int> s;
3452   int zeDim=-1;
3453   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
3454     {
3455       const MEDCouplingUMesh *cur(*it);
3456       if(!cur)
3457         throw INTERP_KERNEL::Exception("MEDFileUMesh::setMeshes : null instance in input vector of meshes !");
3458       if(coo!=cur->getCoords())
3459         throw INTERP_KERNEL::Exception("MEDFileUMesh::setMeshes : The input meshes do not share the same coordinates !");
3460       int mdim=cur->getMeshDimension();
3461       zeDim=std::max(zeDim,mdim);
3462       if(s.find(mdim)!=s.end())
3463         throw INTERP_KERNEL::Exception("MEDFileUMesh::setMeshes : The input meshes must share the same coordinates pointer, and should have different mesh dimension each other !");
3464     }
3465   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
3466     {
3467       int mdim=(*it)->getMeshDimension();
3468       setName((*it)->getName());
3469       setMeshAtLevel(mdim-zeDim,const_cast<MEDCouplingUMesh *>(*it),renum);
3470     }
3471   setName(name.c_str());
3472 }
3473
3474 /*!
3475  * Creates one MEDCouplingUMesh at a given level in \a this mesh from a sequence of
3476  * meshes each representing a group, and creates corresponding groups in \a this mesh.
3477  * The given meshes must share the same node coordinates array.
3478  *  \param [in] meshDimRelToMax - the relative dimension to create the mesh and groups at.
3479  *  \param [in] ms - the sequence of meshes. Each mesh in \a ms represents a group to
3480  *          create in \a this mesh.
3481  *  \throw If \a ms is empty.
3482  *  \throw If dimension of meshes in \a ms does not correspond to \a meshDimRelToMax or
3483  *         to the existing meshes of other levels of \a this mesh.
3484  *  \throw If the meshes in \a ms do not share the same node coordinates array.
3485  *  \throw If the node coordinates array of \a this mesh (if any) is not the same as that
3486  *         of the given meshes.
3487  *  \throw If \a ms[ i ] is not well defined (MEDCouplingUMesh::checkCoherency()).
3488  *  \throw If names of some meshes in \a ms are equal.
3489  *  \throw If \a ms includes a mesh with an empty name.
3490  */
3491 void MEDFileUMesh::setGroupsFromScratch(int meshDimRelToMax, const std::vector<const MEDCouplingUMesh *>& ms, bool renum) throw(INTERP_KERNEL::Exception)
3492 {
3493   if(ms.empty())
3494     throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsFromScratch : expecting a non empty vector !");
3495   int sz=(-meshDimRelToMax)+1;
3496   if(sz>=(int)_ms.size())
3497     _ms.resize(sz);
3498   checkMeshDimCoherency(ms[0]->getMeshDimension(),meshDimRelToMax);
3499   DataArrayDouble *coo=checkMultiMesh(ms);
3500   if((DataArrayDouble *)_coords==0)
3501     {
3502       coo->incrRef();
3503       _coords=coo;
3504     }
3505   else
3506     if((DataArrayDouble *)_coords!=coo)
3507       throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsFromScratch : coordinates mismatches !");
3508   std::vector<DataArrayInt *> corr;
3509   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=MEDCouplingUMesh::FuseUMeshesOnSameCoords(ms,_zipconn_pol,corr);
3510   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > corr3(corr.begin(),corr.end());
3511   setMeshAtLevel(meshDimRelToMax,m,renum);
3512   std::vector<const DataArrayInt *> corr2(corr.begin(),corr.end());
3513   setGroupsAtLevel(meshDimRelToMax,corr2,true);
3514 }
3515
3516 /*!
3517  * Creates groups at a given level in \a this mesh from a sequence of
3518  * meshes each representing a group.
3519  * The given meshes must share the same node coordinates array.
3520  *  \param [in] meshDimRelToMax - the relative dimension to create the groups at.
3521  *  \param [in] ms - the sequence of meshes. Each mesh in \a ms represents a group to
3522  *         create in \a this mesh.
3523  *  \param [in] renum - if \c true, then the optional numbers of entities are taken into
3524  *         account. 
3525  *  \throw If \a ms is empty.
3526  *  \throw If dimension of meshes in \a ms does not correspond to \a meshDimRelToMax or
3527  *         to the existing meshes of other levels of \a this mesh.
3528  *  \throw If the meshes in \a ms do not share the same node coordinates array.
3529  *  \throw If the node coordinates array of \a this mesh (if any) is not the same as that
3530  *         of the given meshes.
3531  *  \throw If \a ms[ i ] is not well defined (MEDCouplingUMesh::checkCoherency()).
3532  *  \throw If names of some meshes in \a ms are equal.
3533  *  \throw If \a ms includes a mesh with an empty name.
3534  */
3535 void MEDFileUMesh::setGroupsOnSetMesh(int meshDimRelToMax, const std::vector<const MEDCouplingUMesh *>& ms, bool renum) throw(INTERP_KERNEL::Exception)
3536 {
3537   if(ms.empty())
3538     throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsOnSetMesh : expecting a non empty vector !");
3539   int sz=(-meshDimRelToMax)+1;
3540   if(sz>=(int)_ms.size())
3541     _ms.resize(sz);
3542   checkMeshDimCoherency(ms[0]->getMeshDimension(),meshDimRelToMax);
3543   DataArrayDouble *coo=checkMultiMesh(ms);
3544   if((DataArrayDouble *)_coords==0)
3545     {
3546       coo->incrRef();
3547       _coords=coo;
3548     }
3549   else
3550     if((DataArrayDouble *)_coords!=coo)
3551       throw INTERP_KERNEL::Exception("MEDFileUMesh::setGroupsOnSetMesh : coordinates mismatches !");
3552   MEDCouplingUMesh *m=getMeshAtLevel(meshDimRelToMax,renum);
3553   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > corr(ms.size());
3554   int i=0;
3555   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++,i++)
3556     {
3557       DataArrayInt *arr=0;
3558       bool test=m->areCellsIncludedIn(*it,_zipconn_pol,arr);
3559       corr[i]=arr;
3560       if(!test)
3561         {
3562           std::ostringstream oss; oss << "MEDFileUMesh::setGroupsOnSetMesh : mesh #" << i << " is not part of whole mesh !";
3563           throw INTERP_KERNEL::Exception(oss.str().c_str());
3564         }
3565     }
3566   std::vector<const DataArrayInt *> corr2(corr.begin(),corr.end());
3567   setGroupsAtLevel(meshDimRelToMax,corr2,renum);
3568 }
3569
3570 DataArrayDouble *MEDFileUMesh::checkMultiMesh(const std::vector<const MEDCouplingUMesh *>& ms) const throw(INTERP_KERNEL::Exception)
3571 {
3572   const DataArrayDouble *ret=ms[0]->getCoords();
3573   int mdim=ms[0]->getMeshDimension();
3574   for(unsigned int i=1;i<ms.size();i++)
3575     {
3576       ms[i]->checkCoherency();
3577       if(ms[i]->getCoords()!=ret)
3578         throw INTERP_KERNEL::Exception("MEDFileUMesh::checkMultiMesh : meshes must share the same coords !");
3579       if(ms[i]->getMeshDimension()!=mdim)
3580         throw INTERP_KERNEL::Exception("MEDFileUMesh::checkMultiMesh : meshes have not same mesh dimension !");
3581     }
3582   return const_cast<DataArrayDouble *>(ret);
3583 }
3584
3585 /*!
3586  * Sets the family field of a given relative dimension.
3587  *  \param [in] meshDimRelToMaxExt - the relative dimension of entities for which
3588  *          the family field is set.
3589  *  \param [in] famArr - the array of the family field.
3590  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3591  *  \throw If \a famArr has an invalid size.
3592  */
3593 void MEDFileUMesh::setFamilyFieldArr(int meshDimRelToMaxExt, DataArrayInt *famArr) throw(INTERP_KERNEL::Exception)
3594 {
3595   if(meshDimRelToMaxExt==1)
3596     {
3597       if(!famArr)
3598         {
3599           _fam_coords=0;
3600           return ;
3601         }
3602       DataArrayDouble *coo(_coords);
3603       if(!coo)
3604         throw INTERP_KERNEL::Exception("MEDFileUMesh::setFamilyFieldArr : the coordinates have not been set !");
3605       famArr->checkNbOfTuplesAndComp(coo->getNumberOfTuples(),1,"MEDFileUMesh::setFamilyFieldArr : Problem in size of node family arr ! ");
3606       famArr->incrRef();
3607       _fam_coords=famArr;
3608       return ;
3609     }
3610   if(meshDimRelToMaxExt>1)
3611     throw INTERP_KERNEL::Exception("MEDFileUMesh::setFamilyFieldArr : Dimension request is invalid (>1) !");
3612   int traducedRk=-meshDimRelToMaxExt;
3613   if(traducedRk>=(int)_ms.size())
3614     throw INTERP_KERNEL::Exception("Invalid mesh dim relative to max given ! To low !");
3615   if((MEDFileUMeshSplitL1 *)_ms[traducedRk]==0)
3616     throw INTERP_KERNEL::Exception("On specified lev (or entity) no cells exists !");
3617   return _ms[traducedRk]->setFamilyArr(famArr);
3618 }
3619
3620 /*!
3621  * Sets the optional numbers of mesh entities of a given dimension.
3622  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
3623  *  \param [in] renumArr - the array of the numbers.
3624  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3625  *  \throw If \a renumArr has an invalid size.
3626  */
3627 void MEDFileUMesh::setRenumFieldArr(int meshDimRelToMaxExt, DataArrayInt *renumArr) throw(INTERP_KERNEL::Exception)
3628 {
3629   if(meshDimRelToMaxExt==1)
3630     {
3631       if(!renumArr)
3632         {
3633           _num_coords=0;
3634           _rev_num_coords=0;
3635           return ;
3636         }
3637       DataArrayDouble *coo(_coords);
3638       if(!coo)
3639         throw INTERP_KERNEL::Exception("MEDFileUMesh::setRenumFieldArr : the coordinates have not been set !");
3640       renumArr->checkNbOfTuplesAndComp(coo->getNumberOfTuples(),1,"MEDFileUMesh::setRenumArr : Problem in size of node numbering arr ! ");
3641       renumArr->incrRef();
3642       _num_coords=renumArr;
3643       computeRevNum();
3644       return ;
3645     }
3646   if(meshDimRelToMaxExt>1)
3647     throw INTERP_KERNEL::Exception("MEDFileUMesh::setRenumArr : Dimension request is invalid (>1) !");
3648   int traducedRk=-meshDimRelToMaxExt;
3649   if(traducedRk>=(int)_ms.size())
3650     throw INTERP_KERNEL::Exception("Invalid mesh dim relative to max given ! To low !");
3651   if((MEDFileUMeshSplitL1 *)_ms[traducedRk]==0)
3652     throw INTERP_KERNEL::Exception("On specified lev (or entity) no cells exists !");
3653   return _ms[traducedRk]->setRenumArr(renumArr);
3654 }
3655
3656 /*!
3657  * Sets the optional names of mesh entities of a given dimension.
3658  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
3659  *  \param [in] nameArr - the array of the names.
3660  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3661  *  \throw If \a nameArr has an invalid size.
3662  */
3663 void MEDFileUMesh::setNameFieldAtLevel(int meshDimRelToMaxExt, DataArrayAsciiChar *nameArr) throw(INTERP_KERNEL::Exception)
3664 {
3665   if(meshDimRelToMaxExt==1)
3666     {
3667       if(!nameArr)
3668         {
3669           _name_coords=0;
3670           return ;
3671         }
3672       DataArrayDouble *coo(_coords);
3673       if(!coo)
3674         throw INTERP_KERNEL::Exception("MEDFileUMesh::setNameFieldAtLevel : the coordinates have not been set !");
3675       nameArr->checkNbOfTuplesAndComp(coo->getNumberOfTuples(),MED_SNAME_SIZE,"MEDFileUMesh::setNameFieldAtLevel : Problem in size of node numbering arr ! ");
3676       nameArr->incrRef();
3677       _name_coords=nameArr;
3678       return ;
3679     }
3680   if(meshDimRelToMaxExt>1)
3681     throw INTERP_KERNEL::Exception("MEDFileUMesh::setNameFieldAtLevel : Dimension request is invalid (>1) !");
3682   int traducedRk=-meshDimRelToMaxExt;
3683   if(traducedRk>=(int)_ms.size())
3684     throw INTERP_KERNEL::Exception("Invalid mesh dim relative to max given ! To low !");
3685   if((MEDFileUMeshSplitL1 *)_ms[traducedRk]==0)
3686     throw INTERP_KERNEL::Exception("On specified lev (or entity) no cells exists !");
3687   return _ms[traducedRk]->setNameArr(nameArr);
3688 }
3689
3690 void MEDFileUMesh::synchronizeTinyInfoOnLeaves() const
3691 {
3692   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
3693     if((const MEDFileUMeshSplitL1 *)(*it))
3694       (*it)->synchronizeTinyInfo(*this);
3695 }
3696
3697 /*!
3698  * This method is called by MEDFileMesh::changeFamilyId. It performs only one part of the family id modification.
3699  */
3700 void MEDFileUMesh::changeFamilyIdArr(int oldId, int newId) throw(INTERP_KERNEL::Exception)
3701 {
3702   DataArrayInt *arr=_fam_coords;
3703   if(arr)
3704     arr->changeValue(oldId,newId);
3705   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::iterator it=_ms.begin();it!=_ms.end();it++)
3706     {
3707       MEDFileUMeshSplitL1 *sp=(*it);
3708       if(sp)
3709         {
3710           sp->changeFamilyIdArr(oldId,newId);
3711         }
3712     }
3713 }
3714
3715 std::list< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > MEDFileUMesh::getAllNonNullFamilyIds() const
3716 {
3717   std::list< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > ret;
3718   const DataArrayInt *da(_fam_coords);
3719   if(da)
3720     { da->incrRef(); ret.push_back(MEDCouplingAutoRefCountObjectPtr<DataArrayInt>(const_cast<DataArrayInt *>(da))); }
3721   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();it!=_ms.end();it++)
3722     {
3723       const MEDFileUMeshSplitL1 *elt(*it);
3724       if(elt)
3725         {
3726           da=elt->getFamilyField();
3727           if(da)
3728             { da->incrRef(); ret.push_back(MEDCouplingAutoRefCountObjectPtr<DataArrayInt>(const_cast<DataArrayInt *>(da))); }
3729         }
3730     }
3731   return ret;
3732 }
3733
3734 void MEDFileUMesh::computeRevNum() const
3735 {
3736   if((const DataArrayInt *)_num_coords)
3737     {
3738       int pos;
3739       int maxValue=_num_coords->getMaxValue(pos);
3740       _rev_num_coords=_num_coords->invertArrayN2O2O2N(maxValue+1);
3741     }
3742 }
3743
3744 std::size_t MEDFileStructuredMesh::getHeapMemorySize() const
3745 {
3746   std::size_t ret=MEDFileMesh::getHeapMemorySize();
3747   if((const DataArrayInt*)_fam_nodes)
3748     ret+=_fam_nodes->getHeapMemorySize();
3749   if((const DataArrayInt*)_num_nodes)
3750     ret+=_num_nodes->getHeapMemorySize();
3751   if((const DataArrayInt*)_fam_cells)
3752     ret+=_fam_cells->getHeapMemorySize();
3753   if((const DataArrayInt*)_num_cells)
3754     ret+=_num_cells->getHeapMemorySize();
3755   if((const DataArrayInt*)_rev_num_nodes)
3756     ret+=_rev_num_nodes->getHeapMemorySize();
3757   if((const DataArrayInt*)_rev_num_cells)
3758     ret+=_rev_num_cells->getHeapMemorySize();
3759   return ret;
3760 }
3761
3762 int MEDFileStructuredMesh::getMaxAbsFamilyIdInArrays() const throw(INTERP_KERNEL::Exception)
3763 {
3764   int ret=-std::numeric_limits<int>::max(),tmp=-1;
3765   if((const DataArrayInt *)_fam_nodes)
3766     {
3767       int val=_fam_nodes->getMaxValue(tmp);
3768       ret=std::max(ret,std::abs(val));
3769     }
3770   if((const DataArrayInt *)_fam_cells)
3771     {
3772       int val=_fam_cells->getMaxValue(tmp);
3773       ret=std::max(ret,std::abs(val));
3774     }
3775   return ret;
3776 }
3777
3778 int MEDFileStructuredMesh::getMaxFamilyIdInArrays() const throw(INTERP_KERNEL::Exception)
3779 {
3780   int ret=-std::numeric_limits<int>::max(),tmp=-1;
3781   if((const DataArrayInt *)_fam_nodes)
3782     {
3783       int val=_fam_nodes->getMaxValue(tmp);
3784       ret=std::max(ret,val);
3785     }
3786   if((const DataArrayInt *)_fam_cells)
3787     {
3788       int val=_fam_cells->getMaxValue(tmp);
3789       ret=std::max(ret,val);
3790     }
3791   return ret;
3792 }
3793
3794 int MEDFileStructuredMesh::getMinFamilyIdInArrays() const throw(INTERP_KERNEL::Exception)
3795 {
3796   int ret=std::numeric_limits<int>::max(),tmp=-1;
3797   if((const DataArrayInt *)_fam_nodes)
3798     {
3799       int val=_fam_nodes->getMinValue(tmp);
3800       ret=std::min(ret,val);
3801     }
3802   if((const DataArrayInt *)_fam_cells)
3803     {
3804       int val=_fam_cells->getMinValue(tmp);
3805       ret=std::min(ret,val);
3806     }
3807   return ret;
3808 }
3809
3810 bool MEDFileStructuredMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const
3811 {
3812   if(!MEDFileMesh::isEqual(other,eps,what))
3813     return false;
3814   const MEDFileStructuredMesh *otherC=dynamic_cast<const  MEDFileStructuredMesh *>(other);
3815   if(!otherC)
3816     {
3817       what="Mesh types differ ! This is structured and other is NOT !";
3818       return false;
3819     }
3820   const DataArrayInt *famc1=_fam_nodes;
3821   const DataArrayInt *famc2=otherC->_fam_nodes;
3822   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
3823     {
3824       what="Mismatch of families arr on nodes ! One is defined and not other !";
3825       return false;
3826     }
3827   if(famc1)
3828     {
3829       bool ret=famc1->isEqual(*famc2);
3830       if(!ret)
3831         {
3832           what="Families arr on nodes differ !";
3833           return false;
3834         }
3835     }
3836   famc1=_fam_cells;
3837   famc2=otherC->_fam_cells;
3838   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
3839     {
3840       what="Mismatch of families arr on cells ! One is defined and not other !";
3841       return false;
3842     }
3843   if(famc1)
3844     {
3845       bool ret=famc1->isEqual(*famc2);
3846       if(!ret)
3847         {
3848           what="Families arr on cells differ !";
3849           return false;
3850         }
3851     }
3852   famc1=_num_nodes;
3853   famc2=otherC->_num_nodes;
3854   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
3855     {
3856       what="Mismatch of numbering arr on nodes ! One is defined and not other !";
3857       return false;
3858     }
3859   if(famc1)
3860     {
3861       bool ret=famc1->isEqual(*famc2);
3862       if(!ret)
3863         {
3864           what="Numbering arr on nodes differ !";
3865           return false;
3866         }
3867     }
3868   famc1=_num_cells;
3869   famc2=otherC->_num_cells;
3870   if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0))
3871     {
3872       what="Mismatch of numbering arr on cells ! One is defined and not other !";
3873       return false;
3874     }
3875   if(famc1)
3876     {
3877       bool ret=famc1->isEqual(*famc2);
3878       if(!ret)
3879         {
3880           what="Numbering arr on cells differ !";
3881           return false;
3882         }
3883     }
3884   const DataArrayAsciiChar *d1=_names_cells;
3885   const DataArrayAsciiChar *d2=otherC->_names_cells;
3886   if((d1==0 && d2!=0) || (d1!=0 && d2==0))
3887     {
3888       what="Mismatch of naming arr on cells ! One is defined and not other !";
3889       return false;
3890     }
3891   if(d1)
3892     {
3893       bool ret=d1->isEqual(*d2);
3894       if(!ret)
3895         {
3896           what="Naming arr on cells differ !";
3897           return false;
3898         }
3899     }
3900   d1=_names_nodes;
3901   d2=otherC->_names_nodes;
3902   if((d1==0 && d2!=0) || (d1!=0 && d2==0))
3903     {
3904       what="Mismatch of naming arr on nodes ! One is defined and not other !";
3905       return false;
3906     }
3907   if(d1)
3908     {
3909       bool ret=d1->isEqual(*d2);
3910       if(!ret)
3911         {
3912           what="Naming arr on nodes differ !";
3913           return false;
3914         }
3915     }
3916   return true;
3917 }
3918
3919 void MEDFileStructuredMesh::clearNonDiscrAttributes() const
3920 {
3921   MEDFileMesh::clearNonDiscrAttributes();
3922   const DataArrayInt *tmp=_fam_nodes;
3923   if(tmp)
3924     (const_cast<DataArrayInt *>(tmp))->setName("");
3925   tmp=_num_nodes;
3926   if(tmp)
3927     (const_cast<DataArrayInt *>(tmp))->setName("");
3928   tmp=_fam_cells;
3929   if(tmp)
3930     (const_cast<DataArrayInt *>(tmp))->setName("");
3931   tmp=_num_cells;
3932   if(tmp)
3933     (const_cast<DataArrayInt *>(tmp))->setName("");
3934 }
3935
3936 /*!
3937  * Returns ids of mesh entities contained in given families of a given dimension.
3938  *  \param [in] meshDimRelToMaxExt - a relative dimension of the mesh entities whose ids
3939  *          are required.
3940  *  \param [in] fams - the names of the families of interest.
3941  *  \param [in] renum - if \c true, the optional numbers of entities, if available, are
3942  *          returned instead of ids.
3943  *  \return DataArrayInt * - a new instance of DataArrayInt holding either ids or
3944  *          numbers, if available and required, of mesh entities of the families. The caller
3945  *          is to delete this array using decrRef() as it is no more needed. 
3946  *  \throw If the family field is missing for \a meshDimRelToMaxExt.
3947  */
3948 DataArrayInt *MEDFileStructuredMesh::getFamiliesArr(int meshDimRelToMaxExt, const std::vector<std::string>& fams, bool renum) const throw(INTERP_KERNEL::Exception)
3949 {
3950   if(meshDimRelToMaxExt!=0 && meshDimRelToMaxExt!=1)
3951     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamiliesArr : Only available for levels 0 or 1 !");
3952   std::vector<int> famIds=getFamiliesIds(fams);
3953   if(meshDimRelToMaxExt==1)
3954     {
3955       if((const DataArrayInt *)_fam_nodes)
3956         {
3957           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da;
3958           if(!famIds.empty())
3959             da=_fam_nodes->getIdsEqualList(&famIds[0],&famIds[0]+famIds.size());
3960           else
3961             da=_fam_nodes->getIdsEqualList(0,0);
3962           if(renum)
3963             return MEDFileUMeshSplitL1::Renumber(_num_nodes,da);
3964           else
3965             return da.retn();
3966         }
3967       else
3968         throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamiliesArr : no family array specified on nodes !");
3969     }
3970   else
3971     {
3972       if((const DataArrayInt *)_fam_cells)
3973         {
3974           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da;
3975           if(!famIds.empty())
3976             da=_fam_cells->getIdsEqualList(&famIds[0],&famIds[0]+famIds.size());
3977           else
3978             da=_fam_cells->getIdsEqualList(0,0);
3979           if(renum)
3980             return MEDFileUMeshSplitL1::Renumber(_num_cells,da);
3981           else
3982             return da.retn();
3983         }
3984       else
3985         throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamiliesArr : no family array specified on cells !");
3986     }
3987 }
3988
3989 /*!
3990  * Sets the family field of a given relative dimension.
3991  *  \param [in] meshDimRelToMaxExt - the relative dimension of entities for which
3992  *          the family field is set.
3993  *  \param [in] famArr - the array of the family field.
3994  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
3995  *  \throw If \a famArr has an invalid size.
3996  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1.
3997  */
3998 void MEDFileStructuredMesh::setFamilyFieldArr(int meshDimRelToMaxExt, DataArrayInt *famArr) throw(INTERP_KERNEL::Exception)
3999 {
4000   if(meshDimRelToMaxExt!=0 && meshDimRelToMaxExt!=1)
4001     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setRenumFieldArr : Only available for levels 0 or 1 !");
4002   const MEDCouplingStructuredMesh *mesh=getStructuredMesh();
4003   if(!mesh)
4004     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setFamilyFieldArr : no structured mesh specified ! Impossible to set family array !");
4005   if(meshDimRelToMaxExt==0)
4006     {
4007       int nbCells=mesh->getNumberOfCells();
4008       famArr->checkNbOfTuplesAndComp(nbCells,1,"MEDFileStructuredMesh::setFamilyFieldArr : Problem in size of Family arr ! Mismatch with number of cells of mesh !");
4009       _fam_cells=famArr;
4010     }
4011   else
4012     {
4013       int nbNodes=mesh->getNumberOfNodes();
4014       famArr->checkNbOfTuplesAndComp(nbNodes,1,"MEDFileStructuredMesh::setFamilyFieldArr : Problem in size of Family arr ! Mismatch with number of nodes of mesh !");
4015       _fam_nodes=famArr;
4016     }
4017   if(famArr)
4018     famArr->incrRef();
4019 }
4020
4021 /*!
4022  * Sets the optional numbers of mesh entities of a given dimension.
4023  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
4024  *  \param [in] renumArr - the array of the numbers.
4025  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
4026  *  \throw If \a renumArr has an invalid size.
4027  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1.
4028  */
4029 void MEDFileStructuredMesh::setRenumFieldArr(int meshDimRelToMaxExt, DataArrayInt *renumArr) throw(INTERP_KERNEL::Exception)
4030 {
4031   if(meshDimRelToMaxExt!=0 && meshDimRelToMaxExt!=1)
4032     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setRenumFieldArr : Only available for levels 0 or 1 !");
4033   const MEDCouplingStructuredMesh *mesh=getStructuredMesh();
4034   if(!mesh)
4035     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setRenumFieldArr : no structured mesh specified ! Impossible to set number array !");
4036   if(meshDimRelToMaxExt==0)
4037     {
4038       int nbCells=mesh->getNumberOfCells();
4039       renumArr->checkNbOfTuplesAndComp(nbCells,1,"MEDFileStructuredMesh::setRenumFieldArr : Problem in size of Renum arr ! Mismatch with number of cells of mesh !");
4040       _num_cells=renumArr;
4041     }
4042   else
4043     {
4044       int nbNodes=mesh->getNumberOfNodes();
4045       renumArr->checkNbOfTuplesAndComp(nbNodes,1,"MEDFileStructuredMesh::setRenumFieldArr : Problem in size of Family arr ! Mismatch with number of nodes of mesh !");
4046       _num_nodes=renumArr;
4047     }
4048   if(renumArr)
4049     renumArr->incrRef();
4050 }
4051
4052 /*!
4053  * Sets the optional names of mesh entities of a given dimension.
4054  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
4055  *  \param [in] nameArr - the array of the names.
4056  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
4057  *  \throw If \a nameArr has an invalid size.
4058  */
4059 void MEDFileStructuredMesh::setNameFieldAtLevel(int meshDimRelToMaxExt, DataArrayAsciiChar *nameArr) throw(INTERP_KERNEL::Exception)
4060 {
4061   if(meshDimRelToMaxExt!=0 && meshDimRelToMaxExt!=1)
4062     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setNameFieldAtLevel : Only available for levels 0 or 1 !");
4063   const MEDCouplingStructuredMesh *mesh=getStructuredMesh();
4064   if(!mesh)
4065     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setNameFieldAtLevel : no structured mesh specified ! Impossible to set names array !");
4066   if(meshDimRelToMaxExt==0)
4067     {
4068       int nbCells=mesh->getNumberOfCells();
4069       nameArr->checkNbOfTuplesAndComp(nbCells,MED_SNAME_SIZE,"MEDFileStructuredMesh::setNameFieldAtLevel : Problem in size of names arr ! Mismatch with number of cells of mesh !");
4070       _names_cells=nameArr;
4071     }
4072   else
4073     {
4074       int nbNodes=mesh->getNumberOfNodes();
4075       nameArr->checkNbOfTuplesAndComp(nbNodes,MED_SNAME_SIZE,"MEDFileStructuredMesh::setNameFieldAtLevel : Problem in size of names arr ! Mismatch with number of nodes of mesh !");
4076       _names_nodes=nameArr;
4077     }
4078   if(nameArr)
4079     nameArr->incrRef();
4080 }
4081
4082 /*!
4083  * Returns the family field for mesh entities of a given dimension.
4084  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
4085  *  \return const DataArrayInt * - the family field. It is an array of ids of families
4086  *          each mesh entity belongs to. It can be \c NULL.
4087  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1.
4088  */
4089 const DataArrayInt *MEDFileStructuredMesh::getFamilyFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
4090 {
4091   if(meshDimRelToMaxExt!=0 && meshDimRelToMaxExt!=1)
4092     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getFamilyFieldAtLevel : Only available for levels 0 or 1 !");
4093   if(meshDimRelToMaxExt==0)
4094     return _fam_cells;
4095   else
4096     return _fam_nodes;
4097 }
4098
4099 /*!
4100  * Returns the optional numbers of mesh entities of a given dimension.
4101  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
4102  *  \return const DataArrayInt * - the array of the entity numbers.
4103  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
4104  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1.
4105  */
4106 const DataArrayInt *MEDFileStructuredMesh::getNumberFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
4107 {
4108   if(meshDimRelToMaxExt!=0 && meshDimRelToMaxExt!=1)
4109     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getNumberFieldAtLevel : Only available for levels 0 or 1 !");
4110   if(meshDimRelToMaxExt==0)
4111     return _num_cells;
4112   else
4113     return _num_nodes;
4114 }
4115
4116 /*!
4117  * Returns the optional numbers of mesh entities of a given dimension transformed using
4118  * DataArrayInt::invertArrayN2O2O2N().
4119  *  \param [in] meshDimRelToMaxExt - the relative dimension of mesh entities.
4120  *  \return const DataArrayInt * - the array of the entity numbers transformed using
4121  *          DataArrayInt::invertArrayN2O2O2N().
4122  *  \throw If \a meshDimRelToMaxExt != 0 and \a meshDimRelToMaxExt != 1.
4123  *  \throw If there are no mesh entities of \a meshDimRelToMaxExt dimension in \a this mesh.
4124  */
4125 const DataArrayInt *MEDFileStructuredMesh::getRevNumberFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
4126 {
4127   if(meshDimRelToMaxExt!=0 && meshDimRelToMaxExt!=1)
4128     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getRevNumberFieldAtLevel : Only available for levels 0 or 1 !");
4129   if(meshDimRelToMaxExt==0)
4130     {
4131       if((const DataArrayInt *)_num_cells)
4132         {
4133           int pos;
4134           int maxValue=_num_cells->getMaxValue(pos);
4135           _rev_num_cells=_num_cells->invertArrayN2O2O2N(maxValue+1);
4136           return _rev_num_cells;
4137         }
4138       else
4139         throw INTERP_KERNEL::Exception("MEDFileCMesh::getRevNumberFieldAtLevel : no cell renumbering for a request on reverse numbering !");
4140     }
4141   else
4142     {
4143       if((const DataArrayInt *)_num_nodes)
4144         {
4145           int pos;
4146           int maxValue=_num_nodes->getMaxValue(pos);
4147           _rev_num_nodes=_num_nodes->invertArrayN2O2O2N(maxValue+1);
4148           return _rev_num_nodes;
4149         }
4150       else
4151         throw INTERP_KERNEL::Exception("MEDFileCMesh::getRevNumberFieldAtLevel : no node renumbering for a request on reverse numbering !");
4152     }
4153 }
4154
4155 const DataArrayAsciiChar *MEDFileStructuredMesh::getNameFieldAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
4156 {
4157   if(meshDimRelToMaxExt!=0 && meshDimRelToMaxExt!=1)
4158     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getNameFieldAtLevel : Only available for levels 0 or 1 !");
4159   if(meshDimRelToMaxExt==0)
4160     return _names_cells;
4161   else
4162     return _names_nodes;
4163 }
4164
4165 /*!
4166  * Returns relative dimensions of mesh entities (excluding nodes) present in \a this mesh.
4167  *  \return std::vector<int> - a sequence of the relative dimensions: [0].
4168  */
4169 std::vector<int> MEDFileStructuredMesh::getNonEmptyLevels() const
4170 {
4171   std::vector<int> ret(1);
4172   return ret;
4173 }
4174
4175 /*!
4176  * Returns relative dimensions of mesh entities (including nodes) present in \a this mesh.
4177  *  \return std::vector<int> - a sequence of the relative dimensions: [1,0].
4178  */
4179 std::vector<int> MEDFileStructuredMesh::getNonEmptyLevelsExt() const
4180 {
4181   std::vector<int> ret(2);
4182   ret[0]=1;
4183   return ret;
4184 }
4185
4186 /*!
4187  * Returns the set of extensive levels (nodes included) where not NULL family arr are defined.
4188  */
4189 std::vector<int> MEDFileStructuredMesh::getFamArrNonEmptyLevelsExt() const
4190 {
4191   std::vector<int> ret;
4192   const DataArrayInt *famNodes(_fam_nodes),*famCells(_fam_cells);
4193   if(famNodes)
4194     ret.push_back(1);
4195   if(famCells)
4196     ret.push_back(0);
4197   return ret;
4198 }
4199
4200 /*!
4201  * Returns the set of extensive levels (nodes included) where not NULL numbering arr are defined.
4202  */
4203 std::vector<int> MEDFileStructuredMesh::getNumArrNonEmptyLevelsExt() const
4204 {
4205   std::vector<int> ret;
4206   const DataArrayInt *numNodes(_num_nodes),*numCells(_num_cells);
4207   if(numNodes)
4208     ret.push_back(1);
4209   if(numCells)
4210     ret.push_back(0);
4211   return ret;
4212 }
4213
4214 /*!
4215  * Returns the set of extensive levels (nodes included) where not NULL naming arr are defined.
4216  */
4217 std::vector<int> MEDFileStructuredMesh::getNameArrNonEmptyLevelsExt() const
4218 {
4219   std::vector<int> ret;
4220   const DataArrayAsciiChar *namesCells(_names_cells);
4221   if(namesCells)
4222     ret.push_back(0);
4223   return ret;
4224 }
4225
4226 /*!
4227  * no implementation here, it is not a bug, but intresically no polyhedra in \a this.
4228  */
4229 bool MEDFileStructuredMesh::unPolyze(std::vector<int>& oldCode, std::vector<int>& newCode, DataArrayInt *& o2nRenumCell) throw(INTERP_KERNEL::Exception)
4230 {
4231   oldCode.clear(); newCode.clear(); o2nRenumCell=0;
4232   return false;
4233 }
4234
4235 void MEDFileStructuredMesh::changeFamilyIdArr(int oldId, int newId) throw(INTERP_KERNEL::Exception)
4236 {
4237   DataArrayInt *arr=_fam_nodes;
4238   if(arr)
4239     arr->changeValue(oldId,newId);
4240   arr=_fam_cells;
4241   if(arr)
4242     arr->changeValue(oldId,newId);
4243 }
4244
4245 void MEDFileStructuredMesh::deepCpyAttributes() throw(INTERP_KERNEL::Exception)
4246 {
4247   if((const DataArrayInt*)_fam_nodes)
4248     _fam_nodes=_fam_nodes->deepCpy();
4249   if((const DataArrayInt*)_num_nodes)
4250     _num_nodes=_num_nodes->deepCpy();
4251   if((const DataArrayInt*)_fam_cells)
4252     _fam_cells=_fam_cells->deepCpy();
4253   if((const DataArrayInt*)_num_cells)
4254     _num_cells=_num_cells->deepCpy();
4255   if((const DataArrayInt*)_rev_num_nodes)
4256     _rev_num_nodes=_rev_num_nodes->deepCpy();
4257   if((const DataArrayInt*)_rev_num_cells)
4258     _rev_num_cells=_rev_num_cells->deepCpy();
4259 }
4260
4261 /*!
4262  * Returns a pointer to mesh at the specified level (here 0 is compulsary for cartesian mesh).
4263  * 
4264  * \return a pointer to cartesian mesh that need to be managed by the caller.
4265  * \warning the returned pointer has to be managed by the caller.
4266  */
4267
4268 /*!
4269  * Returns a pointer to MEDCouplingStructuredMesh held by \a this. 
4270  *  \param [in] meshDimRelToMax - it must be \c 0.
4271  *  \param [in] renum - it must be \c false.
4272  *  \return MEDCouplingMesh * - a pointer to MEDCouplingMesh that the caller is to
4273  *          delete using decrRef() as it is no more needed. 
4274  */
4275 MEDCouplingMesh *MEDFileStructuredMesh::getGenMeshAtLevel(int meshDimRelToMax, bool renum) const throw(INTERP_KERNEL::Exception)
4276 {
4277   if(renum)
4278     throw INTERP_KERNEL::Exception("MEDFileCurveLinearMesh does not support renumbering ! To do it perform request of renum array directly !");
4279   if(meshDimRelToMax!=0)
4280     throw INTERP_KERNEL::Exception("MEDFileCurveLinearMesh does not support multi level for mesh 0 expected as input !");
4281   const MEDCouplingStructuredMesh *m=getStructuredMesh();
4282   if(m)
4283     m->incrRef();
4284   return const_cast<MEDCouplingStructuredMesh *>(m);
4285 }
4286
4287 /*!
4288  * Returns number of mesh entities of a given relative dimension in \a this mesh.
4289  *  \param [in] meshDimRelToMaxExt - the relative dimension of interest.
4290  *  \return int - the number of entities.
4291  *  \throw If no mesh entities of dimension \a meshDimRelToMaxExt are available in \a this mesh.
4292  */
4293 int MEDFileStructuredMesh::getSizeAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception)
4294 {
4295   if(meshDimRelToMaxExt!=0 && meshDimRelToMaxExt!=1)
4296     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getSizeAtLevel : Only available for levels 0 or 1 !");
4297   const MEDCouplingStructuredMesh *cmesh=getStructuredMesh();
4298   if(!cmesh)
4299     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getSizeAtLevel : No structured mesh set !");
4300   if(meshDimRelToMaxExt==0)
4301     return cmesh->getNumberOfCells();
4302   else
4303     return cmesh->getNumberOfNodes();
4304 }
4305
4306 int MEDFileStructuredMesh::getNumberOfNodes() const throw(INTERP_KERNEL::Exception)
4307 {
4308   const MEDCouplingStructuredMesh *cmesh=getStructuredMesh();
4309   if(!cmesh)
4310     throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getNumberOfNodes : no cartesian mesh set !");
4311   return cmesh->getNumberOfNodes();
4312 }
4313
4314 med_geometry_type MEDFileStructuredMesh::GetGeoTypeFromMeshDim(int meshDim) throw(INTERP_KERNEL::Exception)
4315 {
4316   med_geometry_type geoTypeReq=MED_NONE;
4317   switch(meshDim)
4318     {
4319     case 3:
4320       geoTypeReq=MED_HEXA8;
4321       break;
4322     case 2:
4323       geoTypeReq=MED_QUAD4;
4324       break;
4325     case 1:
4326       geoTypeReq=MED_SEG2;
4327       break;
4328     case 0:
4329       geoTypeReq=MED_POINT1;
4330       break;
4331     default:
4332       throw INTERP_KERNEL::Exception("Invalid meshdim detected for structured mesh ! Must be in (1,2,3) !");
4333     }
4334   return geoTypeReq;
4335 }
4336
4337 void MEDFileStructuredMesh::loadStrMeshFromFile(MEDFileStrMeshL2 *strm, med_idt fid, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
4338 {
4339   setName(strm->getName());
4340   setDescription(strm->getDescription());
4341   setUnivName(strm->getUnivName());
4342   setIteration(strm->getIteration());
4343   setOrder(strm->getOrder());
4344   setTimeValue(strm->getTime());
4345   setTimeUnit(strm->getTimeUnit());
4346   MEDFileMeshL2::ReadFamiliesAndGrps(fid,mName,_families,_groups,mrs);
4347   med_bool chgt=MED_FALSE,trsf=MED_FALSE;
4348   int nbOfElt=MEDmeshnEntity(fid,mName,dt,it,MED_NODE,MED_NONE,MED_FAMILY_NUMBER,MED_NODAL,&chgt,&trsf);
4349   if(nbOfElt>0)
4350     {
4351       if(!mrs || mrs->isNodeFamilyFieldReading())
4352         {
4353           _fam_nodes=DataArrayInt::New();
4354           _fam_nodes->alloc(nbOfElt,1);
4355           MEDmeshEntityFamilyNumberRd(fid,mName,dt,it,MED_NODE,MED_NONE,_fam_nodes->getPointer());
4356         }
4357     }
4358   nbOfElt=MEDmeshnEntity(fid,mName,dt,it,MED_NODE,MED_NONE,MED_NUMBER,MED_NODAL,&chgt,&trsf);
4359   if(nbOfElt>0)
4360     {
4361       if(!mrs || mrs->isNodeNumFieldReading())
4362         {
4363           _num_nodes=DataArrayInt::New();
4364           _num_nodes->alloc(nbOfElt,1);
4365           MEDmeshEntityNumberRd(fid,mName,dt,it,MED_NODE,MED_NONE,_num_nodes->getPointer());
4366         }
4367     }
4368   int meshDim=getStructuredMesh()->getMeshDimension();
4369   med_geometry_type geoTypeReq=GetGeoTypeFromMeshDim(meshDim);
4370   nbOfElt=MEDmeshnEntity(fid,mName,dt,it,MED_CELL,geoTypeReq,MED_FAMILY_NUMBER,MED_NODAL,&chgt,&trsf);
4371   if(nbOfElt>0)
4372     {
4373       if(!mrs || mrs->isCellFamilyFieldReading())
4374         {
4375           _fam_cells=DataArrayInt::New();
4376           _fam_cells->alloc(nbOfElt,1);
4377           MEDmeshEntityFamilyNumberRd(fid,mName,dt,it,MED_CELL,geoTypeReq,_fam_cells->getPointer());
4378         }
4379     }
4380   nbOfElt=MEDmeshnEntity(fid,mName,dt,it,MED_CELL,geoTypeReq,MED_NUMBER,MED_NODAL,&chgt,&trsf);
4381   if(nbOfElt>0)
4382     {
4383       if(!mrs || mrs->isCellNumFieldReading())
4384         {
4385           _num_cells=DataArrayInt::New();
4386           _num_cells->alloc(nbOfElt,1);
4387           MEDmeshEntityNumberRd(fid,mName,dt,it,MED_CELL,geoTypeReq,_num_cells->getPointer());
4388         }
4389     }
4390   nbOfElt=MEDmeshnEntity(fid,mName,dt,it,MED_CELL,geoTypeReq,MED_NAME,MED_NODAL,&chgt,&trsf);
4391   if(nbOfElt>0)
4392     {
4393       if(!mrs || mrs->isCellNameFieldReading())
4394         {
4395           _names_cells=DataArrayAsciiChar::New();
4396           _names_cells->alloc(nbOfElt+1,MED_SNAME_SIZE);//not a bug to avoid the memory corruption due to last \0 at the end
4397           MEDmeshEntityNameRd(fid,mName,dt,it,MED_CELL,geoTypeReq,_names_cells->getPointer());
4398           _names_cells->reAlloc(nbOfElt);//not a bug to avoid the memory corruption due to last \0 at the end
4399         }
4400     }
4401   nbOfElt=MEDmeshnEntity(fid,mName,dt,it,MED_NODE,MED_NONE,MED_NAME,MED_NODAL,&chgt,&trsf);
4402   if(nbOfElt>0)
4403     {
4404       if(!mrs || mrs->isNodeNameFieldReading())
4405         {
4406           _names_nodes=DataArrayAsciiChar::New();
4407           _names_nodes->alloc(nbOfElt+1,MED_SNAME_SIZE);//not a bug to avoid the memory corruption due to last \0 at the end
4408           MEDmeshEntityNameRd(fid,mName,dt,it,MED_NODE,MED_NONE,_names_nodes->getPointer());
4409           _names_nodes->reAlloc(nbOfElt);//not a bug to avoid the memory corruption due to last \0 at the end
4410         }
4411     }
4412 }
4413
4414 void MEDFileStructuredMesh::writeStructuredLL(med_idt fid, const char *maa) const throw(INTERP_KERNEL::Exception)
4415 {
4416   int meshDim=getStructuredMesh()->getMeshDimension();
4417   med_geometry_type geoTypeReq=GetGeoTypeFromMeshDim(meshDim);
4418   //
4419   if((const DataArrayInt *)_fam_cells)
4420     MEDmeshEntityFamilyNumberWr(fid,maa,_iteration,_order,MED_CELL,geoTypeReq,_fam_cells->getNumberOfTuples(),_fam_cells->getConstPointer());
4421   if((const DataArrayInt *)_fam_nodes)
4422     MEDmeshEntityFamilyNumberWr(fid,maa,_iteration,_order,MED_NODE,MED_NONE,_fam_nodes->getNumberOfTuples(),_fam_nodes->getConstPointer());
4423   if((const DataArrayInt *)_num_cells)
4424     MEDmeshEntityNumberWr(fid,maa,_iteration,_order,MED_CELL,geoTypeReq,_num_cells->getNumberOfTuples(),_num_cells->getConstPointer());
4425   if((const DataArrayInt *)_num_nodes)
4426     MEDmeshEntityNumberWr(fid,maa,_iteration,_order,MED_NODE,MED_NONE,_num_nodes->getNumberOfTuples(),_num_nodes->getConstPointer());
4427   if((const DataArrayAsciiChar *)_names_cells)
4428     {
4429       if(_names_cells->getNumberOfComponents()!=MED_SNAME_SIZE)
4430         {
4431           std::ostringstream oss; oss << "MEDFileStructuredMesh::writeStructuredLL : expected a name field on cells with number of components set to " << MED_SNAME_SIZE;
4432           oss << " ! The array has " << _names_cells->getNumberOfComponents() << " components !";
4433           throw INTERP_KERNEL::Exception(oss.str().c_str());
4434         }
4435       MEDmeshEntityNameWr(fid,maa,_iteration,_order,MED_CELL,geoTypeReq,_names_cells->getNumberOfTuples(),_names_cells->getConstPointer());
4436     }
4437   if((const DataArrayAsciiChar *)_names_nodes)
4438     {
4439       if(_names_nodes->getNumberOfComponents()!=MED_SNAME_SIZE)
4440         {
4441           std::ostringstream oss; oss << "MEDFileStructuredMesh::writeStructuredLL : expected a name field on nodes with number of components set to " << MED_SNAME_SIZE;
4442           oss << " ! The array has " << _names_cells->getNumberOfComponents() << " components !";
4443           throw INTERP_KERNEL::Exception(oss.str().c_str());
4444         }
4445       MEDmeshEntityNameWr(fid,maa,_iteration,_order,MED_NODE,MED_NONE,_names_nodes->getNumberOfTuples(),_names_nodes->getConstPointer());
4446     }
4447   //
4448   MEDFileUMeshL2::WriteFamiliesAndGrps(fid,maa,_families,_groups,_too_long_str);
4449 }
4450
4451 /*!
4452  * Returns an empty instance of MEDFileCMesh.
4453  *  \return MEDFileCMesh * - a new instance of MEDFileCMesh. The caller is to delete this
4454  *          mesh using decrRef() as it is no more needed. 
4455  */
4456 MEDFileCMesh *MEDFileCMesh::New()
4457 {
4458   return new MEDFileCMesh;
4459 }
4460
4461 /*!
4462  * Returns a new MEDFileCMesh holding the mesh data that has been read from a given MED
4463  * file. The first mesh in the file is loaded.
4464  *  \param [in] fileName - the name of MED file to read.
4465  *  \return MEDFileCMesh * - a new instance of MEDFileCMesh. The caller is to delete this
4466  *          mesh using decrRef() as it is no more needed. 
4467  *  \throw If the file is not readable.
4468  *  \throw If there is no meshes in the file.
4469  *  \throw If the mesh in the file is not a Cartesian one.
4470  */
4471 MEDFileCMesh *MEDFileCMesh::New(const char *fileName, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
4472 {
4473   std::vector<std::string> ms=MEDLoader::GetMeshNames(fileName);
4474   if(ms.empty())
4475     {
4476       std::ostringstream oss; oss << "MEDFileUMesh::New : no meshes in file \"" << fileName << "\" !";
4477       throw INTERP_KERNEL::Exception(oss.str().c_str());
4478     }
4479   MEDFileUtilities::CheckFileForRead(fileName);
4480   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,MED_ACC_RDONLY);
4481   int dt,it;
4482   ParaMEDMEM::MEDCouplingMeshType meshType;
4483   std::string dummy2;
4484   MEDFileMeshL2::GetMeshIdFromName(fid,ms.front().c_str(),meshType,dt,it,dummy2);
4485   return new MEDFileCMesh(fid,ms.front().c_str(),dt,it,mrs);
4486 }
4487
4488 /*!
4489  * Returns a new MEDFileCMesh holding the mesh data that has been read from a given MED
4490  * file. The mesh to load is specified by its name and numbers of a time step and an
4491  * iteration.
4492  *  \param [in] fileName - the name of MED file to read.
4493  *  \param [in] mName - the name of the mesh to read.
4494  *  \param [in] dt - the number of a time step.
4495  *  \param [in] it - the number of an iteration.
4496  *  \return MEDFileCMesh * - a new instance of MEDFileCMesh. The caller is to delete this
4497  *          mesh using decrRef() as it is no more needed. 
4498  *  \throw If the file is not readable.
4499  *  \throw If there is no mesh with given attributes in the file.
4500  *  \throw If the mesh in the file is not a Cartesian one.
4501  */
4502 MEDFileCMesh *MEDFileCMesh::New(const char *fileName, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
4503 {
4504   MEDFileUtilities::CheckFileForRead(fileName);
4505   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,MED_ACC_RDONLY);
4506   return new MEDFileCMesh(fid,mName,dt,it,mrs);
4507 }
4508
4509 std::size_t MEDFileCMesh::getHeapMemorySize() const
4510 {
4511   std::size_t ret=MEDFileStructuredMesh::getHeapMemorySize();
4512   if((const MEDCouplingCMesh *)_cmesh)
4513     ret+=_cmesh->getHeapMemorySize();
4514   return ret;
4515 }
4516
4517 /*!
4518  * Returns the dimension on cells in \a this mesh.
4519  *  \return int - the mesh dimension.
4520  *  \throw If there are no cells in this mesh.
4521  */
4522 int MEDFileCMesh::getMeshDimension() const throw(INTERP_KERNEL::Exception)
4523 {
4524   if(!((const MEDCouplingCMesh*)_cmesh))
4525     throw INTERP_KERNEL::Exception("MEDFileCMesh::getMeshDimension : unable to get meshdimension because no mesh set !");
4526   return _cmesh->getMeshDimension();
4527 }
4528
4529 /*!
4530  * Returns a string describing \a this mesh.
4531  *  \return std::string - the mesh information string.
4532  */
4533 std::string MEDFileCMesh::simpleRepr() const
4534 {
4535   return MEDFileStructuredMesh::simpleRepr();
4536 }
4537
4538 /*!
4539  * Returns a full textual description of \a this mesh.
4540  *  \return std::string - the string holding the mesh description.
4541  */
4542 std::string MEDFileCMesh::advancedRepr() const
4543 {
4544   return simpleRepr();
4545 }
4546
4547 MEDFileMesh *MEDFileCMesh::shallowCpy() const throw(INTERP_KERNEL::Exception)
4548 {
4549   MEDCouplingAutoRefCountObjectPtr<MEDFileCMesh> ret=new MEDFileCMesh(*this);
4550   return ret.retn();
4551 }
4552
4553 MEDFileMesh *MEDFileCMesh::createNewEmpty() const throw(INTERP_KERNEL::Exception)
4554 {
4555   return new MEDFileCMesh;
4556 }
4557
4558 MEDFileMesh *MEDFileCMesh::deepCpy() const throw(INTERP_KERNEL::Exception)
4559 {
4560   MEDCouplingAutoRefCountObjectPtr<MEDFileCMesh> ret=new MEDFileCMesh(*this);
4561   if((const MEDCouplingCMesh*)_cmesh)
4562     ret->_cmesh=static_cast<MEDCouplingCMesh*>(_cmesh->deepCpy());
4563   ret->deepCpyAttributes();
4564   return ret.retn();
4565 }
4566
4567 /*!
4568  * Checks if \a this and another mesh are equal.
4569  *  \param [in] other - the mesh to compare with.
4570  *  \param [in] eps - a precision used to compare real values.
4571  *  \param [in,out] what - the string returning description of unequal data.
4572  *  \return bool - \c true if the meshes are equal, \c false, else.
4573  */
4574 bool MEDFileCMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const
4575 {
4576   if(!MEDFileStructuredMesh::isEqual(other,eps,what))
4577     return false;
4578   const MEDFileCMesh *otherC=dynamic_cast<const MEDFileCMesh *>(other);
4579   if(!otherC)
4580     {
4581       what="Mesh types differ ! This is cartesian and other is NOT !";
4582       return false;
4583     }
4584   clearNonDiscrAttributes();
4585   otherC->clearNonDiscrAttributes();
4586   const MEDCouplingCMesh *coo1=_cmesh;
4587   const MEDCouplingCMesh *coo2=otherC->_cmesh;
4588   if((coo1==0 && coo2!=0) || (coo1!=0 && coo2==0))
4589     {
4590       what="Mismatch of cartesian meshes ! One is defined and not other !";
4591       return false;
4592     }
4593   if(coo1)
4594     {
4595       bool ret=coo1->isEqual(coo2,eps);
4596       if(!ret)
4597         {
4598           what="cartesian meshes differ !";
4599           return false;
4600         }
4601     }
4602   return true;
4603 }
4604
4605 /*!
4606  * Clears redundant attributes of incorporated data arrays.
4607  */
4608 void MEDFileCMesh::clearNonDiscrAttributes() const
4609 {
4610   MEDFileStructuredMesh::clearNonDiscrAttributes();
4611   MEDFileUMeshSplitL1::ClearNonDiscrAttributes(_cmesh);//to it is not a bug umeshsplit have already the method implemented
4612 }
4613
4614 MEDFileCMesh::MEDFileCMesh()
4615 {
4616 }
4617
4618 MEDFileCMesh::MEDFileCMesh(med_idt fid, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
4619 try
4620   {
4621     loadCMeshFromFile(fid,mName,dt,it,mrs);
4622   }
4623 catch(INTERP_KERNEL::Exception& e)
4624   {
4625     throw e;
4626   }
4627
4628 void MEDFileCMesh::loadCMeshFromFile(med_idt fid, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
4629 {
4630   ParaMEDMEM::MEDCouplingMeshType meshType;
4631   int dummy0,dummy1;
4632   std::string dtunit;
4633   int mid=MEDFileMeshL2::GetMeshIdFromName(fid,mName,meshType,dummy0,dummy1,dtunit);
4634   if(meshType!=CARTESIAN)
4635     {
4636       std::ostringstream oss; oss << "Trying to load as cartesian an existing mesh with name '" << mName << "' that is NOT cartesian !";
4637       throw INTERP_KERNEL::Exception(oss.str().c_str());
4638     }
4639   MEDFileCMeshL2 loaderl2;
4640   loaderl2.loadAll(fid,mid,mName,dt,it);
4641   MEDCouplingCMesh *mesh=loaderl2.getMesh();
4642   mesh->incrRef();
4643   _cmesh=mesh;
4644   loadStrMeshFromFile(&loaderl2,fid,mName,dt,it,mrs);
4645 }
4646
4647 /*!
4648  * Returns a const pointer to MEDCouplingCMesh held by \a this mesh.
4649  *  \return const MEDCouplingCMesh * - a pointer to the held MEDCouplingCMesh.
4650  */
4651 const MEDCouplingCMesh *MEDFileCMesh::getMesh() const
4652 {
4653   synchronizeTinyInfoOnLeaves();
4654   return _cmesh;
4655 }
4656
4657 const MEDCouplingStructuredMesh *MEDFileCMesh::getStructuredMesh() const
4658 {
4659   synchronizeTinyInfoOnLeaves();
4660   return _cmesh;
4661 }
4662
4663 /*!
4664  * Sets the MEDCouplingCMesh holding the data of \a this mesh.
4665  *  \param [in] m - the new MEDCouplingCMesh to refer to.
4666  *  \throw If the name or the description of \a this mesh and \a m are not empty and are
4667  *         different. 
4668  */
4669 void MEDFileCMesh::setMesh(MEDCouplingCMesh *m) throw(INTERP_KERNEL::Exception)
4670 {
4671   dealWithTinyInfo(m);
4672   if(m)
4673     m->incrRef();
4674   _cmesh=m;
4675 }
4676
4677 void MEDFileCMesh::writeLL(med_idt fid) const throw(INTERP_KERNEL::Exception)
4678 {
4679   INTERP_KERNEL::AutoPtr<char> maa=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE);
4680   INTERP_KERNEL::AutoPtr<char> desc=MEDLoaderBase::buildEmptyString(MED_COMMENT_SIZE);
4681   INTERP_KERNEL::AutoPtr<char> dtunit=MEDLoaderBase::buildEmptyString(MED_LNAME_SIZE);
4682   MEDLoaderBase::safeStrCpy(_name.c_str(),MED_NAME_SIZE,maa,_too_long_str);
4683   MEDLoaderBase::safeStrCpy(_desc_name.c_str(),MED_COMMENT_SIZE,desc,_too_long_str);
4684   MEDLoaderBase::safeStrCpy(_dt_unit.c_str(),MED_LNAME_SIZE,dtunit,_too_long_str);
4685   int spaceDim=_cmesh->getSpaceDimension();
4686   int meshDim=_cmesh->getMeshDimension();
4687   INTERP_KERNEL::AutoPtr<char> comp=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
4688   INTERP_KERNEL::AutoPtr<char> unit=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
4689   for(int i=0;i<spaceDim;i++)
4690     {
4691       std::string info(_cmesh->getCoordsAt(i)->getInfoOnComponent(0));
4692       std::string c,u;
4693       MEDLoaderBase::splitIntoNameAndUnit(info,c,u);
4694       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
4695       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
4696     }
4697   MEDmeshCr(fid,maa,spaceDim,meshDim,MED_STRUCTURED_MESH,desc,dtunit,MED_SORT_DTIT,MED_CARTESIAN,comp,unit);
4698   MEDmeshUniversalNameWr(fid,maa);
4699   MEDmeshGridTypeWr(fid,maa,MED_CARTESIAN_GRID);
4700   for(int i=0;i<spaceDim;i++)
4701     {
4702       const DataArrayDouble *da=_cmesh->getCoordsAt(i);
4703       MEDmeshGridIndexCoordinateWr(fid,maa,_iteration,_order,_time,i+1,da->getNumberOfTuples(),da->getConstPointer());
4704     }
4705   //
4706   MEDFileStructuredMesh::writeStructuredLL(fid,maa);
4707 }
4708
4709 void MEDFileCMesh::synchronizeTinyInfoOnLeaves() const
4710 {
4711   const MEDCouplingCMesh *cmesh=_cmesh;
4712   if(!cmesh)
4713     return;
4714   (const_cast<MEDCouplingCMesh *>(cmesh))->setName(_name.c_str());
4715   (const_cast<MEDCouplingCMesh *>(cmesh))->setDescription(_desc_name.c_str());
4716   (const_cast<MEDCouplingCMesh *>(cmesh))->setTime(_time,_iteration,_order);
4717   (const_cast<MEDCouplingCMesh *>(cmesh))->setTimeUnit(_dt_unit.c_str());
4718 }
4719
4720 MEDFileCurveLinearMesh *MEDFileCurveLinearMesh::New()
4721 {
4722   return new MEDFileCurveLinearMesh;
4723 }
4724
4725 MEDFileCurveLinearMesh *MEDFileCurveLinearMesh::New(const char *fileName, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
4726 {
4727   std::vector<std::string> ms=MEDLoader::GetMeshNames(fileName);
4728   if(ms.empty())
4729     {
4730       std::ostringstream oss; oss << "MEDFileUMesh::New : no meshes in file \"" << fileName << "\" !";
4731       throw INTERP_KERNEL::Exception(oss.str().c_str());
4732     }
4733   MEDFileUtilities::CheckFileForRead(fileName);
4734   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,MED_ACC_RDONLY);
4735   int dt,it;
4736   ParaMEDMEM::MEDCouplingMeshType meshType;
4737   std::string dummy2;
4738   MEDFileMeshL2::GetMeshIdFromName(fid,ms.front().c_str(),meshType,dt,it,dummy2);
4739   return new MEDFileCurveLinearMesh(fid,ms.front().c_str(),dt,it,mrs);
4740 }
4741
4742 MEDFileCurveLinearMesh *MEDFileCurveLinearMesh::New(const char *fileName, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
4743 {
4744   MEDFileUtilities::CheckFileForRead(fileName);
4745   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,MED_ACC_RDONLY);
4746   return new MEDFileCurveLinearMesh(fid,mName,dt,it,mrs);
4747 }
4748
4749 std::size_t MEDFileCurveLinearMesh::getHeapMemorySize() const
4750 {
4751   std::size_t ret=MEDFileStructuredMesh::getHeapMemorySize();
4752   if((const MEDCouplingCurveLinearMesh *)_clmesh)
4753     ret+=_clmesh->getHeapMemorySize();
4754   return ret;
4755 }
4756
4757 MEDFileMesh *MEDFileCurveLinearMesh::shallowCpy() const throw(INTERP_KERNEL::Exception)
4758 {
4759   MEDCouplingAutoRefCountObjectPtr<MEDFileCurveLinearMesh> ret=new MEDFileCurveLinearMesh(*this);
4760   return ret.retn();
4761 }
4762
4763 MEDFileMesh *MEDFileCurveLinearMesh::createNewEmpty() const throw(INTERP_KERNEL::Exception)
4764 {
4765   return new MEDFileCurveLinearMesh;
4766 }
4767
4768 MEDFileMesh *MEDFileCurveLinearMesh::deepCpy() const throw(INTERP_KERNEL::Exception)
4769 {
4770   MEDCouplingAutoRefCountObjectPtr<MEDFileCurveLinearMesh> ret=new MEDFileCurveLinearMesh(*this);
4771   if((const MEDCouplingCurveLinearMesh*)_clmesh)
4772     ret->_clmesh=static_cast<MEDCouplingCurveLinearMesh*>(_clmesh->deepCpy());
4773   ret->deepCpyAttributes();
4774   return ret.retn();
4775 }
4776
4777 int MEDFileCurveLinearMesh::getMeshDimension() const throw(INTERP_KERNEL::Exception)
4778 {
4779   if(!((const MEDCouplingCurveLinearMesh*)_clmesh))
4780     throw INTERP_KERNEL::Exception("MEDFileCurveLinearMesh::getMeshDimension : unable to get meshdimension because no mesh set !");
4781   return _clmesh->getMeshDimension();
4782 }
4783
4784 std::string MEDFileCurveLinearMesh::simpleRepr() const
4785 {
4786   return MEDFileStructuredMesh::simpleRepr();
4787 }
4788
4789 std::string MEDFileCurveLinearMesh::advancedRepr() const
4790 {
4791   return simpleRepr();
4792 }
4793
4794 bool MEDFileCurveLinearMesh::isEqual(const MEDFileMesh *other, double eps, std::string& what) const
4795 {
4796   if(!MEDFileStructuredMesh::isEqual(other,eps,what))
4797     return false;
4798   const MEDFileCurveLinearMesh *otherC=dynamic_cast<const MEDFileCurveLinearMesh *>(other);
4799   if(!otherC)
4800     {
4801       what="Mesh types differ ! This is curve linear and other is NOT !";
4802       return false;
4803     }
4804   clearNonDiscrAttributes();
4805   otherC->clearNonDiscrAttributes();
4806   const MEDCouplingCurveLinearMesh *coo1=_clmesh;
4807   const MEDCouplingCurveLinearMesh *coo2=otherC->_clmesh;
4808   if((coo1==0 && coo2!=0) || (coo1!=0 && coo2==0))
4809     {
4810       what="Mismatch of curve linear meshes ! One is defined and not other !";
4811       return false;
4812     }
4813   if(coo1)
4814     {
4815       bool ret=coo1->isEqual(coo2,eps);
4816       if(!ret)
4817         {
4818           what="curve linear meshes differ !";
4819           return false;
4820         }
4821     }
4822   return true;
4823 }
4824
4825 void MEDFileCurveLinearMesh::clearNonDiscrAttributes() const
4826 {
4827   MEDFileStructuredMesh::clearNonDiscrAttributes();
4828   MEDFileUMeshSplitL1::ClearNonDiscrAttributes(_clmesh);//to it is not a bug umeshsplit have already the method implemented
4829 }
4830
4831 void MEDFileCurveLinearMesh::synchronizeTinyInfoOnLeaves() const
4832 {
4833   const MEDCouplingCurveLinearMesh *clmesh=_clmesh;
4834   if(!clmesh)
4835     return;
4836   (const_cast<MEDCouplingCurveLinearMesh *>(clmesh))->setName(_name.c_str());
4837   (const_cast<MEDCouplingCurveLinearMesh *>(clmesh))->setDescription(_desc_name.c_str());
4838   (const_cast<MEDCouplingCurveLinearMesh *>(clmesh))->setTime(_time,_iteration,_order);
4839   (const_cast<MEDCouplingCurveLinearMesh *>(clmesh))->setTimeUnit(_dt_unit.c_str());
4840 }
4841
4842 const MEDCouplingCurveLinearMesh *MEDFileCurveLinearMesh::getMesh() const
4843 {
4844   synchronizeTinyInfoOnLeaves();
4845   return _clmesh;
4846 }
4847
4848 void MEDFileCurveLinearMesh::setMesh(MEDCouplingCurveLinearMesh *m) throw(INTERP_KERNEL::Exception)
4849 {
4850   dealWithTinyInfo(m);
4851   if(m)
4852     m->incrRef();
4853   _clmesh=m;
4854 }
4855
4856 const MEDCouplingStructuredMesh *MEDFileCurveLinearMesh::getStructuredMesh() const
4857 {
4858   synchronizeTinyInfoOnLeaves();
4859   return _clmesh;
4860 }
4861
4862 MEDFileCurveLinearMesh::MEDFileCurveLinearMesh()
4863 {
4864 }
4865
4866 MEDFileCurveLinearMesh::MEDFileCurveLinearMesh(med_idt fid, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
4867 try
4868   {
4869     loadCLMeshFromFile(fid,mName,dt,it,mrs);
4870   }
4871 catch(INTERP_KERNEL::Exception& e)
4872   {
4873     throw e;
4874   }
4875
4876 void MEDFileCurveLinearMesh::writeLL(med_idt fid) const throw(INTERP_KERNEL::Exception)
4877 {
4878   INTERP_KERNEL::AutoPtr<char> maa=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE);
4879   INTERP_KERNEL::AutoPtr<char> desc=MEDLoaderBase::buildEmptyString(MED_COMMENT_SIZE);
4880   INTERP_KERNEL::AutoPtr<char> dtunit=MEDLoaderBase::buildEmptyString(MED_LNAME_SIZE);
4881   MEDLoaderBase::safeStrCpy(_name.c_str(),MED_NAME_SIZE,maa,_too_long_str);
4882   MEDLoaderBase::safeStrCpy(_desc_name.c_str(),MED_COMMENT_SIZE,desc,_too_long_str);
4883   MEDLoaderBase::safeStrCpy(_dt_unit.c_str(),MED_LNAME_SIZE,dtunit,_too_long_str);
4884   int spaceDim=_clmesh->getSpaceDimension();
4885   int meshDim=_clmesh->getMeshDimension();
4886   INTERP_KERNEL::AutoPtr<char> comp=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
4887   INTERP_KERNEL::AutoPtr<char> unit=MEDLoaderBase::buildEmptyString(spaceDim*MED_SNAME_SIZE);
4888   const DataArrayDouble *coords=_clmesh->getCoords();
4889   if(!coords)
4890     throw INTERP_KERNEL::Exception("MEDFileCurveLinearMesh::writeLL : no coordinates set !");
4891   for(int i=0;i<spaceDim;i++)
4892     {
4893       std::string info(_clmesh->getCoords()->getInfoOnComponent(i));
4894       std::string c,u;
4895       MEDLoaderBase::splitIntoNameAndUnit(info,c,u);
4896       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
4897       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
4898     }
4899   MEDmeshCr(fid,maa,spaceDim,meshDim,MED_STRUCTURED_MESH,desc,dtunit,MED_SORT_DTIT,MED_CARTESIAN,comp,unit);
4900   MEDmeshUniversalNameWr(fid,maa);
4901   MEDmeshGridTypeWr(fid,maa,MED_CURVILINEAR_GRID);
4902   std::vector<int> nodeGridSt=_clmesh->getNodeGridStructure();
4903   MEDmeshGridStructWr(fid,maa,_iteration,_order,_time,&nodeGridSt[0]);
4904   
4905   MEDmeshNodeCoordinateWr(fid,maa,_iteration,_order,_time,MED_FULL_INTERLACE,coords->getNumberOfTuples(),coords->begin());
4906   //
4907   MEDFileStructuredMesh::writeStructuredLL(fid,maa);
4908 }
4909
4910 void MEDFileCurveLinearMesh::loadCLMeshFromFile(med_idt fid, const char *mName, int dt, int it, MEDFileMeshReadSelector *mrs) throw(INTERP_KERNEL::Exception)
4911 {
4912   ParaMEDMEM::MEDCouplingMeshType meshType;
4913   int dummy0,dummy1;
4914   std::string dtunit;
4915   int mid=MEDFileMeshL2::GetMeshIdFromName(fid,mName,meshType,dummy0,dummy1,dtunit);
4916   if(meshType!=CURVE_LINEAR)
4917     {
4918       std::ostringstream oss; oss << "Trying to load as curve linear an existing mesh with name '" << mName << "' that is NOT curve linear !";
4919       throw INTERP_KERNEL::Exception(oss.str().c_str());
4920     }
4921   MEDFileCLMeshL2 loaderl2;
4922   loaderl2.loadAll(fid,mid,mName,dt,it);
4923   MEDCouplingCurveLinearMesh *mesh=loaderl2.getMesh();
4924   mesh->incrRef();
4925   _clmesh=mesh;
4926   loadStrMeshFromFile(&loaderl2,fid,mName,dt,it,mrs);
4927 }
4928
4929 MEDFileMeshMultiTS *MEDFileMeshMultiTS::New()
4930 {
4931   return new MEDFileMeshMultiTS;
4932 }
4933
4934 MEDFileMeshMultiTS *MEDFileMeshMultiTS::New(const char *fileName) throw(INTERP_KERNEL::Exception)
4935 {
4936   return new MEDFileMeshMultiTS(fileName);
4937 }
4938
4939 MEDFileMeshMultiTS *MEDFileMeshMultiTS::New(const char *fileName, const char *mName) throw(INTERP_KERNEL::Exception)
4940 {
4941   return new MEDFileMeshMultiTS(fileName,mName);
4942 }
4943
4944 MEDFileMeshMultiTS *MEDFileMeshMultiTS::deepCpy() const throw(INTERP_KERNEL::Exception)
4945 {
4946   MEDCouplingAutoRefCountObjectPtr<MEDFileMeshMultiTS> ret=MEDFileMeshMultiTS::New();
4947   std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMesh> > meshOneTs(_mesh_one_ts.size());
4948   std::size_t i=0;
4949   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMesh> >::const_iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++,i++)
4950     if((const MEDFileMesh *)*it)
4951       meshOneTs[i]=(*it)->deepCpy();
4952   ret->_mesh_one_ts=meshOneTs;
4953   return ret.retn();
4954 }
4955
4956 std::size_t MEDFileMeshMultiTS::getHeapMemorySize() const
4957 {
4958   std::size_t ret=_mesh_one_ts.capacity()*sizeof(MEDCouplingAutoRefCountObjectPtr<MEDFileMesh>);
4959   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMesh> >::const_iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++)
4960     ret+=(*it)->getHeapMemorySize();
4961   return ret;
4962 }
4963
4964 const char *MEDFileMeshMultiTS::getName() const throw(INTERP_KERNEL::Exception)
4965 {
4966   if(_mesh_one_ts.empty())
4967     throw INTERP_KERNEL::Exception("MEDFileMeshMultiTS::getName : no time steps set !");
4968   return _mesh_one_ts[0]->getName();
4969 }
4970
4971 void MEDFileMeshMultiTS::setName(const char *newMeshName) throw(INTERP_KERNEL::Exception)
4972 {
4973   std::string oldName(getName());
4974   std::vector< std::pair<std::string,std::string> > v(1);
4975   v[0].first=oldName; v[0].second=newMeshName;
4976   changeNames(v);
4977 }
4978
4979 bool MEDFileMeshMultiTS::changeNames(const std::vector< std::pair<std::string,std::string> >& modifTab) throw(INTERP_KERNEL::Exception)
4980 {
4981   bool ret=false;
4982   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMesh> >::iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++)
4983     {
4984       MEDFileMesh *cur(*it);
4985       if(cur)
4986         ret=cur->changeNames(modifTab) || ret;
4987     }
4988   return ret;
4989 }
4990
4991 MEDFileMesh *MEDFileMeshMultiTS::getOneTimeStep() const throw(INTERP_KERNEL::Exception)
4992 {
4993   if(_mesh_one_ts.empty())
4994     throw INTERP_KERNEL::Exception("MEDFileMeshMultiTS::getOneTimeStep : empty time step set !");
4995   return const_cast<MEDFileMesh *>(static_cast<const MEDFileMesh *>(_mesh_one_ts[0]));
4996 }
4997
4998 void MEDFileMeshMultiTS::setOneTimeStep(MEDFileMesh *mesh1TimeStep) throw(INTERP_KERNEL::Exception)
4999 {
5000   if(!mesh1TimeStep)
5001     throw INTERP_KERNEL::Exception("MEDFileMeshMultiTS::setOneTimeStep : input pointer should be different from 0 !");
5002   _mesh_one_ts.resize(1);
5003   mesh1TimeStep->incrRef();
5004   //MEDCouplingAutoRefCountObjectPtr<MEDFileMesh> toto=mesh1TimeStep;
5005   _mesh_one_ts[0]=mesh1TimeStep;
5006 }
5007
5008 void MEDFileMeshMultiTS::write(med_idt fid) const throw(INTERP_KERNEL::Exception)
5009 {
5010   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMesh> >::const_iterator it=_mesh_one_ts.begin();it!=_mesh_one_ts.end();it++)
5011     {
5012       (*it)->copyOptionsFrom(*this);
5013       (*it)->write(fid);
5014     }
5015 }
5016
5017 void MEDFileMeshMultiTS::write(const char *fileName, int mode) const throw(INTERP_KERNEL::Exception)
5018 {
5019   med_access_mode medmod=MEDFileUtilities::TraduceWriteMode(mode);
5020   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,medmod);
5021   std::ostringstream oss; oss << "MEDFileMesh : error on attempt to write in file : \"" << fileName << "\""; 
5022   MEDFileUtilities::CheckMEDCode(fid,fid,oss.str().c_str());
5023   write(fid);
5024 }
5025
5026 void MEDFileMeshMultiTS::loadFromFile(const char *fileName, const char *mName) throw(INTERP_KERNEL::Exception)
5027 {//for the moment to be improved
5028   _mesh_one_ts.resize(1);
5029   _mesh_one_ts[0]=MEDFileMesh::New(fileName,mName,-1,-1);
5030 }
5031
5032 MEDFileMeshMultiTS::MEDFileMeshMultiTS()
5033 {
5034 }
5035
5036 MEDFileMeshMultiTS::MEDFileMeshMultiTS(const char *fileName) throw(INTERP_KERNEL::Exception)
5037 try
5038   {
5039     std::vector<std::string> ms=MEDLoader::GetMeshNames(fileName);
5040     if(ms.empty())
5041     {
5042       std::ostringstream oss; oss << "MEDFileUMesh::New : no meshes in file \"" << fileName << "\" !";
5043       throw INTERP_KERNEL::Exception(oss.str().c_str());
5044     }
5045     MEDFileUtilities::CheckFileForRead(fileName);
5046     MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,MED_ACC_RDONLY);
5047     int dt,it;
5048     ParaMEDMEM::MEDCouplingMeshType meshType;
5049     std::string dummy2;
5050     MEDFileMeshL2::GetMeshIdFromName(fid,ms.front().c_str(),meshType,dt,it,dummy2);
5051     loadFromFile(fileName,ms.front().c_str());
5052   }
5053 catch(INTERP_KERNEL::Exception& e)
5054   {
5055     throw e;
5056   }
5057
5058 MEDFileMeshMultiTS::MEDFileMeshMultiTS(const char *fileName, const char *mName) throw(INTERP_KERNEL::Exception)
5059 try
5060   {
5061     loadFromFile(fileName,mName);
5062   }
5063 catch(INTERP_KERNEL::Exception& e)
5064   {
5065     throw e;
5066   }
5067
5068 MEDFileMeshes *MEDFileMeshes::New()
5069 {
5070   return new MEDFileMeshes;
5071 }
5072
5073 MEDFileMeshes *MEDFileMeshes::New(const char *fileName) throw(INTERP_KERNEL::Exception)
5074 {
5075   return new MEDFileMeshes(fileName);
5076 }
5077
5078 void MEDFileMeshes::write(med_idt fid) const throw(INTERP_KERNEL::Exception)
5079 {
5080   checkCoherency();
5081   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++)
5082     {
5083       (*it)->copyOptionsFrom(*this);
5084       (*it)->write(fid);
5085     }
5086 }
5087
5088 void MEDFileMeshes::write(const char *fileName, int mode) const throw(INTERP_KERNEL::Exception)
5089 {
5090   med_access_mode medmod=MEDFileUtilities::TraduceWriteMode(mode);
5091   MEDFileUtilities::AutoFid fid=MEDfileOpen(fileName,medmod);
5092   std::ostringstream oss; oss << "MEDFileMesh : error on attempt to write in file : \"" << fileName << "\""; 
5093   MEDFileUtilities::CheckMEDCode(fid,fid,oss.str().c_str());
5094   checkCoherency();
5095   write(fid);
5096 }
5097
5098 int MEDFileMeshes::getNumberOfMeshes() const throw(INTERP_KERNEL::Exception)
5099 {
5100   return _meshes.size();
5101 }
5102
5103 MEDFileMeshesIterator *MEDFileMeshes::iterator() throw(INTERP_KERNEL::Exception)
5104 {
5105   return new MEDFileMeshesIterator(this);
5106 }
5107
5108 MEDFileMesh *MEDFileMeshes::getMeshAtPos(int i) const throw(INTERP_KERNEL::Exception)
5109 {
5110   if(i<0 || i>=(int)_meshes.size())
5111     {
5112       std::ostringstream oss; oss << "MEDFileMeshes::getMeshAtPos : invalid mesh id given in parameter ! Should be in [0;" << _meshes.size() << ") !";
5113       throw INTERP_KERNEL::Exception(oss.str().c_str());
5114     }
5115   return _meshes[i]->getOneTimeStep();
5116 }
5117
5118 MEDFileMesh *MEDFileMeshes::getMeshWithName(const char *mname) const throw(INTERP_KERNEL::Exception)
5119 {
5120   std::vector<std::string> ms=getMeshesNames();
5121   std::vector<std::string>::iterator it=std::find(ms.begin(),ms.end(),mname);
5122   if(it==ms.end())
5123     {
5124       std::ostringstream oss; oss << "MEDFileMeshes::getMeshWithName : Mesh  \"" << mname << "\" does not exist in this ! Existing are : ";
5125       std::copy(ms.begin(),ms.end(),std::ostream_iterator<std::string>(oss," "));
5126       throw INTERP_KERNEL::Exception(oss.str().c_str());
5127     }
5128   return getMeshAtPos((int)std::distance(ms.begin(),it));
5129 }
5130
5131 std::vector<std::string> MEDFileMeshes::getMeshesNames() const throw(INTERP_KERNEL::Exception)
5132 {
5133   std::vector<std::string> ret(_meshes.size());
5134   int i=0;
5135   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++,i++)
5136     {
5137       const MEDFileMeshMultiTS *f=(*it);
5138       if(f)
5139         {
5140           ret[i]=f->getName();
5141         }
5142       else
5143         {
5144           std::ostringstream oss; oss << "MEDFileMeshes::getMeshesNames : At rank #" << i << " mesh is not defined !";
5145           throw INTERP_KERNEL::Exception(oss.str().c_str());
5146         }
5147     }
5148   return ret;
5149 }
5150
5151 bool MEDFileMeshes::changeNames(const std::vector< std::pair<std::string,std::string> >& modifTab) throw(INTERP_KERNEL::Exception)
5152 {
5153   bool ret=false;
5154   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMeshMultiTS> >::iterator it=_meshes.begin();it!=_meshes.end();it++)
5155     {
5156       MEDFileMeshMultiTS *cur(*it);
5157       if(cur)
5158         ret=cur->changeNames(modifTab) || ret;
5159     }
5160   return ret;
5161 }
5162
5163 void MEDFileMeshes::resize(int newSize) throw(INTERP_KERNEL::Exception)
5164 {
5165   _meshes.resize(newSize);
5166 }
5167
5168 void MEDFileMeshes::pushMesh(MEDFileMesh *mesh) throw(INTERP_KERNEL::Exception)
5169 {
5170   if(!mesh)
5171     throw INTERP_KERNEL::Exception("MEDFileMeshes::pushMesh : invalid input pointer ! should be different from 0 !");
5172   MEDFileMeshMultiTS *elt=MEDFileMeshMultiTS::New();
5173   elt->setOneTimeStep(mesh);
5174   _meshes.push_back(elt);
5175 }
5176
5177 void MEDFileMeshes::setMeshAtPos(int i, MEDFileMesh *mesh) throw(INTERP_KERNEL::Exception)
5178 {
5179   if(!mesh)
5180     throw INTERP_KERNEL::Exception("MEDFileMeshes::setMeshAtPos : invalid input pointer ! should be different from 0 !");
5181   if(i>=(int)_meshes.size())
5182     _meshes.resize(i+1);
5183   MEDFileMeshMultiTS *elt=MEDFileMeshMultiTS::New();
5184   elt->setOneTimeStep(mesh);
5185   _meshes[i]=elt;
5186 }
5187
5188 void MEDFileMeshes::destroyMeshAtPos(int i) throw(INTERP_KERNEL::Exception)
5189 {
5190   if(i<0 || i>=(int)_meshes.size())
5191     {
5192       std::ostringstream oss; oss << "MEDFileMeshes::destroyMeshAtPos : Invalid given id in input (" << i << ") should be in [0," << _meshes.size() << ") !";
5193       throw INTERP_KERNEL::Exception(oss.str().c_str());
5194     }
5195   _meshes.erase(_meshes.begin()+i);
5196 }
5197
5198 void MEDFileMeshes::loadFromFile(const char *fileName) throw(INTERP_KERNEL::Exception)
5199 {
5200   std::vector<std::string> ms=MEDLoader::GetMeshNames(fileName);
5201   int i=0;
5202   _meshes.resize(ms.size());
5203   for(std::vector<std::string>::const_iterator it=ms.begin();it!=ms.end();it++,i++)
5204     _meshes[i]=MEDFileMeshMultiTS::New(fileName,(*it).c_str());
5205 }
5206
5207 MEDFileMeshes::MEDFileMeshes()
5208 {
5209 }
5210
5211 MEDFileMeshes::MEDFileMeshes(const char *fileName) throw(INTERP_KERNEL::Exception)
5212 try
5213   {
5214     loadFromFile(fileName);
5215   }
5216 catch(INTERP_KERNEL::Exception& e)
5217   {
5218   }
5219
5220 MEDFileMeshes *MEDFileMeshes::deepCpy() const throw(INTERP_KERNEL::Exception)
5221 {
5222   std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMeshMultiTS> > meshes(_meshes.size());
5223   std::size_t i=0;
5224   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++,i++)
5225     if((const MEDFileMeshMultiTS *)*it)
5226       meshes[i]=(*it)->deepCpy();
5227   MEDCouplingAutoRefCountObjectPtr<MEDFileMeshes> ret=MEDFileMeshes::New();
5228   ret->_meshes=meshes;
5229   return ret.retn();
5230 }
5231
5232 std::size_t MEDFileMeshes::getHeapMemorySize() const
5233 {
5234   std::size_t ret=_meshes.capacity()*(sizeof(MEDCouplingAutoRefCountObjectPtr<MEDFileMeshMultiTS>));
5235   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++)
5236     if((const MEDFileMeshMultiTS*)*it)
5237       ret+=(*it)->getHeapMemorySize();
5238   return ret; 
5239 }
5240
5241 std::string MEDFileMeshes::simpleRepr() const
5242 {
5243   std::ostringstream oss;
5244   oss << "(*****************)\n(* MEDFileMeshes *)\n(*****************)\n\n";
5245   simpleReprWithoutHeader(oss);
5246   return oss.str();
5247 }
5248
5249 void MEDFileMeshes::simpleReprWithoutHeader(std::ostream& oss) const
5250 {
5251   int nbOfMeshes=getNumberOfMeshes();
5252   oss << "There are " << nbOfMeshes << " meshes with the following names : \n";
5253   std::vector<std::string> mns=getMeshesNames();
5254   for(int i=0;i<nbOfMeshes;i++)
5255     oss << "  - #" << i << " \"" << mns[i] << "\"\n";
5256 }
5257
5258 void MEDFileMeshes::checkCoherency() const throw(INTERP_KERNEL::Exception)
5259 {
5260   static const char MSG[]="MEDFileMeshes::checkCoherency : mesh at rank ";
5261   int i=0;
5262   std::set<std::string> s;
5263   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileMeshMultiTS> >::const_iterator it=_meshes.begin();it!=_meshes.end();it++,i++)
5264     {
5265       const MEDFileMeshMultiTS *elt=(*it);
5266       if(!elt)
5267         {
5268           std::ostringstream oss; oss << MSG << i << "/" << _meshes.size() << " is empty !";
5269           throw INTERP_KERNEL::Exception(oss.str().c_str());
5270         }
5271       std::size_t sz=s.size();
5272       s.insert(std::string((*it)->getName()));
5273       if(s.size()==sz)
5274         {
5275           std::ostringstream oss; oss << MSG << i << " has a name (\"" << (*it)->getName() << "\") already used by an another mesh in list !";
5276           throw INTERP_KERNEL::Exception(oss.str().c_str());
5277         }
5278     }
5279 }
5280
5281 MEDFileMeshesIterator::MEDFileMeshesIterator(MEDFileMeshes *ms):_ms(ms),_iter_id(0),_nb_iter(0)
5282 {
5283   if(ms)
5284     {
5285       ms->incrRef();
5286       _nb_iter=ms->getNumberOfMeshes();
5287     }
5288 }
5289
5290 MEDFileMeshesIterator::~MEDFileMeshesIterator()
5291 {
5292 }
5293
5294 MEDFileMesh *MEDFileMeshesIterator::nextt()
5295 {
5296   if(_iter_id<_nb_iter)
5297     {
5298       MEDFileMeshes *ms(_ms);
5299       if(ms)
5300         return ms->getMeshAtPos(_iter_id++);
5301       else
5302         return 0;
5303     }
5304   else
5305     return 0;
5306 }