Nektar++
FieldIOXml.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: FieldIOXml.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: I/O routines relating to Fields into XML
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
38 
39 #include <boost/format.hpp>
40 
41 #ifdef NEKTAR_USE_MPI
42 #include <mpi.h>
43 #endif
44 
45 namespace berrc = boost::system::errc;
46 
47 namespace Nektar
48 {
49 namespace LibUtilities
50 {
51 
53  "Xml", FieldIOXml::create, "XML-based output of field data.");
54 
55 /**
56  * @brief Default constructor.
57  *
58  * @param pComm Communicator.
59  * @param sharedFilesystem True if the underlying filesystem is shared by the
60  * compute nodes.
61  */
63  : FieldIO(pComm, sharedFilesystem)
64 {
65 }
66 
67 /**
68  * @brief Write an XML file to @p outFile given the field definitions @p
69  * fielddefs, field data @p fielddata and metadata @p fieldmetadatamap.
70  *
71  * The writing strategy is as follows:
72  *
73  * - Use FieldIO::SetUpOutput to construct the directory to contain each
74  * partition.
75  * - The root processor writes an `Info.xml` file containing the field
76  * metadata and an index that describes which elements lie in which XML
77  * file.
78  * - Each processor then writes an XML file containing the field definitions
79  * for that processor and output data in base64-encoded zlib-compressed
80  * format.
81  *
82  * @param outFile Output filename.
83  * @param fielddefs Input field definitions.
84  * @param fielddata Input field data.
85  * @param fieldmetadatamap Field metadata.
86  */
87 void FieldIOXml::v_Write(const std::string &outFile,
88  std::vector<FieldDefinitionsSharedPtr> &fielddefs,
89  std::vector<std::vector<NekDouble>> &fielddata,
90  const FieldMetaDataMap &fieldmetadatamap,
91  const bool backup)
92 {
93  double tm0 = 0.0, tm1 = 0.0;
94  if (m_comm->TreatAsRankZero())
95  {
96  tm0 = m_comm->Wtime();
97  }
98 
99  // Check everything seems sensible
100  ASSERTL1(fielddefs.size() == fielddata.size(),
101  "Length of fielddefs and fielddata incompatible");
102  for (int f = 0; f < fielddefs.size(); ++f)
103  {
104  ASSERTL1(fielddata[f].size() > 0,
105  "Fielddata vector must contain at least one value.");
106 
107  ASSERTL1(fielddata[f].size() == fielddefs[f]->m_fields.size() *
108  CheckFieldDefinition(fielddefs[f]),
109  "Invalid size of fielddata vector.");
110  }
111 
112  // Prepare to write out data. In parallel, we must create directory and
113  // determine the full pathname to the file to write out. Any existing
114  // file/directory which is in the way is removed.
115  std::string filename = SetUpOutput(outFile, true, backup);
116  SetUpFieldMetaData(outFile, fielddefs, fieldmetadatamap);
117 
118  // Create the file (partition)
119  TiXmlDocument doc;
120  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
121  doc.LinkEndChild(decl);
122 
123  TiXmlElement *root = new TiXmlElement("NEKTAR");
124  doc.LinkEndChild(root);
125 
126  AddInfoTag(XmlTagWriterSharedPtr(new XmlTagWriter(root)), fieldmetadatamap);
127 
128  for (int f = 0; f < fielddefs.size(); ++f)
129  {
130  //---------------------------------------------
131  // Write ELEMENTS
132  TiXmlElement *elemTag = new TiXmlElement("ELEMENTS");
133  root->LinkEndChild(elemTag);
134 
135  // Write FIELDS
136  std::string fieldsString;
137  {
138  std::stringstream fieldsStringStream;
139  bool first = true;
140  for (std::vector<int>::size_type i = 0;
141  i < fielddefs[f]->m_fields.size(); i++)
142  {
143  if (!first)
144  {
145  fieldsStringStream << ",";
146  }
147  fieldsStringStream << fielddefs[f]->m_fields[i];
148  first = false;
149  }
150  fieldsString = fieldsStringStream.str();
151  }
152  elemTag->SetAttribute("FIELDS", fieldsString);
153 
154  // Write SHAPE
155  std::string shapeString;
156  {
157  std::stringstream shapeStringStream;
158  shapeStringStream << ShapeTypeMap[fielddefs[f]->m_shapeType];
159  if (fielddefs[f]->m_numHomogeneousDir == 1)
160  {
161  shapeStringStream << "-HomogenousExp1D";
162  }
163  else if (fielddefs[f]->m_numHomogeneousDir == 2)
164  {
165  shapeStringStream << "-HomogenousExp2D";
166  }
167 
168  if (fielddefs[f]->m_homoStrips)
169  {
170  shapeStringStream << "-Strips";
171  }
172 
173  shapeString = shapeStringStream.str();
174  }
175  elemTag->SetAttribute("SHAPE", shapeString);
176 
177  // Write BASIS
178  std::string basisString;
179  {
180  std::stringstream basisStringStream;
181  bool first = true;
182  for (std::vector<BasisType>::size_type i = 0;
183  i < fielddefs[f]->m_basis.size(); i++)
184  {
185  if (!first)
186  {
187  basisStringStream << ",";
188  }
189  basisStringStream << BasisTypeMap[fielddefs[f]->m_basis[i]];
190  first = false;
191  }
192  basisString = basisStringStream.str();
193  }
194  elemTag->SetAttribute("BASIS", basisString);
195 
196  // Write homogeneuous length details
197  if (fielddefs[f]->m_numHomogeneousDir)
198  {
199  std::string homoLenString;
200  {
201  std::stringstream homoLenStringStream;
202  bool first = true;
203  for (int i = 0; i < fielddefs[f]->m_numHomogeneousDir; ++i)
204  {
205  if (!first)
206  homoLenStringStream << ",";
207  homoLenStringStream
208  << fielddefs[f]->m_homogeneousLengths[i];
209  first = false;
210  }
211  homoLenString = homoLenStringStream.str();
212  }
213  elemTag->SetAttribute("HOMOGENEOUSLENGTHS", homoLenString);
214  }
215 
216  // Write homogeneuous planes/lines details
217  if (fielddefs[f]->m_numHomogeneousDir)
218  {
219  if (fielddefs[f]->m_homogeneousYIDs.size() > 0)
220  {
221  std::string homoYIDsString;
222  {
223  std::stringstream homoYIDsStringStream;
224  bool first = true;
225  for (int i = 0; i < fielddefs[f]->m_homogeneousYIDs.size();
226  i++)
227  {
228  if (!first)
229  {
230  homoYIDsStringStream << ",";
231  }
232  homoYIDsStringStream
233  << fielddefs[f]->m_homogeneousYIDs[i];
234  first = false;
235  }
236  homoYIDsString = homoYIDsStringStream.str();
237  }
238  elemTag->SetAttribute("HOMOGENEOUSYIDS", homoYIDsString);
239  }
240 
241  if (fielddefs[f]->m_homogeneousZIDs.size() > 0)
242  {
243  std::string homoZIDsString;
244  {
245  std::stringstream homoZIDsStringStream;
246  bool first = true;
247  for (int i = 0; i < fielddefs[f]->m_homogeneousZIDs.size();
248  i++)
249  {
250  if (!first)
251  {
252  homoZIDsStringStream << ",";
253  }
254  homoZIDsStringStream
255  << fielddefs[f]->m_homogeneousZIDs[i];
256  first = false;
257  }
258  homoZIDsString = homoZIDsStringStream.str();
259  }
260  elemTag->SetAttribute("HOMOGENEOUSZIDS", homoZIDsString);
261  }
262 
263  if (fielddefs[f]->m_homogeneousSIDs.size() > 0)
264  {
265  std::string homoSIDsString;
266  {
267  std::stringstream homoSIDsStringStream;
268  bool first = true;
269  for (int i = 0; i < fielddefs[f]->m_homogeneousSIDs.size();
270  i++)
271  {
272  if (!first)
273  {
274  homoSIDsStringStream << ",";
275  }
276  homoSIDsStringStream
277  << fielddefs[f]->m_homogeneousSIDs[i];
278  first = false;
279  }
280  homoSIDsString = homoSIDsStringStream.str();
281  }
282  elemTag->SetAttribute("HOMOGENEOUSSIDS", homoSIDsString);
283  }
284  }
285 
286  // Write NUMMODESPERDIR
287  std::string numModesString;
288  {
289  std::stringstream numModesStringStream;
290 
291  if (fielddefs[f]->m_uniOrder)
292  {
293  numModesStringStream << "UNIORDER:";
294  // Just dump single definition
295  bool first = true;
296  for (std::vector<int>::size_type i = 0;
297  i < fielddefs[f]->m_basis.size(); i++)
298  {
299  if (!first)
300  {
301  numModesStringStream << ",";
302  }
303  numModesStringStream << fielddefs[f]->m_numModes[i];
304  first = false;
305  }
306  }
307  else
308  {
309  numModesStringStream << "MIXORDER:";
310  bool first = true;
311  for (std::vector<int>::size_type i = 0;
312  i < fielddefs[f]->m_numModes.size(); i++)
313  {
314  if (!first)
315  {
316  numModesStringStream << ",";
317  }
318  numModesStringStream << fielddefs[f]->m_numModes[i];
319  first = false;
320  }
321  }
322 
323  numModesString = numModesStringStream.str();
324  }
325  elemTag->SetAttribute("NUMMODESPERDIR", numModesString);
326 
327  // Write ID
328  // Should ideally look at ways of compressing this stream
329  // if just sequential;
330  std::string idString;
331  {
332  std::stringstream idStringStream;
333  idString =
334  ParseUtils::GenerateSeqString(fielddefs[f]->m_elementIDs);
335  }
336  elemTag->SetAttribute("ID", idString);
337  elemTag->SetAttribute("COMPRESSED",
339 
340  // Add this information for future compatibility
341  // issues, for exmaple in case we end up using a 128
342  // bit machine.
343  elemTag->SetAttribute("BITSIZE",
345  std::string base64string;
346  ASSERTL0(Z_OK == CompressData::ZlibEncodeToBase64Str(fielddata[f],
347  base64string),
348  "Failed to compress field data.");
349 
350  elemTag->LinkEndChild(new TiXmlText(base64string));
351  }
352  doc.SaveFile(filename);
353 
354  m_comm->GetSpaceComm()->Block();
355 
356  // all data has been written
357  if (m_comm->TreatAsRankZero())
358  {
359  tm1 = m_comm->Wtime();
360  std::cout << " (" << tm1 - tm0 << "s, XML)" << std::endl;
361  }
362 }
363 
364 /**
365  * @brief Write out a file containing element ID to partition mapping.
366  *
367  * This function writes out an XML file (usually called `Info.xml`) that
368  * contains the element IDs that are contained within each partition, as well as
369  * the field metadata map.
370  *
371  * @param outFile Output multi-field file name.
372  * @param fileNames List of partition filenames.
373  * @param elementList Vector of element IDs that lie on each process.
374  * @param fieldmetadatamap Field metadata map that is written into @p outFile.
375  */
377  const std::string &outFile, const std::vector<std::string> fileNames,
378  std::vector<std::vector<unsigned int>> &elementList,
379  const FieldMetaDataMap &fieldmetadatamap)
380 {
381  TiXmlDocument doc;
382  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
383  doc.LinkEndChild(decl);
384 
385  ASSERTL0(fileNames.size() == elementList.size(),
386  "Outfile names and list of elements ids does not match");
387 
388  TiXmlElement *root = new TiXmlElement("NEKTAR");
389  doc.LinkEndChild(root);
390 
391  AddInfoTag(XmlTagWriterSharedPtr(new XmlTagWriter(root)), fieldmetadatamap);
392 
393  for (int t = 0; t < fileNames.size(); ++t)
394  {
395  if (elementList[t].size())
396  {
397  TiXmlElement *elemIDs = new TiXmlElement("Partition");
398  root->LinkEndChild(elemIDs);
399 
400  elemIDs->SetAttribute("FileName", fileNames[t]);
401 
402  std::string IDstr = ParseUtils::GenerateSeqString(elementList[t]);
403 
404  elemIDs->LinkEndChild(new TiXmlText(IDstr));
405  }
406  }
407 
408  doc.SaveFile(outFile);
409 }
410 
411 /**
412  * @brief Read file containing element ID to partition mapping.
413  *
414  * This function reads an XML file (usually called `Info.xml`) that contains the
415  * element IDs that are contained within each partition, as well as the field
416  * metadata map.
417  *
418  * @param inFile Input multi-field file name.
419  * @param fileNames List of partition filenames.
420  * @param elementList Vector of element IDs that lie on each process.
421  * @param fieldmetadatamap Field metadata map that is read from @p inFile.
422  */
424  const std::string &inFile, std::vector<std::string> &fileNames,
425  std::vector<std::vector<unsigned int>> &elementList,
426  FieldMetaDataMap &fieldmetadatamap)
427 {
428  boost::ignore_unused(fieldmetadatamap);
429 
430  TiXmlDocument doc(inFile);
431  bool loadOkay = doc.LoadFile();
432 
433  std::stringstream errstr;
434  errstr << "Unable to load file: " << inFile << std::endl;
435  errstr << "Reason: " << doc.ErrorDesc() << std::endl;
436  errstr << "Position: Line " << doc.ErrorRow() << ", Column "
437  << doc.ErrorCol() << std::endl;
438  ASSERTL0(loadOkay, errstr.str());
439 
440  // Handle on XML document
441  TiXmlHandle docHandle(&doc);
442 
443  // Retrieve main NEKTAR tag - XML specification states one
444  // top-level element tag per file.
445  TiXmlElement *master = doc.FirstChildElement("NEKTAR");
446  ASSERTL0(master, "Unable to find NEKTAR tag in file.");
447 
448  // Partition element tag name
449  std::string strPartition = "Partition";
450 
451  // First attempt to get the first Partition element
452  TiXmlElement *fldfileIDs = master->FirstChildElement(strPartition.c_str());
453  if (!fldfileIDs)
454  {
455  // If this files try previous name
456  strPartition = "MultipleFldFiles";
457  fldfileIDs = master->FirstChildElement("MultipleFldFiles");
458  }
459  ASSERTL0(fldfileIDs, "Unable to find 'Partition' or 'MultipleFldFiles' tag "
460  "within nektar tag.");
461 
462  while (fldfileIDs)
463  {
464  // Read file name of partition file
465  const char *attr = fldfileIDs->Attribute("FileName");
466  ASSERTL0(attr, "'FileName' not provided as an attribute of '" +
467  strPartition + "' tag.");
468  fileNames.push_back(std::string(attr));
469 
470  const char *elementIDs = fldfileIDs->GetText();
471  ASSERTL0(elementIDs, "Element IDs not specified.");
472 
473  std::string elementIDsStr(elementIDs);
474 
475  std::vector<unsigned int> idvec;
476  ParseUtils::GenerateSeqVector(elementIDsStr, idvec);
477 
478  elementList.push_back(idvec);
479 
480  fldfileIDs = fldfileIDs->NextSiblingElement(strPartition.c_str());
481  }
482 }
483 
484 /**
485  * @brief Import an XML format file.
486  *
487  * @param finfilename Input filename
488  * @param fielddefs Field definitions of resulting field
489  * @param fielddata Field data of resulting field
490  * @param fieldinfomap Field metadata of resulting field
491  * @param ElementIDs If specified, contains the list of element IDs on
492  * this rank. The resulting field definitions will only
493  * contain data for the element IDs specified in this
494  * array.
495  */
496 void FieldIOXml::v_Import(const std::string &infilename,
497  std::vector<FieldDefinitionsSharedPtr> &fielddefs,
498  std::vector<std::vector<NekDouble>> &fielddata,
499  FieldMetaDataMap &fieldinfomap,
500  const Array<OneD, int> &ElementIDs)
501 {
502  std::string infile = infilename;
503 
504  fs::path pinfilename(infilename);
505 
506  // Check to see whether infile is a directory and therefore read in parallel
507  // or serial.
508  if (fs::is_directory(pinfilename))
509  {
510  fs::path infofile("Info.xml");
511  fs::path fullpath = pinfilename / infofile;
512  infile = PortablePath(fullpath);
513 
514  std::vector<std::string> filenames;
515  std::vector<std::vector<unsigned int>> elementIDs_OnPartitions;
516 
517  ImportMultiFldFileIDs(infile, filenames, elementIDs_OnPartitions,
518  fieldinfomap);
519 
520  // Load metadata
521  ImportFieldMetaData(infile, fieldinfomap);
522 
523  if (ElementIDs == NullInt1DArray) // load all elements
524  {
525  for (int i = 0; i < filenames.size(); ++i)
526  {
527  fs::path pfilename(filenames[i]);
528  fullpath = pinfilename / pfilename;
529  std::string fname = PortablePath(fullpath);
530  DataSourceSharedPtr dataSource = XmlDataSource::create(fname);
531  ImportFieldDefs(dataSource, fielddefs, false);
532  if (fielddata != NullVectorNekDoubleVector)
533  {
534  ImportFieldData(dataSource, fielddefs, fielddata);
535  }
536  }
537  }
538  else // only load relevant elements from partitions
539  {
540  int i, j;
541  std::map<int, std::vector<int>> FileIDs;
542  std::set<int> LoadFile;
543 
544  for (i = 0; i < elementIDs_OnPartitions.size(); ++i)
545  {
546  for (j = 0; j < elementIDs_OnPartitions[i].size(); ++j)
547  {
548  FileIDs[elementIDs_OnPartitions[i][j]].push_back(i);
549  }
550  }
551 
552  for (i = 0; i < ElementIDs.size(); ++i)
553  {
554  auto it = FileIDs.find(ElementIDs[i]);
555  if (it != FileIDs.end())
556  {
557  for (j = 0; j < it->second.size(); ++j)
558  {
559  LoadFile.insert(it->second[j]);
560  }
561  }
562  }
563 
564  for (auto &iter : LoadFile)
565  {
566  fs::path pfilename(filenames[iter]);
567  fullpath = pinfilename / pfilename;
568  std::string fname = PortablePath(fullpath);
569  DataSourceSharedPtr dataSource = XmlDataSource::create(fname);
570  ImportFieldDefs(dataSource, fielddefs, false);
571  if (fielddata != NullVectorNekDoubleVector)
572  {
573  ImportFieldData(dataSource, fielddefs, fielddata);
574  }
575  }
576  }
577  }
578  else
579  {
580  // serial format case
581  DataSourceSharedPtr doc = ImportFieldMetaData(infilename, fieldinfomap);
582  ImportFieldDefs(doc, fielddefs, false);
583  if (fielddata != NullVectorNekDoubleVector)
584  {
585  ImportFieldData(doc, fielddefs, fielddata);
586  }
587  }
588 }
589 
590 /**
591  * @brief Import field metadata from @p filename and return the data source
592  * which wraps @p filename.
593  *
594  * @param filename Input filename.
595  * @param fieldmetadatamap Resulting field metadata from @p dataSource.
596  */
598  const std::string &filename, FieldMetaDataMap &fieldmetadatamap)
599 {
601  XmlDataSourceSharedPtr xml = std::static_pointer_cast<XmlDataSource>(doc);
602  TiXmlElement *metadata = 0;
603  TiXmlElement *master = 0; // Master tag within which all data is
604  // contained.
605 
606  master = xml->Get().FirstChildElement("NEKTAR");
607  ASSERTL0(master, "Unable to find NEKTAR tag in file.");
608  std::string strLoop = "NEKTAR";
609 
610  // Retain original metadata structure for backwards compatibility
611  // TODO: Remove old metadata format
612  metadata = master->FirstChildElement("FIELDMETADATA");
613  if (metadata)
614  {
615  TiXmlElement *param = metadata->FirstChildElement("P");
616 
617  while (param)
618  {
619  TiXmlAttribute *paramAttr = param->FirstAttribute();
620  std::string attrName(paramAttr->Name());
621  std::string paramString;
622 
623  if (attrName == "PARAM")
624  {
625  paramString.insert(0, paramAttr->Value());
626  }
627  else
628  {
630  "PARAM not provided as an attribute in "
631  "FIELDMETADATA section");
632  }
633 
634  // Now read body of param
635  std::string paramBodyStr;
636 
637  TiXmlNode *paramBody = param->FirstChild();
638 
639  paramBodyStr += paramBody->ToText()->Value();
640 
641  fieldmetadatamap[paramString] = paramBodyStr;
642  param = param->NextSiblingElement("P");
643  }
644  }
645 
646  // New metadata format
647  metadata = master->FirstChildElement("Metadata");
648  if (metadata)
649  {
650  TiXmlElement *param = metadata->FirstChildElement();
651 
652  while (param)
653  {
654  std::string paramString = param->Value();
655  if (paramString != "Provenance")
656  {
657  // Now read body of param
658  if (param->NoChildren())
659  {
660  fieldmetadatamap[paramString] = "";
661  }
662  else
663  {
664  TiXmlNode *paramBody = param->FirstChild();
665  std::string paramBodyStr = paramBody->ToText()->Value();
666  fieldmetadatamap[paramString] = paramBodyStr;
667  }
668  }
669  param = param->NextSiblingElement();
670  }
671  }
672 
673  return doc;
674 }
675 
676 /// Returns the class name.
677 const std::string &FieldIOXml::v_GetClassName() const
678 {
679  return className;
680 }
681 
682 /**
683  * @brief Set up field meta data map.
684  *
685  * This routine sets up the necessary information for the field metadata map
686  * before calling FieldIOXml::WriteMultiFldFileIDs, which involves each process
687  * sending its element ID list to the root processor. The root processor writes
688  * the `Info.xml` file.
689  *
690  * @param outname Output directory.
691  * @param fielddefs Field definitions, needed to grab element IDs.
692  * @param fieldmetadatamap Field metadata map that is also written to the
693  * `Info.xml` file.
694  */
696  const std::string &outname,
697  const std::vector<FieldDefinitionsSharedPtr> &fielddefs,
698  const FieldMetaDataMap &fieldmetadatamap)
699 {
700  ASSERTL0(!outname.empty(), "Empty path given to SetUpFieldMetaData()");
701 
702  unsigned int nprocs = m_comm->GetSpaceComm()->GetSize();
703  unsigned int rank = m_comm->GetSpaceComm()->GetRank();
704 
705  fs::path specPath(outname);
706 
707  // Compute number of elements on this process and share with other
708  // processes. Also construct list of elements on this process from
709  // available vector of field definitions.
710  std::vector<size_t> elmtnums(nprocs, 0);
711  std::vector<unsigned int> idlist;
712  for (size_t i = 0; i < fielddefs.size(); ++i)
713  {
714  elmtnums[rank] += fielddefs[i]->m_elementIDs.size();
715  idlist.insert(idlist.end(), fielddefs[i]->m_elementIDs.begin(),
716  fielddefs[i]->m_elementIDs.end());
717  }
718  m_comm->GetSpaceComm()->AllReduce(elmtnums, LibUtilities::ReduceMax);
719 
720  // Collate per-process element lists on root process to generate
721  // the info file.
722  if (rank == 0)
723  {
724  std::vector<std::vector<unsigned int>> ElementIDs(nprocs);
725 
726  // Populate the list of element ID lists from all processes
727  ElementIDs[0] = idlist;
728  for (size_t i = 1; i < nprocs; ++i)
729  {
730  if (elmtnums[i] > 0)
731  {
732  std::vector<unsigned int> tmp(elmtnums[i]);
733  m_comm->GetSpaceComm()->Recv(i, tmp);
734  ElementIDs[i] = tmp;
735  }
736  }
737 
738  // Set up output names
739  std::vector<std::string> filenames;
740  for (unsigned int i = 0; i < nprocs; ++i)
741  {
742  boost::format pad("P%1$07d.%2$s");
743  pad % i % GetFileEnding();
744  filenames.push_back(pad.str());
745  }
746 
747  // Write the Info.xml file
748  std::string infofile =
749  LibUtilities::PortablePath(specPath / fs::path("Info.xml"));
750 
751  WriteMultiFldFileIDs(infofile, filenames, ElementIDs, fieldmetadatamap);
752  }
753  else
754  {
755  // Send this process's ID list to the root process
756  if (elmtnums[rank] > 0)
757  {
758  m_comm->GetSpaceComm()->Send(0, idlist);
759  }
760  }
761 }
762 
763 /**
764  * @brief Import field definitions from the target file.
765  *
766  * @param dataSource Target XML file
767  * @param fielddefs Output vector that will contain read field definitions.
768  * @param expChild Determines if the field definitions are defined by
769  * `<EXPANSIONS>` or in `<NEKTAR>`.
770  */
772  DataSourceSharedPtr dataSource,
773  std::vector<FieldDefinitionsSharedPtr> &fielddefs, bool expChild)
774 {
776  std::static_pointer_cast<XmlDataSource>(dataSource);
777  TiXmlElement *master =
778  NULL; // Master tag within which all data is contained.
779 
780  master = xml->Get().FirstChildElement("NEKTAR");
781  ASSERTL0(master, "Unable to find NEKTAR tag in file.");
782  std::string strLoop = "NEKTAR";
783  TiXmlElement *loopXml = master;
784 
785  TiXmlElement *expansionTypes;
786  if (expChild)
787  {
788  expansionTypes = master->FirstChildElement("EXPANSIONS");
789  ASSERTL0(expansionTypes, "Unable to find EXPANSIONS tag in file.");
790  loopXml = expansionTypes;
791  strLoop = "EXPANSIONS";
792  }
793 
794  // Loop through all nektar tags, finding all of the element tags.
795  while (loopXml)
796  {
797  TiXmlElement *element = loopXml->FirstChildElement("ELEMENTS");
798 
799  while (element)
800  {
801  // Extract the attributes.
802  std::string idString;
803  std::string shapeString;
804  std::string basisString;
805  std::string homoLengthsString;
806  std::string homoSIDsString;
807  std::string homoZIDsString;
808  std::string homoYIDsString;
809  std::string numModesString;
810  std::string numPointsString;
811  std::string fieldsString;
812  std::string pointsString;
813  bool pointDef = false;
814  bool numPointDef = false;
815  TiXmlAttribute *attr = element->FirstAttribute();
816  while (attr)
817  {
818  std::string attrName(attr->Name());
819  if (attrName == "FIELDS")
820  {
821  fieldsString.insert(0, attr->Value());
822  }
823  else if (attrName == "SHAPE")
824  {
825  shapeString.insert(0, attr->Value());
826  }
827  else if (attrName == "BASIS")
828  {
829  basisString.insert(0, attr->Value());
830  }
831  else if (attrName == "HOMOGENEOUSLENGTHS")
832  {
833  homoLengthsString.insert(0, attr->Value());
834  }
835  else if (attrName == "HOMOGENEOUSSIDS")
836  {
837  homoSIDsString.insert(0, attr->Value());
838  }
839  else if (attrName == "HOMOGENEOUSZIDS")
840  {
841  homoZIDsString.insert(0, attr->Value());
842  }
843  else if (attrName == "HOMOGENEOUSYIDS")
844  {
845  homoYIDsString.insert(0, attr->Value());
846  }
847  else if (attrName == "NUMMODESPERDIR")
848  {
849  numModesString.insert(0, attr->Value());
850  }
851  else if (attrName == "ID")
852  {
853  idString.insert(0, attr->Value());
854  }
855  else if (attrName == "POINTSTYPE")
856  {
857  pointsString.insert(0, attr->Value());
858  pointDef = true;
859  }
860  else if (attrName == "NUMPOINTSPERDIR")
861  {
862  numPointsString.insert(0, attr->Value());
863  numPointDef = true;
864  }
865  else if (attrName == "COMPRESSED")
866  {
867  WARNINGL0(boost::iequals(attr->Value(),
869  "Compressed formats do not "
870  "match. Expected: " +
872  " but got " + std::string(attr->Value()));
873  }
874  else if (attrName == "BITSIZE")
875  {
876  // This information is for future compatibility
877  // issues, for example in case we end up using a 128
878  // bit machine. Currently just do nothing.
879  }
880  else
881  {
882  std::string errstr("Unknown attribute: ");
883  errstr += attrName;
884  NEKERROR(ErrorUtil::ewarning, errstr.c_str());
885  }
886 
887  // Get the next attribute.
888  attr = attr->Next();
889  }
890 
891  // Check to see if using strips formulation
892  bool strips = false;
893  if (shapeString.find("Strips") != std::string::npos)
894  {
895  strips = true;
896  }
897 
898  // Check to see if homogeneous expansion and if so
899  // strip down the shapeString definition
900  int numHomoDir = 0;
901  size_t loc;
902  //---> This finds the first location of 'n'!
903  if ((loc = shapeString.find_first_of("-")) != std::string::npos)
904  {
905  if (shapeString.find("Exp1D") != std::string::npos)
906  {
907  numHomoDir = 1;
908  }
909  else // HomogeneousExp1D
910  {
911  numHomoDir = 2;
912  }
913 
914  shapeString.erase(loc, shapeString.length());
915  }
916 
917  // Reconstruct the fielddefs.
918  std::vector<unsigned int> elementIds;
919  {
920  bool valid =
921  ParseUtils::GenerateSeqVector(idString, elementIds);
922  ASSERTL0(valid, "Unable to correctly parse the element ids.");
923  }
924 
925  // Get the geometrical shape
926  ShapeType shape = (ShapeType)0;
927  bool valid = false;
928  for (unsigned int j = 0; j < SIZE_ShapeType; j++)
929  {
930  if (ShapeTypeMap[j] == shapeString)
931  {
932  shape = (ShapeType)j;
933  valid = true;
934  break;
935  }
936  }
937 
938  ASSERTL0(valid,
939  std::string("Unable to correctly parse the shape type: ")
940  .append(shapeString)
941  .c_str());
942 
943  // Get the basis
944  std::vector<std::string> basisStrings;
945  std::vector<BasisType> basis;
946  valid = ParseUtils::GenerateVector(basisString, basisStrings);
947  ASSERTL0(valid, "Unable to correctly parse the basis types.");
948  for (std::vector<std::string>::size_type i = 0;
949  i < basisStrings.size(); i++)
950  {
951  valid = false;
952  for (unsigned int j = 0; j < SIZE_BasisType; j++)
953  {
954  if (BasisTypeMap[j] == basisStrings[i])
955  {
956  basis.push_back((BasisType)j);
957  valid = true;
958  break;
959  }
960  }
961  ASSERTL0(
962  valid,
963  std::string("Unable to correctly parse the basis type: ")
964  .append(basisStrings[i])
965  .c_str());
966  }
967 
968  // Get homoLengths
969  std::vector<NekDouble> homoLengths;
970  if (numHomoDir)
971  {
972  valid =
973  ParseUtils::GenerateVector(homoLengthsString, homoLengths);
974  ASSERTL0(valid, "Unable to correctly parse the number of "
975  "homogeneous lengths.");
976  }
977 
978  // Get Homogeneous strips IDs
979  std::vector<unsigned int> homoSIDs;
980  if (strips)
981  {
982  valid = ParseUtils::GenerateVector(homoSIDsString, homoSIDs);
983  ASSERTL0(valid,
984  "Unable to correctly parse homogeneous strips IDs.");
985  }
986 
987  // Get Homogeneous points IDs
988  std::vector<unsigned int> homoZIDs;
989  std::vector<unsigned int> homoYIDs;
990 
991  if (numHomoDir == 1)
992  {
993  valid = ParseUtils::GenerateSeqVector(homoZIDsString, homoZIDs);
994  ASSERTL0(valid,
995  "Unable to correctly parse homogeneous planes IDs.");
996  }
997 
998  if (numHomoDir == 2)
999  {
1000  valid = ParseUtils::GenerateSeqVector(homoZIDsString, homoZIDs);
1001  ASSERTL0(valid, "Unable to correctly parse homogeneous lines "
1002  "IDs in z-direction.");
1003  valid = ParseUtils::GenerateSeqVector(homoYIDsString, homoYIDs);
1004  ASSERTL0(valid, "Unable to correctly parse homogeneous lines "
1005  "IDs in y-direction.");
1006  }
1007 
1008  // Get points type
1009  std::vector<PointsType> points;
1010 
1011  if (pointDef)
1012  {
1013  std::vector<std::string> pointsStrings;
1014  valid = ParseUtils::GenerateVector(pointsString, pointsStrings);
1015  ASSERTL0(valid, "Unable to correctly parse the points types.");
1016  for (std::vector<std::string>::size_type i = 0;
1017  i < pointsStrings.size(); i++)
1018  {
1019  valid = false;
1020  for (unsigned int j = 0; j < SIZE_PointsType; j++)
1021  {
1022  if (kPointsTypeStr[j] == pointsStrings[i])
1023  {
1024  points.push_back((PointsType)j);
1025  valid = true;
1026  break;
1027  }
1028  }
1029 
1030  ASSERTL0(valid,
1031  std::string(
1032  "Unable to correctly parse the points type: ")
1033  .append(pointsStrings[i])
1034  .c_str());
1035  }
1036  }
1037 
1038  // Get numModes
1039  std::vector<unsigned int> numModes;
1040  bool UniOrder = false;
1041 
1042  if (strstr(numModesString.c_str(), "UNIORDER:"))
1043  {
1044  UniOrder = true;
1045  }
1046 
1047  valid =
1048  ParseUtils::GenerateVector(numModesString.substr(9), numModes);
1049  ASSERTL0(valid, "Unable to correctly parse the number of modes.");
1050 
1051  // Get numPoints
1052  std::vector<unsigned int> numPoints;
1053  if (numPointDef)
1054  {
1055  valid = ParseUtils::GenerateVector(numPointsString, numPoints);
1056  ASSERTL0(valid,
1057  "Unable to correctly parse the number of points.");
1058  }
1059 
1060  // Get fields names
1061  std::vector<std::string> Fields;
1062  valid = ParseUtils::GenerateVector(fieldsString, Fields);
1063  ASSERTL0(valid, "Unable to correctly parse the number of fields.");
1064 
1065  FieldDefinitionsSharedPtr fielddef =
1067  shape, elementIds, basis, UniOrder, numModes, Fields,
1068  numHomoDir, homoLengths, strips, homoSIDs, homoZIDs,
1069  homoYIDs, points, pointDef, numPoints, numPointDef);
1070 
1071  fielddefs.push_back(fielddef);
1072 
1073  element = element->NextSiblingElement("ELEMENTS");
1074  }
1075  loopXml = loopXml->NextSiblingElement(strLoop);
1076  }
1077 }
1078 
1079 /**
1080  * @brief Import field data from a target file.
1081  *
1082  * @param dataSource Target XML file
1083  * @param fielddefs Field definitions for file
1084  * @param fielddata On return, contains field data for each field.
1085  */
1087  DataSourceSharedPtr dataSource,
1088  const std::vector<FieldDefinitionsSharedPtr> &fielddefs,
1089  std::vector<std::vector<NekDouble>> &fielddata)
1090 {
1091  int cntdumps = 0;
1093  std::static_pointer_cast<XmlDataSource>(dataSource);
1094 
1095  TiXmlElement *master =
1096  NULL; // Master tag within which all data is contained.
1097 
1098  master = xml->Get().FirstChildElement("NEKTAR");
1099  ASSERTL0(master, "Unable to find NEKTAR tag in file.");
1100 
1101  // Loop through all nektar tags, finding all of the element tags.
1102  while (master)
1103  {
1104  TiXmlElement *element = master->FirstChildElement("ELEMENTS");
1105  ASSERTL0(element, "Unable to find ELEMENTS tag within nektar tag.");
1106  while (element)
1107  {
1108  // Extract the body, which the "data".
1109  TiXmlNode *elementChild = element->FirstChild();
1110  ASSERTL0(elementChild,
1111  "Unable to extract the data from the element tag.");
1112  std::string elementStr;
1113  while (elementChild)
1114  {
1115  if (elementChild->Type() == TiXmlNode::TINYXML_TEXT)
1116  {
1117  elementStr += elementChild->ToText()->ValueStr();
1118  }
1119  elementChild = elementChild->NextSibling();
1120  }
1121 
1122  std::vector<NekDouble> elementFieldData;
1123 
1124  // Convert from base64 to binary.
1125  const char *CompressStr = element->Attribute("COMPRESSED");
1126  if (CompressStr)
1127  {
1128  WARNINGL0(boost::iequals(CompressStr,
1130  "Compressed formats do not match. "
1131  "Expected: " +
1132  CompressData::GetCompressString() + " but got " +
1133  std::string(CompressStr));
1134  }
1135 
1137  elementStr, elementFieldData),
1138  "Failed to decompress field data.");
1139  fielddata.push_back(elementFieldData);
1140 
1141  int datasize = CheckFieldDefinition(fielddefs[cntdumps]);
1142  ASSERTL0(
1143  fielddata[cntdumps].size() ==
1144  datasize * fielddefs[cntdumps]->m_fields.size(),
1145  "Input data is not the same length as header infoarmation");
1146 
1147  cntdumps++;
1148 
1149  element = element->NextSiblingElement("ELEMENTS");
1150  }
1151  master = master->NextSiblingElement("NEKTAR");
1152  }
1153 }
1154 } // namespace LibUtilities
1155 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
#define WARNINGL0(condition, msg)
Definition: ErrorUtil.hpp:222
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
Class for operating on Nektar++ input/output files.
Definition: FieldIO.h:229
int CheckFieldDefinition(const FieldDefinitionsSharedPtr &fielddefs)
Check field definitions for correctness and return storage size.
Definition: FieldIO.cpp:585
DataSourceSharedPtr ImportFieldMetaData(const std::string &filename, FieldMetaDataMap &fieldmetadatamap)
Import the metadata from a field file.
Definition: FieldIO.h:376
std::string SetUpOutput(const std::string outname, bool perRank, bool backup=false)
Set up the filesystem ready for output.
Definition: FieldIO.cpp:406
LibUtilities::CommSharedPtr m_comm
Communicator to use when writing parallel format.
Definition: FieldIO.h:278
std::string GetFileEnding() const
Helper function that determines default file extension.
Definition: FieldIO.h:275
static void AddInfoTag(TagWriterSharedPtr root, const FieldMetaDataMap &fieldmetadatamap)
Add provenance information to the field metadata map.
Definition: FieldIO.cpp:344
virtual void v_Write(const std::string &outFile, std::vector< FieldDefinitionsSharedPtr > &fielddefs, std::vector< std::vector< NekDouble >> &fielddata, const FieldMetaDataMap &fieldinfomap=NullFieldMetaDataMap, const bool backup=false) override
Write an XML file to outFile given the field definitions fielddefs, field data fielddata and metadata...
Definition: FieldIOXml.cpp:87
virtual const std::string & v_GetClassName() const override
Returns the class name.
Definition: FieldIOXml.cpp:677
void ImportFieldDefs(DataSourceSharedPtr dataSource, std::vector< FieldDefinitionsSharedPtr > &fielddefs, bool expChild)
Import field definitions from the target file.
Definition: FieldIOXml.cpp:771
void WriteMultiFldFileIDs(const std::string &outfile, const std::vector< std::string > fileNames, std::vector< std::vector< unsigned int >> &elementList, const FieldMetaDataMap &fieldinfomap=NullFieldMetaDataMap)
Write out a file containing element ID to partition mapping.
Definition: FieldIOXml.cpp:376
static FieldIOSharedPtr create(LibUtilities::CommSharedPtr pComm, bool sharedFilesystem)
Creates an instance of this class.
Definition: FieldIOXml.h:211
void ImportMultiFldFileIDs(const std::string &inFile, std::vector< std::string > &fileNames, std::vector< std::vector< unsigned int >> &elementList, FieldMetaDataMap &fieldmetadatamap)
Read file containing element ID to partition mapping.
Definition: FieldIOXml.cpp:423
void ImportFieldData(DataSourceSharedPtr dataSource, const std::vector< FieldDefinitionsSharedPtr > &fielddefs, std::vector< std::vector< NekDouble >> &fielddata)
Import field data from a target file.
virtual DataSourceSharedPtr v_ImportFieldMetaData(const std::string &filename, FieldMetaDataMap &fieldmetadatamap) override
Import field metadata from filename and return the data source which wraps filename.
Definition: FieldIOXml.cpp:597
void v_Import(const std::string &infilename, std::vector< FieldDefinitionsSharedPtr > &fielddefs, std::vector< std::vector< NekDouble >> &fielddata=NullVectorNekDoubleVector, FieldMetaDataMap &fieldinfomap=NullFieldMetaDataMap, const Array< OneD, int > &ElementIDs=NullInt1DArray) override
Import an XML format file.
Definition: FieldIOXml.cpp:496
FieldIOXml(LibUtilities::CommSharedPtr pComm, bool sharedFilesystem)
Default constructor.
Definition: FieldIOXml.cpp:62
void SetUpFieldMetaData(const std::string &outname, const std::vector< FieldDefinitionsSharedPtr > &fielddefs, const FieldMetaDataMap &fieldmetadatamap)
Set up field meta data map.
Definition: FieldIOXml.cpp:695
static std::string className
Name of class.
Definition: FieldIOXml.h:219
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
static DataSourceSharedPtr create(const std::string &fn)
Create a new XML data source based on the filename.
Definition: FieldIOXml.h:94
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
static std::string GenerateSeqString(const std::vector< T > &v)
Generate a compressed comma-separated string representation of a vector of unsigned integers.
Definition: ParseUtils.h:72
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
Definition: ParseUtils.cpp:131
static bool GenerateSeqVector(const std::string &str, std::vector< unsigned int > &out)
Takes a comma-separated compressed string and converts it to entries in a vector.
Definition: ParseUtils.cpp:105
int ZlibDecodeFromBase64Str(std::string &in64, std::vector< T > &out)
Definition: CompressData.h:220
int ZlibEncodeToBase64Str(std::vector< T > &in, std::string &out64)
Definition: CompressData.h:132
const char *const ShapeTypeMap[SIZE_ShapeType]
Definition: ShapeType.hpp:79
const char *const BasisTypeMap[]
Definition: Foundations.hpp:46
std::shared_ptr< DataSource > DataSourceSharedPtr
Definition: FieldIO.h:90
std::map< std::string, std::string > FieldMetaDataMap
Definition: FieldIO.h:52
const std::string kPointsTypeStr[]
Definition: Foundations.hpp:54
std::string PortablePath(const boost::filesystem::path &path)
create portable path on different platforms for boost::filesystem path
Definition: FileSystem.cpp:45
std::shared_ptr< XmlDataSource > XmlDataSourceSharedPtr
Definition: FieldIOXml.h:111
static std::vector< std::vector< NekDouble > > NullVectorNekDoubleVector
std::shared_ptr< FieldDefinitions > FieldDefinitionsSharedPtr
Definition: FieldIO.h:186
FieldIOFactory & GetFieldIOFactory()
Returns the FieldIO factory.
Definition: FieldIO.cpp:72
std::shared_ptr< XmlTagWriter > XmlTagWriterSharedPtr
Definition: FieldIOXml.h:169
@ SIZE_PointsType
Length of enum list.
Definition: PointsType.h:97
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:54
@ SIZE_BasisType
Length of enum list.
Definition: BasisType.h:72
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
static Array< OneD, int > NullInt1DArray