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
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 auto it = pParams.find("OutputFile");
59 if (it == pParams.end())
60 {
61 m_outputFile = m_session->GetSessionName();
62 }
63 else
64 {
65 ASSERTL0(it->second.length() > 0, "Missing parameter 'OutputFile'.");
66 m_outputFile = it->second;
67 }
68 if (!(m_outputFile.length() >= 4 &&
69 m_outputFile.substr(m_outputFile.length() - 4) == ".mdl"))
70 {
71 m_outputFile += ".mdl";
72 }
73
74 // OutputFrequency
75 it = pParams.find("OutputFrequency");
76 if (it == pParams.end())
77 {
79 }
80 else
81 {
82 LibUtilities::Equation equ(m_session->GetInterpreter(), it->second);
83 m_outputFrequency = round(equ.Evaluate());
84 }
85
86 m_session->MatchSolverInfo("Homogeneous", "1D", m_isHomogeneous1D, false);
87 m_session->MatchSolverInfo("Homogeneous", "2D", m_isHomogeneous2D, false);
88 m_session->MatchSolverInfo("CalculatePerturbationEnergy", "True",
89 m_PertEnergy, false);
90 m_session->LoadParameter("NumQuadPointsError", m_NumQuadPointsError, 0);
91 m_EqTypeStr = m_session->GetSolverInfo("EQTYPE");
92
93 // OutputPlane
95 {
96 m_session->LoadParameter("LZ", m_LhomZ);
97
98 it = pParams.find("OutputPlane");
99 if (it == pParams.end())
100 {
101 m_outputPlane = 0;
102 }
103 else
104 {
105 LibUtilities::Equation equ(m_session->GetInterpreter(), it->second);
106 m_outputPlane = round(equ.Evaluate());
107 }
108 }
109
111}
112
113/**
114 * Destructor.
115 */
117{
118}
119
120/**
121 * Initialize the parallel communication and the output stream.
122 */
125 const NekDouble &time)
126{
127 LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
128
129 if (vComm->GetRank() == 0)
130 {
131 // Open output stream
132 bool adaptive;
133 m_session->MatchSolverInfo("Driver", "Adaptive", adaptive, false);
134 if (adaptive)
135 {
136 m_outputStream.open(m_outputFile.c_str(), ofstream::app);
137 }
138 else
139 {
140 m_outputStream.open(m_outputFile.c_str());
141 }
143 {
144 m_outputStream << "# Time, Fourier Mode, Energy ";
145 m_outputStream << endl;
146 }
147 else
148 {
149 m_outputStream << "# Time, Energy ";
150 m_outputStream << endl;
151 }
152 }
153
154 m_index = 0;
155 v_Update(pFields, time);
156}
157
158/**
159 * Update the modal energy every m_outputFrequency.
160 */
163 const NekDouble &time)
164{
165 // Only output every m_outputFrequency
166 if ((m_index++) % m_outputFrequency)
167 {
168 return;
169 }
170
171 LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
172
173 // Homogeneous 1D implementation
175 {
176 int colrank = vComm->GetColumnComm()->GetRank();
177 int nproc = vComm->GetColumnComm()->GetSize();
178 m_npointsZ = (m_session->GetParameter("HomModesZ"));
179 int locsize = m_npointsZ / nproc / 2;
180
181 Array<OneD, NekDouble> energy(locsize, 0.0);
182 Array<OneD, NekDouble> energy_tmp(locsize, 0.0);
184
185 // Calculate the energy of the perturbation for stability
186 // analysis
187 if (m_PertEnergy)
188 {
189 // Compressible Flow Solver
190 if (m_EqTypeStr == "EulerCFE" || m_EqTypeStr == "EulerADCFE" ||
191 m_EqTypeStr == "NavierStokesCFE")
192 {
193 ASSERTL0(false, "Stability analysis module not "
194 "implemented for the Compressible Flow "
195 "Solver. Please remove the function BaseFlow "
196 "from your .xml file");
197 }
198 // Incompressible Navier-Stokes Solver
199 else
200 {
203 SetUpBaseFields(graphShrPtr);
204 string file = m_session->GetFunctionFilename("BaseFlow", 0);
205 ImportFldBase(file);
206
207 for (int i = 0; i < pFields.size() - 1; ++i)
208 {
209 Vmath::Vsub(pFields[i]->GetNcoeffs(),
210 pFields[i]->GetCoeffs(), 1,
211 m_base[i]->GetCoeffs(), 1,
212 pFields[i]->UpdateCoeffs(), 1);
213
214 energy_tmp = pFields[i]->HomogeneousEnergy();
215 Vmath::Vadd(locsize, energy_tmp, 1, energy, 1, energy, 1);
216
217 Vmath::Vadd(pFields[i]->GetNcoeffs(),
218 pFields[i]->GetCoeffs(), 1,
219 m_base[i]->GetCoeffs(), 1,
220 pFields[i]->UpdateCoeffs(), 1);
221 }
222 }
223 }
224 // Calculate the modal energy for general simulation
225 else
226 {
227 // Compressible Flow Solver
228 if (m_EqTypeStr == "EulerCFE" || m_EqTypeStr == "EulerADCFE" ||
229 m_EqTypeStr == "NavierStokesCFE")
230 {
231 // Extracting kinetic energy
232 for (int i = 1; i < pFields.size() - 1; ++i)
233 {
234 energy_tmp = pFields[i]->HomogeneousEnergy();
235 Vmath::Vadd(locsize, energy_tmp, 1, energy, 1, energy, 1);
236 }
237 }
238 // Incompressible Navier-Stokes Solver
239 else
240 {
241 // Extracting kinetic energy
242 for (int i = 0; i < pFields.size() - 1; ++i)
243 {
244 energy_tmp = pFields[i]->HomogeneousEnergy();
245 Vmath::Vadd(locsize, energy_tmp, 1, energy, 1, energy, 1);
246 }
247 }
248 }
249
250 // Send to root process
251 if (colrank == 0)
252 {
253 int j, m = 0;
254
255 for (j = 0; j < energy.size(); ++j, ++m)
256 {
257 m_outputStream << setw(10) << time << setw(5) << m << setw(18)
258 << energy[j] << endl;
259 }
260
261 for (int i = 1; i < nproc; ++i)
262 {
263 vComm->GetColumnComm()->Recv(i, energy);
264
265 for (j = 0; j < energy.size(); ++j, ++m)
266 {
267 m_outputStream << setw(10) << time << setw(5) << m
268 << setw(18) << energy[j] << endl;
269 }
270 }
271 }
272 else
273 {
274 vComm->GetColumnComm()->Send(0, energy);
275 }
276 }
277 // Homogeneous 2D implementation
278 else if (m_isHomogeneous2D)
279 {
280 ASSERTL0(false, "3D Homogeneous 2D energy "
281 "dumping not implemented yet");
282 }
283 // General implementation
284 else
285 {
286 // Compressible Flow Solver
287 if (m_EqTypeStr == "EulerCFE" || m_EqTypeStr == "EulerADCFE" ||
288 m_EqTypeStr == "NavierStokesCFE")
289 {
290 // Total energy
291 NekDouble energy = 0.0;
292 for (int i = 1; i < pFields.size() - 1; ++i)
293 {
294 pFields[i]->SetPhysState(true);
295 NekDouble norm = L2Error(pFields, i, time);
296 energy += norm * norm;
297 }
298
299 m_outputStream << setprecision(6) << time;
300 m_outputStream.width(25);
301 m_outputStream << setprecision(8) << 0.5 * energy;
302 m_outputStream << endl;
303 }
304 // Incompressible Navier-Stokes Solver
305 else
306 {
307 // Kinetic energy
308 NekDouble energy = 0.0;
309 for (int i = 0; i < pFields.size() - 1; ++i)
310 {
311 pFields[i]->SetPhysState(true);
312 NekDouble norm = L2Error(pFields, i, time);
313 energy += norm * norm;
314 }
315 m_outputStream << setprecision(6) << time;
316 m_outputStream.width(25);
317 m_outputStream << setprecision(8) << 0.5 * energy;
318 m_outputStream << endl;
319 }
320 }
321}
322
323/**
324 * Close the output stream.
325 */
328 [[maybe_unused]] const NekDouble &time)
329{
330 if (pFields[0]->GetComm()->GetRank() == 0)
331 {
332 m_outputStream.close();
333 }
334}
335
336/**
337 * Calculate the L2 norm of a given field for calculating the
338 * modal energy.
339 */
342 unsigned int field, [[maybe_unused]] const NekDouble &time)
343{
344 NekDouble L2error = -1.0;
345 LibUtilities::CommSharedPtr vComm = pFields[0]->GetComm();
346
347 if (m_NumQuadPointsError == 0)
348 {
349 if (pFields[field]->GetPhysState() == false)
350 {
351 pFields[field]->BwdTrans(pFields[field]->GetCoeffs(),
352 pFields[field]->UpdatePhys());
353 }
354 }
355
356 L2error = pFields[field]->L2(pFields[field]->GetPhys());
357 return L2error;
358}
359
360/**
361 * Setup the base fields in case of stability analyses.
362 */
365{
366 int i;
367 int m_expdim = graphShrPtr->GetMeshDimension();
368
369 // definition of the projection tipe:
370 if (m_session->DefinesSolverInfo("PROJECTION"))
371 {
372 std::string ProjectStr = m_session->GetSolverInfo("PROJECTION");
373
374 if ((ProjectStr == "Continuous") || (ProjectStr == "Galerkin") ||
375 (ProjectStr == "CONTINUOUS") || (ProjectStr == "GALERKIN"))
376 {
378 }
379 else if ((ProjectStr == "MixedCGDG") ||
380 (ProjectStr == "Mixed_CG_Discontinuous"))
381 {
383 }
384 else if (ProjectStr == "DisContinuous")
385 {
387 }
388 else
389 {
390 ASSERTL0(false, "PROJECTION value not recognised");
391 }
392 }
393 else
394 {
395 cerr << "Projection type not specified in SOLVERINFO,"
396 "defaulting to continuous Galerkin"
397 << endl;
399 }
400
401 if (m_session->DefinesSolverInfo("ModeType"))
402 {
403 m_session->MatchSolverInfo("ModeType", "SingleMode", m_SingleMode,
404 false);
405 m_session->MatchSolverInfo("ModeType", "HalfMode", m_HalfMode, false);
406 m_session->MatchSolverInfo("ModeType", "MultipleModes", m_MultipleModes,
407 false);
408 }
409
410 m_session->MatchSolverInfo("USEFFT", "FFTW", m_useFFT, false);
411 m_session->MatchSolverInfo("DEALIASING", "True", m_homogen_dealiasing,
412 false);
413
414 // Stability Analysis flags
415 if (m_session->DefinesSolverInfo("ModeType"))
416 {
417 if (m_SingleMode)
418 {
419 m_npointsZ = 2;
420 }
421 else if (m_HalfMode)
422 {
423 m_npointsZ = 1;
424 }
425 else if (m_MultipleModes)
426 {
427 m_npointsZ = m_session->GetParameter("HomModesZ");
428 }
429 else
430 {
431 ASSERTL0(false, "SolverInfo ModeType not valid");
432 }
433 }
434 else
435 {
436 m_npointsZ = m_session->GetParameter("HomModesZ");
437 }
438
441 {
442 switch (m_expdim)
443 {
444 case 1:
445 {
446 for (i = 0; i < m_base.size(); i++)
447 {
449 AllocateSharedPtr(m_session, graphShrPtr,
450 m_session->GetVariable(0));
451 }
452 }
453 break;
454 case 2:
455 {
457 {
458 if (m_SingleMode)
459 {
460 const LibUtilities::PointsKey PkeyZ(
462 const LibUtilities::BasisKey BkeyZ(
464
465 for (i = 0; i < m_base.size(); i++)
466 {
469 AllocateSharedPtr(
470 m_session, BkeyZ, m_LhomZ, m_useFFT,
471 m_homogen_dealiasing, graphShrPtr,
472 m_session->GetVariable(i));
473
474 m_base[i]->SetWaveSpace(true);
475 }
476 }
477 else if (m_HalfMode)
478 {
479 // 1 plane field (half mode expansion)
480 const LibUtilities::PointsKey PkeyZ(
482 const LibUtilities::BasisKey BkeyZ(
484 PkeyZ);
485
486 for (i = 0; i < m_base.size(); i++)
487 {
490 AllocateSharedPtr(
491 m_session, BkeyZ, m_LhomZ, m_useFFT,
492 m_homogen_dealiasing, graphShrPtr,
493 m_session->GetVariable(i));
494
495 m_base[i]->SetWaveSpace(true);
496 }
497 }
498 else
499 {
500 const LibUtilities::PointsKey PkeyZ(
502 const LibUtilities::BasisKey BkeyZ(
504
505 for (i = 0; i < m_base.size(); i++)
506 {
509 AllocateSharedPtr(
510 m_session, BkeyZ, m_LhomZ, m_useFFT,
511 m_homogen_dealiasing, graphShrPtr,
512 m_session->GetVariable(i));
513
514 m_base[i]->SetWaveSpace(false);
515 }
516 }
517 }
518 else
519 {
520 i = 0;
523 AllocateSharedPtr(m_session, graphShrPtr,
524 m_session->GetVariable(i));
525
526 m_base[0] = firstbase;
527
528 for (i = 1; i < m_base.size(); i++)
529 {
531 AllocateSharedPtr(*firstbase, graphShrPtr,
532 m_session->GetVariable(i));
533 }
534 }
535 }
536 break;
537 case 3:
538 {
541 m_session, graphShrPtr, m_session->GetVariable(0));
542 m_base[0] = firstbase;
543 for (i = 1; i < m_base.size(); i++)
544 {
546 AllocateSharedPtr(*firstbase, graphShrPtr,
547 m_session->GetVariable(0));
548 }
549 }
550 break;
551 default:
553 "Expansion dimension not recognised");
554 break;
555 }
556 }
557 else
558 {
559 switch (m_expdim)
560 {
561 case 1:
562 {
563 // need to use zero for variable as may be more base
564 // flows than variables
565 for (i = 0; i < m_base.size(); i++)
566 {
568 AllocateSharedPtr(m_session, graphShrPtr,
569 m_session->GetVariable(0));
570 }
571 break;
572 }
573 case 2:
574 {
575 for (i = 0; i < m_base.size(); i++)
576 {
578 AllocateSharedPtr(m_session, graphShrPtr,
579 m_session->GetVariable(0));
580 }
581 break;
582 }
583 case 3:
584 NEKERROR(ErrorUtil::efatal, "3D not set up");
585 break;
586 default:
588 "Expansion dimension not recognised");
589 break;
590 }
591 }
592}
593
594/**
595 * Import the base flow fld file.
596 */
597void FilterModalEnergy::ImportFldBase(std::string pInfile)
598{
599 std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef;
600 std::vector<std::vector<NekDouble>> FieldData;
601
602 // Get Homogeneous
603 m_fld->Import(pInfile, FieldDef, FieldData);
604
605 int nvar = m_session->GetVariables().size();
606 if (m_session->DefinesSolverInfo("HOMOGENEOUS"))
607 {
608 std::string HomoStr = m_session->GetSolverInfo("HOMOGENEOUS");
609 }
610 // Copy FieldData into m_fields
611 for (int j = 0; j < nvar; ++j)
612 {
613 for (int i = 0; i < FieldDef.size(); ++i)
614 {
615 bool flag = FieldDef[i]->m_fields[j] == m_session->GetVariable(j);
616
617 ASSERTL0(flag, (std::string("Order of ") + pInfile +
618 std::string(" data and that defined in "
619 "m_boundaryconditions differs"))
620 .c_str());
621
622 m_base[j]->ExtractDataToCoeffs(FieldDef[i], FieldData[i],
623 FieldDef[i]->m_fields[j],
624 m_base[j]->UpdateCoeffs());
625 }
626 }
627}
628
629/**
630 * Flag for time-dependent flows.
631 */
633{
634 return true;
635}
636} // namespace Nektar::SolverUtils
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:202
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:195
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.
LibUtilities::SessionReaderSharedPtr m_session
Definition: Filter.h:83
std::map< std::string, std::string > ParamMap
Definition: Filter.h:65
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)
SOLVER_UTILS_EXPORT ~FilterModalEnergy() override
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)
Definition: MeshGraphIO.cpp:53
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:66
@ eFourier
Fourier Expansion .
Definition: BasisType.h:55
std::shared_ptr< ContField > ContFieldSharedPtr
Definition: ContField.h:268
FilterFactory & GetFilterFactory()
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
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.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.