Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OutputFld.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: OutputFld.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 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: FLD file format output.
33 //
34 ////////////////////////////////////////////////////////////////////////////////
35 
36 #include <set>
37 #include <string>
38 using namespace std;
39 
40 #include "OutputFld.h"
42 
43 namespace Nektar
44 {
45 namespace Utilities
46 {
47 
48 ModuleKey OutputFld::m_className[2] = {
50  ModuleKey(eOutputModule, "fld"), OutputFld::create,
51  "Writes a Fld file."),
53  ModuleKey(eOutputModule, "chk"), OutputFld::create,
54  "Writes a Fld file."),
55 };
56 
57 OutputFld::OutputFld(FieldSharedPtr f) : OutputModule(f)
58 {
59 }
60 
62 {
63 }
64 
65 void OutputFld::Process(po::variables_map &vm)
66 {
67  Timer timer;
68  // Extract the output filename and extension
69  string filename = m_config["outfile"].as<string>();
70 
71  if (m_f->m_verbose)
72  {
73  timer.Start();
74  }
75 
76  if (m_f->m_writeBndFld)
77  {
78  Timer timer;
79  ModuleKey module;
80 
81  if (m_f->m_verbose)
82  {
83  if(m_f->m_comm->GetRank() == 0)
84  {
85  cout << "OutputFld: Writing boundary file(s): ";
86  for(int i = 0; i < m_f->m_bndRegionsToWrite.size(); ++i)
87  {
88  cout << m_f->m_bndRegionsToWrite[i];
89  if(i < m_f->m_bndRegionsToWrite.size()-1)
90  {
91  cout << ",";
92  }
93  }
94  cout << endl;
95  }
96  }
97 
98  // Extract data to boundaryconditions
99  if (m_f->m_fldToBnd) {
100  for (int i = 0; i < m_f->m_exp.size(); ++i)
101  {
102  m_f->m_exp[i]->FillBndCondFromField();
103  }
104  }
105 
106 
107  int nfields = m_f->m_exp.size();
109  BndExp(nfields);
110  for (int i = 0; i < nfields; ++i)
111  {
112  BndExp[i] = m_f->m_exp[i]->GetBndCondExpansions();
113  }
114 
115  // get hold of partition boundary regions so we can match it to desired
116  // region extraction
118  m_f->m_exp[0]->GetGraph());
120  bcs.GetBoundaryRegions();
121  SpatialDomains::BoundaryRegionCollection::const_iterator breg_it;
122  map<int,int> BndRegionMap;
123  int cnt =0;
124  for(breg_it = bregions.begin(); breg_it != bregions.end();
125  ++breg_it, ++cnt)
126  {
127  BndRegionMap[breg_it->first] = cnt;
128  }
129 
130  // find ending of output file and insert _b1, _b2
131  int dot = filename.find_last_of('.') + 1;
132  string ext = filename.substr(dot, filename.length() - dot);
133  string name = filename.substr(0, dot-1);
134 
135  for(int i = 0; i < m_f->m_bndRegionsToWrite.size(); ++i)
136  {
137  string outname = name + "_b"
138  + boost::lexical_cast<string>(m_f->m_bndRegionsToWrite[i])
139  + "." + ext;
140 
141  std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef;
142  std::vector<std::vector<NekDouble> > FieldData;
143 
144  if(BndRegionMap.count(m_f->m_bndRegionsToWrite[i]) == 1)
145  {
146  int Border = BndRegionMap[m_f->m_bndRegionsToWrite[i]];
147 
148  FieldDef = BndExp[0][Border]->GetFieldDefinitions();
149  FieldData.resize(FieldDef.size());
150 
151  for (int j = 0; j < nfields; ++j)
152  {
153  for (int k = 0; k < FieldDef.size(); ++k)
154  {
155  BndExp[j][Border]->AppendFieldData(FieldDef[k],
156  FieldData[k]);
157 
158  if (m_f->m_fielddef.size() > 0)
159  {
160  FieldDef[k]->m_fields.push_back(
161  m_f->m_fielddef[0]->m_fields[j]);
162  }
163  else
164  {
165  FieldDef[k]->m_fields.push_back(
166  m_f->m_session->GetVariable(j));
167  }
168  }
169  }
170 
171  if(m_f->m_addNormals)
172  {
173  int normdim = m_f->m_graph->GetMeshDimension();
174  string normstr[3] = {"Norm_x","Norm_y","Norm_z"};
175 
176  // Add normal information
178  Array<OneD, int> BoundarytoElmtID, BoundarytoTraceID;
179 
180  m_f->m_exp[0]->GetBoundaryToElmtMap(BoundarytoElmtID,
181  BoundarytoTraceID);
182 
183  // determine offset of this Bnd Expansion Border
184  int cnt = 0;
185  for(int n = 0; n < Border; ++n)
186  {
187  cnt += BndExp[0][n]->GetExpSize();
188  }
189 
190  Array<OneD, NekDouble> tmp_array;
191  Array<OneD, Array<OneD, NekDouble> > NormPhys(normdim);
192 
193  for(int j = 0; j < normdim; ++j)
194  {
195  NormPhys[j] = Array<OneD, NekDouble>(BndExp[0][Border]->GetTotPoints(),0.0);
196  }
197 
198  // setup phys arrays of normals
199  for(int j=0; j < BndExp[0][Border]->GetExpSize(); ++j,++cnt)
200  {
201  int elmtid = BoundarytoElmtID[cnt];
202 
203  elmt = m_f->m_exp[0]->GetExp(elmtid);
204 
205  //identify boundary of element looking at.
206  int boundary = BoundarytoTraceID[cnt];
207 
208  // Dimension specific part
209  switch(normdim)
210  {
211  case 2:
212  {
213  // Get edge 1D expansion from element expansion
215  bc = boost::dynamic_pointer_cast
217  (BndExp[0][Border]->GetExp(j));
218  // Get edge normals
220  normals = elmt->GetEdgeNormal(boundary);
221 
222  for(int k = 0; k < normdim; ++k)
223  {
224  Vmath::Vcopy(bc->GetTotPoints(),
225  normals[k], 1,
226  tmp_array = NormPhys[k]+
227  BndExp[0][Border]->
228  GetPhys_Offset(j), 1);
229  }
230  }
231  break;
232 
233  case 3:
234  {
235  // Get face 2D expansion from element expansion
237  bc = boost::dynamic_pointer_cast
239  (BndExp[0][Border]->GetExp(j));
240  //Get face normals
242  normals = elmt->GetFaceNormal(boundary);
243 
244  for(int k = 0; k < normdim; ++k)
245  {
246  Vmath::Vcopy(bc->GetTotPoints(),
247  normals[k], 1,
248  tmp_array = NormPhys[k]+
249  BndExp[0][Border]->
250  GetPhys_Offset(j), 1);
251  }
252  }
253  break;
254 
255  default:
256  ASSERTL0(false, "Addnormals requires expdim >=2.");
257  break;
258  }
259  }
260 
261  // add normal coefficients to list to be dumped
262  for (int j = 0; j < normdim; ++j)
263  {
264  BndExp[0][Border]->FwdTrans( NormPhys[j],
265  BndExp[0][Border]->UpdateCoeffs());
266 
267  for (int k = 0; k < FieldDef.size(); ++k)
268  {
269  BndExp[0][Border]->AppendFieldData(FieldDef[k],
270  FieldData[k]);
271  FieldDef[k]->m_fields.push_back(normstr[j]);
272  }
273  }
274  }
275 
276  // output error for regression checking.
277  if (vm.count("error"))
278  {
279  int rank = m_f->m_session->GetComm()->GetRank();
280 
281  for (int j = 0; j < nfields; ++j)
282  {
283  BndExp[j][Border]->BwdTrans(BndExp[j][Border]->GetCoeffs(),
284  BndExp[j][Border]->UpdatePhys());
285 
286  //Note currently these calls will
287  //hange since not all partitions will
288  //call error.
289  NekDouble l2err = BndExp[j][Border]
290  ->L2(BndExp[j][Border]->GetPhys());
291 
292  NekDouble linferr = BndExp[j][Border]
293  ->Linf(BndExp[j][Border]->GetPhys());
294 
295  if (rank == 0)
296  {
297  cout << "L 2 error (variable "
298  << FieldDef[0]->m_fields[j]
299  << ") : " << l2err << endl;
300 
301  cout << "L inf error (variable "
302  << FieldDef[0]->m_fields[j]
303  << ") : " << linferr << endl;
304  }
305  }
306  }
307  }
308 
309  m_f->m_fld->Write(outname, FieldDef, FieldData,
310  m_f->m_fieldMetaDataMap);
311 
312  }
313  }
314  else
315  {
316  if (m_f->m_verbose)
317  {
318  if(m_f->m_comm->GetRank() == 0)
319  {
320  cout << "OutputFld: Writing file..." << endl;
321  }
322  }
323 
324  fs::path writefile(filename);
325  int writefld = 1;
326  if(fs::exists(writefile)&&(vm.count("forceoutput") == 0))
327  {
328  LibUtilities::CommSharedPtr comm = m_f->m_session->GetComm();
329  int rank = comm->GetRank();
330  writefld = 0; // set to zero for reduce all to be correct.
331 
332  if(rank == 0)
333  {
334  string answer;
335  cout << "Did you wish to overwrite " << filename << " (y/n)? ";
336  getline(cin,answer);
337  if(answer.compare("y") == 0)
338  {
339  writefld = 1;
340  }
341  else
342  {
343  cout << "Not writing file " << filename << " because it already exists" << endl;
344  }
345  }
346 
347  comm->AllReduce(writefld,LibUtilities::ReduceSum);
348 
349  }
350 
351  if(writefld)
352  {
353  m_f->m_fld->Write(filename, m_f->m_fielddef, m_f->m_data,
354  m_f->m_fieldMetaDataMap);
355  }
356 
357  // output error for regression checking.
358  if (vm.count("error"))
359  {
360  int rank = m_f->m_session->GetComm()->GetRank();
361 
362  for (int j = 0; j < m_f->m_exp.size(); ++j)
363  {
364  if (m_f->m_exp[j]->GetPhysState() == false)
365  {
366  m_f->m_exp[j]->BwdTrans(
367  m_f->m_exp[j]->GetCoeffs(),
368  m_f->m_exp[j]->UpdatePhys());
369  }
370 
371  NekDouble l2err = m_f->m_exp[j]->L2(
372  m_f->m_exp[j]->GetPhys());
373 
374  NekDouble linferr = m_f->m_exp[j]->Linf(
375  m_f->m_exp[j]->GetPhys());
376  if (rank == 0)
377  {
378  cout << "L 2 error (variable "
379  << m_f->m_fielddef[0]->m_fields[j]
380  << ") : " << l2err << endl;
381 
382  cout << "L inf error (variable "
383  << m_f->m_fielddef[0]->m_fields[j]
384  << ") : " << linferr << endl;
385  }
386  }
387  }
388  }
389  if(m_f->m_verbose)
390  {
391  if(m_f->m_comm->GetRank() == 0)
392  {
393  timer.Stop();
394  NekDouble cpuTime = timer.TimePerTest(1);
395 
396  stringstream ss;
397  ss << cpuTime << "s";
398  cout << "OutputFld CPU Time: " << setw(8) << left
399  << ss.str() << endl;
400  cpuTime = 0.0;
401  }
402  }
403 
404 }
405 
406 }
407 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:161
pair< ModuleType, string > ModuleKey
Abstract base class for output modules.
virtual void Process()=0
map< string, ConfigOption > m_config
List of configuration values.
STL namespace.
FieldSharedPtr m_f
Field object.
boost::shared_ptr< StdExpansion2D > StdExpansion2DSharedPtr
void Stop()
Definition: Timer.cpp:62
boost::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:53
std::map< int, BoundaryRegionShPtr > BoundaryRegionCollection
Definition: Conditions.h:206
boost::shared_ptr< StdExpansion1D > StdExpansion1DSharedPtr
double NekDouble
boost::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:695
const BoundaryRegionCollection & GetBoundaryRegions(void) const
Definition: Conditions.h:227
void Start()
Definition: Timer.cpp:51
boost::shared_ptr< StdExpansion > StdExpansionSharedPtr
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
Definition: Timer.cpp:108
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1047
ModuleFactory & GetModuleFactory()
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, tDescription pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:215