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.size(); ++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  if (elmtnums[i] > 0)
734  {
735  std::vector<unsigned int> tmp(elmtnums[i]);
736  m_comm->Recv(i, tmp);
737  ElementIDs[i] = tmp;
738  }
739  }
740 
741  // Set up output names
742  std::vector<std::string> filenames;
743  for (unsigned int i = 0; i < nprocs; ++i)
744  {
745  boost::format pad("P%1$07d.%2$s");
746  pad % i % GetFileEnding();
747  filenames.push_back(pad.str());
748  }
749 
750  // Write the Info.xml file
751  std::string infofile =
752  LibUtilities::PortablePath(specPath / fs::path("Info.xml"));
753 
754  WriteMultiFldFileIDs(infofile, filenames, ElementIDs, fieldmetadatamap);
755  }
756  else
757  {
758  // Send this process's ID list to the root process
759  if (elmtnums[rank] > 0)
760  {
761  m_comm->Send(0, idlist);
762  }
763  }
764 
765 }
766 
767 /**
768  * @brief Import field definitions from the target file.
769  *
770  * @param dataSource Target XML file
771  * @param fielddefs Output vector that will contain read field definitions.
772  * @param expChild Determines if the field definitions are defined by
773  * `<EXPANSIONS>` or in `<NEKTAR>`.
774  */
776  DataSourceSharedPtr dataSource,
777  std::vector<FieldDefinitionsSharedPtr> &fielddefs,
778  bool expChild)
779 {
781  std::static_pointer_cast<XmlDataSource>(dataSource);
782  TiXmlElement *master =
783  NULL; // Master tag within which all data is contained.
784 
785  master = xml->Get().FirstChildElement("NEKTAR");
786  ASSERTL0(master, "Unable to find NEKTAR tag in file.");
787  std::string strLoop = "NEKTAR";
788  TiXmlElement *loopXml = master;
789 
790  TiXmlElement *expansionTypes;
791  if (expChild)
792  {
793  expansionTypes = master->FirstChildElement("EXPANSIONS");
794  ASSERTL0(expansionTypes, "Unable to find EXPANSIONS tag in file.");
795  loopXml = expansionTypes;
796  strLoop = "EXPANSIONS";
797  }
798 
799  // Loop through all nektar tags, finding all of the element tags.
800  while (loopXml)
801  {
802  TiXmlElement *element = loopXml->FirstChildElement("ELEMENTS");
803 
804  while (element)
805  {
806  // Extract the attributes.
807  std::string idString;
808  std::string shapeString;
809  std::string basisString;
810  std::string homoLengthsString;
811  std::string homoSIDsString;
812  std::string homoZIDsString;
813  std::string homoYIDsString;
814  std::string numModesString;
815  std::string numPointsString;
816  std::string fieldsString;
817  std::string pointsString;
818  bool pointDef = false;
819  bool numPointDef = false;
820  TiXmlAttribute *attr = element->FirstAttribute();
821  while (attr)
822  {
823  std::string attrName(attr->Name());
824  if (attrName == "FIELDS")
825  {
826  fieldsString.insert(0, attr->Value());
827  }
828  else if (attrName == "SHAPE")
829  {
830  shapeString.insert(0, attr->Value());
831  }
832  else if (attrName == "BASIS")
833  {
834  basisString.insert(0, attr->Value());
835  }
836  else if (attrName == "HOMOGENEOUSLENGTHS")
837  {
838  homoLengthsString.insert(0, attr->Value());
839  }
840  else if (attrName == "HOMOGENEOUSSIDS")
841  {
842  homoSIDsString.insert(0, attr->Value());
843  }
844  else if (attrName == "HOMOGENEOUSZIDS")
845  {
846  homoZIDsString.insert(0, attr->Value());
847  }
848  else if (attrName == "HOMOGENEOUSYIDS")
849  {
850  homoYIDsString.insert(0, attr->Value());
851  }
852  else if (attrName == "NUMMODESPERDIR")
853  {
854  numModesString.insert(0, attr->Value());
855  }
856  else if (attrName == "ID")
857  {
858  idString.insert(0, attr->Value());
859  }
860  else if (attrName == "POINTSTYPE")
861  {
862  pointsString.insert(0, attr->Value());
863  pointDef = true;
864  }
865  else if (attrName == "NUMPOINTSPERDIR")
866  {
867  numPointsString.insert(0, attr->Value());
868  numPointDef = true;
869  }
870  else if (attrName == "COMPRESSED")
871  {
872  WARNINGL0(boost::iequals(attr->Value(),
874  "Compressed formats do not "
875  "match. Expected: " +
877  " but got " + std::string(attr->Value()));
878  }
879  else if (attrName == "BITSIZE")
880  {
881  // This information is for future compatibility
882  // issues, for example in case we end up using a 128
883  // bit machine. Currently just do nothing.
884  }
885  else
886  {
887  std::string errstr("Unknown attribute: ");
888  errstr += attrName;
889  NEKERROR(ErrorUtil::ewarning, errstr.c_str());
890  }
891 
892  // Get the next attribute.
893  attr = attr->Next();
894  }
895 
896  // Check to see if using strips formulation
897  bool strips = false;
898  if (shapeString.find("Strips") != std::string::npos)
899  {
900  strips = true;
901  }
902 
903  // Check to see if homogeneous expansion and if so
904  // strip down the shapeString definition
905  int numHomoDir = 0;
906  size_t loc;
907  //---> This finds the first location of 'n'!
908  if ((loc = shapeString.find_first_of("-")) != std::string::npos)
909  {
910  if (shapeString.find("Exp1D") != std::string::npos)
911  {
912  numHomoDir = 1;
913  }
914  else // HomogeneousExp1D
915  {
916  numHomoDir = 2;
917  }
918 
919  shapeString.erase(loc, shapeString.length());
920  }
921 
922  // Reconstruct the fielddefs.
923  std::vector<unsigned int> elementIds;
924  {
925  bool valid =
926  ParseUtils::GenerateSeqVector(idString, elementIds);
927  ASSERTL0(valid, "Unable to correctly parse the element ids.");
928  }
929 
930  // Get the geometrical shape
931  ShapeType shape = (ShapeType)0;
932  bool valid = false;
933  for (unsigned int j = 0; j < SIZE_ShapeType; j++)
934  {
935  if (ShapeTypeMap[j] == shapeString)
936  {
937  shape = (ShapeType)j;
938  valid = true;
939  break;
940  }
941  }
942 
943  ASSERTL0(valid,
944  std::string("Unable to correctly parse the shape type: ")
945  .append(shapeString)
946  .c_str());
947 
948  // Get the basis
949  std::vector<std::string> basisStrings;
950  std::vector<BasisType> basis;
951  valid = ParseUtils::GenerateVector(basisString, basisStrings);
952  ASSERTL0(valid, "Unable to correctly parse the basis types.");
953  for (std::vector<std::string>::size_type i = 0;
954  i < basisStrings.size();
955  i++)
956  {
957  valid = false;
958  for (unsigned int j = 0; j < SIZE_BasisType; j++)
959  {
960  if (BasisTypeMap[j] == basisStrings[i])
961  {
962  basis.push_back((BasisType)j);
963  valid = true;
964  break;
965  }
966  }
967  ASSERTL0(
968  valid,
969  std::string("Unable to correctly parse the basis type: ")
970  .append(basisStrings[i])
971  .c_str());
972  }
973 
974  // Get homoLengths
975  std::vector<NekDouble> homoLengths;
976  if (numHomoDir)
977  {
978  valid = ParseUtils::GenerateVector(homoLengthsString,
979  homoLengths);
980  ASSERTL0(valid, "Unable to correctly parse the number of "
981  "homogeneous lengths.");
982  }
983 
984  // Get Homogeneous strips IDs
985  std::vector<unsigned int> homoSIDs;
986  if (strips)
987  {
988  valid = ParseUtils::GenerateVector(homoSIDsString, homoSIDs);
989  ASSERTL0(valid,
990  "Unable to correctly parse homogeneous strips IDs.");
991  }
992 
993  // Get Homogeneous points IDs
994  std::vector<unsigned int> homoZIDs;
995  std::vector<unsigned int> homoYIDs;
996 
997  if (numHomoDir == 1)
998  {
999  valid = ParseUtils::GenerateSeqVector(homoZIDsString,
1000  homoZIDs);
1001  ASSERTL0(valid,
1002  "Unable to correctly parse homogeneous planes IDs.");
1003  }
1004 
1005  if (numHomoDir == 2)
1006  {
1007  valid = ParseUtils::GenerateSeqVector(homoZIDsString,
1008  homoZIDs);
1009  ASSERTL0(valid, "Unable to correctly parse homogeneous lines "
1010  "IDs in z-direction.");
1011  valid = ParseUtils::GenerateSeqVector(homoYIDsString,
1012  homoYIDs);
1013  ASSERTL0(valid, "Unable to correctly parse homogeneous lines "
1014  "IDs in y-direction.");
1015  }
1016 
1017  // Get points type
1018  std::vector<PointsType> points;
1019 
1020  if (pointDef)
1021  {
1022  std::vector<std::string> pointsStrings;
1023  valid = ParseUtils::GenerateVector(pointsString, pointsStrings);
1024  ASSERTL0(valid, "Unable to correctly parse the points types.");
1025  for (std::vector<std::string>::size_type i = 0;
1026  i < pointsStrings.size();
1027  i++)
1028  {
1029  valid = false;
1030  for (unsigned int j = 0; j < SIZE_PointsType; j++)
1031  {
1032  if (kPointsTypeStr[j] == pointsStrings[i])
1033  {
1034  points.push_back((PointsType)j);
1035  valid = true;
1036  break;
1037  }
1038  }
1039 
1040  ASSERTL0(valid,
1041  std::string(
1042  "Unable to correctly parse the points type: ")
1043  .append(pointsStrings[i])
1044  .c_str());
1045  }
1046  }
1047 
1048  // Get numModes
1049  std::vector<unsigned int> numModes;
1050  bool UniOrder = false;
1051 
1052  if (strstr(numModesString.c_str(), "UNIORDER:"))
1053  {
1054  UniOrder = true;
1055  }
1056 
1058  numModesString.substr(9), numModes);
1059  ASSERTL0(valid, "Unable to correctly parse the number of modes.");
1060 
1061  // Get numPoints
1062  std::vector<unsigned int> numPoints;
1063  if (numPointDef)
1064  {
1065  valid = ParseUtils::GenerateVector(numPointsString, numPoints);
1066  ASSERTL0(valid,
1067  "Unable to correctly parse the number of points.");
1068  }
1069 
1070  // Get fields names
1071  std::vector<std::string> Fields;
1072  valid = ParseUtils::GenerateVector(fieldsString, Fields);
1073  ASSERTL0(valid, "Unable to correctly parse the number of fields.");
1074 
1075  FieldDefinitionsSharedPtr fielddef =
1077  elementIds,
1078  basis,
1079  UniOrder,
1080  numModes,
1081  Fields,
1082  numHomoDir,
1083  homoLengths,
1084  strips,
1085  homoSIDs,
1086  homoZIDs,
1087  homoYIDs,
1088  points,
1089  pointDef,
1090  numPoints,
1091  numPointDef);
1092 
1093  fielddefs.push_back(fielddef);
1094 
1095  element = element->NextSiblingElement("ELEMENTS");
1096  }
1097  loopXml = loopXml->NextSiblingElement(strLoop);
1098  }
1099 }
1100 
1101 /**
1102  * @brief Import field data from a target file.
1103  *
1104  * @param dataSource Target XML file
1105  * @param fielddefs Field definitions for file
1106  * @param fielddata On return, contains field data for each field.
1107  */
1109  DataSourceSharedPtr dataSource,
1110  const std::vector<FieldDefinitionsSharedPtr> &fielddefs,
1111  std::vector<std::vector<NekDouble> > &fielddata)
1112 {
1113  int cntdumps = 0;
1115  std::static_pointer_cast<XmlDataSource>(dataSource);
1116 
1117  TiXmlElement *master =
1118  NULL; // Master tag within which all data is contained.
1119 
1120  master = xml->Get().FirstChildElement("NEKTAR");
1121  ASSERTL0(master, "Unable to find NEKTAR tag in file.");
1122 
1123  // Loop through all nektar tags, finding all of the element tags.
1124  while (master)
1125  {
1126  TiXmlElement *element = master->FirstChildElement("ELEMENTS");
1127  ASSERTL0(element, "Unable to find ELEMENTS tag within nektar tag.");
1128  while (element)
1129  {
1130  // Extract the body, which the "data".
1131  TiXmlNode *elementChild = element->FirstChild();
1132  ASSERTL0(elementChild,
1133  "Unable to extract the data from the element tag.");
1134  std::string elementStr;
1135  while (elementChild)
1136  {
1137  if (elementChild->Type() == TiXmlNode::TINYXML_TEXT)
1138  {
1139  elementStr += elementChild->ToText()->ValueStr();
1140  }
1141  elementChild = elementChild->NextSibling();
1142  }
1143 
1144  std::vector<NekDouble> elementFieldData;
1145 
1146  // Convert from base64 to binary.
1147  const char *CompressStr = element->Attribute("COMPRESSED");
1148  if (CompressStr)
1149  {
1150  WARNINGL0(boost::iequals(CompressStr,
1152  "Compressed formats do not match. "
1153  "Expected: " +
1155  " but got " + std::string(CompressStr));
1156  }
1157 
1159  elementStr, elementFieldData),
1160  "Failed to decompress field data.");
1161  fielddata.push_back(elementFieldData);
1162 
1163  int datasize = CheckFieldDefinition(fielddefs[cntdumps]);
1164  ASSERTL0(
1165  fielddata[cntdumps].size() ==
1166  datasize * fielddefs[cntdumps]->m_fields.size(),
1167  "Input data is not the same length as header infoarmation");
1168 
1169  cntdumps++;
1170 
1171  element = element->NextSiblingElement("ELEMENTS");
1172  }
1173  master = master->NextSiblingElement("NEKTAR");
1174  }
1175 }
1176 }
1177 }
#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 mode...
Definition: ErrorUtil.hpp:209
#define WARNINGL0(condition, msg)
Definition: ErrorUtil.hpp:223
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:250
Class for operating on Nektar++ input/output files.
Definition: FieldIO.h:223
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:355
std::string SetUpOutput(const std::string outname, bool perRank, bool backup=false)
Set up the filesystem ready for output.
Definition: FieldIO.cpp:410
LibUtilities::CommSharedPtr m_comm
Communicator to use when writing parallel format.
Definition: FieldIO.h:266
static void AddInfoTag(TagWriterSharedPtr root, const FieldMetaDataMap &fieldmetadatamap)
Add provenance information to the field metadata map.
Definition: FieldIO.cpp:348
virtual std::string GetFileEnding() const
Helper function that determines default file extension.
Definition: FieldIO.h:276
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
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
void ImportFieldData(DataSourceSharedPtr dataSource, const std::vector< FieldDefinitionsSharedPtr > &fielddefs, std::vector< std::vector< NekDouble > > &fielddata)
Import field data from a target file.
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:775
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 FieldIOSharedPtr create(LibUtilities::CommSharedPtr pComm, bool sharedFilesystem)
Creates an instance of this class.
Definition: FieldIOXml.h:205
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
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:697
static std::string className
Name of class.
Definition: FieldIOXml.h:213
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:200
static DataSourceSharedPtr create(const std::string &fn)
Create a new XML data source based on the filename.
Definition: FieldIOXml.h:92
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:135
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
int ZlibDecodeFromBase64Str(std::string &in64, std::vector< T > &out)
Definition: CompressData.h:231
int ZlibEncodeToBase64Str(std::vector< T > &in, std::string &out64)
Definition: CompressData.h:138
const char *const BasisTypeMap[]
Definition: Foundations.hpp:46
std::shared_ptr< DataSource > DataSourceSharedPtr
Definition: FieldIO.h:79
std::map< std::string, std::string > FieldMetaDataMap
Definition: FieldIO.h:52
const std::string kPointsTypeStr[]
Definition: Foundations.hpp:70
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:109
static std::vector< std::vector< NekDouble > > NullVectorNekDoubleVector
std::shared_ptr< FieldDefinitions > FieldDefinitionsSharedPtr
Definition: FieldIO.h:179
FieldIOFactory & GetFieldIOFactory()
Returns the FieldIO factory.
Definition: FieldIO.cpp:72
std::shared_ptr< XmlTagWriter > XmlTagWriterSharedPtr
Definition: FieldIOXml.h:163
@ SIZE_PointsType
Length of enum list.
Definition: PointsType.h:81
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:54
const char *const ShapeTypeMap[]
Definition: ShapeType.hpp:67
@ SIZE_BasisType
Length of enum list.
Definition: BasisType.h:62
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
static Array< OneD, int > NullInt1DArray