diff --git a/src/calorically_perfect.cpp b/src/calorically_perfect.cpp index e6c49c3d9..b93ba7fd1 100644 --- a/src/calorically_perfect.cpp +++ b/src/calorically_perfect.cpp @@ -153,10 +153,14 @@ CaloricallyPerfectThermoChem::~CaloricallyPerfectThermoChem() { delete HtInvPC_; delete MsInv_; delete MsInvPC_; + delete Mv_inv_; + delete Mv_inv_pc_; delete Ht_form_; delete MsRho_form_; delete Ms_form_; + delete Mv_form_; delete At_form_; + delete G_form_; delete D_form_; delete rhou_coeff_; delete rhon_next_coeff_; @@ -262,6 +266,9 @@ void CaloricallyPerfectThermoChem::initializeSelf() { tmpR0c_.SetSize(sfes_truevsize); tmpR1_.SetSize(vfes_truevsize); + gradT_.SetSize(vfes_truevsize); + gradT_ = 0.0; + R0PM0_gf_.SetSpace(sfes_); rhoDt.SetSpace(sfes_); @@ -510,6 +517,43 @@ void CaloricallyPerfectThermoChem::initializeOperators() { D_form_->Assemble(); D_form_->FormRectangularSystemMatrix(empty, empty, D_op_); + // Gradient + G_form_ = new ParMixedBilinearForm(sfes_, vfes_); + // auto *g_mblfi = new GradientIntegrator(); + GradientIntegrator *g_mblfi; + // if (axisym_) { + // g_mblfi = new GradientIntegrator(radius_coeff); + // } else { + g_mblfi = new GradientIntegrator(); + //} + if (numerical_integ_) { + g_mblfi->SetIntRule(&ir_nli); + } + G_form_->AddDomainIntegrator(g_mblfi); + if (partial_assembly_) { + G_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); + } + G_form_->Assemble(); + G_form_->FormRectangularSystemMatrix(empty, empty, G_op_); + + // Mass matrix for the vector (gradT) + Mv_form_ = new ParBilinearForm(vfes_); + VectorMassIntegrator *mv_blfi; + // if (axisym_) { + // mv_blfi = new VectorMassIntegrator(radius_coeff); + // } else { + mv_blfi = new VectorMassIntegrator(); + //} + if (numerical_integ_) { + mv_blfi->SetIntRule(&ir_nli); + } + Mv_form_->AddDomainIntegrator(mv_blfi); + if (partial_assembly_) { + Mv_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); + } + Mv_form_->Assemble(); + Mv_form_->FormSystemMatrix(temp_ess_tdof_, Mv_); + // mass matrix with rho MsRho_form_ = new ParBilinearForm(sfes_); auto *msrho_blfi = new MassIntegrator(*rho_coeff_); @@ -522,6 +566,7 @@ void CaloricallyPerfectThermoChem::initializeOperators() { MsRho_form_->FormSystemMatrix(empty, MsRho_); if (rank0_) std::cout << "CaloricallyPerfectThermoChem MsRho operator set" << endl; + // Helmholtz Ht_form_ = new ParBilinearForm(sfes_); auto *hmt_blfi = new MassIntegrator(*rho_over_dt_coeff_); auto *hdt_blfi = new DiffusionIntegrator(*thermal_diff_total_coeff_); @@ -556,6 +601,27 @@ void CaloricallyPerfectThermoChem::initializeOperators() { MsInv_->SetAbsTol(mass_inverse_atol_); MsInv_->SetMaxIter(mass_inverse_max_iter_); + // Inverse (unweighted) mass operator (velocity space) + if (partial_assembly_) { + Vector diag_pa(vfes_->GetTrueVSize()); + Mv_form_->AssembleDiagonal(diag_pa); + Mv_inv_pc_ = new OperatorJacobiSmoother(diag_pa, empty); + } else { + Mv_inv_pc_ = new HypreSmoother(*Mv_.As()); + dynamic_cast(Mv_inv_pc_)->SetType(HypreSmoother::Jacobi, smoother_passes_); + dynamic_cast(Mv_inv_pc_)->SetSOROptions(smoother_relax_weight_, smoother_relax_omega_); + dynamic_cast(Mv_inv_pc_) + ->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, smoother_eig_est_); + } + Mv_inv_ = new CGSolver(vfes_->GetComm()); + Mv_inv_->iterative_mode = false; + Mv_inv_->SetOperator(*Mv_); + Mv_inv_->SetPreconditioner(*Mv_inv_pc_); + Mv_inv_->SetPrintLevel(mass_inverse_pl_); + Mv_inv_->SetAbsTol(mass_inverse_atol_); + Mv_inv_->SetRelTol(mass_inverse_rtol_); + Mv_inv_->SetMaxIter(mass_inverse_max_iter_); + HtInvPC_ = new HypreSmoother(*Ht_.As()); dynamic_cast(HtInvPC_)->SetType(HypreSmoother::Jacobi, smoother_passes_); dynamic_cast(HtInvPC_)->SetSOROptions(hsmoother_relax_weight_, hsmoother_relax_omega_); @@ -707,7 +773,12 @@ void CaloricallyPerfectThermoChem::step() { // Add streamwise stability to rhs if (sw_stab_) { - streamwiseDiffusion(Tn_, swDiff_); + // compute temp gradient (only really needed for sw-stab) + G_op_->Mult(Text_, tmpR1_); + Mv_inv_->Mult(tmpR1_, gradT_); + + // streamwiseDiffusion(Tn_, swDiff_); + streamwiseDiffusion(gradT_, swDiff_); resT_.Add(1.0, swDiff_); } @@ -1068,25 +1139,35 @@ void CaloricallyPerfectThermoChem::screenValues(std::vector &values) { } } -void CaloricallyPerfectThermoChem::streamwiseDiffusion(Vector &phi, Vector &swDiff) { - // compute streamwise gradient of input field - tmpR0_gf_.SetFromTrueDofs(phi); +// void CaloricallyPerfectThermoChem::streamwiseDiffusion(Vector &phi, Vector &swDiff) { +void CaloricallyPerfectThermoChem::streamwiseDiffusion(Vector &gradPhi, Vector &swDiff) { (flow_interface_->velocity)->GetTrueDofs(tmpR0a_); vel_gf_.SetFromTrueDofs(tmpR0a_); - streamwiseGrad(dim_, tmpR0_gf_, vel_gf_, tmpR1_gf_); + + // compute streamwise gradient of input field + // tmpR0_gf_.SetFromTrueDofs(phi); + // streamwiseGrad(dim_, tmpR0_gf_, vel_gf_, tmpR1_gf_); + + tmpR1_gf_.SetFromTrueDofs(gradPhi); + streamwiseGrad(dim_, vel_gf_, tmpR1_gf_); // divergence of sw-grad tmpR1_gf_.GetTrueDofs(tmpR1_); D_op_->Mult(tmpR1_, swDiff); gridScale_gf_->GetTrueDofs(tmpR0b_); - (turbModel_interface_->eddy_viscosity)->GetTrueDofs(tmpR0c_); + //(turbModel_interface_->eddy_viscosity)->GetTrueDofs(tmpR0c_); + (flow_interface_->Reh)->GetTrueDofs(tmpR0c_); + upwindDiff(dim_, re_factor_, re_offset_, tmpR0a_, rn_, tmpR0b_, tmpR0c_, swDiff); + + /* const double *rho = rn_.HostRead(); const double *vel = tmpR0a_.HostRead(); const double *del = tmpR0b_.HostRead(); - const double *mu = visc_.HostRead(); - const double *muT = tmpR0c_.HostRead(); + //const double *mu = visc_.HostRead(); + //const double *muT = tmpR0c_.HostRead(); + const double *Reh = tmpR0c_.HostRead(); double *data = swDiff.HostReadWrite(); int Sdof = rn_.Size(); @@ -1096,7 +1177,8 @@ void CaloricallyPerfectThermoChem::streamwiseDiffusion(Vector &phi, Vector &swDi Umag = std::sqrt(Umag); // element Re - double Re = Umag * del[dof] * rho[dof] / (mu[dof] + muT[dof]); + //double Re = Umag * del[dof] * rho[dof] / (mu[dof] + muT[dof]); + double Re = Reh[dof]; // SUPG weight double Csupg = 0.5 * (tanh(re_factor_ * Re - re_offset_) + 1.0); @@ -1107,4 +1189,5 @@ void CaloricallyPerfectThermoChem::streamwiseDiffusion(Vector &phi, Vector &swDi // scaled streamwise Laplacian data[dof] *= CswDiff; } + */ } diff --git a/src/calorically_perfect.hpp b/src/calorically_perfect.hpp index 769430336..3f6f72e75 100644 --- a/src/calorically_perfect.hpp +++ b/src/calorically_perfect.hpp @@ -189,11 +189,13 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { // operators and solvers ParBilinearForm *At_form_ = nullptr; ParBilinearForm *Ms_form_ = nullptr; + ParBilinearForm *Mv_form_ = nullptr; ParBilinearForm *MsRho_form_ = nullptr; ParBilinearForm *Ht_form_ = nullptr; ParBilinearForm *Mq_form_ = nullptr; ParBilinearForm *LQ_form_ = nullptr; ParMixedBilinearForm *D_form_ = nullptr; + ParMixedBilinearForm *G_form_ = nullptr; ParLinearForm *LQ_bdry_ = nullptr; OperatorHandle LQ_; @@ -202,7 +204,9 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { OperatorHandle Ms_; OperatorHandle MsRho_; OperatorHandle Mq_; + OperatorHandle Mv_; OperatorHandle D_op_; + OperatorHandle G_op_; mfem::Solver *MsInvPC_ = nullptr; mfem::CGSolver *MsInv_ = nullptr; @@ -210,6 +214,8 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { mfem::CGSolver *MqInv_ = nullptr; mfem::Solver *HtInvPC_ = nullptr; mfem::CGSolver *HtInv_ = nullptr; + mfem::Solver *Mv_inv_pc_ = nullptr; + mfem::CGSolver *Mv_inv_ = nullptr; // Vectors Vector Tn_, Tn_next_, Tnm1_, Tnm2_; @@ -219,6 +225,7 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { Vector tmpR0_, tmpR0a_, tmpR0b_, tmpR0c_; Vector tmpR1_; Vector swDiff_; + Vector gradT_; Vector Qt_; Vector rn_; @@ -276,7 +283,8 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { void computeExplicitTempConvectionOP(bool extrap); void computeQt(); void computeQtTO(); - void streamwiseDiffusion(Vector &phi, Vector &swDiff); + // void streamwiseDiffusion(Vector &phi, Vector &swDiff); + void streamwiseDiffusion(Vector &gradPhi, Vector &swDiff); /// Return a pointer to the current temperature ParGridFunction. ParGridFunction *GetCurrentTemperature() { return &Tn_gf_; } diff --git a/src/cases.cpp b/src/cases.cpp index 6fecd0af9..89529ef26 100644 --- a/src/cases.cpp +++ b/src/cases.cpp @@ -202,7 +202,7 @@ double temp_channel(const Vector &coords, double t) { double Tlo = 200.0; double y = coords(1); double temp; - temp = Tlo + (y + 0.5) * (Thi - Tlo); + temp = Tlo + 0.5 * (y + 0.1) * (Thi - Tlo); return temp; } diff --git a/src/lte_thermo_chem.cpp b/src/lte_thermo_chem.cpp index d057c19b1..482305692 100644 --- a/src/lte_thermo_chem.cpp +++ b/src/lte_thermo_chem.cpp @@ -168,6 +168,17 @@ LteThermoChem::LteThermoChem(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, t tps->getInput("loMach/ltethermo/linear-solver-max-iter", max_iter_, 1000); tps->getInput("loMach/ltethermo/linear-solver-verbosity", pl_solve_, 0); + // not deleting above block to maintain backwards-compatability + tpsP_->getInput("loMach/ltethermo/hsolve-rtol", hsolve_rtol_, rtol_); + tpsP_->getInput("loMach/ltethermo/hsolve-atol", hsolve_atol_, default_atol_); + tpsP_->getInput("loMach/ltethermo/hsolve-max-iter", hsolve_max_iter_, max_iter_); + tpsP_->getInput("loMach/ltethermo/hsolve-verbosity", hsolve_pl_, pl_solve_); + + tpsP_->getInput("loMach/ltethermo/msolve-rtol", mass_inverse_rtol_, rtol_); + tpsP_->getInput("loMach/ltethermo/msolve-atol", mass_inverse_atol_, default_atol_); + tpsP_->getInput("loMach/ltethermo/msolve-max-iter", mass_inverse_max_iter_, max_iter_); + tpsP_->getInput("loMach/ltethermo/msolve-verbosity", mass_inverse_pl_, pl_solve_); + tps->getInput("loMach/ltethermo/streamwise-stabilization", sw_stab_, false); tps->getInput("loMach/ltethermo/Reh_offset", re_offset_, 1.0); tps->getInput("loMach/ltethermo/Reh_factor", re_factor_, 0.1); @@ -192,12 +203,16 @@ LteThermoChem::~LteThermoChem() { delete MsInvPC_; delete MrhoInv_; delete MrhoInvPC_; + delete Mv_inv_; + delete Mv_inv_pc_; delete Ht_form_; delete M_rho_form_; delete M_rho_Cp_form_; delete Ms_form_; + delete Mv_form_; delete At_form_; delete D_form_; + delete G_form_; delete rho_Cp_u_coeff_; delete un_next_coeff_; delete kap_gradT_coeff_; @@ -666,6 +681,43 @@ void LteThermoChem::initializeOperators() { D_form_->Assemble(); D_form_->FormRectangularSystemMatrix(empty, empty, D_op_); + // Gradient + G_form_ = new ParMixedBilinearForm(sfes_, vfes_); + // auto *g_mblfi = new GradientIntegrator(); + GradientIntegrator *g_mblfi; + if (axisym_) { + g_mblfi = new GradientIntegrator(radius_coeff); + } else { + g_mblfi = new GradientIntegrator(); + } + if (numerical_integ_) { + g_mblfi->SetIntRule(&ir_nli); + } + G_form_->AddDomainIntegrator(g_mblfi); + if (partial_assembly_) { + G_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); + } + G_form_->Assemble(); + G_form_->FormRectangularSystemMatrix(empty, empty, G_op_); + + // Mass matrix for the vector (gradT) + Mv_form_ = new ParBilinearForm(vfes_); + VectorMassIntegrator *mv_blfi; + if (axisym_) { + mv_blfi = new VectorMassIntegrator(radius_coeff); + } else { + mv_blfi = new VectorMassIntegrator(); + } + if (numerical_integ_) { + mv_blfi->SetIntRule(&ir_nli); + } + Mv_form_->AddDomainIntegrator(mv_blfi); + if (partial_assembly_) { + Mv_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); + } + Mv_form_->Assemble(); + Mv_form_->FormSystemMatrix(temp_ess_tdof_, Mv_); + // helmholtz Ht_form_ = new ParBilinearForm(sfes_); MassIntegrator *hmt_blfi; @@ -722,6 +774,27 @@ void LteThermoChem::initializeOperators() { MrhoInv_->SetRelTol(rtol_); MrhoInv_->SetMaxIter(max_iter_); + // Inverse (unweighted) mass operator (velocity space) + if (partial_assembly_) { + Vector diag_pa(vfes_->GetTrueVSize()); + Mv_form_->AssembleDiagonal(diag_pa); + Mv_inv_pc_ = new OperatorJacobiSmoother(diag_pa, empty); + } else { + Mv_inv_pc_ = new HypreSmoother(*Mv_.As()); + dynamic_cast(Mv_inv_pc_)->SetType(HypreSmoother::Jacobi, smoother_passes_); + dynamic_cast(Mv_inv_pc_)->SetSOROptions(smoother_relax_weight_, smoother_relax_omega_); + dynamic_cast(Mv_inv_pc_) + ->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, smoother_eig_est_); + } + Mv_inv_ = new CGSolver(vfes_->GetComm()); + Mv_inv_->iterative_mode = false; + Mv_inv_->SetOperator(*Mv_); + Mv_inv_->SetPreconditioner(*Mv_inv_pc_); + Mv_inv_->SetPrintLevel(mass_inverse_pl_); + Mv_inv_->SetAbsTol(mass_inverse_atol_); + Mv_inv_->SetRelTol(mass_inverse_rtol_); + Mv_inv_->SetMaxIter(mass_inverse_max_iter_); + if (partial_assembly_) { Vector diag_pa(sfes_->GetTrueVSize()); Ht_form_->AssembleDiagonal(diag_pa); @@ -945,7 +1018,12 @@ void LteThermoChem::step() { // Add streamwise stability to rhs if (sw_stab_) { - streamwiseDiffusion(Tn_, swDiff_); + // compute temp gradient (only really needed for sw-stab) + G_op_->Mult(Text_, tmpR1_); + Mv_inv_->Mult(tmpR1_, gradT_); + + // streamwiseDiffusion(Tn_, swDiff_); + streamwiseDiffusion(gradT_, swDiff_); resT_.Add(1.0, swDiff_); } @@ -1276,25 +1354,32 @@ void LteThermoChem::computeQt() { Qt_gf_.SetFromTrueDofs(Qt_); } -void LteThermoChem::streamwiseDiffusion(Vector &phi, Vector &swDiff) { - // compute streamwise gradient of input field - tmpR0_gf_.SetFromTrueDofs(phi); +// void LteThermoChem::streamwiseDiffusion(Vector &phi, Vector &swDiff) { +void LteThermoChem::streamwiseDiffusion(Vector &gradPhi, Vector &swDiff) { (flow_interface_->velocity)->GetTrueDofs(tmpR0a_); vel_gf_.SetFromTrueDofs(tmpR0a_); - streamwiseGrad(dim_, tmpR0_gf_, vel_gf_, tmpR1_gf_); + + // compute streamwise gradient of input field + // tmpR0_gf_.SetFromTrueDofs(phi); + // streamwiseGrad(dim_, tmpR0_gf_, vel_gf_, tmpR1_gf_); + + tmpR1_gf_.SetFromTrueDofs(gradPhi); + streamwiseGrad(dim_, vel_gf_, tmpR1_gf_); // divergence of sw-grad tmpR1_gf_.GetTrueDofs(tmpR1_); D_op_->Mult(tmpR1_, swDiff); gridScale_gf_->GetTrueDofs(tmpR0b_); - (turbModel_interface_->eddy_viscosity)->GetTrueDofs(tmpR0c_); + //(turbModel_interface_->eddy_viscosity)->GetTrueDofs(tmpR0c_); + (flow_interface_->Reh)->GetTrueDofs(tmpR0c_); const double *rho = rn_.HostRead(); const double *vel = tmpR0a_.HostRead(); const double *del = tmpR0b_.HostRead(); - const double *mu = visc_.HostRead(); - const double *muT = tmpR0c_.HostRead(); + // const double *mu = visc_.HostRead(); + // const double *muT = tmpR0c_.HostRead(); + const double *Reh = tmpR0c_.HostRead(); double *data = swDiff.HostReadWrite(); int Sdof = rn_.Size(); @@ -1304,7 +1389,8 @@ void LteThermoChem::streamwiseDiffusion(Vector &phi, Vector &swDiff) { Umag = std::sqrt(Umag); // element Re - double Re = Umag * del[dof] * rho[dof] / (mu[dof] + muT[dof]); + // double Re = Umag * del[dof] * rho[dof] / (mu[dof] + muT[dof]); + double Re = Reh[dof]; // SUPG weight double Csupg = 0.5 * (tanh(re_factor_ * Re - re_offset_) + 1.0); diff --git a/src/lte_thermo_chem.hpp b/src/lte_thermo_chem.hpp index 2aaed5e61..ff634b3a7 100644 --- a/src/lte_thermo_chem.hpp +++ b/src/lte_thermo_chem.hpp @@ -92,10 +92,34 @@ class LteThermoChem final : public ThermoChemModelBase { bool axisym_ = false; // Linear-solver-related options + int smoother_poly_order_; + double smoother_poly_fraction_ = 0.75; + int smoother_eig_est_ = 10; + int smoother_passes_ = 1; + double smoother_relax_weight_ = 0.4; + double smoother_relax_omega_ = 1.0; + double hsmoother_relax_weight_ = 0.8; + double hsmoother_relax_omega_ = 0.1; + + // solver tolerance options int pl_solve_ = 0; /**< Verbosity level passed to mfem solvers */ int max_iter_; /**< Maximum number of linear solver iterations */ double rtol_ = 1e-12; /**< Linear solver relative tolerance */ + int default_max_iter_ = 1000; + double default_rtol_ = 1.0e-10; + double default_atol_ = 1.0e-12; + + int mass_inverse_pl_ = 0; + int mass_inverse_max_iter_; + double mass_inverse_rtol_; + double mass_inverse_atol_; + + int hsolve_pl_ = 0; + int hsolve_max_iter_; + double hsolve_rtol_; + double hsolve_atol_; + // streamwise-stabilization bool sw_stab_; double re_offset_; @@ -198,6 +222,7 @@ class LteThermoChem final : public ThermoChemModelBase { // operators and solvers ParBilinearForm *At_form_ = nullptr; ParBilinearForm *Ms_form_ = nullptr; + ParBilinearForm *Mv_form_ = nullptr; ParBilinearForm *M_rho_Cp_form_ = nullptr; ParBilinearForm *Ht_form_ = nullptr; @@ -211,16 +236,19 @@ class LteThermoChem final : public ThermoChemModelBase { ParLinearForm *LQ_bdry_ = nullptr; ParMixedBilinearForm *D_form_ = nullptr; + ParMixedBilinearForm *G_form_ = nullptr; OperatorHandle At_; OperatorHandle Ht_; OperatorHandle Ms_; + OperatorHandle Mv_; OperatorHandle Mq_; OperatorHandle LQ_; OperatorHandle M_rho_Cp_; OperatorHandle M_rho_; OperatorHandle A_rho_; OperatorHandle D_op_; + OperatorHandle G_op_; mfem::Solver *MsInvPC_ = nullptr; mfem::CGSolver *MsInv_ = nullptr; @@ -230,6 +258,8 @@ class LteThermoChem final : public ThermoChemModelBase { mfem::CGSolver *MrhoInv_ = nullptr; mfem::Solver *HtInvPC_ = nullptr; mfem::CGSolver *HtInv_ = nullptr; + mfem::Solver *Mv_inv_pc_ = nullptr; + mfem::CGSolver *Mv_inv_ = nullptr; // Vectors Vector Tn_, Tn_next_, Tnm1_, Tnm2_; @@ -239,6 +269,7 @@ class LteThermoChem final : public ThermoChemModelBase { Vector tmpR0_, tmpR0a_, tmpR0b_, tmpR0c_; Vector tmpR1_; Vector swDiff_; + Vector gradT_; Vector Qt_; Vector rn_, rnm1_, rnm2_, rnm3_; @@ -282,7 +313,8 @@ class LteThermoChem final : public ThermoChemModelBase { void computeExplicitTempConvectionOP(); void computeQt(); void updateHistory(); - void streamwiseDiffusion(Vector &phi, Vector &swDiff); + // void streamwiseDiffusion(Vector &phi, Vector &swDiff); + void streamwiseDiffusion(Vector &gradPhi, Vector &swDiff); /// Return a pointer to the current temperature ParGridFunction. ParGridFunction *GetCurrentTemperature() { return &Tn_gf_; } diff --git a/src/split_flow_base.hpp b/src/split_flow_base.hpp index 9ef8949f0..3634e3c86 100644 --- a/src/split_flow_base.hpp +++ b/src/split_flow_base.hpp @@ -49,6 +49,8 @@ struct flowToThermoChem { bool swirl_supported = false; const mfem::ParGridFunction *swirl = nullptr; + + const mfem::ParGridFunction *Reh = nullptr; }; struct flowToTurbModel { @@ -60,6 +62,8 @@ struct flowToTurbModel { const mfem::ParGridFunction *gradU = nullptr; const mfem::ParGridFunction *gradV = nullptr; const mfem::ParGridFunction *gradW = nullptr; + + const mfem::ParGridFunction *Reh = nullptr; }; class FlowBase { diff --git a/src/tomboulides.cpp b/src/tomboulides.cpp index 4dc42b906..5a8eb9f8e 100644 --- a/src/tomboulides.cpp +++ b/src/tomboulides.cpp @@ -230,6 +230,7 @@ Tomboulides::~Tomboulides() { delete gradU_gf_; delete gradV_gf_; delete gradW_gf_; + delete Reh_gf_; delete tmpR0_gf_; delete tmpR1_gf_; delete vfes_; @@ -242,6 +243,11 @@ void Tomboulides::initializeSelf() { // Initialize minimal state and interface vfec_ = new H1_FECollection(vorder_, dim_); vfes_ = new ParFiniteElementSpace(pmesh_, vfec_, dim_); + // sfec_ = new H1_FECollection(vorder_); + // sfes_ = new ParFiniteElementSpace(pmesh_, sfec_); + pfec_ = new H1_FECollection(porder_); + pfes_ = new ParFiniteElementSpace(pmesh_, pfec_); + u_curr_gf_ = new ParGridFunction(vfes_); u_next_gf_ = new ParGridFunction(vfes_); curl_gf_ = new ParGridFunction(vfes_); @@ -251,20 +257,15 @@ void Tomboulides::initializeSelf() { gradU_gf_ = new ParGridFunction(vfes_); gradV_gf_ = new ParGridFunction(vfes_); gradW_gf_ = new ParGridFunction(vfes_); - sfec_ = new H1_FECollection(vorder_); - sfes_ = new ParFiniteElementSpace(pmesh_, sfec_); - - pfec_ = new H1_FECollection(porder_); - pfes_ = new ParFiniteElementSpace(pmesh_, pfec_); p_gf_ = new ParGridFunction(pfes_); resp_gf_ = new ParGridFunction(pfes_); - mu_total_gf_ = new ParGridFunction(pfes_); pp_div_rad_comp_gf_ = new ParGridFunction(pfes_, *pp_div_gf_); u_next_rad_comp_gf_ = new ParGridFunction(pfes_, *u_next_gf_); - tmpR0_gf_ = new ParGridFunction(sfes_); + Reh_gf_ = new ParGridFunction(pfes_); + tmpR0_gf_ = new ParGridFunction(pfes_); tmpR1_gf_ = new ParGridFunction(vfes_); if (axisym_) { @@ -285,17 +286,20 @@ void Tomboulides::initializeSelf() { *p_gf_ = 0.0; *resp_gf_ = 0.0; *mu_total_gf_ = 0.0; + *Reh_gf_ = 0.0; if (axisym_) { *utheta_gf_ = 0.0; *utheta_next_gf_ = 0.0; } + // exports toThermoChem_interface_.velocity = u_next_gf_; if (axisym_) { toThermoChem_interface_.swirl_supported = true; toThermoChem_interface_.swirl = utheta_next_gf_; } + toThermoChem_interface_.Reh = Reh_gf_; toTurbModel_interface_.velocity = u_next_gf_; if (axisym_) { @@ -305,10 +309,11 @@ void Tomboulides::initializeSelf() { toTurbModel_interface_.gradU = gradU_gf_; toTurbModel_interface_.gradV = gradV_gf_; toTurbModel_interface_.gradW = gradW_gf_; + toTurbModel_interface_.Reh = Reh_gf_; // Allocate Vector storage const int vfes_truevsize = vfes_->GetTrueVSize(); - const int sfes_truevsize = sfes_->GetTrueVSize(); + // const int sfes_truevsize = sfes_->GetTrueVSize(); const int pfes_truevsize = pfes_->GetTrueVSize(); forcing_vec_.SetSize(vfes_truevsize); @@ -345,9 +350,10 @@ void Tomboulides::initializeSelf() { } swDiff_vec_.SetSize(vfes_truevsize); - tmpR0_.SetSize(sfes_truevsize); - tmpR0a_.SetSize(sfes_truevsize); - tmpR0b_.SetSize(sfes_truevsize); + tmpR0_.SetSize(pfes_truevsize); + tmpR0a_.SetSize(pfes_truevsize); + tmpR0b_.SetSize(pfes_truevsize); + tmpR0c_.SetSize(pfes_truevsize); tmpR1_.SetSize(vfes_truevsize); gradU_.SetSize(vfes_truevsize); @@ -799,6 +805,9 @@ void Tomboulides::initializeOperators() { } Mv_form_->Assemble(); Mv_form_->FormSystemMatrix(empty, Mv_op_); + // NOTE: should have dirichlet bc's here for inverse solve, but + // this operator is overloaded and not just used for vel... + // Mv_form_->FormSystemMatrix(vel_ess_tdof_, Mv_op_); // Mass matrix (density weighted) for the velocity Mv_rho_form_ = new ParBilinearForm(vfes_); @@ -1073,6 +1082,7 @@ void Tomboulides::initializeViz(mfem::ParaViewDataCollection &pvdc) const { if (axisym_) { pvdc.RegisterField("swirl", utheta_gf_); } + pvdc.RegisterField("Re_h", Reh_gf_); } void Tomboulides::initializeStats(Averaging &average, IODataOrganizer &io, bool continuation) const { @@ -1360,12 +1370,21 @@ void Tomboulides::step() { } // Add streamwise stability to rhs + computeReh(); if (sw_stab_) { + /* for (int i = 0; i < dim_; i++) { setScalarFromVector(u_vec_, i, &tmpR0a_); streamwiseDiffusion(tmpR0a_, tmpR0b_); setVectorFromScalar(tmpR0b_, i, &swDiff_vec_); } + */ + streamwiseDiffusion(gradU_, tmpR0b_); + setVectorFromScalar(tmpR0b_, 0, &swDiff_vec_); + streamwiseDiffusion(gradV_, tmpR0b_); + setVectorFromScalar(tmpR0b_, 1, &swDiff_vec_); + streamwiseDiffusion(gradW_, tmpR0b_); + setVectorFromScalar(tmpR0b_, 2, &swDiff_vec_); Mv_rho_inv_->Mult(swDiff_vec_, tmpR1_); pp_div_vec_ += tmpR1_; } @@ -1715,11 +1734,42 @@ void Tomboulides::evaluateVelocityGradient() { gradW_gf_->SetFromTrueDofs(gradW_); } +void Tomboulides::computeReh() { + (thermo_interface_->density)->GetTrueDofs(rho_vec_); + gridScale_gf_->GetTrueDofs(tmpR0_); + mu_total_gf_->GetTrueDofs(mu_vec_); + // u_curr_gf_->GetTrueDofs(u_vec_); + u_next_gf_->GetTrueDofs(uext_vec_); + + const double *rho = rho_vec_.HostRead(); + const double *del = tmpR0_.HostRead(); + const double *vel = uext_vec_.HostRead(); + const double *mu = mu_vec_.HostRead(); + double *data = tmpR0c_.HostReadWrite(); + + int Sdof = tmpR0c_.Size(); + for (int dof = 0; dof < Sdof; dof++) { + // vel mag + double Umag = 0.0; + for (int i = 0; i < dim_; i++) Umag += vel[dof + i * Sdof] * vel[dof + i * Sdof]; + Umag = std::sqrt(Umag); + + // element Re + double Re = Umag * del[dof] * rho[dof] / mu[dof]; + data[dof] = Re; + } + Reh_gf_->SetFromTrueDofs(tmpR0c_); +} + // f(Re_h) * Mu_sw * div(streamwiseGrad), i.e. this does not consider grad of f(Re_h) * Mu_sw -void Tomboulides::streamwiseDiffusion(Vector &phi, Vector &swDiff) { +// void Tomboulides::streamwiseDiffusion(Vector &phi, Vector &swDiff) { +void Tomboulides::streamwiseDiffusion(Vector &gradPhi, Vector &swDiff) { // compute streamwise gradient of input field - tmpR0_gf_->SetFromTrueDofs(phi); - streamwiseGrad(dim_, *tmpR0_gf_, *u_curr_gf_, *tmpR1_gf_); + // tmpR0_gf_->SetFromTrueDofs(phi); + // streamwiseGrad(dim_, *tmpR0_gf_, *u_curr_gf_, *tmpR1_gf_); + + tmpR1_gf_->SetFromTrueDofs(gradPhi); + streamwiseGrad(dim_, *u_curr_gf_, *tmpR1_gf_); // divergence of sw-grad tmpR1_gf_->GetTrueDofs(tmpR1_); @@ -1727,12 +1777,16 @@ void Tomboulides::streamwiseDiffusion(Vector &phi, Vector &swDiff) { (thermo_interface_->density)->GetTrueDofs(rho_vec_); gridScale_gf_->GetTrueDofs(tmpR0_); - mu_total_gf_->GetTrueDofs(mu_vec_); + Reh_gf_->GetTrueDofs(tmpR0c_); + // mu_total_gf_->GetTrueDofs(mu_vec_); + upwindDiff(dim_, re_factor_, re_offset_, u_vec_, rho_vec_, tmpR0_, tmpR0c_, swDiff); + /* const double *rho = rho_vec_.HostRead(); const double *del = tmpR0_.HostRead(); const double *vel = u_vec_.HostRead(); - const double *mu = mu_vec_.HostRead(); + //const double *mu = mu_vec_.HostRead(); + const double *Reh = tmpR0c_.HostRead(); double *data = swDiff.HostReadWrite(); int Sdof = rho_vec_.Size(); @@ -1742,7 +1796,8 @@ void Tomboulides::streamwiseDiffusion(Vector &phi, Vector &swDiff) { Umag = std::sqrt(Umag); // element Re - double Re = Umag * del[dof] * rho[dof] / mu[dof]; + //double Re = Umag * del[dof] * rho[dof] / mu[dof]; + double Re = Reh[dof]; // SUPG weight double Csupg = 0.5 * (tanh(re_factor_ * Re - re_offset_) + 1.0); @@ -1753,4 +1808,5 @@ void Tomboulides::streamwiseDiffusion(Vector &phi, Vector &swDiff) { // scaled streamwise Laplacian data[dof] *= CswDiff; } + */ } diff --git a/src/tomboulides.hpp b/src/tomboulides.hpp index 7b408d3fe..1010d7c8a 100644 --- a/src/tomboulides.hpp +++ b/src/tomboulides.hpp @@ -229,6 +229,7 @@ class Tomboulides final : public FlowBase { mfem::ParGridFunction *gradW_gf_ = nullptr; // mfem::ParGridFunction *buffer_uInlet_ = nullptr; mfem::VectorGridFunctionCoefficient *velocity_field_ = nullptr; + mfem::ParGridFunction *Reh_gf_ = nullptr; mfem::ParGridFunction *tmpR0_gf_ = nullptr; mfem::ParGridFunction *tmpR1_gf_ = nullptr; @@ -367,6 +368,7 @@ class Tomboulides final : public FlowBase { mfem::Vector tmpR0_; mfem::Vector tmpR0a_; mfem::Vector tmpR0b_; + mfem::Vector tmpR0c_; mfem::Vector tmpR1_; mfem::Vector gradU_; mfem::Vector gradV_; @@ -447,6 +449,11 @@ class Tomboulides final : public FlowBase { */ void streamwiseDiffusion(Vector &phi, Vector &swDiff); + /** + * @brief Computes element convective Reynolds number + */ + void computeReh(); + /// Advance void step() final; diff --git a/src/utils.cpp b/src/utils.cpp index 5843fa626..8bb9ac27a 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -763,6 +763,7 @@ void ComputeCurl3D(const ParGridFunction &u, ParGridFunction &cu) { // Communication + /* // Count the zones globally. GroupCommunicator &gcomm = u.ParFESpace()->GroupComm(); gcomm.Reduce(zones_per_vdof, GroupCommunicator::Sum); @@ -771,6 +772,7 @@ void ComputeCurl3D(const ParGridFunction &u, ParGridFunction &cu) { // Accumulate for all vdofs. gcomm.Reduce(cu.GetData(), GroupCommunicator::Sum); gcomm.Bcast(cu.GetData()); + */ // Compute means. for (int i = 0; i < cu.Size(); i++) { @@ -894,6 +896,7 @@ void scalarGrad3D(ParGridFunction &u, ParGridFunction &gu) { } } + /* // Count the zones globally. GroupCommunicator &gcomm = u.ParFESpace()->GroupComm(); gcomm.Reduce(zones_per_vdof, GroupCommunicator::Sum); @@ -902,6 +905,7 @@ void scalarGrad3D(ParGridFunction &u, ParGridFunction &gu) { // Accumulate for all vdofs. gcomm.Reduce(gu.GetData(), GroupCommunicator::Sum); gcomm.Bcast(gu.GetData()); + */ // Compute means. for (int dir = 0; dir < dim_; dir++) { @@ -985,6 +989,7 @@ void ComputeCurl2D(const ParGridFunction &u, ParGridFunction &cu, bool assume_sc // Communication. + /* // Count the zones globally. GroupCommunicator &gcomm = u.ParFESpace()->GroupComm(); gcomm.Reduce(zones_per_vdof, GroupCommunicator::Sum); @@ -993,6 +998,7 @@ void ComputeCurl2D(const ParGridFunction &u, ParGridFunction &cu, bool assume_sc // Accumulate for all vdofs. gcomm.Reduce(cu.GetData(), GroupCommunicator::Sum); gcomm.Bcast(cu.GetData()); + */ // Compute means. for (int i = 0; i < cu.Size(); i++) { @@ -1088,6 +1094,7 @@ void ComputeCurlAxi(const ParGridFunction &u, ParGridFunction &cu, bool assume_s // Communication. + /* // Count the zones globally. GroupCommunicator &gcomm = u.ParFESpace()->GroupComm(); gcomm.Reduce(zones_per_vdof, GroupCommunicator::Sum); @@ -1096,6 +1103,7 @@ void ComputeCurlAxi(const ParGridFunction &u, ParGridFunction &cu, bool assume_s // Accumulate for all vdofs. gcomm.Reduce(cu.GetData(), GroupCommunicator::Sum); gcomm.Bcast(cu.GetData()); + */ // Compute means. for (int i = 0; i < cu.Size(); i++) { @@ -1165,7 +1173,8 @@ bool copyFile(const char *SRC, const char *DEST) { return src && dest; } -void streamwiseGrad(int dim, ParGridFunction &phi, ParGridFunction &u, ParGridFunction &swGrad) { +// void streamwiseGrad(int dim, ParGridFunction &phi, ParGridFunction &u, ParGridFunction &swGrad) { +void streamwiseGrad(int dim, ParGridFunction &u, ParGridFunction &swGrad) { /* std::cout << "maxInd minusInd plusInd" << endl; std::cout << 0 << " " << ((0-1) % dim_ + dim_) % dim_ << " " << (0 + 1) % dim_ << endl; @@ -1174,12 +1183,12 @@ void streamwiseGrad(int dim, ParGridFunction &phi, ParGridFunction &u, ParGridFu */ // compute gradient of input field - scalarGrad3D(phi, swGrad); + // scalarGrad3D(phi, swGrad); const double *vel = u.HostRead(); double *gPhi = swGrad.HostReadWrite(); - int Sdof = phi.Size(); + int Sdof = u.Size() / dim; for (int dof = 0; dof < Sdof; dof++) { // streamwise coordinate system Vector unitNorm; @@ -1253,7 +1262,7 @@ void streamwiseGrad(int dim, ParGridFunction &phi, ParGridFunction &u, ParGridFu } */ - // muSWgbl = M_{im} muSw_{mn} M_{jn} or M*mu*M^T (with n,t1,t2 in columns of M) + // M_{im} swM_{mn} M_{jn} or M*"mu"*M^T (with n,t1,t2 in columns of M) DenseMatrix swMgbl(dim, dim); swMgbl = 0.0; for (int i = 0; i < dim; i++) { @@ -1266,11 +1275,12 @@ void streamwiseGrad(int dim, ParGridFunction &phi, ParGridFunction &u, ParGridFu } } - // mu*gPhi + // copy grad into local vecotr Vector tmp1; tmp1.SetSize(dim); for (int i = 0; i < dim; i++) tmp1[i] = gPhi[dof + i * Sdof]; + // gradient in streamwise-direction Vector tmp2; tmp2.SetSize(dim); for (int i = 0; i < dim; i++) tmp2[i] = 0.0; @@ -1285,6 +1295,34 @@ void streamwiseGrad(int dim, ParGridFunction &phi, ParGridFunction &u, ParGridFu } } +void upwindDiff(int dim, double re_factor, double re_offset, Vector &u_vec, Vector &rho_vec, Vector &del_vec, + Vector &Reh_vec, Vector &swDiff) { + const double *rho = rho_vec.HostRead(); + const double *del = del_vec.HostRead(); + const double *vel = u_vec.HostRead(); + const double *Reh = Reh_vec.HostRead(); + double *data = swDiff.HostReadWrite(); + + int Sdof = rho_vec.Size(); + for (int dof = 0; dof < Sdof; dof++) { + double Umag = 0.0; + for (int i = 0; i < dim; i++) Umag += vel[i] * vel[i]; + Umag = std::sqrt(Umag); + + // element Re + double Re = Reh[dof]; + + // SUPG weight + double Csupg = 0.5 * (tanh(re_factor * Re - re_offset) + 1.0); + + // streamwise diffusion coeff + double CswDiff = Csupg * Umag * del[dof] * rho[dof]; + + // scaled streamwise Laplacian + data[dof] *= CswDiff; + } +} + namespace mfem { GradientVectorGridFunctionCoefficient::GradientVectorGridFunctionCoefficient(const GridFunction *gf) : MatrixCoefficient((gf) ? gf->VectorDim() : 0) { diff --git a/src/utils.hpp b/src/utils.hpp index 603e0804b..8ae3877f8 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -174,7 +174,10 @@ void scalarGrad3D(ParGridFunction &u, ParGridFunction &gu); void vectorGrad3DV(FiniteElementSpace *fes, Vector u, Vector *gu, Vector *gv, Vector *gw); void scalarGrad3DV(FiniteElementSpace *fes, FiniteElementSpace *vfes, Vector u, Vector *gu); bool copyFile(const char *SRC, const char *DEST); -void streamwiseGrad(int dim, ParGridFunction &phi, ParGridFunction &u, ParGridFunction &swGrad); +// void streamwiseGrad(int dim, ParGridFunction &phi, ParGridFunction &u, ParGridFunction &swGrad); +void streamwiseGrad(int dim, ParGridFunction &u, ParGridFunction &swGrad); +void upwindDiff(int dim, double re_factor, double re_offset, Vector &u_vec, Vector &rho_vec, Vector &del_vec, + Vector &Reh_vec, Vector &swDiff); /// Eliminate essential BCs in an Operator and apply to RHS. /// rename this to something sensible "ApplyEssentialBC" or something