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