38#include <boost/algorithm/string/classification.hpp>
39#include <boost/algorithm/string/predicate.hpp>
40#include <boost/algorithm/string/split.hpp>
107 if (
m_comm->GetRank() == 0)
119 if (
m_session->GetSolverInfo(
"EqType") ==
"UnsteadyNavierStokes" ||
120 m_session->GetSolverInfo(
"EqType") ==
"SteadyNavierStokes")
122 int nConvectiveFields =
m_session->GetVariables().size();
123 if (boost::iequals(
m_session->GetVariable(nConvectiveFields - 1),
"p"))
125 nConvectiveFields -= 1;
130 if (
m_session->GetSolverInfo(
"EqType") ==
"EulerCFE" ||
131 m_session->GetSolverInfo(
"EqType") ==
"NavierStokesCFE" ||
132 m_session->GetSolverInfo(
"EqType") ==
"NavierStokesImplicitCFE")
137 if (
m_session->DefinesSolverInfo(
"HOMOGENEOUS"))
139 if (
m_session->GetSolverInfo(
"HOMOGENEOUS") ==
"1D")
151 cout <<
"Besed on the dominant EV given in the xml file,"
152 <<
"a 1D model is used to evaluate the optumum parameters"
153 <<
"of the SFD method:" << endl;
165 ofstream
m_file(
"ConvergenceHistory.txt", ios::out | ios::trunc);
226 if (
m_comm->GetRank() == 0)
228 cout <<
"\n\t The SFD method is converging: we compute "
229 <<
"stability analysis using the 'partially "
230 <<
"converged' steady state as base flow:\n"
237 A->GetAdvObject()->SetBaseFlow(q0,
238 m_equ[0]->UpdateFields());
241 if (
m_comm->GetRank() == 0)
264 if (
m_comm->GetRank() == 0)
266 cout <<
"\n\t We compute stability analysis using"
267 <<
" the current flow field as base flow:\n"
274 A->GetAdvObject()->SetBaseFlow(q0,
275 m_equ[0]->UpdateFields());
278 if (
m_comm->GetRank() == 0)
315 for (
int j = 0; j <
m_equ[
m_nequ - 1]->GetNvariables(); ++j)
319 if (
m_comm->GetRank() == 0)
321 out <<
"L 2 error (variable " <<
m_equ[
m_nequ - 1]->GetVariable(j)
322 <<
") : " << vL2Error << endl;
323 out <<
"L inf error (variable " <<
m_equ[
m_nequ - 1]->GetVariable(j)
324 <<
") : " << vLinfError << endl;
340 NekDouble coeff = 1.0 / (1.0 + X * Delta);
341 M11 = coeff * (1.0 + X * Delta * exp(-(X + 1.0 / Delta)));
342 M12 = coeff * (X * Delta * (1.0 - exp(-(X + 1.0 / Delta))));
343 M21 = coeff * (1.0 - exp(-(X + 1.0 / Delta)));
344 M22 = coeff * (X * Delta + exp(-(X + 1.0 / Delta)));
363 Vmath::Svtvp(qBar1[i].size(),
M21, q0[i], 1, qBar1[i], 1, qBar1[i], 1);
364 Vmath::Svtvp(qBar1[i].size(),
M22, qBar0[i], 1, qBar1[i], 1, qBar1[i], 1);
379 cout <<
"\n\tgrowthEV = " << growthEV << endl;
380 cout <<
"\tfrequencyEV = " << frequencyEV << endl;
382 complex<NekDouble> ApproxEV = polar(exp(growthEV), frequencyEV);
404 cout <<
"\n\tWe enter the Gradient Descent Method [...]" << endl;
405 bool OptParmFound =
false;
406 bool Descending =
true;
424 while (OptParmFound ==
false)
432 s =
abs(0.000001 / dirx);
433 X_output = X_input + s * dirx;
434 Delta_output = Delta_input + s * diry;
437 while (Descending ==
true)
441 Delta_input = Delta_output;
451 X_output = X_input + s * dirx;
452 Delta_output = Delta_input + s * diry;
455 if (stepCounter > 9999999)
461 Delta_init = Delta_init + Delta_init * 0.1;
462 Delta_input = Delta_init;
468 if (
abs(F0 - F1) < dx)
470 cout <<
"\tThe Gradient Descent Method has converged!" << endl;
472 cout <<
"\n\tThe updated parameters are: X_tilde = " << X_output
473 <<
" and Delta_tilde = " << Delta_output << endl;
485 const complex<NekDouble> &alpha,
489 (1.0 + X_input * Delta_input * exp(-(X_input + 1.0 / Delta_input))) /
490 (1.0 + X_input * Delta_input);
492 (X_input * Delta_input -
493 X_input * Delta_input * exp(-(X_input + 1.0 / Delta_input))) /
494 (1.0 + X_input * Delta_input);
495 NekDouble A21 = (1.0 - 1.0 * exp(-(X_input + 1.0 / Delta_input))) /
496 (1 + X_input * Delta_input);
498 (X_input * Delta_input + 1.0 * exp(-(X_input + 1.0 / Delta_input))) /
499 (1.0 + X_input * Delta_input);
501 complex<NekDouble> B11 = alpha;
506 complex<NekDouble> a = A11 * B11 + A12 * B21;
508 complex<NekDouble> c = A21 * B11 + A22 * B21;
511 complex<NekDouble> delt =
sqrt((a -
d) * (a -
d) + 4.0 * b * c);
512 complex<NekDouble> lambda_1 = 0.5 * (a +
d + delt);
513 complex<NekDouble> lambda_2 = 0.5 * (a +
d - delt);
518 MaxEV = max(NORM_1, NORM_2);
530 int NumLinesInFile = 0;
531 std::string EVfileName =
m_session->GetSessionName() +
".evl";
532 std::ifstream EVfile(EVfileName.c_str());
533 ASSERTL0(EVfile.good(),
"Cannot open .evl file.");
539 while (getline(EVfile, line))
548 KrylovSubspaceDim * 2.0 +
549 KrylovSubspaceDim * (KrylovSubspaceDim + 1.0) / 2.0)
551 for (
int i = 1; i <= KrylovSubspaceDim; ++i)
553 if (NumLinesInFile == i * 2.0 + i * (i + 1.0) / 2.0)
555 KrylovSubspaceDim = i;
562 EVfile.seekg(0, ios::beg);
566 for (
int i = 0; i < (NumLinesInFile - KrylovSubspaceDim); ++i)
568 std::getline(EVfile, line);
569 cout <<
"Discard line: " << line << endl;
572 std::vector<std::string> tokens;
573 std::getline(EVfile, line);
574 boost::algorithm::split(tokens, line, boost::is_any_of(
"\t "),
575 boost::token_compress_on);
578 "Unexpected formatting of .evl file while reading line:\n" +
580 growthEV = boost::lexical_cast<NekDouble>(tokens[4]);
581 frequencyEV = boost::lexical_cast<NekDouble>(tokens[5]);
585 cout <<
"An error occurred when opening the .evl file" << endl;
601 MaxNormDiff_q_qBar = 0.0;
602 MaxNormDiff_q1_q0 = 0.0;
606 NormDiff_q_qBar[i] =
m_equ[
m_nequ - 1]->LinfError(i, qBar1[i]);
607 NormDiff_q1_q0[i] =
m_equ[
m_nequ - 1]->LinfError(i, q0[i]);
609 if (MaxNormDiff_q_qBar < NormDiff_q_qBar[i])
611 MaxNormDiff_q_qBar = NormDiff_q_qBar[i];
613 if (MaxNormDiff_q1_q0 < NormDiff_q1_q0[i])
615 MaxNormDiff_q1_q0 = NormDiff_q1_q0[i];
624 if (
m_comm->GetRank() == 0)
627 <<
";\tTime: " << left <<
m_equ[
m_nequ - 1]->GetFinalTime()
628 <<
";\tCPU time = " << left <<
cpuTime <<
" s"
629 <<
";\tTot time = " << left <<
totalTime <<
" s"
630 <<
";\tX = " << left <<
m_X <<
";\tDelta = " << left <<
m_Delta
631 <<
";\t|q-qBar|inf = " << left << MaxNormDiff_q_qBar << endl;
632 std::ofstream
m_file(
"ConvergenceHistory.txt", std::ios_base::app);
634 <<
"\t" <<
totalTime <<
"\t" << MaxNormDiff_q_qBar <<
"\t"
635 << MaxNormDiff_q1_q0 << endl;
648 cout <<
"\n====================================="
649 "=================================="
651 cout <<
"Parameters for the SFD method:" << endl;
652 cout <<
"\tControl Coefficient: X = " <<
m_X << endl;
653 cout <<
"\tFilter Width: Delta = " <<
m_Delta << endl;
654 cout <<
"The simulation is stopped when |q-qBar|inf < " <<
TOL << endl;
657 cout <<
"\nWe use the adaptive SFD method:" << endl;
658 cout <<
" The parameters are updated every " <<
AdaptiveTime
659 <<
" time units;" << endl;
660 cout <<
" until |q-qBar|inf becomes smaller than " <<
AdaptiveTOL
663 cout <<
"====================================="
664 "==================================\n"
#define ASSERTL0(condition, msg)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
static std::string RegisterEnumValue(std::string pEnum, std::string pString, int pEnumValue)
Registers an enumeration value.
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
A base class for PDEs which include an advection component.
LibUtilities::SessionReaderSharedPtr m_session
Session reader object.
LibUtilities::CommSharedPtr m_comm
Communication object.
enum EvolutionOperatorType m_EvolutionOperator
Evolution Operator.
Array< OneD, EquationSystemSharedPtr > m_equ
Equation system to solve.
int m_nequ
number of equations
virtual void v_InitObject(std::ostream &out=std::cout) override
Virtual function for initialisation implementation.
virtual void v_Execute(std::ostream &out=std::cout) override
Virtual function for solve implementation.
LibUtilities::Timer timer
static std::string driverLookupId
void ComputeSFD(const int i, const Array< OneD, const Array< OneD, NekDouble > > &q0, const Array< OneD, const Array< OneD, NekDouble > > &qBar0, Array< OneD, Array< OneD, NekDouble > > &q1, Array< OneD, Array< OneD, NekDouble > > &qBar1)
int m_NonConvergingStepsCounter
virtual SOLVER_UTILS_EXPORT void v_InitObject(std::ostream &out=std::cout) override
Initialises EquationSystem class members.
void ConvergenceHistory(const Array< OneD, const Array< OneD, NekDouble > > &qBar1, const Array< OneD, const Array< OneD, NekDouble > > &q0, NekDouble &MaxNormDiff_q_qBar, NekDouble &MaxNormDiff_q1_q0)
void ComputeOptimization()
static DriverSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Creates an instance of this class.
SOLVER_UTILS_EXPORT DriverSteadyState(const LibUtilities::SessionReaderSharedPtr pSession, const SpatialDomains::MeshGraphSharedPtr pGraph)
Constructor.
NekDouble m_Delta
Definition of the SFD parameters:
void SetSFDOperator(const NekDouble X_input, const NekDouble Delta_input)
NekDouble M11
Definition of the SFD operator.
virtual SOLVER_UTILS_EXPORT void v_Execute(std::ostream &out=std::cout) override
Virtual function for solve implementation.
void GradientDescentMethod(const std::complex< NekDouble > &alpha, NekDouble &X_output, NekDouble &Delta_output)
static std::string className
Name of the class.
void EvalEV_ScalarSFD(const NekDouble &X_input, const NekDouble &Delta_input, const std::complex< NekDouble > &alpha, NekDouble &MaxEV)
bool FlowPartiallyConverged
For adaptive SFD method.
void ReadEVfile(int &KrylovSubspaceDim, NekDouble &growthEV, NekDouble &frequencyEV)
std::shared_ptr< SessionReader > SessionReaderSharedPtr
DriverFactory & GetDriverFactory()
std::shared_ptr< AdvectionSystem > AdvectionSystemSharedPtr
Shared pointer to an AdvectionSystem class.
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
std::vector< double > d(NPUPPER *NPUPPER)
The above copyright notice and this permission notice shall be included.
void Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
svtvp (scalar times vector plus vector): z = alpha*x + y
scalarT< T > abs(scalarT< T > in)
scalarT< T > sqrt(scalarT< T > in)