38 #include <boost/algorithm/string/classification.hpp>
39 #include <boost/algorithm/string/split.hpp>
40 #include <boost/algorithm/string/predicate.hpp>
49 string DriverSteadyState::className
51 "SteadyState", DriverSteadyState::create);
52 string DriverSteadyState::driverLookupId
53 = LibUtilities::SessionReader::RegisterEnumValue(
54 "Driver",
"SteadyState",0);
59 DriverSteadyState::DriverSteadyState(
115 if (
m_comm->GetRank() == 0)
127 if (
m_session->GetSolverInfo(
"EqType")==
"UnsteadyNavierStokes"||
128 m_session->GetSolverInfo(
"EqType")==
"SteadyNavierStokes")
130 int nConvectiveFields =
m_session->GetVariables().size();
131 if (boost::iequals(
m_session->GetVariable(nConvectiveFields-1),
"p"))
133 nConvectiveFields -= 1;
138 if (
m_session->GetSolverInfo(
"EqType") ==
"EulerCFE" ||
139 m_session->GetSolverInfo(
"EqType") ==
"NavierStokesCFE")
144 if(
m_session->DefinesSolverInfo(
"HOMOGENEOUS"))
146 if (
m_session->GetSolverInfo(
"HOMOGENEOUS") ==
"1D")
158 cout <<
"Besed on the dominant EV given in the xml file,"
159 <<
"a 1D model is used to evaluate the optumum parameters"
160 <<
"of the SFD method:" << endl;
173 ofstream
m_file(
"ConvergenceHistory.txt", ios::out | ios::trunc);
234 if (
m_comm->GetRank() == 0)
236 cout <<
"\n\t The SFD method is converging: we compute "
237 <<
"stability analysis using the 'partially "
238 <<
"converged' steady state as base flow:\n" << endl;
244 A->GetAdvObject()->SetBaseFlow(q0,
m_equ[0]->UpdateFields());
247 if (
m_comm->GetRank() == 0)
270 if (
m_comm->GetRank() == 0)
272 cout <<
"\n\t We compute stability analysis using"
273 <<
" the current flow field as base flow:\n"
280 A->GetAdvObject()->SetBaseFlow(q0,
m_equ[0]->UpdateFields());
283 if (
m_comm->GetRank() == 0)
319 for(
int j = 0; j <
m_equ[
m_nequ - 1]->GetNvariables(); ++j)
323 if (
m_comm->GetRank() == 0)
325 out <<
"L 2 error (variable " <<
m_equ[
m_nequ - 1]->GetVariable(j)
326 <<
") : " << vL2Error << endl;
327 out <<
"L inf error (variable " <<
m_equ[
m_nequ - 1]->GetVariable(j)
328 <<
") : " << vLinfError << endl;
345 M11 = coeff*(1.0 + X*Delta*exp(-(X + 1.0/Delta)));
346 M12 = coeff*(X*Delta*(1.0 - exp(-(X + 1.0/Delta))));
347 M21 = coeff*(1.0 - exp(-(X + 1.0/Delta)));
348 M22 = coeff*(X*Delta + exp(-(X + 1.0/Delta)));
381 cout <<
"\n\tgrowthEV = " << growthEV << endl;
382 cout <<
"\tfrequencyEV = " << frequencyEV << endl;
384 complex<NekDouble> ApproxEV = polar(exp(growthEV), frequencyEV);
403 const complex<NekDouble> &alpha,
407 cout <<
"\n\tWe enter the Gradient Descent Method [...]" << endl;
408 bool OptParmFound =
false;
409 bool Descending =
true;
427 while (OptParmFound ==
false)
435 s =
abs(0.000001/dirx);
436 X_output = X_input + s*dirx;
437 Delta_output = Delta_input + s*diry;
440 while (Descending ==
true)
444 Delta_input = Delta_output;
454 X_output = X_input + s*dirx;
455 Delta_output = Delta_input + s*diry;
458 if(stepCounter > 9999999)
464 Delta_init = Delta_init + Delta_init*0.1;
465 Delta_input = Delta_init;
473 cout <<
"\tThe Gradient Descent Method has converged!" << endl;
475 cout <<
"\n\tThe updated parameters are: X_tilde = " << X_output
476 <<
" and Delta_tilde = " << Delta_output << endl;
491 const complex<NekDouble> &alpha,
494 NekDouble A11 = ( 1.0 + X_input * Delta_input *
495 exp(-(X_input + 1.0/Delta_input)) )/(1.0 + X_input*Delta_input);
496 NekDouble A12 = ( X_input*Delta_input - X_input * Delta_input *
497 exp(-(X_input + 1.0/Delta_input)) )/(1.0 + X_input*Delta_input);
499 exp(-(X_input + 1.0/Delta_input)) )/(1 + X_input*Delta_input);
500 NekDouble A22 = ( X_input*Delta_input + 1.0 *
501 exp(-(X_input + 1.0/Delta_input)) )/(1.0 + X_input*Delta_input);
503 complex<NekDouble> B11 = alpha;
508 complex<NekDouble> a = A11*B11 + A12*B21;
510 complex<NekDouble> c = A21*B11 + A22*B21;
513 complex<NekDouble> delt =
sqrt((a-d)*(a-d) + 4.0*b*c);
514 complex<NekDouble> lambda_1 = 0.5*(a+d + delt);
515 complex<NekDouble> lambda_2 = 0.5*(a+d - delt);
520 MaxEV = max(NORM_1, NORM_2);
525 int &KrylovSubspaceDim,
532 int NumLinesInFile = 0;
533 std::string EVfileName =
m_session->GetSessionName() +
".evl";
534 std::ifstream EVfile(EVfileName.c_str());
535 ASSERTL0(EVfile.good(),
"Cannot open .evl file.");
541 while(getline(EVfile, line))
549 if(NumLinesInFile < KrylovSubspaceDim*2.0
550 + KrylovSubspaceDim*(KrylovSubspaceDim+1.0)/2.0)
552 for(
int i = 1; i <= KrylovSubspaceDim; ++i)
554 if(NumLinesInFile == i*2.0 + i*(i+1.0)/2.0)
556 KrylovSubspaceDim = i;
563 EVfile.seekg(0, ios::beg);
567 for(
int i = 0; i < (NumLinesInFile - KrylovSubspaceDim); ++i)
569 std::getline(EVfile, line);
570 cout <<
"Discard line: " << line << endl;
573 std::vector<std::string> tokens;
574 std::getline(EVfile, line);
575 boost::algorithm::split(tokens, line,
576 boost::is_any_of(
"\t "),boost::token_compress_on);
579 "Unexpected formatting of .evl file while reading line:\n"
581 growthEV = boost::lexical_cast<NekDouble>(tokens[4]);
582 frequencyEV = boost::lexical_cast<NekDouble>(tokens[5]);
586 cout <<
"An error occurred when opening the .evl file" << endl;
604 MaxNormDiff_q_qBar=0.0;
605 MaxNormDiff_q1_q0=0.0;
609 NormDiff_q_qBar[i] =
m_equ[
m_nequ - 1]->LinfError(i, qBar1[i]);
610 NormDiff_q1_q0[i] =
m_equ[
m_nequ - 1]->LinfError(i, q0[i]);
612 if (MaxNormDiff_q_qBar < NormDiff_q_qBar[i])
614 MaxNormDiff_q_qBar = NormDiff_q_qBar[i];
616 if (MaxNormDiff_q1_q0 < NormDiff_q1_q0[i])
618 MaxNormDiff_q1_q0 = NormDiff_q1_q0[i];
627 if (
m_comm->GetRank() == 0)
630 <<
";\tTime: " << left <<
m_equ[
m_nequ - 1]->GetFinalTime()
631 <<
";\tCPU time = " << left <<
cpuTime <<
" s"
632 <<
";\tTot time = " << left <<
totalTime <<
" s"
633 <<
";\tX = " << left <<
m_X
634 <<
";\tDelta = " << left <<
m_Delta
635 <<
";\t|q-qBar|inf = " << left << MaxNormDiff_q_qBar << endl;
636 std::ofstream
m_file(
"ConvergenceHistory.txt", std::ios_base::app);
640 << MaxNormDiff_q_qBar <<
"\t"
641 << MaxNormDiff_q1_q0 << endl;
652 cout <<
"\n====================================="
653 "=================================="
655 cout <<
"Parameters for the SFD method:" << endl;
656 cout <<
"\tControl Coefficient: X = " <<
m_X << endl;
657 cout <<
"\tFilter Width: Delta = " <<
m_Delta << endl;
658 cout <<
"The simulation is stopped when |q-qBar|inf < " <<
TOL << endl;
661 cout <<
"\nWe use the adaptive SFD method:" << endl;
662 cout <<
" The parameters are updated every " <<
AdaptiveTime
663 <<
" time units;" << endl;
664 cout <<
" until |q-qBar|inf becomes smaller than " <<
AdaptiveTOL
667 cout <<
"====================================="
668 "==================================\n" << endl;
#define ASSERTL0(condition, msg)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
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)
Virtual function for initialisation implementation.
virtual void v_Execute(std::ostream &out=std::cout)
Virtual function for solve implementation.
LibUtilities::Timer timer
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)
virtual SOLVER_UTILS_EXPORT void v_Execute(std::ostream &out=std::cout)
Virtual function for solve implementation.
int m_NonConvergingStepsCounter
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()
NekDouble m_Delta
Definition of the SFD parameters:
virtual SOLVER_UTILS_EXPORT void v_InitObject(std::ostream &out=std::cout)
Second-stage initialisation.
virtual SOLVER_UTILS_EXPORT ~DriverSteadyState()
Destructor.
void SetSFDOperator(const NekDouble X_input, const NekDouble Delta_input)
NekDouble M11
Definition of the SFD operator.
void GradientDescentMethod(const std::complex< NekDouble > &alpha, NekDouble &X_output, NekDouble &Delta_output)
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
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)