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