00001
00002
00003 #ifndef DUNE_VTKWRITER_HH
00004 #define DUNE_VTKWRITER_HH
00005
00006 #include <iostream>
00007 #include <fstream>
00008 #include <vector>
00009 #include <list>
00010 #include <string.h>
00011 #include <dune/common/exceptions.hh>
00012 #include <dune/common/iteratorfacades.hh>
00013 #include <dune/grid/common/mcmgmapper.hh>
00014 #include <dune/grid/common/referenceelements.hh>
00015
00016
00017
00018
00019
00020
00021
00032 namespace Dune
00033 {
00036 struct VTKOptions
00037 {
00038 enum OutputType {
00040 ascii,
00042 binary,
00044 binaryappended
00045 };
00046 enum DataMode {
00047 conforming, nonconforming
00048 };
00049 };
00050
00051
00052
00053 template<class T>
00054 struct VTKTypeNameTraits {
00055 std::string operator () (){
00056 return "";
00057 }
00058 };
00059
00060 template<>
00061 struct VTKTypeNameTraits<char> {
00062 std::string operator () () {
00063 return "Int8";
00064 }
00065 typedef int PrintType;
00066 };
00067
00068 template<>
00069 struct VTKTypeNameTraits<unsigned char> {
00070 std::string operator () () {
00071 return "UInt8";
00072 }
00073 typedef int PrintType;
00074 };
00075
00076 template<>
00077 struct VTKTypeNameTraits<short> {
00078 std::string operator () () {
00079 return "Int16";
00080 }
00081 typedef short PrintType;
00082 };
00083
00084 template<>
00085 struct VTKTypeNameTraits<unsigned short> {
00086 std::string operator () () {
00087 return "UInt16";
00088 }
00089 typedef unsigned short PrintType;
00090 };
00091
00092 template<>
00093 struct VTKTypeNameTraits<int> {
00094 std::string operator () () {
00095 return "Int32";
00096 }
00097 typedef int PrintType;
00098 };
00099
00100 template<>
00101 struct VTKTypeNameTraits<unsigned int> {
00102 std::string operator () () {
00103 return "UInt32";
00104 }
00105 typedef unsigned int PrintType;
00106 };
00107
00108 template<>
00109 struct VTKTypeNameTraits<float> {
00110 std::string operator () () {
00111 return "Float32";
00112 }
00113 typedef float PrintType;
00114 };
00115
00116 template<>
00117 struct VTKTypeNameTraits<double> {
00118 std::string operator () () {
00119 return "Float64";
00120 }
00121 typedef double PrintType;
00122 };
00123
00124
00133 template<class GridImp, class IS=typename GridImp::template Codim<0>::LeafIndexSet>
00134 class VTKWriter {
00135 template<int dim>
00136 struct P0Layout
00137 {
00138 bool contains (Dune::GeometryType gt)
00139 {
00140 return gt.dim()==dim;
00141 }
00142 };
00143
00144 template<int dim>
00145 struct P1Layout
00146 {
00147 bool contains (Dune::GeometryType gt)
00148 {
00149 return gt.dim()==0;
00150 }
00151 };
00152
00153
00154 enum {n=GridImp::dimension};
00155 enum {w=GridImp::dimensionworld};
00156 typedef typename GridImp::ctype DT;
00157 typedef typename GridImp::Traits::template Codim<0>::Entity Entity;
00158 typedef typename GridImp::Traits::template Codim<0>::Entity Cell;
00159 typedef typename GridImp::Traits::template Codim<n>::Entity Vertex;
00160 typedef IS IndexSet;
00161 static const PartitionIteratorType vtkPartition = InteriorBorder_Partition;
00162 typedef typename IS::template Codim<0>::template Partition<vtkPartition>::Iterator GridCellIterator;
00163 typedef typename IS::template Codim<n>::template Partition<vtkPartition>::Iterator GridVertexIterator;
00164 typedef MultipleCodimMultipleGeomTypeMapper<GridImp,IS,P1Layout> VertexMapper;
00165 public:
00166
00172 class VTKFunction
00173 {
00174 public:
00176 virtual int ncomps () const = 0;
00177
00179
00185 virtual double evaluate (int comp, const Entity& e, const Dune::FieldVector<DT,n>& xi) const = 0;
00186
00188 virtual std::string name () const = 0;
00189
00191 virtual ~VTKFunction () {}
00192 };
00193
00194 private:
00195 typedef typename std::list<VTKFunction*>::iterator FunctionIterator;
00196
00197 class CellIterator :
00198 public ForwardIteratorFacade<CellIterator, Entity, Entity&, int>
00199 {
00200 GridCellIterator git;
00201 GridCellIterator gend;
00202 public:
00203 CellIterator(const GridCellIterator & x, const GridCellIterator & end) : git(x), gend(end) {};
00204 void increment ()
00205 {
00206 ++git;
00207 while (git!=gend && git->partitionType()!=InteriorEntity) ++git;
00208 }
00209 bool equals (const CellIterator & cit) const
00210 {
00211 return git == cit.git;
00212 }
00213 Entity& dereference() const
00214 {
00215 return *git;
00216 }
00217 const FieldVector<DT,n> position() const
00218 {
00219 return ReferenceElements<DT,n>::general(git->geometry().type()).position(0,0);
00220 }
00221 };
00222 CellIterator cellBegin() const
00223 {
00224 return CellIterator(is.template begin<0,vtkPartition>(), is.template end<0,vtkPartition>());
00225 }
00226 CellIterator cellEnd() const
00227 {
00228 return CellIterator(is.template end<0,vtkPartition>(), is.template end<0,vtkPartition>());
00229 }
00230
00231 class VertexIterator :
00232 public ForwardIteratorFacade<VertexIterator, Entity, Entity&, int>
00233 {
00234 GridCellIterator git;
00235 GridCellIterator gend;
00236 VTKOptions::DataMode datamode;
00237 int index;
00238 const VertexMapper & vertexmapper;
00239 std::vector<bool> visited;
00240 const std::vector<int> & number;
00241 int offset;
00242 protected:
00243 void basicIncrement ()
00244 {
00245 if (git == gend) return;
00246 index++;
00247 if (index == git->template count<n>()) {
00248 offset += git->template count<n>();
00249 index = 0;
00250 ++git;
00251 if(git == gend) return;
00252 while (git->partitionType()!=InteriorEntity) ++git;
00253 }
00254 }
00255 public:
00256 VertexIterator(const GridCellIterator & x,
00257 const GridCellIterator & end,
00258 const VTKOptions::DataMode & dm,
00259 const VertexMapper & vm,
00260 const std::vector<int> & num) :
00261 git(x), gend(end), datamode(dm), index(0),
00262 vertexmapper(vm), visited(vm.size(), false),
00263 number(num), offset(0)
00264 {
00265 if (datamode == VTKOptions::conforming && git != gend)
00266 visited[vertexmapper.template map<n>(*git,index)] = true;
00267 };
00268 void increment ()
00269 {
00270 switch (datamode)
00271 {
00272 case VTKOptions::conforming:
00273 while(visited[vertexmapper.template map<n>(*git,index)])
00274 {
00275 basicIncrement();
00276 if (git == gend) return;
00277 }
00278 visited[vertexmapper.template map<n>(*git,index)] = true;
00279 break;
00280 case VTKOptions::nonconforming:
00281 basicIncrement();
00282 break;
00283 }
00284 }
00285 bool equals (const VertexIterator & cit) const
00286 {
00287 return git == cit.git
00288 && index == cit.index && datamode == cit.datamode;
00289 }
00290 Entity& dereference() const
00291 {
00292 return *git;
00293 }
00294 int id () const
00295 {
00296 switch (datamode)
00297 {
00298 case VTKOptions::conforming:
00299 return
00300 number[vertexmapper.template map<n>(*git,renumber(*git,index))];
00301 case VTKOptions::nonconforming:
00302 return offset + renumber(*git,index);
00303 default:
00304 DUNE_THROW(IOError,"VTKWriter: unsupported DataMode" << datamode);
00305 }
00306 }
00307 int localindex () const
00308 {
00309 return index;
00310 }
00311 const FieldVector<DT,n> & position () const
00312 {
00313 return ReferenceElements<DT,n>::general(git->geometry().type()).position(index,n);
00314 }
00315 };
00316 VertexIterator vertexBegin() const
00317 {
00318 return VertexIterator(is.template begin<0,vtkPartition>(),
00319 is.template end<0,vtkPartition>(),
00320 datamode, *vertexmapper, number);
00321 }
00322 VertexIterator vertexEnd() const
00323 {
00324 return VertexIterator(is.template end<0,vtkPartition>(),
00325 is.template end<0,vtkPartition>(),
00326 datamode, *vertexmapper, number);
00327 }
00328
00329 class CornerIterator :
00330 public ForwardIteratorFacade<CornerIterator, Entity, Entity&, int>
00331 {
00332 GridCellIterator git;
00333 GridCellIterator gend;
00334 VTKOptions::DataMode datamode;
00335 int index;
00336 const VertexMapper & vertexmapper;
00337 std::vector<bool> visited;
00338 const std::vector<int> & number;
00339 int offset;
00340 protected:
00341 void basicIncrement ()
00342 {
00343 if (git == gend) return;
00344 index++;
00345 if (index == git->template count<n>()) {
00346 offset += git->template count<n>();
00347 index = 0;
00348 ++git;
00349 if (git == gend) return;
00350 while (git->partitionType()!=InteriorEntity) ++git;
00351 }
00352 }
00353 public:
00354 CornerIterator(const GridCellIterator & x,
00355 const GridCellIterator & end,
00356 const VTKOptions::DataMode & dm,
00357 const VertexMapper & vm,
00358 const std::vector<int> & num) :
00359 git(x), gend(end), datamode(dm), index(0),
00360 vertexmapper(vm),
00361 number(num), offset(0) {};
00362 void increment ()
00363 {
00364 basicIncrement();
00365 }
00366 bool equals (const CornerIterator & cit) const
00367 {
00368 return git == cit.git
00369 && index == cit.index && datamode == cit.datamode;
00370 }
00371 Entity& dereference() const
00372 {
00373 return *git;
00374 }
00375 int id () const
00376 {
00377 switch (datamode)
00378 {
00379 case VTKOptions::conforming:
00380 return
00381 number[vertexmapper.template map<n>(*git,renumber(*git,index))];
00382 case VTKOptions::nonconforming:
00383 return offset + renumber(*git,index);
00384 default:
00385 DUNE_THROW(IOError,"VTKWriter: unsupported DataMode" << datamode);
00386 }
00387 }
00388 int localindex () const
00389 {
00390 return index;
00391 }
00392 };
00393 CornerIterator cornerBegin() const
00394 {
00395 return CornerIterator(is.template begin<0,vtkPartition>(),
00396 is.template end<0,vtkPartition>(),
00397 datamode, *vertexmapper, number);
00398 }
00399 CornerIterator cornerEnd() const
00400 {
00401 return CornerIterator(is.template end<0,vtkPartition>(),
00402 is.template end<0,vtkPartition>(),
00403 datamode, *vertexmapper, number);
00404 }
00405
00409 template<class V>
00410 class P0VectorWrapper : public VTKFunction
00411 {
00412 typedef MultipleCodimMultipleGeomTypeMapper<GridImp,IS,P0Layout> VM0;
00413 public:
00415 virtual int ncomps () const
00416 {
00417 return 1;
00418 }
00419
00421 virtual double evaluate (int comp, const Entity& e, const Dune::FieldVector<DT,n>& xi) const
00422 {
00423 return v[mapper.map(e)];
00424 }
00425
00427 virtual std::string name () const
00428 {
00429 return s;
00430 }
00431
00433 P0VectorWrapper (const GridImp& g_, const IS& is_, const V& v_, std::string s_)
00434 : g(g_), is(is_), v(v_), s(s_), mapper(g_,is_)
00435 {
00436 if (v.size()!=(unsigned int)mapper.size())
00437 DUNE_THROW(IOError,"VTKWriter::P0VectorWrapper: size mismatch");
00438 }
00439
00440 virtual ~P0VectorWrapper() {}
00441
00442 private:
00443 const GridImp& g;
00444 const IS& is;
00445 const V& v;
00446 std::string s;
00447 VM0 mapper;
00448 };
00449
00453 template<class V>
00454 class P1VectorWrapper : public VTKFunction
00455 {
00456 typedef MultipleCodimMultipleGeomTypeMapper<GridImp,IS,P1Layout> VM1;
00457 public:
00459 virtual int ncomps () const
00460 {
00461 return 1;
00462 }
00463
00465 virtual double evaluate (int comp, const Entity& e, const Dune::FieldVector<DT,n>& xi) const
00466 {
00467 double min=1E100;
00468 int imin=-1;
00469 Dune::GeometryType gt = e.geometry().type();
00470 for (int i=0; i<e.template count<n>(); ++i)
00471 {
00472 Dune::FieldVector<DT,n>
00473 local = Dune::ReferenceElements<DT,n>::general(gt).position(i,n);
00474 local -= xi;
00475 if (local.infinity_norm()<min)
00476 {
00477 min = local.infinity_norm();
00478 imin = i;
00479 }
00480 }
00481 return v[mapper.template map<n>(e,imin)];
00482 }
00483
00485 virtual std::string name () const
00486 {
00487 return s;
00488 }
00489
00491 P1VectorWrapper (const GridImp& g_, const IS& is_, const V& v_, std::string s_)
00492 : g(g_), is(is_), v(v_), s(s_), mapper(g_,is_)
00493 {
00494 if (v.size()!=(unsigned int)mapper.size())
00495 DUNE_THROW(IOError,"VTKWriter::P1VectorWrapper: size mismatch");
00496 }
00497
00498 virtual ~P1VectorWrapper() {}
00499
00500 private:
00501 const GridImp& g;
00502 const IS& is;
00503 const V& v;
00504 std::string s;
00505 VM1 mapper;
00506 };
00507
00508 public:
00518 VTKWriter (const GridImp& g, VTKOptions::DataMode dm = VTKOptions::conforming) :
00519 grid(g), is(grid.leafIndexSet()), datamode(dm)
00520 {
00521 indentCount = 0;
00522 numPerLine = 4*3;
00523 }
00524
00533 VTKWriter (const GridImp& g, const IndexSet& i, VTKOptions::DataMode dm = VTKOptions::conforming) :
00534 grid(g), is(i), datamode(dm)
00535 {
00536 indentCount = 0;
00537 numPerLine = 4*3;
00538 }
00539
00544 void addCellData (VTKFunction* p)
00545 {
00546 celldata.push_back(p);
00547 }
00548
00560 template<class V>
00561 void addCellData (const V& v, std::string name)
00562 {
00563 VTKFunction* p = new P0VectorWrapper<V>(grid,is,v,name);
00564 celldata.push_back(p);
00565 }
00566
00571 void addVertexData (VTKFunction* p)
00572 {
00573 vertexdata.push_back(p);
00574 }
00575
00587 template<class V>
00588 void addVertexData (const V& v, std::string name)
00589 {
00590 VTKFunction* p = new P1VectorWrapper<V>(grid,is,v,name);
00591 vertexdata.push_back(p);
00592 }
00593
00595 void clear ()
00596 {
00597 for (FunctionIterator it=celldata.begin();
00598 it!=celldata.end(); ++it)
00599 delete *it;
00600 celldata.clear();
00601 for (FunctionIterator it=vertexdata.begin();
00602 it!=vertexdata.end(); ++it)
00603 delete *it;
00604 vertexdata.clear();
00605 }
00606
00608 ~VTKWriter ()
00609 {
00610 this->clear();
00611 }
00612
00618 void write (const char* name, VTKOptions::OutputType ot = VTKOptions::ascii)
00619 {
00620
00621 outputtype=ot;
00622
00623
00624 bytecount = 0;
00625
00626 if (grid.comm().size()==1)
00627 {
00628 std::ofstream file;
00629 char fullname[128];
00630 if (n>1)
00631 sprintf(fullname,"%s.vtu",name);
00632 else
00633 sprintf(fullname,"%s.vtp",name);
00634 if (outputtype==VTKOptions::binaryappended)
00635 file.open(fullname,std::ios::binary);
00636 else
00637 file.open(fullname);
00638 writeDataFile(file);
00639 file.close();
00640 }
00641 else
00642 {
00643 std::ofstream file;
00644 char fullname[128];
00645 if (n>1)
00646 sprintf(fullname,"s%04d:p%04d:%s.vtu",grid.comm().size(),grid.comm().rank(),name);
00647 else
00648 sprintf(fullname,"s%04d:p%04d:%s.vtp",grid.comm().size(),grid.comm().rank(),name);
00649 if (outputtype==VTKOptions::binaryappended)
00650 file.open(fullname,std::ios::binary);
00651 else
00652 file.open(fullname);
00653 writeDataFile(file);
00654 file.close();
00655 grid.comm().barrier();
00656 if (grid.comm().rank()==0)
00657 {
00658 if (n>1)
00659 sprintf(fullname,"s%04d:%s.pvtu",grid.comm().size(),name);
00660 else
00661 sprintf(fullname,"s%04d:%s.pvtp",grid.comm().size(),name);
00662 file.open(fullname);
00663 writeParallelHeader(file,name,"");
00664 file.close();
00665 }
00666 grid.comm().barrier();
00667 }
00668 }
00669
00671 void pwrite (const char* name, const char* path, const char* extendpath,
00672 VTKOptions::OutputType ot = VTKOptions::ascii)
00673 {
00674
00675 outputtype=ot;
00676
00677
00678 bytecount = 0;
00679
00680
00681 std::ofstream file;
00682 char piecepath[256];
00683 char relpiecepath[256];
00684 int n=strlen(path);
00685 int m=strlen(extendpath);
00686 if (n>0 && path[0]=='/' && path[n-1]=='/')
00687 {
00688
00689
00690
00691 if (m==0)
00692 {
00693
00694 piecepath[0] = '/';
00695 piecepath[1] = '\0';
00696 }
00697 else
00698 {
00699
00700 char *p=piecepath;
00701 if (extendpath[0]!='/')
00702 {
00703 *p = '/';
00704 p++;
00705 }
00706 for (int i=0; i<m; i++)
00707 {
00708 *p = extendpath[i];
00709 p++;
00710 }
00711 if (*(p-1)!='/')
00712 {
00713 *p = '/';
00714 p++;
00715 }
00716 *p = '\0';
00717 }
00718
00719
00720 int k=0;
00721 const char *p=path;
00722 while (*p!='\0')
00723 {
00724 if (*p=='/') k++;
00725 p++;
00726 }
00727 char *pp = relpiecepath;
00728 if (k>1)
00729 {
00730 for (int i=0; i<k; i++)
00731 {
00732 *pp='.'; pp++; *pp='.'; pp++; *pp='/'; pp++;
00733 }
00734 }
00735
00736 for (int i=0; i<m; i++)
00737 {
00738 if (i==0 && extendpath[i]=='/') continue;
00739 *pp = extendpath[i];
00740 pp++;
00741 }
00742 if ( pp!=relpiecepath && (*(pp-1)!='/') )
00743 {
00744 *pp = '/';
00745 pp++;
00746 }
00747 *pp = '\0';
00748 }
00749 else
00750 {
00751
00752
00753 if (n==0 || m==0)
00754 sprintf(piecepath,"%s%s",path,extendpath);
00755 else
00756 {
00757
00758 if (path[n-1]!='/' && extendpath[0]!='/')
00759 sprintf(piecepath,"%s/%s",path,extendpath);
00760 else
00761 sprintf(piecepath,"%s%s",path,extendpath);
00762 }
00763
00764 sprintf(relpiecepath,"%s",extendpath);
00765 }
00766 char fullname[256];
00767 if (n>1)
00768 sprintf(fullname,"%s/s%04d:p%04d:%s.vtu",piecepath,grid.comm().size(),grid.comm().rank(),name);
00769 else
00770 sprintf(fullname,"%s/s%04d:p%04d:%s.vtp",piecepath,grid.comm().size(),grid.comm().rank(),name);
00771 if (outputtype==VTKOptions::binaryappended)
00772 file.open(fullname,std::ios::binary);
00773 else
00774 file.open(fullname);
00775 writeDataFile(file);
00776 file.close();
00777 grid.comm().barrier();
00778 if (grid.comm().rank()==0)
00779 {
00780 if (n>1)
00781 sprintf(fullname,"%s/s%04d:%s.pvtu",path,grid.comm().size(),name);
00782 else
00783 sprintf(fullname,"%s/s%04d:%s.pvtp",path,grid.comm().size(),name);
00784 file.open(fullname);
00785 writeParallelHeader(file,name,relpiecepath);
00786 file.close();
00787 }
00788 grid.comm().barrier();
00789 }
00790
00791 private:
00792
00793 enum VTKGeometryType
00794 {
00795 vtkLine = 3,
00796 vtkTriangle = 5,
00797 vtkQuadrilateral = 9,
00798 vtkTetrahedron = 10,
00799 vtkHexahedron = 12,
00800 vtkPrism = 13,
00801 vtkPyramid = 14
00802 };
00803
00805 static VTKGeometryType vtkType(const Dune::GeometryType & t)
00806 {
00807 if (t.isLine())
00808 return vtkLine;
00809 if (t.isTriangle())
00810 return vtkTriangle;
00811 if (t.isQuadrilateral())
00812 return vtkQuadrilateral;
00813 if (t.isTetrahedron())
00814 return vtkTetrahedron;
00815 if (t.isPyramid())
00816 return vtkPyramid;
00817 if (t.isPrism())
00818 return vtkPrism;
00819 if (t.isHexahedron())
00820 return vtkHexahedron;
00821 DUNE_THROW(IOError,"VTKWriter: unsupported GeometryType " << t);
00822 }
00823
00825 void writeParallelHeader (std::ostream& s, const char* piecename, const char* piecepath)
00826 {
00827
00828 s << "<?xml version=\"1.0\"?>" << std::endl;
00829
00830
00831 if (n>1)
00832 s << "<VTKFile type=\"PUnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">" << std::endl;
00833 else
00834 s << "<VTKFile type=\"PPolyData\" version=\"0.1\" byte_order=\"LittleEndian\">" << std::endl;
00835 indentUp();
00836
00837
00838 indent(s);
00839 if (n>1)
00840 s << "<PUnstructuredGrid GhostLevel=\"0\">" << std::endl;
00841 else
00842 s << "<PPolyData GhostLevel=\"0\">" << std::endl;
00843 indentUp();
00844
00845
00846 indent(s); s << "<PPointData";
00847 for (FunctionIterator it=vertexdata.begin(); it!=vertexdata.end(); ++it)
00848 if ((*it)->ncomps()==1)
00849 {
00850 s << " Scalars=\"" << (*it)->name() << "\"" ;
00851 break;
00852 }
00853 for (FunctionIterator it=vertexdata.begin(); it!=vertexdata.end(); ++it)
00854 if ((*it)->ncomps()>1)
00855 {
00856 s << " Vectors=\"" << (*it)->name() << "\"" ;
00857 break;
00858 }
00859 s << ">" << std::endl;
00860 indentUp();
00861 for (FunctionIterator it=vertexdata.begin(); it!=vertexdata.end(); ++it)
00862 {
00863 indent(s); s << "<PDataArray type=\"Float32\" Name=\"" << (*it)->name() << "\" ";
00864 s << "NumberOfComponents=\"" << ((*it)->ncomps()>1?3:1) << "\" ";
00865 if (outputtype==VTKOptions::ascii)
00866 s << "format=\"ascii\"/>" << std::endl;
00867 if (outputtype==VTKOptions::binary)
00868 s << "format=\"binary\"/>" << std::endl;
00869 if (outputtype==VTKOptions::binaryappended)
00870 s << "format=\"appended\"/>" << std::endl;
00871 }
00872 indentDown();
00873 indent(s); s << "</PPointData>" << std::endl;
00874
00875
00876 indent(s); s << "<PCellData";
00877 for (FunctionIterator it=celldata.begin(); it!=celldata.end(); ++it)
00878 if ((*it)->ncomps()==1)
00879 {
00880 s << " Scalars=\"" << (*it)->name() << "\"" ;
00881 break;
00882 }
00883 for (FunctionIterator it=celldata.begin(); it!=celldata.end(); ++it)
00884 if ((*it)->ncomps()>1)
00885 {
00886 s << " Vectors=\"" << (*it)->name() << "\"" ;
00887 break;
00888 }
00889 s << ">" << std::endl;
00890 indentUp();
00891 for (FunctionIterator it=celldata.begin(); it!=celldata.end(); ++it)
00892 {
00893 indent(s); s << "<PDataArray type=\"Float32\" Name=\"" << (*it)->name() << "\" ";
00894 s << "NumberOfComponents=\"" << ((*it)->ncomps()>1?3:1) << "\" ";
00895 if (outputtype==VTKOptions::ascii)
00896 s << "format=\"ascii\"/>" << std::endl;
00897 if (outputtype==VTKOptions::binary)
00898 s << "format=\"binary\"/>" << std::endl;
00899 if (outputtype==VTKOptions::binaryappended)
00900 s << "format=\"appended\"/>" << std::endl;
00901 }
00902 indentDown();
00903 indent(s); s << "</PCellData>" << std::endl;
00904
00905
00906 indent(s); s << "<PPoints>" << std::endl;
00907 indentUp();
00908 indent(s); s << "<PDataArray type=\"Float32\" Name=\"Coordinates\" NumberOfComponents=\"" << "3" << "\" ";
00909 if (outputtype==VTKOptions::ascii)
00910 s << "format=\"ascii\"/>" << std::endl;
00911 if (outputtype==VTKOptions::binary)
00912 s << "format=\"binary\"/>" << std::endl;
00913 if (outputtype==VTKOptions::binaryappended)
00914 s << "format=\"appended\"/>" << std::endl;
00915 indentDown();
00916 indent(s); s << "</PPoints>" << std::endl;
00917
00918
00919 for (int i=0; i<grid.comm().size(); i++)
00920 {
00921 char fullname[128];
00922 if (n>1)
00923 sprintf(fullname,"%s/s%04d:p%0d:%s.vtu",piecepath,grid.comm().size(),i,piecename);
00924 else
00925 sprintf(fullname,"%s/s%04d:p%0d:%s.vtp",piecepath,grid.comm().size(),i,piecename);
00926 indent(s); s << "<Piece Source=\"" << fullname << "\"/>" << std::endl;
00927 }
00928
00929
00930 indentDown();
00931 indent(s);
00932 if (n>1)
00933 s << "</PUnstructuredGrid>" << std::endl;
00934 else
00935 s << "</PPolyData>" << std::endl;
00936
00937
00938 indentDown();
00939 s << "</VTKFile>" << std::endl;
00940 }
00941
00943 void writeDataFile (std::ostream& s)
00944 {
00945
00946 s << "<?xml version=\"1.0\"?>" << std::endl;
00947
00948
00949 if (n>1)
00950 s << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">" << std::endl;
00951 else
00952 s << "<VTKFile type=\"PolyData\" version=\"0.1\" byte_order=\"LittleEndian\">" << std::endl;
00953 indentUp();
00954
00955
00956 vertexmapper = new VertexMapper(grid,is);
00957 if (datamode == VTKOptions::conforming)
00958 {
00959 number.resize(vertexmapper->size());
00960 for (std::vector<int>::size_type i=0; i<number.size(); i++) number[i] = -1;
00961 }
00962 nvertices = 0;
00963 ncells = 0;
00964 ncorners = 0;
00965 for (CellIterator it=cellBegin(); it!=cellEnd(); ++it)
00966 {
00967 ncells++;
00968 for (int i=0; i<it->template count<n>(); ++i)
00969 {
00970 ncorners++;
00971 if (datamode == VTKOptions::conforming)
00972 {
00973 int alpha = vertexmapper->template map<n>(*it,i);
00974 if (number[alpha]<0)
00975 number[alpha] = nvertices++;
00976 }
00977 else
00978 {
00979 nvertices++;
00980 }
00981 }
00982 }
00983
00984
00985 indent(s);
00986 if (n>1)
00987 s << "<UnstructuredGrid>" << std::endl;
00988 else
00989 s << "<PolyData>" << std::endl;
00990 indentUp();
00991
00992
00993 indent(s);
00994 if (n>1)
00995 s << "<Piece NumberOfPoints=\"" << nvertices << "\" NumberOfCells=\"" << ncells << "\">" << std::endl;
00996 else
00997 s << "<Piece NumberOfPoints=\"" << nvertices << "\""
00998 << " NumberOfVerts=\"0\""
00999 << " NumberOfLines=\"" << ncells << "\">"
01000 << " NumberOfPolys=\"0\"" << std::endl;
01001 indentUp();
01002
01003
01004 writeVertexData(s);
01005
01006
01007 writeCellData(s);
01008
01009
01010 writeGridPoints(s);
01011
01012
01013 writeGridCells(s);
01014
01015
01016 indentDown();
01017 indent(s); s << "</Piece>" << std::endl;
01018
01019
01020 indentDown();
01021 indent(s);
01022 if (n>1)
01023 s << "</UnstructuredGrid>" << std::endl;
01024 else
01025 s << "</PolyData>" << std::endl;
01026
01027
01028 if (outputtype==VTKOptions::binaryappended)
01029 writeAppendedData(s);
01030
01031
01032 indentDown();
01033 s << "</VTKFile>" << std::endl;
01034
01035 delete vertexmapper; number.clear();
01036 }
01037
01038 void writeCellData (std::ostream& s)
01039 {
01040 indent(s); s << "<CellData";
01041 for (FunctionIterator it=celldata.begin(); it!=celldata.end(); ++it)
01042 if ((*it)->ncomps()==1)
01043 {
01044 s << " Scalars=\"" << (*it)->name() << "\"" ;
01045 break;
01046 }
01047 for (FunctionIterator it=celldata.begin(); it!=celldata.end(); ++it)
01048 if ((*it)->ncomps()>1)
01049 {
01050 s << " Vectors=\"" << (*it)->name() << "\"" ;
01051 break;
01052 }
01053 s << ">" << std::endl;
01054 indentUp();
01055 for (FunctionIterator it=celldata.begin(); it!=celldata.end(); ++it)
01056 {
01057 VTKDataArrayWriter<float> *p=0;
01058 if (outputtype==VTKOptions::ascii)
01059 p = new VTKAsciiDataArrayWriter<float>(s,(*it)->name(),(*it)->ncomps());
01060 if (outputtype==VTKOptions::binary)
01061 p = new VTKBinaryDataArrayWriter<float>(s,(*it)->name(),(*it)->ncomps(),(*it)->ncomps()*ncells);
01062 if (outputtype==VTKOptions::binaryappended)
01063 p = new VTKBinaryAppendedDataArrayWriter<float>(s,(*it)->name(),(*it)->ncomps(),bytecount);
01064 for (CellIterator i=cellBegin(); i!=cellEnd(); ++i)
01065 for (int j=0; j<(*it)->ncomps(); j++)
01066 p->write((*it)->evaluate(j,*i,i.position()));
01067 delete p;
01068 }
01069 indentDown();
01070 indent(s); s << "</CellData>" << std::endl;
01071 }
01072
01073 void writeVertexData (std::ostream& s)
01074 {
01075 indent(s); s << "<PointData";
01076 for (FunctionIterator it=vertexdata.begin(); it!=vertexdata.end(); ++it)
01077 if ((*it)->ncomps()==1)
01078 {
01079 s << " Scalars=\"" << (*it)->name() << "\"" ;
01080 break;
01081 }
01082 for (FunctionIterator it=vertexdata.begin(); it!=vertexdata.end(); ++it)
01083 if ((*it)->ncomps()>1)
01084 {
01085 s << " Vectors=\"" << (*it)->name() << "\"" ;
01086 break;
01087 }
01088 s << ">" << std::endl;
01089 indentUp();
01090 for (FunctionIterator it=vertexdata.begin(); it!=vertexdata.end(); ++it)
01091 {
01092 VTKDataArrayWriter<float> *p=0;
01093 if (outputtype==VTKOptions::ascii)
01094 p = new VTKAsciiDataArrayWriter<float>(s,(*it)->name(),(*it)->ncomps());
01095 if (outputtype==VTKOptions::binary)
01096 p = new VTKBinaryDataArrayWriter<float>(s,(*it)->name(),(*it)->ncomps(),(*it)->ncomps()*nvertices);
01097 if (outputtype==VTKOptions::binaryappended)
01098 p = new VTKBinaryAppendedDataArrayWriter<float>(s,(*it)->name(),(*it)->ncomps(),bytecount);
01099 for (VertexIterator vit=vertexBegin(); vit!=vertexEnd(); ++vit)
01100 {
01101 for (int j=0; j<(*it)->ncomps(); j++)
01102 p->write((*it)->evaluate(j,*vit,vit.position()));
01103
01104 if((*it)->ncomps()==2)
01105 p->write(0.0);
01106 }
01107 delete p;
01108 }
01109 indentDown();
01110 indent(s); s << "</PointData>" << std::endl;
01111 }
01112
01113 void writeGridPoints (std::ostream& s)
01114 {
01115 indent(s); s << "<Points>" << std::endl;
01116 indentUp();
01117
01118 VTKDataArrayWriter<float> *p=0;
01119 if (outputtype==VTKOptions::ascii)
01120 p = new VTKAsciiDataArrayWriter<float>(s,"Coordinates",3);
01121 if (outputtype==VTKOptions::binary)
01122 p = new VTKBinaryDataArrayWriter<float>(s,"Coordinates",3,3*nvertices);
01123 if (outputtype==VTKOptions::binaryappended)
01124 p = new VTKBinaryAppendedDataArrayWriter<float>(s,"Coordinates",3,bytecount);
01125 for (VertexIterator vit=vertexBegin(); vit!=vertexEnd(); ++vit)
01126 {
01127 int dimw=w;
01128 for (int j=0; j<std::min(dimw,3); j++)
01129 p->write(vit->geometry()[vit.localindex()][j]);
01130 for (int j=std::min(dimw,3); j<3; j++)
01131 p->write(0.0);
01132 }
01133 delete p;
01134
01135 indentDown();
01136 indent(s); s << "</Points>" << std::endl;
01137 }
01138
01139 void writeGridCells (std::ostream& s)
01140 {
01141 indent(s);
01142 if (n>1)
01143 s << "<Cells>" << std::endl;
01144 else
01145 s << "<Lines>" << std::endl;
01146 indentUp();
01147
01148
01149 VTKDataArrayWriter<int> *p1=0;
01150 if (outputtype==VTKOptions::ascii)
01151 p1 = new VTKAsciiDataArrayWriter<int>(s,"connectivity",1);
01152 if (outputtype==VTKOptions::binary)
01153 p1 = new VTKBinaryDataArrayWriter<int>(s,"connectivity",1,ncorners);
01154 if (outputtype==VTKOptions::binaryappended)
01155 p1 = new VTKBinaryAppendedDataArrayWriter<int>(s,"connectivity",1,bytecount);
01156 for (CornerIterator it=cornerBegin(); it!=cornerEnd(); ++it)
01157 p1->write(it.id());
01158 delete p1;
01159
01160
01161 VTKDataArrayWriter<int> *p2=0;
01162 if (outputtype==VTKOptions::ascii)
01163 p2 = new VTKAsciiDataArrayWriter<int>(s,"offsets",1);
01164 if (outputtype==VTKOptions::binary)
01165 p2 = new VTKBinaryDataArrayWriter<int>(s,"offsets",1,ncells);
01166 if (outputtype==VTKOptions::binaryappended)
01167 p2 = new VTKBinaryAppendedDataArrayWriter<int>(s,"offsets",1,bytecount);
01168 {
01169 int offset = 0;
01170 for (CellIterator it=cellBegin(); it!=cellEnd(); ++it)
01171 {
01172 offset += it->template count<n>();
01173 p2->write(offset);
01174 }
01175 }
01176 delete p2;
01177
01178
01179 if (n>1)
01180 {
01181 VTKDataArrayWriter<unsigned char> *p3=0;
01182 if (outputtype==VTKOptions::ascii)
01183 p3 = new VTKAsciiDataArrayWriter<unsigned char>(s,"types",1);
01184 if (outputtype==VTKOptions::binary)
01185 p3 = new VTKBinaryDataArrayWriter<unsigned char>(s,"types",1,ncells);
01186 if (outputtype==VTKOptions::binaryappended)
01187 p3 = new VTKBinaryAppendedDataArrayWriter<unsigned char>(s,"types",1,bytecount);
01188 for (CellIterator it=cellBegin(); it!=cellEnd(); ++it)
01189 {
01190 int vtktype = vtkType(it->geometry().type());
01191 p3->write(vtktype);
01192 }
01193 delete p3;
01194 }
01195
01196 indentDown();
01197 indent(s);
01198 if (n>1)
01199 s << "</Cells>" << std::endl;
01200 else
01201 s << "</Lines>" << std::endl;
01202 }
01203
01204
01205 void writeAppendedData (std::ostream& s)
01206 {
01207 indent(s); s << "<AppendedData encoding=\"raw\">" << std::endl;
01208 indentUp();
01209 indent(s); s << "_";
01210
01211 SimpleStream stream(s);
01212
01213
01214 unsigned long blocklength;
01215
01216
01217 for (FunctionIterator it=vertexdata.begin(); it!=vertexdata.end(); ++it)
01218 {
01219
01220 blocklength = nvertices * (*it)->ncomps() * sizeof(float);
01221
01222 if((*it)->ncomps()==2)
01223 blocklength = nvertices * (3) * sizeof(float);
01224 stream.write(blocklength);
01225 std::vector<bool> visited(vertexmapper->size(), false);
01226 #if 0
01227 for (CellIterator eit=is.template begin<0,vtkPartition>(); eit!=is.template end<0,vtkPartition>(); ++eit)
01228 if (eit->partitionType()==InteriorEntity)
01229 for (int i=0; i<eit->template count<n>(); ++i)
01230 if (datamode == VTKOptions::conforming)
01231 {
01232 int alpha = vertexmapper->template map<n>(*eit,i);
01233 if (!visited[alpha])
01234 {
01235 for (int j=0; j<(*it)->ncomps(); j++)
01236 {
01237 float data = (*it)->evaluate(j,*eit,ReferenceElements<DT,n>::general(eit->geometry().type()).position(i,n));
01238 stream.write(data);
01239 }
01240 visited[alpha] = true;
01241 }
01242 }
01243 else
01244 {
01245 for (int j=0; j<(*it)->ncomps(); j++)
01246 {
01247 float data = (*it)->evaluate(j,*eit,ReferenceElements<DT,n>::general(eit->geometry().type()).position(i,n));
01248 stream.write(data);
01249 }
01250 }
01251 #else
01252 for (VertexIterator vit=vertexBegin(); vit!=vertexEnd(); ++vit)
01253 {
01254 for (int j=0; j<(*it)->ncomps(); j++)
01255 {
01256 float data = (*it)->evaluate(j,*vit,vit.position());
01257 stream.write(data);
01258 }
01259
01260 if((*it)->ncomps()==2){
01261 float data=0.0;
01262 stream.write(data);}
01263 }
01264 #endif
01265 }
01266
01267
01268 for (FunctionIterator it=celldata.begin(); it!=celldata.end(); ++it)
01269 {
01270 blocklength = ncells * (*it)->ncomps() * sizeof(float);
01271 stream.write(blocklength);
01272 for (CellIterator i=cellBegin(); i!=cellEnd(); ++i)
01273 for (int j=0; j<(*it)->ncomps(); j++)
01274 {
01275 float data = (*it)->evaluate(j,*i,i.position());
01276 stream.write(data);
01277 }
01278 }
01279
01280
01281 blocklength = nvertices * 3 * sizeof(float);
01282 stream.write(blocklength);
01283 std::vector<bool> visited(vertexmapper->size(), false);
01284 #if 0
01285 for (CellIterator it=is.template begin<0,vtkPartition>(); it!=is.template end<0,vtkPartition>(); ++it)
01286 if (it->partitionType()==InteriorEntity)
01287 for (int i=0; i<it->template count<n>(); ++i)
01288 if (datamode == VTKOptions::conforming)
01289 {
01290 int alpha = vertexmapper->template map<n>(*it,i);
01291 if (!visited[alpha])
01292 {
01293 int dimw=w;
01294 float data;
01295 for (int j=0; j<std::min(dimw,3); j++)
01296 {
01297 data = it->geometry()[i][j];
01298 stream.write(data);
01299 }
01300 data = 0;
01301 for (int j=std::min(dimw,3); j<3; j++)
01302 stream.write(data);
01303 visited[alpha] = true;
01304 }
01305 }
01306 else
01307 {
01308 int dimw=w;
01309 float data;
01310 for (int j=0; j<std::min(dimw,3); j++)
01311 {
01312 data = it->geometry()[i][j];
01313 stream.write(data);
01314 }
01315 data = 0;
01316 for (int j=std::min(dimw,3); j<3; j++)
01317 stream.write(data);
01318 }
01319 #else
01320 for (VertexIterator vit=vertexBegin(); vit!=vertexEnd(); ++vit)
01321 {
01322 int dimw=w;
01323 float data;
01324 for (int j=0; j<std::min(dimw,3); j++)
01325 {
01326 data = vit->geometry()[vit.localindex()][j];
01327 stream.write(data);
01328 }
01329 data = 0;
01330 for (int j=std::min(dimw,3); j<3; j++)
01331 stream.write(data);
01332 }
01333 #endif
01334
01335
01336 blocklength = ncorners * sizeof(unsigned int);
01337 stream.write(blocklength);
01338 #if 0
01339 if (datamode == VTKOptions::conforming)
01340 {
01341 for (CellIterator it=is.template begin<0,vtkPartition>(); it!=is.template end<0,vtkPartition>(); ++it)
01342 if (it->partitionType()==InteriorEntity)
01343 for (int i=0; i<it->template count<n>(); ++i)
01344 {
01345 int data = number[vertexmapper->template map<n>(*it,renumber(*it,i))];
01346 stream.write(data);
01347 }
01348 }
01349 else
01350 {
01351 int offset = 0;
01352 for (CellIterator it=is.template begin<0,vtkPartition>(); it!=is.template end<0,vtkPartition>(); ++it)
01353 if (it->partitionType()==InteriorEntity)
01354 {
01355 for (int i=0; i<it->template count<n>(); ++i)
01356 {
01357 stream.write(offset + renumber(*it,i));
01358 }
01359 offset += it->template count<n>();
01360 }
01361 }
01362 #else
01363 for (CornerIterator it=cornerBegin(); it!=cornerEnd(); ++it)
01364 {
01365 stream.write(it.id());
01366 }
01367 #endif
01368
01369
01370 blocklength = ncells * sizeof(unsigned int);
01371 stream.write(blocklength);
01372 {
01373 int offset = 0;
01374 for (CellIterator it=cellBegin(); it!=cellEnd(); ++it)
01375 {
01376 offset += it->template count<n>();
01377 stream.write(offset);
01378 }
01379 }
01380
01381
01382 if (n>1)
01383 {
01384 blocklength = ncells * sizeof(unsigned char);
01385 stream.write(blocklength);
01386 for (CellIterator it=cellBegin(); it!=cellEnd(); ++it)
01387 {
01388 unsigned char vtktype = vtkType(it->geometry().type());
01389 stream.write(vtktype);
01390 }
01391 }
01392
01393 s << std::endl;
01394 indentDown();
01395 indent(s); s << "</AppendedData>" << std::endl;
01396 }
01397
01398
01399 template<class T>
01400 class VTKDataArrayWriter
01401 {
01402 public:
01403 virtual void write (T data) = 0;
01404 virtual ~VTKDataArrayWriter () {}
01405 };
01406
01407
01408 template<class T>
01409 class VTKAsciiDataArrayWriter : public VTKDataArrayWriter<T>
01410 {
01411 public:
01413 VTKAsciiDataArrayWriter (std::ostream& theStream, std::string name, int ncomps)
01414 : s(theStream), counter(0), numPerLine(12)
01415 {
01416 VTKTypeNameTraits<T> tn;
01417 s << "<DataArray type=\"" << tn() << "\" Name=\"" << name << "\" ";
01418
01419 s << "NumberOfComponents=\"" << (ncomps>1?3:1) << "\" ";
01420 s << "format=\"ascii\">" << std::endl;
01421 }
01422
01424 void write (T data)
01425 {
01426 typedef typename VTKTypeNameTraits<T>::PrintType PT;
01427 s << (PT) data << " ";
01428 counter++;
01429 if (counter%numPerLine==0) s << std::endl;
01430 }
01431
01433 ~VTKAsciiDataArrayWriter ()
01434 {
01435 if (counter%numPerLine!=0) s << std::endl;
01436 s << "</DataArray>" << std::endl;
01437 }
01438
01439 private:
01440 std::ostream& s;
01441 int counter;
01442 int numPerLine;
01443 };
01444
01445
01446 template<class T>
01447 class VTKBinaryDataArrayWriter : public VTKDataArrayWriter<T>
01448 {
01449 public:
01451 VTKBinaryDataArrayWriter (std::ostream& theStream, std::string name, int ncomps, int nitems)
01452 : s(theStream),bufsize(4096),n(0)
01453 {
01454 DUNE_THROW(IOError, "binary does not work yet, use binaryappended!");
01455 VTKTypeNameTraits<T> tn;
01456 s << "<DataArray type=\"" << tn() << "\" Name=\"" << name << "\" ";
01457
01458 s << "NumberOfComponents=\"" << (ncomps>1?3:1) << "\" ";
01459 s << "format=\"binary\">" << std::endl;
01460 buffer = new char[bufsize*sizeof(T)];
01461 code = new char[2*bufsize*sizeof(T)];
01462 unsigned int size = nitems*sizeof(T);
01463 char* p = reinterpret_cast<char*>(&size);
01464 memcpy(buffer+n,p,sizeof(int));
01465 n += sizeof(int);
01466
01467 }
01468
01470 void write (T data)
01471 {
01472 if (n+sizeof(T)>bufsize)
01473 {
01474
01475
01476
01477 n=0;
01478 }
01479 char* p = reinterpret_cast<char*>(&data);
01480 memcpy(buffer+n,p,sizeof(T));
01481 n += sizeof(T);
01482 }
01483
01485 ~VTKBinaryDataArrayWriter ()
01486 {
01487
01488 if (n>0)
01489 {
01490
01491
01492 }
01493
01494
01495
01496 s << std::endl;
01497 s << "</DataArray>" << std::endl;
01498 delete [] code;
01499 delete [] buffer;
01500 }
01501
01502 private:
01503 std::ostream& s;
01504
01505 size_t bufsize;
01506 char* buffer;
01507 char* code;
01508 int n;
01509 };
01510
01511
01512 template<class T>
01513 class VTKBinaryAppendedDataArrayWriter : public VTKDataArrayWriter<T>
01514 {
01515 public:
01517 VTKBinaryAppendedDataArrayWriter (std::ostream& theStream, std::string name, int ncomps, unsigned int& bc)
01518 : s(theStream),bytecount(bc)
01519 {
01520 VTKTypeNameTraits<T> tn;
01521 s << "<DataArray type=\"" << tn() << "\" Name=\"" << name << "\" ";
01522
01523 s << "NumberOfComponents=\"" << (ncomps>1?3:1) << "\" ";
01524 s << "format=\"appended\" offset=\""<< bytecount << "\" />" << std::endl;
01525 bytecount += 4;
01526 }
01527
01529 void write (T data)
01530 {
01531 bytecount += sizeof(T);
01532 }
01533
01534 private:
01535 std::ostream& s;
01536 unsigned int& bytecount;
01537 };
01538
01539
01540
01541 class SimpleStream
01542 {
01543 public:
01544 SimpleStream (std::ostream& theStream)
01545 : s(theStream)
01546 {}
01547 template<class T>
01548 void write (T data)
01549 {
01550 char* p = reinterpret_cast<char*>(&data);
01551 s.write(p,sizeof(T));
01552 }
01553 private:
01554 std::ostream& s;
01555 };
01556
01557 void indentUp ()
01558 {
01559 indentCount++;
01560 }
01561
01562 void indentDown ()
01563 {
01564 indentCount--;
01565 }
01566
01567 void indent (std::ostream& s)
01568 {
01569 for (int i=0; i<indentCount; i++)
01570 s << " ";
01571 }
01572
01573
01574 static int renumber (const Entity& e, int i)
01575 {
01576 static const int quadRenumbering[4] = {0,1,3,2};
01577 static const int cubeRenumbering[8] = {0,1,3,2,4,5,7,6};
01578 static const int prismRenumbering[6] = {0,2,1,3,5,4};
01579 switch (vtkType(e.geometry().type()))
01580 {
01581 case vtkQuadrilateral:
01582 return quadRenumbering[i];
01583 case vtkHexahedron:
01584 return cubeRenumbering[i];
01585 case vtkPrism:
01586 return prismRenumbering[i];
01587 default:
01588 return i;
01589 }
01590 }
01591
01592
01593 std::list<VTKFunction*> celldata;
01594 std::list<VTKFunction*> vertexdata;
01595
01596
01597 const GridImp& grid;
01598
01599
01600 const IndexSet& is;
01601
01602
01603 int indentCount;
01604 int numPerLine;
01605
01606
01607 int ncells;
01608 int nvertices;
01609 int ncorners;
01610 VertexMapper* vertexmapper;
01611 std::vector<int> number;
01612 VTKOptions::DataMode datamode;
01613 VTKOptions::OutputType outputtype;
01614 unsigned int bytecount;
01615 };
01616
01620 template<class G>
01621 class LeafVTKWriter : public VTKWriter<G,typename G::template Codim<0>::LeafIndexSet>
01622 {
01623 public:
01625 LeafVTKWriter (const G& grid, VTKOptions::DataMode dm = VTKOptions::conforming)
01626 : VTKWriter<G,typename G::template Codim<0>::LeafIndexSet>(grid,grid.leafIndexSet(),dm)
01627 {}
01628 };
01629
01633 template<class G>
01634 class LevelVTKWriter : public VTKWriter<G, typename G::template Codim<0>::LevelIndexSet>
01635 {
01636 public:
01638 LevelVTKWriter (const G& grid, int level, VTKOptions::DataMode dm = VTKOptions::conforming)
01639 : VTKWriter<G,typename G::template Codim<0>::LevelIndexSet>(grid,grid.levelIndexSet(level),dm)
01640 {}
01641 };
01642 }
01643 #endif