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
50using namespace std;
51
52namespace Nektar
53{
54namespace LibUtilities
55{
56
57PtsIO::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 */
68void 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 */
132void 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}
208void PtsIO::ImportFieldData(const string inFile, PtsFieldSharedPtr &ptsField,
209 DomainRangeShPtr &Range)
210{
211 v_ImportFieldData(inFile, ptsField, Range);
212}
213
214void 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
306void 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:282
std::string GetFileEnding() const
Helper function that determines default file extension.
Definition: FieldIO.h:275
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 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 Write(const std::string &outFile, const PtsFieldSharedPtr &ptsField, const bool backup=false)
Save a pts field to a file.
Definition: PtsIO.cpp:132
PtsIO(LibUtilities::CommSharedPtr pComm, bool sharedFilesystem=false)
Definition: PtsIO.cpp:57
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:57
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble