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