Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
FilterHistoryPoints.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File FilterHistoryPoints.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: Outputs values at specific points during time-stepping.
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
37 #include <iomanip>
40 
41 #include <boost/format.hpp>
42 
43 using namespace std;
44 
45 namespace Nektar
46 {
47 namespace SolverUtils
48 {
49 std::string FilterHistoryPoints::className = GetFilterFactory().RegisterCreatorFunction("HistoryPoints", FilterHistoryPoints::create);
50 
51 /**
52  *
53  */
54 FilterHistoryPoints::FilterHistoryPoints(
56  const ParamMap &pParams) :
57  Filter(pSession)
58 {
59  ParamMap::const_iterator it;
60 
61  // OutputFile
62  it = pParams.find("OutputFile");
63  if (it == pParams.end())
64  {
65  m_outputFile = m_session->GetSessionName();
66  }
67  else
68  {
69  ASSERTL0(it->second.length() > 0, "Missing parameter 'OutputFile'.");
70  m_outputFile = it->second;
71  }
72  if (!(m_outputFile.length() >= 4
73  && m_outputFile.substr(m_outputFile.length() - 4) == ".his"))
74  {
75  m_outputFile += ".his";
76  }
77 
78  // OutputFrequency
79  it = pParams.find("OutputFrequency");
80  if (it == pParams.end())
81  {
83  }
84  else
85  {
86  LibUtilities::Equation equ(m_session, it->second);
87  m_outputFrequency = floor(equ.Evaluate());
88  }
89 
90  // OutputPlane
91  m_session->MatchSolverInfo("Homogeneous", "1D", m_isHomogeneous1D, false);
93  {
94  it = pParams.find("OutputPlane");
95  if (it == pParams.end())
96  {
97  m_outputPlane = -1;
98  }
99  else
100  {
101  LibUtilities::Equation equ(m_session, it->second);
102  m_outputPlane = floor(equ.Evaluate());
103  }
104 
105  it = pParams.find("WaveSpace");
106  if (it == pParams.end())
107  {
108  m_waveSpace = false;
109  }
110  else
111  {
112  std::string sOption = it->second.c_str();
113  m_waveSpace = ( boost::iequals(sOption,"true")) ||
114  ( boost::iequals(sOption,"yes"));
115  }
116  }
117 
118  // Points
119  it = pParams.find("Points");
120  ASSERTL0(it != pParams.end(), "Missing parameter 'Points'.");
121  m_historyPointStream.str(it->second);
122  m_index = 0;
123 }
124 
125 
126 /**
127  *
128  */
130 {
131 
132 }
133 
134 
135 /**
136  *
137  */
140  const NekDouble &time)
141 {
143  "No history points in stream.");
144 
145  m_index = 0;
146  m_historyList.clear();
147 
148  vector<unsigned int> planeIDs;
149  // Read history points
150  Array<OneD, NekDouble> gloCoord(3,0.0);
151  int dim = pFields[0]->GetGraph()->GetSpaceDimension();
152  if (m_isHomogeneous1D)
153  {
154  dim++;
155  }
156  int i = 0;
157  while (!m_historyPointStream.fail())
158  {
159  m_historyPointStream >> gloCoord[0]
160  >> gloCoord[1]
161  >> gloCoord[2];
162 
163  if (!m_historyPointStream.fail())
164  {
165  // Overwrite gloCoord[2] for 3DH1D using m_outputPlane if it is
166  // defined, or a nearby plane otherwise
168  {
169  int nplanes = pFields[0]->GetHomogeneousBasis()
170  ->GetZ().num_elements();
171  NekDouble lhom = pFields[0]->GetHomoLen();
172  int plane;
173  if (m_outputPlane == -1)
174  {
175  // Pick plane immediately before the point
176  plane = floor((gloCoord[2]*nplanes)/lhom);
177  }
178  else
179  {
180  plane = m_outputPlane;
181  }
182 
183  NekDouble Z = (pFields[0]->GetHomogeneousBasis()
184  ->GetZ())[plane];
185  Z = (Z+1)*lhom/2;
186  if(fabs(gloCoord[2]-Z) > NekConstants::kVertexTheSameDouble)
187  {
188  cout << "Reseting History point from z = " << gloCoord[2]
189  << " to z = " << Z << endl;
190  }
191  gloCoord[2] = Z;
192  planeIDs.push_back(plane);
193  }
194 
197  ::AllocateSharedPtr(dim, i, gloCoord[0],
198  gloCoord[1], gloCoord[2]);
199 
200  m_historyPoints.push_back(vert);
201  ++i;
202  }
203  }
204 
205 
206  // Determine the unique process responsible for each history point
207  // For points on a partition boundary, must select a single process
208  LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
209  int vRank = vComm->GetRowComm()->GetRank();
210  int vHP = m_historyPoints.size();
211  Array<OneD, int> procList(vHP, -1 );
212  Array<OneD, int> idList (vHP, -1 );
213  Array<OneD, NekDouble> dist (vHP, 1e16);
214  Array<OneD, NekDouble> dist_loc(vHP, 1e16);
215  std::vector<Array<OneD, NekDouble> > LocCoords;
216 
217  // Find the nearest element on this process to which the history
218  // point could belong and note down the distance from the element
219  // and the process ID.
220  for (i = 0; i < vHP; ++i)
221  {
222  Array<OneD, NekDouble> locCoords(3);
223  m_historyPoints[i]->GetCoords( gloCoord[0],
224  gloCoord[1],
225  gloCoord[2]);
226 
227  // Determine the expansion and local coordinates
228  if (m_isHomogeneous1D)
229  {
230  idList[i] = pFields[0]->GetPlane(0)->GetExpIndex(gloCoord,locCoords,
232  }
233  else
234  {
235  idList[i] = pFields[0]->GetExpIndex(gloCoord,locCoords,
237  }
238 
239  // Save Local coordinates for later
240  LocCoords.push_back(locCoords);
241 
242  // For those points for which a potential nearby element exists
243  // compute the perp. distance from the point to the element and
244  // store in the distances array.
245  if (idList[i] != -1)
246  {
248  pFields[0]->GetExp(idList[i])->GetGeom();
249  StdRegions::StdExpansionSharedPtr e = g->GetXmap();
250  Array<OneD, NekDouble> coordVals(e->GetTotPoints());
251  dist_loc[i] = 0.0;
252  for (int j = 0; j < g->GetCoordim(); ++j)
253  {
254  e->BwdTrans(g->GetCoeffs(j), coordVals);
255  NekDouble x = e->PhysEvaluate(locCoords, coordVals)
256  - gloCoord[j];
257  dist_loc[i] += x*x;
258  }
259  }
260  }
261 
262  // Reduce distances of points from elements, keeping the smallest
263  // distance.
264  Vmath::Vcopy(vHP, dist_loc, 1, dist, 1);
265  vComm->AllReduce(dist, LibUtilities::ReduceMin);
266 
267  // If multiple processes find they are the nearest (e.g. point lies
268  // on a partition boundary, we will choose the process of highest
269  // rank.
270  m_planeIDs = Array<OneD, int> (planeIDs.size(),-1);
271  for (i = 0; i < vHP; ++i)
272  {
273  if (dist_loc[i] == dist[i])
274  {
275  // Set element id to Vid of m_history point for later use
276  m_historyPoints[i]->SetVid(idList[i]);
277  }
278  else
279  {
280  // This history point is not handled by this process
281  idList[i] = -1;
282  }
283 
284  // If a matching element is found on this process, note the
285  // process ID
286  if (idList[i] != -1)
287  {
288  procList[i] = vRank;
290  {
291  int j;
293  = pFields[0]->GetZIDs();
294  for(j = 0; j < IDs.num_elements(); ++j)
295  {
296  if(IDs[j] == planeIDs[i])
297  {
298  break;
299  }
300  }
301 
302  if(j != IDs.num_elements())
303  {
304  m_planeIDs[i] = j;
305  }
306  }
307  }
308  }
309 
310  // Reduce process IDs for all history points. The process with
311  // largest rank will handle the history point in the case where the
312  // distance was the same.
313  vComm->AllReduce(procList, LibUtilities::ReduceMax);
314 
315  // Determine the element in which each history point resides.
316  // If point is not in mesh (on this process), id is -1.
317  for (i = 0; i < vHP; ++i)
318  {
319  // If point lies on partition boundary, only the proc with max
320  // rank retains possession.
321  if (procList[i] != vRank)
322  {
323  idList[i] = -1;
324  }
325 
326  // If the current process owns this history point, add it to its
327  // local list of history points.
328  if (idList[i] != -1)
329  {
331  m_historyList.push_back(
334  (m_historyPoints[i], LocCoords[i]));
335  }
336  }
337 
338  // Collate the element ID list across processes and check each
339  // history point is allocated to a process
340  vComm->AllReduce(idList, LibUtilities::ReduceMax);
341  if (vComm->GetRank() == 0)
342  {
343  for (i = 0; i < vHP; ++i)
344  {
345  m_historyPoints[i]->GetCoords( gloCoord[0],
346  gloCoord[1],
347  gloCoord[2]);
348 
349  // Write an error if no process owns history point
350  ASSERTL0(idList[i] != -1,
351  "History point "
352  + boost::lexical_cast<std::string>(gloCoord[0])
353  + ", "
354  + boost::lexical_cast<std::string>(gloCoord[1])
355  + ", "
356  + boost::lexical_cast<std::string>(gloCoord[2])
357  + " cannot be found in the mesh.");
358 
359  // Print a warning if a process owns it but it is not close
360  // enough to the element.
361  if (dist[i] > NekConstants::kGeomFactorsTol)
362  {
363  cout << "Warning: History point " << i << " at ("
364  << gloCoord[0] << "," << gloCoord[1] << ","
365  << gloCoord[2] << ") lies a distance of "
366  << sqrt(dist[i]) << " from the manifold." << endl;
367  }
368  }
369 
370  // Open output stream
371  bool adaptive;
372  m_session->MatchSolverInfo("Driver", "Adaptive",
373  adaptive, false);
374  if (adaptive)
375  {
376  m_outputStream.open(m_outputFile.c_str(), ofstream::app);
377  }
378  else
379  {
380  m_outputStream.open(m_outputFile.c_str());
381  }
382  m_outputStream << "# History data for variables (:";
383 
384  for (i = 0; i < pFields.num_elements(); ++i)
385  {
386  m_outputStream << m_session->GetVariable(i) <<",";
387  }
388 
390  {
391  m_outputStream << ") at points:" << endl;
392  }
393  else
394  {
395  m_outputStream << ") at points:" << endl;
396  }
397 
398  for (i = 0; i < vHP; ++i)
399  {
400  m_historyPoints[i]->GetCoords( gloCoord[0],
401  gloCoord[1],
402  gloCoord[2]);
403 
404  m_outputStream << "# " << boost::format("%6.0f") % i;
405  m_outputStream << " " << boost::format("%25.19e") % gloCoord[0];
406  m_outputStream << " " << boost::format("%25.19e") % gloCoord[1];
407  m_outputStream << " " << boost::format("%25.19e") % gloCoord[2];
408  m_outputStream << endl;
409  }
410 
412  {
413  if (m_waveSpace)
414  {
415  m_outputStream << "# (in Wavespace)" << endl;
416  }
417  }
418  }
419  v_Update(pFields, time);
420 }
421 
422 
423 /**
424  *
425  */
427 {
428  // Only output every m_outputFrequency.
429  if ((m_index++) % m_outputFrequency)
430  {
431  return;
432  }
433 
434  int j = 0;
435  int k = 0;
436  int numPoints = m_historyPoints.size();
437  int numFields = pFields.num_elements();
438  LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
439  Array<OneD, NekDouble> data(numPoints*numFields, 0.0);
440  std::list<std::pair<SpatialDomains::PointGeomSharedPtr, Array<OneD, NekDouble> > >::iterator x;
441 
442  Array<OneD, NekDouble> physvals;
443  Array<OneD, NekDouble> locCoord;
444  int expId;
445 
446  // Pull out data values field by field
447  for (j = 0; j < numFields; ++j)
448  {
450  {
451  for (k = 0, x = m_historyList.begin(); x != m_historyList.end();
452  ++x, ++k)
453  {
454  locCoord = (*x).second;
455  expId = (*x).first->GetVid();
456  NekDouble value;
457  int plane = m_planeIDs[m_historyLocalPointMap[k]];
458 
459  if (m_waveSpace)
460  {
461  ASSERTL0( pFields[j]->GetWaveSpace() == true,
462  "HistoryPoints in wavespace require that solution is in wavespace");
463  }
464  if ( pFields[j]->GetWaveSpace() == false || m_waveSpace)
465  {
466  if (plane != -1)
467  {
468  physvals = pFields[j]->GetPlane(plane)->
469  UpdatePhys() + pFields[j]->GetPhys_Offset(expId);
470 
471  // transform elemental data if required.
472  if(pFields[j]->GetPhysState() == false)
473  {
474  pFields[j]->GetPlane(plane)->GetExp(expId)->
475  BwdTrans(pFields[j]->GetPlane(plane)->
476  GetCoeffs() + pFields[j]->
477  GetCoeff_Offset(expId),physvals);
478  }
479  // Interpolate data
480  value = pFields[j]->GetPlane(plane)->GetExp(expId)->
481  StdPhysEvaluate(locCoord,physvals);
482  }
483  }
484  else
485  {
486  // Create vector with eIDs across all planes
487  std::vector<unsigned int> eIDs;
488  int nPlanes = pFields[j]->GetZIDs().num_elements();
489  int elmtsPerPlane = pFields[j]->GetExpSize()/nPlanes;
490 
491  for ( int n = 0; n < nPlanes; n++)
492  {
493  eIDs.push_back(expId + n*elmtsPerPlane);
494  }
495 
496  // Create new 3DH1D expansion with one element per plane
498  boost::dynamic_pointer_cast<MultiRegions::
499  ExpList3DHomogeneous1D>(pFields[j]);
500  ASSERTL0(tmp,"Failed to type cast expansion");
501 
505  AllocateSharedPtr(*tmp, eIDs);
506  // Fill phys array of new expansion and apply HomoBwdTrans
507  for ( int n = 0; n < nPlanes; n++)
508  {
509  Array<OneD, NekDouble> toPhys =
510  exp->GetPlane(n)->UpdatePhys();
511  if(pFields[j]->GetPhysState())
512  {
513  int nq = exp->GetPlane(0)->GetTotPoints();
514  Array<OneD, NekDouble> fromPhys =
515  pFields[j]->GetPlane(n)->GetPhys() +
516  pFields[j]->GetPhys_Offset(expId);
517  Vmath::Vcopy(nq, fromPhys, 1, toPhys, 1);
518  }
519  else
520  {
521  Array<OneD, NekDouble> fromCoeffs =
522  pFields[j]->GetPlane(n)->GetCoeffs() +
523  pFields[j]->GetCoeff_Offset(expId);
524  exp->GetPlane(n)->GetExp(0)->
525  BwdTrans(fromCoeffs, toPhys);
526  }
527  }
528  exp->HomogeneousBwdTrans(exp->GetPhys(), exp->UpdatePhys());
529  // Interpolate data
530  if (plane != -1)
531  {
532  physvals = exp->GetPlane(plane)->UpdatePhys();
533 
534  value = exp->GetPlane(plane)->GetExp(0)->
535  StdPhysEvaluate(locCoord,physvals);
536  }
537  }
538 
539  // store data
540  if (plane != -1)
541  {
542  data[m_historyLocalPointMap[k]*numFields+j] = value;
543  }
544  }
545  }
546  else
547  {
548  for (k = 0, x = m_historyList.begin(); x != m_historyList.end(); ++x, ++k)
549  {
550  locCoord = (*x).second;
551  expId = (*x).first->GetVid();
552 
553  physvals = pFields[j]->UpdatePhys() + pFields[j]->GetPhys_Offset(expId);
554 
555  // transform elemental data if required.
556  if(pFields[j]->GetPhysState() == false)
557  {
558  pFields[j]->GetExp(expId)->BwdTrans(pFields[j]->GetCoeffs() + pFields[j]->GetCoeff_Offset(expId),physvals);
559  }
560 
561  // interpolate point
562  data[m_historyLocalPointMap[k]*numFields+j] = pFields[j]->GetExp(expId)->StdPhysEvaluate(locCoord,physvals);
563  }
564  }
565  }
566 
567  // Exchange history data
568  // This could be improved to reduce communication but works for now
569  vComm->AllReduce(data, LibUtilities::ReduceSum);
570 
571  // Only the root process writes out history data
572  if (vComm->GetRank() == 0)
573  {
574 
575  // Write data values point by point
576  for (k = 0; k < m_historyPoints.size(); ++k)
577  {
578  m_outputStream << boost::format("%25.19e") % time;
579  for (int j = 0; j < numFields; ++j)
580  {
581  m_outputStream << " " << boost::format("%25.19e") % data[k*numFields+j];
582  }
583  m_outputStream << endl;
584  }
585  }
586 }
587 
588 
589 /**
590  *
591  */
593 {
594  if (pFields[0]->GetComm()->GetRank() == 0)
595  {
596  m_outputStream.close();
597  }
598 }
599 
600 
601 /**
602  *
603  */
605 {
606  return true;
607 }
608 }
609 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:188
static boost::shared_ptr< DataType > AllocateSharedPtr()
Allocate a shared pointer from the memory pool.
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
STL namespace.
static const NekDouble kVertexTheSameDouble
boost::shared_ptr< SessionReader > SessionReaderSharedPtr
Definition: MeshPartition.h:51
boost::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:53
static const NekDouble kNekZeroTol
unsigned int m_outputPlane
plane to take history point from if using a homogeneous1D expansion
NekDouble Evaluate() const
Definition: Equation.h:102
SpatialDomains::PointGeomVector m_historyPoints
double NekDouble
std::map< std::string, std::string > ParamMap
Definition: Filter.h:67
LibUtilities::SessionReaderSharedPtr m_session
Definition: Filter.h:84
virtual SOLVER_UTILS_EXPORT void v_Finalise(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time)
virtual SOLVER_UTILS_EXPORT void v_Initialise(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time)
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs typedef NekMatrix< LhsDataType, StandardMatrixTag >::iterator iterator
virtual SOLVER_UTILS_EXPORT bool v_IsTimeDependent()
static const NekDouble kGeomFactorsTol
FilterFactory & GetFilterFactory()
Definition: Filter.cpp:42
boost::shared_ptr< ExpList3DHomogeneous1D > ExpList3DHomogeneous1DSharedPtr
Shared pointer to an ExpList3DHomogeneous1D object.
boost::shared_ptr< StdExpansion > StdExpansionSharedPtr
virtual SOLVER_UTILS_EXPORT void v_Update(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time)
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1047
boost::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:53
Abstraction of a two-dimensional multi-elemental expansion which is merely a collection of local expa...
std::list< std::pair< SpatialDomains::PointGeomSharedPtr, Array< OneD, NekDouble > > > m_historyList
boost::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:60
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, tDescription pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:215