Nektar++
OutputFileBase.cpp
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////////////
2//
3// File: OutputFileBase.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: Base class for outputting to a file
32//
33////////////////////////////////////////////////////////////////////////////////
34
35#include <set>
36#include <string>
37using namespace std;
38
39#include "OutputFileBase.h"
41#include <boost/format.hpp>
42#include <iomanip>
43
44namespace Nektar::FieldUtils
45{
46
48{
49 m_requireEquiSpaced = false;
50 m_config["writemultiplefiles"] = ConfigOption(
51 true, "0",
52 "Write multiple files in parallel or when using nparts option");
53}
54
56{
57}
58
59void OutputFileBase::v_Process(po::variables_map &vm)
60{
61 m_f->SetUpExp(vm);
62
63 string filename = m_config["outfile"].as<string>();
64
65 if (m_f->m_fieldPts != LibUtilities::NullPtsField)
66 {
67 ASSERTL0(!m_f->m_writeBndFld, "Boundary can't be obtained from pts.");
68 if (WriteFile(filename, vm))
69 {
71
72 if (vm.count("error"))
73 {
75 }
76 }
77 }
78 else if (m_f->m_exp.size())
79 {
80 // reset expansion definition to use equispaced points if required.
81 if (m_requireEquiSpaced && (vm.count("no-equispaced") == 0) &&
82 m_f->m_exp[0]->GetNumElmts() != 0)
83 {
85 }
86 if (m_f->m_writeBndFld)
87 {
88 if (m_f->m_verbose &&
89 m_f->m_comm->GetSpaceComm()->TreatAsRankZero())
90 {
91 cout << "\t" << GetModuleName()
92 << ": Writing boundary file(s): ";
93 for (int i = 0; i < m_f->m_bndRegionsToWrite.size(); ++i)
94 {
95 cout << m_f->m_bndRegionsToWrite[i];
96 if (i < m_f->m_bndRegionsToWrite.size() - 1)
97 {
98 cout << ", ";
99 }
100 }
101 cout << endl;
102 }
103
104 int nfields = m_f->m_variables.size();
105 int normdim = m_f->m_graph->GetMeshDimension();
106
107 // Prepare for normals output
108 if (m_f->m_addNormals)
109 {
110 // Prepare for creating expansions for normals
111 m_f->m_exp.resize(nfields + normdim);
112
113 // Include normal name in m_variables
114 string normstr[3] = {"Norm_x", "Norm_y", "Norm_z"};
115 for (int j = 0; j < normdim; ++j)
116 {
117 m_f->m_exp[nfields + j] =
118 m_f->AppendExpList(m_f->m_numHomogeneousDir);
119 m_f->m_variables.push_back(normstr[j]);
120 }
121 }
122
123 // Move m_exp to a new expansion vector
124 vector<MultiRegions::ExpListSharedPtr> exp(m_f->m_exp.size());
125 exp.swap(m_f->m_exp);
126
128 BndExp(exp.size());
129 for (int i = 0; i < exp.size(); ++i)
130 {
131 BndExp[i] = exp[i]->GetBndCondExpansions();
132 }
133
134 // get hold of partition boundary regions so we can match it to
135 // desired region extraction
137 exp[0]->GetGraph());
139 bcs.GetBoundaryRegions();
140 map<int, int> BndRegionMap;
141 map<int, LibUtilities::CommSharedPtr> BndRegionComm;
142 int cnt = 0;
143 for (auto &breg_it : bregions)
144 {
145 BndRegionMap[breg_it.first] = cnt++;
146 BndRegionComm[breg_it.first] =
147 bcs.GetBoundaryCommunicators()[breg_it.first];
148 }
149
150 // find ending of output file and insert _b1, _b2
151 int dot = filename.find_last_of('.') + 1;
152 string ext = filename.substr(dot, filename.length() - dot);
153 string name = filename.substr(0, dot - 1);
154
155 // Store temporary communicator
156 LibUtilities::CommSharedPtr tmpComm = m_f->m_comm;
157
158 for (int i = 0; i < m_f->m_bndRegionsToWrite.size(); ++i)
159 {
160 string outname =
161 name + "_b" +
162 boost::lexical_cast<string>(m_f->m_bndRegionsToWrite[i]) +
163 "." + ext;
164
165 if (!WriteFile(outname, vm))
166 {
167 continue;
168 }
169 RegisterConfig("outfile", outname);
170
171 if (BndRegionMap.count(m_f->m_bndRegionsToWrite[i]) == 1)
172 {
173 m_f->m_comm = BndRegionComm[m_f->m_bndRegionsToWrite[i]];
174
175 int Border = BndRegionMap[m_f->m_bndRegionsToWrite[i]];
176
177 // set up m_exp to point to boundary expansion
178 for (int j = 0; j < exp.size(); ++j)
179 {
180 m_f->m_exp[j] = BndExp[j][Border];
181 }
182
183 for (int j = 0; j < exp.size(); ++j)
184 {
185 m_f->m_exp[j] = BndExp[j][Border];
186 m_f->m_exp[j]->BwdTrans(m_f->m_exp[j]->GetCoeffs(),
187 m_f->m_exp[j]->UpdatePhys());
188 }
189
190 if (m_f->m_addNormals)
191 {
192 // Get normals
194 exp[0]->GetBoundaryNormals(Border, NormPhys);
195
196 // add normal coefficients to expansions
197 for (int j = 0; j < normdim; ++j)
198 {
199 m_f->m_exp[nfields + j] =
200 BndExp[nfields + j][Border];
202 m_f->m_exp[nfields + j]->GetTotPoints(),
203 NormPhys[j], 1,
204 m_f->m_exp[nfields + j]->UpdatePhys(), 1);
205 m_f->m_exp[nfields + j]->FwdTransLocalElmt(
206 m_f->m_exp[nfields + j]->GetPhys(),
207 m_f->m_exp[nfields + j]->UpdateCoeffs());
208 }
209 }
210 v_OutputFromExp(vm);
211 // output error for regression checking.
212 if (vm.count("error"))
213 {
215 }
216
217 // Reset communicator
218 m_f->m_comm = tmpComm;
219 }
220
221 // put outfile back to filename in case of nparts option
222 RegisterConfig("outfile", filename);
223 }
224 // Restore m_exp
225 exp.swap(m_f->m_exp);
226 }
227 else
228 {
229 if (WriteFile(filename, vm))
230 {
231 v_OutputFromExp(vm);
232 // output error for regression checking.
233 if (vm.count("error"))
234 {
236 }
237 }
238 }
239 }
240 else if (m_f->m_data.size())
241 {
242 ASSERTL0(!m_f->m_writeBndFld, "Boundary extraction requires xml file.");
243 if (WriteFile(filename, vm))
244 {
246 }
247 }
248}
249
250bool OutputFileBase::WriteFile(std::string &filename, po::variables_map &vm)
251{
252 // Get path to file. If procid was defined, get the full name
253 // to avoid checking files from other partitions
254 fs::path outFile;
255 if (vm.count("nparts"))
256 {
257 outFile = GetFullOutName(filename, vm);
258 }
259 else
260 {
261 outFile = GetPath(filename, vm);
262 }
263
265 if (m_f->m_comm)
266 {
267 comm = m_f->m_comm;
268 }
269 else
270 {
271 comm = LibUtilities::GetCommFactory().CreateInstance("Serial", 0, 0);
272 }
273
274 int count = fs::exists(outFile) ? 1 : 0;
275 comm->GetSpaceComm()->AllReduce(count, LibUtilities::ReduceSum);
276
277 int writeFile = 1;
278 if (count && (vm.count("force-output") == 0))
279 {
280 if (vm.count("nparts") == 0) // do not do check if --nparts is enabled.
281 {
282 writeFile = 0; // set to zero for reduce all to be correct.
283
284 if (comm->GetSpaceComm()->TreatAsRankZero())
285 {
286 string answer;
287 cout << "Did you wish to overwrite " << outFile << " (y/n)? ";
288 getline(cin, answer);
289 if (answer.compare("y") == 0)
290 {
291 writeFile = 1;
292 }
293 else
294 {
295 cout << "Not writing file '" << filename
296 << "' because it already exists" << endl;
297 }
298 }
299 comm->GetSpaceComm()->AllReduce(writeFile, LibUtilities::ReduceSum);
300 }
301 }
302 return (writeFile == 0) ? false : true;
303}
304
305void OutputFileBase::ConvertExpToEquispaced(po::variables_map &vm)
306{
307 // Information to create new expansion
308 int numFields = m_f->m_exp.size();
309 m_f->m_fielddef = m_f->m_exp[0]->GetFieldDefinitions();
310
311 // Set points to equispaced
312 int nPointsNew = 0;
313 if (vm.count("output-points"))
314 {
315 nPointsNew = vm["output-points"].as<int>();
316 }
317 m_f->m_graph->SetExpansionInfoToEvenlySpacedPoints(nPointsNew);
318
319 // Save original expansion
320 vector<MultiRegions::ExpListSharedPtr> expOld = m_f->m_exp;
321
322 // Create new expansion
323 m_f->m_exp[0] = m_f->SetUpFirstExpList(m_f->m_numHomogeneousDir, true);
324 for (int i = 1; i < numFields; ++i)
325 {
326 m_f->m_exp[i] = m_f->AppendExpList(m_f->m_numHomogeneousDir);
327 }
328
329 // Extract result to new expansion
330 for (int i = 0; i < numFields; ++i)
331 {
332 m_f->m_exp[i]->ExtractCoeffsToCoeffs(expOld[i], expOld[i]->GetCoeffs(),
333 m_f->m_exp[i]->UpdateCoeffs());
334 m_f->m_exp[i]->BwdTrans(m_f->m_exp[i]->GetCoeffs(),
335 m_f->m_exp[i]->UpdatePhys());
336 }
337 // Extract boundary expansion if needed
338 if (m_f->m_writeBndFld)
339 {
342
343 for (int i = 0; i < numFields; ++i)
344 {
345 BndExpOld = expOld[i]->GetBndCondExpansions();
346 for (int j = 0; j < BndExpOld.size(); ++j)
347 {
348 BndExp = m_f->m_exp[i]->UpdateBndCondExpansion(j);
349 BndExp->ExtractCoeffsToCoeffs(BndExpOld[j],
350 BndExpOld[j]->GetCoeffs(),
351 BndExp->UpdateCoeffs());
352 }
353 }
354 }
355 m_f->m_fielddef = std::vector<LibUtilities::FieldDefinitionsSharedPtr>();
356}
357
359{
360 int coordim = m_f->m_fieldPts->GetDim();
361 std::string coordVars[] = {"x", "y", "z"};
362
363 vector<string> variables = m_f->m_variables;
364 variables.insert(variables.begin(), coordVars, coordVars + coordim);
365 // Get fields and coordinates
366 Array<OneD, Array<OneD, NekDouble>> fields(variables.size());
367
368 // We can just grab everything from points. This should be a
369 // reference, not a copy.
370 m_f->m_fieldPts->GetPts(fields);
371 for (int i = 0; i < fields.size(); ++i)
372 {
373 // calculate L2 and Linf value
374 int npts = fields[i].size();
375
376 NekDouble l2err = 0.0;
377 NekDouble linferr = 0.0;
378 for (int j = 0; j < npts; ++j)
379 {
380 l2err += fields[i][j] * fields[i][j];
381 linferr = max(linferr, fabs(fields[i][j]));
382 }
383
384 m_f->m_comm->GetSpaceComm()->AllReduce(l2err, LibUtilities::ReduceSum);
385 m_f->m_comm->GetSpaceComm()->AllReduce(npts, LibUtilities::ReduceSum);
386 m_f->m_comm->GetSpaceComm()->AllReduce(linferr,
388
389 l2err /= npts;
390 l2err = sqrt(l2err);
391
392 if (m_f->m_comm->GetSpaceComm()->TreatAsRankZero())
393 {
394 cout << "L 2 error (variable " << variables[i] << ") : " << l2err
395 << endl;
396
397 cout << "L inf error (variable " << variables[i]
398 << ") : " << linferr << endl;
399 }
400 }
401}
402
404{
405 int coordim =
406 m_f->m_exp[0]->GetExp(0)->GetCoordim() + m_f->m_numHomogeneousDir;
407 int totpoints = m_f->m_exp[0]->GetTotPoints();
408 std::string coordVars[] = {"x", "y", "z"};
409
410 // Set up storage for coordinates
411 Array<OneD, Array<OneD, NekDouble>> coords(coordim);
412 for (int i = 0; i < coordim; ++i)
413 {
414 coords[i] = Array<OneD, NekDouble>(totpoints);
415 }
416
417 // Get coordinates
418 if (coordim == 1)
419 {
420 m_f->m_exp[0]->GetCoords(coords[0]);
421 }
422 else if (coordim == 2)
423 {
424 m_f->m_exp[0]->GetCoords(coords[0], coords[1]);
425 }
426 else
427 {
428 m_f->m_exp[0]->GetCoords(coords[0], coords[1], coords[2]);
429 }
430
431 for (int j = 0; j < coordim; ++j)
432 {
433 NekDouble l2err = m_f->m_exp[0]->L2(coords[j]);
434 NekDouble linferr = m_f->m_exp[0]->Linf(coords[j]);
435
436 if (m_f->m_comm->GetSpaceComm()->TreatAsRankZero())
437 {
438 cout << "L 2 error (variable " << coordVars[j] << ") : " << l2err
439 << endl;
440
441 cout << "L inf error (variable " << coordVars[j]
442 << ") : " << linferr << endl;
443 }
444 }
445
446 for (int j = 0; j < m_f->m_exp.size(); ++j)
447 {
448 NekDouble l2err = m_f->m_exp[j]->L2(m_f->m_exp[j]->GetPhys());
449 NekDouble linferr = m_f->m_exp[j]->Linf(m_f->m_exp[j]->GetPhys());
450
451 if (m_f->m_comm->GetSpaceComm()->TreatAsRankZero() &&
452 m_f->m_variables.size() > 0)
453 {
454 cout << "L 2 error (variable " << m_f->m_variables[j]
455 << ") : " << l2err << endl;
456
457 cout << "L inf error (variable " << m_f->m_variables[j]
458 << ") : " << linferr << endl;
459 }
460 }
461}
462
463} // namespace Nektar::FieldUtils
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
FIELD_UTILS_EXPORT void RegisterConfig(std::string key, std::string value="")
Register a configuration option with a module.
Definition: Module.cpp:100
std::string GetModuleName()
Definition: Module.h:200
FieldSharedPtr m_f
Field object.
Definition: Module.h:239
std::map< std::string, ConfigOption > m_config
List of configuration values.
Definition: Module.h:272
virtual void v_OutputFromExp(po::variables_map &vm)=0
Write from m_exp to output file.
bool WriteFile(std::string &filename, po::variables_map &vm)
fs::path GetFullOutName(std::string &filename, po::variables_map &vm)
void ConvertExpToEquispaced(po::variables_map &vm)
virtual void v_OutputFromData(po::variables_map &vm)=0
Write from data to output file.
virtual void v_OutputFromPts(po::variables_map &vm)=0
Write from pts to output file.
fs::path GetPath(std::string &filename, po::variables_map &vm)
void v_Process(po::variables_map &vm) override
Write fld to output file.
Abstract base class for output modules.
Definition: Module.h:316
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:143
std::map< int, LibUtilities::CommSharedPtr > GetBoundaryCommunicators() const
Definition: Conditions.h:260
const BoundaryRegionCollection & GetBoundaryRegions(void) const
Definition: Conditions.h:234
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:990
static PtsFieldSharedPtr NullPtsField
Definition: PtsField.h:185
CommFactory & GetCommFactory()
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:55
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
std::map< int, BoundaryRegionShPtr > BoundaryRegionCollection
Definition: Conditions.h:210
double NekDouble
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.hpp:825
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294
Represents a command-line configuration option.
Definition: Module.h:129