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>
37 using namespace std;
38 
39 #include "OutputFileBase.h"
41 #include <boost/format.hpp>
42 #include <iomanip>
43 
44 namespace Nektar
45 {
46 namespace FieldUtils
47 {
48 
49 OutputFileBase::OutputFileBase(FieldSharedPtr f) : OutputModule(f)
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 
61 void OutputFileBase::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  {
72  OutputFromPts(vm);
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 && m_f->m_comm->TreatAsRankZero())
91  {
92  cout << "\t" << GetModuleName()
93  << ": Writing boundary file(s): ";
94  for (int i = 0; i < m_f->m_bndRegionsToWrite.size(); ++i)
95  {
96  cout << m_f->m_bndRegionsToWrite[i];
97  if (i < m_f->m_bndRegionsToWrite.size() - 1)
98  {
99  cout << ", ";
100  }
101  }
102  cout << endl;
103  }
104 
105  int nfields = m_f->m_variables.size();
106  int normdim = m_f->m_graph->GetMeshDimension();
107 
108  // Prepare for normals output
109  if (m_f->m_addNormals)
110  {
111  // Prepare for creating expansions for normals
112  m_f->m_exp.resize(nfields + normdim);
113  ;
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  for (int j = 0; j < exp.size(); ++j)
180  {
181  m_f->m_exp[j] = BndExp[j][Border];
182  m_f->m_exp[j]->BwdTrans(m_f->m_exp[j]->GetCoeffs(),
183  m_f->m_exp[j]->UpdatePhys());
184  }
185 
186  if (m_f->m_addNormals)
187  {
188  // Get normals
190  exp[0]->GetBoundaryNormals(Border, NormPhys);
191 
192  // add normal coefficients to expansions
193  for (int j = 0; j < normdim; ++j)
194  {
195  m_f->m_exp[nfields + j] =
196  BndExp[nfields + j][Border];
197  Vmath::Vcopy(
198  m_f->m_exp[nfields + j]->GetTotPoints(),
199  NormPhys[j], 1,
200  m_f->m_exp[nfields + j]->UpdatePhys(), 1);
201  m_f->m_exp[nfields + j]->FwdTrans_IterPerExp(
202  m_f->m_exp[nfields + j]->GetPhys(),
203  m_f->m_exp[nfields + j]->UpdateCoeffs());
204  }
205  }
206  OutputFromExp(vm);
207  // output error for regression checking.
208  if (vm.count("error"))
209  {
211  }
212 
213  // Reset communicator
214  m_f->m_comm = tmpComm;
215  }
216 
217  // put outfile back to filename in case of nparts option
218  RegisterConfig("outfile", filename);
219  }
220  // Restore m_exp
221  exp.swap(m_f->m_exp);
222  }
223  else
224  {
225  if (WriteFile(filename, vm))
226  {
227  OutputFromExp(vm);
228  // output error for regression checking.
229  if (vm.count("error"))
230  {
232  }
233  }
234  }
235  }
236  else if (m_f->m_data.size())
237  {
238  ASSERTL0(!m_f->m_writeBndFld, "Boundary extraction requires xml file.");
239  if (WriteFile(filename, vm))
240  {
241  OutputFromData(vm);
242  }
243  }
244 }
245 
246 bool OutputFileBase::WriteFile(std::string &filename, po::variables_map &vm)
247 {
248  // Get path to file. If procid was defined, get the full name
249  // to avoid checking files from other partitions
250  fs::path outFile;
251  if (vm.count("nparts"))
252  {
253  outFile = GetFullOutName(filename, vm);
254  }
255  else
256  {
257  outFile = GetPath(filename, vm);
258  }
259 
261  if (m_f->m_comm)
262  {
263  comm = m_f->m_comm;
264  }
265  else
266  {
267  comm = LibUtilities::GetCommFactory().CreateInstance("Serial", 0, 0);
268  }
269 
270  int count = fs::exists(outFile) ? 1 : 0;
271  comm->AllReduce(count, LibUtilities::ReduceSum);
272 
273  int writeFile = 1;
274  if (count && (vm.count("forceoutput") == 0))
275  {
276  if (vm.count("nparts") == 0) // do not do check if --nparts is enabled.
277  {
278 
279  writeFile = 0; // set to zero for reduce all to be correct.
280 
281  if (comm->TreatAsRankZero())
282  {
283  string answer;
284  cout << "Did you wish to overwrite " << outFile << " (y/n)? ";
285  getline(cin, answer);
286  if (answer.compare("y") == 0)
287  {
288  writeFile = 1;
289  }
290  else
291  {
292  cout << "Not writing file " << filename
293  << " because it already exists" << endl;
294  }
295  }
296  comm->AllReduce(writeFile, LibUtilities::ReduceSum);
297  }
298  }
299  return (writeFile == 0) ? false : true;
300 }
301 
302 void OutputFileBase::ConvertExpToEquispaced(po::variables_map &vm)
303 {
304  // Information to create new expansion
305  int numFields = m_f->m_exp.size();
306  m_f->m_fielddef = m_f->m_exp[0]->GetFieldDefinitions();
307 
308  // Set points to equispaced
309  int nPointsNew = 0;
310  if (vm.count("output-points"))
311  {
312  nPointsNew = vm["output-points"].as<int>();
313  }
314  m_f->m_graph->SetExpansionInfoToEvenlySpacedPoints(nPointsNew);
315 
316  // Save original expansion
317  vector<MultiRegions::ExpListSharedPtr> expOld = m_f->m_exp;
318  // Create new expansion
319  m_f->m_exp[0] = m_f->SetUpFirstExpList(m_f->m_numHomogeneousDir, true);
320  for (int i = 1; i < numFields; ++i)
321  {
322  m_f->m_exp[i] = m_f->AppendExpList(m_f->m_numHomogeneousDir);
323  }
324  // Extract result to new expansion
325  for (int i = 0; i < numFields; ++i)
326  {
327  m_f->m_exp[i]->ExtractCoeffsToCoeffs(expOld[i], expOld[i]->GetCoeffs(),
328  m_f->m_exp[i]->UpdateCoeffs());
329  m_f->m_exp[i]->BwdTrans(m_f->m_exp[i]->GetCoeffs(),
330  m_f->m_exp[i]->UpdatePhys());
331  }
332  // Extract boundary expansion if needed
333  if (m_f->m_writeBndFld)
334  {
337  for (int i = 0; i < numFields; ++i)
338  {
339  BndExpOld = expOld[i]->GetBndCondExpansions();
340  for (int j = 0; j < BndExpOld.size(); ++j)
341  {
342  BndExp = m_f->m_exp[i]->UpdateBndCondExpansion(j);
343 
344  BndExp->ExtractCoeffsToCoeffs(BndExpOld[j],
345  BndExpOld[j]->GetCoeffs(),
346  BndExp->UpdateCoeffs());
347  }
348  }
349  }
350  m_f->m_fielddef = std::vector<LibUtilities::FieldDefinitionsSharedPtr>();
351 }
352 
354 {
355  int coordim = m_f->m_fieldPts->GetDim();
356  std::string coordVars[] = {"x", "y", "z"};
357 
358  vector<string> variables = m_f->m_variables;
359  variables.insert(variables.begin(), coordVars, coordVars + coordim);
360  // Get fields and coordinates
361  Array<OneD, Array<OneD, NekDouble>> fields(variables.size());
362 
363  // We can just grab everything from points. This should be a
364  // reference, not a copy.
365  m_f->m_fieldPts->GetPts(fields);
366  for (int i = 0; i < fields.size(); ++i)
367  {
368  // calculate L2 and Linf value
369  int npts = fields[i].size();
370 
371  NekDouble l2err = 0.0;
372  NekDouble linferr = 0.0;
373  for (int j = 0; j < npts; ++j)
374  {
375  l2err += fields[i][j] * fields[i][j];
376  linferr = max(linferr, fabs(fields[i][j]));
377  }
378 
379  m_f->m_comm->AllReduce(l2err, LibUtilities::ReduceSum);
380  m_f->m_comm->AllReduce(npts, LibUtilities::ReduceSum);
381  m_f->m_comm->AllReduce(linferr, LibUtilities::ReduceMax);
382 
383  l2err /= npts;
384  l2err = sqrt(l2err);
385 
386  if (m_f->m_comm->TreatAsRankZero())
387  {
388  cout << "L 2 error (variable " << variables[i] << ") : " << l2err
389  << endl;
390 
391  cout << "L inf error (variable " << variables[i]
392  << ") : " << linferr << endl;
393  }
394  }
395 }
396 
398 {
399  int coordim =
400  m_f->m_exp[0]->GetExp(0)->GetCoordim() + m_f->m_numHomogeneousDir;
401  int totpoints = m_f->m_exp[0]->GetTotPoints();
402  std::string coordVars[] = {"x", "y", "z"};
403 
404  // Set up storage for coordinates
405  Array<OneD, Array<OneD, NekDouble>> coords(coordim);
406  for (int i = 0; i < coordim; ++i)
407  {
408  coords[i] = Array<OneD, NekDouble>(totpoints);
409  }
410 
411  // Get coordinates
412  if (coordim == 1)
413  {
414  m_f->m_exp[0]->GetCoords(coords[0]);
415  }
416  else if (coordim == 2)
417  {
418  m_f->m_exp[0]->GetCoords(coords[0], coords[1]);
419  }
420  else
421  {
422  m_f->m_exp[0]->GetCoords(coords[0], coords[1], coords[2]);
423  }
424 
425  for (int j = 0; j < coordim; ++j)
426  {
427  NekDouble l2err = m_f->m_exp[0]->L2(coords[j]);
428  NekDouble linferr = m_f->m_exp[0]->Linf(coords[j]);
429 
430  if (m_f->m_comm->TreatAsRankZero())
431  {
432  cout << "L 2 error (variable " << coordVars[j] << ") : " << l2err
433  << endl;
434 
435  cout << "L inf error (variable " << coordVars[j]
436  << ") : " << linferr << endl;
437  }
438  }
439 
440  for (int j = 0; j < m_f->m_exp.size(); ++j)
441  {
442  NekDouble l2err = m_f->m_exp[j]->L2(m_f->m_exp[j]->GetPhys());
443  NekDouble linferr = m_f->m_exp[j]->Linf(m_f->m_exp[j]->GetPhys());
444 
445  if (m_f->m_comm->TreatAsRankZero() && m_f->m_variables.size() > 0)
446  {
447  cout << "L 2 error (variable " << m_f->m_variables[j]
448  << ") : " << l2err << endl;
449 
450  cout << "L inf error (variable " << m_f->m_variables[j]
451  << ") : " << linferr << endl;
452  }
453  }
454 }
455 
456 } // namespace FieldUtils
457 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
FIELD_UTILS_EXPORT void RegisterConfig(std::string key, std::string value="")
Register a configuration option with a module.
Definition: Module.cpp:102
FieldSharedPtr m_f
Field object.
Definition: Module.h:230
std::map< std::string, ConfigOption > m_config
List of configuration values.
Definition: Module.h:233
virtual void OutputFromPts(po::variables_map &vm)=0
Write from pts to output file.
bool WriteFile(std::string &filename, po::variables_map &vm)
virtual fs::path GetFullOutName(std::string &filename, po::variables_map &vm)=0
virtual fs::path GetPath(std::string &filename, po::variables_map &vm)=0
virtual void OutputFromData(po::variables_map &vm)=0
Write from data to output file.
virtual void Process(po::variables_map &vm)
Write fld to output file.
void ConvertExpToEquispaced(po::variables_map &vm)
virtual std::string GetModuleName()
virtual void OutputFromExp(po::variables_map &vm)=0
Write from m_exp to output file.
Abstract base class for output modules.
Definition: Module.h:280
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:145
std::map< int, LibUtilities::CommSharedPtr > GetBoundaryCommunicators() const
Definition: Conditions.h:264
const BoundaryRegionCollection & GetBoundaryRegions(void) const
Definition: Conditions.h:238
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:989
static PtsFieldSharedPtr NullPtsField
Definition: PtsField.h:183
CommFactory & GetCommFactory()
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:54
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
std::map< int, BoundaryRegionShPtr > BoundaryRegionCollection
Definition: Conditions.h:217
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
double NekDouble
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1199
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:267
Represents a command-line configuration option.
Definition: Module.h:134