LifeV
ExporterHDF5.hpp
Go to the documentation of this file.
1 //@HEADER
2 /*
3 *******************************************************************************
4 
5 Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
6 Copyright (C) 2010 EPFL, Politecnico di Milano, Emory University
7 
8 This file is part of LifeV.
9 
10 LifeV is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14 
15 LifeV is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with LifeV. If not, see <http://www.gnu.org/licenses/>.
22 
23 *******************************************************************************
24 */
25 //@HEADER
26 /*!
27  @file
28  @brief This file provides the class ExporterHDF5 for post-processing with hdf5
29 
30  @date 11-11-2008
31  @author Simone Deparis <simone.deparis@epfl.ch>
32 
33  @contributor Radu Popescu <radu.popescu@epfl.ch>
34  @maintainer Radu Popescu <radu.popescu@epfl.ch>
35 */
36 
37 #ifndef EXPORTER_HDF5_H
38 #define EXPORTER_HDF5_H 1
39 
40 #include <sstream>
41 
42 
43 #include <Epetra_ConfigDefs.h>
44 #include <EpetraExt_DistArray.h>
45 #include <EpetraExt_HDF5.h>
46 #include <Epetra_Comm.h>
47 #include <Epetra_IntVector.h>
48 #include <Epetra_MultiVector.h>
49 
50 #include <boost/algorithm/string.hpp>
51 #include <boost/shared_array.hpp>
52 #include <boost/shared_ptr.hpp>
53 
54 #ifndef HAVE_HDF5
55 
56 #warning warning you should reconfigure Trilinos with -D TPL_ENABLE_HDF5:BOOL=ON
57 
58 #else
59 
60 #include <lifev/core/LifeV.hpp>
61 
62 #include <lifev/core/array/MapEpetra.hpp>
63 #include <lifev/core/util/StringUtility.hpp>
64 #include <lifev/core/fem/ReferenceFE.hpp>
65 #include <lifev/core/fem/ReferenceFEScalar.hpp>
66 #include <lifev/core/filter/Exporter.hpp>
67 
68 namespace LifeV
69 {
70 
71 //! Hdf5 data exporter, implementation of Exporter
72 /*!
73  @author Simone Deparis <simone.deparis@epfl.ch>
74  @author Radu Popescu <radu.popescu@epfl.ch>
75 
76  Usage: two steps
77  <ol>
78  <li> first: add the variables using addVariable
79  <li> second: call postProcess( time );
80  </ol>
81 */
82 template<typename MeshType>
83 class ExporterHDF5 : public Exporter<MeshType>
84 {
85 
86 public:
87  //! @name Public typedefs
88  //@{
89  typedef MeshType mesh_Type;
90  typedef Exporter<MeshType> super;
91  typedef typename super::meshPtr_Type meshPtr_Type;
92  typedef typename super::vector_Type vector_Type;
93  typedef typename super::vectorPtr_Type vectorPtr_Type;
94  typedef typename super::exporterData_Type exporterData_Type;
95 
96  typedef EpetraExt::HDF5 hdf5_Type;
97  typedef std::shared_ptr<hdf5_Type> hdf5Ptr_Type;
98  typedef std::vector<std::vector<Int> > graph_Type;
99  typedef std::shared_ptr<graph_Type> graphPtr_Type;
100  typedef std::shared_ptr<std::vector<meshPtr_Type> > serial_meshPtr_Type;
101 
102  //! @name Static members
103 
104  //! returns the type of the map to use for the VectorEpetra
105  static MapEpetraType const MapType;
106  //@}
107 
108  //@}
109 
110  //! @name Constructor & Destructor
111  //@{
112 
113  //! Empty Constructor for ExporterHDF5
114  ExporterHDF5();
115 
116  //! Constructor for ExporterHDF5
117  /*!
118  @param dfile the GetPot data file where you must provide an [exporter] section with:
119  "start" (start index for sections in the hdf5 data structure 0 for 000, 1 for 001 etc.),
120  "save" (how many time steps per postprocessing)
121  "multimesh" ( = true if the mesh has to be saved at each post-processing step)
122  @param mesh the mesh
123  @param the prefix for the case file (ex. "test" for test.case)
124  @param the procId determines de CPU id. if negative, it ussemes there is only one processor
125  */
126  ExporterHDF5 (const GetPot& dfile, meshPtr_Type mesh, const std::string& prefix, const Int& procId);
127 
128  //! Constructor for ExporterHDF5 without prefix and procID
129  /*!
130  @param dfile the GetPot data file where you must provide an [exporter] section with:
131  "start" (start index for sections in the hdf5 data structure 0 for 000, 1 for 001 etc.),
132  "save" (how many time steps per postprocessing)
133  "multimesh" ( = true if the mesh has to be saved at each post-processing step)
134  @param mesh the mesh
135  */
136  ExporterHDF5 (const GetPot& dfile, const std::string& prefix);
137 
138  //! Destructor for ExporterHDF5
139  virtual ~ExporterHDF5() {}
140 
141  //@}
142 
143  //! @name Public Methods
144  //@{
145  virtual void postProcess (const Real& time);
146 
147  //! Import data from previous simulations at a certain time
148  /*!
149  @param Time the time of the data to be imported
150  @return number of iteration corresponding at the time step
151  */
152  UInt importFromTime ( const Real& Time );
153 
154  //! Import data from previous simulations at a certain time
155  /*!
156  @param Time the time of the data to be imported
157  @return the simulation time corresponding to the iteration
158  */
159  Real importFromIter ( const UInt& );
160 
161  //! Import data from previous simulations
162  /*!
163  @param time the solver time
164  */
165  void import (const Real& startTime, const Real& dt); // dt is used to rebuild the history up to now
166 
167  //! Import data from previous simulations
168  /*!
169  @param time the solver time
170  */
171  void import (const Real& time);
172 
173  //! Close the Hdf5 file
174  /*!
175  Close the HDF5 file.
176  */
177  void closeFile()
178  {
179  M_HDF5->Close();
180  }
181 
182  //! Read variable
183  void readVariable ( exporterData_Type& dvar);
184 
185  //@}
186 
187  //! @name Set Methods
188  //@{
189 
190  //! Set data from file.
191  /*!
192  * @param dataFile data file.
193  * @param section section in the data file.
194  */
195  void setDataFromGetPot ( const GetPot& dataFile, const std::string& section = "exporter" );
196 
197  //@}
198 
199  //! @name Get Methods
200  //@{
201 
202  //! returns the type of the map to use for the VectorEpetra
203  MapEpetraType mapType() const;
204 
205  //@}
206 
207 protected:
208 
209  //! @name Protected Methods
210  //@{
211  //! Define the shape of the elements
212  void defineShape();
213  //! write empty xdmf file
214  void writeInitXdmf();
215  //! append to xdmf file
216  void writeXdmf (const Real& time);
217  //! save position and write closing lines
218  void writeCloseLinesXdmf();
219  //! remove closing lines
220  void removeCloseLinesXdmf();
221 
222  void writeTopology ( std::ofstream& xdmf );
223  void writeGeometry ( std::ofstream& xdmf );
224  void writeAttributes ( std::ofstream& xdmf );
225  void writeScalarDatastructure ( std::ofstream& xdmf, const exporterData_Type& dvar );
226  void writeVectorDatastructure ( std::ofstream& xdmf, const exporterData_Type& dvar );
227 
228  void writeVariable (const exporterData_Type& dvar);
229  void writeScalar (const exporterData_Type& dvar);
230  void writeVector (const exporterData_Type& dvar);
231 
232  void writeGeometry();
233 
234  void readScalar ( exporterData_Type& dvar);
235  void readVector ( exporterData_Type& dvar);
236  //@}
237 
238  //! @name Protected data members
239  //@{
240  hdf5Ptr_Type M_HDF5;
241  std::ofstream M_xdmf;
242 
243  const std::string M_closingLines;
244  std::streampos M_closingLinesPosition;
245  std::string M_outputFileName;
246 
247  //! do we want to write on file the connectivity?
248  bool M_printConnectivity;
249  //@}
250 
251 };
252 
253 template<typename MeshType>
254 MapEpetraType const ExporterHDF5<MeshType>::MapType (Unique);
255 
256 
257 // ===================================================
258 // Constructors
259 // ===================================================
260 template<typename MeshType>
261 ExporterHDF5<MeshType>::ExporterHDF5() :
262  super (),
263  M_HDF5 (),
264  M_closingLines ( "\n </Grid>\n\n </Domain>\n</Xdmf>\n"),
265  M_outputFileName ( "noninitialisedFileName" ),
266  M_printConnectivity ( true )
267 {
268 }
269 
270 template<typename MeshType>
271 ExporterHDF5<MeshType>::ExporterHDF5 (const GetPot& dfile, meshPtr_Type mesh, const std::string& prefix,
272  const Int& procId) :
273  super ( dfile, prefix ),
274  M_HDF5 (),
275  M_closingLines ( "\n </Grid>\n\n </Domain>\n</Xdmf>\n"),
276  M_outputFileName ( "noninitialisedFileName" )
277 {
278  M_printConnectivity = dfile ( ( prefix + "/printConnectivity" ).data(), 1);
279  this->setMeshProcId ( mesh, procId );
280 }
281 
282 template<typename MeshType>
283 ExporterHDF5<MeshType>::ExporterHDF5 (const GetPot& dfile, const std::string& prefix) :
284  super ( dfile, prefix ),
285  M_HDF5 (),
286  M_closingLines ( "\n </Grid>\n\n </Domain>\n</Xdmf>\n"),
287  M_outputFileName ( "noninitialisedFileName" )
288 {
289  M_printConnectivity = dfile ( ( prefix + "/printConnectivity" ).data(), 1);
290 }
291 
292 // ===================================================
293 // Methods
294 // ===================================================
295 
296 template<typename MeshType>
297 void ExporterHDF5<MeshType>::postProcess (const Real& time)
298 {
299  if ( M_HDF5.get() == 0)
300  {
301  M_HDF5.reset (new hdf5_Type (this->M_dataVector.begin()->storedArrayPtr()->comm() ) );
302  M_outputFileName = this->M_prefix + ".h5";
303  M_HDF5->Create (this->M_postDir + M_outputFileName);
304 
305  // write empty xdmf file
306  writeInitXdmf();
307 
308  if (!this->M_multimesh)
309  {
310  writeGeometry(); // see also writeGeometry
311  M_HDF5->Flush();
312  }
313  }
314 
315  // typedef std::list< exporterData_Type >::const_iterator Iterator;
316 
317  this->computePostfix();
318 
319  std::size_t found ( this->M_postfix.find ( "*" ) );
320  if ( found == std::string::npos )
321  {
322  if (!this->M_procId)
323  {
324  std::cout << " X- HDF5 post-processing ... " << std::flush;
325  }
326  LifeChrono chrono;
327  chrono.start();
328  for (typename super::dataVectorIterator_Type i = this->M_dataVector.begin(); i != this->M_dataVector.end(); ++i)
329  {
330  writeVariable (*i);
331  }
332  // pushing time
333  this->M_timeSteps.push_back (time);
334 
335  writeXdmf (time);
336 
337  if (this->M_multimesh)
338  {
339  writeGeometry(); // see also writeGeometry
340  }
341 
342  chrono.stop();
343 
344  // Write to file without closing the file
345  M_HDF5->Flush();
346 
347  if (!this->M_procId)
348  {
349  std::cout << "done in " << chrono.diff() << " s." << std::endl;
350  }
351  }
352 }
353 
354 template<typename MeshType>
355 UInt ExporterHDF5<MeshType>::importFromTime ( const Real& Time )
356 {
357  // Container for the time and the postfix
358  std::pair< Real, Int > SelectedTimeAndPostfix;
359  if ( !this->M_procId )
360  {
361  // Open the xmf file
362  std::ifstream xmfFile;
363  xmfFile.open ( ( this->M_postDir + this->M_prefix + ".xmf" ).c_str(), std::ios::in );
364 
365  // Vector of TimeStep
366  std::vector< std::pair< Real, Int > > TimeAndPostfix;
367  if ( xmfFile.is_open() )
368  {
369  // Define some variables
370  std::string line;
371  std::vector<std::string> stringsVector;
372 
373  // Read one-by-one all the lines of the file
374  while ( !xmfFile.eof() )
375  {
376  std::getline ( xmfFile, line, '\n' );
377 
378  // If the line begin with "<!-- Time " it is the beginning of a new block
379  if ( !line.compare ( 0, 10, "<!-- Time " ) )
380  {
381  boost::split ( stringsVector, line, boost::is_any_of ( " " ) );
382  TimeAndPostfix.push_back ( std::make_pair ( string2number ( stringsVector[2] ),
383  string2number ( stringsVector[4] ) ) );
384  }
385  }
386  }
387  xmfFile.close();
388 
389  // Find the closest time step
390  SelectedTimeAndPostfix = TimeAndPostfix.front();
391  for ( std::vector< std::pair< Real, Int > >::const_iterator i = TimeAndPostfix.begin();
392  i < TimeAndPostfix.end() ; ++i )
393  if ( std::fabs ( SelectedTimeAndPostfix.first - Time ) >= std::fabs ( (*i).first - Time ) )
394  {
395  SelectedTimeAndPostfix = *i;
396  }
397  }
398  this->M_dataVector.begin()->storedArrayPtr()->comm().Broadcast ( &SelectedTimeAndPostfix.second, 1, 0 );
399  this->M_timeIndex = SelectedTimeAndPostfix.second;
400  this->computePostfix();
401 
402  // Importing
403  if ( !this->M_procId )
404  {
405  std::cout << " X- HDF5 importing ... " << std::flush;
406  }
407 
408  LifeChrono chrono;
409  chrono.start();
410  for (typename super::dataVectorIterator_Type i = this->M_dataVector.begin(); i != this->M_dataVector.end(); ++i)
411  {
412  this->readVariable (*i);
413  }
414 
415  chrono.stop();
416  if ( !this->M_procId )
417  std::cout << "done in " << chrono.diff() << " s. (Time " << SelectedTimeAndPostfix.first
418  << ", Iteration " << SelectedTimeAndPostfix.second << " )" << std::endl;
419 
420  return static_cast <UInt> ( SelectedTimeAndPostfix.second );
421 }
422 
423 template<typename MeshType>
424 Real ExporterHDF5<MeshType>::importFromIter ( const UInt& iter )
425 {
426  // Container for the time and the postfix
427  std::pair< Real, Int > SelectedTimeAndPostfix;
428  if ( !this->M_procId )
429  {
430  // Open the xmf file
431  std::ifstream xmfFile;
432  xmfFile.open ( ( this->M_postDir + this->M_prefix + ".xmf" ).c_str(), std::ios::in );
433 
434  // Vector of TimeStep
435  std::vector< std::pair< Real, UInt > > TimeAndPostfix;
436 
437  if ( xmfFile.is_open() )
438  {
439  // Define some variables
440  std::string line;
441  std::vector<std::string> stringsVector;
442 
443  // Read one-by-one all the lines of the file
444  while ( !xmfFile.eof() )
445  {
446  std::getline ( xmfFile, line, '\n' );
447 
448  // If the line begin with "<!-- Time " it is the beginning of a new block
449  if ( !line.compare ( 0, 10, "<!-- Time " ) )
450  {
451  boost::split ( stringsVector, line, boost::is_any_of ( " " ) );
452  TimeAndPostfix.push_back ( std::make_pair ( string2number ( stringsVector[2] ),
453  string2number ( stringsVector[4] ) ) );
454  }
455  }
456  }
457 
458  xmfFile.close();
459 
460  // Find the closest time step
461  SelectedTimeAndPostfix = TimeAndPostfix.front();
462  bool found = false;
463 
464  for ( std::vector< std::pair< Real, UInt > >::const_iterator i = TimeAndPostfix.begin();
465  i < TimeAndPostfix.end() ; ++i )
466  {
467  if ( i->second == iter )
468  {
469  SelectedTimeAndPostfix = *i;
470  found = true;
471  break;
472  }
473  }
474 
475  ASSERT (found, "Selected iteration not found");
476 
477  }
478 
479  this->M_dataVector.begin()->storedArrayPtr()->Comm().Broadcast ( &SelectedTimeAndPostfix.second, 1, 0 );
480  this->M_timeIndex = SelectedTimeAndPostfix.second;
481 
482  std::ostringstream index;
483  index.fill ('0');
484 
485  index << std::setw (5) << this->M_timeIndex;
486  this->M_postfix = "." + index.str();
487 
488  // Importing
489  if ( !this->M_procId )
490  std::cout << " X- HDF5 importing iteration "
491  << index.str()
492  << " at time " << SelectedTimeAndPostfix.first
493  << " ... " << std::flush;
494 
495  LifeChrono chrono;
496  chrono.start();
497  for (typename super::dataVectorIterator_Type i = this->M_dataVector.begin(); i != this->M_dataVector.end(); ++i)
498  {
499  this->readVariable (*i);
500  }
501  chrono.stop();
502 
503  if ( !this->M_procId )
504  std::cout << "done in " << chrono.diff() << " s. (Time " << SelectedTimeAndPostfix.first
505  << ", Iteration " << SelectedTimeAndPostfix.second << " )" << std::endl;
506 
507  return SelectedTimeAndPostfix.first;
508 }
509 
510 
511 template<typename MeshType>
512 void ExporterHDF5<MeshType>::import (const Real& Tstart, const Real& dt)
513 {
514  // dt is used to rebuild the history up to now
515  Real time (Tstart - this->M_timeIndex * dt);
516 
517  for ( UInt count (0); count < this->M_timeIndex; ++count )
518  {
519  this->M_timeSteps.push_back (time);
520  time += dt;
521  }
522 
523  time += dt;
524 
525  import (time);
526 }
527 
528 template<typename MeshType>
529 void ExporterHDF5<MeshType>::import (const Real& time)
530 {
531  if ( M_HDF5.get() == 0)
532  {
533  M_HDF5.reset (new hdf5_Type (this->M_dataVector.begin()->storedArrayPtr()->comm() ) );
534  M_HDF5->Open (this->M_postDir + this->M_prefix + ".h5"); //!! Simone
535  }
536 
537  this->M_timeSteps.push_back (time);
538 
539  this->computePostfix();
540 
541  assert ( this->M_postfix != "*****" );
542 
543  if (!this->M_procId)
544  {
545  std::cout << " X- HDF5 importing ... " << std::endl;
546  }
547 
548  LifeChrono chrono;
549  chrono.start();
550  for (typename super::dataVectorIterator_Type i = this->M_dataVector.begin(); i != this->M_dataVector.end(); ++i)
551  {
552  this->readVariable (*i); ///!!! Simone
553  }
554  chrono.stop();
555  if (!this->M_procId)
556  {
557  std::cout << "done in " << chrono.diff() << " s." << std::endl;
558  }
559 }
560 
561 template <typename MeshType>
562 void ExporterHDF5<MeshType>::readVariable (exporterData_Type& dvar)
563 {
564  if ( M_HDF5.get() == 0)
565  {
566  M_HDF5.reset (new hdf5_Type (dvar.storedArrayPtr()->blockMap().Comm() ) );
567  M_HDF5->Open (this->M_postDir + this->M_prefix + ".h5"); //!! Simone
568  }
569  super::readVariable (dvar);
570 }
571 
572 // ===================================================
573 // Set Methods
574 // ===================================================
575 template<typename MeshType>
576 void ExporterHDF5<MeshType>::setDataFromGetPot ( const GetPot& dataFile, const std::string& section )
577 {
578  super::setDataFromGetPot ( dataFile, section );
579  M_printConnectivity = dataFile ( ( section + "/printConnectivity" ).data(), 1);
580 }
581 
582 // ===================================================
583 // Get Methods
584 // ===================================================
585 template<typename MeshType>
586 MapEpetraType ExporterHDF5<MeshType>::mapType() const
587 {
588  return MapType;
589 }
590 
591 // ===================================================
592 // Protected Methods
593 // ===================================================
594 template<typename MeshType>
595 void ExporterHDF5<MeshType>::defineShape()
596 {
597 }
598 
599 // write empty xdmf file
600 template <typename MeshType>
601 void ExporterHDF5<MeshType>::writeInitXdmf()
602 {
603  if (this->M_procId == 0)
604  {
605  M_xdmf.open ( (this->M_postDir + this->M_prefix + ".xmf").c_str(), std::ios_base::out );
606 
607  M_xdmf << "<?xml version=\"1.0\" ?>\n"
608  << "<!DOCTYPE Xdmf SYSTEM \""
609  << this->M_prefix
610  << ".xdmf\" [\n"
611  << "<!ENTITY DataFile \""
612  << this->M_prefix
613  << ".h5\">\n"
614  << "]>\n"
615  << "<!-- "
616  << this->M_prefix
617  << ".h5 is generated by LifeV -->\n"
618  << "<Xdmf>\n"
619  << " <Domain Name=\""
620  << this->M_prefix
621  << "\">\n"
622  << " <Grid Name=\""
623  << this->M_prefix
624  << "Grid\" GridType=\"Collection\" CollectionType=\"Temporal\">\n"
625  << "\n";
626 
627  writeCloseLinesXdmf();
628  }
629 }
630 
631 template <typename MeshType>
632 void ExporterHDF5<MeshType>::writeXdmf (const Real& time)
633 {
634  /*
635  strategy: write the topology,
636  <Topology
637  Type="Tetrahedron"
638  NumberOfElements="183"
639  BaseOffset="1">
640  <DataStructure Format="HDF"
641  Dimensions="602 4" ???
642  DataType="Int"
643  Precision="8">
644  &DataFile;:/Connections/Values
645  </DataStructure>
646  </Topology>
647  and then the geometry
648  <Geometry Type="X_Y_Z">
649  <DataStructure Format="HDF"
650  Dimensions="183"
651  DataType="Float"
652  Precision="8">
653  &DataFile;:/PointsX/Values
654  </DataStructure>
655  <DataStructure Format="HDF"
656  Dimensions="183"
657  DataType="Float"
658  Precision="8">
659  &DataFile;:/PointsY/Values
660  </DataStructure>
661  <DataStructure Format="HDF"
662  Dimensions="183"
663  DataType="Float"
664  Precision="8">
665  &DataFile;:/PointsY/Values
666  </DataStructure>
667  </Geometry>
668 
669 
670  In this aim we create
671  two Epetra_IntVector, one with a repeated map and the second with a unique map
672  two Epetra_MultiVector, one with a repeated map and the second with a unique map
673 
674  The Int vectors are for the connections, the Real ones for the Vertices
675  */
676 
677  if (this->M_procId == 0)
678  {
679  removeCloseLinesXdmf();
680 
681  // write grid with time, topology, geometry and attributes
682  // NOTE: The first line (<!-- Time t Iteration i -->) is used in function importFromTime.
683  // Check compatibility after any change on it!
684  M_xdmf <<
685  "<!-- Time " << time << " Iteration " << this->M_postfix.substr (1, 5) << " -->\n" <<
686  " <Grid Name=\"Mesh " << time << "\">\n" <<
687  " <Time TimeType=\"Single\" Value=\"" << time << "\" />\n";
688  writeTopology (M_xdmf);
689  writeGeometry (M_xdmf);
690  writeAttributes (M_xdmf);
691 
692  M_xdmf << "\n"
693  " </Grid>\n\n";
694 
695 
696 
697  // write closing lines
698  writeCloseLinesXdmf();
699  }
700 }
701 
702 // save position and write closing lines
703 template <typename MeshType>
704 void ExporterHDF5<MeshType>::writeCloseLinesXdmf()
705 {
706  // save position
707  M_closingLinesPosition = M_xdmf.tellp();
708 
709  // write closing lines
710  M_xdmf << M_closingLines;
711  M_xdmf.flush();
712 
713 }
714 
715 // remove closing lines
716 template <typename MeshType>
717 void ExporterHDF5<MeshType>::removeCloseLinesXdmf()
718 {
719  M_xdmf.seekp (M_closingLinesPosition);
720 }
721 
722 template <typename MeshType>
723 void ExporterHDF5<MeshType>::writeTopology ( std::ofstream& xdmf )
724 {
725  std::string FEstring;
726 
727  switch ( MeshType::elementShape_Type::S_shape )
728  {
729  case TETRA:
730  FEstring = "Tetrahedron";
731  break;
732  case HEXA:
733  FEstring = "Hexahedron";
734  break;
735  case TRIANGLE:
736  FEstring = "Triangle";
737  break;
738  case QUAD:
739  FEstring = "Quadrilateral";
740  break;
741  case LINE:
742  FEstring = "Polyline";
743  break;
744  default:
745  ERROR_MSG ( "FE not allowed in HDF5 Exporter" );
746  }
747 
748  xdmf << " <Topology\n"
749  << " Type=\""
750  << FEstring
751  << "\"\n"
752  << " NumberOfElements=\""
753  << this->M_mesh->numGlobalElements()
754  << "\"\n"
755  << " BaseOffset=\""
756  << 0
757  << "\">\n"
758  << " <DataStructure Format=\"HDF\"\n"
759  << " Dimensions=\""
760  << this->M_mesh->numGlobalElements()
761  << " "
762  << this->M_mesh->numLocalVertices()
763  << "\"\n" << " DataType=\"Int\"\n"
764  << " Precision=\"8\">\n" << " "
765  << M_outputFileName << ":/Connections/Values\n"
766  << " </DataStructure>\n" << " </Topology>\n";
767 }
768 
769 template <typename MeshType>
770 void ExporterHDF5<MeshType>::writeGeometry ( std::ofstream& xdmf )
771 {
772 
773  std::string postfix_string;
774 
775  // see also in postProcess
776  if (this->M_multimesh)
777  {
778  postfix_string = this->M_postfix;
779  }
780  else
781  {
782  postfix_string = "";
783  }
784 
785 
786  xdmf <<
787  " <Geometry Type=\"X_Y_Z\">\n" <<
788  " <DataStructure Format=\"HDF\"\n" <<
789  " Dimensions=\"" << this->M_mesh->numGlobalVertices() << "\"\n" <<
790  " DataType=\"Float\"\n" <<
791  " Precision=\"8\">\n" <<
792  " " << M_outputFileName << ":/" << "PointsX" << postfix_string << "/Values\n" <<
793  " </DataStructure>\n" <<
794  " <DataStructure Format=\"HDF\"\n" <<
795  " Dimensions=\"" << this->M_mesh->numGlobalVertices() << "\"\n" <<
796  " DataType=\"Float\"\n" <<
797  " Precision=\"8\">\n" <<
798  " " << M_outputFileName << ":/" << "PointsY" << postfix_string << "/Values\n" <<
799  " </DataStructure>\n" <<
800  " <DataStructure Format=\"HDF\"\n" <<
801  " Dimensions=\"" << this->M_mesh->numGlobalVertices() << "\"\n" <<
802  " DataType=\"Float\"\n" <<
803  " Precision=\"8\">\n" <<
804  " " << M_outputFileName << ":/" << "PointsZ" << postfix_string << "/Values\n" <<
805  " </DataStructure>\n" <<
806  " </Geometry>\n" <<
807  "\n";
808 }
809 
810 template <typename MeshType>
811 void ExporterHDF5<MeshType>::writeAttributes ( std::ofstream& xdmf )
812 {
813 
814  // Loop on the variables to output
815  for (typename super::dataVectorIterator_Type i = this->M_dataVector.begin(); i != this->M_dataVector.end(); ++i)
816  {
817  xdmf <<
818  "\n <Attribute\n" <<
819  " Type=\"" << i->typeName() << "\"\n" <<
820  " Center=\"" << i->whereName() << "\"\n" <<
821  " Name=\"" << i->variableName() << "\">\n";
822 
823  switch ( i->fieldType() )
824  {
825  case exporterData_Type::ScalarField:
826  writeScalarDatastructure (xdmf, *i);
827  break;
828  case exporterData_Type::VectorField:
829  writeScalarDatastructure (xdmf, *i);
830  //writeVectorFieldstructure(xdmf, *i);
831  break;
832  }
833 
834  xdmf <<
835  " </Attribute>\n";
836  }
837 }
838 
839 template <typename MeshType>
840 void ExporterHDF5<MeshType>::writeScalarDatastructure ( std::ofstream& xdmf, const exporterData_Type& dvar )
841 {
842 
843  Int globalUnknowns (0);
844  switch ( dvar.where() )
845  {
846  case exporterData_Type::Node:
847  globalUnknowns = this->M_mesh->numGlobalVertices();
848  break;
849  case exporterData_Type::Cell:
850  globalUnknowns = this->M_mesh->numGlobalElements();
851  break;
852  }
853 
854  //exported vectors are threedimensional also in 2D (check)
855  UInt dim = (dvar.fieldDim() == 1) ? 1 : nDimensions;
856 
857  // First: hyperslab definition, then description of the data
858  xdmf <<
859 
860  " <DataStructure ItemType=\"HyperSlab\"\n" <<
861  " Dimensions=\"" << globalUnknowns << " " << dim << "\"\n" <<
862  " Type=\"HyperSlab\">\n" <<
863  " <DataStructure Dimensions=\"3 2\"\n" <<
864  " Format=\"XML\">\n" <<
865  " 0 0\n" <<
866  " 1 1\n" <<
867  " " << globalUnknowns << " " << dim << "\n" <<
868  " </DataStructure>\n" <<
869 
870  " <DataStructure Format=\"HDF\"\n" <<
871  " Dimensions=\"" << dvar.numDOF() << " " << dim << "\"\n" <<
872  " DataType=\"Float\"\n" <<
873  " Precision=\"8\">\n" <<
874  " " << M_outputFileName << ":/" << dvar.variableName()
875  << this->M_postfix << "/Values\n" << // see also in writeVector/scalar
876  " </DataStructure>\n" <<
877  " </DataStructure>\n";
878 
879 }
880 
881 template <typename MeshType>
882 void ExporterHDF5<MeshType>::writeVectorDatastructure ( std::ofstream& xdmf, const exporterData_Type& dvar )
883 {
884 
885 
886  std::string coord[3] = {"X", "Y", "Z"}; // see also wr_vector
887 
888  xdmf << " <DataStructure ItemType=\"Function\"\n"
889  << " Dimensions=\""
890  << this->M_mesh->numGlobalVertices()
891  << " "
892  << nDimensions
893  << "\"\n"
894  << " Function=\"JOIN($0 , $1, $2)\">\n";
895 
896  for ( UInt i (0); i < nDimensions; ++i )
897  {
898  xdmf << " <DataStructure Format=\"HDF\"\n"
899  << " Dimensions=\""
900  << this->M_mesh->numGlobalVertices()
901  << " 1\"\n"
902  << " DataType=\"Float\"\n"
903  << " Precision=\"8\">\n"
904  << " "
905  << M_outputFileName
906  << ":/"
907  << dvar.variableName()
908  << coord[i]
909  << this->M_postfix
910  << "/Values\n"
911  << " </DataStructure>\n";
912  }
913 
914  xdmf << " </DataStructure>\n";
915 }
916 
917 template <typename MeshType>
918 void ExporterHDF5<MeshType>::writeVariable (const exporterData_Type& dvar)
919 {
920 
921  switch ( dvar.fieldType() )
922  {
923  case exporterData_Type::ScalarField:
924  writeScalar (dvar);
925  break;
926  case exporterData_Type::VectorField:
927  writeVector (dvar);
928  break;
929  }
930 }
931 
932 template <typename MeshType>
933 void ExporterHDF5<MeshType>::writeScalar (const exporterData_Type& dvar)
934 {
935  /* Examples:
936  M_HDF5->Write("map-" + toString(Comm.NumProc()), Map);
937  M_HDF5->Write("matrix", Matrix);
938  M_HDF5->Write("LHS", LHS);
939  M_HDF5->Write("RHS", RHS);
940  */
941 
942  //UInt size = dvar.numDOF();
943  UInt size;
944 
945  switch ( dvar.where() )
946  {
947  case exporterData_Type::Node:
948  size = dvar.numDOF();
949  break;
950  case exporterData_Type::Cell:
951  size = dvar.storedArrayPtr()->size();
952  break;
953  }
954 
955  UInt start = dvar.start();
956 
957  MapEpetra subMap (dvar.storedArrayPtr()->blockMap(), start, size);
958  vector_Type subVar (subMap);
959  subVar.subset (*dvar.storedArrayPtr(), start);
960 
961  std::string varname (dvar.variableName() + this->M_postfix); // see also in writeAttributes
962  bool writeTranspose (true);
963  M_HDF5->Write (varname, subVar.epetraVector(), writeTranspose );
964 }
965 
966 template <typename MeshType>
967 void ExporterHDF5<MeshType>::writeVector (const exporterData_Type& dvar)
968 {
969 
970  //UInt size = dvar.numDOF();
971 
972  UInt size;
973 
974  switch ( dvar.where() )
975  {
976  case exporterData_Type::Node:
977  size = dvar.numDOF();
978  break;
979  case exporterData_Type::Cell:
980  size = ( (dvar.storedArrayPtr()->size() ) / ( nDimensions ) );
981  break;
982  }
983 
984  UInt start = dvar.start();
985 
986  // solution array has to be reordered and stored in a Multivector.
987  // Using auxiliary arrays:
988  Real** ArrayOfPointers (new Real*[nDimensions]);
989  boost::shared_array< std::shared_ptr<vector_Type> >
990  ArrayOfVectors (new std::shared_ptr<vector_Type>[nDimensions]);
991 
992  Int MyLDA;
993 
994 
995  // Building subsets (new vectors) of the original data and than taking a view of them to
996  // build a multivector.
997  // Note: the contents of ArrayOfPointers[0,1,2] must not be deleted explicitly, since their
998  // content belongs to ArrayOfVectors[0,1,2].
999  // ArrayOfVectors[0,1,2] are deleted when ArrayOfVectors is destroyed
1000 
1001  for (UInt d ( 0 ); d < dvar.fieldDim(); ++d)
1002  {
1003  MapEpetra subMap (dvar.storedArrayPtr()->blockMap(), start + d * size, size);
1004  ArrayOfVectors[d].reset (new vector_Type (subMap) );
1005  ArrayOfVectors[d]->subset (*dvar.storedArrayPtr(), start + d * size);
1006 
1007  ArrayOfVectors[d]->epetraVector().ExtractView (&ArrayOfPointers[d], &MyLDA);
1008  }
1009 
1010  for (UInt d ( dvar.fieldDim() ); d < nDimensions; ++d)
1011  {
1012  MapEpetra subMap (dvar.storedArrayPtr()->blockMap(), start, size);
1013  ArrayOfVectors[d].reset (new vector_Type (subMap) );
1014 
1015  ArrayOfVectors[d]->epetraVector().ExtractView (&ArrayOfPointers[d], &MyLDA);
1016  }
1017 
1018  MapEpetra subMap (dvar.storedArrayPtr()->blockMap(), start, size);
1019  Epetra_MultiVector multiVector (View, *subMap.map (Unique), ArrayOfPointers, nDimensions);
1020 
1021 
1022  bool writeTranspose (true);
1023  std::string varname (dvar.variableName() + this->M_postfix); // see also in writeAttributes
1024  M_HDF5->Write (varname, multiVector, writeTranspose);
1025 
1026  delete[] ArrayOfPointers;
1027 }
1028 
1029 template <typename MeshType>
1030 void ExporterHDF5<MeshType>::writeGeometry()
1031 {
1032  /*
1033  2 variables:
1034  &DataFile;:/Connections/Values
1035  &DataFile;:/PointsX/Values
1036  &DataFile;:/PointsY/Values
1037  &DataFile;:/PointsZ/Values
1038  note:
1039  if (this->M_multimesh)
1040  &DataFile;:/Points+ this->M_postfix + X/Values
1041  see also writeGeometry
1042  */
1043 
1044  /* Steps:
1045  generate local connections and local coordinates (not repeated)
1046  write out
1047  */
1048 
1049  // We need a map ,but it's not always possible to use that from the variables
1050  // (if we write out a P0 variable)
1051  // We build a map for the connections based on the element numbers and for the points we fake a P1 map
1052 
1053  ASSERT (this->M_dataVector.size() > 0 , "hdf5exporter: ListData is empty");
1054 
1055  // Connections
1056  // Need to use elements not dofs for this map. Recover local element lists
1057  UInt numberOfPoints = MeshType::elementShape_Type::S_numPoints;
1058 
1059  std::vector<Int> elementList;
1060  UInt ownedElements = this->M_mesh->elementList().countElementsWithFlag ( EntityFlags::GHOST, &Flag::testOneNotSet );
1061  elementList.reserve ( ownedElements * numberOfPoints );
1062  UInt elementCount = 0;
1063  for ( ID i = 0; i < this->M_mesh->numElements(); ++i )
1064  {
1065  typename MeshType::element_Type const& element (this->M_mesh->element (i) );
1066  if ( element.isOwned() )
1067  {
1068  UInt lid = elementCount * numberOfPoints;
1069  for (ID j = 0; j < numberOfPoints; ++j, ++lid)
1070  {
1071  elementList[lid] = element.id() * numberOfPoints + j;
1072  }
1073  elementCount++;
1074  }
1075  }
1076 
1077  Epetra_Map connectionsMap ( this->M_mesh->numGlobalElements() *numberOfPoints,
1078  ownedElements * numberOfPoints,
1079  &elementList[0],
1080  0, this->M_dataVector.begin()->storedArrayPtr()->comm() );
1081 
1082  Epetra_IntVector connections (connectionsMap);
1083  elementCount = 0;
1084  for (ID i = 0; i < this->M_mesh->numElements(); ++i)
1085  {
1086  typename MeshType::element_Type const& element (this->M_mesh->element (i) );
1087  if ( element.isOwned() )
1088  {
1089  UInt lid = elementCount * numberOfPoints;
1090  for (ID j = 0; j < numberOfPoints; ++j, ++lid)
1091  {
1092  connections[lid] = element.point (j).id();
1093  }
1094  elementCount++;
1095  }
1096  }
1097 
1098  this->M_dataVector.begin()->storedArrayPtr()->comm().Barrier();
1099 
1100  // Points
1101 
1102  // Build a map for linear elements, even though the original FE might be P0
1103  // This gives the right map for the coordinate arrays
1104 
1105  MapEpetra subMap;
1106  switch ( MeshType::elementShape_Type::S_shape )
1107  {
1108  case TETRA:
1109  {
1110  const ReferenceFE& refFEP1 = feTetraP1;
1111  DOF tmpDof ( *this->M_mesh, refFEP1 );
1112  std::vector<Int> myGlobalElements ( tmpDof.globalElements ( *this->M_mesh ) );
1113  // Create the map
1114  MapEpetra tmpMapP1 ( -1, myGlobalElements.size(), &myGlobalElements[0],
1115  this->M_dataVector.begin()->storedArrayPtr()->mapPtr()->commPtr() );
1116  subMap = tmpMapP1;
1117  break;
1118  }
1119  case TRIANGLE:
1120  {
1121  const ReferenceFE& refFEP1 = feTriaP1;
1122  DOF tmpDof ( *this->M_mesh, refFEP1 );
1123  std::vector<Int> myGlobalElements ( tmpDof.globalElements ( *this->M_mesh ) );
1124  // Create the map
1125  MapEpetra tmpMapP1 ( -1, myGlobalElements.size(), &myGlobalElements[0],
1126  this->M_dataVector.begin()->storedArrayPtr()->mapPtr()->commPtr() );
1127  subMap = tmpMapP1;
1128  break;
1129  }
1130  case HEXA:
1131  {
1132  const ReferenceFE& refFEQ1 = feHexaQ1;
1133  DOF tmpDof ( *this->M_mesh, refFEQ1 );
1134  std::vector<Int> myGlobalElements ( tmpDof.globalElements ( *this->M_mesh ) );
1135  // Create the map
1136  MapEpetra tmpMapQ1 ( -1, myGlobalElements.size(), &myGlobalElements[0],
1137  this->M_dataVector.begin()->storedArrayPtr()->mapPtr()->commPtr() );
1138  subMap = tmpMapQ1;
1139  break;
1140  }
1141  case LINE:
1142  {
1143  const ReferenceFE& refFEP11D = feSegP1;
1144  DOF tmpDof ( *this->M_mesh, refFEP11D );
1145  std::vector<Int> myGlobalElements ( tmpDof.globalElements ( *this->M_mesh ) );
1146  // Create the map
1147  MapEpetra tmpMapQ11D ( -1, myGlobalElements.size(), &myGlobalElements[0],
1148  this->M_dataVector.begin()->storedArrayPtr()->mapPtr()->commPtr() );
1149  subMap = tmpMapQ11D;
1150  break;
1151  }
1152  default:
1153  ERROR_MSG ( "FE not allowed in HDF5 Exporter" );
1154 
1155  }
1156 
1157  VectorEpetra pointsX (subMap);
1158  VectorEpetra pointsY (subMap);
1159  VectorEpetra pointsZ (subMap);
1160 
1161  Int gid;
1162  for (ID i = 0; i < this->M_mesh->numVertices(); ++i)
1163  {
1164  typename MeshType::point_Type point;
1165  if ( this->M_multimesh )
1166  {
1167  point = this->M_mesh->point (i);
1168  }
1169  else
1170  {
1171  point = this->M_mesh->meshTransformer().pointInitial (i);
1172  }
1173 
1174  if ( point.isOwned() )
1175  {
1176 
1177  gid = point.id();
1178 
1179  bool insertedX (true);
1180  bool insertedY (true);
1181  bool insertedZ (true);
1182 
1183  insertedX = insertedX && pointsX.setCoefficient (gid, point.x() );
1184  insertedY = insertedY && pointsY.setCoefficient (gid, point.y() );
1185  insertedZ = insertedZ && pointsZ.setCoefficient (gid, point.z() );
1186  }
1187  }
1188 
1189  // Now we are ready to export the vectors to the hdf5 file
1190 
1191  std::string pointsXVarname ("PointsX");
1192  std::string pointsYVarname ("PointsY");
1193  std::string pointsZVarname ("PointsZ");
1194  std::string connectionsVarname ("Connections");
1195 
1196  if (this->M_multimesh)
1197  {
1198  pointsXVarname += this->M_postfix; // see also in writeGeometry
1199  pointsYVarname += this->M_postfix; // see also in writeGeometry
1200  pointsZVarname += this->M_postfix; // see also in writeGeometry
1201  }
1202 
1203  if ( this->M_printConnectivity )
1204  {
1205  M_HDF5->Write (connectionsVarname, connections);
1206  this->M_printConnectivity = false;
1207  }
1208 
1209  // bool writeTranspose (true);
1210  M_HDF5->Write (pointsXVarname, pointsX.epetraVector(), true);
1211  M_HDF5->Write (pointsYVarname, pointsY.epetraVector(), true);
1212  M_HDF5->Write (pointsZVarname, pointsZ.epetraVector(), true);
1213 }
1214 
1215 template <typename MeshType>
1216 void ExporterHDF5<MeshType>::readScalar (exporterData_Type& dvar)
1217 {
1218 
1219  UInt size = dvar.numDOF();
1220  UInt start = dvar.start();
1221 
1222  MapEpetra subMap (dvar.storedArrayPtr()->blockMap(), start, size);
1223  Epetra_MultiVector* subVar (0);
1224 
1225  std::string varname (dvar.variableName() ); // see also in writeAttributes
1226  if (this->M_postfix != "")
1227  {
1228  varname += this->M_postfix;
1229  }
1230  bool readTranspose (true);
1231  M_HDF5->Read (varname, *subMap.map (this->mapType() ), subVar, readTranspose);
1232 
1233  dvar.storedArrayPtr()->subset (*subVar, subMap, 0, start );
1234 
1235  delete subVar;
1236 
1237 }
1238 
1239 template <typename MeshType>
1240 void ExporterHDF5<MeshType>::readVector ( exporterData_Type& dvar)
1241 {
1242  UInt size = dvar.numDOF();
1243  UInt start = dvar.start();
1244 
1245  using namespace boost;
1246 
1247  // solution array has first to be read has Multivector.
1248 
1249  // first read the multivector:
1250  MapEpetra subMap (dvar.storedArrayPtr()->blockMap(), start, size);
1251  Epetra_MultiVector* subVar (0);
1252 
1253  bool readTranspose (true);
1254  std::string varname (dvar.variableName() ); // see also in writeAttributes
1255 
1256  if (this->M_postfix != "")
1257  {
1258  varname += this->M_postfix;
1259  }
1260 
1261  M_HDF5->Read (varname, *subMap.map (this->mapType() ), subVar, readTranspose);
1262 
1263 
1264  // then put back value in our VectorEpetra
1265 
1266  for (UInt d ( 0 ); d < dvar.fieldDim(); ++d)
1267  {
1268  dvar.storedArrayPtr()->subset (*subVar, subMap, 0, start + d * size, d );
1269  }
1270 
1271  delete subVar;
1272 }
1273 
1274 } // Namespace LifeV
1275 
1276 #endif // HAVE_HDF5
1277 
1278 #endif // EXPORTER_HDF5_H