Nektar++
FilterModalEnergy.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: FilterModalEnergy.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: Output values of the modal energy
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #include <iomanip>
36 
37 #include <boost/core/ignore_unused.hpp>
38 
41 
42 using namespace std;
43 
44 namespace Nektar
45 {
46 namespace SolverUtils
47 {
48 std::string FilterModalEnergy::className =
50  FilterModalEnergy::create);
51 
52 /**
53  * Constructor.
54  */
55 FilterModalEnergy::FilterModalEnergy(
57  const std::weak_ptr<EquationSystem> &pEquation, const ParamMap &pParams)
58  : Filter(pSession, pEquation)
59 {
60  // OutputFile
61  auto it = pParams.find("OutputFile");
62  if (it == pParams.end())
63  {
64  m_outputFile = m_session->GetSessionName();
65  }
66  else
67  {
68  ASSERTL0(it->second.length() > 0, "Missing parameter 'OutputFile'.");
69  m_outputFile = it->second;
70  }
71  if (!(m_outputFile.length() >= 4 &&
72  m_outputFile.substr(m_outputFile.length() - 4) == ".mdl"))
73  {
74  m_outputFile += ".mdl";
75  }
76 
77  // OutputFrequency
78  it = pParams.find("OutputFrequency");
79  if (it == pParams.end())
80  {
82  }
83  else
84  {
85  LibUtilities::Equation equ(m_session->GetInterpreter(), it->second);
86  m_outputFrequency = round(equ.Evaluate());
87  }
88 
89  m_session->MatchSolverInfo("Homogeneous", "1D", m_isHomogeneous1D, false);
90  m_session->MatchSolverInfo("Homogeneous", "2D", m_isHomogeneous2D, false);
91  m_session->MatchSolverInfo("CalculatePerturbationEnergy", "True",
92  m_PertEnergy, false);
93  m_session->LoadParameter("NumQuadPointsError", m_NumQuadPointsError, 0);
94  m_EqTypeStr = m_session->GetSolverInfo("EQTYPE");
95 
96  // OutputPlane
98  {
99  m_session->LoadParameter("LZ", m_LhomZ);
100 
101  it = pParams.find("OutputPlane");
102  if (it == pParams.end())
103  {
104  m_outputPlane = 0;
105  }
106  else
107  {
108  LibUtilities::Equation equ(m_session->GetInterpreter(), it->second);
109  m_outputPlane = round(equ.Evaluate());
110  }
111  }
112 
114 }
115 
116 /**
117  * Destructor.
118  */
120 {
121 }
122 
123 /**
124  * Initialize the parallel communication and the output stream.
125  */
128  const NekDouble &time)
129 {
130  LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
131 
132  if (vComm->GetRank() == 0)
133  {
134  // Open output stream
135  bool adaptive;
136  m_session->MatchSolverInfo("Driver", "Adaptive", adaptive, false);
137  if (adaptive)
138  {
139  m_outputStream.open(m_outputFile.c_str(), ofstream::app);
140  }
141  else
142  {
143  m_outputStream.open(m_outputFile.c_str());
144  }
145  if (m_isHomogeneous1D)
146  {
147  m_outputStream << "# Time, Fourier Mode, Energy ";
148  m_outputStream << endl;
149  }
150  else
151  {
152  m_outputStream << "# Time, Energy ";
153  m_outputStream << endl;
154  }
155  }
156 
157  m_index = 0;
158  v_Update(pFields, time);
159 }
160 
161 /**
162  * Update the modal energy every m_outputFrequency.
163  */
166  const NekDouble &time)
167 {
168  // Only output every m_outputFrequency
169  if ((m_index++) % m_outputFrequency)
170  {
171  return;
172  }
173 
174  LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
175 
176  // Homogeneous 1D implementation
177  if (m_isHomogeneous1D)
178  {
179  int colrank = vComm->GetColumnComm()->GetRank();
180  int nproc = vComm->GetColumnComm()->GetSize();
181  m_npointsZ = (m_session->GetParameter("HomModesZ"));
182  int locsize = m_npointsZ / nproc / 2;
183 
184  Array<OneD, NekDouble> energy(locsize, 0.0);
185  Array<OneD, NekDouble> energy_tmp(locsize, 0.0);
187 
188  // Calculate the energy of the perturbation for stability
189  // analysis
190  if (m_PertEnergy)
191  {
192  // Compressible Flow Solver
193  if (m_EqTypeStr == "EulerCFE" || m_EqTypeStr == "EulerADCFE" ||
194  m_EqTypeStr == "NavierStokesCFE")
195  {
196  ASSERTL0(false, "Stability analysis module not "
197  "implemented for the Compressible Flow "
198  "Solver. Please remove the function BaseFlow "
199  "from your .xml file");
200  }
201  // Incompressible Navier-Stokes Solver
202  else
203  {
206  SetUpBaseFields(graphShrPtr);
207  string file = m_session->GetFunctionFilename("BaseFlow", 0);
208  ImportFldBase(file);
209 
210  for (int i = 0; i < pFields.size() - 1; ++i)
211  {
212  Vmath::Vsub(pFields[i]->GetNcoeffs(),
213  pFields[i]->GetCoeffs(), 1,
214  m_base[i]->GetCoeffs(), 1,
215  pFields[i]->UpdateCoeffs(), 1);
216 
217  energy_tmp = pFields[i]->HomogeneousEnergy();
218  Vmath::Vadd(locsize, energy_tmp, 1, energy, 1, energy, 1);
219 
220  Vmath::Vadd(pFields[i]->GetNcoeffs(),
221  pFields[i]->GetCoeffs(), 1,
222  m_base[i]->GetCoeffs(), 1,
223  pFields[i]->UpdateCoeffs(), 1);
224  }
225  }
226  }
227  // Calculate the modal energy for general simulation
228  else
229  {
230  // Compressible Flow Solver
231  if (m_EqTypeStr == "EulerCFE" || m_EqTypeStr == "EulerADCFE" ||
232  m_EqTypeStr == "NavierStokesCFE")
233  {
234  // Extracting kinetic energy
235  for (int i = 1; i < pFields.size() - 1; ++i)
236  {
237  energy_tmp = pFields[i]->HomogeneousEnergy();
238  Vmath::Vadd(locsize, energy_tmp, 1, energy, 1, energy, 1);
239  }
240  }
241  // Incompressible Navier-Stokes Solver
242  else
243  {
244  // Extracting kinetic energy
245  for (int i = 0; i < pFields.size() - 1; ++i)
246  {
247  energy_tmp = pFields[i]->HomogeneousEnergy();
248  Vmath::Vadd(locsize, energy_tmp, 1, energy, 1, energy, 1);
249  }
250  }
251  }
252 
253  // Send to root process
254  if (colrank == 0)
255  {
256  int j, m = 0;
257 
258  for (j = 0; j < energy.size(); ++j, ++m)
259  {
260  m_outputStream << setw(10) << time << setw(5) << m << setw(18)
261  << energy[j] << endl;
262  }
263 
264  for (int i = 1; i < nproc; ++i)
265  {
266  vComm->GetColumnComm()->Recv(i, energy);
267 
268  for (j = 0; j < energy.size(); ++j, ++m)
269  {
270  m_outputStream << setw(10) << time << setw(5) << m
271  << setw(18) << energy[j] << endl;
272  }
273  }
274  }
275  else
276  {
277  vComm->GetColumnComm()->Send(0, energy);
278  }
279  }
280  // Homogeneous 2D implementation
281  else if (m_isHomogeneous2D)
282  {
283  ASSERTL0(false, "3D Homogeneous 2D energy "
284  "dumping not implemented yet");
285  }
286  // General implementation
287  else
288  {
289  // Compressible Flow Solver
290  if (m_EqTypeStr == "EulerCFE" || m_EqTypeStr == "EulerADCFE" ||
291  m_EqTypeStr == "NavierStokesCFE")
292  {
293  // Total energy
294  NekDouble energy = 0.0;
295  for (int i = 1; i < pFields.size() - 1; ++i)
296  {
297  pFields[i]->SetPhysState(true);
298  NekDouble norm = L2Error(pFields, i, time);
299  energy += norm * norm;
300  }
301 
302  m_outputStream << setprecision(6) << time;
303  m_outputStream.width(25);
304  m_outputStream << setprecision(8) << 0.5 * energy;
305  m_outputStream << endl;
306  }
307  // Incompressible Navier-Stokes Solver
308  else
309  {
310  // Kinetic energy
311  NekDouble energy = 0.0;
312  for (int i = 0; i < pFields.size() - 1; ++i)
313  {
314  pFields[i]->SetPhysState(true);
315  NekDouble norm = L2Error(pFields, i, time);
316  energy += norm * norm;
317  }
318  m_outputStream << setprecision(6) << time;
319  m_outputStream.width(25);
320  m_outputStream << setprecision(8) << 0.5 * energy;
321  m_outputStream << endl;
322  }
323  }
324 }
325 
326 /**
327  * Close the output stream.
328  */
331  const NekDouble &time)
332 {
333  boost::ignore_unused(time);
334 
335  if (pFields[0]->GetComm()->GetRank() == 0)
336  {
337  m_outputStream.close();
338  }
339 }
340 
341 /**
342  * Calculate the L2 norm of a given field for calculating the
343  * modal energy.
344  */
347  unsigned int field, const NekDouble &time)
348 {
349  boost::ignore_unused(time);
350 
351  NekDouble L2error = -1.0;
352  LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
353 
354  if (m_NumQuadPointsError == 0)
355  {
356  if (pFields[field]->GetPhysState() == false)
357  {
358  pFields[field]->BwdTrans(pFields[field]->GetCoeffs(),
359  pFields[field]->UpdatePhys());
360  }
361  }
362 
363  L2error = pFields[field]->L2(pFields[field]->GetPhys());
364  return L2error;
365 }
366 
367 /**
368  * Setup the base fields in case of stability analyses.
369  */
372 {
373  int i;
374  int m_expdim = graphShrPtr->GetMeshDimension();
375 
376  // definition of the projection tipe:
377  if (m_session->DefinesSolverInfo("PROJECTION"))
378  {
379  std::string ProjectStr = m_session->GetSolverInfo("PROJECTION");
380 
381  if ((ProjectStr == "Continuous") || (ProjectStr == "Galerkin") ||
382  (ProjectStr == "CONTINUOUS") || (ProjectStr == "GALERKIN"))
383  {
385  }
386  else if ((ProjectStr == "MixedCGDG") ||
387  (ProjectStr == "Mixed_CG_Discontinuous"))
388  {
390  }
391  else if (ProjectStr == "DisContinuous")
392  {
394  }
395  else
396  {
397  ASSERTL0(false, "PROJECTION value not recognised");
398  }
399  }
400  else
401  {
402  cerr << "Projection type not specified in SOLVERINFO,"
403  "defaulting to continuous Galerkin"
404  << endl;
406  }
407 
408  if (m_session->DefinesSolverInfo("ModeType"))
409  {
410  m_session->MatchSolverInfo("ModeType", "SingleMode", m_SingleMode,
411  false);
412  m_session->MatchSolverInfo("ModeType", "HalfMode", m_HalfMode, false);
413  m_session->MatchSolverInfo("ModeType", "MultipleModes", m_MultipleModes,
414  false);
415  }
416 
417  m_session->MatchSolverInfo("USEFFT", "FFTW", m_useFFT, false);
418  m_session->MatchSolverInfo("DEALIASING", "True", m_homogen_dealiasing,
419  false);
420 
421  // Stability Analysis flags
422  if (m_session->DefinesSolverInfo("ModeType"))
423  {
424  if (m_SingleMode)
425  {
426  m_npointsZ = 2;
427  }
428  else if (m_HalfMode)
429  {
430  m_npointsZ = 1;
431  }
432  else if (m_MultipleModes)
433  {
434  m_npointsZ = m_session->GetParameter("HomModesZ");
435  }
436  else
437  {
438  ASSERTL0(false, "SolverInfo ModeType not valid");
439  }
440  }
441  else
442  {
443  m_npointsZ = m_session->GetParameter("HomModesZ");
444  }
445 
448  {
449  switch (m_expdim)
450  {
451  case 1:
452  {
453  for (i = 0; i < m_base.size(); i++)
454  {
456  AllocateSharedPtr(m_session, graphShrPtr,
457  m_session->GetVariable(0));
458  }
459  }
460  break;
461  case 2:
462  {
463  if (m_isHomogeneous1D)
464  {
465  if (m_SingleMode)
466  {
467  const LibUtilities::PointsKey PkeyZ(
469  const LibUtilities::BasisKey BkeyZ(
471 
472  for (i = 0; i < m_base.size(); i++)
473  {
474  m_base[i] = MemoryManager<
476  AllocateSharedPtr(
477  m_session, BkeyZ, m_LhomZ, m_useFFT,
478  m_homogen_dealiasing, graphShrPtr,
479  m_session->GetVariable(i));
480 
481  m_base[i]->SetWaveSpace(true);
482  }
483  }
484  else if (m_HalfMode)
485  {
486  // 1 plane field (half mode expansion)
487  const LibUtilities::PointsKey PkeyZ(
489  const LibUtilities::BasisKey BkeyZ(
491  PkeyZ);
492 
493  for (i = 0; i < m_base.size(); i++)
494  {
495  m_base[i] = MemoryManager<
497  AllocateSharedPtr(
498  m_session, BkeyZ, m_LhomZ, m_useFFT,
499  m_homogen_dealiasing, graphShrPtr,
500  m_session->GetVariable(i));
501 
502  m_base[i]->SetWaveSpace(true);
503  }
504  }
505  else
506  {
507  const LibUtilities::PointsKey PkeyZ(
509  const LibUtilities::BasisKey BkeyZ(
511 
512  for (i = 0; i < m_base.size(); i++)
513  {
514  m_base[i] = MemoryManager<
516  AllocateSharedPtr(
517  m_session, BkeyZ, m_LhomZ, m_useFFT,
518  m_homogen_dealiasing, graphShrPtr,
519  m_session->GetVariable(i));
520 
521  m_base[i]->SetWaveSpace(false);
522  }
523  }
524  }
525  else
526  {
527  i = 0;
530  AllocateSharedPtr(m_session, graphShrPtr,
531  m_session->GetVariable(i));
532 
533  m_base[0] = firstbase;
534 
535  for (i = 1; i < m_base.size(); i++)
536  {
538  AllocateSharedPtr(*firstbase, graphShrPtr,
539  m_session->GetVariable(i));
540  }
541  }
542  }
543  break;
544  case 3:
545  {
548  m_session, graphShrPtr, m_session->GetVariable(0));
549  m_base[0] = firstbase;
550  for (i = 1; i < m_base.size(); i++)
551  {
553  AllocateSharedPtr(*firstbase, graphShrPtr,
554  m_session->GetVariable(0));
555  }
556  }
557  break;
558  default:
560  "Expansion dimension not recognised");
561  break;
562  }
563  }
564  else
565  {
566  switch (m_expdim)
567  {
568  case 1:
569  {
570  // need to use zero for variable as may be more base
571  // flows than variables
572  for (i = 0; i < m_base.size(); i++)
573  {
575  AllocateSharedPtr(m_session, graphShrPtr,
576  m_session->GetVariable(0));
577  }
578  break;
579  }
580  case 2:
581  {
582  for (i = 0; i < m_base.size(); i++)
583  {
585  AllocateSharedPtr(m_session, graphShrPtr,
586  m_session->GetVariable(0));
587  }
588  break;
589  }
590  case 3:
591  NEKERROR(ErrorUtil::efatal, "3D not set up");
592  break;
593  default:
595  "Expansion dimension not recognised");
596  break;
597  }
598  }
599 }
600 
601 /**
602  * Import the base flow fld file.
603  */
604 void FilterModalEnergy::ImportFldBase(std::string pInfile)
605 {
606  std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef;
607  std::vector<std::vector<NekDouble>> FieldData;
608 
609  // Get Homogeneous
610  m_fld->Import(pInfile, FieldDef, FieldData);
611 
612  int nvar = m_session->GetVariables().size();
613  if (m_session->DefinesSolverInfo("HOMOGENEOUS"))
614  {
615  std::string HomoStr = m_session->GetSolverInfo("HOMOGENEOUS");
616  }
617  // Copy FieldData into m_fields
618  for (int j = 0; j < nvar; ++j)
619  {
620  for (int i = 0; i < FieldDef.size(); ++i)
621  {
622  bool flag = FieldDef[i]->m_fields[j] == m_session->GetVariable(j);
623 
624  ASSERTL0(flag, (std::string("Order of ") + pInfile +
625  std::string(" data and that defined in "
626  "m_boundaryconditions differs"))
627  .c_str());
628 
629  m_base[j]->ExtractDataToCoeffs(FieldDef[i], FieldData[i],
630  FieldDef[i]->m_fields[j],
631  m_base[j]->UpdateCoeffs());
632  }
633  }
634 }
635 
636 /**
637  * Flag for time-dependent flows.
638  */
640 {
641  return true;
642 }
643 } // namespace SolverUtils
644 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
Describes the specification for a Basis.
Definition: Basis.h:50
static std::shared_ptr< FieldIO > CreateDefault(const LibUtilities::SessionReaderSharedPtr session)
Returns an object for the default FieldIO method.
Definition: FieldIO.cpp:197
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
Defines a specification for a set of points.
Definition: Points.h:59
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
LibUtilities::SessionReaderSharedPtr m_session
Definition: Filter.h:85
std::map< std::string, std::string > ParamMap
Definition: Filter.h:67
virtual void v_Initialise(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
virtual void v_Finalise(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
virtual void v_Update(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
enum MultiRegions::ProjectionType m_projectionType
LibUtilities::FieldIOSharedPtr m_fld
NekDouble L2Error(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, unsigned int field, const NekDouble &time)
Array< OneD, MultiRegions::ExpListSharedPtr > m_base
virtual SOLVER_UTILS_EXPORT ~FilterModalEnergy()
void SetUpBaseFields(SpatialDomains::MeshGraphSharedPtr &mesh)
static MeshGraphSharedPtr Read(const LibUtilities::SessionReaderSharedPtr pSession, LibUtilities::DomainRangeShPtr rng=LibUtilities::NullDomainRangeShPtr, bool fillGraph=true)
Definition: MeshGraph.cpp:111
std::shared_ptr< SessionReader > SessionReaderSharedPtr
@ eFourierEvenlySpaced
1D Evenly-spaced points using Fourier Fit
Definition: PointsType.h:76
@ eFourierSingleModeSpaced
1D Non Evenly-spaced points for Single Mode analysis
Definition: PointsType.h:77
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:54
@ eFourierHalfModeRe
Fourier Modified expansions with just the real part of the first mode .
Definition: BasisType.h:68
@ eFourier
Fourier Expansion .
Definition: BasisType.h:57
std::shared_ptr< ContField > ContFieldSharedPtr
Definition: ContField.h:289
FilterFactory & GetFilterFactory()
Definition: Filter.cpp:41
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:172
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition: Vmath.cpp:359
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition: Vmath.cpp:419