Nektar++
SessionFunction.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: SessionFunction.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2017 Kilian Lackhove
10 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
11 // Department of Aeronautics, Imperial College London (UK), and Scientific
12 // Computing and Imaging Institute, University of Utah (USA).
13 //
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: Session Function
33 //
34 ////////////////////////////////////////////////////////////////////////////////
35 
38 
40 
41 #include <boost/format.hpp>
42 
43 using namespace std;
44 
45 namespace Nektar
46 {
47 namespace SolverUtils
48 {
49 
50 /**
51  * Representation of a FUNCTION defined in the session xml file.
52  *
53  * @param session The session where the function was defined.
54  * @param field The field the function is defined on.
55  * @param functionName The name of the function.
56  * @param toCache Store the evaluated function for later use.
57  */
58 SessionFunction::SessionFunction(const LibUtilities::SessionReaderSharedPtr &session,
59  const MultiRegions::ExpListSharedPtr &field,
60  std::string functionName,
61  bool toCache)
62  : m_session(session), m_field(field), m_name(functionName), m_toCache(toCache)
63 {
64  ASSERTL0(m_session->DefinesFunction(m_name),
65  "Function '" + m_name + "' does not exist.");
66 }
67 
68 /**
69  * Evaluates a function defined in the xml session file at each quadrature point.
70  *
71  * @param pArray The array into which to write the values.
72  * @param pTime The time at which to evaluate the function.
73  * @param domain The domain to evaluate the function in.
74  */
76  const NekDouble pTime,
77  const int domain)
78 {
79  std::vector<std::string> vFieldNames = m_session->GetVariables();
80 
81  for (int i = 0; i < vFieldNames.size(); i++)
82  {
83  Evaluate(vFieldNames[i], pArray[i], pTime, domain);
84  }
85 }
86 
87 /**
88  * Evaluates a function defined in the xml session file at each quadrature point.
89  *
90  * @param pFieldNames The names of the fields to evaluate the function for.
91  * @param pArray The array into which to write the values.
92  * @param pTime The time at which to evaluate the function.
93  * @param domain The domain to evaluate the function in.
94  */
95 void SessionFunction::Evaluate(std::vector<std::string> pFieldNames,
97  const NekDouble &pTime,
98  const int domain)
99 {
100  ASSERTL1(pFieldNames.size() == pArray.num_elements(),
101  "Function '" + m_name +
102  "' variable list size mismatch with array storage.");
103 
104  for (int i = 0; i < pFieldNames.size(); i++)
105  {
106  Evaluate(pFieldNames[i], pArray[i], pTime, domain);
107  }
108 }
109 
110 /**
111  * Evaluates a function defined in the xml session file at each quadrature point.
112  *
113  * @param pFieldNames The names of the fields to evaluate the function for.
114  * @param pFields The fields into which to write the values.
115  * @param pTime The time at which to evaluate the function.
116  * @param domain The domain to evaluate the function in.
117  */
119  std::vector<std::string> pFieldNames,
121  const NekDouble &pTime,
122  const int domain)
123 {
124  ASSERTL0(pFieldNames.size() == pFields.num_elements(),
125  "Field list / name list size mismatch.");
126 
127  for (int i = 0; i < pFieldNames.size(); i++)
128  {
129  Evaluate(pFieldNames[i], pFields[i]->UpdatePhys(), pTime, domain);
130  pFields[i]->FwdTrans_IterPerExp(pFields[i]->GetPhys(),
131  pFields[i]->UpdateCoeffs());
132  }
133 }
134 
135 /**
136  * Evaluates a function defined in the xml session file at each quadrature point.
137  *
138  * @param pFieldName The name of the field to evaluate the function for.
139  * @param pArray The array into which to write the values.
140  * @param pTime The time at which to evaluate the function.
141  * @param domain The domain to evaluate the function in.
142  */
143 void SessionFunction::Evaluate(std::string pFieldName,
144  Array<OneD, NekDouble> &pArray,
145  const NekDouble &pTime,
146  const int domain)
147 {
149  m_session->GetFunctionType(m_name, pFieldName, domain);
150 
151  unsigned int nq = m_field->GetNpoints();
152 
153  std::pair<std::string, int> key(pFieldName, domain);
154  // sorry
155  if ((m_arrays.find(key) != m_arrays.end()) &&
157  ((m_lastCached.find(key) != m_lastCached.end()) &&
158  (pTime - m_lastCached[key] < NekConstants::kNekZeroTol))))
159  {
160  // found cached field
161  if (pArray.num_elements() < nq)
162  {
163  pArray = Array<OneD, NekDouble>(nq);
164  }
165  Vmath::Vcopy(nq, m_arrays[key], 1, pArray, 1);
166 
167  return;
168  }
169 
171  {
172  EvaluateExp(pFieldName, pArray, pTime, domain);
173  }
174  else if (vType == LibUtilities::eFunctionTypeFile ||
176  {
177  std::string filename =
178  m_session->GetFunctionFilename(m_name, pFieldName, domain);
179 
180  if (boost::filesystem::path(filename).extension() == ".pts" ||
181  boost::filesystem::path(filename).extension() == ".csv")
182  {
183  EvaluatePts(pFieldName, pArray, pTime, domain);
184  }
185  else
186  {
187  EvaluateFld(pFieldName, pArray, pTime, domain);
188  }
189  }
190  else
191  {
192  ASSERTL0(false, "unknown eFunctionType");
193  }
194 
195  if (m_toCache)
196  {
197  m_arrays[key] = Array<OneD, NekDouble>(nq);
198  Vmath::Vcopy(nq, pArray, 1, m_arrays[key], 1);
199 
200  m_lastCached[key] = pTime;
201  }
202 }
203 
204 /**
205  * @brief Provide a description of a function for a given field name.
206  *
207  * @param pFieldName Field name.
208  * @param domain The domain to evaluate the function in.
209  */
210 std::string SessionFunction::Describe(std::string pFieldName, const int domain)
211 {
212  std::string retVal;
213 
215  m_session->GetFunctionType(m_name, pFieldName, domain);
217  {
219  m_session->GetFunction(m_name, pFieldName, domain);
220  retVal = ffunc->GetExpression();
221  }
222  else if (vType == LibUtilities::eFunctionTypeFile ||
224  {
225  std::string filename =
226  m_session->GetFunctionFilename(m_name, pFieldName, domain);
227  retVal = "from file " + filename;
228  }
229  else
230  {
231  ASSERTL0(false, "unknown eFunctionType");
232  }
233 
234  return retVal;
235 }
236 
237 /**
238  * Evaluates a function from expression
239  *
240  * @param pFieldName The name of the field to evaluate the function for.
241  * @param pArray The array into which to write the values.
242  * @param pTime The time at which to evaluate the function.
243  * @param domain The domain to evaluate the function in.
244  */
245 void SessionFunction::EvaluateExp(string pFieldName,
246  Array<OneD, NekDouble> &pArray,
247  const NekDouble &pTime,
248  const int domain)
249 {
250  unsigned int nq = m_field->GetNpoints();
251  if (pArray.num_elements() < nq)
252  {
253  pArray = Array<OneD, NekDouble>(nq);
254  }
255 
256  Array<OneD, NekDouble> x0(nq);
257  Array<OneD, NekDouble> x1(nq);
258  Array<OneD, NekDouble> x2(nq);
259 
260  // Get the coordinates (assuming all fields have the same
261  // discretisation)
262  m_field->GetCoords(x0, x1, x2);
264  m_session->GetFunction(m_name, pFieldName, domain);
265 
266  ffunc->Evaluate(x0, x1, x2, pTime, pArray);
267 }
268 
269 /**
270  * Evaluates a function from fld file
271  *
272  * @param pFieldName The name of the field to evaluate the function for.
273  * @param pArray The array into which to write the values.
274  * @param pTime The time at which to evaluate the function.
275  * @param domain The domain to evaluate the function in.
276  */
277 void SessionFunction::EvaluateFld(string pFieldName,
278  Array<OneD, NekDouble> &pArray,
279  const NekDouble &pTime,
280  const int domain)
281 {
282  unsigned int nq = m_field->GetNpoints();
283  if (pArray.num_elements() < nq)
284  {
285  pArray = Array<OneD, NekDouble>(nq);
286  }
287 
288  std::string filename =
289  m_session->GetFunctionFilename(m_name, pFieldName, domain);
290  std::string fileVar =
291  m_session->GetFunctionFilenameVariable(m_name, pFieldName, domain);
292 
293  if (fileVar.length() == 0)
294  {
295  fileVar = pFieldName;
296  }
297 
298  // In case of eFunctionTypeTransientFile, generate filename from
299  // format string
301  m_session->GetFunctionType(m_name, pFieldName, domain);
303  {
304  try
305  {
306 #if (defined _WIN32 && _MSC_VER < 1900)
307  // We need this to make sure boost::format has always
308  // two digits in the exponents of Scientific notation.
309  unsigned int old_exponent_format;
310  old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT);
311  filename = boost::str(boost::format(filename) % pTime);
312  _set_output_format(old_exponent_format);
313 #else
314  filename = boost::str(boost::format(filename) % pTime);
315 #endif
316  }
317  catch (...)
318  {
319  ASSERTL0(false,
320  "Invalid Filename in function \"" + m_name +
321  "\", variable \"" + fileVar + "\"")
322  }
323  }
324 
325  // Define list of global element ids
326  int numexp = m_field->GetExpSize();
327  Array<OneD, int> ElementGIDs(numexp);
328  for (int i = 0; i < numexp; ++i)
329  {
330  ElementGIDs[i] = m_field->GetExp(i)->GetGeom()->GetGlobalID();
331  }
332 
333  std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef;
334  std::vector<std::vector<NekDouble> > FieldData;
337  fldIO->Import(filename,
338  FieldDef,
339  FieldData,
341  ElementGIDs);
342 
343  int idx = -1;
344  Array<OneD, NekDouble> vCoeffs(m_field->GetNcoeffs(), 0.0);
345  // Loop over all the expansions
346  for (int i = 0; i < FieldDef.size(); ++i)
347  {
348  // Find the index of the required field in the
349  // expansion segment
350  for (int j = 0; j < FieldDef[i]->m_fields.size(); ++j)
351  {
352  if (FieldDef[i]->m_fields[j] == fileVar)
353  {
354  idx = j;
355  }
356  }
357 
358  if (idx >= 0)
359  {
360  m_field->ExtractDataToCoeffs(
361  FieldDef[i], FieldData[i], FieldDef[i]->m_fields[idx], vCoeffs);
362  }
363  else
364  {
365  cout << "Field " + fileVar + " not found." << endl;
366  }
367  }
368 
369  m_field->BwdTrans_IterPerExp(vCoeffs, pArray);
370 }
371 
372 /**
373  * Evaluates a function from pts file
374  *
375  * @param pFieldName The name of the field to evaluate the function for.
376  * @param pArray The array into which to write the values.
377  * @param pTime The time at which to evaluate the function.
378  * @param domain The domain to evaluate the function in.
379  */
380 void SessionFunction::EvaluatePts(string pFieldName,
381  Array<OneD, NekDouble> &pArray,
382  const NekDouble &pTime,
383  const int domain)
384 {
385  unsigned int nq = m_field->GetNpoints();
386  if (pArray.num_elements() < nq)
387  {
388  pArray = Array<OneD, NekDouble>(nq);
389  }
390 
391  std::string filename =
392  m_session->GetFunctionFilename(m_name, pFieldName, domain);
393  std::string fileVar =
394  m_session->GetFunctionFilenameVariable(m_name, pFieldName, domain);
395 
396  if (fileVar.length() == 0)
397  {
398  fileVar = pFieldName;
399  }
400 
401  // In case of eFunctionTypeTransientFile, generate filename from
402  // format string
404  m_session->GetFunctionType(m_name, pFieldName, domain);
406  {
407  try
408  {
409 #if (defined _WIN32 && _MSC_VER < 1900)
410  // We need this to make sure boost::format has always
411  // two digits in the exponents of Scientific notation.
412  unsigned int old_exponent_format;
413  old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT);
414  filename = boost::str(boost::format(filename) % pTime);
415  _set_output_format(old_exponent_format);
416 #else
417  filename = boost::str(boost::format(filename) % pTime);
418 #endif
419  }
420  catch (...)
421  {
422  ASSERTL0(false,
423  "Invalid Filename in function \"" + m_name +
424  "\", variable \"" + fileVar + "\"")
425  }
426  }
427 
429  // check if we already loaded this file. For transient files,
430  // funcFilename != filename so we can make sure we only keep the
431  // latest pts field per funcFilename.
432  std::string funcFilename =
433  m_session->GetFunctionFilename(m_name, pFieldName, domain);
434 
436  if (boost::filesystem::path(filename).extension() == ".pts")
437  {
438  LibUtilities::PtsIO ptsIO(m_session->GetComm());
439  ptsIO.Import(filename, inPts);
440  }
441  else if (boost::filesystem::path(filename).extension() == ".csv")
442  {
443  LibUtilities::CsvIO csvIO(m_session->GetComm());
444  csvIO.Import(filename, inPts);
445  }
446  else
447  {
448  ASSERTL1(false, "Unsupported file type");
449  }
450 
451 
452  Array<OneD, Array<OneD, NekDouble> > pts(inPts->GetDim() +
453  inPts->GetNFields());
454  for (int i = 0; i < inPts->GetDim() + inPts->GetNFields(); ++i)
455  {
456  pts[i] = Array<OneD, NekDouble>(nq);
457  }
458  if (inPts->GetDim() == 1)
459  {
460  m_field->GetCoords(pts[0]);
461  }
462  else if (inPts->GetDim() == 2)
463  {
464  m_field->GetCoords(pts[0], pts[1]);
465  }
466  else if (inPts->GetDim() == 3)
467  {
468  m_field->GetCoords(pts[0], pts[1], pts[2]);
469  }
471  inPts->GetDim(), inPts->GetFieldNames(), pts);
472 
474  if (m_interpolators.find(funcFilename) != m_interpolators.end())
475  {
476  interp = m_interpolators[funcFilename];
477  }
478  else
479  {
481  if (m_session->GetComm()->GetRank() == 0)
482  {
483  interp.SetProgressCallback(&SessionFunction::PrintProgressbar,
484  this);
485  }
486  interp.CalcWeights(inPts, outPts);
487  if (m_session->GetComm()->GetRank() == 0)
488  {
489  cout << endl;
490  if (m_session->DefinesCmdLineArgument("verbose"))
491  {
492  interp.PrintStatistics();
493  }
494  }
495  }
496 
497  if (m_toCache)
498  {
499  m_interpolators[funcFilename] = interp;
500  }
501 
502  // TODO: only interpolate the field we actually want
503  interp.Interpolate(inPts, outPts);
504 
505  int fieldInd;
506  vector<string> fieldNames = outPts->GetFieldNames();
507  for (fieldInd = 0; fieldInd < fieldNames.size(); ++fieldInd)
508  {
509  if (outPts->GetFieldName(fieldInd) == fileVar)
510  {
511  break;
512  }
513  }
514  ASSERTL0(fieldInd != fieldNames.size(), "field not found");
515 
516  pArray = outPts->GetPts(fieldInd + outPts->GetDim());
517 }
518 
519 // end of namespaces
520 }
521 }
bool m_toCache
Store resulting arrays (and interpolators)
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
A class that contains algorithms for interpolation between pts fields, expansions and different meshe...
std::map< std::pair< std::string, int >, NekDouble > m_lastCached
Last time the cache for this variable & domain combo was updated.
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
SOLVER_UTILS_EXPORT void EvaluateExp(std::string pFieldName, Array< OneD, NekDouble > &pArray, const NekDouble &pTime=0.0, const int domain=0)
SOLVER_UTILS_EXPORT void PrintProgressbar(const int position, const int goal) const
STL namespace.
LibUtilities::SessionReaderSharedPtr m_session
The session reader.
void Import(const std::string &inFile, PtsFieldSharedPtr &ptsField, FieldMetaDataMap &fieldmetadatamap=NullFieldMetaDataMap)
Import a pts field from file.
Definition: PtsIO.cpp:69
std::map< std::pair< std::string, int >, Array< OneD, NekDouble > > m_arrays
Cached result arrays.
std::shared_ptr< PtsField > PtsFieldSharedPtr
Definition: PtsField.h:179
static const NekDouble kNekZeroTol
SOLVER_UTILS_EXPORT std::string Describe(std::string pFieldName, const int domain=0)
Provide a description of a function for a given field name.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
double NekDouble
SOLVER_UTILS_EXPORT void Evaluate(Array< OneD, Array< OneD, NekDouble > > &pArray, const NekDouble pTime=0.0, const int domain=0)
Evaluates a function defined in the xml session file at each quadrature point.
SOLVER_UTILS_EXPORT void EvaluatePts(std::string pFieldName, Array< OneD, NekDouble > &pArray, const NekDouble &pTime=0.0, const int domain=0)
Evaluates a function from pts file.
std::shared_ptr< Equation > EquationSharedPtr
Definition: Equation.h:131
static std::shared_ptr< FieldIO > CreateForFile(const LibUtilities::SessionReaderSharedPtr session, const std::string &filename)
Construct a FieldIO object for a given input filename.
Definition: FieldIO.cpp:226
std::map< std::string, FieldUtils::Interpolator > m_interpolators
Interpolator for pts file input for a variable & domain combination.
SOLVER_UTILS_EXPORT void EvaluateFld(std::string pFieldName, Array< OneD, NekDouble > &pArray, const NekDouble &pTime=0.0, const int domain=0)
MultiRegions::ExpListSharedPtr m_field
The expansion we want to evaluate this function for.
std::shared_ptr< FieldIO > FieldIOSharedPtr
Definition: FieldIO.h:306
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1064
static FieldMetaDataMap NullFieldMetaDataMap
Definition: FieldIO.h:53
std::shared_ptr< SessionReader > SessionReaderSharedPtr