Nektar++
MeshGraphHDF5.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: MeshGraphHDF5.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: HDF5-based mesh format for Nektar++.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include <type_traits>
36 #include <tinyxml.h>
37 #include <boost/core/ignore_unused.hpp>
38 #include <boost/algorithm/string.hpp>
39 #include <boost/filesystem.hpp>
40 
45 
46 #define TIME_RESULT(verb, msg, timer) \
47  if (verb) \
48  { \
49  std::cout << " - " << msg << ": " \
50  << timer.TimePerTest(1) << std::endl; \
51  }
52 
53 using namespace std;
54 using namespace Nektar::LibUtilities;
55 
56 namespace Nektar
57 {
58 namespace SpatialDomains
59 {
60 
61 /// Version of the Nektar++ HDF5 geometry format, which is embedded into the
62 /// main NEKTAR/GEOMETRY group as an attribute.
63 const unsigned int MeshGraphHDF5::FORMAT_VERSION = 1;
64 
65 std::string MeshGraphHDF5::className =
67  "HDF5", MeshGraphHDF5::create, "IO with HDF5 geometry");
68 
69 void MeshGraphHDF5::ReadGeometry(
70  DomainRangeShPtr rng,
71  bool fillGraph)
72 {
73  boost::ignore_unused(rng);
74 
75  ReadComposites();
76  ReadDomain();
77  ReadExpansions();
78 
79  // Close up shop.
80  m_mesh->Close();
81  m_maps->Close();
82  m_file->Close();
83 
84  if (fillGraph)
85  {
86  MeshGraph::FillGraph();
87  }
88 }
89 
90 /**
91  * @brief Utility function to split a vector equally amongst a number of
92  * processors.
93  *
94  * @param vecsize Size of the total amount of work
95  * @param rank Rank of this process
96  * @param nprocs Number of processors in the group
97  *
98  * @return A pair with the offset this process should occupy, along with the
99  * count for the amount of work.
100  */
101 std::pair<size_t, size_t> SplitWork(size_t vecsize, int rank, int nprocs)
102 {
103  size_t div = vecsize / nprocs;
104  size_t rem = vecsize % nprocs;
105  if (rank < rem)
106  {
107  return std::make_pair(rank * (div + 1), div + 1);
108  }
109  else
110  {
111  return std::make_pair((rank - rem) * div + rem * (div + 1), div);
112  }
113 }
114 
115 template<class T, typename std::enable_if<T::kDim == 0, int>::type = 0>
116 inline int GetGeomDataDim(std::map<int, std::shared_ptr<T>> &geomMap)
117 {
118  boost::ignore_unused(geomMap);
119  return 3;
120 }
121 
122 template<class T, typename std::enable_if<T::kDim == 1, int>::type = 0>
123 inline int GetGeomDataDim(std::map<int, std::shared_ptr<T>> &geomMap)
124 {
125  boost::ignore_unused(geomMap);
126  return T::kNverts;
127 }
128 
129 template<class T, typename std::enable_if<T::kDim == 2, int>::type = 0>
130 inline int GetGeomDataDim(std::map<int, std::shared_ptr<T>> &geomMap)
131 {
132  boost::ignore_unused(geomMap);
133  return T::kNedges;
134 }
135 
136 template<class T, typename std::enable_if<T::kDim == 3, int>::type = 0>
137 inline int GetGeomDataDim(std::map<int, std::shared_ptr<T>> &geomMap)
138 {
139  boost::ignore_unused(geomMap);
140  return T::kNfaces;
141 }
142 
143 template<class ...T>
144 inline void UniqueValues(std::unordered_set<int> &unique)
145 {
146  boost::ignore_unused(unique);
147 }
148 
149 template<class ...T>
150 inline void UniqueValues(std::unordered_set<int> &unique,
151  const std::vector<int> &input,
152  T&... args)
153 {
154  for (auto i : input)
155  {
156  unique.insert(i);
157  }
158 
159  UniqueValues(unique, args...);
160 }
161 
162 /**
163  * @brief Partition the mesh
164  */
165 void MeshGraphHDF5::PartitionMesh(LibUtilities::SessionReaderSharedPtr session)
166 {
168  all.Start();
169  int err;
170  LibUtilities::CommSharedPtr comm = session->GetComm();
171  int rank = comm->GetRank(), nproc = comm->GetSize();
172 
173  // By default, only the root process will have read the session file, which
174  // is done to avoid every process needing to read the XML file. For HDF5, we
175  // don't care about this, so just have every process parse the session file.
176  if (rank > 0)
177  {
178  session->InitSession();
179  }
180 
181  // We use the XML geometry to find information about the HDF5 file.
182  m_session = session;
183  m_xmlGeom = m_session->GetElement("NEKTAR/GEOMETRY");
184  TiXmlAttribute *attr = m_xmlGeom->FirstAttribute();
185  m_meshPartitioned = true;
186  m_meshDimension = 3;
187  m_spaceDimension = 3;
188 
189  while (attr)
190  {
191  std::string attrName(attr->Name());
192  if (attrName == "DIM")
193  {
194  err = attr->QueryIntValue(&m_meshDimension);
195  ASSERTL0(err == TIXML_SUCCESS, "Unable to read mesh dimension.");
196  }
197  else if (attrName == "SPACE")
198  {
199  err = attr->QueryIntValue(&m_spaceDimension);
200  ASSERTL0(err == TIXML_SUCCESS, "Unable to read space dimension.");
201  }
202  else if (attrName == "PARTITION")
203  {
204  ASSERTL0(false,
205  "PARTITION parameter should only be used in XML meshes");
206  }
207  else if(attrName == "HDF5FILE")
208  {
209  m_hdf5Name = attr->Value();
210  ASSERTL1(err == TIXML_SUCCESS, "Unable to read hdf5 name.");
211  }
212  else if(attrName == "PARTITIONED")
213  {
214  ASSERTL0(false,
215  "PARTITIONED parameter should only be used in XML meshes");
216  }
217  else
218  {
219  std::string errstr("Unknown attribute: ");
220  errstr += attrName;
221  ASSERTL1(false, errstr.c_str());
222  }
223  // Get the next attribute.
224  attr = attr->Next();
225  }
226 
227  ASSERTL0(m_hdf5Name.size() > 0, "Unable to obtain mesh file name.");
228  ASSERTL0(m_meshDimension <= m_spaceDimension,
229  "Mesh dimension greater than space dimension.");
230 
231  // Open handle to the HDF5 mesh
232  LibUtilities::H5::PListSharedPtr parallelProps = H5::PList::Default();
233  m_readPL = H5::PList::Default();
234 
235  if (nproc > 1)
236  {
237  // Use MPI/O to access the file
238  parallelProps = H5::PList::FileAccess();
239  parallelProps->SetMpio(comm);
240  // Use collective IO
241  m_readPL = H5::PList::DatasetXfer();
242  m_readPL->SetDxMpioCollective();
243  }
244 
245  m_file = H5::File::Open(m_hdf5Name, H5F_ACC_RDONLY, parallelProps);
246 
247  auto root = m_file->OpenGroup("NEKTAR");
248  ASSERTL0(root, "Cannot find NEKTAR group in HDF5 file.");
249 
250  auto root2 = root->OpenGroup("GEOMETRY");
251  ASSERTL0(root2, "Cannot find NEKTAR/GEOMETRY group in HDF5 file.");
252 
253  // Check format version
254  unsigned int formatVersion;
255  H5::Group::AttrIterator attrIt = root2->attr_begin();
256  H5::Group::AttrIterator attrEnd = root2->attr_end();
257  for (; attrIt != attrEnd; ++attrIt)
258  {
259  if (*attrIt == "FORMAT_VERSION")
260  {
261  break;
262  }
263  }
264  ASSERTL0(attrIt != attrEnd,
265  "Unable to determine Nektar++ geometry HDF5 file version.");
266  root2->GetAttribute("FORMAT_VERSION", formatVersion);
267 
268  ASSERTL0(formatVersion <= FORMAT_VERSION,
269  "File format in " + m_hdf5Name + " is higher than supported in "
270  "this version of Nektar++");
271 
272  m_mesh = root2->OpenGroup("MESH");
273  ASSERTL0(m_mesh, "Cannot find NEKTAR/GEOMETRY/MESH group in HDF5 file.");
274  m_maps = root2->OpenGroup("MAPS");
275  ASSERTL0(m_mesh, "Cannot find NEKTAR/GEOMETRY/MAPS group in HDF5 file.");
276 
277  // Depending on dimension, read element IDs.
278  std::map<int, std::vector<std::tuple<
279  std::string, int, LibUtilities::ShapeType>>> dataSets;
280 
281  dataSets[1] = { make_tuple("SEG", 2, LibUtilities::eSegment) };
282  dataSets[2] = { make_tuple("TRI", 3, LibUtilities::eTriangle),
283  make_tuple("QUAD", 4, LibUtilities::eQuadrilateral) };
284  dataSets[3] = { make_tuple("TET", 4, LibUtilities::eTetrahedron),
285  make_tuple("PYR", 5, LibUtilities::ePyramid),
286  make_tuple("PRISM", 5, LibUtilities::ePrism),
287  make_tuple("HEX", 6, LibUtilities::eHexahedron) };
288 
289  // Read IDs for partitioning purposes
290  std::vector<MeshEntity> elmts;
291  std::vector<int> ids;
292 
293  // Map from element ID to 'row' which is a contiguous ordering required for
294  // parallel partitioning.
295  std::unordered_map<int, int> row2id, id2row;
296 
298  t.Start();
299  int rowCount = 0;
300  for (auto &it : dataSets[m_meshDimension])
301  {
302  std::string ds = std::get<0>(it);
303 
304  if (!m_mesh->ContainsDataSet(ds))
305  {
306  continue;
307  }
308 
309  // Open metadata dataset
310  H5::DataSetSharedPtr data = m_mesh->OpenDataSet(ds);
311  H5::DataSpaceSharedPtr space = data->GetSpace();
312  vector<hsize_t> dims = space->GetDims();
313 
314  H5::DataSetSharedPtr mdata = m_maps->OpenDataSet(ds);
315  H5::DataSpaceSharedPtr mspace = mdata->GetSpace();
316  vector<hsize_t> mdims = mspace->GetDims();
317 
318  // TODO: This could be done more intelligently; reads all IDs so that we
319  // can construct the dual graph of the mesh.
320  vector<int> tmpElmts, tmpIds;
321  mdata->Read(tmpIds, mspace, m_readPL);
322  data->Read(tmpElmts, space, m_readPL);
323 
324  const int nGeomData = std::get<1>(it);
325 
326  for (int i = 0, cnt = 0; i < tmpIds.size(); ++i, ++rowCount)
327  {
328  MeshEntity e;
329  row2id[rowCount] = tmpIds[i];
330  id2row[tmpIds[i]] = row2id[rowCount];
331  e.id = rowCount;
332  e.origId = tmpIds[i];
333  e.list = std::vector<unsigned int>(
334  &tmpElmts[cnt], &tmpElmts[cnt+nGeomData]);
335  elmts.push_back(e);
336  cnt += nGeomData;
337  }
338  }
339 
340  comm->Block();
341  t.Stop();
342 
343  bool verbRoot = rank == 0 &&
344  m_session->DefinesCmdLineArgument("verbose");
345 
346  if (verbRoot)
347  {
348  std::cout << "Reading HDF5 geometry..." << std::endl;
349  }
350 
351  TIME_RESULT(verbRoot, "initial read", t);
352 
353  // Check to see we have at least as many processors as elements.
354  size_t numElmt = elmts.size();
355  ASSERTL0(nproc <= numElmt,
356  "This mesh has more processors than elements!");
357 
358  // Calculate reasonably even distribution of processors for calling ptScotch
359  auto elRange = SplitWork(numElmt, rank, nproc);
360 
361  t.Start();
362 
363  // Construct map of element entities for partitioner.
364  std::map<int, MeshEntity> partElmts;
365  std::unordered_set<int> facetIDs;
366 
367  int vcnt = 0;
368 
369  for (int el = elRange.first; el < elRange.first + elRange.second;
370  ++el, ++vcnt)
371  {
372  MeshEntity elmt = elmts[el];
373  elmt.ghost = false;
374  partElmts[el] = elmt;
375 
376  for (auto &facet : elmt.list)
377  {
378  facetIDs.insert(facet);
379  }
380  }
381 
382  // Now identify ghost vertices for the graph. This could probably be
383  // improved.
384  int nLocal = vcnt;
385  for (int i = 0; i < numElmt; ++i)
386  {
387  // Ignore anything we already read.
388  if (i >= elRange.first && i < elRange.first + elRange.second)
389  {
390  //i += elRange.second - elRange.first - 1;
391  continue;
392  }
393 
394  MeshEntity elmt = elmts[i];
395  bool insert = false;
396 
397  // Check for connections to local elements.
398  for (auto &eId : elmt.list)
399  {
400  if (facetIDs.find(eId) != facetIDs.end())
401  {
402  insert = true;
403  break;
404  }
405  }
406 
407  if (insert)
408  {
409  elmt.ghost = true;
410  partElmts[elmt.id] = elmt;
411  }
412  }
413 
414  // Create partitioner. Default partitioner to use is PtScotch. Use ParMetis
415  // as default if it is installed. Override default with command-line flags
416  // if they are set.
417  string partitionerName = nproc > 1 ? "PtScotch" : "Scotch";
418  if (GetMeshPartitionFactory().ModuleExists("ParMetis"))
419  {
420  partitionerName = "ParMetis";
421  }
422  if (session->DefinesCmdLineArgument("use-parmetis"))
423  {
424  partitionerName = "ParMetis";
425  }
426  if (session->DefinesCmdLineArgument("use-ptscotch"))
427  {
428  partitionerName = "PtScotch";
429  }
430 
431  MeshPartitionSharedPtr partitioner =
433  partitionerName, session, m_meshDimension,
434  partElmts, CreateCompositeDescriptor(id2row));
435 
436  partitioner->PartitionMesh(nproc, true, false, nLocal);
437 
438  // Now we need to distribute vertex IDs to all the different processors.
439  t.Stop();
440  TIME_RESULT(verbRoot, "partitioning", t);
441 
442  // Each process now knows which rows of the dataset it needs to read for the
443  // elements of dimension m_meshDimension.
444  std::vector<unsigned int> tmp;
445  std::unordered_set<int> toRead;
446  partitioner->GetElementIDs(comm->GetRank(), tmp);
447 
448  for (auto &tmpId : tmp)
449  {
450  toRead.insert(row2id[tmpId]);
451  }
452 
453  // Since objects are going to be constructed starting from vertices, we now
454  // need to recurse down the geometry facet dimensions to figure out which
455  // rows to read from each dataset.
456  std::vector<int> vertIDs, segIDs, triIDs, quadIDs;
457  std::vector<int> tetIDs, prismIDs, pyrIDs, hexIDs;
458  std::vector<int> segData, triData, quadData, tetData;
459  std::vector<int> prismData, pyrData, hexData;
460  std::vector<NekDouble> vertData;
461 
462  if (m_meshDimension == 3)
463  {
464  t.Start();
465  // Read 3D data
466  ReadGeometryData(m_hexGeoms, "HEX", toRead, hexIDs, hexData);
467  ReadGeometryData(m_pyrGeoms, "PYR", toRead, pyrIDs, pyrData);
468  ReadGeometryData(m_prismGeoms, "PRISM", toRead, prismIDs, prismData);
469  ReadGeometryData(m_tetGeoms, "TET", toRead, tetIDs, tetData);
470 
471  toRead.clear();
472  UniqueValues(toRead, hexData, pyrData, prismData, tetData);
473  t.Stop();
474  TIME_RESULT(verbRoot, "read 3D elements", t);
475  }
476 
477  if (m_meshDimension >= 2)
478  {
479  t.Start();
480  // Read 2D data
481  ReadGeometryData(m_triGeoms, "TRI", toRead, triIDs, triData);
482  ReadGeometryData(m_quadGeoms, "QUAD", toRead, quadIDs, quadData);
483 
484  toRead.clear();
485  UniqueValues(toRead, triData, quadData);
486  t.Stop();
487  TIME_RESULT(verbRoot, "read 2D elements", t);
488  }
489 
490  if (m_meshDimension >= 1)
491  {
492  t.Start();
493  // Read 2D data
494  ReadGeometryData(m_segGeoms, "SEG", toRead, segIDs, segData);
495 
496  toRead.clear();
497  UniqueValues(toRead, segData);
498  t.Stop();
499  TIME_RESULT(verbRoot, "read 1D elements", t);
500  }
501 
502  t.Start();
503  ReadGeometryData(m_vertSet, "VERT", toRead, vertIDs, vertData);
504  t.Stop();
505  TIME_RESULT(verbRoot, "read 0D elements", t);
506 
507  // Now start to construct geometry objects, starting from vertices upwards.
508  t.Start();
509  FillGeomMap(m_vertSet, CurveMap(), vertIDs, vertData);
510  t.Stop();
511  TIME_RESULT(verbRoot, "construct 0D elements", t);
512 
513  if (m_meshDimension >= 1)
514  {
515  // Read curves
516  toRead.clear();
517  for (auto &edge : segIDs)
518  {
519  toRead.insert(edge);
520  }
521  ReadCurveMap(m_curvedEdges, "CURVE_EDGE", toRead);
522 
523  t.Start();
524  FillGeomMap(m_segGeoms, m_curvedEdges, segIDs, segData);
525  t.Stop();
526  TIME_RESULT(verbRoot, "construct 1D elements", t);
527  }
528 
529  if (m_meshDimension >= 2)
530  {
531  // Read curves
532  toRead.clear();
533  for (auto &face : triIDs)
534  {
535  toRead.insert(face);
536  }
537  for (auto &face : quadIDs)
538  {
539  toRead.insert(face);
540  }
541  ReadCurveMap(m_curvedFaces, "CURVE_FACE", toRead);
542 
543  t.Start();
544  FillGeomMap(m_triGeoms, m_curvedFaces, triIDs, triData);
545  FillGeomMap(m_quadGeoms, m_curvedFaces, quadIDs, quadData);
546  t.Stop();
547  TIME_RESULT(verbRoot, "construct 2D elements", t);
548  }
549 
550  if (m_meshDimension >= 3)
551  {
552  t.Start();
553  FillGeomMap(m_hexGeoms, CurveMap(), hexIDs, hexData);
554  FillGeomMap(m_prismGeoms, CurveMap(), prismIDs, prismData);
555  FillGeomMap(m_pyrGeoms, CurveMap(), pyrIDs, pyrData);
556  FillGeomMap(m_tetGeoms, CurveMap(), tetIDs, tetData);
557  t.Stop();
558  TIME_RESULT(verbRoot, "construct 3D elements", t);
559  }
560 
561  // Populate m_bndRegOrder.
562  if (m_session->DefinesElement("NEKTAR/CONDITIONS"))
563  {
564  std::set<int> vBndRegionIdList;
565  TiXmlElement *vConditions =
566  new TiXmlElement(*m_session->GetElement("Nektar/Conditions"));
567  TiXmlElement *vBndRegions =
568  vConditions->FirstChildElement("BOUNDARYREGIONS");
569  TiXmlElement *vItem;
570 
571  if (vBndRegions)
572  {
573  vItem = vBndRegions->FirstChildElement();
574  while (vItem)
575  {
576  std::string vSeqStr =
577  vItem->FirstChild()->ToText()->Value();
578  std::string::size_type indxBeg =
579  vSeqStr.find_first_of('[') + 1;
580  std::string::size_type indxEnd =
581  vSeqStr.find_last_of(']') - 1;
582  vSeqStr = vSeqStr.substr(indxBeg, indxEnd - indxBeg + 1);
583 
584  std::vector<unsigned int> vSeq;
585  ParseUtils::GenerateSeqVector(vSeqStr.c_str(), vSeq);
586 
587  int p = atoi(vItem->Attribute("ID"));
588  m_bndRegOrder[p] = vSeq;
589  vItem = vItem->NextSiblingElement();
590  }
591  }
592  }
593 
594  all.Stop();
595  TIME_RESULT(verbRoot, "total time", all);
596 }
597 
598 template<class T, typename DataType> void MeshGraphHDF5::ConstructGeomObject(
599  std::map<int, std::shared_ptr<T>> &geomMap, int id,
600  DataType *data, CurveSharedPtr curve)
601 {
602  boost::ignore_unused(geomMap, id, data, curve);
603 }
604 
605 template<> void MeshGraphHDF5::ConstructGeomObject(
606  std::map<int, std::shared_ptr<PointGeom>> &geomMap, int id,
607  NekDouble *data, CurveSharedPtr curve)
608 {
609  boost::ignore_unused(curve);
611  m_spaceDimension, id, data[0], data[1], data[2]);
612 }
613 
614 template<> void MeshGraphHDF5::ConstructGeomObject(
615  std::map<int, std::shared_ptr<SegGeom>> &geomMap, int id, int *data,
616  CurveSharedPtr curve)
617 {
618  PointGeomSharedPtr pts[2] = { GetVertex(data[0]), GetVertex(data[1]) };
620  id, m_spaceDimension, pts, curve);
621 }
622 
623 template<> void MeshGraphHDF5::ConstructGeomObject(
624  std::map<int, std::shared_ptr<TriGeom>> &geomMap, int id, int *data,
625  CurveSharedPtr curve)
626 {
627  SegGeomSharedPtr segs[3] = {
628  GetSegGeom(data[0]), GetSegGeom(data[1]), GetSegGeom(data[2]) };
629  geomMap[id] = MemoryManager<TriGeom>::AllocateSharedPtr(id, segs, curve);
630 }
631 
632 template<> void MeshGraphHDF5::ConstructGeomObject(
633  std::map<int, std::shared_ptr<QuadGeom>> &geomMap, int id, int *data,
634  CurveSharedPtr curve)
635 {
636  SegGeomSharedPtr segs[4] = {
637  GetSegGeom(data[0]), GetSegGeom(data[1]), GetSegGeom(data[2]),
638  GetSegGeom(data[3])
639  };
640  geomMap[id] = MemoryManager<QuadGeom>::AllocateSharedPtr(id, segs, curve);
641 }
642 
643 template<> void MeshGraphHDF5::ConstructGeomObject(
644  std::map<int, std::shared_ptr<TetGeom>> &geomMap, int id, int *data,
645  CurveSharedPtr curve)
646 {
647  boost::ignore_unused(curve);
648  TriGeomSharedPtr faces[4] = {
649  std::static_pointer_cast<TriGeom>(GetGeometry2D(data[0])),
650  std::static_pointer_cast<TriGeom>(GetGeometry2D(data[1])),
651  std::static_pointer_cast<TriGeom>(GetGeometry2D(data[2])),
652  std::static_pointer_cast<TriGeom>(GetGeometry2D(data[3]))
653  };
654 
655  auto tetGeom = MemoryManager<TetGeom>::AllocateSharedPtr(id, faces);
656  PopulateFaceToElMap(tetGeom, TetGeom::kNfaces);
657  geomMap[id] = tetGeom;
658 }
659 
660 template<> void MeshGraphHDF5::ConstructGeomObject(
661  std::map<int, std::shared_ptr<PyrGeom>> &geomMap, int id, int *data,
662  CurveSharedPtr curve)
663 {
664  boost::ignore_unused(curve);
665  Geometry2DSharedPtr faces[5] = {
666  GetGeometry2D(data[0]), GetGeometry2D(data[1]), GetGeometry2D(data[2]),
667  GetGeometry2D(data[3]), GetGeometry2D(data[4])
668  };
669 
670  auto pyrGeom = MemoryManager<PyrGeom>::AllocateSharedPtr(id, faces);
671  PopulateFaceToElMap(pyrGeom, PyrGeom::kNfaces);
672  geomMap[id] = pyrGeom;
673 }
674 
675 template<> void MeshGraphHDF5::ConstructGeomObject(
676  std::map<int, std::shared_ptr<PrismGeom>> &geomMap, int id, int *data,
677  CurveSharedPtr curve)
678 {
679  boost::ignore_unused(curve);
680  Geometry2DSharedPtr faces[5] = {
681  GetGeometry2D(data[0]), GetGeometry2D(data[1]), GetGeometry2D(data[2]),
682  GetGeometry2D(data[3]), GetGeometry2D(data[4])
683  };
684 
685  auto prismGeom = MemoryManager<PrismGeom>::AllocateSharedPtr(id, faces);
686  PopulateFaceToElMap(prismGeom, PrismGeom::kNfaces);
687  geomMap[id] = prismGeom;
688 }
689 
690 template<> void MeshGraphHDF5::ConstructGeomObject(
691  std::map<int, std::shared_ptr<HexGeom>> &geomMap, int id, int *data,
692  CurveSharedPtr curve)
693 {
694  boost::ignore_unused(curve);
695  QuadGeomSharedPtr faces[6] = {
696  std::static_pointer_cast<QuadGeom>(GetGeometry2D(data[0])),
697  std::static_pointer_cast<QuadGeom>(GetGeometry2D(data[1])),
698  std::static_pointer_cast<QuadGeom>(GetGeometry2D(data[2])),
699  std::static_pointer_cast<QuadGeom>(GetGeometry2D(data[3])),
700  std::static_pointer_cast<QuadGeom>(GetGeometry2D(data[4])),
701  std::static_pointer_cast<QuadGeom>(GetGeometry2D(data[5]))
702  };
703 
704  auto hexGeom = MemoryManager<HexGeom>::AllocateSharedPtr(id, faces);
705  PopulateFaceToElMap(hexGeom, HexGeom::kNfaces);
706  geomMap[id] = hexGeom;
707 }
708 
709 template<class T, typename DataType>
710 void MeshGraphHDF5::FillGeomMap(
711  std::map<int, std::shared_ptr<T>> &geomMap,
712  const CurveMap &curveMap,
713  std::vector<int> &ids,
714  std::vector<DataType> &geomData)
715 {
716  const int nGeomData = GetGeomDataDim(geomMap);
717  const int nRows = geomData.size() / nGeomData;
718  CurveSharedPtr empty;
719 
720  // Construct geometry object.
721  if (curveMap.size() > 0)
722  {
723  for(int i = 0, cnt = 0; i < nRows; i++, cnt += nGeomData)
724  {
725  auto cIt = curveMap.find(ids[i]);
726  ConstructGeomObject(
727  geomMap, ids[i], &geomData[cnt],
728  cIt == curveMap.end() ? empty : cIt->second);
729  }
730  }
731  else
732  {
733  for(int i = 0, cnt = 0; i < nRows; i++, cnt += nGeomData)
734  {
735  ConstructGeomObject(geomMap, ids[i], &geomData[cnt], empty);
736  }
737  }
738 }
739 
740 template<class T, typename DataType>
741 void MeshGraphHDF5::ReadGeometryData(
742  std::map<int, std::shared_ptr<T>> &geomMap,
743  std::string dataSet,
744  const std::unordered_set<int> &readIds,
745  std::vector<int> &ids,
746  std::vector<DataType> &geomData)
747 {
748  if (!m_mesh->ContainsDataSet(dataSet))
749  {
750  return;
751  }
752 
753  // Open mesh dataset
754  H5::DataSetSharedPtr data = m_mesh->OpenDataSet(dataSet);
755  H5::DataSpaceSharedPtr space = data->GetSpace();
756  vector<hsize_t> dims = space->GetDims();
757 
758  // Open metadata dataset
759  H5::DataSetSharedPtr mdata = m_maps->OpenDataSet(dataSet);
760  H5::DataSpaceSharedPtr mspace = mdata->GetSpace();
761  vector<hsize_t> mdims = mspace->GetDims();
762 
763  ASSERTL0(mdims[0] == dims[0], "map and data set lengths do not match");
764 
765  const int nGeomData = GetGeomDataDim(geomMap);
766 
767  // Read all IDs
768  vector<int> allIds;
769  mdata->Read(allIds, mspace);
770 
771  // Selective reading; clear data space range so that we can select certain
772  // rows from the datasets.
773  space->ClearRange();
774 
775  int i = 0;
776  std::vector<hsize_t> coords;
777  for (auto &id : allIds)
778  {
779  if (readIds.find(id) != readIds.end())
780  {
781  for (int j = 0; j < nGeomData; ++j)
782  {
783  coords.push_back(i);
784  coords.push_back(j);
785  }
786  ids.push_back(id);
787  }
788  ++i;
789  }
790 
791  space->SetSelection(coords.size() / 2, coords);
792 
793  // Read selected data.
794  data->Read(geomData, space, m_readPL);
795 }
796 
797 void MeshGraphHDF5::ReadCurveMap(
798  CurveMap &curveMap,
799  std::string dsName,
800  const std::unordered_set<int> &readIds)
801 {
802  // If dataset does not exist, exit.
803  if (!m_mesh->ContainsDataSet(dsName))
804  {
805  return;
806  }
807 
808  // Open up curve map data.
809  H5::DataSetSharedPtr curveData = m_mesh->OpenDataSet(dsName);
810  H5::DataSpaceSharedPtr curveSpace = curveData->GetSpace();
811 
812  // Open up ID data set.
813  H5::DataSetSharedPtr idData = m_maps->OpenDataSet(dsName);
814  H5::DataSpaceSharedPtr idSpace = idData->GetSpace();
815 
816  // Read all IDs and clear data space.
817  vector<int> ids, newIds;
818  idData->Read(ids, idSpace);
819  curveSpace->ClearRange();
820 
821  // Search IDs to figure out which curves to read.
822  vector<hsize_t> curveSel;
823 
824  int cnt = 0;
825  for (auto &id : ids)
826  {
827  if (readIds.find(id) != readIds.end())
828  {
829  curveSel.push_back(cnt);
830  curveSel.push_back(0);
831  curveSel.push_back(cnt);
832  curveSel.push_back(1);
833  curveSel.push_back(cnt);
834  curveSel.push_back(2);
835  newIds.push_back(id);
836  }
837 
838  ++cnt;
839  }
840 
841  // Check to see whether any processor will read anything
842  auto toRead = newIds.size();
843  m_session->GetComm()->AllReduce(toRead, LibUtilities::ReduceSum);
844 
845  if (toRead == 0)
846  {
847  return;
848  }
849 
850  // Now read curve map and read data.
851  vector<int> curveInfo;
852  curveSpace->SetSelection(curveSel.size() / 2, curveSel);
853  curveData->Read(curveInfo, curveSpace, m_readPL);
854 
855  curveSel.clear();
856 
857  std::unordered_map<int, int> curvePtOffset;
858 
859  // Construct curves. We'll populate nodes in a minute!
860  for (int i = 0, cnt = 0, cnt2 = 0; i < curveInfo.size() / 3; ++i, cnt += 3)
861  {
863  newIds[i], (LibUtilities::PointsType)curveInfo[cnt + 1]);
864 
865  curve->m_points.resize(curveInfo[cnt]);
866 
867  const int ptOffset = curveInfo[cnt + 2];
868 
869  for (int j = 0; j < curveInfo[cnt]; ++j)
870  {
871  // ptoffset gives us the row, multiply by 3 for number of
872  // coordinates.
873  curveSel.push_back(ptOffset + j);
874  curveSel.push_back(0);
875  curveSel.push_back(ptOffset + j);
876  curveSel.push_back(1);
877  curveSel.push_back(ptOffset + j);
878  curveSel.push_back(2);
879  }
880 
881  // Store the offset so we know to come back later on to fill in these
882  // points.
883  curvePtOffset[newIds[i]] = 3 * cnt2;
884  cnt2 += curveInfo[cnt];
885 
886  curveMap[newIds[i]] = curve;
887  }
888 
889  curveInfo.clear();
890 
891  // Open node data spacee.
892  H5::DataSetSharedPtr nodeData = m_mesh->OpenDataSet("CURVE_NODES");
893  H5::DataSpaceSharedPtr nodeSpace = nodeData->GetSpace();
894 
895  nodeSpace->ClearRange();
896  nodeSpace->SetSelection(curveSel.size() / 2, curveSel);
897 
898  vector<NekDouble> nodeRawData;
899  nodeData->Read(nodeRawData, nodeSpace, m_readPL);
900 
901  // Go back and populate data from nodes.
902  for (auto &cIt : curvePtOffset)
903  {
904  CurveSharedPtr curve = curveMap[cIt.first];
905 
906  // Create nodes.
907  int cnt = cIt.second;
908  for (int i = 0; i < curve->m_points.size(); ++i, cnt += 3)
909  {
910  curve->m_points[i] = MemoryManager<PointGeom>::AllocateSharedPtr(
911  0, m_spaceDimension, nodeRawData[cnt], nodeRawData[cnt+1],
912  nodeRawData[cnt+2]);
913  }
914  }
915 }
916 
917 void MeshGraphHDF5::ReadDomain()
918 {
919  map<int, CompositeSharedPtr> fullDomain;
920  H5::DataSetSharedPtr dst = m_mesh->OpenDataSet("DOMAIN");
921  H5::DataSpaceSharedPtr space = dst->GetSpace();
922 
923  vector<string> data;
924  dst->ReadVectorString(data, space, m_readPL);
925  GetCompositeList(data[0], fullDomain);
926  m_domain.push_back(fullDomain);
927 }
928 
929 void MeshGraphHDF5::ReadComposites()
930 {
931  string nm = "COMPOSITE";
932 
933  H5::DataSetSharedPtr data = m_mesh->OpenDataSet(nm);
934  H5::DataSpaceSharedPtr space = data->GetSpace();
935  vector<hsize_t> dims = space->GetDims();
936 
937  vector<string> comps;
938  data->ReadVectorString(comps, space);
939 
940  H5::DataSetSharedPtr mdata = m_maps->OpenDataSet(nm);
941  H5::DataSpaceSharedPtr mspace = mdata->GetSpace();
942  vector<hsize_t> mdims = mspace->GetDims();
943 
944  vector<int> ids;
945  mdata->Read(ids, mspace);
946 
947  for(int i = 0; i < dims[0]; i++)
948  {
949  string compStr = comps[i];
950 
951  char type;
952  istringstream strm(compStr);
953 
954  strm >> type;
955 
956  CompositeSharedPtr comp =
958 
959  string::size_type indxBeg = compStr.find_first_of('[') + 1;
960  string::size_type indxEnd = compStr.find_last_of(']') - 1;
961 
962  string indxStr = compStr.substr(indxBeg, indxEnd - indxBeg + 1);
963  vector<unsigned int> seqVector;
964 
965  ParseUtils::GenerateSeqVector(indxStr, seqVector);
966  m_compOrder[ids[i]] = seqVector;
967 
968  switch (type)
969  {
970  case 'V':
971  for (auto &i : seqVector)
972  {
973  auto it = m_vertSet.find(i);
974  if (it != m_vertSet.end())
975  {
976  comp->m_geomVec.push_back(it->second);
977  }
978  }
979  break;
980  case 'S':
981  case 'E':
982  for (auto &i : seqVector)
983  {
984  auto it = m_segGeoms.find(i);
985  if (it != m_segGeoms.end())
986  {
987  comp->m_geomVec.push_back(it->second);
988  }
989  }
990  break;
991  case 'Q':
992  for (auto &i : seqVector)
993  {
994  auto it = m_quadGeoms.find(i);
995  if (it != m_quadGeoms.end())
996  {
997  comp->m_geomVec.push_back(it->second);
998  }
999  }
1000  break;
1001  case 'T':
1002  for (auto &i : seqVector)
1003  {
1004  auto it = m_triGeoms.find(i);
1005  if (it != m_triGeoms.end())
1006  {
1007  comp->m_geomVec.push_back(it->second);
1008  }
1009  }
1010  break;
1011  case 'F':
1012  for(auto &i : seqVector)
1013  {
1014  auto it1 = m_quadGeoms.find(i);
1015  if (it1 != m_quadGeoms.end())
1016  {
1017  comp->m_geomVec.push_back(it1->second);
1018  continue;
1019  }
1020  auto it2 = m_triGeoms.find(i);
1021  if (it2 != m_triGeoms.end())
1022  {
1023  comp->m_geomVec.push_back(it2->second);
1024  }
1025  }
1026  break;
1027  case 'A':
1028  for(auto &i : seqVector)
1029  {
1030  auto it = m_tetGeoms.find(i);
1031  if (it != m_tetGeoms.end())
1032  {
1033  comp->m_geomVec.push_back(it->second);
1034  }
1035  }
1036  break;
1037  case 'P':
1038  for(auto &i : seqVector)
1039  {
1040  auto it = m_pyrGeoms.find(i);
1041  if (it != m_pyrGeoms.end())
1042  {
1043  comp->m_geomVec.push_back(it->second);
1044  }
1045  }
1046  break;
1047  case 'R':
1048  for(auto &i : seqVector)
1049  {
1050  auto it = m_prismGeoms.find(i);
1051  if (it != m_prismGeoms.end())
1052  {
1053  comp->m_geomVec.push_back(it->second);
1054  }
1055  }
1056  break;
1057  case 'H':
1058  for(auto &i : seqVector)
1059  {
1060  auto it = m_hexGeoms.find(i);
1061  if (it != m_hexGeoms.end())
1062  {
1063  comp->m_geomVec.push_back(it->second);
1064  }
1065  }
1066  break;
1067  }
1068 
1069  if (comp->m_geomVec.size() > 0)
1070  {
1071  m_meshComposites[ids[i]] = comp;
1072  }
1073  }
1074 }
1075 
1076 CompositeDescriptor MeshGraphHDF5::CreateCompositeDescriptor(
1077  std::unordered_map<int, int> &id2row)
1078 {
1079  CompositeDescriptor ret;
1080 
1081  string nm = "COMPOSITE";
1082 
1083  H5::DataSetSharedPtr data = m_mesh->OpenDataSet(nm);
1084  H5::DataSpaceSharedPtr space = data->GetSpace();
1085  vector<hsize_t> dims = space->GetDims();
1086 
1087  vector<string> comps;
1088  data->ReadVectorString(comps, space);
1089 
1090  H5::DataSetSharedPtr mdata = m_maps->OpenDataSet(nm);
1091  H5::DataSpaceSharedPtr mspace = mdata->GetSpace();
1092  vector<hsize_t> mdims = mspace->GetDims();
1093 
1094  vector<int> ids;
1095  mdata->Read(ids, mspace);
1096 
1097  for (int i = 0; i < dims[0]; i++)
1098  {
1099  string compStr = comps[i];
1100 
1101  char type;
1102  istringstream strm(compStr);
1103 
1104  strm >> type;
1105 
1106  string::size_type indxBeg = compStr.find_first_of('[') + 1;
1107  string::size_type indxEnd = compStr.find_last_of(']') - 1;
1108 
1109  string indxStr = compStr.substr(indxBeg, indxEnd - indxBeg + 1);
1110  vector<unsigned int> seqVector;
1111  ParseUtils::GenerateSeqVector(indxStr, seqVector);
1112 
1113  LibUtilities::ShapeType shapeType;
1114 
1115  switch (type)
1116  {
1117  case 'V':
1118  shapeType = LibUtilities::ePoint;
1119  break;
1120  case 'S':
1121  case 'E':
1122  shapeType = LibUtilities::eSegment;
1123  break;
1124  case 'Q':
1125  case 'F':
1126  // Note that for HDF5, the composite descriptor is only used for
1127  // partitioning purposes so 'F' tag is not really going to be
1128  // critical in this context.
1129  shapeType = LibUtilities::eQuadrilateral;
1130  break;
1131  case 'T':
1132  shapeType = LibUtilities::eTriangle;
1133  break;
1134  case 'A':
1135  shapeType = LibUtilities::eTetrahedron;
1136  break;
1137  case 'P':
1138  shapeType = LibUtilities::ePyramid;
1139  break;
1140  case 'R':
1141  shapeType = LibUtilities::ePrism;
1142  break;
1143  case 'H':
1144  shapeType = LibUtilities::eHexahedron;
1145  break;
1146  }
1147 
1148  std::vector<int> filteredVector;
1149  for (auto &compElmt : seqVector)
1150  {
1151  if (id2row.find(compElmt) == id2row.end())
1152  {
1153  continue;
1154  }
1155 
1156  filteredVector.push_back(compElmt);
1157  }
1158 
1159  if (filteredVector.size() == 0)
1160  {
1161  continue;
1162  }
1163 
1164  ret[ids[i]] = std::make_pair(shapeType, filteredVector);
1165  }
1166 
1167  return ret;
1168 }
1169 
1170 
1171 template<class T, typename std::enable_if<T::kDim == 0, int>::type = 0>
1172 inline NekDouble GetGeomData(std::shared_ptr<T> &geom, int i)
1173 {
1174  return (*geom)(i);
1175 }
1176 
1177 template<class T, typename std::enable_if<T::kDim == 1, int>::type = 0>
1178 inline int GetGeomData(std::shared_ptr<T> &geom, int i)
1179 {
1180  return geom->GetVid(i);
1181 }
1182 
1183 template<class T, typename std::enable_if<T::kDim == 2, int>::type = 0>
1184 inline int GetGeomData(std::shared_ptr<T> &geom, int i)
1185 {
1186  return geom->GetEid(i);
1187 }
1188 
1189 template<class T, typename std::enable_if<T::kDim == 3, int>::type = 0>
1190 inline int GetGeomData(std::shared_ptr<T> &geom, int i)
1191 {
1192  return geom->GetFid(i);
1193 }
1194 
1195 template<class T>
1196 void MeshGraphHDF5::WriteGeometryMap(std::map<int, std::shared_ptr<T>> &geomMap,
1197  std::string datasetName)
1198 {
1199  typedef typename std::conditional<
1200  std::is_same<T, PointGeom>::value, NekDouble, int>::type DataType;
1201 
1202  const int nGeomData = GetGeomDataDim(geomMap);
1203  const size_t nGeom = geomMap.size();
1204 
1205  if (nGeom == 0)
1206  {
1207  return;
1208  }
1209 
1210  // Construct a map storing IDs
1211  vector<int> idMap(nGeom);
1212  vector<DataType> data(nGeom * nGeomData);
1213 
1214  int cnt1 = 0, cnt2 = 0;
1215  for (auto &it : geomMap)
1216  {
1217  idMap[cnt1++] = it.first;
1218 
1219  for (int j = 0; j < nGeomData; ++j)
1220  {
1221  data[cnt2 + j] = GetGeomData(it.second, j);
1222  }
1223 
1224  cnt2 += nGeomData;
1225  }
1226 
1227  vector<hsize_t> dims = { static_cast<hsize_t>(nGeom),
1228  static_cast<hsize_t>(nGeomData) };
1229  H5::DataTypeSharedPtr tp = H5::DataType::OfObject(data[0]);
1231  std::shared_ptr<H5::DataSpace>(new H5::DataSpace(dims));
1232  H5::DataSetSharedPtr dst = m_mesh->CreateDataSet(datasetName, tp, ds);
1233  dst->Write(data, ds);
1234 
1235  tp = H5::DataType::OfObject(idMap[0]);
1236  dims = { nGeom };
1237  ds = std::shared_ptr<H5::DataSpace>(new H5::DataSpace(dims));
1238  dst = m_maps->CreateDataSet(datasetName, tp, ds);
1239  dst->Write(idMap, ds);
1240 }
1241 
1242 void MeshGraphHDF5::WriteCurveMap(CurveMap &curves,
1243  std::string dsName,
1244  MeshCurvedPts &curvedPts,
1245  int &ptOffset,
1246  int &newIdx)
1247 {
1248  vector<int> data, map;
1249 
1250  // Compile curve data.
1251  for (auto &c : curves)
1252  {
1253  map.push_back(c.first);
1254  data.push_back(c.second->m_points.size());
1255  data.push_back(c.second->m_ptype);
1256  data.push_back(ptOffset);
1257 
1258  ptOffset += c.second->m_points.size();
1259 
1260  for (auto &pt : c.second->m_points)
1261  {
1262  MeshVertex v;
1263  v.id = newIdx;
1264  pt->GetCoords(v.x, v.y, v.z);
1265  curvedPts.pts.push_back(v);
1266  curvedPts.index.push_back(newIdx++);
1267  }
1268  }
1269 
1270  // Write data.
1271  vector<hsize_t> dims = { data.size() / 3, 3 };
1272  H5::DataTypeSharedPtr tp = H5::DataType::OfObject(data[0]);
1274  std::shared_ptr<H5::DataSpace>(new H5::DataSpace(dims));
1275  H5::DataSetSharedPtr dst = m_mesh->CreateDataSet(dsName, tp, ds);
1276  dst->Write(data, ds);
1277 
1278  tp = H5::DataType::OfObject(map[0]);
1279  dims = { map.size() };
1280  ds = std::shared_ptr<H5::DataSpace>(new H5::DataSpace(dims));
1281  dst = m_maps->CreateDataSet(dsName, tp, ds);
1282  dst->Write(map, ds);
1283 }
1284 
1285 void MeshGraphHDF5::WriteCurvePoints(MeshCurvedPts &curvedPts)
1286 {
1287  vector<double> vertData(curvedPts.pts.size() * 3);
1288 
1289  int cnt = 0;
1290  for (auto &pt : curvedPts.pts)
1291  {
1292  vertData[cnt++] = pt.x;
1293  vertData[cnt++] = pt.y;
1294  vertData[cnt++] = pt.z;
1295  }
1296 
1297  vector<hsize_t> dims = { curvedPts.pts.size(), 3 };
1298  H5::DataTypeSharedPtr tp = H5::DataType::OfObject(vertData[0]);
1300  std::shared_ptr<H5::DataSpace>(new H5::DataSpace(dims));
1301  H5::DataSetSharedPtr dst = m_mesh->CreateDataSet("CURVE_NODES", tp, ds);
1302  dst->Write(vertData, ds);
1303 }
1304 
1305 void MeshGraphHDF5::WriteComposites(CompositeMap &composites)
1306 {
1307  vector<string> comps;
1308 
1309  //dont need location map only a id map
1310  //will filter the composites per parition on read, its easier
1311  //composites do not need to be written in paralell.
1312  vector<int> c_map;
1313 
1314  for (auto &cIt : composites)
1315  {
1316  if (cIt.second->m_geomVec.size() == 0)
1317  {
1318  continue;
1319  }
1320 
1321  comps.push_back(GetCompositeString(cIt.second));
1322  c_map.push_back(cIt.first);
1323  }
1324 
1325  H5::DataTypeSharedPtr tp = H5::DataType::String();
1326  H5::DataSpaceSharedPtr ds = H5::DataSpace::OneD(comps.size());
1327  H5::DataSetSharedPtr dst = m_mesh->CreateDataSet("COMPOSITE", tp, ds);
1328  dst->WriteVectorString(comps, ds, tp);
1329 
1330  tp = H5::DataType::OfObject(c_map[0]);
1331  ds = H5::DataSpace::OneD(c_map.size());
1332  dst = m_maps->CreateDataSet("COMPOSITE", tp, ds);
1333  dst->Write(c_map, ds);
1334 }
1335 
1336 void MeshGraphHDF5::WriteDomain(vector<CompositeMap> &domain)
1337 {
1338  vector<unsigned int> idxList;
1339  for (auto cIt = domain[0].begin(); cIt != domain[0].end(); ++cIt)
1340  {
1341  idxList.push_back(cIt->first);
1342  }
1343  stringstream domString;
1344  vector<string> doms;
1345  doms.push_back(ParseUtils::GenerateSeqString(idxList));
1346 
1347  H5::DataTypeSharedPtr tp = H5::DataType::String();
1348  H5::DataSpaceSharedPtr ds = H5::DataSpace::OneD(doms.size());
1349  H5::DataSetSharedPtr dst = m_mesh->CreateDataSet("DOMAIN", tp, ds);
1350  dst->WriteVectorString(doms, ds, tp);
1351 }
1352 
1353 void MeshGraphHDF5::WriteGeometry(
1354  std::string &outfilename,
1355  bool defaultExp,
1356  const LibUtilities::FieldMetaDataMap &metadata)
1357 {
1358  boost::ignore_unused(metadata);
1359 
1360  vector<string> tmp;
1361  boost::split(tmp, outfilename, boost::is_any_of("."));
1362  string filenameXml = tmp[0] + ".xml";
1363  string filenameHdf5 = tmp[0] + ".nekg";
1364 
1365  //////////////////
1366  // XML part
1367  //////////////////
1368 
1369  //Check to see if a xml of the same name exists
1370  //if might have boundary conditions etc, we will just alter the geometry
1371  //tag if needed
1372  TiXmlDocument *doc = new TiXmlDocument;
1373  TiXmlElement *root;
1374  TiXmlElement *geomTag;
1375 
1376  if(boost::filesystem::exists(filenameXml.c_str()))
1377  {
1378  ifstream file(filenameXml.c_str());
1379  file >> (*doc);
1380  TiXmlHandle docHandle(doc);
1381  root = docHandle.FirstChildElement("NEKTAR").Element();
1382  ASSERTL0(root, "Unable to find NEKTAR tag in file.");
1383  geomTag = root->FirstChildElement("GEOMETRY");
1384  defaultExp = false;
1385  }
1386  else
1387  {
1388  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
1389  doc->LinkEndChild(decl);
1390  root = new TiXmlElement("NEKTAR");
1391  doc->LinkEndChild(root);
1392 
1393  geomTag = new TiXmlElement("GEOMETRY");
1394  root->LinkEndChild(geomTag);
1395  }
1396 
1397  // Update attributes with dimensions.
1398  geomTag->SetAttribute("DIM", m_meshDimension);
1399  geomTag->SetAttribute("SPACE", m_spaceDimension);
1400  geomTag->SetAttribute("HDF5FILE", filenameHdf5);
1401 
1402  geomTag->Clear();
1403 
1404  if (defaultExp)
1405  {
1406  TiXmlElement *expTag = new TiXmlElement("EXPANSIONS");
1407 
1408  for (auto it = m_meshComposites.begin(); it != m_meshComposites.end();
1409  it++)
1410  {
1411  if (it->second->m_geomVec[0]->GetShapeDim() == m_meshDimension)
1412  {
1413  TiXmlElement *exp = new TiXmlElement("E");
1414  exp->SetAttribute(
1415  "COMPOSITE",
1416  "C[" + boost::lexical_cast<string>(it->first) + "]");
1417  exp->SetAttribute("NUMMODES", 4);
1418  exp->SetAttribute("TYPE", "MODIFIED");
1419  exp->SetAttribute("FIELDS", "u");
1420 
1421  expTag->LinkEndChild(exp);
1422  }
1423  }
1424  root->LinkEndChild(expTag);
1425  }
1426 
1427  doc->SaveFile(filenameXml);
1428 
1429  //////////////////
1430  // HDF5 part
1431  //////////////////
1432 
1433  // This is serial IO so we will just override any existing file.
1434  m_file = H5::File::Create(filenameHdf5, H5F_ACC_TRUNC);
1435  auto hdfRoot = m_file->CreateGroup("NEKTAR");
1436  auto hdfRoot2 = hdfRoot->CreateGroup("GEOMETRY");
1437 
1438  // Write format version.
1439  hdfRoot2->SetAttribute("FORMAT_VERSION", FORMAT_VERSION);
1440 
1441  // Create main groups.
1442  m_mesh = hdfRoot2->CreateGroup("MESH");
1443  m_maps = hdfRoot2->CreateGroup("MAPS");
1444 
1445  WriteGeometryMap(m_vertSet, "VERT");
1446  WriteGeometryMap(m_segGeoms, "SEG");
1447  if (m_meshDimension > 1)
1448  {
1449  WriteGeometryMap(m_triGeoms, "TRI");
1450  WriteGeometryMap(m_quadGeoms, "QUAD");
1451  }
1452  if (m_meshDimension > 2)
1453  {
1454  WriteGeometryMap(m_tetGeoms, "TET");
1455  WriteGeometryMap(m_pyrGeoms, "PYR");
1456  WriteGeometryMap(m_prismGeoms, "PRISM");
1457  WriteGeometryMap(m_hexGeoms, "HEX");
1458  }
1459 
1460  // Write curves
1461  int ptOffset = 0, newIdx = 0;
1462  MeshCurvedPts curvePts;
1463  WriteCurveMap(m_curvedEdges, "CURVE_EDGE", curvePts, ptOffset, newIdx);
1464  WriteCurveMap(m_curvedFaces, "CURVE_FACE", curvePts, ptOffset, newIdx);
1465  WriteCurvePoints(curvePts);
1466 
1467  // Write composites and domain.
1468  WriteComposites(m_meshComposites);
1469  WriteDomain(m_domain);
1470 }
1471 
1472 }
1473 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
std::vector< NekInt64 > index
id of this Point set
std::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry.h:65
std::shared_ptr< MeshPartition > MeshPartitionSharedPtr
std::unordered_map< int, CurveSharedPtr > CurveMap
Definition: Curve.hpp:62
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
HDF5 DataSpace wrapper.
Definition: H5.h:314
std::shared_ptr< QuadGeom > QuadGeomSharedPtr
Definition: HexGeom.h:46
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:53
STL namespace.
std::map< int, CompositeSharedPtr > CompositeMap
Definition: MeshGraph.h:137
std::vector< MeshVertex > pts
mapping to access pts value.
std::shared_ptr< DataSpace > DataSpaceSharedPtr
Definition: H5.h:90
std::shared_ptr< Composite > CompositeSharedPtr
Definition: MeshGraph.h:136
std::shared_ptr< DomainRange > DomainRangeShPtr
Definition: MeshGraph.h:128
std::map< std::string, std::string > FieldMetaDataMap
Definition: FieldIO.h:52
std::shared_ptr< DataSet > DataSetSharedPtr
Definition: H5.h:102
std::shared_ptr< DataType > DataTypeSharedPtr
Definition: H5.h:86
std::shared_ptr< PList > PListSharedPtr
Definition: H5.h:104
int GetGeomData(std::shared_ptr< T > &geom, int i)
int GetGeomDataDim(std::map< int, std::shared_ptr< T >> &geomMap)
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
std::shared_ptr< TriGeom > TriGeomSharedPtr
Definition: TriGeom.h:58
bool ModuleExists(tKey idKey)
Checks if a particular module is available.
Definition: NekFactory.hpp:215
MeshGraphFactory & GetMeshGraphFactory()
Definition: MeshGraph.cpp:76
std::vector< unsigned int > list
double NekDouble
std::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:59
std::map< int, std::pair< LibUtilities::ShapeType, std::vector< int > > > CompositeDescriptor
Definition: MeshGraph.h:62
std::shared_ptr< Curve > CurveSharedPtr
Definition: Curve.hpp:61
std::pair< size_t, size_t > SplitWork(size_t vecsize, int rank, int nprocs)
Utility function to split a vector equally amongst a number of processors.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199
MeshPartitionFactory & GetMeshPartitionFactory()
void UniqueValues(std::unordered_set< int > &unique, const std::vector< int > &input, T &... args)
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
std::shared_ptr< SegGeom > SegGeomSharedPtr
Definition: Geometry2D.h:62
std::shared_ptr< SessionReader > SessionReaderSharedPtr
#define TIME_RESULT(verb, msg, timer)