Nektar++
FieldIOXml.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: FieldIO.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->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 /**
677  * @brief Set up field meta data map.
678  *
679  * This routine sets up the necessary information for the field metadata map
680  * before calling FieldIOXml::WriteMultiFldFileIDs, which involves each process
681  * sending its element ID list to the root processor. The root processor writes
682  * the `Info.xml` file.
683  *
684  * @param outname Output directory.
685  * @param fielddefs Field definitions, needed to grab element IDs.
686  * @param fieldmetadatamap Field metadata map that is also written to the
687  * `Info.xml` file.
688  */
690  const std::string &outname,
691  const std::vector<FieldDefinitionsSharedPtr> &fielddefs,
692  const FieldMetaDataMap &fieldmetadatamap)
693 {
694  ASSERTL0(!outname.empty(), "Empty path given to SetUpFieldMetaData()");
695 
696  unsigned int nprocs = m_comm->GetSize();
697  unsigned int rank = m_comm->GetRank();
698 
699  fs::path specPath(outname);
700 
701  // Compute number of elements on this process and share with other
702  // processes. Also construct list of elements on this process from
703  // available vector of field definitions.
704  std::vector<size_t> elmtnums(nprocs, 0);
705  std::vector<unsigned int> idlist;
706  for (size_t i = 0; i < fielddefs.size(); ++i)
707  {
708  elmtnums[rank] += fielddefs[i]->m_elementIDs.size();
709  idlist.insert(idlist.end(), fielddefs[i]->m_elementIDs.begin(),
710  fielddefs[i]->m_elementIDs.end());
711  }
712  m_comm->AllReduce(elmtnums, LibUtilities::ReduceMax);
713 
714  // Collate per-process element lists on root process to generate
715  // the info file.
716  if (rank == 0)
717  {
718  std::vector<std::vector<unsigned int>> ElementIDs(nprocs);
719 
720  // Populate the list of element ID lists from all processes
721  ElementIDs[0] = idlist;
722  for (size_t i = 1; i < nprocs; ++i)
723  {
724  if (elmtnums[i] > 0)
725  {
726  std::vector<unsigned int> tmp(elmtnums[i]);
727  m_comm->Recv(i, tmp);
728  ElementIDs[i] = tmp;
729  }
730  }
731 
732  // Set up output names
733  std::vector<std::string> filenames;
734  for (unsigned int i = 0; i < nprocs; ++i)
735  {
736  boost::format pad("P%1$07d.%2$s");
737  pad % i % GetFileEnding();
738  filenames.push_back(pad.str());
739  }
740 
741  // Write the Info.xml file
742  std::string infofile =
743  LibUtilities::PortablePath(specPath / fs::path("Info.xml"));
744 
745  WriteMultiFldFileIDs(infofile, filenames, ElementIDs, fieldmetadatamap);
746  }
747  else
748  {
749  // Send this process's ID list to the root process
750  if (elmtnums[rank] > 0)
751  {
752  m_comm->Send(0, idlist);
753  }
754  }
755 }
756 
757 /**
758  * @brief Import field definitions from the target file.
759  *
760  * @param dataSource Target XML file
761  * @param fielddefs Output vector that will contain read field definitions.
762  * @param expChild Determines if the field definitions are defined by
763  * `<EXPANSIONS>` or in `<NEKTAR>`.
764  */
766  DataSourceSharedPtr dataSource,
767  std::vector<FieldDefinitionsSharedPtr> &fielddefs, bool expChild)
768 {
770  std::static_pointer_cast<XmlDataSource>(dataSource);
771  TiXmlElement *master =
772  NULL; // Master tag within which all data is contained.
773 
774  master = xml->Get().FirstChildElement("NEKTAR");
775  ASSERTL0(master, "Unable to find NEKTAR tag in file.");
776  std::string strLoop = "NEKTAR";
777  TiXmlElement *loopXml = master;
778 
779  TiXmlElement *expansionTypes;
780  if (expChild)
781  {
782  expansionTypes = master->FirstChildElement("EXPANSIONS");
783  ASSERTL0(expansionTypes, "Unable to find EXPANSIONS tag in file.");
784  loopXml = expansionTypes;
785  strLoop = "EXPANSIONS";
786  }
787 
788  // Loop through all nektar tags, finding all of the element tags.
789  while (loopXml)
790  {
791  TiXmlElement *element = loopXml->FirstChildElement("ELEMENTS");
792 
793  while (element)
794  {
795  // Extract the attributes.
796  std::string idString;
797  std::string shapeString;
798  std::string basisString;
799  std::string homoLengthsString;
800  std::string homoSIDsString;
801  std::string homoZIDsString;
802  std::string homoYIDsString;
803  std::string numModesString;
804  std::string numPointsString;
805  std::string fieldsString;
806  std::string pointsString;
807  bool pointDef = false;
808  bool numPointDef = false;
809  TiXmlAttribute *attr = element->FirstAttribute();
810  while (attr)
811  {
812  std::string attrName(attr->Name());
813  if (attrName == "FIELDS")
814  {
815  fieldsString.insert(0, attr->Value());
816  }
817  else if (attrName == "SHAPE")
818  {
819  shapeString.insert(0, attr->Value());
820  }
821  else if (attrName == "BASIS")
822  {
823  basisString.insert(0, attr->Value());
824  }
825  else if (attrName == "HOMOGENEOUSLENGTHS")
826  {
827  homoLengthsString.insert(0, attr->Value());
828  }
829  else if (attrName == "HOMOGENEOUSSIDS")
830  {
831  homoSIDsString.insert(0, attr->Value());
832  }
833  else if (attrName == "HOMOGENEOUSZIDS")
834  {
835  homoZIDsString.insert(0, attr->Value());
836  }
837  else if (attrName == "HOMOGENEOUSYIDS")
838  {
839  homoYIDsString.insert(0, attr->Value());
840  }
841  else if (attrName == "NUMMODESPERDIR")
842  {
843  numModesString.insert(0, attr->Value());
844  }
845  else if (attrName == "ID")
846  {
847  idString.insert(0, attr->Value());
848  }
849  else if (attrName == "POINTSTYPE")
850  {
851  pointsString.insert(0, attr->Value());
852  pointDef = true;
853  }
854  else if (attrName == "NUMPOINTSPERDIR")
855  {
856  numPointsString.insert(0, attr->Value());
857  numPointDef = true;
858  }
859  else if (attrName == "COMPRESSED")
860  {
861  WARNINGL0(boost::iequals(attr->Value(),
863  "Compressed formats do not "
864  "match. Expected: " +
866  " but got " + std::string(attr->Value()));
867  }
868  else if (attrName == "BITSIZE")
869  {
870  // This information is for future compatibility
871  // issues, for example in case we end up using a 128
872  // bit machine. Currently just do nothing.
873  }
874  else
875  {
876  std::string errstr("Unknown attribute: ");
877  errstr += attrName;
878  NEKERROR(ErrorUtil::ewarning, errstr.c_str());
879  }
880 
881  // Get the next attribute.
882  attr = attr->Next();
883  }
884 
885  // Check to see if using strips formulation
886  bool strips = false;
887  if (shapeString.find("Strips") != std::string::npos)
888  {
889  strips = true;
890  }
891 
892  // Check to see if homogeneous expansion and if so
893  // strip down the shapeString definition
894  int numHomoDir = 0;
895  size_t loc;
896  //---> This finds the first location of 'n'!
897  if ((loc = shapeString.find_first_of("-")) != std::string::npos)
898  {
899  if (shapeString.find("Exp1D") != std::string::npos)
900  {
901  numHomoDir = 1;
902  }
903  else // HomogeneousExp1D
904  {
905  numHomoDir = 2;
906  }
907 
908  shapeString.erase(loc, shapeString.length());
909  }
910 
911  // Reconstruct the fielddefs.
912  std::vector<unsigned int> elementIds;
913  {
914  bool valid =
915  ParseUtils::GenerateSeqVector(idString, elementIds);
916  ASSERTL0(valid, "Unable to correctly parse the element ids.");
917  }
918 
919  // Get the geometrical shape
920  ShapeType shape = (ShapeType)0;
921  bool valid = false;
922  for (unsigned int j = 0; j < SIZE_ShapeType; j++)
923  {
924  if (ShapeTypeMap[j] == shapeString)
925  {
926  shape = (ShapeType)j;
927  valid = true;
928  break;
929  }
930  }
931 
932  ASSERTL0(valid,
933  std::string("Unable to correctly parse the shape type: ")
934  .append(shapeString)
935  .c_str());
936 
937  // Get the basis
938  std::vector<std::string> basisStrings;
939  std::vector<BasisType> basis;
940  valid = ParseUtils::GenerateVector(basisString, basisStrings);
941  ASSERTL0(valid, "Unable to correctly parse the basis types.");
942  for (std::vector<std::string>::size_type i = 0;
943  i < basisStrings.size(); i++)
944  {
945  valid = false;
946  for (unsigned int j = 0; j < SIZE_BasisType; j++)
947  {
948  if (BasisTypeMap[j] == basisStrings[i])
949  {
950  basis.push_back((BasisType)j);
951  valid = true;
952  break;
953  }
954  }
955  ASSERTL0(
956  valid,
957  std::string("Unable to correctly parse the basis type: ")
958  .append(basisStrings[i])
959  .c_str());
960  }
961 
962  // Get homoLengths
963  std::vector<NekDouble> homoLengths;
964  if (numHomoDir)
965  {
966  valid =
967  ParseUtils::GenerateVector(homoLengthsString, homoLengths);
968  ASSERTL0(valid, "Unable to correctly parse the number of "
969  "homogeneous lengths.");
970  }
971 
972  // Get Homogeneous strips IDs
973  std::vector<unsigned int> homoSIDs;
974  if (strips)
975  {
976  valid = ParseUtils::GenerateVector(homoSIDsString, homoSIDs);
977  ASSERTL0(valid,
978  "Unable to correctly parse homogeneous strips IDs.");
979  }
980 
981  // Get Homogeneous points IDs
982  std::vector<unsigned int> homoZIDs;
983  std::vector<unsigned int> homoYIDs;
984 
985  if (numHomoDir == 1)
986  {
987  valid = ParseUtils::GenerateSeqVector(homoZIDsString, homoZIDs);
988  ASSERTL0(valid,
989  "Unable to correctly parse homogeneous planes IDs.");
990  }
991 
992  if (numHomoDir == 2)
993  {
994  valid = ParseUtils::GenerateSeqVector(homoZIDsString, homoZIDs);
995  ASSERTL0(valid, "Unable to correctly parse homogeneous lines "
996  "IDs in z-direction.");
997  valid = ParseUtils::GenerateSeqVector(homoYIDsString, homoYIDs);
998  ASSERTL0(valid, "Unable to correctly parse homogeneous lines "
999  "IDs in y-direction.");
1000  }
1001 
1002  // Get points type
1003  std::vector<PointsType> points;
1004 
1005  if (pointDef)
1006  {
1007  std::vector<std::string> pointsStrings;
1008  valid = ParseUtils::GenerateVector(pointsString, pointsStrings);
1009  ASSERTL0(valid, "Unable to correctly parse the points types.");
1010  for (std::vector<std::string>::size_type i = 0;
1011  i < pointsStrings.size(); i++)
1012  {
1013  valid = false;
1014  for (unsigned int j = 0; j < SIZE_PointsType; j++)
1015  {
1016  if (kPointsTypeStr[j] == pointsStrings[i])
1017  {
1018  points.push_back((PointsType)j);
1019  valid = true;
1020  break;
1021  }
1022  }
1023 
1024  ASSERTL0(valid,
1025  std::string(
1026  "Unable to correctly parse the points type: ")
1027  .append(pointsStrings[i])
1028  .c_str());
1029  }
1030  }
1031 
1032  // Get numModes
1033  std::vector<unsigned int> numModes;
1034  bool UniOrder = false;
1035 
1036  if (strstr(numModesString.c_str(), "UNIORDER:"))
1037  {
1038  UniOrder = true;
1039  }
1040 
1041  valid =
1042  ParseUtils::GenerateVector(numModesString.substr(9), numModes);
1043  ASSERTL0(valid, "Unable to correctly parse the number of modes.");
1044 
1045  // Get numPoints
1046  std::vector<unsigned int> numPoints;
1047  if (numPointDef)
1048  {
1049  valid = ParseUtils::GenerateVector(numPointsString, numPoints);
1050  ASSERTL0(valid,
1051  "Unable to correctly parse the number of points.");
1052  }
1053 
1054  // Get fields names
1055  std::vector<std::string> Fields;
1056  valid = ParseUtils::GenerateVector(fieldsString, Fields);
1057  ASSERTL0(valid, "Unable to correctly parse the number of fields.");
1058 
1059  FieldDefinitionsSharedPtr fielddef =
1061  shape, elementIds, basis, UniOrder, numModes, Fields,
1062  numHomoDir, homoLengths, strips, homoSIDs, homoZIDs,
1063  homoYIDs, points, pointDef, numPoints, numPointDef);
1064 
1065  fielddefs.push_back(fielddef);
1066 
1067  element = element->NextSiblingElement("ELEMENTS");
1068  }
1069  loopXml = loopXml->NextSiblingElement(strLoop);
1070  }
1071 }
1072 
1073 /**
1074  * @brief Import field data from a target file.
1075  *
1076  * @param dataSource Target XML file
1077  * @param fielddefs Field definitions for file
1078  * @param fielddata On return, contains field data for each field.
1079  */
1081  DataSourceSharedPtr dataSource,
1082  const std::vector<FieldDefinitionsSharedPtr> &fielddefs,
1083  std::vector<std::vector<NekDouble>> &fielddata)
1084 {
1085  int cntdumps = 0;
1087  std::static_pointer_cast<XmlDataSource>(dataSource);
1088 
1089  TiXmlElement *master =
1090  NULL; // Master tag within which all data is contained.
1091 
1092  master = xml->Get().FirstChildElement("NEKTAR");
1093  ASSERTL0(master, "Unable to find NEKTAR tag in file.");
1094 
1095  // Loop through all nektar tags, finding all of the element tags.
1096  while (master)
1097  {
1098  TiXmlElement *element = master->FirstChildElement("ELEMENTS");
1099  ASSERTL0(element, "Unable to find ELEMENTS tag within nektar tag.");
1100  while (element)
1101  {
1102  // Extract the body, which the "data".
1103  TiXmlNode *elementChild = element->FirstChild();
1104  ASSERTL0(elementChild,
1105  "Unable to extract the data from the element tag.");
1106  std::string elementStr;
1107  while (elementChild)
1108  {
1109  if (elementChild->Type() == TiXmlNode::TINYXML_TEXT)
1110  {
1111  elementStr += elementChild->ToText()->ValueStr();
1112  }
1113  elementChild = elementChild->NextSibling();
1114  }
1115 
1116  std::vector<NekDouble> elementFieldData;
1117 
1118  // Convert from base64 to binary.
1119  const char *CompressStr = element->Attribute("COMPRESSED");
1120  if (CompressStr)
1121  {
1122  WARNINGL0(boost::iequals(CompressStr,
1124  "Compressed formats do not match. "
1125  "Expected: " +
1126  CompressData::GetCompressString() + " but got " +
1127  std::string(CompressStr));
1128  }
1129 
1131  elementStr, elementFieldData),
1132  "Failed to decompress field data.");
1133  fielddata.push_back(elementFieldData);
1134 
1135  int datasize = CheckFieldDefinition(fielddefs[cntdumps]);
1136  ASSERTL0(
1137  fielddata[cntdumps].size() ==
1138  datasize * fielddefs[cntdumps]->m_fields.size(),
1139  "Input data is not the same length as header infoarmation");
1140 
1141  cntdumps++;
1142 
1143  element = element->NextSiblingElement("ELEMENTS");
1144  }
1145  master = master->NextSiblingElement("NEKTAR");
1146  }
1147 }
1148 } // namespace LibUtilities
1149 } // 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:220
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:350
std::string SetUpOutput(const std::string outname, bool perRank, bool backup=false)
Set up the filesystem ready for output.
Definition: FieldIO.cpp:407
LibUtilities::CommSharedPtr m_comm
Communicator to use when writing parallel format.
Definition: FieldIO.h:261
static void AddInfoTag(TagWriterSharedPtr root, const FieldMetaDataMap &fieldmetadatamap)
Add provenance information to the field metadata map.
Definition: FieldIO.cpp:345
virtual std::string GetFileEnding() const
Helper function that determines default file extension.
Definition: FieldIO.h:271
virtual DataSourceSharedPtr v_ImportFieldMetaData(const std::string &filename, FieldMetaDataMap &fieldmetadatamap)
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)
Import an XML format file.
Definition: FieldIOXml.cpp:496
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)
Write an XML file to outFile given the field definitions fielddefs, field data fielddata and metadata...
Definition: FieldIOXml.cpp:87
void ImportFieldDefs(DataSourceSharedPtr dataSource, std::vector< FieldDefinitionsSharedPtr > &fielddefs, bool expChild)
Import field definitions from the target file.
Definition: FieldIOXml.cpp:765
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:209
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.
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:689
static std::string className
Name of class.
Definition: FieldIOXml.h:217
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:71
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:129
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:103
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:77
const char *const BasisTypeMap[]
Definition: Foundations.hpp:46
std::shared_ptr< DataSource > DataSourceSharedPtr
Definition: FieldIO.h:81
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:41
std::shared_ptr< XmlDataSource > XmlDataSourceSharedPtr
Definition: FieldIOXml.h:111
static std::vector< std::vector< NekDouble > > NullVectorNekDoubleVector
std::shared_ptr< FieldDefinitions > FieldDefinitionsSharedPtr
Definition: FieldIO.h:177
FieldIOFactory & GetFieldIOFactory()
Returns the FieldIO factory.
Definition: FieldIO.cpp:72
std::shared_ptr< XmlTagWriter > XmlTagWriterSharedPtr
Definition: FieldIOXml.h:167
@ 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:1
static Array< OneD, int > NullInt1DArray