Nektar++
Loading...
Searching...
No Matches
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"
42#include <boost/format.hpp>
43#include <iomanip>
44
45namespace Nektar::FieldUtils
46{
47
49{
50 m_requireEquiSpaced = false;
51 m_prohibitWrite = false;
52 m_config["writemultiplefiles"] = ConfigOption(
53 true, "0",
54 "Write multiple files in parallel or when using nparts option");
55}
56
60
61void OutputFileBase::v_Process(po::variables_map &vm)
62{
63 string filename = m_config["outfile"].as<string>();
64
65 if (filename == "")
66 {
67 m_prohibitWrite = true;
68 }
69
70 if (m_f->m_fieldPts != LibUtilities::NullPtsField)
71 {
72 m_f->SetUpExp(vm);
73
74 ASSERTL0(!m_f->m_writeBndFld, "Boundary can't be obtained from pts.");
75 if (WriteFile(filename, vm))
76 {
78
79 if (vm.count("error"))
80 {
82 }
83 }
84 }
85 else
86 {
87 // reset expansion definition to use equispaced points if required.
88 if (m_requireEquiSpaced && (vm.count("no-equispaced") == 0) &&
89 m_f->m_graph->GetNumElements() != 0 && !m_equispacedSetup)
90 {
91 if (m_f->m_exp.size())
92 {
94 }
95 else
96 {
97 m_f->SetUpExp(vm, true);
98 m_equispacedSetup = true;
99 }
100 }
101 else
102 {
103 m_f->SetUpExp(vm);
104 }
105 if (!m_f->m_exp.size())
106 {
107 if (m_f->m_data.size())
108 {
109 ASSERTL0(!m_f->m_writeBndFld,
110 "Boundary extraction requires xml file.");
111 if (WriteFile(filename, vm))
112 {
114 }
115 }
116 return;
117 }
118 if (m_f->m_writeBndFld)
119 {
120 if (m_f->m_verbose &&
121 m_f->m_comm->GetSpaceComm()->TreatAsRankZero())
122 {
123 cout << "\t" << GetModuleName()
124 << ": Writing boundary file(s): ";
125 for (int i = 0; i < m_f->m_bndRegionsToWrite.size(); ++i)
126 {
127 cout << m_f->m_bndRegionsToWrite[i];
128 if (i < m_f->m_bndRegionsToWrite.size() - 1)
129 {
130 cout << ", ";
131 }
132 }
133 cout << endl;
134 }
135
136 int nfields = m_f->m_variables.size();
137 int normdim = m_f->m_graph->GetMeshDimension();
138
139 // Prepare for normals output
140 if (m_f->m_addNormals)
141 {
142 // Prepare for creating expansions for normals
143 m_f->m_exp.resize(nfields + normdim);
144
145 // Include normal name in m_variables
146 string normstr[3] = {"Norm_x", "Norm_y", "Norm_z"};
147 for (int j = 0; j < normdim; ++j)
148 {
149 m_f->m_exp[nfields + j] =
150 m_f->AppendExpList(m_f->m_numHomogeneousDir);
151 m_f->m_variables.push_back(normstr[j]);
152 }
153 }
154
155 // Move m_exp to a new expansion vector
156 vector<MultiRegions::ExpListSharedPtr> exp(m_f->m_exp.size());
157 exp.swap(m_f->m_exp);
158
160 BndExp(exp.size());
161 for (int i = 0; i < exp.size(); ++i)
162 {
163 BndExp[i] = exp[i]->GetBndCondExpansions();
164 }
165
166 // get hold of partition boundary regions so we can match it to
167 // desired region extraction
169 exp[0]->GetGraph());
171 bcs.GetBoundaryRegions();
172 map<int, int> BndRegionMap;
173 map<int, LibUtilities::CommSharedPtr> BndRegionComm;
174
175 // when using extract we may not have defined all boundary regions
176 // so identify that here
177 std::set<int> ProcessBnd;
178 if (m_f->m_session->DefinesTag("CreateBndRegions"))
179 {
180 // evaluate bnd regions to be generated
181 vector<unsigned int> bndRegions;
182 ASSERTL0(
184 m_f->m_session->GetTag("CreateBndRegions"), bndRegions),
185 "Failed to interpret bnd values string");
186
187 for (auto &bnd : bndRegions)
188 {
189 if (bregions.count(bnd) == 1)
190 {
191 ProcessBnd.insert(bnd);
192 }
193 }
194 }
195 else
196 {
197 for (auto &it : bregions)
198 {
199 ProcessBnd.insert(it.first);
200 }
201 }
202
203 int cnt = 0;
204 for (auto &breg_it : bregions)
205 {
206 if (ProcessBnd.count(breg_it.first))
207 {
208 BndRegionMap[breg_it.first] = cnt++;
209 BndRegionComm[breg_it.first] =
210 bcs.GetBoundaryCommunicators()[breg_it.first];
211 }
212 }
213
214 // find ending of output file and insert _b1, _b2
215 int dot = filename.find_last_of('.') + 1;
216 string ext = filename.substr(dot, filename.length() - dot);
217 string name = filename.substr(0, dot - 1);
218
219 // Store temporary communicator
220 LibUtilities::CommSharedPtr tmpComm = m_f->m_comm;
221
222 for (int i = 0; i < m_f->m_bndRegionsToWrite.size(); ++i)
223 {
224 string outname = name + "_b" +
225 std::to_string(m_f->m_bndRegionsToWrite[i]) +
226 "." + ext;
227
228 if (!WriteFile(outname, vm))
229 {
230 continue;
231 }
232 RegisterConfig("outfile", outname);
233
234 if (BndRegionMap.count(m_f->m_bndRegionsToWrite[i]) == 1)
235 {
236 m_f->m_comm = BndRegionComm[m_f->m_bndRegionsToWrite[i]];
237
238 int Border = BndRegionMap[m_f->m_bndRegionsToWrite[i]];
239
240 // set up m_exp to point to boundary expansion
241 for (int j = 0; j < exp.size(); ++j)
242 {
243 m_f->m_exp[j] = BndExp[j][Border];
244 }
245
246 for (int j = 0; j < exp.size(); ++j)
247 {
248 m_f->m_exp[j] = BndExp[j][Border];
249 m_f->m_exp[j]->BwdTrans(m_f->m_exp[j]->GetCoeffs(),
250 m_f->m_exp[j]->UpdatePhys());
251 }
252
253 if (m_f->m_addNormals)
254 {
255 // Get normals
257 exp[0]->GetBoundaryNormals(Border, NormPhys);
258
259 // add normal coefficients to expansions
260 for (int j = 0; j < normdim; ++j)
261 {
262 m_f->m_exp[nfields + j] =
263 BndExp[nfields + j][Border];
265 m_f->m_exp[nfields + j]->GetTotPoints(),
266 NormPhys[j], 1,
267 m_f->m_exp[nfields + j]->UpdatePhys(), 1);
268 m_f->m_exp[nfields + j]->FwdTransLocalElmt(
269 m_f->m_exp[nfields + j]->GetPhys(),
270 m_f->m_exp[nfields + j]->UpdateCoeffs());
271 }
272 }
273 v_OutputFromExp(vm);
274 // output error for regression checking.
275 if (vm.count("error"))
276 {
278 }
279
280 // Reset communicator
281 m_f->m_comm = tmpComm;
282 }
283
284 // put outfile back to filename in case of nparts option
285 RegisterConfig("outfile", filename);
286 }
287 // Restore m_exp
288 exp.swap(m_f->m_exp);
289 }
290 else
291 {
292 if (WriteFile(filename, vm))
293 {
294 v_OutputFromExp(vm);
295 // output error for regression checking.
296 if (vm.count("error"))
297 {
299 }
300 }
301 }
302 }
303}
304
305bool OutputFileBase::WriteFile(std::string &filename, po::variables_map &vm)
306{
307 if (m_prohibitWrite)
308 {
309 return true;
310 }
311
312 // Get path to file. If procid was defined, get the full name to avoid
313 // checking files from other partitions
314 fs::path outFile;
315 if (vm.count("nparts"))
316 {
317 outFile = GetFullOutName(filename, vm);
318 }
319 else
320 {
321 outFile = GetPath(filename, vm);
322 }
323
325 if (m_f->m_comm)
326 {
327 comm = m_f->m_comm;
328 }
329 else
330 {
331 comm = LibUtilities::GetCommFactory().CreateInstance("Serial", 0, 0);
332 }
333
334 int count = fs::exists(outFile) ? 1 : 0;
335 comm->GetSpaceComm()->AllReduce(count, LibUtilities::ReduceSum);
336
337 int writeFile = 1;
338 if (count && (vm.count("force-output") == 0))
339 {
340 if (vm.count("nparts") == 0) // do not do check if --nparts is enabled.
341 {
342 writeFile = 0; // set to zero for reduce all to be correct.
343
344 if (comm->GetSpaceComm()->TreatAsRankZero())
345 {
346 string answer;
347 cout << "Did you wish to overwrite " << outFile << " (y/n)? ";
348 getline(cin, answer);
349 if (answer.compare("y") == 0)
350 {
351 writeFile = 1;
352 }
353 else
354 {
355 cout << "Not writing file '" << filename
356 << "' because it already exists" << endl;
357 }
358 }
359 comm->GetSpaceComm()->AllReduce(writeFile, LibUtilities::ReduceSum);
360 }
361 }
362 return (writeFile == 0) ? false : true;
363}
364
365void OutputFileBase::ConvertExpToEquispaced(po::variables_map &vm)
366{
367 // Information to create new expansion
368 int numFields = m_f->m_exp.size();
369 m_f->m_fielddef = m_f->m_exp[0]->GetFieldDefinitions();
370
371 // Set points to equispaced
372 int nPointsNew = 0;
373 if (vm.count("output-points"))
374 {
375 nPointsNew = vm["output-points"].as<int>();
376 }
377 m_f->m_graph->SetExpansionInfoToEvenlySpacedPoints(nPointsNew);
378
379 // Save original expansion
380 vector<MultiRegions::ExpListSharedPtr> expOld = m_f->m_exp;
381
382 // Create new expansion
383 m_f->m_exp[0] = m_f->SetUpFirstExpList(m_f->m_numHomogeneousDir, true);
384 for (int i = 1; i < numFields; ++i)
385 {
386 m_f->m_exp[i] = m_f->AppendExpList(m_f->m_numHomogeneousDir);
387 }
388
389 // Extract result to new expansion
390 for (int i = 0; i < numFields; ++i)
391 {
392 m_f->m_exp[i]->ExtractCoeffsToCoeffs(expOld[i], expOld[i]->GetCoeffs(),
393 m_f->m_exp[i]->UpdateCoeffs());
394 m_f->m_exp[i]->BwdTrans(m_f->m_exp[i]->GetCoeffs(),
395 m_f->m_exp[i]->UpdatePhys());
396 }
397
398 // Extract boundary expansion if needed
399 if (m_f->m_writeBndFld)
400 {
403
404 for (int i = 0; i < numFields; ++i)
405 {
406 BndExpOld = expOld[i]->GetBndCondExpansions();
407 for (int j = 0; j < BndExpOld.size(); ++j)
408 {
409 BndExp = m_f->m_exp[i]->UpdateBndCondExpansion(j);
410 BndExp->ExtractCoeffsToCoeffs(BndExpOld[j],
411 BndExpOld[j]->GetCoeffs(),
412 BndExp->UpdateCoeffs());
413 }
414 }
415 }
416
417 m_f->m_fielddef = std::vector<LibUtilities::FieldDefinitionsSharedPtr>();
418
419 // Make a note so that we know that the fielddefs have now been setup.
420 m_equispacedSetup = true;
421}
422
424{
425 int coordim = m_f->m_fieldPts->GetDim();
426 std::string coordVars[] = {"x", "y", "z"};
427
428 vector<string> variables = m_f->m_variables;
429 variables.insert(variables.begin(), coordVars, coordVars + coordim);
430 // Get fields and coordinates
431 Array<OneD, Array<OneD, NekDouble>> fields(variables.size());
432
433 // We can just grab everything from points. This should be a
434 // reference, not a copy.
435 m_f->m_fieldPts->GetPts(fields);
436 for (int i = 0; i < fields.size(); ++i)
437 {
438 // calculate L2 and Linf value
439 int npts = fields[i].size();
440
441 NekDouble l2err = 0.0;
442 NekDouble linferr = 0.0;
443 for (int j = 0; j < npts; ++j)
444 {
445 l2err += fields[i][j] * fields[i][j];
446 linferr = max(linferr, fabs(fields[i][j]));
447 }
448
449 m_f->m_comm->GetSpaceComm()->AllReduce(l2err, LibUtilities::ReduceSum);
450 m_f->m_comm->GetSpaceComm()->AllReduce(npts, LibUtilities::ReduceSum);
451 m_f->m_comm->GetSpaceComm()->AllReduce(linferr,
453
454 l2err /= npts;
455 l2err = sqrt(l2err);
456
457 if (m_f->m_comm->GetSpaceComm()->TreatAsRankZero())
458 {
459 cout << "L 2 error (variable " << variables[i] << ") : " << l2err
460 << endl;
461
462 cout << "L inf error (variable " << variables[i]
463 << ") : " << linferr << endl;
464 }
465 }
466}
467
469{
470 int coordim =
471 m_f->m_exp[0]->GetExp(0)->GetCoordim() + m_f->m_numHomogeneousDir;
472 int totpoints = m_f->m_exp[0]->GetTotPoints();
473 std::string coordVars[] = {"x", "y", "z"};
474
475 // Set up storage for coordinates
476 Array<OneD, Array<OneD, NekDouble>> coords(coordim);
477 for (int i = 0; i < coordim; ++i)
478 {
479 coords[i] = Array<OneD, NekDouble>(totpoints);
480 }
481
482 // Get coordinates
483 if (coordim == 1)
484 {
485 m_f->m_exp[0]->GetCoords(coords[0]);
486 }
487 else if (coordim == 2)
488 {
489 m_f->m_exp[0]->GetCoords(coords[0], coords[1]);
490 }
491 else
492 {
493 m_f->m_exp[0]->GetCoords(coords[0], coords[1], coords[2]);
494 }
495
496 for (int j = 0; j < coordim; ++j)
497 {
498 NekDouble l2err = m_f->m_exp[0]->L2(coords[j]);
499 NekDouble linferr = m_f->m_exp[0]->Linf(coords[j]);
500
501 if (m_f->m_comm->GetSpaceComm()->TreatAsRankZero())
502 {
503 cout << "L 2 error (variable " << coordVars[j] << ") : " << l2err
504 << endl;
505
506 cout << "L inf error (variable " << coordVars[j]
507 << ") : " << linferr << endl;
508 }
509 }
510
511 for (int j = 0; j < m_f->m_exp.size(); ++j)
512 {
513 NekDouble l2err = m_f->m_exp[j]->L2(m_f->m_exp[j]->GetPhys());
514 NekDouble linferr = m_f->m_exp[j]->Linf(m_f->m_exp[j]->GetPhys());
515
516 if (m_f->m_comm->GetSpaceComm()->TreatAsRankZero() &&
517 m_f->m_variables.size() > 0)
518 {
519 cout << "L 2 error (variable " << m_f->m_variables[j]
520 << ") : " << l2err << endl;
521
522 cout << "L inf error (variable " << m_f->m_variables[j]
523 << ") : " << linferr << endl;
524 }
525 }
526}
527
528} // namespace Nektar::FieldUtils
#define ASSERTL0(condition, msg)
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.
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
std::map< int, LibUtilities::CommSharedPtr > GetBoundaryCommunicators() const
Definition Conditions.h:299
const BoundaryRegionCollection & GetBoundaryRegions(void) const
Definition Conditions.h:273
std::shared_ptr< Field > FieldSharedPtr
Definition Field.hpp:1030
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:249
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition Vmath.hpp:825
STL namespace.
scalarT< T > max(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:305
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290
Represents a command-line configuration option.
Definition Module.h:129