Nektar++
PtsIO.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: PtsIO.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2014 Kilian Lackhove
10 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
11 // Department of Aeronautics, Imperial College London (UK), and Scientific
12 // Computing and Imaging Institute, University of Utah (USA).
13 //
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 Pts data
33 //
34 ////////////////////////////////////////////////////////////////////////////////
35 
37 #include <boost/algorithm/string.hpp>
38 
39 #include <fstream>
40 
41 #include <boost/format.hpp>
42 
43 #ifdef NEKTAR_USE_MPI
44 #include <mpi.h>
45 #endif
46 
49 
50 using namespace std;
51 
52 namespace Nektar
53 {
54 namespace LibUtilities
55 {
56 
57 PtsIO::PtsIO(CommSharedPtr pComm, bool sharedFilesystem)
58  : FieldIOXml(pComm, sharedFilesystem)
59 {
60 }
61 
62 /**
63  * @brief Import a pts field from file
64  *
65  * @param inFile filename of the file to read
66  * @param ptsField the resulting pts field.
67  */
68 void PtsIO::Import(const string &inFile, PtsFieldSharedPtr &ptsField,
69  FieldMetaDataMap &fieldmetadatamap, DomainRangeShPtr &Range)
70 {
71  std::string infile = inFile;
72 
73  fs::path pinfilename(infile);
74 
75  // check to see that infile is a directory
76  if (fs::is_directory(pinfilename))
77  {
78  fs::path infofile("Info.xml");
79  fs::path fullpath = pinfilename / infofile;
80  infile = PortablePath(fullpath);
81 
82  std::vector<std::string> filenames;
83  std::vector<std::vector<unsigned int>> elementIDs_OnPartitions;
84 
85  ImportMultiFldFileIDs(infile, filenames, elementIDs_OnPartitions,
86  fieldmetadatamap);
87 
88  // Load metadata
89  ImportFieldMetaData(infile, fieldmetadatamap);
90 
91  if (filenames.size() == m_comm->GetSpaceComm()->GetSize())
92  {
93  // only load the file that matches this rank
94  filenames.clear();
95  boost::format pad("P%1$07d.%2$s");
96  pad % m_comm->GetSpaceComm()->GetRank() % GetFileEnding();
97  filenames.push_back(pad.str());
98  }
99 
100  for (int i = 0; i < filenames.size(); ++i)
101  {
102  fs::path pfilename(filenames[i]);
103  fullpath = pinfilename / pfilename;
104  string fname = PortablePath(fullpath);
105 
106  if (i == 0)
107  {
108  ImportFieldData(fname, ptsField, Range);
109  }
110  else
111  {
113  ImportFieldData(fname, newPtsField, Range);
115  newPtsField->GetPts(pts);
116  ptsField->AddPoints(pts);
117  }
118  }
119  }
120  else
121  {
122  ImportFieldData(infile, ptsField, Range);
123  }
124 }
125 
126 /**
127  * @brief Save a pts field to a file
128  *
129  * @param outFile filename of the file
130  * @param ptsField the pts field
131  */
132 void PtsIO::Write(const string &outFile,
134  const bool backup)
135 {
136  size_t nTotvars = ptsField->GetNFields() + ptsField->GetDim();
137  size_t np = ptsField->GetNpoints();
138 
139  std::string filename = SetUpOutput(outFile, true, backup);
140  SetUpFieldMetaData(outFile);
141 
142  // until tinyxml gains support for line break, write the xml manually
143  std::ofstream ptsFile;
144  ptsFile.open(filename.c_str());
145 
146  ptsFile << "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" << endl;
147  ptsFile << "<NEKTAR>" << endl;
148  ptsFile << " <POINTS ";
149  ptsFile << "DIM=\"" << ptsField->GetDim() << "\" ";
150  string fn = boost::algorithm::join(ptsField->GetFieldNames(), ",");
151  ptsFile << "FIELDS=\"" << fn << "\" ";
152  ptsFile << ">" << endl;
153 
155  ptsField->GetPts(pts);
156  for (size_t i = 0; i < np; ++i)
157  {
158  ptsFile << " ";
159  ptsFile << pts[0][i];
160  for (size_t j = 1; j < nTotvars; ++j)
161  {
162  ptsFile << " " << pts[j][i];
163  }
164  ptsFile << endl;
165  }
166  ptsFile << " </POINTS>" << endl;
167  ptsFile << "</NEKTAR>" << endl;
168 
169  ptsFile.close();
170 
171  // this is what the above cpart would read if tinyxml
172  // supported line breaks
173  /*
174  // Create the file (partition)
175  TiXmlDocument doc;
176  TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
177  doc.LinkEndChild(decl);
178 
179  TiXmlElement *root = new TiXmlElement("NEKTAR");
180  doc.LinkEndChild(root);
181 
182  TiXmlElement *pointsTag = new TiXmlElement("POINTS");
183  root->LinkEndChild(pointsTag);
184 
185  pointsTag->SetAttribute("DIM", ptsField->GetDim());
186 
187  string fn = boost::algorithm::join(ptsField->GetFieldNames(), ",");
188  pointsTag->SetAttribute("FIELDS", fn);
189 
190  Array <OneD, Array <OneD, NekDouble > > pts;
191  ptsField->GetPts(pts);
192  ostringstream os;
193  for (int i = 0; i < np; ++i)
194  {
195  os << pts[0][i];
196  for (int j = 1; j < nTotvars; ++j)
197  {
198  os << " " << pts[j][i];
199  }
200  os << " ";
201  }
202 
203  pointsTag->LinkEndChild(new TiXmlText(os.str()));
204 
205  doc.SaveFile(filename);
206  */
207 }
208 void PtsIO::ImportFieldData(const string inFile, PtsFieldSharedPtr &ptsField,
209  DomainRangeShPtr &Range)
210 {
211  v_ImportFieldData(inFile, ptsField, Range);
212 }
213 
214 void PtsIO::v_ImportFieldData(const string inFile, PtsFieldSharedPtr &ptsField,
215  DomainRangeShPtr &Range)
216 {
217  boost::ignore_unused(Range);
218  TiXmlDocument docInput(inFile);
219  bool loadOkay1 = docInput.LoadFile();
220 
221  std::stringstream errstr;
222  errstr << "Unable to load file: " << inFile << std::endl;
223  errstr << "Reason: " << docInput.ErrorDesc() << std::endl;
224  errstr << "Position: Line " << docInput.ErrorRow() << ", Column "
225  << docInput.ErrorCol() << std::endl;
226  ASSERTL0(loadOkay1, errstr.str());
227 
228  TiXmlElement *nektar = docInput.FirstChildElement("NEKTAR");
229  TiXmlElement *points = nektar->FirstChildElement("POINTS");
230  int dim;
231  int err = points->QueryIntAttribute("DIM", &dim);
232 
233  ASSERTL0(err == TIXML_SUCCESS, "Unable to read attribute DIM.");
234 
235  std::string fields = points->Attribute("FIELDS");
236 
237  vector<string> fieldNames;
238  if (!fields.empty())
239  {
240  bool valid = ParseUtils::GenerateVector(fields, fieldNames);
241  ASSERTL0(
242  valid,
243  "Unable to process list of field variable in FIELDS attribute: " +
244  fields);
245  }
246 
247  map<PtsInfo, int> ptsInfo = NullPtsInfoMap;
248 
249  const char *ptinfo = points->Attribute("PTSINFO");
250  if (ptinfo && boost::iequals(ptinfo, "EquiSpaced"))
251  {
252  ptsInfo[eIsEquiSpacedData] = 1;
253  }
254 
255  int np;
256  err = points->QueryIntAttribute("PTSPERELMTEDGE", &np);
257  if (err == TIXML_SUCCESS)
258  {
259  ptsInfo[ePtsPerElmtEdge] = np;
260  }
261 
262  size_t nfields = fieldNames.size();
263  size_t totvars = dim + nfields;
264 
265  TiXmlNode *pointsBody = points->FirstChild();
266 
267  std::istringstream pointsDataStrm(pointsBody->ToText()->Value());
268 
269  vector<NekDouble> ptsSerial;
271 
272  try
273  {
274  NekDouble ptsStream;
275  while (!pointsDataStrm.fail())
276  {
277  pointsDataStrm >> ptsStream;
278 
279  ptsSerial.push_back(ptsStream);
280  }
281  }
282  catch (...)
283  {
284  NEKERROR(ErrorUtil::efatal, "Unable to read Points data.");
285  }
286 
287  size_t npts = ptsSerial.size() / totvars;
288 
289  for (size_t i = 0; i < totvars; ++i)
290  {
291  pts[i] = Array<OneD, NekDouble>(npts);
292  }
293 
294  for (size_t i = 0; i < npts; ++i)
295  {
296  for (size_t j = 0; j < totvars; ++j)
297  {
298  pts[j][i] = ptsSerial[i * totvars + j];
299  }
300  }
301 
302  ptsField = MemoryManager<PtsField>::AllocateSharedPtr(dim, fieldNames, pts,
303  ptsInfo);
304 }
305 
306 void PtsIO::SetUpFieldMetaData(const string outname)
307 {
308  ASSERTL0(!outname.empty(), "Empty path given to SetUpFieldMetaData()");
309 
310  int nprocs = m_comm->GetSpaceComm()->GetSize();
311  int rank = m_comm->GetSpaceComm()->GetRank();
312 
313  fs::path specPath(outname);
314 
315  // Collate per-process element lists on root process to generate
316  // the info file.
317  if (rank == 0)
318  {
319  // Set up output names
320  std::vector<std::string> filenames;
321  std::vector<std::vector<unsigned int>> ElementIDs;
322  for (int i = 0; i < nprocs; ++i)
323  {
324  boost::format pad("P%1$07d.%2$s");
325  pad % i % GetFileEnding();
326  filenames.push_back(pad.str());
327 
328  std::vector<unsigned int> tmp;
329  tmp.push_back(0);
330  ElementIDs.push_back(tmp);
331  }
332 
333  // Write the Info.xml file
334  string infofile =
335  LibUtilities::PortablePath(specPath / fs::path("Info.xml"));
336 
337  cout << "Writing: " << specPath << endl;
338 
339  const FieldMetaDataMap fieldmetadatamap;
340  WriteMultiFldFileIDs(infofile, filenames, ElementIDs, fieldmetadatamap);
341  }
342 }
343 } // namespace LibUtilities
344 } // 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
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:278
std::string GetFileEnding() const
Helper function that determines default file extension.
Definition: FieldIO.h:275
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
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 Write(const std::string &outFile, const PtsFieldSharedPtr &ptsField, const bool backup=false)
Save a pts field to a file.
Definition: PtsIO.cpp:132
virtual void v_ImportFieldData(const std::string inFile, PtsFieldSharedPtr &ptsField, DomainRangeShPtr &Range=NullDomainRangeShPtr)
Definition: PtsIO.cpp:214
void SetUpFieldMetaData(const std::string outname)
Definition: PtsIO.cpp:306
void ImportFieldData(const std::string inFile, PtsFieldSharedPtr &ptsField, DomainRangeShPtr &Range=NullDomainRangeShPtr)
Definition: PtsIO.cpp:208
void Import(const std::string &inFile, PtsFieldSharedPtr &ptsField, FieldMetaDataMap &fieldmetadatamap=NullFieldMetaDataMap, DomainRangeShPtr &Range=NullDomainRangeShPtr)
Import a pts field from file.
Definition: PtsIO.cpp:68
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
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 std::map< PtsInfo, int > NullPtsInfoMap
Definition: PtsField.h:70
std::map< std::string, std::string > FieldMetaDataMap
Definition: FieldIO.h:52
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< PtsField > PtsFieldSharedPtr
Definition: PtsField.h:190
std::shared_ptr< DomainRange > DomainRangeShPtr
Definition: DomainRange.h:66
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:54
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble