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
42using namespace std;
43
44namespace Nektar
45{
46namespace SolverUtils
47{
51
52/**
53 * Constructor.
54 */
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 }
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
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 {
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 {
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 {
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 {
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 */
604void 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:47
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:55
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
static FilterSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const std::weak_ptr< EquationSystem > &pEquation, const ParamMap &pParams)
LibUtilities::FieldIOSharedPtr m_fld
SOLVER_UTILS_EXPORT FilterModalEnergy(const LibUtilities::SessionReaderSharedPtr &pSession, const std::weak_ptr< EquationSystem > &pEquation, const ParamMap &pParams)
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, SpatialDomains::MeshGraphSharedPtr partitionedGraph=nullptr)
Definition: MeshGraph.cpp:116
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:57
@ 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:270
FilterFactory & GetFilterFactory()
Definition: Filter.cpp:41
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:176
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:354
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:414