Salome HOME
Generalization of meshes without cells but only nodes
[modules/paravis.git] / src / Plugins / MEDWriter / IO / vtkMEDWriter.cxx
1 // Copyright (C) 2016  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "vtkMEDWriter.h"
22
23 #include "vtkAdjacentVertexIterator.h"
24 #include "vtkIntArray.h"
25 #include "vtkLongArray.h"
26 #include "vtkCellData.h"
27 #include "vtkPointData.h"
28 #include "vtkFloatArray.h"
29 #include "vtkCellArray.h"
30
31 #include "vtkStreamingDemandDrivenPipeline.h"
32 #include "vtkInformationDataObjectMetaDataKey.h"
33 #include "vtkUnstructuredGrid.h"
34 #include "vtkMultiBlockDataSet.h"
35 #include "vtkRectilinearGrid.h"
36 #include "vtkInformationStringKey.h"
37 #include "vtkAlgorithmOutput.h"
38 #include "vtkObjectFactory.h"
39 #include "vtkMutableDirectedGraph.h"
40 #include "vtkMultiBlockDataSet.h"
41 #include "vtkPolyData.h"
42 #include "vtkDataSet.h"
43 #include "vtkInformationVector.h"
44 #include "vtkInformation.h"
45 #include "vtkDataArraySelection.h"
46 #include "vtkTimeStamp.h"
47 #include "vtkInEdgeIterator.h"
48 #include "vtkInformationDataObjectKey.h"
49 #include "vtkExecutive.h"
50 #include "vtkVariantArray.h"
51 #include "vtkStringArray.h"
52 #include "vtkDoubleArray.h"
53 #include "vtkCharArray.h"
54 #include "vtkUnsignedCharArray.h"
55 #include "vtkDataSetAttributes.h"
56 #include "vtkDemandDrivenPipeline.h"
57 #include "vtkDataObjectTreeIterator.h"
58 #include "vtkWarpScalar.h"
59
60 #include "MEDFileMesh.hxx"
61 #include "MEDFileField.hxx"
62 #include "MEDFileData.hxx"
63 #include "MEDCouplingMemArray.hxx"
64 #include "MEDCouplingFieldInt.hxx"
65 #include "MEDCouplingFieldDouble.hxx"
66 #include "MEDCouplingRefCountObject.hxx"
67
68 #include <map>
69 #include <deque>
70 #include <sstream>
71
72 using MEDCoupling::MEDFileData;
73 using MEDCoupling::MEDFileMesh;
74 using MEDCoupling::MEDFileCMesh;
75 using MEDCoupling::MEDFileUMesh;
76 using MEDCoupling::MEDFileFields;
77 using MEDCoupling::MEDFileMeshes;
78
79 using MEDCoupling::MEDFileIntField1TS;
80 using MEDCoupling::MEDFileField1TS;
81 using MEDCoupling::MEDFileIntFieldMultiTS;
82 using MEDCoupling::MEDFileFieldMultiTS;
83 using MEDCoupling::MEDFileAnyTypeFieldMultiTS;
84 using MEDCoupling::DataArray;
85 using MEDCoupling::DataArrayInt;
86 using MEDCoupling::DataArrayDouble;
87 using MEDCoupling::MEDCouplingMesh;
88 using MEDCoupling::MEDCouplingUMesh;
89 using MEDCoupling::MEDCouplingCMesh;
90 using MEDCoupling::MEDCouplingFieldDouble;
91 using MEDCoupling::MEDCouplingFieldInt;
92 using MEDCoupling::MCAuto;
93
94 vtkStandardNewMacro(vtkMEDWriter);
95
96 ///////////////////
97
98 class MZCException : public std::exception
99 {
100 public:
101   MZCException(const std::string& s):_reason(s) { }
102   virtual const char *what() const throw() { return _reason.c_str(); }
103   virtual ~MZCException() throw() { }
104 private:
105   std::string _reason;
106 };
107
108 ///////////////////
109
110 std::map<int,int> ComputeMapOfType()
111 {
112   std::map<int,int> ret;
113   int nbOfTypesInMC(sizeof(MEDCouplingUMesh::MEDCOUPLING2VTKTYPETRADUCER)/sizeof(int));
114   for(int i=0;i<nbOfTypesInMC;i++)
115     {
116       int vtkId(MEDCouplingUMesh::MEDCOUPLING2VTKTYPETRADUCER[i]);
117       if(vtkId!=-1)
118         ret[vtkId]=i;
119     }
120   return ret;
121 }
122
123 std::string GetMeshNameWithContext(const std::vector<int>& context)
124 {
125   static const char DFT_MESH_NAME[]="Mesh";
126   if(context.empty())
127     return DFT_MESH_NAME;
128   std::ostringstream oss; oss << DFT_MESH_NAME;
129   for(std::vector<int>::const_iterator it=context.begin();it!=context.end();it++)
130     oss << "_" << *it;
131   return oss.str();
132 }
133
134 DataArrayInt *ConvertVTKArrayToMCArrayInt(vtkDataArray *data)
135 {
136   if(!data)
137     throw MZCException("ConvertVTKArrayToMCArrayInt : internal error !");
138   int nbTuples(data->GetNumberOfTuples()),nbComp(data->GetNumberOfComponents());
139   std::size_t nbElts(nbTuples*nbComp);
140   MCAuto<DataArrayInt> ret(DataArrayInt::New());
141   ret->alloc(nbTuples,nbComp);
142   for(int i=0;i<nbComp;i++)
143     {
144       const char *comp(data->GetComponentName(i));
145       if(comp)
146         ret->setInfoOnComponent(i,comp);
147     }
148   int *ptOut(ret->getPointer());
149   vtkIntArray *d0(vtkIntArray::SafeDownCast(data));
150   if(d0)
151     {
152       const int *pt(d0->GetPointer(0));
153       std::copy(pt,pt+nbElts,ptOut);
154       return ret.retn();
155     }
156   vtkLongArray *d1(vtkLongArray::SafeDownCast(data));
157   if(d1)
158     {
159       const long *pt(d1->GetPointer(0));
160       std::copy(pt,pt+nbElts,ptOut);
161       return ret.retn();
162     }
163   std::ostringstream oss;
164   oss << "ConvertVTKArrayToMCArrayInt : unrecognized array \"" << typeid(*data).name() << "\" type !";
165   throw MZCException(oss.str());
166 }
167
168 DataArrayDouble *ConvertVTKArrayToMCArrayDouble(vtkDataArray *data)
169 {
170   if(!data)
171     throw MZCException("ConvertVTKArrayToMCArrayDouble : internal error !");
172   int nbTuples(data->GetNumberOfTuples()),nbComp(data->GetNumberOfComponents());
173   std::size_t nbElts(nbTuples*nbComp);
174   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
175   ret->alloc(nbTuples,nbComp);
176   for(int i=0;i<nbComp;i++)
177     {
178       const char *comp(data->GetComponentName(i));
179       if(comp)
180         ret->setInfoOnComponent(i,comp);
181     }
182   double *ptOut(ret->getPointer());
183   vtkFloatArray *d0(vtkFloatArray::SafeDownCast(data));
184   if(d0)
185     {
186       const float *pt(d0->GetPointer(0));
187       for(std::size_t i=0;i<nbElts;i++)
188         ptOut[i]=pt[i];
189       return ret.retn();
190     }
191   vtkDoubleArray *d1(vtkDoubleArray::SafeDownCast(data));
192   if(d1)
193     {
194       const double *pt(d1->GetPointer(0));
195       std::copy(pt,pt+nbElts,ptOut);
196       return ret.retn();
197     }
198   std::ostringstream oss;
199   oss << "ConvertVTKArrayToMCArrayDouble : unrecognized array \"" << typeid(*data).name() << "\" type !";
200   throw MZCException(oss.str());
201 }
202
203 DataArray *ConvertVTKArrayToMCArray(vtkDataArray *data)
204 {
205   if(!data)
206     throw MZCException("ConvertVTKArrayToMCArray : internal error !");
207   vtkFloatArray *d0(vtkFloatArray::SafeDownCast(data));
208   vtkDoubleArray *d1(vtkDoubleArray::SafeDownCast(data));
209   if(d0 || d1)
210     return ConvertVTKArrayToMCArrayDouble(data);
211   vtkIntArray *d2(vtkIntArray::SafeDownCast(data));
212   vtkLongArray *d3(vtkLongArray::SafeDownCast(data));
213   if(d2 || d3)
214     return ConvertVTKArrayToMCArrayInt(data);
215   std::ostringstream oss;
216   oss << "ConvertVTKArrayToMCArray : unrecognized array \"" << typeid(*data).name() << "\" type !";
217   throw MZCException(oss.str());
218 }
219
220 MEDCouplingUMesh *BuildMeshFromCellArray(vtkCellArray *ca, DataArrayDouble *coords, int meshDim, INTERP_KERNEL::NormalizedCellType type)
221 {
222   MCAuto<MEDCouplingUMesh> subMesh(MEDCouplingUMesh::New("",meshDim));
223   subMesh->setCoords(coords); subMesh->allocateCells();
224   int nbCells(ca->GetNumberOfCells());
225   if(nbCells==0)
226     return 0;
227   vtkIdType nbEntries(ca->GetNumberOfConnectivityEntries());
228   const vtkIdType *conn(ca->GetPointer());
229   for(int i=0;i<nbCells;i++)
230     {
231       int sz(*conn++);
232       std::vector<int> conn2(sz);
233       for(int jj=0;jj<sz;jj++)
234         conn2[jj]=conn[jj];
235       subMesh->insertNextCell(type,sz,&conn2[0]);
236       conn+=sz;
237     }
238   return subMesh.retn();
239 }
240
241 MEDCouplingUMesh *BuildMeshFromCellArrayTriangleStrip(vtkCellArray *ca, DataArrayDouble *coords, MCAuto<DataArrayInt>& ids)
242 {
243   MCAuto<MEDCouplingUMesh> subMesh(MEDCouplingUMesh::New("",2));
244   subMesh->setCoords(coords); subMesh->allocateCells();
245   int nbCells(ca->GetNumberOfCells());
246   if(nbCells==0)
247     return 0;
248   vtkIdType nbEntries(ca->GetNumberOfConnectivityEntries());
249   const vtkIdType *conn(ca->GetPointer());
250   ids=DataArrayInt::New() ; ids->alloc(0,1);
251   for(int i=0;i<nbCells;i++)
252     {
253       int sz(*conn++);
254       int nbTri(sz-2);
255       if(nbTri>0)
256         {
257           for(int j=0;j<nbTri;j++,conn++)
258             {
259               int conn2[3]; conn2[0]=conn[0] ; conn2[1]=conn[1] ; conn2[2]=conn[2];
260               subMesh->insertNextCell(INTERP_KERNEL::NORM_TRI3,3,conn2);
261               ids->pushBackSilent(i);
262             }
263         }
264       else
265         {
266           std::ostringstream oss; oss << "BuildMeshFromCellArrayTriangleStrip : on cell #" << i << " the triangle stip looks bab !";
267           throw MZCException(oss.str());
268         }
269       conn+=sz;
270     }
271   return subMesh.retn();
272 }
273
274 class MicroField
275 {
276 public:
277   MicroField(const MCAuto<MEDCouplingUMesh>& m, const std::vector<MCAuto<DataArray> >& cellFs):_m(m),_cellFs(cellFs) { }
278   MicroField(const std::vector< MicroField >& vs);
279   void setNodeFields(const std::vector<MCAuto<DataArray> >& nf) { _nodeFs=nf; }
280   MCAuto<MEDCouplingUMesh> getMesh() const { return _m; }
281   std::vector<MCAuto<DataArray> > getCellFields() const { return _cellFs; }
282 private:
283   MCAuto<MEDCouplingUMesh> _m;
284   std::vector<MCAuto<DataArray> > _cellFs;
285   std::vector<MCAuto<DataArray> > _nodeFs;
286 };
287
288 MicroField::MicroField(const std::vector< MicroField >& vs)
289 {
290   std::size_t sz(vs.size());
291   std::vector<const MEDCouplingUMesh *> vs2(sz);
292   std::vector< std::vector< MCAuto<DataArray> > > arrs2(sz);
293   int nbElts(-1);
294   for(std::size_t ii=0;ii<sz;ii++)
295     {
296       vs2[ii]=vs[ii].getMesh();
297       arrs2[ii]=vs[ii].getCellFields();
298       if(nbElts<0)
299         nbElts=arrs2[ii].size();
300       else
301         if(arrs2[ii].size()!=nbElts)
302           throw MZCException("MicroField cstor : internal error !");
303     }
304   _cellFs.resize(nbElts);
305   for(int ii=0;ii<nbElts;ii++)
306     {
307       std::vector<const DataArray *> arrsTmp(sz);
308       for(std::size_t jj=0;jj<sz;jj++)
309         {
310           arrsTmp[jj]=arrs2[jj][ii];
311         }
312       _cellFs[ii]=DataArray::Aggregate(arrsTmp);
313     }
314   _m=MEDCouplingUMesh::MergeUMeshesOnSameCoords(vs2);
315 }
316
317 void AppendMCFieldFrom(MEDCoupling::TypeOfField tf, MEDCouplingMesh *mesh, MEDFileData *mfd, MCAuto<DataArray> da, const DataArrayInt *n2oPtr)
318 {
319   static const char FAMFIELD_FOR_CELLS[]="FamilyIdCell";
320   static const char FAMFIELD_FOR_NODES[]="FamilyIdNode";
321   if(!da || !mesh || !mfd)
322     throw MZCException("AppendMCFieldFrom : internal error !");
323   MEDFileFields *fs(mfd->getFields());
324   MEDFileMeshes *ms(mfd->getMeshes());
325   if(!fs || !ms)
326     throw MZCException("AppendMCFieldFrom : internal error 2 !");
327   MCAuto<DataArrayDouble> dad(MEDCoupling::DynamicCast<DataArray,DataArrayDouble>(da));
328   DataArrayDouble *dadPtr(dad);
329   std::string fieldName;
330   if(dadPtr)
331     {
332       fieldName=dadPtr->getName();
333       MCAuto<MEDCouplingFieldDouble> f(MEDCouplingFieldDouble::New(tf));
334       f->setName(fieldName);
335       if(!n2oPtr)
336         f->setArray(dadPtr);
337       else
338         {
339           MCAuto<DataArrayDouble> dad2(dadPtr->selectByTupleId(n2oPtr->begin(),n2oPtr->end()));
340           f->setArray(dad2);
341         }
342       f->setMesh(mesh);
343       MCAuto<MEDFileFieldMultiTS> fmts(MEDFileFieldMultiTS::New());
344       MCAuto<MEDFileField1TS> f1ts(MEDFileField1TS::New());
345       f1ts->setFieldNoProfileSBT(f);
346       fmts->pushBackTimeStep(f1ts);
347       fs->pushField(fmts);
348       return ;
349     }
350   MCAuto<DataArrayInt> dai(MEDCoupling::DynamicCast<DataArray,DataArrayInt>(da));
351   DataArrayInt *daiPtr(dai);
352   if(daiPtr)
353     {
354       fieldName=daiPtr->getName();
355       if((fieldName!=FAMFIELD_FOR_CELLS || tf!=MEDCoupling::ON_CELLS) && (fieldName!=FAMFIELD_FOR_NODES || tf!=MEDCoupling::ON_NODES))
356         {
357           MCAuto<MEDCouplingFieldInt> f(MEDCouplingFieldInt::New(tf));
358           f->setName(fieldName);
359           f->setMesh(mesh);
360           MCAuto<MEDFileIntFieldMultiTS> fmts(MEDFileIntFieldMultiTS::New());
361           MCAuto<MEDFileIntField1TS> f1ts(MEDFileIntField1TS::New());
362           if(!n2oPtr)
363             {
364               f->setArray(dai);
365               f1ts->setFieldNoProfileSBT(f);
366             }
367           else
368             {
369               MCAuto<DataArrayInt> dai2(daiPtr->selectByTupleId(n2oPtr->begin(),n2oPtr->end()));
370               f->setArray(dai2);
371               f1ts->setFieldNoProfileSBT(f);
372             }
373           fmts->pushBackTimeStep(f1ts);
374           fs->pushField(fmts);
375           return ;
376         }
377       else if(fieldName==FAMFIELD_FOR_CELLS && tf==MEDCoupling::ON_CELLS)
378         {
379           MEDFileMesh *mm(ms->getMeshWithName(mesh->getName()));
380           if(!mm)
381             throw MZCException("AppendMCFieldFrom : internal error 3 !");
382           if(!n2oPtr)
383             mm->setFamilyFieldArr(mesh->getMeshDimension()-mm->getMeshDimension(),daiPtr);
384           else
385             {
386               MCAuto<DataArrayInt> dai2(daiPtr->selectByTupleId(n2oPtr->begin(),n2oPtr->end()));
387               mm->setFamilyFieldArr(mesh->getMeshDimension()-mm->getMeshDimension(),dai2);
388             }
389         }
390       else if(fieldName==FAMFIELD_FOR_NODES || tf==MEDCoupling::ON_NODES)
391         {
392           MEDFileMesh *mm(ms->getMeshWithName(mesh->getName()));
393           if(!mm)
394             throw MZCException("AppendMCFieldFrom : internal error 4 !");
395           if(!n2oPtr)
396             mm->setFamilyFieldArr(1,daiPtr);
397           else
398             {
399               MCAuto<DataArrayInt> dai2(daiPtr->selectByTupleId(n2oPtr->begin(),n2oPtr->end()));
400               mm->setFamilyFieldArr(1,dai2);
401             }
402         }
403     }
404 }
405
406 void PutAtLevelDealOrder(MEDFileData *mfd, int meshDimRel, const MicroField& mf)
407 {
408   if(!mfd)
409     throw MZCException("PutAtLevelDealOrder : internal error !");
410   MEDFileMesh *mm(mfd->getMeshes()->getMeshAtPos(0));
411   MEDFileUMesh *mmu(dynamic_cast<MEDFileUMesh *>(mm));
412   if(!mmu)
413     throw MZCException("PutAtLevelDealOrder : internal error 2 !");
414   MCAuto<MEDCouplingUMesh> mesh(mf.getMesh());
415   mesh->setName(mfd->getMeshes()->getMeshAtPos(0)->getName());
416   MCAuto<DataArrayInt> o2n(mesh->sortCellsInMEDFileFrmt());
417   const DataArrayInt *o2nPtr(o2n);
418   MCAuto<DataArrayInt> n2o;
419   mmu->setMeshAtLevel(meshDimRel,mesh);
420   const DataArrayInt *n2oPtr(0);
421   if(o2n)
422     {
423       n2o=o2n->invertArrayO2N2N2O(mesh->getNumberOfCells());
424       n2oPtr=n2o;
425       if(n2oPtr && n2oPtr->isIota(mesh->getNumberOfCells()))
426         n2oPtr=0;
427       if(n2oPtr)
428         mm->setRenumFieldArr(meshDimRel,n2o);
429     }
430   //
431   std::vector<MCAuto<DataArray> > cells(mf.getCellFields());
432   for(std::vector<MCAuto<DataArray> >::const_iterator it=cells.begin();it!=cells.end();it++)
433     {
434       MCAuto<DataArray> da(*it);
435       AppendMCFieldFrom(MEDCoupling::ON_CELLS,mesh,mfd,da,n2oPtr);
436     }
437 }
438
439 void AssignSingleGTMeshes(MEDFileData *mfd, const std::vector< MicroField >& ms)
440 {
441   if(!mfd)
442     throw MZCException("AssignSingleGTMeshes : internal error !");
443   MEDFileMesh *mm0(mfd->getMeshes()->getMeshAtPos(0));
444   MEDFileUMesh *mm(dynamic_cast<MEDFileUMesh *>(mm0));
445   if(!mm)
446     throw MZCException("AssignSingleGTMeshes : internal error 2 !");
447   int meshDim(-std::numeric_limits<int>::max());
448   std::map<int, std::vector< MicroField > > ms2;
449   for(std::vector< MicroField >::const_iterator it=ms.begin();it!=ms.end();it++)
450     {
451       const MEDCouplingUMesh *elt((*it).getMesh());
452       if(elt)
453         {
454           int myMeshDim(elt->getMeshDimension());
455           meshDim=std::max(meshDim,myMeshDim);
456           ms2[myMeshDim].push_back(*it);
457         }
458     }
459   if(ms2.empty())
460     return ;
461   for(std::map<int, std::vector< MicroField > >::const_iterator it=ms2.begin();it!=ms2.end();it++)
462     {
463       const std::vector< MicroField >& vs((*it).second);
464       if(vs.size()==1)
465         {
466           PutAtLevelDealOrder(mfd,(*it).first-meshDim,vs[0]);
467         }
468       else
469         {
470           MicroField merge(vs);
471           PutAtLevelDealOrder(mfd,(*it).first-meshDim,merge);
472         }
473     }
474 }
475
476 DataArrayDouble *BuildCoordsFrom(vtkPointSet *ds)
477 {
478   if(!ds)
479     throw MZCException("BuildCoordsFrom : internal error !");
480   vtkPoints *pts(ds->GetPoints());
481   if(!pts)
482     throw MZCException("BuildCoordsFrom : internal error 2 !");
483   vtkDataArray *data(pts->GetData());
484   if(!data)
485     throw MZCException("BuildCoordsFrom : internal error 3 !");
486   MCAuto<DataArrayDouble> coords(ConvertVTKArrayToMCArrayDouble(data));
487   return coords.retn();
488 }
489
490 void AddNodeFields(MEDFileData *mfd, vtkDataSetAttributes *dsa)
491 {
492   if(!mfd || !dsa)
493     throw MZCException("AddNodeFields : internal error !");
494   MEDFileMesh *mm(mfd->getMeshes()->getMeshAtPos(0));
495   MEDFileUMesh *mmu(dynamic_cast<MEDFileUMesh *>(mm));
496   if(!mmu)
497     throw MZCException("AddNodeFields : internal error 2 !");
498   MCAuto<MEDCouplingUMesh> mesh;
499   if(!mmu->getNonEmptyLevels().empty())
500     mesh=mmu->getMeshAtLevel(0);
501   else
502     {
503       mesh=MEDCouplingUMesh::Build0DMeshFromCoords(mmu->getCoords());
504       mesh->setName(mmu->getName());
505     }
506   int nba(dsa->GetNumberOfArrays());
507   for(int i=0;i<nba;i++)
508     {
509       vtkDataArray *arr(dsa->GetArray(i));
510       const char *name(arr->GetName());
511       if(!arr)
512         continue;
513       MCAuto<DataArray> da(ConvertVTKArrayToMCArray(arr));
514       da->setName(name);
515       AppendMCFieldFrom(MEDCoupling::ON_NODES,mesh,mfd,da,0);
516     }
517 }
518
519 std::vector<MCAuto<DataArray> > AddPartFields(const DataArrayInt *part, vtkDataSetAttributes *dsa)
520 {
521   std::vector< MCAuto<DataArray> > ret;
522   if(!dsa)
523     return ret;
524   int nba(dsa->GetNumberOfArrays());
525   for(int i=0;i<nba;i++)
526     {
527       vtkDataArray *arr(dsa->GetArray(i));
528       if(!arr)
529         continue;
530       const char *name(arr->GetName());
531       int nbCompo(arr->GetNumberOfComponents());
532       vtkIdType nbTuples(arr->GetNumberOfTuples());
533       MCAuto<DataArray> mcarr(ConvertVTKArrayToMCArray(arr));
534       if(part)
535         mcarr=mcarr->selectByTupleId(part->begin(),part->end());
536       mcarr->setName(name);
537       ret.push_back(mcarr);
538     }
539   return ret;
540 }
541
542 std::vector<MCAuto<DataArray> > AddPartFields2(int bg, int end, vtkDataSetAttributes *dsa)
543 {
544   std::vector< MCAuto<DataArray> > ret;
545   if(!dsa)
546     return ret;
547   int nba(dsa->GetNumberOfArrays());
548   for(int i=0;i<nba;i++)
549     {
550       vtkDataArray *arr(dsa->GetArray(i));
551       if(!arr)
552         continue;
553       const char *name(arr->GetName());
554       int nbCompo(arr->GetNumberOfComponents());
555       vtkIdType nbTuples(arr->GetNumberOfTuples());
556       MCAuto<DataArray> mcarr(ConvertVTKArrayToMCArray(arr));
557       mcarr=mcarr->selectByTupleIdSafeSlice(bg,end,1);
558       mcarr->setName(name);
559       ret.push_back(mcarr);
560     }
561   return ret;
562 }
563
564 void ConvertFromRectilinearGrid(MEDFileData *ret, vtkRectilinearGrid *ds, const std::vector<int>& context)
565 {
566   if(!ds || !ret)
567     throw MZCException("ConvertFromRectilinearGrid : internal error !");
568   //
569   MCAuto<MEDFileMeshes> meshes(MEDFileMeshes::New());
570   ret->setMeshes(meshes);
571   MCAuto<MEDFileFields> fields(MEDFileFields::New());
572   ret->setFields(fields);
573   //
574   MCAuto<MEDFileCMesh> cmesh(MEDFileCMesh::New());
575   meshes->pushMesh(cmesh);
576   MCAuto<MEDCouplingCMesh> cmeshmc(MEDCouplingCMesh::New());
577   vtkDataArray *cx(ds->GetXCoordinates()),*cy(ds->GetYCoordinates()),*cz(ds->GetZCoordinates());
578   if(cx)
579     {
580       MCAuto<DataArrayDouble> arr(ConvertVTKArrayToMCArrayDouble(cx));
581       cmeshmc->setCoordsAt(0,arr);
582     }
583   if(cy)
584     {
585       MCAuto<DataArrayDouble> arr(ConvertVTKArrayToMCArrayDouble(cy));
586       cmeshmc->setCoordsAt(1,arr);
587     }
588   if(cz)
589     {
590       MCAuto<DataArrayDouble> arr(ConvertVTKArrayToMCArrayDouble(cz));
591       cmeshmc->setCoordsAt(2,arr);
592     }
593   std::string meshName(GetMeshNameWithContext(context));
594   cmeshmc->setName(meshName);
595   cmesh->setMesh(cmeshmc);
596   std::vector<MCAuto<DataArray> > cellFs(AddPartFields(0,ds->GetCellData()));
597   for(std::vector<MCAuto<DataArray> >::const_iterator it=cellFs.begin();it!=cellFs.end();it++)
598     {
599       MCAuto<DataArray> da(*it);
600       AppendMCFieldFrom(MEDCoupling::ON_CELLS,cmeshmc,ret,da,0);
601     }
602   std::vector<MCAuto<DataArray> > nodeFs(AddPartFields(0,ds->GetPointData()));
603   for(std::vector<MCAuto<DataArray> >::const_iterator it=nodeFs.begin();it!=nodeFs.end();it++)
604     {
605       MCAuto<DataArray> da(*it);
606       AppendMCFieldFrom(MEDCoupling::ON_NODES,cmeshmc,ret,da,0);
607     }
608 }
609
610 void ConvertFromPolyData(MEDFileData *ret, vtkPolyData *ds, const std::vector<int>& context)
611 {
612   if(!ds || !ret)
613     throw MZCException("ConvertFromPolyData : internal error !");
614   //
615   MCAuto<MEDFileMeshes> meshes(MEDFileMeshes::New());
616   ret->setMeshes(meshes);
617   MCAuto<MEDFileFields> fields(MEDFileFields::New());
618   ret->setFields(fields);
619   //
620   MCAuto<MEDFileUMesh> umesh(MEDFileUMesh::New());
621   meshes->pushMesh(umesh);
622   MCAuto<DataArrayDouble> coords(BuildCoordsFrom(ds));
623   umesh->setCoords(coords);
624   umesh->setName(GetMeshNameWithContext(context));
625   //
626   int offset(0);
627   std::vector< MicroField > ms;
628   vtkCellArray *cd(ds->GetVerts());
629   if(cd)
630     {
631       MCAuto<MEDCouplingUMesh> subMesh(BuildMeshFromCellArray(cd,coords,0,INTERP_KERNEL::NORM_POINT1));
632       if((const MEDCouplingUMesh *)subMesh)
633         {
634           std::vector<MCAuto<DataArray> > cellFs(AddPartFields2(offset,offset+subMesh->getNumberOfCells(),ds->GetCellData()));
635           offset+=subMesh->getNumberOfCells();
636           ms.push_back(MicroField(subMesh,cellFs));
637         }
638     }
639   vtkCellArray *cc(ds->GetLines());
640   if(cc)
641     {
642       MCAuto<MEDCouplingUMesh> subMesh(BuildMeshFromCellArray(cc,coords,1,INTERP_KERNEL::NORM_SEG2));
643       if((const MEDCouplingUMesh *)subMesh)
644         {
645           std::vector<MCAuto<DataArray> > cellFs(AddPartFields2(offset,offset+subMesh->getNumberOfCells(),ds->GetCellData()));
646           offset+=subMesh->getNumberOfCells();
647           ms.push_back(MicroField(subMesh,cellFs));
648         }
649     }
650   vtkCellArray *cb(ds->GetPolys());
651   if(cb)
652     {
653       MCAuto<MEDCouplingUMesh> subMesh(BuildMeshFromCellArray(cb,coords,2,INTERP_KERNEL::NORM_POLYGON));
654       if((const MEDCouplingUMesh *)subMesh)
655         {
656           std::vector<MCAuto<DataArray> > cellFs(AddPartFields2(offset,offset+subMesh->getNumberOfCells(),ds->GetCellData()));
657           offset+=subMesh->getNumberOfCells();
658           ms.push_back(MicroField(subMesh,cellFs));
659         }
660     }
661   vtkCellArray *ca(ds->GetStrips());
662   if(ca)
663     {
664       MCAuto<DataArrayInt> ids;
665       MCAuto<MEDCouplingUMesh> subMesh(BuildMeshFromCellArrayTriangleStrip(ca,coords,ids));
666       if((const MEDCouplingUMesh *)subMesh)
667         {
668           std::vector<MCAuto<DataArray> > cellFs(AddPartFields(ids,ds->GetCellData()));
669           offset+=subMesh->getNumberOfCells();
670           ms.push_back(MicroField(subMesh,cellFs));
671         }
672     }
673   AssignSingleGTMeshes(ret,ms);
674   AddNodeFields(ret,ds->GetPointData());
675 }
676
677 void ConvertFromUnstructuredGrid(MEDFileData *ret, vtkUnstructuredGrid *ds, const std::vector<int>& context)
678 {
679   if(!ds || !ret)
680     throw MZCException("ConvertFromUnstructuredGrid : internal error !");
681   //
682   MCAuto<MEDFileMeshes> meshes(MEDFileMeshes::New());
683   ret->setMeshes(meshes);
684   MCAuto<MEDFileFields> fields(MEDFileFields::New());
685   ret->setFields(fields);
686   //
687   MCAuto<MEDFileUMesh> umesh(MEDFileUMesh::New());
688   meshes->pushMesh(umesh);
689   MCAuto<DataArrayDouble> coords(BuildCoordsFrom(ds));
690   umesh->setCoords(coords);
691   umesh->setName(GetMeshNameWithContext(context));
692   vtkIdType nbCells(ds->GetNumberOfCells());
693   vtkCellArray *ca(ds->GetCells());
694   if(!ca)
695     return ;
696   vtkIdType nbEnt(ca->GetNumberOfConnectivityEntries());
697   vtkIdType *caPtr(ca->GetPointer());
698   vtkUnsignedCharArray *ct(ds->GetCellTypesArray());
699   if(!ct)
700     throw MZCException("ConvertFromUnstructuredGrid : internal error");
701   vtkIdTypeArray *cla(ds->GetCellLocationsArray());
702   const vtkIdType *claPtr(cla->GetPointer(0));
703   if(!cla)
704     throw MZCException("ConvertFromUnstructuredGrid : internal error 2");
705   const unsigned char *ctPtr(ct->GetPointer(0));
706   std::map<int,int> m(ComputeMapOfType());
707   MCAuto<DataArrayInt> lev(DataArrayInt::New()) ;  lev->alloc(nbCells,1);
708   int *levPtr(lev->getPointer());
709   for(vtkIdType i=0;i<nbCells;i++)
710     {
711       std::map<int,int>::iterator it(m.find(ctPtr[i]));
712       if(it!=m.end())
713         {
714           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)(*it).second));
715           levPtr[i]=cm.getDimension();
716         }
717       else
718         {
719           std::ostringstream oss; oss << "ConvertFromUnstructuredGrid : at pos #" << i << " unrecognized VTK cell with type =" << ctPtr[i];
720           throw MZCException(oss.str());
721         }
722     }
723   int dummy(0);
724   MCAuto<DataArrayInt> levs(lev->getDifferentValues());
725   std::vector< MicroField > ms;
726   vtkIdTypeArray *faces(ds->GetFaces()),*faceLoc(ds->GetFaceLocations());
727   for(const int *curLev=levs->begin();curLev!=levs->end();curLev++)
728     {
729       MCAuto<MEDCouplingUMesh> m0(MEDCouplingUMesh::New("",*curLev));
730       m0->setCoords(coords); m0->allocateCells();
731       MCAuto<DataArrayInt> cellIdsCurLev(lev->findIdsEqual(*curLev));
732       for(const int *cellId=cellIdsCurLev->begin();cellId!=cellIdsCurLev->end();cellId++)
733         {
734           std::map<int,int>::iterator it(m.find(ctPtr[*cellId]));
735           vtkIdType offset(claPtr[*cellId]);
736           vtkIdType sz(caPtr[offset]);
737           INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)(*it).second);
738           if(ct!=INTERP_KERNEL::NORM_POLYHED)
739             {
740               std::vector<int> conn2(sz);
741               for(int kk=0;kk<sz;kk++)
742                 conn2[kk]=caPtr[offset+1+kk];
743               m0->insertNextCell(ct,sz,&conn2[0]);
744             }
745           else
746             {
747               if(!faces || !faceLoc)
748                 throw MZCException("ConvertFromUnstructuredGrid : faces are expected when there are polyhedra !");
749               const vtkIdType *facPtr(faces->GetPointer(0)),*facLocPtr(faceLoc->GetPointer(0));
750               std::vector<int> conn;
751               int off0(facLocPtr[*cellId]);
752               int nbOfFaces(facPtr[off0++]);
753               for(int k=0;k<nbOfFaces;k++)
754                 {
755                   int nbOfNodesInFace(facPtr[off0++]);
756                   std::copy(facPtr+off0,facPtr+off0+nbOfNodesInFace,std::back_inserter(conn));
757                   off0+=nbOfNodesInFace;
758                   if(k<nbOfFaces-1)
759                     conn.push_back(-1);
760                 }
761               m0->insertNextCell(ct,conn.size(),&conn[0]);
762             }
763         }
764       std::vector<MCAuto<DataArray> > cellFs(AddPartFields(cellIdsCurLev,ds->GetCellData()));
765       ms.push_back(MicroField(m0,cellFs));
766     }
767   AssignSingleGTMeshes(ret,ms);
768   AddNodeFields(ret,ds->GetPointData());
769 }
770
771 ///////////////////
772
773 vtkMEDWriter::vtkMEDWriter():WriteAllTimeSteps(0),FileName(0),IsTouched(false)
774 {
775 }
776
777 vtkMEDWriter::~vtkMEDWriter()
778 {
779 }
780
781 vtkInformationDataObjectMetaDataKey *GetMEDReaderMetaDataIfAny()
782 {
783   static const char ZE_KEY[]="vtkMEDReader::META_DATA";
784   MEDCoupling::GlobalDict *gd(MEDCoupling::GlobalDict::GetInstance());
785   if(!gd->hasKey(ZE_KEY))
786     return 0;
787   std::string ptSt(gd->value(ZE_KEY));
788   void *pt(0);
789   std::istringstream iss(ptSt); iss >> pt;
790   return reinterpret_cast<vtkInformationDataObjectMetaDataKey *>(pt);
791 }
792
793 bool IsInformationOK(vtkInformation *info)
794 {
795   vtkInformationDataObjectMetaDataKey *key(GetMEDReaderMetaDataIfAny());
796   if(!key)
797     return false;
798   // Check the information contain meta data key
799   if(!info->Has(key))
800     return false;
801   // Recover Meta Data
802   vtkMutableDirectedGraph *sil(vtkMutableDirectedGraph::SafeDownCast(info->Get(key)));
803   if(!sil)
804     return false;
805   int idNames(0);
806   vtkAbstractArray *verticesNames(sil->GetVertexData()->GetAbstractArray("Names",idNames));
807   vtkStringArray *verticesNames2(vtkStringArray::SafeDownCast(verticesNames));
808   if(!verticesNames2)
809     return false;
810   for(int i=0;i<verticesNames2->GetNumberOfValues();i++)
811     {
812       vtkStdString &st(verticesNames2->GetValue(i));
813       if(st=="MeshesFamsGrps")
814         return true;
815     }
816   return false;
817 }
818
819 class Grp
820 {
821 public:
822   Grp(const std::string& name):_name(name) { }
823   void setFamilies(const std::vector<std::string>& fams) { _fams=fams; }
824   std::string getName() const { return _name; }
825   std::vector<std::string> getFamilies() const { return _fams; }
826 private:
827   std::string _name;
828   std::vector<std::string> _fams;
829 };
830
831 class Fam
832 {
833 public:
834   Fam(const std::string& name)
835   {
836     static const char ZE_SEP[]="@@][@@";
837     std::size_t pos(name.find(ZE_SEP));
838     std::string name0(name.substr(0,pos)),name1(name.substr(pos+strlen(ZE_SEP)));
839     std::istringstream iss(name1);
840     iss >> _id;
841     _name=name0;
842   }
843   std::string getName() const { return _name; }
844   int getID() const { return _id; }
845 private:
846   std::string _name;
847   int _id;
848 };
849
850 void LoadFamGrpMapInfo(vtkMutableDirectedGraph *sil, std::string& meshName, std::vector<Grp>& groups, std::vector<Fam>& fams)
851 {
852   if(!sil)
853     throw MZCException("LoadFamGrpMapInfo : internal error !");
854   int idNames(0);
855   vtkAbstractArray *verticesNames(sil->GetVertexData()->GetAbstractArray("Names",idNames));
856   vtkStringArray *verticesNames2(vtkStringArray::SafeDownCast(verticesNames));
857   vtkIdType id0;
858   bool found(false);
859   for(int i=0;i<verticesNames2->GetNumberOfValues();i++)
860     {
861       vtkStdString &st(verticesNames2->GetValue(i));
862       if(st=="MeshesFamsGrps")
863         {
864           id0=i;
865           found=true;
866         }
867     }
868   if(!found)
869     throw INTERP_KERNEL::Exception("There is an internal error ! The tree on server side has not the expected look !");
870   vtkAdjacentVertexIterator *it0(vtkAdjacentVertexIterator::New());
871   sil->GetAdjacentVertices(id0,it0);
872   int kk(0),ll(0);
873   while(it0->HasNext())
874     {
875       vtkIdType id1(it0->Next());
876       std::string mName((const char *)verticesNames2->GetValue(id1));
877       meshName=mName;
878       vtkAdjacentVertexIterator *it1(vtkAdjacentVertexIterator::New());
879       sil->GetAdjacentVertices(id1,it1);
880       vtkIdType idZeGrps(it1->Next());//zeGroups
881       vtkAdjacentVertexIterator *itGrps(vtkAdjacentVertexIterator::New());
882       sil->GetAdjacentVertices(idZeGrps,itGrps);
883       while(itGrps->HasNext())
884         {
885           vtkIdType idg(itGrps->Next());
886           Grp grp((const char *)verticesNames2->GetValue(idg));
887           vtkAdjacentVertexIterator *itGrps2(vtkAdjacentVertexIterator::New());
888           sil->GetAdjacentVertices(idg,itGrps2);
889           std::vector<std::string> famsOnGroup;
890           while(itGrps2->HasNext())
891             {
892               vtkIdType idgf(itGrps2->Next());
893               famsOnGroup.push_back(std::string((const char *)verticesNames2->GetValue(idgf)));
894             }
895           grp.setFamilies(famsOnGroup);
896           itGrps2->Delete();
897           groups.push_back(grp);
898         }
899       itGrps->Delete();
900       vtkIdType idZeFams(it1->Next());//zeFams
901       it1->Delete();
902       vtkAdjacentVertexIterator *itFams(vtkAdjacentVertexIterator::New());
903       sil->GetAdjacentVertices(idZeFams,itFams);
904       while(itFams->HasNext())
905         {
906           vtkIdType idf(itFams->Next());
907           Fam fam((const char *)verticesNames2->GetValue(idf));
908           fams.push_back(fam);
909         }
910       itFams->Delete();
911     }
912   it0->Delete();
913 }
914
915 int vtkMEDWriter::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector)
916
917   //std::cerr << "########################################## vtkMEDWriter::RequestInformation ########################################## " << (const char *) this->FileName << std::endl;
918   return 1;
919 }
920
921 void WriteMEDFileFromVTKDataSet(MEDFileData *mfd, vtkDataSet *ds, const std::vector<int>& context)
922 {
923   if(!ds || !mfd)
924     throw MZCException("Internal error in WriteMEDFileFromVTKDataSet.");
925   vtkPolyData *ds2(vtkPolyData::SafeDownCast(ds));
926   vtkUnstructuredGrid *ds3(vtkUnstructuredGrid::SafeDownCast(ds));
927   vtkRectilinearGrid *ds4(vtkRectilinearGrid::SafeDownCast(ds));
928   if(ds2)
929     {
930       ConvertFromPolyData(mfd,ds2,context);
931     }
932   else if(ds3)
933     {
934       ConvertFromUnstructuredGrid(mfd,ds3,context);
935     }
936   else if(ds4)
937     {
938       ConvertFromRectilinearGrid(mfd,ds4,context);
939     }
940   else
941     throw MZCException("Unrecognized vtkDataSet ! Sorry ! Try to convert it to UnstructuredGrid to be able to write it !");
942 }
943
944 void WriteMEDFileFromVTKMultiBlock(MEDFileData *mfd, vtkMultiBlockDataSet *ds, const std::vector<int>& context)
945 {
946   if(!ds || !mfd)
947     throw MZCException("Internal error in WriteMEDFileFromVTKMultiBlock.");
948   int nbBlocks(ds->GetNumberOfBlocks());
949   if(nbBlocks==1 && context.empty())
950     {
951       vtkDataObject *uniqueElt(ds->GetBlock(0));
952       if(!uniqueElt)
953         throw MZCException("Unique elt in multiblock is NULL !");
954       vtkDataSet *uniqueEltc(vtkDataSet::SafeDownCast(uniqueElt));
955       if(uniqueEltc)
956         {
957           WriteMEDFileFromVTKDataSet(mfd,uniqueEltc,context);
958           return ;
959         }
960     }
961   for(int i=0;i<nbBlocks;i++)
962     {
963       vtkDataObject *elt(ds->GetBlock(i));
964       std::vector<int> context2;
965       context2.push_back(i);
966       if(!elt)
967         {
968           std::ostringstream oss; oss << "In context ";
969           std::copy(context.begin(),context.end(),std::ostream_iterator<int>(oss," "));
970           oss << " at pos #" << i << " elt is NULL !";
971           throw MZCException(oss.str());
972         }
973       vtkDataSet *elt1(vtkDataSet::SafeDownCast(elt));
974       if(elt1)
975         {
976           WriteMEDFileFromVTKDataSet(mfd,elt1,context);
977           continue;
978         }
979       vtkMultiBlockDataSet *elt2(vtkMultiBlockDataSet::SafeDownCast(elt));
980       if(elt2)
981         {
982           WriteMEDFileFromVTKMultiBlock(mfd,elt2,context);
983           continue;
984         }
985       std::ostringstream oss; oss << "In context ";
986       std::copy(context.begin(),context.end(),std::ostream_iterator<int>(oss," "));
987       oss << " at pos #" << i << " elt not recognized data type !";
988       throw MZCException(oss.str());
989     }
990 }
991
992 void WriteMEDFileFromVTKGDS(MEDFileData *mfd, vtkDataObject *input)
993 {
994   if(!input || !mfd)
995     throw MZCException("WriteMEDFileFromVTKGDS : internal error !");
996   std::vector<int> context;
997   vtkDataSet *input1(vtkDataSet::SafeDownCast(input));
998   if(input1)
999     {
1000       WriteMEDFileFromVTKDataSet(mfd,input1,context);
1001       return ;
1002     }
1003   vtkMultiBlockDataSet *input2(vtkMultiBlockDataSet::SafeDownCast(input));
1004   if(input2)
1005     {
1006       WriteMEDFileFromVTKMultiBlock(mfd,input2,context);
1007       return ;
1008     }
1009   throw MZCException("WriteMEDFileFromVTKGDS : not recognized data type !");
1010 }
1011
1012 void PutFamGrpInfoIfAny(MEDFileData *mfd, const std::string& meshName, const std::vector<Grp>& groups, const std::vector<Fam>& fams)
1013 {
1014   if(!mfd)
1015     return ;
1016   if(meshName.empty())
1017     return ;
1018   MEDFileMeshes *meshes(mfd->getMeshes());
1019   if(!meshes)
1020     return ;
1021   if(meshes->getNumberOfMeshes()!=1)
1022     return ;
1023   MEDFileMesh *mm(meshes->getMeshAtPos(0));
1024   if(!mm)
1025     return ;
1026   mm->setName(meshName);
1027   for(std::vector<Fam>::const_iterator it=fams.begin();it!=fams.end();it++)
1028     mm->setFamilyId((*it).getName(),(*it).getID());
1029   for(std::vector<Grp>::const_iterator it=groups.begin();it!=groups.end();it++)
1030     mm->setFamiliesOnGroup((*it).getName(),(*it).getFamilies());
1031   MEDFileFields *fields(mfd->getFields());
1032   if(!fields)
1033     return ;
1034   for(int i=0;i<fields->getNumberOfFields();i++)
1035     {
1036       MEDFileAnyTypeFieldMultiTS *fmts(fields->getFieldAtPos(i));
1037       if(!fmts)
1038         continue;
1039       fmts->setMeshName(meshName);
1040     }
1041 }
1042
1043 int vtkMEDWriter::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector)
1044 {
1045   //std::cerr << "########################################## vtkMEDWriter::RequestData        ########################################## " << (const char *) this->FileName << std::endl;
1046   try
1047     {
1048       vtkInformation *inputInfo(inputVector[0]->GetInformationObject(0));
1049       std::string meshName;
1050       std::vector<Grp> groups; std::vector<Fam> fams;
1051       if(IsInformationOK(inputInfo))
1052         {
1053           vtkMutableDirectedGraph *famGrpGraph(vtkMutableDirectedGraph::SafeDownCast(inputInfo->Get(GetMEDReaderMetaDataIfAny())));
1054           LoadFamGrpMapInfo(famGrpGraph,meshName,groups,fams);
1055         }
1056       vtkInformation *outInfo(outputVector->GetInformationObject(0));
1057       vtkDataObject *input(vtkDataObject::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT())));
1058       if(!input)
1059         throw MZCException("Not recognized data object in input of the MEDWriter ! Maybe not implemented yet !");
1060       MCAuto<MEDFileData> mfd(MEDFileData::New());
1061       WriteMEDFileFromVTKGDS(mfd,input);
1062       PutFamGrpInfoIfAny(mfd,meshName,groups,fams);
1063       mfd->write(this->FileName,this->IsTouched?0:2); this->IsTouched=true;
1064       outInfo->Set(vtkDataObject::DATA_OBJECT(),input);
1065     }
1066   catch(MZCException& e)
1067     {
1068       std::ostringstream oss;
1069       oss << "Exception has been thrown in vtkMEDWriter::RequestData : During writing of \"" << (const char *) this->FileName << "\", the following exception has been thrown : "<< e.what() << std::endl;
1070       if(this->HasObserver("ErrorEvent") )
1071         this->InvokeEvent("ErrorEvent",const_cast<char *>(oss.str().c_str()));
1072       else
1073         vtkOutputWindowDisplayErrorText(const_cast<char *>(oss.str().c_str()));
1074       vtkObject::BreakOnError();
1075       return 0;
1076     }
1077   return 1;
1078 }
1079
1080 void vtkMEDWriter::PrintSelf(ostream& os, vtkIndent indent)
1081 {
1082   this->Superclass::PrintSelf(os, indent);
1083 }
1084
1085 int vtkMEDWriter::Write()
1086 {
1087   this->Update();
1088   return 0;
1089 }