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