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