Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
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 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: I/O routines relating to Fields into XML
33 //
34 ////////////////////////////////////////////////////////////////////////////////
35 
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->GetRank() == 0)
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->GetRank() == 0)
362  {
363  tm1 = m_comm->Wtime();
364  cout << " (" << tm1 - tm0 << "s, XML)" << 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  string IDstring = ParseUtils::GenerateSeqString(elementList[t]);
408 
409  elemIDs->LinkEndChild(new TiXmlText(IDstring));
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  TiXmlDocument doc(inFile);
435  bool loadOkay = doc.LoadFile();
436 
437  std::stringstream errstr;
438  errstr << "Unable to load file: " << inFile << std::endl;
439  errstr << "Reason: " << doc.ErrorDesc() << std::endl;
440  errstr << "Position: Line " << doc.ErrorRow() << ", Column "
441  << doc.ErrorCol() << std::endl;
442  ASSERTL0(loadOkay, errstr.str());
443 
444  // Handle on XML document
445  TiXmlHandle docHandle(&doc);
446 
447  // Retrieve main NEKTAR tag - XML specification states one
448  // top-level element tag per file.
449  TiXmlElement *master = doc.FirstChildElement("NEKTAR");
450  ASSERTL0(master, "Unable to find NEKTAR tag in file.");
451 
452  // Partition element tag name
453  std::string strPartition = "Partition";
454 
455  // First attempt to get the first Partition element
456  TiXmlElement *fldfileIDs = master->FirstChildElement(strPartition.c_str());
457  if (!fldfileIDs)
458  {
459  // If this files try previous name
460  strPartition = "MultipleFldFiles";
461  fldfileIDs = master->FirstChildElement("MultipleFldFiles");
462  }
463  ASSERTL0(fldfileIDs,
464  "Unable to find 'Partition' or 'MultipleFldFiles' tag "
465  "within nektar tag.");
466 
467  while (fldfileIDs)
468  {
469  // Read file name of partition file
470  const char *attr = fldfileIDs->Attribute("FileName");
471  ASSERTL0(attr,
472  "'FileName' not provided as an attribute of '" + strPartition +
473  "' tag.");
474  fileNames.push_back(std::string(attr));
475 
476  const char *elementIDs = fldfileIDs->GetText();
477  ASSERTL0(elementIDs, "Element IDs not specified.");
478 
479  std::string elementIDsStr(elementIDs);
480 
481  std::vector<unsigned int> idvec;
482  ParseUtils::GenerateSeqVector(elementIDsStr.c_str(), idvec);
483 
484  elementList.push_back(idvec);
485 
486  fldfileIDs = fldfileIDs->NextSiblingElement(strPartition.c_str());
487  }
488 }
489 
490 /**
491  * @brief Import an XML format file.
492  *
493  * @param finfilename Input filename
494  * @param fielddefs Field definitions of resulting field
495  * @param fielddata Field data of resulting field
496  * @param fieldinfomap Field metadata of resulting field
497  * @param ElementIDs If specified, contains the list of element IDs on
498  * this rank. The resulting field definitions will only
499  * contain data for the element IDs specified in this
500  * array.
501  */
502 void FieldIOXml::v_Import(const std::string &infilename,
503  std::vector<FieldDefinitionsSharedPtr> &fielddefs,
504  std::vector<std::vector<NekDouble> > &fielddata,
505  FieldMetaDataMap &fieldinfomap,
506  const Array<OneD, int> &ElementIDs)
507 {
508  std::string infile = infilename;
509 
510  fs::path pinfilename(infilename);
511 
512  // Check to see whether infile is a directory and therefore read in parallel
513  // or serial.
514  if (fs::is_directory(pinfilename))
515  {
516  fs::path infofile("Info.xml");
517  fs::path fullpath = pinfilename / infofile;
518  infile = PortablePath(fullpath);
519 
520  std::vector<std::string> filenames;
521  std::vector<std::vector<unsigned int> > elementIDs_OnPartitions;
522 
524  infile, filenames, elementIDs_OnPartitions, fieldinfomap);
525 
526  // Load metadata
527  ImportFieldMetaData(infile, fieldinfomap);
528 
529  if (ElementIDs == NullInt1DArray) // load all elements
530  {
531  for (int i = 0; i < filenames.size(); ++i)
532  {
533  fs::path pfilename(filenames[i]);
534  fullpath = pinfilename / pfilename;
535  string fname = PortablePath(fullpath);
536  DataSourceSharedPtr dataSource = XmlDataSource::create(fname);
537  ImportFieldDefs(dataSource, fielddefs, false);
538  if (fielddata != NullVectorNekDoubleVector)
539  {
540  ImportFieldData(dataSource, fielddefs, fielddata);
541  }
542  }
543  }
544  else // only load relevant elements from partitions
545  {
546  int i, j;
547  map<int, vector<int> > FileIDs;
548  map<int, vector<int> >::iterator it;
549  set<int> LoadFile;
550 
551  for (i = 0; i < elementIDs_OnPartitions.size(); ++i)
552  {
553  for (j = 0; j < elementIDs_OnPartitions[i].size(); ++j)
554  {
555  FileIDs[elementIDs_OnPartitions[i][j]].push_back(i);
556  }
557  }
558 
559  for (i = 0; i < ElementIDs.num_elements(); ++i)
560  {
561  it = FileIDs.find(ElementIDs[i]);
562  if (it != FileIDs.end())
563  {
564  for (j = 0; j < it->second.size(); ++j)
565  {
566  LoadFile.insert(it->second[j]);
567  }
568  }
569  }
570 
571  set<int>::iterator iter;
572  for (iter = LoadFile.begin(); iter != LoadFile.end(); ++iter)
573  {
574  fs::path pfilename(filenames[*iter]);
575  fullpath = pinfilename / pfilename;
576  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 = boost::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  {
637  ASSERTL0(false, "PARAM not provided as an attribute in "
638  "FIELDMETADATA section");
639  }
640 
641  // Now read body of param
642  std::string paramBodyStr;
643 
644  TiXmlNode *paramBody = param->FirstChild();
645 
646  paramBodyStr += paramBody->ToText()->Value();
647 
648  fieldmetadatamap[paramString] = paramBodyStr;
649  param = param->NextSiblingElement("P");
650  }
651  }
652 
653  // New metadata format
654  metadata = master->FirstChildElement("Metadata");
655  if (metadata)
656  {
657  TiXmlElement *param = metadata->FirstChildElement();
658 
659  while (param)
660  {
661  std::string paramString = param->Value();
662  if (paramString != "Provenance")
663  {
664  // Now read body of param
665  TiXmlNode *paramBody = param->FirstChild();
666  std::string paramBodyStr = paramBody->ToText()->Value();
667 
668  fieldmetadatamap[paramString] = paramBodyStr;
669  }
670  param = param->NextSiblingElement();
671  }
672  }
673 
674  return doc;
675 }
676 
677 /**
678  * @brief Set up field meta data map.
679  *
680  * This routine sets up the necessary information for the field metadata map
681  * before calling FieldIOXml::WriteMultiFldFileIDs, which involves each process
682  * sending its element ID list to the root processor. The root processor writes
683  * the `Info.xml` file.
684  *
685  * @param outname Output directory.
686  * @param fielddefs Field definitions, needed to grab element IDs.
687  * @param fieldmetadatamap Field metadata map that is also written to the
688  * `Info.xml` file.
689  */
691  const std::string &outname,
692  const vector<FieldDefinitionsSharedPtr> &fielddefs,
693  const FieldMetaDataMap &fieldmetadatamap)
694 {
695  ASSERTL0(!outname.empty(), "Empty path given to SetUpFieldMetaData()");
696 
697  int nprocs = m_comm->GetSize();
698  int rank = m_comm->GetRank();
699 
700  fs::path specPath(outname);
701 
702  // Compute number of elements on this process and share with other
703  // processes. Also construct list of elements on this process from
704  // available vector of field definitions.
705  std::vector<unsigned int> elmtnums(nprocs, 0);
706  std::vector<unsigned int> idlist;
707  int i;
708  for (i = 0; i < fielddefs.size(); ++i)
709  {
710  elmtnums[rank] += fielddefs[i]->m_elementIDs.size();
711  idlist.insert(idlist.end(),
712  fielddefs[i]->m_elementIDs.begin(),
713  fielddefs[i]->m_elementIDs.end());
714  }
715  m_comm->AllReduce(elmtnums, LibUtilities::ReduceMax);
716 
717  // Collate per-process element lists on root process to generate
718  // the info file.
719  if (rank == 0)
720  {
721  std::vector<std::vector<unsigned int> > ElementIDs(nprocs);
722 
723  // Populate the list of element ID lists from all processes
724  ElementIDs[0] = idlist;
725  for (i = 1; i < nprocs; ++i)
726  {
727  std::vector<unsigned int> tmp(elmtnums[i]);
728  m_comm->Recv(i, tmp);
729  ElementIDs[i] = tmp;
730  }
731 
732  // Set up output names
733  std::vector<std::string> filenames;
734  for (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  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  m_comm->Send(0, idlist);
751  }
752 }
753 
754 /**
755  * @brief Import field definitions from the target file.
756  *
757  * @param dataSource Target XML file
758  * @param fielddefs Output vector that will contain read field definitions.
759  * @param expChild Determines if the field definitions are defined by
760  * `<EXPANSIONS>` or in `<NEKTAR>`.
761  */
763  DataSourceSharedPtr dataSource,
764  std::vector<FieldDefinitionsSharedPtr> &fielddefs,
765  bool expChild)
766 {
768  boost::static_pointer_cast<XmlDataSource>(dataSource);
769  TiXmlElement *master =
770  NULL; // Master tag within which all data is contained.
771 
772  master = xml->Get().FirstChildElement("NEKTAR");
773  ASSERTL0(master, "Unable to find NEKTAR tag in file.");
774  std::string strLoop = "NEKTAR";
775  TiXmlElement *loopXml = master;
776 
777  TiXmlElement *expansionTypes;
778  if (expChild)
779  {
780  expansionTypes = master->FirstChildElement("EXPANSIONS");
781  ASSERTL0(expansionTypes, "Unable to find EXPANSIONS tag in file.");
782  loopXml = expansionTypes;
783  strLoop = "EXPANSIONS";
784  }
785 
786  // Loop through all nektar tags, finding all of the element tags.
787  while (loopXml)
788  {
789  TiXmlElement *element = loopXml->FirstChildElement("ELEMENTS");
790  ASSERTL0(element, "Unable to find ELEMENTS tag within nektar tag.");
791 
792  while (element)
793  {
794  // Extract the attributes.
795  std::string idString;
796  std::string shapeString;
797  std::string basisString;
798  std::string homoLengthsString;
799  std::string homoSIDsString;
800  std::string homoZIDsString;
801  std::string homoYIDsString;
802  std::string numModesString;
803  std::string numPointsString;
804  std::string fieldsString;
805  std::string pointsString;
806  bool pointDef = false;
807  bool numPointDef = false;
808  TiXmlAttribute *attr = element->FirstAttribute();
809  while (attr)
810  {
811  std::string attrName(attr->Name());
812  if (attrName == "FIELDS")
813  {
814  fieldsString.insert(0, attr->Value());
815  }
816  else if (attrName == "SHAPE")
817  {
818  shapeString.insert(0, attr->Value());
819  }
820  else if (attrName == "BASIS")
821  {
822  basisString.insert(0, attr->Value());
823  }
824  else if (attrName == "HOMOGENEOUSLENGTHS")
825  {
826  homoLengthsString.insert(0, attr->Value());
827  }
828  else if (attrName == "HOMOGENEOUSSIDS")
829  {
830  homoSIDsString.insert(0, attr->Value());
831  }
832  else if (attrName == "HOMOGENEOUSZIDS")
833  {
834  homoZIDsString.insert(0, attr->Value());
835  }
836  else if (attrName == "HOMOGENEOUSYIDS")
837  {
838  homoYIDsString.insert(0, attr->Value());
839  }
840  else if (attrName == "NUMMODESPERDIR")
841  {
842  numModesString.insert(0, attr->Value());
843  }
844  else if (attrName == "ID")
845  {
846  idString.insert(0, attr->Value());
847  }
848  else if (attrName == "POINTSTYPE")
849  {
850  pointsString.insert(0, attr->Value());
851  pointDef = true;
852  }
853  else if (attrName == "NUMPOINTSPERDIR")
854  {
855  numPointsString.insert(0, attr->Value());
856  numPointDef = true;
857  }
858  else if (attrName == "COMPRESSED")
859  {
860  WARNINGL0(boost::iequals(attr->Value(),
862  "Compressed formats do not "
863  "match. Expected: " +
865  " but got " + string(attr->Value()));
866  }
867  else if (attrName == "BITSIZE")
868  {
869  // This information is for future compatibility
870  // issues, for example in case we end up using a 128
871  // bit machine. Currently just do nothing.
872  }
873  else
874  {
875  std::string errstr("Unknown attribute: ");
876  errstr += attrName;
877  ASSERTL1(false, errstr.c_str());
878  }
879 
880  // Get the next attribute.
881  attr = attr->Next();
882  }
883 
884  // Check to see if using strips formulation
885  bool strips = false;
886  if (shapeString.find("Strips") != string::npos)
887  {
888  strips = true;
889  }
890 
891  // Check to see if homogeneous expansion and if so
892  // strip down the shapeString definition
893  int numHomoDir = 0;
894  size_t loc;
895  //---> This finds the first location of 'n'!
896  if ((loc = shapeString.find_first_of("-")) != string::npos)
897  {
898  if (shapeString.find("Exp1D") != string::npos)
899  {
900  numHomoDir = 1;
901  }
902  else // HomogeneousExp1D
903  {
904  numHomoDir = 2;
905  }
906 
907  shapeString.erase(loc, shapeString.length());
908  }
909 
910  // Reconstruct the fielddefs.
911  std::vector<unsigned int> elementIds;
912  {
913  bool valid =
914  ParseUtils::GenerateSeqVector(idString.c_str(), elementIds);
915  ASSERTL0(valid, "Unable to correctly parse the element ids.");
916  }
917 
918  // Get the geometrical shape
919  ShapeType shape;
920  bool valid = false;
921  for (unsigned int j = 0; j < SIZE_ShapeType; j++)
922  {
923  if (ShapeTypeMap[j] == shapeString)
924  {
925  shape = (ShapeType)j;
926  valid = true;
927  break;
928  }
929  }
930 
931  ASSERTL0(valid,
932  std::string("Unable to correctly parse the shape type: ")
933  .append(shapeString)
934  .c_str());
935 
936  // Get the basis
937  std::vector<std::string> basisStrings;
938  std::vector<BasisType> basis;
939  valid = ParseUtils::GenerateOrderedStringVector(basisString.c_str(),
940  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();
944  i++)
945  {
946  valid = false;
947  for (unsigned int j = 0; j < SIZE_BasisType; j++)
948  {
949  if (BasisTypeMap[j] == basisStrings[i])
950  {
951  basis.push_back((BasisType)j);
952  valid = true;
953  break;
954  }
955  }
956  ASSERTL0(
957  valid,
958  std::string("Unable to correctly parse the basis type: ")
959  .append(basisStrings[i])
960  .c_str());
961  }
962 
963  // Get homoLengths
964  std::vector<NekDouble> homoLengths;
965  if (numHomoDir)
966  {
968  homoLengthsString.c_str(), homoLengths);
969  ASSERTL0(valid, "Unable to correctly parse the number of "
970  "homogeneous lengths.");
971  }
972 
973  // Get Homogeneous strips IDs
974  std::vector<unsigned int> homoSIDs;
975  if (strips)
976  {
977  valid = ParseUtils::GenerateSeqVector(homoSIDsString.c_str(),
978  homoSIDs);
979  ASSERTL0(valid,
980  "Unable to correctly parse homogeneous strips IDs.");
981  }
982 
983  // Get Homogeneous points IDs
984  std::vector<unsigned int> homoZIDs;
985  std::vector<unsigned int> homoYIDs;
986 
987  if (numHomoDir == 1)
988  {
989  valid = ParseUtils::GenerateSeqVector(homoZIDsString.c_str(),
990  homoZIDs);
991  ASSERTL0(valid,
992  "Unable to correctly parse homogeneous planes IDs.");
993  }
994 
995  if (numHomoDir == 2)
996  {
997  valid = ParseUtils::GenerateSeqVector(homoZIDsString.c_str(),
998  homoZIDs);
999  ASSERTL0(valid, "Unable to correctly parse homogeneous lines "
1000  "IDs in z-direction.");
1001  valid = ParseUtils::GenerateSeqVector(homoYIDsString.c_str(),
1002  homoYIDs);
1003  ASSERTL0(valid, "Unable to correctly parse homogeneous lines "
1004  "IDs in y-direction.");
1005  }
1006 
1007  // Get points type
1008  std::vector<PointsType> points;
1009 
1010  if (pointDef)
1011  {
1012  std::vector<std::string> pointsStrings;
1014  pointsString.c_str(), pointsStrings);
1015  ASSERTL0(valid, "Unable to correctly parse the points types.");
1016  for (std::vector<std::string>::size_type i = 0;
1017  i < pointsStrings.size();
1018  i++)
1019  {
1020  valid = false;
1021  for (unsigned int j = 0; j < SIZE_PointsType; j++)
1022  {
1023  if (kPointsTypeStr[j] == pointsStrings[i])
1024  {
1025  points.push_back((PointsType)j);
1026  valid = true;
1027  break;
1028  }
1029  }
1030 
1031  ASSERTL0(valid,
1032  std::string(
1033  "Unable to correctly parse the points type: ")
1034  .append(pointsStrings[i])
1035  .c_str());
1036  }
1037  }
1038 
1039  // Get numModes
1040  std::vector<unsigned int> numModes;
1041  bool UniOrder = false;
1042 
1043  if (strstr(numModesString.c_str(), "UNIORDER:"))
1044  {
1045  UniOrder = true;
1046  }
1047 
1049  numModesString.c_str() + 9, numModes);
1050  ASSERTL0(valid, "Unable to correctly parse the number of modes.");
1051 
1052  // Get numPoints
1053  std::vector<unsigned int> numPoints;
1054  if (numPointDef)
1055  {
1057  numPointsString.c_str(), numPoints);
1058  ASSERTL0(valid,
1059  "Unable to correctly parse the number of points.");
1060  }
1061 
1062  // Get fields names
1063  std::vector<std::string> Fields;
1065  fieldsString.c_str(), 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  boost::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 " + 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:198
static bool GenerateOrderedStringVector(const char *const str, std::vector< std::string > &vec)
Definition: ParseUtils.hpp:143
static bool GenerateOrderedVector(const char *const str, std::vector< unsigned int > &vec)
Definition: ParseUtils.hpp:97
static boost::shared_ptr< DataType > AllocateSharedPtr()
Allocate a shared pointer from the memory pool.
const char *const BasisTypeMap[]
Definition: Foundations.hpp:47
const std::string kPointsTypeStr[]
Definition: Foundations.hpp:69
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
boost::shared_ptr< XmlTagWriter > XmlTagWriterSharedPtr
Definition: FieldIOXml.h:139
boost::shared_ptr< FieldDefinitions > FieldDefinitionsSharedPtr
Definition: FieldIO.h:181
TiXmlDocument & Get()
Return the TinyXML document of this source.
Definition: FieldIOXml.h:79
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 GenerateSeqString(const std::vector< unsigned int > &elmtids)
Definition: ParseUtils.hpp:159
static std::string className
Name of class.
Definition: FieldIOXml.h:189
FieldIOFactory & GetFieldIOFactory()
Returns the FieldIO factory.
Definition: FieldIO.cpp:74
static bool GenerateSeqVector(const char *const str, std::vector< unsigned int > &vec)
Definition: ParseUtils.hpp:79
std::map< std::string, std::string > FieldMetaDataMap
Definition: FieldIO.h:54
int CheckFieldDefinition(const FieldDefinitionsSharedPtr &fielddefs)
Check field definitions for correctness and return storage size.
Definition: FieldIO.cpp:561
const char *const ShapeTypeMap[]
Definition: ShapeType.hpp:66
boost::shared_ptr< DataSource > DataSourceSharedPtr
Definition: FieldIO.h:81
boost::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:55
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:502
static DataSourceSharedPtr create(const std::string &fn)
Create a new XML data source based on the filename.
Definition: FieldIOXml.h:91
#define WARNINGL0(condition, msg)
Definition: ErrorUtil.hpp:204
static std::vector< std::vector< NekDouble > > NullVectorNekDoubleVector
static FieldIOSharedPtr create(LibUtilities::CommSharedPtr pComm, bool sharedFilesystem)
Creates an instance of this class.
Definition: FieldIOXml.h:181
DataSourceSharedPtr ImportFieldMetaData(const std::string &filename, FieldMetaDataMap &fieldmetadatamap)
Import the metadata from a field file.
Definition: FieldIO.h:358
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
std::string SetUpOutput(const std::string outname, bool perRank, bool backup=false)
Set up the filesystem ready for output.
Definition: FieldIO.cpp:400
LibUtilities::CommSharedPtr m_comm
Communicator to use when writing parallel format.
Definition: FieldIO.h:265
int ZlibEncodeToBase64Str(std::vector< T > &in, std::string &out64)
Definition: CompressData.h:151
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs typedef NekMatrix< LhsDataType, StandardMatrixTag >::iterator iterator
boost::shared_ptr< XmlDataSource > XmlDataSourceSharedPtr
Definition: FieldIOXml.h:108
Class for operating on Nektar++ input/output files.
Definition: FieldIO.h:224
virtual std::string GetFileEnding() const
Helper function that determines default file extension.
Definition: FieldIO.h:279
void SetUpFieldMetaData(const std::string &outname, const std::vector< FieldDefinitionsSharedPtr > &fielddefs, const FieldMetaDataMap &fieldmetadatamap)
Set up field meta data map.
Definition: FieldIOXml.cpp:690
void ImportFieldDefs(DataSourceSharedPtr dataSource, std::vector< FieldDefinitionsSharedPtr > &fielddefs, bool expChild)
Import field definitions from the target file.
Definition: FieldIOXml.cpp:762
static Array< OneD, int > NullInt1DArray
static bool GenerateUnOrderedVector(const char *const str, std::vector< NekDouble > &vec)
Definition: ParseUtils.hpp:128
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:228
void AddInfoTag(TagWriterSharedPtr root, const FieldMetaDataMap &fieldmetadatamap)
Add provenance information to the field metadata map.
Definition: FieldIO.cpp:334
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:243
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, tDescription pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:215