38#include <boost/algorithm/string/classification.hpp>
39#include <boost/algorithm/string/predicate.hpp>
40#include <boost/algorithm/string/split.hpp>
105 if (
m_comm->GetRank() == 0)
117 if (
m_session->GetSolverInfo(
"EqType") ==
"UnsteadyNavierStokes" ||
118 m_session->GetSolverInfo(
"EqType") ==
"SteadyNavierStokes")
120 int nConvectiveFields =
m_session->GetVariables().size();
121 if (boost::iequals(
m_session->GetVariable(nConvectiveFields - 1),
"p"))
123 nConvectiveFields -= 1;
128 if (
m_session->GetSolverInfo(
"EqType") ==
"EulerCFE" ||
129 m_session->GetSolverInfo(
"EqType") ==
"NavierStokesCFE" ||
130 m_session->GetSolverInfo(
"EqType") ==
"NavierStokesImplicitCFE")
135 if (
m_session->DefinesSolverInfo(
"HOMOGENEOUS"))
137 if (
m_session->GetSolverInfo(
"HOMOGENEOUS") ==
"1D")
149 cout <<
"Besed on the dominant EV given in the xml file,"
150 <<
"a 1D model is used to evaluate the optumum parameters"
151 <<
"of the SFD method:" << endl;
163 ofstream
m_file(
"ConvergenceHistory.txt", ios::out | ios::trunc);
224 if (
m_comm->GetRank() == 0)
226 cout <<
"\n\t The SFD method is converging: we compute "
227 <<
"stability analysis using the 'partially "
228 <<
"converged' steady state as base flow:\n"
235 A->GetAdvObject()->SetBaseFlow(q0,
236 m_equ[0]->UpdateFields());
239 if (
m_comm->GetRank() == 0)
262 if (
m_comm->GetRank() == 0)
264 cout <<
"\n\t We compute stability analysis using"
265 <<
" the current flow field as base flow:\n"
272 A->GetAdvObject()->SetBaseFlow(q0,
273 m_equ[0]->UpdateFields());
276 if (
m_comm->GetRank() == 0)
313 for (
int j = 0; j <
m_equ[
m_nequ - 1]->GetNvariables(); ++j)
317 if (
m_comm->GetRank() == 0)
319 out <<
"L 2 error (variable " <<
m_equ[
m_nequ - 1]->GetVariable(j)
320 <<
") : " << vL2Error << endl;
321 out <<
"L inf error (variable " <<
m_equ[
m_nequ - 1]->GetVariable(j)
322 <<
") : " << vLinfError << endl;
338 NekDouble coeff = 1.0 / (1.0 + X * Delta);
339 M11 = coeff * (1.0 + X * Delta * exp(-(X + 1.0 / Delta)));
340 M12 = coeff * (X * Delta * (1.0 - exp(-(X + 1.0 / Delta))));
341 M21 = coeff * (1.0 - exp(-(X + 1.0 / Delta)));
342 M22 = coeff * (X * Delta + exp(-(X + 1.0 / Delta)));
361 Vmath::Svtvp(qBar1[i].size(),
M21, q0[i], 1, qBar1[i], 1, qBar1[i], 1);
362 Vmath::Svtvp(qBar1[i].size(),
M22, qBar0[i], 1, qBar1[i], 1, qBar1[i], 1);
377 cout <<
"\n\tgrowthEV = " << growthEV << endl;
378 cout <<
"\tfrequencyEV = " << frequencyEV << endl;
380 complex<NekDouble> ApproxEV = polar(exp(growthEV), frequencyEV);
402 cout <<
"\n\tWe enter the Gradient Descent Method [...]" << endl;
403 bool OptParmFound =
false;
404 bool Descending =
true;
422 while (OptParmFound ==
false)
430 s =
abs(0.000001 / dirx);
431 X_output = X_input + s * dirx;
432 Delta_output = Delta_input + s * diry;
435 while (Descending ==
true)
439 Delta_input = Delta_output;
449 X_output = X_input + s * dirx;
450 Delta_output = Delta_input + s * diry;
453 if (stepCounter > 9999999)
459 Delta_init = Delta_init + Delta_init * 0.1;
460 Delta_input = Delta_init;
466 if (
abs(F0 - F1) < dx)
468 cout <<
"\tThe Gradient Descent Method has converged!" << endl;
470 cout <<
"\n\tThe updated parameters are: X_tilde = " << X_output
471 <<
" and Delta_tilde = " << Delta_output << endl;
483 const complex<NekDouble> &alpha,
487 (1.0 + X_input * Delta_input * exp(-(X_input + 1.0 / Delta_input))) /
488 (1.0 + X_input * Delta_input);
490 (X_input * Delta_input -
491 X_input * Delta_input * exp(-(X_input + 1.0 / Delta_input))) /
492 (1.0 + X_input * Delta_input);
493 NekDouble A21 = (1.0 - 1.0 * exp(-(X_input + 1.0 / Delta_input))) /
494 (1 + X_input * Delta_input);
496 (X_input * Delta_input + 1.0 * exp(-(X_input + 1.0 / Delta_input))) /
497 (1.0 + X_input * Delta_input);
499 complex<NekDouble> B11 = alpha;
504 complex<NekDouble> a = A11 * B11 + A12 * B21;
506 complex<NekDouble> c = A21 * B11 + A22 * B21;
509 complex<NekDouble> delt =
sqrt((a -
d) * (a -
d) + 4.0 * b * c);
510 complex<NekDouble> lambda_1 = 0.5 * (a +
d + delt);
511 complex<NekDouble> lambda_2 = 0.5 * (a +
d - delt);
516 MaxEV = max(NORM_1, NORM_2);
528 int NumLinesInFile = 0;
529 std::string EVfileName =
m_session->GetSessionName() +
".evl";
530 std::ifstream EVfile(EVfileName.c_str());
531 ASSERTL0(EVfile.good(),
"Cannot open .evl file.");
537 while (getline(EVfile, line))
546 KrylovSubspaceDim * 2.0 +
547 KrylovSubspaceDim * (KrylovSubspaceDim + 1.0) / 2.0)
549 for (
int i = 1; i <= KrylovSubspaceDim; ++i)
551 if (NumLinesInFile == i * 2.0 + i * (i + 1.0) / 2.0)
553 KrylovSubspaceDim = i;
560 EVfile.seekg(0, ios::beg);
564 for (
int i = 0; i < (NumLinesInFile - KrylovSubspaceDim); ++i)
566 std::getline(EVfile, line);
567 cout <<
"Discard line: " << line << endl;
570 std::vector<std::string> tokens;
571 std::getline(EVfile, line);
572 boost::algorithm::split(tokens, line, boost::is_any_of(
"\t "),
573 boost::token_compress_on);
576 "Unexpected formatting of .evl file while reading line:\n" +
578 growthEV = std::stod(tokens[4]);
579 frequencyEV = std::stod(tokens[5]);
583 cout <<
"An error occurred when opening the .evl file" << endl;
599 MaxNormDiff_q_qBar = 0.0;
600 MaxNormDiff_q1_q0 = 0.0;
604 NormDiff_q_qBar[i] =
m_equ[
m_nequ - 1]->LinfError(i, qBar1[i]);
605 NormDiff_q1_q0[i] =
m_equ[
m_nequ - 1]->LinfError(i, q0[i]);
607 if (MaxNormDiff_q_qBar < NormDiff_q_qBar[i])
609 MaxNormDiff_q_qBar = NormDiff_q_qBar[i];
611 if (MaxNormDiff_q1_q0 < NormDiff_q1_q0[i])
613 MaxNormDiff_q1_q0 = NormDiff_q1_q0[i];
622 if (
m_comm->GetRank() == 0)
625 <<
";\tTime: " << left <<
m_equ[
m_nequ - 1]->GetTime()
626 <<
";\tCPU time = " << left <<
cpuTime <<
" s"
627 <<
";\tTot time = " << left <<
totalTime <<
" s"
628 <<
";\tX = " << left <<
m_X <<
";\tDelta = " << left <<
m_Delta
629 <<
";\t|q-qBar|inf = " << left << MaxNormDiff_q_qBar << endl;
630 std::ofstream
m_file(
"ConvergenceHistory.txt", std::ios_base::app);
632 <<
"\t" <<
totalTime <<
"\t" << MaxNormDiff_q_qBar <<
"\t"
633 << MaxNormDiff_q1_q0 << endl;
646 cout <<
"\n====================================="
647 "=================================="
649 cout <<
"Parameters for the SFD method:" << endl;
650 cout <<
"\tControl Coefficient: X = " <<
m_X << endl;
651 cout <<
"\tFilter Width: Delta = " <<
m_Delta << endl;
652 cout <<
"The simulation is stopped when |q-qBar|inf < " <<
TOL << endl;
655 cout <<
"\nWe use the adaptive SFD method:" << endl;
656 cout <<
" The parameters are updated every " <<
AdaptiveTime
657 <<
" time units;" << endl;
658 cout <<
" until |q-qBar|inf becomes smaller than " <<
AdaptiveTOL
661 cout <<
"====================================="
662 "==================================\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
void v_InitObject(std::ostream &out=std::cout) override
Virtual function for initialisation implementation.
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
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.
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)
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)