From 7deda8ffd11759a82684fa38208f44714c57a11b Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Fri, 15 May 2026 13:11:27 -0700 Subject: [PATCH 01/12] adding spark, wip --- src/reactingFlow.cpp | 53 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/src/reactingFlow.cpp b/src/reactingFlow.cpp index 76e6c61a..947d607b 100644 --- a/src/reactingFlow.cpp +++ b/src/reactingFlow.cpp @@ -83,9 +83,9 @@ static double sigmaTorchStartUp(const Vector &pos) { if (radius_here >= rCyl) rwgt = 0.0; sigma = 2000. * rwgt * hwgt; - if (sigma > 1.0) { - std::cout << "sigma: " << sigma << " radius: " << radius_here << " y: " << y << endl; - } + // if (sigma > 1.0) { + // std::cout << "sigma: " << sigma << " radius: " << radius_here << " y: " << y << endl; + // } return sigma; } @@ -790,6 +790,14 @@ ReactingFlow::ReactingFlow(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, tem tpsP_->getInput("loMach/reactingFlow/neumann-temp", neumann_temp_, false); tpsP_->getInput("loMach/reactingFlow/neumann-species-inlet", neumann_species_inlet_, true); tpsP_->getInput("loMach/reactingFlow/neumann-species-wall", neumann_species_wall_, true); + + // spark flow + Vector zero(dim_); + zero = 0.0; + tpsP_->getInput("loMach/reactingFlow/spark", spark_, false); + tpsP_->getVec("loMach/reactingFlow/spark-center",spark_center_, dim_, zero); + tpsP_->getInput("loMach/reactingFlow/spark-radius",spark_radius_, 0.0); + tpsP_->getInput("loMach/reactingFlow/spark-electron-mass-fraction",spark_peak_, 1.0e-18); } // NOLINT ReactingFlow::~ReactingFlow() { @@ -1998,6 +2006,45 @@ void ReactingFlow::step() { dt_ = time_coeff_.dt; time_ = time_coeff_.time; + // spark flow if triggered + if (spark_) { + int eSlot = nSpecies_ - 2; + int ionSlot = nSpecies_ - 3; + + ParGridFunction coordsDof(sfes); + pmesh_->GetNodes(coordsDof); + + // rough code + auto h_Yn = Yn_next_.HostReadWrite(); + for (int i = 0; i < sDofInt_; i++) { + + double x = coords(0 * sDofInt_ + i); + double y = coords(1 * sDofInt_ + i); + double z = coords(2 * sDofInt_ + i); + x = x - spark_center_[0]; + y = y - spark_center_[1]; + z = z - spark_center_[2]; + + double dist = spark_center_[0]; + double pi = 3.14159265359; + + + double rwgt, hwgt; + double sigma; + rwgt = std::exp(-0.5 * (radius_here / rsig) * (radius_here / rsig)); + hwgt = std::exp(-0.5 * ((y - y0) / ysig) * ((y - y0) / ysig)); + if (radius_here >= rCyl) rwgt = 0.0; + sigma = 2000. * rwgt * hwgt; + + + int sp = eSlot; + = h_Yn[sp * sDofInt_ + i]; + } + + speciesLastStep(); + spark_ = false; + } + // Set current time for velocity Dirichlet boundary conditions. for (auto &temp_dbc : temp_dbcs_) { temp_dbc.coeff->SetTime(time_ + dt_); From f741b34400fdbf68e743f0259d9e84502f47405e Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Fri, 15 May 2026 14:18:27 -0700 Subject: [PATCH 02/12] added sparking to reacting flow. builds, not tested --- src/reactingFlow.cpp | 67 +++++++++++++++++++++++++------------------- src/reactingFlow.hpp | 6 ++++ 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/reactingFlow.cpp b/src/reactingFlow.cpp index 947d607b..1aca08e1 100644 --- a/src/reactingFlow.cpp +++ b/src/reactingFlow.cpp @@ -792,12 +792,13 @@ ReactingFlow::ReactingFlow(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, tem tpsP_->getInput("loMach/reactingFlow/neumann-species-wall", neumann_species_wall_, true); // spark flow + spark_center_.SetSize(dim_); Vector zero(dim_); zero = 0.0; tpsP_->getInput("loMach/reactingFlow/spark", spark_, false); - tpsP_->getVec("loMach/reactingFlow/spark-center",spark_center_, dim_, zero); - tpsP_->getInput("loMach/reactingFlow/spark-radius",spark_radius_, 0.0); - tpsP_->getInput("loMach/reactingFlow/spark-electron-mass-fraction",spark_peak_, 1.0e-18); + tpsP_->getVec("loMach/reactingFlow/spark-center", spark_center_, dim_, zero); + tpsP_->getInput("loMach/reactingFlow/spark-radius", spark_radius_, 0.0); + tpsP_->getInput("loMach/reactingFlow/spark-electron-mass-fraction", spark_peak_, 1.0e-18); } // NOLINT ReactingFlow::~ReactingFlow() { @@ -2006,45 +2007,53 @@ void ReactingFlow::step() { dt_ = time_coeff_.dt; time_ = time_coeff_.time; - // spark flow if triggered + // spark flow at specified location if triggered + // TODO(swh) move to seperate function if (spark_) { + // TODO(swh) confirm that this check is alreay enforced elsewhere + int nSlot = nSpecies_ - 1; int eSlot = nSpecies_ - 2; int ionSlot = nSpecies_ - 3; - ParGridFunction coordsDof(sfes); - pmesh_->GetNodes(coordsDof); + const double m_n = mixture_->GetGasParams(nSlot, GasParams::SPECIES_MW); + const double m_e = mixture_->GetGasParams(eSlot, GasParams::SPECIES_MW); + const double m_ion = mixture_->GetGasParams(ionSlot, GasParams::SPECIES_MW); - // rough code - auto h_Yn = Yn_next_.HostReadWrite(); + ParGridFunction coordsDof(sfes_); + pmesh_->GetNodes(coordsDof); + auto h_Yn = Yn_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { - - double x = coords(0 * sDofInt_ + i); - double y = coords(1 * sDofInt_ + i); - double z = coords(2 * sDofInt_ + i); + // spark volume weight + double x, y, z, dist; + double wgt; + x = coordsDof(0 * sDofInt_ + i); + y = coordsDof(1 * sDofInt_ + i); x = x - spark_center_[0]; y = y - spark_center_[1]; - z = z - spark_center_[2]; - - double dist = spark_center_[0]; - double pi = 3.14159265359; + dist = x * x + y * y; + if (dim_ == 3) { + z = coordsDof(2 * sDofInt_ + i); + z = z - spark_center_[2]; + dist += z * z; + } + dist = std::sqrt(dist); + wgt = std::exp(-0.5 * (dist / spark_radius_) * (dist / spark_radius_)); + // free electron value (mass-fraction) + h_Yn[eSlot * sDofInt_ + i] = wgt * spark_peak_; - double rwgt, hwgt; - double sigma; - rwgt = std::exp(-0.5 * (radius_here / rsig) * (radius_here / rsig)); - hwgt = std::exp(-0.5 * ((y - y0) / ysig) * ((y - y0) / ysig)); - if (radius_here >= rCyl) rwgt = 0.0; - sigma = 2000. * rwgt * hwgt; + // correct ion value to stay consistent + h_Yn[ionSlot * sDofInt_ + i] -= h_Yn[eSlot * sDofInt_ + i] * m_ion / m_e; - - int sp = eSlot; - = h_Yn[sp * sDofInt_ + i]; + // correct nuetral + h_Yn[nSlot * sDofInt_ + i] -= h_Yn[eSlot * sDofInt_ + i] * m_n / m_e; } - - speciesLastStep(); + YnFull_gf_.SetFromTrueDofs(Yn_); + + // only do this once spark_ = false; - } - + } // end spark loop + // Set current time for velocity Dirichlet boundary conditions. for (auto &temp_dbc : temp_dbcs_) { temp_dbc.coeff->SetTime(time_ + dt_); diff --git a/src/reactingFlow.hpp b/src/reactingFlow.hpp index 18740071..26e7e575 100644 --- a/src/reactingFlow.hpp +++ b/src/reactingFlow.hpp @@ -171,6 +171,12 @@ class ReactingFlow : public ThermoChemModelBase { bool sw_stab_; double Reh_factor_, Reh_offset_; + // flow spark + bool spark_ = false; + double spark_radius_; + double spark_peak_; + Vector spark_center_; + // FEM related fields and objects // Scalar \f$H^1\f$ finite element collection. From 3f9e4b7c3ecf26cb7bd9926bae88356e14cafc60 Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Sat, 23 May 2026 02:04:54 -0700 Subject: [PATCH 03/12] fix to spark coordinates --- src/reactingFlow.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/reactingFlow.cpp b/src/reactingFlow.cpp index 1aca08e1..9636bf2b 100644 --- a/src/reactingFlow.cpp +++ b/src/reactingFlow.cpp @@ -797,7 +797,7 @@ ReactingFlow::ReactingFlow(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, tem zero = 0.0; tpsP_->getInput("loMach/reactingFlow/spark", spark_, false); tpsP_->getVec("loMach/reactingFlow/spark-center", spark_center_, dim_, zero); - tpsP_->getInput("loMach/reactingFlow/spark-radius", spark_radius_, 0.0); + tpsP_->getInput("loMach/reactingFlow/spark-radius", spark_radius_, 1.0); tpsP_->getInput("loMach/reactingFlow/spark-electron-mass-fraction", spark_peak_, 1.0e-18); } // NOLINT @@ -2010,6 +2010,8 @@ void ReactingFlow::step() { // spark flow at specified location if triggered // TODO(swh) move to seperate function if (spark_) { + if(rank0_) std::cout << "Sparking flow" << endl; + // TODO(swh) confirm that this check is alreay enforced elsewhere int nSlot = nSpecies_ - 1; int eSlot = nSpecies_ - 2; @@ -2019,10 +2021,11 @@ void ReactingFlow::step() { const double m_e = mixture_->GetGasParams(eSlot, GasParams::SPECIES_MW); const double m_ion = mixture_->GetGasParams(ionSlot, GasParams::SPECIES_MW); - ParGridFunction coordsDof(sfes_); + ParGridFunction coordsDof(vfes_); pmesh_->GetNodes(coordsDof); auto h_Yn = Yn_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { + // spark volume weight double x, y, z, dist; double wgt; @@ -2038,12 +2041,20 @@ void ReactingFlow::step() { } dist = std::sqrt(dist); wgt = std::exp(-0.5 * (dist / spark_radius_) * (dist / spark_radius_)); - + //if (rank0_) std::cout << "SPARK WGT: " << wgt << " | dist: " << dist << " | spark_radius: " << spark_radius_ << endl; + //wgt = 1.0; + //if(wgt < 0) { + //std::cout << "BAD WGT: " << wgt << endl; + //} + //if(wgt >1) { + //std::cout << "BAD WGT: " << wgt << endl; + //} + // free electron value (mass-fraction) - h_Yn[eSlot * sDofInt_ + i] = wgt * spark_peak_; + h_Yn[eSlot * sDofInt_ + i] += wgt * spark_peak_; // correct ion value to stay consistent - h_Yn[ionSlot * sDofInt_ + i] -= h_Yn[eSlot * sDofInt_ + i] * m_ion / m_e; + h_Yn[ionSlot * sDofInt_ + i] += h_Yn[eSlot * sDofInt_ + i] * m_ion / m_e; // correct nuetral h_Yn[nSlot * sDofInt_ + i] -= h_Yn[eSlot * sDofInt_ + i] * m_n / m_e; From 1a19236d4a72fa9130f1b49106cb852f6cf4806e Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Sun, 21 Jun 2026 12:27:31 -0700 Subject: [PATCH 04/12] Series of improvements to v2f and other small changes: 1) improved smoothed transition functions, 2) reinstated f and Pk filtering, 3) removed inconsistent streamwise-stabilization from Qt calculations, 4) added streamwise stab to v2f, and 5) added joule heating guards to prevent heating outside of the torch --- src/calorically_perfect.cpp | 50 +++++-- src/calorically_perfect.hpp | 3 + src/cycle_avg_joule_coupling.cpp | 2 +- src/gas_transport.cpp | 13 +- src/loMach.cpp | 6 +- src/lte_thermo_chem.cpp | 40 ++++-- src/quasimagnetostatic.cpp | 27 +++- src/reactingFlow.cpp | 157 ++++++++++++++++++--- src/tomboulides.cpp | 2 +- src/tps.cpp | 6 + src/zetaModel.cpp | 233 ++++++++++++++++++++++--------- src/zetaModel.hpp | 23 +++ 12 files changed, 440 insertions(+), 122 deletions(-) diff --git a/src/calorically_perfect.cpp b/src/calorically_perfect.cpp index 4a8a79b4..a25b5308 100644 --- a/src/calorically_perfect.cpp +++ b/src/calorically_perfect.cpp @@ -65,6 +65,15 @@ CaloricallyPerfectThermoChem::CaloricallyPerfectThermoChem(mfem::ParMesh *pmesh, order_ = loMach_opts->order; gridScale_gf_ = gridScale; + tps->getInput("loMach/axisymmetric", axisym_, false); + if (axisym_) { + if (rank0_) { + std::cout << "ERROR: axisymmetric is not currently implemented in calorically_perfect. Either implement or use LTE or reacting..." << std::endl; + } + assert(false); + exit(1); + } + std::string visc_model; tpsP_->getInput("loMach/calperfect/viscosity-model", visc_model, std::string("sutherland")); if (visc_model == "sutherland") { @@ -135,10 +144,10 @@ CaloricallyPerfectThermoChem::CaloricallyPerfectThermoChem(mfem::ParMesh *pmesh, tpsP_->getInput("loMach/calperfect/msolve-max-iter", mass_inverse_max_iter_, max_iter_); tpsP_->getInput("loMach/calperfect/msolve-verbosity", mass_inverse_pl_, pl_solve_); - // artificial diffusion (SUPG) + // artificial diffusion (SUPG) use full for all but momentum tpsP_->getInput("loMach/calperfect/streamwise-stabilization", sw_stab_, false); - tpsP_->getInput("loMach/calperfect/Reh_factor", Reh_factor_, 0.5); - tpsP_->getInput("loMach/calperfect/Reh_offset", Reh_offset_, 1.0); + tpsP_->getInput("loMach/calperfect/Reh_factor", Reh_factor_, 1.0); + tpsP_->getInput("loMach/calperfect/Reh_offset", Reh_offset_, 0.0); } CaloricallyPerfectThermoChem::~CaloricallyPerfectThermoChem() { @@ -348,6 +357,17 @@ void CaloricallyPerfectThermoChem::initializeSelf() { } AddTempDirichletBC(temperature_value, inlet_attr); + } else if (type == "normal") { + Array inlet_attr(pmesh_->bdr_attributes.Max()); + inlet_attr = 0; + inlet_attr[patch - 1] = 1; + double temperature_value; + tpsP_->getRequiredInput((basepath + "/temperature").c_str(), temperature_value); + if (rank0_) { + std::cout << "Calorically Perfect: Setting uniform Dirichlet temperature on patch = " << patch << std::endl; + } + AddTempDirichletBC(temperature_value, inlet_attr); + } else if (type == "interpolate") { Array inlet_attr(pmesh_->bdr_attributes.Max()); inlet_attr = 0; @@ -626,20 +646,25 @@ void CaloricallyPerfectThermoChem::initializeOperators() { MqInv_->SetMaxIter(mass_inverse_max_iter_); LQ_form_ = new ParBilinearForm(sfes_); - auto *lqd_blfi = new DiffusionIntegrator(*thermal_diff_total_coeff_); + //auto *lqd_blfi = new DiffusionIntegrator(*thermal_diff_total_coeff_); + //if (axisym_) { + // auto *lqd_blfi = new DiffusionIntegrator(*rad_thermal_diff_total_coeff_); + //} else { + auto *lqd_blfi = new DiffusionIntegrator(*thermal_diff_total_coeff_); + //} if (numerical_integ_) { lqd_blfi->SetIntRule(&ir_di); } LQ_form_->AddDomainIntegrator(lqd_blfi); - // SUPG diffusion - if (sw_stab_) { - auto *slqd_blfi = new DiffusionIntegrator(*supg_coeff_); - if (numerical_integ_) { - slqd_blfi->SetIntRule(&ir_di); - } - LQ_form_->AddDomainIntegrator(slqd_blfi); - } + // NO, this is not consistent and will degrade stability + // if (sw_stab_) { + // auto *slqd_blfi = new DiffusionIntegrator(*supg_coeff_); + // if (numerical_integ_) { + // slqd_blfi->SetIntRule(&ir_di); + // } + // LQ_form_->AddDomainIntegrator(slqd_blfi); + // } if (partial_assembly_) { LQ_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); @@ -1074,6 +1099,7 @@ void CaloricallyPerfectThermoChem::computeQtTO() { Qt_gf_.GetTrueDofs(Qt_); Qt_ *= -Rgas_ / thermo_pressure_; Qt_gf_.SetFromTrueDofs(Qt_); + } void CaloricallyPerfectThermoChem::screenHeader(std::vector &header) const { diff --git a/src/calorically_perfect.hpp b/src/calorically_perfect.hpp index 46b3378b..c86ba853 100644 --- a/src/calorically_perfect.hpp +++ b/src/calorically_perfect.hpp @@ -141,6 +141,9 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { bool sw_stab_; double Reh_factor_, Reh_offset_; + // not currently implemented but we need to yell if someone tries this + bool axisym_; + // FEM related fields and objects // Scalar \f$H^1\f$ finite element collection. diff --git a/src/cycle_avg_joule_coupling.cpp b/src/cycle_avg_joule_coupling.cpp index 296a2b78..7e1bcc64 100644 --- a/src/cycle_avg_joule_coupling.cpp +++ b/src/cycle_avg_joule_coupling.cpp @@ -502,7 +502,7 @@ void CycleAvgJouleCoupling::solveStep() { const double upd_jh = qmsa_solver_->totalJouleHeating(); if (rank0_) { grvy_printf(GRVY_INFO, "current_iter = %d\n", current_iter_); - grvy_printf(GRVY_INFO, "Joule heating scaling ratio = %d\n", ratio); + grvy_printf(GRVY_INFO, "Joule heating scaling ratio = %.6e\n", ratio); grvy_printf(GRVY_INFO, "The total input Joule heating after scaling = %.6e\n", upd_jh); } } diff --git a/src/gas_transport.cpp b/src/gas_transport.cpp index 15f39090..28d8c167 100644 --- a/src/gas_transport.cpp +++ b/src/gas_transport.cpp @@ -899,14 +899,11 @@ MFEM_HOST_DEVICE GasMixtureTransport::GasMixtureTransport(GasMixture *_mixture, if (inputs.gas == GasType::Ar) { gasType_ = Ar; - if (numSpecies > 6) { - printf("\nGas:Ar ternary transport only supports ternary mixture of Ar, Ar.+1, Ar_m, Ar_r, Ar_p, and E (%d)!\n", - numSpecies); - // if (numSpecies > 7) { - // printf( - // "\nGas:Ar ternary transport only supports ternary mixture of Ar, Ar.+1, Ar_m, Ar_r, Ar_p, Ar_h, and E " - // "(%d)!\n", - // numSpecies); + //if (numSpecies > 6) { + // printf("\nGas:Ar ternary transport only supports ternary mixture of Ar, Ar.+1, Ar_m, Ar_r, Ar_p, and E (%d)!\n", + // numSpecies); + if (numSpecies > 7) { + printf("Gas:Ar ternary transport only supports ternary mixture of Ar, Ar.+1, Ar_m, Ar_r, Ar_p, Ar_h, and E (%d)!\n", numSpecies); assert(false); } diff --git a/src/loMach.cpp b/src/loMach.cpp index 6f2a8169..7bc685f4 100644 --- a/src/loMach.cpp +++ b/src/loMach.cpp @@ -92,7 +92,7 @@ LoMachSolver::~LoMachSolver() { delete flow_; delete thermo_; delete sponge_; - delete turbModel_; + // delete turbModel_; // is this causing the seg faults? delete avg_opts_; delete average_; delete meshData_; @@ -417,16 +417,20 @@ void LoMachSolver::solveStep() { if (loMach_opts_.ts_opts_.integrator_type_ == LoMachTemporalOptions::CURL_CURL) { SetTimeIntegrationCoefficients(iter - iter_start_); extData_->step(); + sw_thermChem_.Start(); thermo_->step(); + sw_thermChem_.Stop(); sw_flow_.Start(); if (!disable_flow_) { flow_->step(); } + sw_flow_.Stop(); sw_turb_.Start(); turbModel_->step(); + sw_turb_.Stop(); } else { if (rank0_) std::cout << "Time integration not updated." << endl; diff --git a/src/lte_thermo_chem.cpp b/src/lte_thermo_chem.cpp index 285df56b..e95f6269 100644 --- a/src/lte_thermo_chem.cpp +++ b/src/lte_thermo_chem.cpp @@ -56,12 +56,13 @@ static double sigmaTorchStartUp(const Vector &pos) { const double x = std::sqrt(pos[0] * pos[0] + pos[2] * pos[2]); // radial location const double y = pos[1]; // axial location - const double r0 = 0.005; + //const double r0 = 0.005; + const double r0 = 0.0067; const double y0 = 0.135; const double ysig = 0.015; const double sigma = - 2000. * std::exp(-0.5 * (x / r0) * (x / r0)) * std::exp(-0.5 * ((y - y0) / ysig) * ((y - y0) / ysig)); + 4000. * std::exp(-0.5 * (x / r0) * (x / r0)) * std::exp(-0.5 * ((y - y0) / ysig) * ((y - y0) / ysig)); return sigma; } @@ -178,9 +179,10 @@ 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); + // use full stabilization for all but momentum tpsP_->getInput("loMach/ltethermo/streamwise-stabilization", sw_stab_, false); - tpsP_->getInput("loMach/ltethermo/Reh_factor", Reh_factor_, 0.5); - tpsP_->getInput("loMach/ltethermo/Reh_offset", Reh_offset_, 1.0); + tpsP_->getInput("loMach/ltethermo/Reh_factor", Reh_factor_, 1.0); + tpsP_->getInput("loMach/ltethermo/Reh_offset", Reh_offset_, 0.0); tpsP_->getInput("loMach/ltethermo/neumann-temp", neumann_temp_, false); if (sw_stab_) { @@ -467,6 +469,17 @@ void LteThermoChem::initializeSelf() { } // AddTempDirichletBC(temperature_value, inlet_attr); + } else if (type == "normal") { + Array inlet_attr(pmesh_->bdr_attributes.Max()); + inlet_attr = 0; + inlet_attr[patch - 1] = 1; + double temperature_value; + tpsP_->getRequiredInput((basepath + "/temperature").c_str(), temperature_value); + if (rank0_) { + std::cout << "Calorically Perfect: Setting uniform Dirichlet temperature on patch = " << patch << std::endl; + } + AddTempDirichletBC(temperature_value, inlet_attr); + } else if (type == "interpolate") { temperature_bc_field_ = new GridFunctionCoefficient(extData_interface_->Tdata); if (!neumann_temp_) { @@ -902,15 +915,17 @@ void LteThermoChem::initializeOperators() { } LQ_form_->AddDomainIntegrator(lqd_blfi); - if (sw_stab_) { - auto *slqd_blfi = new DiffusionIntegrator(*supg_coeff_); - if (numerical_integ_) { - slqd_blfi->SetIntRule(&ir_di); - } - LQ_form_->AddDomainIntegrator(slqd_blfi); - } + // NO, this is not consistent and will degrade stability + //if (sw_stab_) { + // auto *slqd_blfi = new DiffusionIntegrator(*supg_coeff_); + // if (numerical_integ_) { + // slqd_blfi->SetIntRule(&ir_di); + // } + // LQ_form_->AddDomainIntegrator(slqd_blfi); + // } + if (partial_assembly_) { - LQ_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); + LQ_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); } LQ_form_->Assemble(); LQ_form_->FormSystemMatrix(empty, LQ_); @@ -961,6 +976,7 @@ void LteThermoChem::initializeOperators() { Tn_gf_.GetTrueDofs(Tn_); Tn_next_gf_.SetFromTrueDofs(Tn_); Tn_next_gf_.GetTrueDofs(Tn_next_); + } else if (filter_restart_) { if (rank0_) std::cout << "************ Filtering temperature restart ******************" << std::endl; // Build the right-hand-side diff --git a/src/quasimagnetostatic.cpp b/src/quasimagnetostatic.cpp index 20856a07..a27a4d27 100644 --- a/src/quasimagnetostatic.cpp +++ b/src/quasimagnetostatic.cpp @@ -222,6 +222,7 @@ void QuasiMagnetostaticSolver3D::initialize() { joule_heating_ = new ParGridFunction(jh_space_); *joule_heating_ = 0.0; + if (rank0_) std::cout << "QM3D initialize okay..." << endl; } void QuasiMagnetostaticSolver3D::InitializeCurrent() { @@ -277,13 +278,13 @@ void QuasiMagnetostaticSolver3D::InitializeCurrent() { PWConstCoefficient J0coef(J0); VectorFunctionCoefficient current(dim_, JFun, &J0coef); - + // 2) Build a discretely divergence-free approximation of the source // current that lives in the Nedelec FE space defined in // Initialize() ParGridFunction *Jorig = new ParGridFunction(Aspace_); ParGridFunction *Jproj = new ParGridFunction(Aspace_); - + r_ = new ParLinearForm(Aspace_); // This call (i.e., GlobalProjectDiscCoefficient) replaces the @@ -316,6 +317,7 @@ void QuasiMagnetostaticSolver3D::InitializeCurrent() { delete Jproj; current_initialized_ = true; + if (rank0_) std::cout << "InitializeCurrent okay..." << endl; } // query solver-specific runtime controls @@ -698,6 +700,26 @@ double QuasiMagnetostaticSolver3D::elementJouleHeating(const FiniteElement &el, const double wt = ip.weight * Tr.Weight(); elem_jh += qpcontrib * wt; + + // HERE + // need to modify here so that joule heating is only IN torch + // this is a problem-specific hack (HACK) + double rCyl = 0.028; + double x, y, z, dist; + double wgt = 1.0; + Vector coords(Tr.GetSpaceDim()); + Tr.Transform(ip, coords); + x = coords[0]; + y = coords[1]; + dist = x * x; + if (dim_ == Tr.GetSpaceDim()) { + z = coords[2]; + dist += z * z; + } + dist = std::sqrt(dist); + if (dist > rCyl) wgt = 0.0; + elem_jh *= wgt; + } return elem_jh; @@ -728,6 +750,7 @@ double QuasiMagnetostaticSolver3D::totalJouleHeating() { // following bad fields here (el_x has the actual data)... int_jh += elementJouleHeating(*fe, *T, el_x); + } // sum over mpi ranks diff --git a/src/reactingFlow.cpp b/src/reactingFlow.cpp index 9636bf2b..065eb5b6 100644 --- a/src/reactingFlow.cpp +++ b/src/reactingFlow.cpp @@ -71,8 +71,9 @@ static double sigmaTorchStartUp(const Vector &pos) { // additions for 3d, this should just use "SetConstantPlasmaConductivity" in equation_of_state.cpp const double z = pos[2]; const double rCyl = 0.029; - const double rsig = 0.005; // 5mm - const double ysig = 0.01; + //const double rsig = 0.005; // 5mm + const double rsig = 0.0075; + const double ysig = 0.1; const double y0 = 0.15; // step location double radius_here = std::sqrt(x * x + z * z); @@ -81,7 +82,7 @@ static double sigmaTorchStartUp(const Vector &pos) { rwgt = std::exp(-0.5 * (radius_here / rsig) * (radius_here / rsig)); hwgt = std::exp(-0.5 * ((y - y0) / ysig) * ((y - y0) / ysig)); if (radius_here >= rCyl) rwgt = 0.0; - sigma = 2000. * rwgt * hwgt; + sigma = 4000. * rwgt * hwgt; // if (sigma > 1.0) { // std::cout << "sigma: " << sigma << " radius: " << radius_here << " y: " << y << endl; @@ -90,7 +91,30 @@ static double sigmaTorchStartUp(const Vector &pos) { return sigma; } +static double sigmaTorchStartUp2D(const Vector &pos) { + const double x = std::sqrt(pos[0] * pos[0]); // radial location + const double y = pos[1]; // axial location + + // additions for 3d, this should just use "SetConstantPlasmaConductivity" in equation_of_state.cpp + const double rCyl = 0.029; + const double rsig = 0.005; // 5mm + const double ysig = 0.01; + const double y0 = 0.15; // step location + + double radius_here = std::sqrt(x * x); + double rwgt, hwgt; + double sigma; + rwgt = std::exp(-0.5 * (radius_here / rsig) * (radius_here / rsig)); + hwgt = std::exp(-0.5 * ((y - y0) / ysig) * ((y - y0) / ysig)); + if (radius_here >= rCyl) rwgt = 0.0; + sigma = 2000. * rwgt * hwgt; + + return sigma; +} + + static FunctionCoefficient sigma_start_up(sigmaTorchStartUp); +static FunctionCoefficient sigma_start_up_2d(sigmaTorchStartUp2D); ReactingFlow::ReactingFlow(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalSchemeCoefficients &time_coeff, ParGridFunction *gridScale, TPS::Tps *tps) @@ -781,10 +805,10 @@ ReactingFlow::ReactingFlow(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, tem // artificial diffusion (SUPG) tpsP_->getInput("loMach/reactingFlow/streamwise-stabilization", sw_stab_, false); - // specified plasma initial condition + // specified plasma initial condition (use full sw-stab for all but momentum) tpsP_->getInput("plasma_models/initialize_species", species_init_, false); - tpsP_->getInput("loMach/reactingFlow/Reh_factor", Reh_factor_, 0.5); - tpsP_->getInput("loMach/reactingFlow/Reh_offset", Reh_offset_, 1.0); + tpsP_->getInput("loMach/reactingFlow/Reh_factor", Reh_factor_, 1.0); + tpsP_->getInput("loMach/reactingFlow/Reh_offset", Reh_offset_, 0.0); // zero-gradient BCs tpsP_->getInput("loMach/reactingFlow/neumann-temp", neumann_temp_, false); @@ -1421,7 +1445,12 @@ void ReactingFlow::initializeOperators() { // TODO(trevilo): Put a flag for this!!!! if (torch_cold_start_) { if (rank0_) std::cout << " Cold start selected. Specifying sigma field." << endl; - sigma_gf_.ProjectCoefficient(sigma_start_up); + if (dim_ == 3) { + sigma_gf_.ProjectCoefficient(sigma_start_up); + } else { + sigma_gf_.ProjectCoefficient(sigma_start_up_2d); + } + } Array empty; @@ -1829,14 +1858,17 @@ void ReactingFlow::initializeOperators() { } LQ_form_->AddDomainIntegrator(lqd_blfi); - DiffusionIntegrator *slqd_blfi; - if (sw_stab_) { - slqd_blfi = new DiffusionIntegrator(*supg_coeff_); - if (numerical_integ_) { - slqd_blfi->SetIntRule(&ir_di); - } - LQ_form_->AddDomainIntegrator(slqd_blfi); - } + + // NO, this is not consistent and will degrade stability + // DiffusionIntegrator *slqd_blfi; + // if (sw_stab_) { + // slqd_blfi = new DiffusionIntegrator(*supg_coeff_); + // if (numerical_integ_) { + // slqd_blfi->SetIntRule(&ir_di); + // } + // LQ_form_->AddDomainIntegrator(slqd_blfi); + // } + if (partial_assembly_) { LQ_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); } @@ -2373,6 +2405,37 @@ void ReactingFlow::temperatureStep() { jh_form_->Update(); jh_form_->Assemble(); jh_form_->ParallelAssemble(jh_); + + + + // this bit is to prevent joule heating bleed -> make more elegant and then move to separate routine + ParGridFunction coordsDof(vfes_); + pmesh_->GetNodes(coordsDof); + double rCyl = 0.029; + { + double *djh = jh_.HostReadWrite(); + for (int i = 0; i < sDofInt_; i++) { + + double x, y, z, dist; + double wgt; + x = coordsDof(0 * sDofInt_ + i); + // y = coordsDof(1 * sDofInt_ + i); + dist = x * x; + if (dim_ == 3) { + z = coordsDof(2 * sDofInt_ + i); + z = z - spark_center_[2]; + dist += z * z; + } + dist = std::sqrt(dist); + wgt = 1.0; + if (dist > rCyl) wgt = 0.0; + djh[i] *= wgt; + + } + } + + + resT_ += jh_; // species-temp diffusion term, already in int-weak form @@ -3225,10 +3288,16 @@ void ReactingFlow::updateDiffusivity() { // electrical conductivity if (!torch_cold_start_ && !fixed_conductivity_) { - // if(rank0_) std::cout << " sigma update portion... " << endl; + + // this bit is to prevent joule heating bleed + //ParGridFunction coordsDof(vfes_); + //pmesh_->GetNodes(coordsDof); + //double rCyl = 0.029; + { double *h_sig = sigma_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { + // int nEq = dim_ + 2 + nActiveSpecies_; double state[gpudata::MAXEQUATIONS]; double conservedState[gpudata::MAXEQUATIONS]; @@ -3248,7 +3317,23 @@ void ReactingFlow::updateDiffusivity() { double sig; transport_->ComputeElectricalConductivity(conservedState, sig); - h_sig[i] = sig; + h_sig[i] = sig; + + // this is hack to prevent heating in outflow tank + //double x, y, z, dist; + //double wgt; + //x = coordsDof(0 * sDofInt_ + i); + //y = coordsDof(1 * sDofInt_ + i); + //dist = x * x; + //if (dim_ == 3) { + // z = coordsDof(2 * sDofInt_ + i); + // dist += z * z; + //} + //dist = std::sqrt(dist); + //wgt = 1.0; + //if (dist > rCyl) wgt = 0.0; + //h_sig[i] = wgt * sig; + } } @@ -3257,7 +3342,8 @@ void ReactingFlow::updateDiffusivity() { } void ReactingFlow::evaluatePlasmaConductivityGF() { - if (rank0_) std::cout << " we are in evaluatePlasmaConductivityGF " << endl; + + if (rank0_) std::cout << " ...we are in evaluatePlasmaConductivityGF " << endl; (flow_interface_->velocity)->GetTrueDofs(tmpR1_); const double *dataTemp = Tn_.HostRead(); @@ -3442,6 +3528,12 @@ void ReactingFlow::AddQtDirichletBC(ScalarFuncT *f, Array &attr) { AddQtDirichletBC(new FunctionCoefficient(f), attr); } +// Rather than filtering Qt, a better way is to filter the temperature +// that is fed to the Qt operators. In particular, temperature +// should live in C1 (at least). This can be done with polynomial +// space filtering or numericallly with and (I-alpha*nabla)T type +// filter. In the latter, alpha should depend on discontinuity in +// grad(T) at element boundaries (which is annoying to compute). void ReactingFlow::computeQtTO() { tmpR0_ = 0.0; // rhsqt_bd_ = 0.0; @@ -3473,6 +3565,35 @@ void ReactingFlow::computeQtTO() { jh_form_->Update(); jh_form_->Assemble(); jh_form_->ParallelAssemble(jh_); + + + // this bit is to prevent joule heating bleed -> make more elegant and then move to separate routine + ParGridFunction coordsDof(vfes_); + pmesh_->GetNodes(coordsDof); + double rCyl = 0.029; + { + double *djh = jh_.HostReadWrite(); + for (int i = 0; i < sDofInt_; i++) { + + double x, y, z, dist; + double wgt; + x = coordsDof(0 * sDofInt_ + i); + // y = coordsDof(1 * sDofInt_ + i); + dist = x * x; + if (dim_ == 3) { + z = coordsDof(2 * sDofInt_ + i); + z = z - spark_center_[2]; + dist += z * z; + } + dist = std::sqrt(dist); + wgt = 1.0; + if (dist > rCyl) wgt = 0.0; + djh[i] *= wgt; + + } + } + + tmpR0_ -= jh_; // rhsqt_jh_.SetFromTrueDofs(jh_); // rhsqt_jh_.Neg(); diff --git a/src/tomboulides.cpp b/src/tomboulides.cpp index 607f413b..80e08a59 100644 --- a/src/tomboulides.cpp +++ b/src/tomboulides.cpp @@ -131,7 +131,7 @@ Tomboulides::Tomboulides(mfem::ParMesh *pmesh, int vorder, int porder, temporalS tps->getInput("loMach/tomboulides/hsolve-maxIters", hsolve_max_iter_, default_max_iter_); tps->getInput("loMach/tomboulides/msolve-maxIters", mass_inverse_max_iter_, default_max_iter_); - // artificial diffusion (SUPG) + // artificial diffusion (SUPG) full-streamwise stab is fine for RANS, but not for LES tpsP_->getInput("loMach/tomboulides/streamwise-stabilization", sw_stab_, false); tpsP_->getInput("loMach/tomboulides/Reh_factor", Reh_factor_, 0.5); tpsP_->getInput("loMach/tomboulides/Reh_offset", Reh_offset_, 1.0); diff --git a/src/tps.cpp b/src/tps.cpp index ab95c001..3ee945bc 100644 --- a/src/tps.cpp +++ b/src/tps.cpp @@ -248,22 +248,28 @@ void Tps::chooseSolver() { if (input_solver_type_ == "flow") { isFlowOnlyMode_ = true; solver_ = new M2ulPhyS(iFile_, this); + if (isRank0_) std::cout << "Using compressible DG solver" << endl; } else if (input_solver_type_ == "em") { isEMOnlyMode_ = true; ElectromagneticOptions em_opt; solver_ = new QuasiMagnetostaticSolver3D(em_opt, this); + if (isRank0_) std::cout << "Using quasi-magnetostatic solver" << endl; } else if (input_solver_type_ == "loMach") { solver_ = new LoMachSolver(this); + if (isRank0_) std::cout << "Using low-Mach solver" << endl; } else if (input_solver_type_ == "em-axi") { isEMOnlyMode_ = true; ElectromagneticOptions em_opt; solver_ = new QuasiMagnetostaticSolverAxiSym(em_opt, this); + if (isRank0_) std::cout << "Using axisymmetric quasi-magnetostatic solver" << endl; } else if (input_solver_type_ == "independent-coupled") { isFlowEMCoupledMode_ = true; solver_ = new IndependentCoupling(iFile_, this); + if (isRank0_) std::cout << "Using independent-coupled solver" << endl; } else if (input_solver_type_ == "cycle-avg-joule-coupled") { isFlowEMCoupledMode_ = true; solver_ = new CycleAvgJouleCoupling(iFile_, this); + if (isRank0_) std::cout << "Using cycle-averaged joule-coupled solver" << endl; } else if (input_solver_type_ == "coupled") { isFlowEMCoupledMode_ = true; grvy_printf(GRVY_ERROR, "\nSlow your roll. Solid high-five for whoever implements this coupled solver mode!\n"); diff --git a/src/zetaModel.cpp b/src/zetaModel.cpp index e830c0c0..1b52dfe8 100644 --- a/src/zetaModel.cpp +++ b/src/zetaModel.cpp @@ -51,6 +51,8 @@ using namespace mfem::common; static double radius(const Vector &pos) { return pos[0]; } static FunctionCoefficient radius_coeff(radius); +double smoothMin(double val1, double val2); +double smoothMax(double val1, double val2); ZetaModel::ZetaModel(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalSchemeCoefficients &time_coeff, TPS::Tps *tps, ParGridFunction *gridScale) @@ -88,6 +90,11 @@ ZetaModel::ZetaModel(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalS tpsP_->getInput("ransModel/zfp-max", zfp_max_, 1.0e12); tpsP_->getInput("ransModel/v2-production-rate-coeff-limit", v2Prod_fLimiter_coeff_, 1.0e6); + // streamwise stabilization (add full, no real disadvantage like in momentum) + tpsP_->getInput("ransModel/streamwise-stabilization", sw_stab_, false); + tpsP_->getInput("ransModel/Reh_factor", Reh_factor_, 1.0); + tpsP_->getInput("ransModel/Reh_offset", Reh_offset_, 0.0); + // solver options tpsP_->getInput("ransModel/hsolve-maxIters", max_iter_, 2000); tpsP_->getInput("ransModel/fsolve-maxIters", f_max_iter_, 4000); @@ -100,6 +107,7 @@ ZetaModel::ZetaModel(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalS } ZetaModel::~ZetaModel() { + delete As_form_; delete Ms_form_; delete MsRho_form_; @@ -139,8 +147,8 @@ ZetaModel::~ZetaModel() { delete prod_coeff_; delete tke_coeff_; delete nu_coeff_; - // delete nu_delta_coeff_; delete gradTKE_coeff_; + // delete nu_delta_coeff_; // delete two_nu_delta_coeff_; // NOTE: seg fault originates from deleting coeffs used for BCs, which is done automatically in @@ -161,6 +169,7 @@ ZetaModel::~ZetaModel() { delete tdr_diff_total_coeff_; delete zeta_diff_total_coeff_; // delete unity_diff_total_coeff_; + delete rhoDt_coeff_; delete rhoTTS_coeff_; delete Ce2_coeff_; @@ -196,6 +205,7 @@ ZetaModel::~ZetaModel() { delete sfes_; delete vfec_; delete vfes_; + } void ZetaModel::initializeSelf() { @@ -207,6 +217,7 @@ void ZetaModel::initializeSelf() { // scalar sfec_ = new H1_FECollection(order_); + //sfec_ = new H1_FECollection(forder_); sfes_ = new ParFiniteElementSpace(pmesh_, sfec_); // f-rate @@ -215,6 +226,7 @@ void ZetaModel::initializeSelf() { // vector vfec_ = new H1_FECollection(order_, dim_); + //vfec_ = new H1_FECollection(forder_, dim_); vfes_ = new ParFiniteElementSpace(pmesh_, vfec_, dim_); // Check if fully periodic mesh @@ -267,11 +279,17 @@ void ZetaModel::initializeSelf() { v2_gf_ = 2.0 / 3.0 * tke_min_; v2_gf_.GetTrueDofs(v2_); - fRate_gf_.SetSpace(ffes_); - fRate_.SetSize(ffes_truevsize); + // only source (and L^2) will be filtered + fRate_gf_.SetSpace(sfes_); + fRate_.SetSize(sfes_truevsize); fRate_gf_ = 0.0; fRate_ = 0.0; + filter_gf_.SetSpace(ffes_); + filter_.SetSize(ffes_truevsize); + filter_gf_ = 0.0; + filter_ = 0.0; + tke_next_gf_.SetSpace(sfes_); tke_next_.SetSize(sfes_truevsize); tke_next_gf_ = tke_gf_; @@ -346,11 +364,11 @@ void ZetaModel::initializeSelf() { tls_gf_ = 1.0; tls_gf_.GetTrueDofs(tls_); - tls2_gf_.SetSpace(ffes_); - tls2_.SetSize(ffes_truevsize); + tls2_gf_.SetSpace(sfes_); + tls2_.SetSize(sfes_truevsize); tls2_gf_ = 1.0; tls2_gf_.GetTrueDofs(tls2_); - + tts_gf_.SetSpace(sfes_); tts_.SetSize(sfes_truevsize); tts_gf_ = 1.0; @@ -395,8 +413,8 @@ void ZetaModel::initializeSelf() { vfres_gf_.SetSpace(sfes_); - resf_gf_.SetSpace(ffes_); - resf_.SetSize(ffes_truevsize); + resf_gf_.SetSpace(sfes_); + resf_.SetSize(sfes_truevsize); rho_.SetSize(sfes_truevsize); mu_.SetSize(sfes_truevsize); @@ -416,7 +434,6 @@ void ZetaModel::initializeSelf() { tmpR0a_.SetSize(sfes_truevsize); tmpR0b_.SetSize(sfes_truevsize); tmpR0c_.SetSize(sfes_truevsize); - ftmpR0_.SetSize(ffes_truevsize); rhoDt_gf_.SetSpace(sfes_); @@ -467,6 +484,7 @@ void ZetaModel::initializeSelf() { if (axisym_) { radius_gf_.ProjectCoefficient(radius_coeff); radius_gf_.GetTrueDofs(radius_v_); + // fradius_gf_.ProjectGridFunction(radius_gf_); } //----------------------------------------------------- @@ -613,12 +631,11 @@ void ZetaModel::initializeSelf() { sfes_->GetEssentialTrueDofs(tdr_ess_attr_, tdr_ess_tdof_); sfes_->GetEssentialTrueDofs(zeta_ess_attr_, zeta_ess_tdof_); sfes_->GetEssentialTrueDofs(v2_ess_attr_, v2_ess_tdof_); - ffes_->GetEssentialTrueDofs(fRate_ess_attr_, fRate_ess_tdof_); + sfes_->GetEssentialTrueDofs(fRate_ess_attr_, fRate_ess_tdof_); if (rank0_) std::cout << "Zeta-f RANS model essential true dof step" << endl; } void ZetaModel::initializeOperators() { - if (rank0_) std::cout << "... here we go ..." << endl; dt_ = time_coeff_.dt; Array empty; @@ -630,8 +647,8 @@ void ZetaModel::initializeOperators() { const IntegrationRule &ir_nli = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 4 * order_); const IntegrationRule &ir_di = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * order_ - 1); - const IntegrationRule &ir_if = gll_rules_.Get(ffes_->GetFE(0)->GetGeomType(), 2 * forder_ + 1); - const IntegrationRule &ir_dif = gll_rules_.Get(ffes_->GetFE(0)->GetGeomType(), 3 * forder_ - 1); + const IntegrationRule &ir_if = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * forder_ + 1); + const IntegrationRule &ir_dif = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * forder_ - 1); // coefficients for operators zero_coeff_ = new ConstantCoefficient(0.0); @@ -677,7 +694,7 @@ void ZetaModel::initializeOperators() { tdr_diff_total_coeff_ = new ProductCoefficient(*mult_coeff_, *tdr_diff_sum_coeff_); zeta_diff_total_coeff_ = new ProductCoefficient(*mult_coeff_, *zeta_diff_sum_coeff_); // unity_diff_total_coeff_ = new ProductCoefficient(*unity_coeff_, *unity_diff_coeff_); - + // unsteady- and destruction-related rhoDt_gf_ = *(thermoChem_interface_->density); rhoDt_gf_ /= dt_; @@ -694,6 +711,7 @@ void ZetaModel::initializeOperators() { zeta_diag_coeff_ = new SumCoefficient(*rhoDt_coeff_, *Pk_coeff_, 1.0, 1.0); v2_diag_coeff_ = new SumCoefficient(*rhoDt_coeff_, *rhoTTS_coeff_, 1.0, 6.0 * des_wgt_); // v2_diag_coeff_ = new SumCoefficient(*rhoDt_coeff_, *ek_rho_coeff_, 1.0, 6.0*des_wgt_); + f_diag_coeff_ = new RatioCoefficient(1.0, *tls2_coeff_); f_diag_total_coeff_ = new SumCoefficient(*f_diag_coeff_, *zero_coeff_); @@ -706,15 +724,51 @@ void ZetaModel::initializeOperators() { rad_tdr_diag_coeff_ = new ProductCoefficient(radius_coeff, *tdr_diag_coeff_); rad_tdr_diff_total_coeff_ = new ProductCoefficient(radius_coeff, *tdr_diff_total_coeff_); rad_v2_diag_coeff_ = new ProductCoefficient(radius_coeff, *v2_diag_coeff_); - rad_f_diag_coeff_ = new ProductCoefficient(radius_coeff, *f_diag_coeff_); rad_unity_coeff_ = new ProductCoefficient(radius_coeff, *unity_coeff_); rad_zeta_diag_coeff_ = new ProductCoefficient(radius_coeff, *zeta_diag_coeff_); rad_zeta_diff_total_coeff_ = new ProductCoefficient(radius_coeff, *zeta_diff_total_coeff_); rad_scalar_diff_coeff_ = new ProductCoefficient(radius_coeff, *scalar_diff_coeff_); rad_nu_gradTKE_coeff_ = new ScalarVectorProductCoefficient(radius_coeff, *nu_gradTKE_coeff_); + + // need separate coeffs for f-space (all of em) + // rad_f_diag_coeff_ = new ProductCoefficient(fradius_coeff, *f_diag_coeff_); + rad_f_diag_coeff_ = new ProductCoefficient(radius_coeff, *f_diag_coeff_); + } - if (rank0_) std::cout << "... coeffs set ..." << endl; + // artifical diffusion coefficients + if (sw_stab_) { + + gscale_coeff_ = new GridFunctionCoefficient(gridScale_gf_); + umag_coeff_ = new VectorMagnitudeCoefficient(*vel_coeff_); + + visc_coeff_ = new GridFunctionCoefficient(*mu_coeff_); + visc_inv_coeff_ = new PowerCoefficient(*visc_coeff_, -1.0); + + // compute Reh + reh1_coeff_ = new ProductCoefficient(*rho_coeff_, *visc_inv_coeff_); + reh2_coeff_ = new ProductCoefficient(*reh1_coeff_, *gscale_coeff_); + Reh_coeff_ = new ProductCoefficient(*reh2_coeff_, *umag_coeff_); + + // Csupg + std::function csupgLambda = std::bind(csupgFactor, std::placeholders::_1, Reh_factor_, Reh_offset_); + csupg_coeff_ = new ExtTransformedCoefficient(Reh_coeff_, csupgLambda); + + // compute upwind magnitude + if (axisym_) { + uw1_coeff_ = new ProductCoefficient(*rad_rho_coeff_, *csupg_coeff_); + } else { + uw1_coeff_ = new ProductCoefficient(*rho_coeff_, *csupg_coeff_); + } + uw2_coeff_ = new ProductCoefficient(*uw1_coeff_, *gscale_coeff_); + upwind_coeff_ = new ProductCoefficient(*uw2_coeff_, *umag_coeff_); + + // streamwise diffusion direction + swdiff_coeff_ = new TransformedMatrixVectorCoefficient(vel_coeff_, &streamwiseTensor); + + supg_coeff_ = new ScalarMatrixProductCoefficient(*upwind_coeff_, *swdiff_coeff_); + } + // operators As_form_ = new ParBilinearForm(sfes_); ConvectionIntegrator *as_blfi; @@ -732,7 +786,6 @@ void ZetaModel::initializeOperators() { } As_form_->Assemble(); As_form_->FormSystemMatrix(empty, As_); - if (rank0_) std::cout << "... op 0 ..." << endl; // mass matrix Ms_form_ = new ParBilinearForm(sfes_); @@ -751,7 +804,6 @@ void ZetaModel::initializeOperators() { } Ms_form_->Assemble(); Ms_form_->FormSystemMatrix(empty, Ms_); - if (rank0_) std::cout << "... op 1 ..." << endl; // mass matrix with rho MsRho_form_ = new ParBilinearForm(sfes_); @@ -771,7 +823,7 @@ void ZetaModel::initializeOperators() { } MsRho_form_->Assemble(); MsRho_form_->FormSystemMatrix(empty, MsRho_); - Mf_form_ = new ParBilinearForm(ffes_); + Mf_form_ = new ParBilinearForm(sfes_); MassIntegrator *mf_blfi; if (axisym_) { mf_blfi = new MassIntegrator(radius_coeff); @@ -787,7 +839,6 @@ void ZetaModel::initializeOperators() { } Mf_form_->Assemble(); Mf_form_->FormSystemMatrix(empty, Mf_); - if (rank0_) std::cout << "... op 3 ..." << endl; // diffusion of tke for tdr bc /* @@ -816,8 +867,6 @@ void ZetaModel::initializeOperators() { // Helmholtz operators for lhs of all scalars Hk_form_ = new ParBilinearForm(sfes_); - if (rank0_) std::cout << "... op 4 1..." << endl; - // auto *hmk_blfi = new MassIntegrator(*tke_diag_coeff_); // auto *hmk_blfi = new MassIntegrator(*rhoDt_coeff_); // auto *hdk_blfi = new DiffusionIntegrator(*tke_diff_total_coeff_); @@ -830,18 +879,21 @@ void ZetaModel::initializeOperators() { hmk_blfi = new MassIntegrator(*tke_diag_coeff_); hdk_blfi = new DiffusionIntegrator(*tke_diff_total_coeff_); } - if (rank0_) std::cout << "... op 4 2..." << endl; if (numerical_integ_) { hmk_blfi->SetIntRule(&ir_di); hdk_blfi->SetIntRule(&ir_i); } Hk_form_->AddDomainIntegrator(hmk_blfi); Hk_form_->AddDomainIntegrator(hdk_blfi); - if (rank0_) std::cout << "... op 4 3 ..." << endl; + if (sw_stab_) { + auto *sdk_blfi = new DiffusionIntegrator(*supg_coeff_); + if (numerical_integ_) { + sdk_blfi->SetIntRule(&ir_di); + } + Hk_form_->AddDomainIntegrator(sdk_blfi); + } Hk_form_->Assemble(); - if (rank0_) std::cout << "... op 4 4 ..." << endl; Hk_form_->FormSystemMatrix(tke_ess_tdof_, Hk_); - if (rank0_) std::cout << "... op 4 5 ..." << endl; He_form_ = new ParBilinearForm(sfes_); // auto *hme_blfi = new MassIntegrator(*tdr_diag_coeff_); @@ -863,9 +915,15 @@ void ZetaModel::initializeOperators() { } He_form_->AddDomainIntegrator(hme_blfi); He_form_->AddDomainIntegrator(hde_blfi); + if (sw_stab_) { + auto *sde_blfi = new DiffusionIntegrator(*supg_coeff_); + if (numerical_integ_) { + sde_blfi->SetIntRule(&ir_di); + } + He_form_->AddDomainIntegrator(sde_blfi); + } He_form_->Assemble(); He_form_->FormSystemMatrix(tdr_ess_tdof_, He_); - if (rank0_) std::cout << "... op 5 ..." << endl; Hv_form_ = new ParBilinearForm(sfes_); // auto *hmv_blfi = new MassIntegrator(*v2_diag_coeff_); @@ -886,11 +944,17 @@ void ZetaModel::initializeOperators() { } Hv_form_->AddDomainIntegrator(hmv_blfi); Hv_form_->AddDomainIntegrator(hdv_blfi); + if (sw_stab_) { + auto *sdv_blfi = new DiffusionIntegrator(*supg_coeff_); + if (numerical_integ_) { + sdv_blfi->SetIntRule(&ir_di); + } + Hv_form_->AddDomainIntegrator(sdv_blfi); + } Hv_form_->Assemble(); Hv_form_->FormSystemMatrix(v2_ess_tdof_, Hv_); - if (rank0_) std::cout << "... op 6 ..." << endl; - Hf_form_ = new ParBilinearForm(ffes_); + Hf_form_ = new ParBilinearForm(sfes_); // dividing all by L^2 // auto *hmf_blfi = new MassIntegrator(*f_diag_coeff_); // auto *hdf_blfi = new DiffusionIntegrator(*unity_diff_coeff_); @@ -914,7 +978,6 @@ void ZetaModel::initializeOperators() { Hf_form_->AddDomainIntegrator(hdf_blfi); Hf_form_->Assemble(); Hf_form_->FormSystemMatrix(fRate_ess_tdof_, Hf_); - if (rank0_) std::cout << "... op 7 ..." << endl; Hz_form_ = new ParBilinearForm(sfes_); // auto *hmz_blfi = new MassIntegrator(*zeta_diag_coeff_); @@ -936,7 +999,6 @@ void ZetaModel::initializeOperators() { Hz_form_->AddDomainIntegrator(hdz_blfi); Hz_form_->Assemble(); Hz_form_->FormSystemMatrix(fRate_ess_tdof_, Hz_); - if (rank0_) std::cout << "... op 8 ..." << endl; // boundary terms for tdr /* @@ -965,7 +1027,6 @@ void ZetaModel::initializeOperators() { } Lk_form_->Assemble(); Lk_form_->FormSystemMatrix(empty, Lk_); - if (rank0_) std::cout << "... op 9 ..." << endl; Lk_bdry_ = new ParLinearForm(sfes_); // auto *lk_bdry_lfi = new BoundaryNormalLFIntegrator(*nu_gradTKE_coeff_, 2, -1); @@ -1045,7 +1106,7 @@ void ZetaModel::initializeOperators() { HfInvPC_ = new HypreSmoother(*Hf_.As()); dynamic_cast(HfInvPC_)->SetType(HypreSmoother::Jacobi, 1); - HfInv_ = new CGSolver(ffes_->GetComm()); + HfInv_ = new CGSolver(sfes_->GetComm()); // HfInv_ = new GMRESSolver(sfes_->GetComm()); HfInv_->iterative_mode = true; HfInv_->SetOperator(*Hf_); @@ -1191,7 +1252,10 @@ void ZetaModel::step() { } void ZetaModel::updateMuT() { + + // Cmu*rho portion eddyVisc_.Set(Cmu_, rho_); + { double twoThirds = 2.0 / 3.0; const double *dv2 = v2_next_.HostRead(); @@ -1200,7 +1264,8 @@ void ZetaModel::updateMuT() { const double *dTTS_strain = tts_strain_.HostRead(); double *muT = eddyVisc_.HostReadWrite(); - for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dv2[i], twoThirds * dk[i]); + //for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dv2[i], twoThirds * dk[i]); + for (int i = 0; i < SdofInt_; i++) muT[i] *= smoothMin(dv2[i], twoThirds * dk[i]); // to prevent kinks // for (int i = 0; i < SdofInt_; i++) { // wgt = std::tanh(tanh_half_ * dv2[i]/(twoThirds*dk[i])); @@ -1208,7 +1273,8 @@ void ZetaModel::updateMuT() { // muT[i] *= ((1.0-wgt)*dv2[i] + wgt*twoThirds*dk[i]); //} - for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dTTS[i], dTTS_strain[i]); + //for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dTTS[i], dTTS_strain[i]); + for (int i = 0; i < SdofInt_; i++) muT[i] *= smoothMin(dTTS[i], dTTS_strain[i]); // to prevent kinks // for (int i = 0; i < SdofInt_; i++) { // wgt = std::tanh(tanh_half_ * dTTS[i]/dTTS_strain[i]); @@ -1216,7 +1282,8 @@ void ZetaModel::updateMuT() { // muT[i] *= ((1.0-wgt)*dTTS[i] + wgt*dTTS_strain[i]); //} - for (int i = 0; i < SdofInt_; i++) muT[i] = std::max(muT[i], mut_min_); + //for (int i = 0; i < SdofInt_; i++) muT[i] = std::max(muT[i], mut_min_); + for (int i = 0; i < SdofInt_; i++) muT[i] = smoothMax(muT[i], mut_min_); } eddyVisc_gf_.SetFromTrueDofs(eddyVisc_); @@ -1316,6 +1383,7 @@ void ZetaModel::updateTTS() { double Ctime; Ctime = 0.6 / (std::sqrt(6.0) * Cmu_); for (int i = 0; i < SdofInt_; i++) { + double T1, T2, T3; T1 = dTKE[i] / std::max(dTDR[i], tdr_min_); T2 = Ctime * dTKE[i] / (dSmag[i] * std::max(dv2[i], v2_min_)); @@ -1335,19 +1403,26 @@ void ZetaModel::updateTTS() { // dTTS[i] = std::max(T1, T3); // to prevent kinks - double wgt = 1.0; - wgt = std::tanh(tanh_half_ * T1 / T3); - dTTS[i] = wgt * T1 + (1.0 - wgt) * T3; + //double wgt = 1.0; + //wgt = std::tanh(tanh_half_ * (T1/T3) * (T1/T3) ); + //dTTS[i] = wgt * T1 + (1.0 - wgt) * T3; + dTTS[i] = smoothMax(T1,T3); // including stag-limit T in nuT only // dTTS[i] = std::min(T1, T2); - dTTS[i] = std::max(dTTS[i], tts_min_); - dTTS[i] = std::min(dTTS[i], tts_max_); + //dTTS[i] = std::max(dTTS[i], tts_min_); + //dTTS[i] = std::min(dTTS[i], tts_max_); + + dTTS[i] = smoothMax(dTTS[i], tts_min_); + dTTS[i] = smoothMin(dTTS[i], tts_max_); + dTTS_kol[i] = T3; dTTS_strain[i] = T2; - dTTS_strain[i] = std::max(dTTS_strain[i], tts_min_); - dTTS_strain[i] = std::min(dTTS_strain[i], tts_max_); + //dTTS_strain[i] = std::max(dTTS_strain[i], tts_min_); + //dTTS_strain[i] = std::min(dTTS_strain[i], tts_max_); + dTTS_strain[i] = smoothMax(dTTS_strain[i], tts_min_); + dTTS_strain[i] = smoothMin(dTTS_strain[i], tts_max_); } tts_gf_.SetFromTrueDofs(tts_); } @@ -1385,22 +1460,25 @@ void ZetaModel::updateTLS() { // to prevent kinks // wgt = std::tanh(tanh_half_ * dTLS[i]/L3); - wgt = std::tanh(tanh_half_ * L1 / L3); - dTLS[i] = Cl_ * (wgt * L1 + (1.0 - wgt) * L3); - - dTLS[i] = std::max(dTLS[i], tls_min_); + //wgt = std::tanh(tanh_half_ * (L1/L3) * (L1/L3)); + //dTLS[i] = Cl_ * (wgt * L1 + (1.0 - wgt) * L3); + dTLS[i] = Cl_ * smoothMax(L1,L3); + //dTLS[i] = std::max(dTLS[i], tls_min_); + dTLS[i] = smoothMax(dTLS[i], tls_min_); // dTLS[i] = std::min(dTLS[i], tls_max_); - wgt = std::tanh(tanh_half_ * dTLS[i] / tls_max_); - dTLS[i] = (1.0 - wgt) * dTLS[i] + wgt * tls_max_; + //wgt = std::tanh(tanh_half_ * dTLS[i] / tls_max_); + //dTLS[i] = (1.0 - wgt) * dTLS[i] + wgt * tls_max_; + dTLS[i] = smoothMin(dTLS[i], tls_max_); } tls_gf_.SetFromTrueDofs(tls_); - // for convience in assembling coeffs + tmpR0_.Set(1.0, tls_); tmpR0_ *= tls_; res_gf_.SetFromTrueDofs(tmpR0_); - tls2_gf_.ProjectGridFunction(res_gf_); + filter_gf_.ProjectGridFunction(res_gf_); + tls2_gf_.ProjectGridFunction(filter_gf_); tls2_gf_.GetTrueDofs(tls2_); } @@ -1450,9 +1528,9 @@ void ZetaModel::updateProd() { tau(1, 1) = 2.0 * Sij[i + 1 * SdofInt_]; tau(2, 2) = 2.0 * Sij[i + 2 * SdofInt_]; tau(0, 1) = 2.0 * Sij[i + 3 * SdofInt_]; - tau(1, 0) = 2.0 * Sij[i + 3 * SdofInt_]; tau(0, 2) = 2.0 * Sij[i + 4 * SdofInt_]; - tau(1, 2) = 2.0 * Sij[i + 5 * SdofInt_]; + tau(1, 2) = 2.0 * Sij[i + 5 * SdofInt_]; + tau(1, 0) = 2.0 * Sij[i + 3 * SdofInt_]; tau(2, 0) = 2.0 * Sij[i + 4 * SdofInt_]; tau(2, 1) = 2.0 * Sij[i + 5 * SdofInt_]; } else { @@ -1510,13 +1588,14 @@ void ZetaModel::updateProd() { // tke example: Pk = std::max(Pk, pk_min_) * (1 + (tke_min_/tke_)^p); // if done to prod_ for all, this should be a consistent way to enforce floors // as all scalars use Pk as a production source on their rhs (except v2 but that uses f which does so) - Pk[i] = std::max(Pk[i], pk_min_) * (1.0 + (2.0 * tke_min_ / std::max(dTKE[i], tke_min_))); + // Pk[i] = std::max(Pk[i], pk_min_) * (1.0 + (2.0 * tke_min_ / std::max(dTKE[i], tke_min_))); } prod_gf_.SetFromTrueDofs(prod_); - resf_gf_.ProjectGridFunction(prod_gf_); - prod_gf_.ProjectGridFunction(resf_gf_); + // filter production + filter_gf_.ProjectGridFunction(prod_gf_); + prod_gf_.ProjectGridFunction(filter_gf_); prod_gf_.GetTrueDofs(prod_); } @@ -2036,9 +2115,9 @@ void ZetaModel::fStep() { data[i] /= std::max(dk[i], tke_min_); } // clip again? - for (int i = 0; i < SdofInt_; i++) { - data[i] = std::min(data[i], zfp_max_); - } + // for (int i = 0; i < SdofInt_; i++) { + // data[i] = std::min(data[i], zfp_max_); + // } } // intercept f res for viz vfres_gf_.SetFromTrueDofs(tmpR0a_); @@ -2098,10 +2177,13 @@ void ZetaModel::fStep() { // if not including L2 in laplacian term tmpR0a_ /= tls2_; - // project to f-space + // filter f-source res_gf_.SetFromTrueDofs(tmpR0a_); - resf_gf_.ProjectGridFunction(res_gf_); - resf_gf_.GetTrueDofs(ftmpR0_); + filter_gf_.ProjectGridFunction(res_gf_); + res_gf_.ProjectGridFunction(filter_gf_); + res_gf_.GetTrueDofs(tmpR0_); + resf_gf_.ProjectGridFunction(res_gf_); + resf_gf_.GetTrueDofs(ftmpR0_); Mf_->AddMult(ftmpR0_, resf_, -1.0); resf_gf_.SetFromTrueDofs(resf_); @@ -2114,7 +2196,7 @@ void ZetaModel::fStep() { HfInv_->SetOperator(*Hf_); if (partial_assembly_) { delete HfInvPC_; - Vector diag_pa(ffes_->GetTrueVSize()); + Vector diag_pa(sfes_->GetTrueVSize()); Hf_form_->AssembleDiagonal(diag_pa); HfInvPC_ = new OperatorJacobiSmoother(diag_pa, fRate_ess_tdof_); HfInv_->SetPreconditioner(*HfInvPC_); @@ -2124,7 +2206,7 @@ void ZetaModel::fStep() { for (auto &fRate_dbc : fRate_dbcs_) { fRate_gf_.ProjectBdrCoefficient(*fRate_dbc.coeff, fRate_dbc.attr); } - ffes_->GetRestrictionMatrix()->MultTranspose(resf_, resf_gf_); + sfes_->GetRestrictionMatrix()->MultTranspose(resf_, resf_gf_); Vector Xt2, Bt2; Hf_form_->FormLinearSystem(fRate_ess_tdof_, fRate_gf_, resf_gf_, Hf_, Xt2, Bt2, 1); @@ -2139,12 +2221,13 @@ void ZetaModel::fStep() { // hard-clip { double *df = fRate_.HostReadWrite(); - for (int i = 0; i < ffes_->GetTrueVSize(); i++) { - df[i] = std::max(df[i], 0.0); + for (int i = 0; i < sfes_->GetTrueVSize(); i++) { if (df[i] != df[i]) std::cout << " f is actually NaN!" << endl; - } + df[i] = std::max(df[i], 0.0); + } } fRate_gf_.SetFromTrueDofs(fRate_); + } /// TODO: pull in tensor gridscale and calc Mnn^T for wall-normal spacing @@ -2292,3 +2375,19 @@ void ZetaModel::AddFRATEDirichletBC(Coefficient *coeff, Array &attr) { } } } + +// Smoothed-min (C-infinity) function which does not over-shoot +double smoothMin(double val1, double val2) { + double C = 4.0; + double val; + val = -1.0/C * std::log(std::exp(-C*val1) + std::exp(-C*val2)); + return val; +} + +// Smoothed-max (C-infinity) function which does not under-shoot +double smoothMax(double val1, double val2) { + double C = 4.0; + double val; + val = 1.0/C * std::log(std::exp(C*val1) + std::exp(C*val2)); + return val; +} diff --git a/src/zetaModel.hpp b/src/zetaModel.hpp index 89bfa2fd..58a371bf 100644 --- a/src/zetaModel.hpp +++ b/src/zetaModel.hpp @@ -123,6 +123,10 @@ class ZetaModel : public TurbModelBase { double zfp_max_; double v2Prod_fLimiter_coeff_; + // streamwise stabilization + bool sw_stab_ = false; /**< Enable/disable supg stabilization. */ + double Reh_factor_, Reh_offset_; /**< supg stabilization parameters */ + // just keep these saved for ease int numWalls_, numInlets_, numOutlets_; @@ -256,6 +260,9 @@ class ZetaModel : public TurbModelBase { ParGridFunction resf_gf_; Vector resf_; + ParGridFunction filter_gf_; + Vector filter_; + ParGridFunction vfres_gf_; // ParGridFunction diag_gf_; @@ -344,6 +351,22 @@ class ZetaModel : public TurbModelBase { GridFunctionCoefficient *tke_field_ = nullptr; GridFunctionCoefficient *v2_field_ = nullptr; + // streamwise stabilization + VectorMagnitudeCoefficient *umag_coeff_ = nullptr; + GridFunctionCoefficient *gscale_coeff_ = nullptr; + ProductCoefficient *gscale2_coeff_ = nullptr; + GridFunctionCoefficient *visc_coeff_ = nullptr; + PowerCoefficient *visc_inv_coeff_ = nullptr; + ProductCoefficient *reh1_coeff_ = nullptr; + ProductCoefficient *reh2_coeff_ = nullptr; + ProductCoefficient *Reh_coeff_ = nullptr; + ExtTransformedCoefficient *csupg_coeff_ = nullptr; + ProductCoefficient *uw1_coeff_ = nullptr; + ProductCoefficient *uw2_coeff_ = nullptr; + ProductCoefficient *upwind_coeff_ = nullptr; + TransformedMatrixVectorCoefficient *swdiff_coeff_ = nullptr; + ScalarMatrixProductCoefficient *supg_coeff_ = nullptr; + /// operators and solvers ParBilinearForm *As_form_ = nullptr; ParBilinearForm *Ms_form_ = nullptr; From da78c2032ef595c61db4754796da3bdd91034440 Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Sun, 21 Jun 2026 12:34:58 -0700 Subject: [PATCH 05/12] style --- src/BCintegrator.cpp | 68 +++--- src/BCintegrator.hpp | 74 +++--- src/BoundaryCondition.cpp | 18 +- src/BoundaryCondition.hpp | 36 +-- src/M2ulPhyS.cpp | 186 +++++++-------- src/M2ulPhyS.hpp | 160 ++++++------- src/M2ulPhyS2Boltzmann.cpp | 24 +- src/algebraicSubgridModels.cpp | 30 +-- src/algebraicSubgridModels.hpp | 46 ++-- src/algebraic_rans.cpp | 24 +- src/algebraic_rans.hpp | 34 +-- src/averaging.cpp | 72 +++--- src/averaging.hpp | 42 ++-- src/calorically_perfect.cpp | 109 ++++----- src/calorically_perfect.hpp | 138 +++++------ src/cases.cpp | 24 +- src/cases.hpp | 28 +-- src/chemistry.cpp | 34 +-- src/chemistry.hpp | 38 +-- src/collision_integrals.cpp | 88 +++---- src/collision_integrals.hpp | 96 ++++---- src/cycle_avg_joule_coupling.cpp | 50 ++-- src/cycle_avg_joule_coupling.hpp | 36 +-- src/dataStructures.hpp | 14 +- src/dgNonlinearForm.cpp | 112 ++++----- src/dgNonlinearForm.hpp | 50 ++-- src/dirichlet_bc_helper.hpp | 6 +- src/domain_integrator.cpp | 10 +- src/domain_integrator.hpp | 10 +- src/em_options.hpp | 2 +- src/equation_of_state.cpp | 196 +++++++-------- src/equation_of_state.hpp | 364 ++++++++++++++-------------- src/externalData_base.hpp | 18 +- src/faceGradientIntegration.cpp | 18 +- src/faceGradientIntegration.hpp | 10 +- src/face_integrator.cpp | 52 ++-- src/face_integrator.hpp | 48 ++-- src/fluxes.cpp | 38 +-- src/fluxes.hpp | 46 ++-- src/forcing_terms.cpp | 188 +++++++-------- src/forcing_terms.hpp | 152 ++++++------ src/gas_transport.cpp | 86 +++---- src/gas_transport.hpp | 82 +++---- src/gaussianInterpExtData.cpp | 58 ++--- src/gaussianInterpExtData.hpp | 38 +-- src/geometricSponge.cpp | 16 +- src/geometricSponge.hpp | 30 +-- src/gpu_constructor.cpp | 56 ++--- src/gpu_constructor.hpp | 54 ++--- src/gradNonLinearForm.cpp | 6 +- src/gradNonLinearForm.hpp | 8 +- src/gradients.cpp | 186 +++++++-------- src/gradients.hpp | 48 ++-- src/gslib_interpolator.cpp | 4 +- src/gslib_interpolator.hpp | 6 +- src/independent_coupling.cpp | 2 +- src/independent_coupling.hpp | 6 +- src/inletBC.cpp | 118 ++++----- src/inletBC.hpp | 76 +++--- src/io.cpp | 56 ++--- src/io.hpp | 36 +-- src/loMach.cpp | 10 +- src/loMach.hpp | 42 ++-- src/loMach_options.cpp | 4 +- src/loMach_options.hpp | 6 +- src/lte_mixture.cpp | 48 ++-- src/lte_mixture.hpp | 86 +++---- src/lte_thermo_chem.cpp | 130 +++++----- src/lte_thermo_chem.hpp | 184 +++++++-------- src/lte_transport_properties.cpp | 22 +- src/lte_transport_properties.hpp | 24 +- src/main.cpp | 2 +- src/masa_handler.cpp | 48 ++-- src/masa_handler.hpp | 40 ++-- src/mesh_base.cpp | 18 +- src/mesh_base.hpp | 34 +-- src/mixing_length_transport.cpp | 36 +-- src/mixing_length_transport.hpp | 54 ++--- src/outletBC.cpp | 136 +++++------ src/outletBC.hpp | 124 +++++----- src/quasimagnetostatic.cpp | 124 +++++----- src/quasimagnetostatic.hpp | 94 ++++---- src/radiation.cpp | 2 +- src/radiation.hpp | 6 +- src/reactingFlow.cpp | 394 +++++++++++++++---------------- src/reactingFlow.hpp | 248 +++++++++---------- src/reaction.cpp | 60 ++--- src/reaction.hpp | 74 +++--- src/rhs_operator.cpp | 118 ++++----- src/rhs_operator.hpp | 126 +++++----- src/riemann_solver.cpp | 22 +- src/riemann_solver.hpp | 20 +- src/solver.hpp | 16 +- src/source_term.cpp | 44 ++-- src/source_term.hpp | 26 +- src/split_flow_base.cpp | 2 +- src/split_flow_base.hpp | 76 +++--- src/sponge_base.cpp | 2 +- src/sponge_base.hpp | 18 +- src/static_rans.cpp | 4 +- src/static_rans.hpp | 18 +- src/table.cpp | 20 +- src/table.hpp | 58 ++--- src/thermo_chem_base.cpp | 4 +- src/thermo_chem_base.hpp | 70 +++--- src/tomboulides.cpp | 150 ++++++------ src/tomboulides.hpp | 284 +++++++++++----------- src/tps.cpp | 70 +++--- src/tps.hpp | 40 ++-- src/tps2Boltzmann.cpp | 54 ++--- src/tps2Boltzmann.hpp | 62 ++--- src/transport_properties.cpp | 70 +++--- src/transport_properties.hpp | 164 ++++++------- src/turb_model_base.cpp | 2 +- src/turb_model_base.hpp | 46 ++-- src/utils.cpp | 296 +++++++++++------------ src/utils.hpp | 126 +++++----- src/wallBC.cpp | 106 ++++----- src/wallBC.hpp | 88 +++---- src/zetaModel.cpp | 315 ++++++++++++------------ src/zetaModel.hpp | 314 ++++++++++++------------ 121 files changed, 4306 insertions(+), 4336 deletions(-) diff --git a/src/BCintegrator.cpp b/src/BCintegrator.cpp index 706439d3..2e6f198e 100644 --- a/src/BCintegrator.cpp +++ b/src/BCintegrator.cpp @@ -37,13 +37,13 @@ #include "outletBC.hpp" #include "wallBC.hpp" -BCintegrator::BCintegrator(bool _mpiRoot, MPI_Groups *_groupsMPI, ParMesh *_mesh, ParFiniteElementSpace *_vfes, - IntegrationRules *_intRules, RiemannSolverTPS *rsolver_, double &_dt, double *_time, - GasMixture *_mixture, GasMixture *d_mixture, Fluxes *_fluxClass, ParGridFunction *_Up, - ParGridFunction *_gradUp, const boundaryFaceIntegrationData &boundary_face_data, - const int _dim, const int _num_equation, double &_max_char_speed, RunConfiguration &_runFile, - Array &local_attr, const int &_maxIntPoints, const int &_maxDofs, - ParGridFunction *distance) +BCintegrator::BCintegrator(bool _mpiRoot, MPI_Groups* _groupsMPI, ParMesh* _mesh, ParFiniteElementSpace* _vfes, + IntegrationRules* _intRules, RiemannSolverTPS* rsolver_, double& _dt, double* _time, + GasMixture* _mixture, GasMixture* d_mixture, Fluxes* _fluxClass, ParGridFunction* _Up, + ParGridFunction* _gradUp, const boundaryFaceIntegrationData& boundary_face_data, + const int _dim, const int _num_equation, double& _max_char_speed, RunConfiguration& _runFile, + Array& local_attr, const int& _maxIntPoints, const int& _maxDofs, + ParGridFunction* distance) : groupsMPI(_groupsMPI), config(_runFile), rsolver(rsolver_), @@ -129,8 +129,8 @@ BCintegrator::BCintegrator(bool _mpiRoot, MPI_Groups *_groupsMPI, ParMesh *_mesh // Inlets if (NumBCelems > 0 && inletBCmap.size() > 0) { - Mesh *mesh_bc = vfes->GetMesh(); - FaceElementTransformations *tr; + Mesh* mesh_bc = vfes->GetMesh(); + FaceElementTransformations* tr; for (int i = 0; i < local_attr.Size(); i++) { int attr = local_attr[i]; @@ -145,15 +145,15 @@ BCintegrator::BCintegrator(bool _mpiRoot, MPI_Groups *_groupsMPI, ParMesh *_mesh } } - std::unordered_map::const_iterator ibc = inletBCmap.find(attr); + std::unordered_map::const_iterator ibc = inletBCmap.find(attr); if (ibc != inletBCmap.end()) ibc->second->setElementList(list); } } // Outlets if (NumBCelems > 0 && outletBCmap.size() > 0) { - Mesh *mesh_bc = vfes->GetMesh(); - FaceElementTransformations *tr; + Mesh* mesh_bc = vfes->GetMesh(); + FaceElementTransformations* tr; for (int i = 0; i < local_attr.Size(); i++) { int attr = local_attr[i]; @@ -168,15 +168,15 @@ BCintegrator::BCintegrator(bool _mpiRoot, MPI_Groups *_groupsMPI, ParMesh *_mesh } } - std::unordered_map::const_iterator obc = outletBCmap.find(attr); + std::unordered_map::const_iterator obc = outletBCmap.find(attr); if (obc != outletBCmap.end()) obc->second->setElementList(list); } } // Walls if (NumBCelems > 0 && wallBCmap.size() > 0) { - Mesh *mesh_bc = vfes->GetMesh(); - FaceElementTransformations *tr; + Mesh* mesh_bc = vfes->GetMesh(); + FaceElementTransformations* tr; for (int i = 0; i < local_attr.Size(); i++) { int attr = local_attr[i]; @@ -191,7 +191,7 @@ BCintegrator::BCintegrator(bool _mpiRoot, MPI_Groups *_groupsMPI, ParMesh *_mesh } } - std::unordered_map::const_iterator wbc = wallBCmap.find(attr); + std::unordered_map::const_iterator wbc = wallBCmap.find(attr); if (wbc != wallBCmap.end()) wbc->second->setElementList(list); } } @@ -225,11 +225,11 @@ void BCintegrator::initBCs() { } } -void BCintegrator::computeBdrFlux(const int attr, Vector &normal, Vector &stateIn, DenseMatrix &gradState, - Vector transip, double delta, double time, double distance, Vector &bdrFlux) { - std::unordered_map::const_iterator ibc = inletBCmap.find(attr); - std::unordered_map::const_iterator obc = outletBCmap.find(attr); - std::unordered_map::const_iterator wbc = wallBCmap.find(attr); +void BCintegrator::computeBdrFlux(const int attr, Vector& normal, Vector& stateIn, DenseMatrix& gradState, + Vector transip, double delta, double time, double distance, Vector& bdrFlux) { + std::unordered_map::const_iterator ibc = inletBCmap.find(attr); + std::unordered_map::const_iterator obc = outletBCmap.find(attr); + std::unordered_map::const_iterator wbc = wallBCmap.find(attr); if (ibc != inletBCmap.end()) ibc->second->computeBdrFlux(normal, stateIn, gradState, transip, delta, time, distance, bdrFlux); @@ -241,7 +241,7 @@ void BCintegrator::computeBdrFlux(const int attr, Vector &normal, Vector &stateI // BCmap[attr]->computeBdrFlux(normal, stateIn, gradState, radius, bdrFlux); } -void BCintegrator::updateBCMean(ParGridFunction *Up) { +void BCintegrator::updateBCMean(ParGridFunction* Up) { for (auto bc = inletBCmap.begin(); bc != inletBCmap.end(); bc++) { bc->second->updateMean(intRules, Up); } @@ -255,7 +255,7 @@ void BCintegrator::updateBCMean(ParGridFunction *Up) { } } -void BCintegrator::integrateBCs(Vector &y, const Vector &x, const elementIndexingData &elem_index_data) { +void BCintegrator::integrateBCs(Vector& y, const Vector& x, const elementIndexingData& elem_index_data) { for (auto bc = inletBCmap.begin(); bc != inletBCmap.end(); bc++) { bc->second->integrationBC(y, // output x, elem_index_data, Up, gradUp, boundary_face_data_, maxIntPoints, maxDofs); @@ -272,12 +272,12 @@ void BCintegrator::integrateBCs(Vector &y, const Vector &x, const elementIndexin } } -void BCintegrator::retrieveGradientsData_gpu(ParGridFunction *gradUp, DenseTensor &elGradUp, Array &vdofs, - const int &num_equation, const int &dim, const int &totalDofs, - const int &elDofs) { +void BCintegrator::retrieveGradientsData_gpu(ParGridFunction* gradUp, DenseTensor& elGradUp, Array& vdofs, + const int& num_equation, const int& dim, const int& totalDofs, + const int& elDofs) { #ifdef _GPU_ - const double *d_GradUp = gradUp->Read(); - double *d_elGradUp = elGradUp.ReadWrite(); + const double* d_GradUp = gradUp->Read(); + double* d_elGradUp = elGradUp.ReadWrite(); auto d_vdofs = vdofs.Read(); MFEM_FORALL(i, elDofs, { @@ -292,15 +292,15 @@ void BCintegrator::retrieveGradientsData_gpu(ParGridFunction *gradUp, DenseTenso #endif } -void BCintegrator::AssembleFaceVector(const FiniteElement &el1, const FiniteElement &el2, - FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect) { +void BCintegrator::AssembleFaceVector(const FiniteElement& el1, const FiniteElement& el2, + FaceElementTransformations& Tr, const Vector& elfun, Vector& elvect) { Vector shape1; Vector funval1(num_equation); Vector nor(dim); Vector fluxN(num_equation); #ifndef _GPU_ - const double *dataGradUp = gradUp->HostRead(); + const double* dataGradUp = gradUp->HostRead(); #endif const int dof1 = el1.GetDof(); @@ -323,7 +323,7 @@ void BCintegrator::AssembleFaceVector(const FiniteElement &el1, const FiniteElem // element size double delta; - Mesh *mesh = vfes->GetMesh(); + Mesh* mesh = vfes->GetMesh(); delta = mesh->GetElementSize(Tr.Elem1No, 1) / el1.GetOrder(); #ifdef _GPU_ @@ -361,12 +361,12 @@ void BCintegrator::AssembleFaceVector(const FiniteElement &el1, const FiniteElem intorder++; } - const IntegrationRule *ir = &intRules->Get(Tr.GetGeometryType(), intorder); + const IntegrationRule* ir = &intRules->Get(Tr.GetGeometryType(), intorder); const int numActiveSpecies = mixture->GetNumActiveSpecies(); const int nvel = mixture->GetNumVels(); for (int i = 0; i < ir->GetNPoints(); i++) { - const IntegrationPoint &ip = ir->IntPoint(i); + const IntegrationPoint& ip = ir->IntPoint(i); Tr.SetAllIntPoints(&ip); // set face and element int. points diff --git a/src/BCintegrator.hpp b/src/BCintegrator.hpp index b28a3ea3..6c5d0ce0 100644 --- a/src/BCintegrator.hpp +++ b/src/BCintegrator.hpp @@ -51,74 +51,74 @@ class BCintegrator : public NonlinearFormIntegrator { friend class M2ulPhyS; protected: - MPI_Groups *groupsMPI; + MPI_Groups* groupsMPI; - RunConfiguration &config; + RunConfiguration& config; - RiemannSolverTPS *rsolver; - GasMixture *mixture; - Fluxes *fluxClass; + RiemannSolverTPS* rsolver; + GasMixture* mixture; + Fluxes* fluxClass; - double &max_char_speed; - IntegrationRules *intRules; + double& max_char_speed; + IntegrationRules* intRules; - ParMesh *mesh; + ParMesh* mesh; // pointer to finite element space - ParFiniteElementSpace *vfes; + ParFiniteElementSpace* vfes; // pointer to primitive varibales - ParGridFunction *Up; + ParGridFunction* Up; - ParGridFunction *gradUp; + ParGridFunction* gradUp; - ParGridFunction *distance_; + ParGridFunction* distance_; - const boundaryFaceIntegrationData &boundary_face_data_; + const boundaryFaceIntegrationData& boundary_face_data_; const int dim; const int num_equation; - const int &maxIntPoints; - const int &maxDofs; + const int& maxIntPoints; + const int& maxDofs; - std::unordered_map inletBCmap; - std::unordered_map outletBCmap; - std::unordered_map wallBCmap; + std::unordered_map inletBCmap; + std::unordered_map outletBCmap; + std::unordered_map wallBCmap; bool mpiRoot; double time; - double *pTime; + double* pTime; // void calcMeanState(); - void computeBdrFlux(const int attr, Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, - double delta, double time, double distance, Vector &bdrFlux); + void computeBdrFlux(const int attr, Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, + double delta, double time, double distance, Vector& bdrFlux); public: - BCintegrator(bool _mpiRoot, MPI_Groups *_groupsMPI, ParMesh *_mesh, ParFiniteElementSpace *_vfes, - IntegrationRules *_intRules, RiemannSolverTPS *rsolver_, double &_dt, double *_time, GasMixture *mixture, - GasMixture *d_mixture, Fluxes *_fluxClass, ParGridFunction *_Up, ParGridFunction *_gradUp, - const boundaryFaceIntegrationData &boundary_face_data, const int _dim, const int _num_equation, - double &_max_char_speed, RunConfiguration &_runFile, Array &local_bdr_attr, - const int &_maxIntPoints, const int &_maxDofs, ParGridFunction *distance_); + BCintegrator(bool _mpiRoot, MPI_Groups* _groupsMPI, ParMesh* _mesh, ParFiniteElementSpace* _vfes, + IntegrationRules* _intRules, RiemannSolverTPS* rsolver_, double& _dt, double* _time, GasMixture* mixture, + GasMixture* d_mixture, Fluxes* _fluxClass, ParGridFunction* _Up, ParGridFunction* _gradUp, + const boundaryFaceIntegrationData& boundary_face_data, const int _dim, const int _num_equation, + double& _max_char_speed, RunConfiguration& _runFile, Array& local_bdr_attr, + const int& _maxIntPoints, const int& _maxDofs, ParGridFunction* distance_); ~BCintegrator(); - virtual void AssembleFaceVector(const FiniteElement &el1, const FiniteElement &el2, FaceElementTransformations &Tr, - const Vector &elfun, Vector &elvect); + virtual void AssembleFaceVector(const FiniteElement& el1, const FiniteElement& el2, FaceElementTransformations& Tr, + const Vector& elfun, Vector& elvect); void initBCs(); - void updateBCMean(ParGridFunction *Up); - void integrateBCs(Vector &y, const Vector &x, const elementIndexingData &elem_index_data); + void updateBCMean(ParGridFunction* Up); + void integrateBCs(Vector& y, const Vector& x, const elementIndexingData& elem_index_data); // GPU functions - static void retrieveGradientsData_gpu(ParGridFunction *gradUp, DenseTensor &elGradUp, Array &vdofs, - const int &num_equation, const int &dim, const int &totalDofs, - const int &elDofs); + static void retrieveGradientsData_gpu(ParGridFunction* gradUp, DenseTensor& elGradUp, Array& vdofs, + const int& num_equation, const int& dim, const int& totalDofs, + const int& elDofs); boundaryCategory getAttributeCategory(int attr) const { - std::unordered_map::const_iterator ibc = inletBCmap.find(attr); - std::unordered_map::const_iterator obc = outletBCmap.find(attr); - std::unordered_map::const_iterator wbc = wallBCmap.find(attr); + std::unordered_map::const_iterator ibc = inletBCmap.find(attr); + std::unordered_map::const_iterator obc = outletBCmap.find(attr); + std::unordered_map::const_iterator wbc = wallBCmap.find(attr); if (ibc != inletBCmap.end()) { return INLET; } diff --git a/src/BoundaryCondition.cpp b/src/BoundaryCondition.cpp index 3e7eee52..d33deac0 100644 --- a/src/BoundaryCondition.cpp +++ b/src/BoundaryCondition.cpp @@ -31,8 +31,8 @@ // -----------------------------------------------------------------------------------el- #include "BoundaryCondition.hpp" -BoundaryCondition::BoundaryCondition(RiemannSolverTPS *_rsolver, GasMixture *_mixture, Equations _eqSystem, - ParFiniteElementSpace *_vfes, IntegrationRules *_intRules, double &_dt, +BoundaryCondition::BoundaryCondition(RiemannSolverTPS* _rsolver, GasMixture* _mixture, Equations _eqSystem, + ParFiniteElementSpace* _vfes, IntegrationRules* _intRules, double& _dt, const int _dim, const int _num_equation, const int _patchNumber, const double _refLength, bool axisym) : rsolver(_rsolver), @@ -52,7 +52,7 @@ BoundaryCondition::BoundaryCondition(RiemannSolverTPS *_rsolver, GasMixture *_mi BoundaryCondition::~BoundaryCondition() {} -void BoundaryCondition::computeBdrPrimitiveStateForGradient(const Vector &stateIn, Vector &stateBC) const { +void BoundaryCondition::computeBdrPrimitiveStateForGradient(const Vector& stateIn, Vector& stateBC) const { stateBC = stateIn; } @@ -63,8 +63,8 @@ double BoundaryCondition::aggregateArea(int bndry_patchnum, MPI_Comm bc_comm) { for (int bel = 0; bel < vfes->GetNBE(); bel++) { int attr = vfes->GetBdrAttribute(bel); if (attr == bndry_patchnum) { - FaceElementTransformations *Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); - const IntegrationRule &ir = IntRules.Get(Tr->GetGeometryType(), Tr->OrderJ()); + FaceElementTransformations* Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); + const IntegrationRule& ir = IntRules.Get(Tr->GetGeometryType(), Tr->OrderJ()); for (int p = 0; p < ir.GetNPoints(); p++) { const IntegrationPoint ip = ir.IntPoint(p); @@ -91,15 +91,15 @@ int BoundaryCondition::aggregateBndryFaces(int bndry_patchnum, MPI_Comm bc_comm) return (nfacesTotal); } -void BoundaryCondition::setElementList(Array &_listElems) { +void BoundaryCondition::setElementList(Array& _listElems) { listElems.SetSize(_listElems.Size()); for (int i = 0; i < listElems.Size(); i++) listElems[i] = _listElems[i]; listElems.ReadWrite(); } -void BoundaryCondition::copyValues(const Vector &orig, Vector &target, const double &mult) { - const double *dOrig = orig.Read(); - double *dTarget = target.Write(); +void BoundaryCondition::copyValues(const Vector& orig, Vector& target, const double& mult) { + const double* dOrig = orig.Read(); + double* dTarget = target.Write(); MFEM_FORALL(i, target.Size(), { dTarget[i] = dOrig[i] * mult; }); } diff --git a/src/BoundaryCondition.hpp b/src/BoundaryCondition.hpp index 47049a81..0b4d4c89 100644 --- a/src/BoundaryCondition.hpp +++ b/src/BoundaryCondition.hpp @@ -46,12 +46,12 @@ using namespace mfem; class BoundaryCondition { protected: - RiemannSolverTPS *rsolver; - GasMixture *mixture; + RiemannSolverTPS* rsolver; + GasMixture* mixture; Equations eqSystem; - ParFiniteElementSpace *vfes; - IntegrationRules *intRules; - double &dt; + ParFiniteElementSpace* vfes; + IntegrationRules* intRules; + double& dt; const int dim_; const int nvel_; const int num_equation_; @@ -68,13 +68,13 @@ class BoundaryCondition { Vector face_flux_; public: - BoundaryCondition(RiemannSolverTPS *_rsolver, GasMixture *_mixture, Equations _eqSystem, ParFiniteElementSpace *_vfes, - IntegrationRules *_intRules, double &dt, const int _dim, const int _num_equation, + BoundaryCondition(RiemannSolverTPS* _rsolver, GasMixture* _mixture, Equations _eqSystem, ParFiniteElementSpace* _vfes, + IntegrationRules* _intRules, double& dt, const int _dim, const int _num_equation, const int _patchNumber, const double _refLength, bool axisym); virtual ~BoundaryCondition(); - virtual void computeBdrFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - double time, double distance, Vector &bdrFlux) = 0; + virtual void computeBdrFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + double time, double distance, Vector& bdrFlux) = 0; /** \brief Set the boundary state used in the gradient evaluation * @@ -84,13 +84,13 @@ class BoundaryCondition { * term is zero. If that is not what you want, you must override * this method in a derived class. */ - virtual void computeBdrPrimitiveStateForGradient(const Vector &stateIn, Vector &stateBC) const; + virtual void computeBdrPrimitiveStateForGradient(const Vector& stateIn, Vector& stateBC) const; // holding function for any miscellaneous items needed to initialize BCs // prior to use (and require MPI) virtual void initBCs() = 0; - virtual void updateMean(IntegrationRules *intRules, ParGridFunction *Up) = 0; + virtual void updateMean(IntegrationRules* intRules, ParGridFunction* Up) = 0; // aggregate boundary area double aggregateArea(int bndry_attr, MPI_Comm bc_comm); @@ -98,15 +98,15 @@ class BoundaryCondition { int aggregateBndryFaces(int bndry_attr, MPI_Comm bc_comm); // integration of BC on GPU - void setElementList(Array &listElems); + void setElementList(Array& listElems); - virtual void integrationBC(Vector &y, // output - const Vector &x, // conservative vars (input) - const elementIndexingData &elem_index_data, ParGridFunction *Up, ParGridFunction *gradUp, - const boundaryFaceIntegrationData &boundary_face_data, const int &maxIntPoints, - const int &maxDofs) = 0; + virtual void integrationBC(Vector& y, // output + const Vector& x, // conservative vars (input) + const elementIndexingData& elem_index_data, ParGridFunction* Up, ParGridFunction* gradUp, + const boundaryFaceIntegrationData& boundary_face_data, const int& maxIntPoints, + const int& maxDofs) = 0; - static void copyValues(const Vector &orig, Vector &target, const double &mult); + static void copyValues(const Vector& orig, Vector& target, const double& mult); }; #endif // BOUNDARYCONDITION_HPP_ diff --git a/src/M2ulPhyS.cpp b/src/M2ulPhyS.cpp index 107f5091..e5468c59 100644 --- a/src/M2ulPhyS.cpp +++ b/src/M2ulPhyS.cpp @@ -39,7 +39,7 @@ #include "utils.hpp" #include "wallBC.hpp" -M2ulPhyS::M2ulPhyS(TPS::Tps *tps) +M2ulPhyS::M2ulPhyS(TPS::Tps* tps) : groupsMPI(new MPI_Groups(tps->getTPSCommWorld())), nprocs_(groupsMPI->getTPSWorldSize()), rank_(groupsMPI->getTPSWorldRank()), @@ -48,7 +48,7 @@ M2ulPhyS::M2ulPhyS(TPS::Tps *tps) parseSolverOptions2(); } -M2ulPhyS::M2ulPhyS(string &inputFileName, TPS::Tps *tps) +M2ulPhyS::M2ulPhyS(string& inputFileName, TPS::Tps* tps) : groupsMPI(new MPI_Groups(tps->getTPSCommWorld())), nprocs_(groupsMPI->getTPSWorldSize()), rank_(groupsMPI->getTPSWorldRank()), @@ -96,10 +96,10 @@ void M2ulPhyS::initMixtureAndTransportModels() { mixture = new DryAir(config, dim, nvel); #if defined(_CUDA_) || defined(_HIP_) - tpsGpuMalloc((void **)(&d_mixture), sizeof(DryAir)); + tpsGpuMalloc((void**)(&d_mixture), sizeof(DryAir)); gpu::instantiateDeviceDryAir<<<1, 1>>>(config.dryAirInput, dim, nvel, d_mixture); - tpsGpuMalloc((void **)&transportPtr, sizeof(DryAirTransport)); + tpsGpuMalloc((void**)&transportPtr, sizeof(DryAirTransport)); gpu::instantiateDeviceDryAirTransport<<<1, 1>>>(d_mixture, config.GetViscMult(), config.GetBulkViscMult(), config.sutherland_.C1, config.sutherland_.S0, config.sutherland_.Pr, transportPtr); @@ -112,7 +112,7 @@ void M2ulPhyS::initMixtureAndTransportModels() { case GasModel::PERFECT_MIXTURE: mixture = new PerfectMixture(config, dim, nvel); #if defined(_CUDA_) || defined(_HIP_) - tpsGpuMalloc((void **)(&d_mixture), sizeof(PerfectMixture)); + tpsGpuMalloc((void**)(&d_mixture), sizeof(PerfectMixture)); gpu::instantiateDevicePerfectMixture<<<1, 1>>>(config.perfectMixtureInput, dim, nvel, d_mixture); #endif break; @@ -124,7 +124,7 @@ void M2ulPhyS::initMixtureAndTransportModels() { switch (config.GetTranportModel()) { case ARGON_MINIMAL: #if defined(_CUDA_) || defined(_HIP_) - tpsGpuMalloc((void **)&transportPtr, sizeof(GasMinimalTransport)); + tpsGpuMalloc((void**)&transportPtr, sizeof(GasMinimalTransport)); gpu::instantiateDeviceGasMinimalTransport<<<1, 1>>>(d_mixture, config.gasTransportInput, transportPtr); #else transportPtr = new GasMinimalTransport(mixture, config); @@ -132,7 +132,7 @@ void M2ulPhyS::initMixtureAndTransportModels() { break; case ARGON_MIXTURE: #if defined(_CUDA_) || defined(_HIP_) - tpsGpuMalloc((void **)&transportPtr, sizeof(GasMixtureTransport)); + tpsGpuMalloc((void**)&transportPtr, sizeof(GasMixtureTransport)); gpu::instantiateDeviceGasMixtureTransport<<<1, 1>>>(d_mixture, config.gasTransportInput, transportPtr); #else transportPtr = new GasMixtureTransport(mixture, config); @@ -140,7 +140,7 @@ void M2ulPhyS::initMixtureAndTransportModels() { break; case CONSTANT: #if defined(_CUDA_) || defined(_HIP_) - tpsGpuMalloc((void **)&transportPtr, sizeof(ConstantTransport)); + tpsGpuMalloc((void**)&transportPtr, sizeof(ConstantTransport)); gpu::instantiateDeviceConstantTransport<<<1, 1>>>(d_mixture, config.constantTransport, transportPtr); #else transportPtr = new ConstantTransport(mixture, config); @@ -153,7 +153,7 @@ void M2ulPhyS::initMixtureAndTransportModels() { switch (config.GetChemistryModel()) { default: #if defined(_CUDA_) || defined(_HIP_) - tpsGpuMalloc((void **)&chemistry_, sizeof(Chemistry)); + tpsGpuMalloc((void**)&chemistry_, sizeof(Chemistry)); gpu::instantiateDeviceChemistry<<<1, 1>>>(d_mixture, config.chemistryInput, chemistry_); #else chemistry_ = new Chemistry(mixture, config.chemistryInput); @@ -216,7 +216,7 @@ void M2ulPhyS::initMixtureAndTransportModels() { T_table_input.fdata = thermo_tables[0].xdata; // LteMixture object valid on device - tpsGpuMalloc((void **)(&d_mixture), sizeof(LteMixture)); + tpsGpuMalloc((void**)(&d_mixture), sizeof(LteMixture)); gpu::instantiateDeviceLteMixture<<<1, 1>>>(config.lteMixtureInput.f, dim, nvel, config.const_plasma_conductivity_, thermo_tables[0], thermo_tables[1], thermo_tables[2], T_table_input, d_mixture); @@ -247,7 +247,7 @@ void M2ulPhyS::initMixtureAndTransportModels() { trans_tables[icol].fdata = trans_data.Read() + (icol + 1) * nrow; } - tpsGpuMalloc((void **)&transportPtr, sizeof(LteTransport)); + tpsGpuMalloc((void**)&transportPtr, sizeof(LteTransport)); gpu::instantiateDeviceLteTransport<<<1, 1>>>(d_mixture, trans_tables[0], trans_tables[1], trans_tables[2], transportPtr); #else @@ -267,13 +267,13 @@ void M2ulPhyS::initMixtureAndTransportModels() { // dynamic_cast on a device-side pointer doesn't work, so instead // pass the TransportProperties pointer and cast it within // instantiateDeviceMixingLengthTransport - TransportProperties *temporary_transport = transportPtr; - tpsGpuMalloc((void **)&transportPtr, sizeof(MixingLengthTransport)); + TransportProperties* temporary_transport = transportPtr; + tpsGpuMalloc((void**)&transportPtr, sizeof(MixingLengthTransport)); gpu::instantiateDeviceMixingLengthTransport<<<1, 1>>>(d_mixture, config.mix_length_trans_input_, temporary_transport, transportPtr); #else // Build mixing length transport using whatever molecular transport we've already instantiated - MolecularTransport *temporary_transport = dynamic_cast(transportPtr); + MolecularTransport* temporary_transport = dynamic_cast(transportPtr); transportPtr = new MixingLengthTransport(mixture, config, temporary_transport); #endif } @@ -370,9 +370,9 @@ void M2ulPhyS::initVariables() { // If requested, evaluate the distance function (i.e., the distance to the nearest no-slip wall) distance_ = NULL; - GridFunction *serial_distance = NULL; - FiniteElementSpace *serial_fes = NULL; - DG_FECollection *tmp_fec = NULL; + GridFunction* serial_distance = NULL; + FiniteElementSpace* serial_fes = NULL; + DG_FECollection* tmp_fec = NULL; if (config.compute_distance) { order = config.GetSolutionOrder(); dim = serial_mesh->Dimension(); @@ -401,7 +401,7 @@ void M2ulPhyS::initVariables() { serial_mesh->SetCurvature(1); } - FiniteElementSpace *tmp_dfes = new FiniteElementSpace(serial_mesh, tmp_fec, dim, Ordering::byNODES); + FiniteElementSpace* tmp_dfes = new FiniteElementSpace(serial_mesh, tmp_fec, dim, Ordering::byNODES); GridFunction coordinates(tmp_dfes); serial_mesh->GetNodes(coordinates); @@ -511,7 +511,7 @@ void M2ulPhyS::initVariables() { switch (config.radiationInput.model) { case NET_EMISSION: #if defined(_CUDA_) || defined(_HIP_) - tpsGpuMalloc((void **)(&radiation_), sizeof(NetEmission)); + tpsGpuMalloc((void**)(&radiation_), sizeof(NetEmission)); gpu::instantiateDeviceNetEmission<<<1, 1>>>(config.radiationInput, radiation_); #else radiation_ = new NetEmission(config.radiationInput); @@ -596,12 +596,12 @@ void M2ulPhyS::initVariables() { vsd.width = config.GetLinearVaryingData().width; } - tpsGpuMalloc((void **)&d_fluxClass, sizeof(Fluxes)); + tpsGpuMalloc((void**)&d_fluxClass, sizeof(Fluxes)); gpu::instantiateDeviceFluxes<<<1, 1>>>(d_mixture, eqSystem, transportPtr, num_equation, dim, config.isAxisymmetric(), config.GetSgsModelType(), config.GetSgsFloor(), config.GetSgsConstant(), vsd, d_fluxClass); - tpsGpuMalloc((void **)&rsolver, sizeof(RiemannSolverTPS)); + tpsGpuMalloc((void**)&rsolver, sizeof(RiemannSolverTPS)); gpu::instantiateDeviceRiemann<<<1, 1>>>(num_equation, d_mixture, eqSystem, d_fluxClass, config.RoeRiemannSolverTPS(), config.isAxisymmetric(), rsolver); @@ -686,7 +686,7 @@ void M2ulPhyS::initVariables() { Array local_attr; getAttributesInPartition(local_attr); - double *pTime; + double* pTime; pTime = &time; bcIntegrator = NULL; @@ -817,7 +817,7 @@ void M2ulPhyS::initIndirectionArrays() { //----------------------------------------------------------------- // Element data //----------------------------------------------------------------- - elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; elem_data.dof_offset.SetSize(vfes->GetNE()); elem_data.dof_offset = -1; // invalid @@ -873,7 +873,7 @@ void M2ulPhyS::initIndirectionArrays() { //----------------------------------------------------------------- // Interior faces //----------------------------------------------------------------- - interiorFaceIntegrationData &face_data = gpu_precomputed_data_.interior_face_data; + interiorFaceIntegrationData& face_data = gpu_precomputed_data_.interior_face_data; face_data.element_to_faces.SetSize(7 * vfes->GetNE()); face_data.element_to_faces = 0; @@ -935,7 +935,7 @@ void M2ulPhyS::initIndirectionArrays() { Vector xyz(dim); for (int face = 0; face < mesh->GetNumFaces(); face++) { - FaceElementTransformations *tr; + FaceElementTransformations* tr; tr = mesh->GetInteriorFaceTransformations(face); if (tr != NULL) { Array vdofs; @@ -957,8 +957,8 @@ void M2ulPhyS::initIndirectionArrays() { h_element_to_faces[7 * tr->Elem2No] = nf; } - const FiniteElement *fe1 = fes->GetFE(tr->Elem1No); - const FiniteElement *fe2 = fes->GetFE(tr->Elem2No); + const FiniteElement* fe1 = fes->GetFE(tr->Elem1No); + const FiniteElement* fe2 = fes->GetFE(tr->Elem2No); const int dof1 = fe1->GetDof(); const int dof2 = fe2->GetDof(); @@ -972,7 +972,7 @@ void M2ulPhyS::initIndirectionArrays() { if (fe1->Space() == FunctionSpace::Pk) { intorder++; } - const IntegrationRule *ir = &intRules->Get(tr->GetGeometryType(), intorder); + const IntegrationRule* ir = &intRules->Get(tr->GetGeometryType(), intorder); h_face_el1[face] = tr->Elem1No; h_face_el2[face] = tr->Elem2No; @@ -989,7 +989,7 @@ void M2ulPhyS::initIndirectionArrays() { // below is from the variant of Mesh::GetElementSize that takes an // ElementTransformation as input, rather than an element index. // We should simply call that function, but it is not public. - ElementTransformation *T = tr->Elem2; + ElementTransformation* T = tr->Elem2; DenseMatrix J(dim, dim); Geometry::Type geom = T->GetGeometryType(); @@ -1010,7 +1010,7 @@ void M2ulPhyS::initIndirectionArrays() { Vector dist1, dist2; if (distance_ != NULL) { - const ParFiniteElementSpace *dist_fes = distance_->ParFESpace(); + const ParFiniteElementSpace* dist_fes = distance_->ParFESpace(); Array dist_dofs1; // dist_fes->GetElementVDofs(tr->Elem1->ElementNo, dist_dofs1); @@ -1032,7 +1032,7 @@ void M2ulPhyS::initIndirectionArrays() { } for (int k = 0; k < ir->GetNPoints(); k++) { - const IntegrationPoint &ip = ir->IntPoint(k); + const IntegrationPoint& ip = ir->IntPoint(k); tr->SetAllIntPoints(&ip); // shape functions fe1->CalcShape(tr->GetElement1IntPoint(), shape1i); @@ -1076,7 +1076,7 @@ void M2ulPhyS::initIndirectionArrays() { //----------------------------------------------------------------- // Boundary faces //----------------------------------------------------------------- - boundaryFaceIntegrationData &bdry_face_data = gpu_precomputed_data_.boundary_face_data; + boundaryFaceIntegrationData& bdry_face_data = gpu_precomputed_data_.boundary_face_data; // This is supposed to be number of boundary faces, and for // non-periodic cases it is. But, for periodic meshes, it includes @@ -1137,8 +1137,8 @@ void M2ulPhyS::initIndirectionArrays() { bdry_face_data.dist = 0.; auto h_bdry_dist = bdry_face_data.dist.HostWrite(); - const FiniteElement *fe; - FaceElementTransformations *tr; + const FiniteElement* fe; + FaceElementTransformations* tr; // Mesh *mesh = fes->GetMesh(); std::vector uniqueElems; @@ -1167,7 +1167,7 @@ void M2ulPhyS::initIndirectionArrays() { if (fe->Space() == FunctionSpace::Pk) { intorder++; } - const IntegrationRule *ir = &intRules->Get(tr->GetGeometryType(), intorder); + const IntegrationRule* ir = &intRules->Get(tr->GetGeometryType(), intorder); h_face_el[f] = tr->Elem1No; h_face_num_quad[f] = ir->GetNPoints(); @@ -1181,7 +1181,7 @@ void M2ulPhyS::initIndirectionArrays() { Vector dist; if (distance_ != NULL) { - const ParFiniteElementSpace *dist_fes = distance_->ParFESpace(); + const ParFiniteElementSpace* dist_fes = distance_->ParFESpace(); Array dist_dofs1; // dist_fes->GetElementVDofs(tr->Elem1->ElementNo, dist_dofs1); @@ -1191,7 +1191,7 @@ void M2ulPhyS::initIndirectionArrays() { } for (int q = 0; q < ir->GetNPoints(); q++) { - const IntegrationPoint &ip = ir->IntPoint(q); + const IntegrationPoint& ip = ir->IntPoint(q); tr->SetAllIntPoints(&ip); Vector nor; nor.UseDevice(false); @@ -1262,7 +1262,7 @@ void M2ulPhyS::initIndirectionArrays() { // Shared faces (i.e., interior faces at boundary of decomposition, // such that element1 and element2 live on different mpi ranks) //----------------------------------------------------------------- - sharedFaceIntegrationData &shared_face_data = gpu_precomputed_data_.shared_face_data; + sharedFaceIntegrationData& shared_face_data = gpu_precomputed_data_.shared_face_data; mesh->ExchangeFaceNbrNodes(); mesh->ExchangeFaceNbrData(); @@ -1342,13 +1342,13 @@ void M2ulPhyS::initIndirectionArrays() { unicElems.clear(); Array vdofs2, vdofsGrad; - FaceElementTransformations *tr; + FaceElementTransformations* tr; for (int i = 0; i < Nshared; i++) { tr = mesh->GetSharedFaceTransformations(i, true); int Elem2NbrNo = tr->Elem2No - mesh->GetNE(); - const FiniteElement *fe1 = vfes->GetFE(tr->Elem1No); - const FiniteElement *fe2 = vfes->GetFaceNbrFE(Elem2NbrNo); + const FiniteElement* fe1 = vfes->GetFE(tr->Elem1No); + const FiniteElement* fe2 = vfes->GetFaceNbrFE(Elem2NbrNo); const int dof1 = fe1->GetDof(); const int dof2 = fe2->GetDof(); @@ -1361,7 +1361,7 @@ void M2ulPhyS::initIndirectionArrays() { // takes an ElementTransformation as input, rather than an // element index. We should simply call that function, but it // is not public. - ElementTransformation *T = tr->Elem2; + ElementTransformation* T = tr->Elem2; DenseMatrix J(dim, dim); Geometry::Type geom = T->GetGeometryType(); @@ -1395,7 +1395,7 @@ void M2ulPhyS::initIndirectionArrays() { intorder++; } // IntegrationRules IntRules2(0, Quadrature1D::GaussLobatto); - const IntegrationRule *ir = &intRules->Get(tr->GetGeometryType(), intorder); + const IntegrationRule* ir = &intRules->Get(tr->GetGeometryType(), intorder); h_face_el1[i] = tr->Elem1No; h_face_num_quad[i] = ir->GetNPoints(); @@ -1409,7 +1409,7 @@ void M2ulPhyS::initIndirectionArrays() { Vector dist1, dist2; if (distance_ != NULL) { - const ParFiniteElementSpace *dist_fes = distance_->ParFESpace(); + const ParFiniteElementSpace* dist_fes = distance_->ParFESpace(); Array dist_dofs1; dist_fes->GetElementVDofs(tr->Elem1->ElementNo, dist_dofs1); @@ -1431,7 +1431,7 @@ void M2ulPhyS::initIndirectionArrays() { nor.SetSize(dim); for (int q = 0; q < ir->GetNPoints(); q++) { - const IntegrationPoint &ip = ir->IntPoint(q); + const IntegrationPoint& ip = ir->IntPoint(q); tr->SetAllIntPoints(&ip); fe1->CalcShape(tr->GetElement1IntPoint(), shape1); @@ -1486,7 +1486,7 @@ void M2ulPhyS::initIndirectionArrays() { } void M2ulPhyS::initIndirectionBC() { - boundaryFaceIntegrationData &bdry_face_data = gpu_precomputed_data_.boundary_face_data; + boundaryFaceIntegrationData& bdry_face_data = gpu_precomputed_data_.boundary_face_data; // This is supposed to be number of boundary faces, and for // non-periodic cases it is. See #199 for more info. @@ -1506,8 +1506,8 @@ void M2ulPhyS::initIndirectionBC() { bdry_face_data.wall_bc_temperature.UseDevice(true); auto h_wall_bc_temperature = bdry_face_data.wall_bc_temperature.HostWrite(); - FaceElementTransformations *tr; - Mesh *mesh = fes->GetMesh(); + FaceElementTransformations* tr; + Mesh* mesh = fes->GetMesh(); for (int f = 0; f < NumBCelems; f++) { tr = mesh->GetBdrFaceTransformations(f); @@ -1515,9 +1515,9 @@ void M2ulPhyS::initIndirectionBC() { int attr = tr->Attribute; h_bc_category[f] = bcIntegrator->getAttributeCategory(attr); if (config.useBCinGrad && h_bc_category[f] == WALL) { - std::unordered_map::const_iterator wbci = bcIntegrator->wallBCmap.find(attr); + std::unordered_map::const_iterator wbci = bcIntegrator->wallBCmap.find(attr); if (wbci != bcIntegrator->wallBCmap.end()) { - WallBC *wbc = dynamic_cast(wbci->second); + WallBC* wbc = dynamic_cast(wbci->second); WallType wt = wbc->getType(); if (wt == VISC_ISOTH) { fflush(stdout); @@ -1624,7 +1624,7 @@ M2ulPhyS::~M2ulPhyS() { #endif } -void M2ulPhyS::getAttributesInPartition(Array &local_attr) { +void M2ulPhyS::getAttributesInPartition(Array& local_attr) { local_attr.DeleteAll(); for (int bel = 0; bel < vfes->GetNBE(); bel++) { int attr = vfes->GetBdrAttribute(bel); @@ -1859,7 +1859,7 @@ void M2ulPhyS::initSolutionAndVisualizationVectors() { mesh->GetNodes(coordsDof); if (config.linViscData.isEnabled) { spaceVaryViscMult = new ParGridFunction(fes); - double *viscMult = spaceVaryViscMult->HostWrite(); + double* viscMult = spaceVaryViscMult->HostWrite(); double wgt = 0.; for (int n = 0; n < fes->GetNDofs(); n++) { auto hcoords = coordsDof.HostRead(); // get coords @@ -1968,7 +1968,7 @@ void M2ulPhyS::projectInitialSolution() { // update plasma electrical conductivity if (tpsP->isFlowEMCoupled()) { - ParGridFunction *coordsDof = new ParGridFunction(dfes); + ParGridFunction* coordsDof = new ParGridFunction(dfes); mesh->GetNodes(*coordsDof); mixture->SetConstantPlasmaConductivity(plasma_conductivity_, Up, coordsDof); delete coordsDof; @@ -2054,7 +2054,7 @@ void M2ulPhyS::solveStep() { #ifdef HAVE_GSLIB // Get the source field for the interpolation // TODO(shaering): improve option to select u, , or for multiple at once - ParGridFunction *u_gf; + ParGridFunction* u_gf; if (config.planeDump.conserved == true) { u_gf = GetSolutionGF(); } else if (config.planeDump.primitive == true) { @@ -2184,13 +2184,13 @@ void M2ulPhyS::solve() { } // Initial conditions for debug/test case -void M2ulPhyS::InitialConditionEulerVortex(const Vector &x, Vector &y) { +void M2ulPhyS::InitialConditionEulerVortex(const Vector& x, Vector& y) { MFEM_ASSERT(x.Size() == 2, ""); int equations = 4; if (x.Size() == 3) equations = 5; int problem = 1; - DryAir *eqState = new DryAir(); + DryAir* eqState = new DryAir(); const double gamma = eqState->GetSpecificHeatRatio(); const double Rg = eqState->GetGasConstant(); @@ -2269,8 +2269,8 @@ void M2ulPhyS::InitialConditionEulerVortex(const Vector &x, Vector &y) { } // Initial conditions for debug/test case -void M2ulPhyS::testInitialCondition(const Vector &x, Vector &y) { - DryAir *eqState = new DryAir(); +void M2ulPhyS::testInitialCondition(const Vector& x, Vector& y) { + DryAir* eqState = new DryAir(); // Nice units const double vel_inf = 1.; @@ -2293,12 +2293,12 @@ void M2ulPhyS::testInitialCondition(const Vector &x, Vector &y) { // // NOTE: Use only for DRY_AIR. // void M2ulPhyS::dryAirUniformInitialConditions() { void M2ulPhyS::uniformInitialConditions() { - double *data = U->HostWrite(); - double *dataUp = Up->HostWrite(); - double *dataGradUp = gradUp->HostWrite(); + double* data = U->HostWrite(); + double* dataUp = Up->HostWrite(); + double* dataGradUp = gradUp->HostWrite(); int dof = vfes->GetNDofs(); - double *inputRhoRhoVp = config.GetConstantInitialCondition(); + double* inputRhoRhoVp = config.GetConstantInitialCondition(); // build initial state Vector initState(num_equation); @@ -2371,7 +2371,7 @@ void M2ulPhyS::uniformInitialConditions() { } void M2ulPhyS::initGradUp() { - double *dataGradUp = gradUp->HostWrite(); + double* dataGradUp = gradUp->HostWrite(); int dof = vfes->GetNDofs(); for (int i = 0; i < dof; i++) { @@ -2386,8 +2386,8 @@ void M2ulPhyS::initGradUp() { // NOTE(Mal): This is a method to be used when we restart from LTE simulation. // It initilzes species mass densities based on LTE assumptions. void M2ulPhyS::initilizeSpeciesFromLTE() { - double *dataU = U->GetData(); - double *dataUp = Up->GetData(); + double* dataU = U->GetData(); + double* dataUp = Up->GetData(); // double *dataGradUp = gradUp->HostWrite(); int dof = vfes->GetNDofs(); @@ -2404,10 +2404,10 @@ void M2ulPhyS::initilizeSpeciesFromLTE() { tpsP->getRequiredInput("flow/lte/e_rev_table", e_rev_file); config.lteMixtureInput.e_rev_file_name = e_rev_file; - TableInterpolator2D *energy_table; - TableInterpolator2D *R_table; - TableInterpolator2D *c_table; - TableInterpolator2D *T_table; + TableInterpolator2D* energy_table; + TableInterpolator2D* R_table; + TableInterpolator2D* c_table; + TableInterpolator2D* T_table; #if defined(HAVE_GSL) && !defined(_CUDA_) && !defined(_HIP_) @@ -2472,7 +2472,7 @@ void M2ulPhyS::Check_NAN() { cout << "Found a NaN!" << endl; } #else - const double *dataU = U->HostRead(); + const double* dataU = U->HostRead(); // bool thereIsNan = false; @@ -2506,8 +2506,8 @@ void M2ulPhyS::Check_NAN() { } } -int M2ulPhyS::Check_NaN_GPU(ParGridFunction *U, int lengthU, Array &loc_print) { - const double *dataU = U->Read(); +int M2ulPhyS::Check_NaN_GPU(ParGridFunction* U, int lengthU, Array& loc_print) { + const double* dataU = U->Read(); auto d_temp = loc_print.ReadWrite(); MFEM_FORALL(n, lengthU, { @@ -2528,7 +2528,7 @@ void M2ulPhyS::Check_Undershoot() { #ifdef _GPU_ int nv = nvel; int nsp = numActiveSpecies; - double *dataU = U->ReadWrite(); + double* dataU = U->ReadWrite(); MFEM_FORALL(i, dof, { for (int sp = 0; sp < nsp; sp++) { @@ -2537,7 +2537,7 @@ void M2ulPhyS::Check_Undershoot() { } }); #else - double *dataU = U->HostReadWrite(); + double* dataU = U->HostReadWrite(); for (int i = 0; i < dof; i++) { for (int sp = 0; sp < numActiveSpecies; sp++) { int eq = nvel + 2 + sp; @@ -3793,7 +3793,7 @@ void M2ulPhyS::parseRadiationInputs() { } } -void M2ulPhyS::readTableWrapper(std::string inputPath, TableInput &result) { +void M2ulPhyS::readTableWrapper(std::string inputPath, TableInput& result) { MPI_Comm TPSCommWorld = this->groupsMPI->getTPSCommWorld(); std::string filename; tpsP->getInput((inputPath + "/x_log").c_str(), result.xLogScale, false); @@ -3851,7 +3851,7 @@ void M2ulPhyS::packUpGasMixtureInput() { } } -void M2ulPhyS::identifySpeciesType(Array &speciesType) { +void M2ulPhyS::identifySpeciesType(Array& speciesType) { speciesType.SetSize(config.numSpecies); for (int sp = 0; sp < config.numSpecies; sp++) { @@ -3922,7 +3922,7 @@ void M2ulPhyS::identifySpeciesType(Array &speciesType) { return; } -void M2ulPhyS::identifyCollisionType(const Array &speciesType, GasColl *collisionIndex) { +void M2ulPhyS::identifyCollisionType(const Array& speciesType, GasColl* collisionIndex) { // collisionIndex_.resize(numSpecies); for (int spI = 0; spI < config.numSpecies; spI++) { // collisionIndex_[spI].resize(numSpecies - spI); @@ -4051,8 +4051,8 @@ void M2ulPhyS::checkSolverOptions() const { } void M2ulPhyS::updatePrimitives() { - const double *data = U->HostRead(); - double *dataUp = Up->HostWrite(); + const double* data = U->HostRead(); + double* dataUp = Up->HostWrite(); int dof = vfes->GetNDofs(); // Change this double * state = new double[num_equation] and same for Upi? @@ -4162,9 +4162,9 @@ void M2ulPhyS::updateVisualizationVariables() { // TODO(kevin): The routine here currently only supports cpu path, though it is written in a gpu-compatible way. // Will require some minor #ifdef additions to implement gpu path. - double *dataU = U->GetData(); - double *dataUp = Up->GetData(); - double *dataGradUp = gradUp->GetData(); + double* dataU = U->GetData(); + double* dataUp = Up->GetData(); + double* dataGradUp = gradUp->GetData(); const int ndofs = vfes->GetNDofs(); const int _dim = dim; const int _nvel = nvel; @@ -4172,14 +4172,14 @@ void M2ulPhyS::updateVisualizationVariables() { const int _numSpecies = numSpecies; const int _numReactions = config.numReactions; - GasMixture *in_mix = mixture; - TransportProperties *in_transport = transportPtr; - Chemistry *in_chem = chemistry_; + GasMixture* in_mix = mixture; + TransportProperties* in_transport = transportPtr; + Chemistry* in_chem = chemistry_; const bool isDryAir = (config.workFluid == DRY_AIR); const int nVisual = visualizationVariables_.size(); const AuxiliaryVisualizationIndexes visualIdxs = visualizationIndexes_; - double *dataVis[gpudata::MAXVISUAL]; + double* dataVis[gpudata::MAXVISUAL]; for (int vis = 0; vis < nVisual; vis++) dataVis[vis] = visualizationVariables_[vis]->GetData(); for (int n = 0; n < ndofs; n++) { @@ -4217,7 +4217,7 @@ void M2ulPhyS::updateVisualizationVariables() { double radius = -1; if (config.isAxisymmetric()) { - ParGridFunction *xyz = new ParGridFunction(dfes); + ParGridFunction* xyz = new ParGridFunction(dfes); mesh->GetNodes(*xyz); radius = (*xyz)[n + 0 * ndofs]; } @@ -4264,18 +4264,18 @@ void M2ulPhyS::updateVisualizationVariables() { void M2ulPhyS::evaluatePlasmaConductivityGF() { assert(plasma_conductivity_ != NULL); - double *d_pc = plasma_conductivity_->Write(); + double* d_pc = plasma_conductivity_->Write(); - const double *d_Up = Up->Read(); - const double *d_U = U->Read(); - const double *d_gradUp = gradUp->Read(); + const double* d_Up = Up->Read(); + const double* d_U = U->Read(); + const double* d_gradUp = gradUp->Read(); - const double *d_distance = NULL; + const double* d_distance = NULL; if (distance_ != NULL) { d_distance = distance_->Read(); } - TransportProperties *d_transport = transportPtr; + TransportProperties* d_transport = transportPtr; const int nnodes = vfes->GetNDofs(); const int _dim = dim; diff --git a/src/M2ulPhyS.hpp b/src/M2ulPhyS.hpp index ebbc9d91..b8b846e4 100644 --- a/src/M2ulPhyS.hpp +++ b/src/M2ulPhyS.hpp @@ -92,13 +92,13 @@ class Tps2Boltzmann; class M2ulPhyS : public TPS::PlasmaSolver { private: - MPI_Groups *groupsMPI; + MPI_Groups* groupsMPI; int nprocs_; // total number of MPI procs int rank_; // local MPI rank bool rank0_; // flag to indicate rank 0 // pointer to parent Tps class - TPS::Tps *tpsP; + TPS::Tps* tpsP; // Run options RunConfiguration config; @@ -140,40 +140,40 @@ class M2ulPhyS : public TPS::PlasmaSolver { double max_char_speed; // reference to mesh - ParMesh *mesh; + ParMesh* mesh; // original mesh partition info (stored on rank 0) Array partitioning_; const int defaultPartMethod = 1; // time integrator - ODESolver *timeIntegrator; + ODESolver* timeIntegrator; // Pointers to the different classes - GasMixture *mixture; // valid on host - GasMixture *d_mixture; // valid on device, when available; otherwise = mixture + GasMixture* mixture; // valid on host + GasMixture* d_mixture; // valid on device, when available; otherwise = mixture - TransportProperties *transportPtr = NULL; // valid on both host and device + TransportProperties* transportPtr = NULL; // valid on both host and device // TransportProperties *d_transport = NULL; // valid on device, when available; otherwise = transportPtr - Chemistry *chemistry_ = NULL; + Chemistry* chemistry_ = NULL; - Radiation *radiation_ = NULL; + Radiation* radiation_ = NULL; // space varying viscosity multiplier - ParGridFunction *spaceVaryViscMult; + ParGridFunction* spaceVaryViscMult; /// Distance to nearest no-slip wall - ParGridFunction *distance_; + ParGridFunction* distance_; - Fluxes *fluxClass; // valid on host - Fluxes *d_fluxClass; // valid on device, when available; otherwise = fluxClass + Fluxes* fluxClass; // valid on host + Fluxes* d_fluxClass; // valid on device, when available; otherwise = fluxClass - RHSoperator *rhsOperator; + RHSoperator* rhsOperator; // Integration rule int intRuleType; // 0: GaussLegendre; 1: GaussLobatto - IntegrationRules *intRules; + IntegrationRules* intRules; // Interpolant function // 0: GaussLegendre; 1: GaussLobatto @@ -182,19 +182,19 @@ class M2ulPhyS : public TPS::PlasmaSolver { // Finite element collection // DG_FECollection *fec; // H1_FECollection *fec; - FiniteElementCollection *fec; + FiniteElementCollection* fec; // Finite element space for a scalar (thermodynamic quantity) - ParFiniteElementSpace *fes; + ParFiniteElementSpace* fes; // Finite element space for a mesh-dim vector quantity (momentum) - ParFiniteElementSpace *dfes; + ParFiniteElementSpace* dfes; // Finite element space for a nvel vector quantity. only for visualization (diffusion velocity). - ParFiniteElementSpace *nvelfes; + ParFiniteElementSpace* nvelfes; // Finite element space for all variables together (total thermodynamic state) - ParFiniteElementSpace *vfes; + ParFiniteElementSpace* vfes; // nodes IDs and indirection array const int maxIntPoints = gpudata::MAXINTPOINTS; // corresponding to HEX face with p=5 @@ -205,56 +205,56 @@ class M2ulPhyS : public TPS::PlasmaSolver { // The solution u has components {density, x-momentum, y-momentum, energy}. // These are stored contiguously in the BlockVector u_block. - Array *offsets; - BlockVector *u_block; - BlockVector *up_block; + Array* offsets; + BlockVector* u_block; + BlockVector* up_block; // paraview collection pointer - ParaViewDataCollection *paraviewColl = NULL; + ParaViewDataCollection* paraviewColl = NULL; // DataCollection *visitColl = NULL; // Riemann Solver - RiemannSolverTPS *rsolver; + RiemannSolverTPS* rsolver; // RHS operators // ParNonlinearForm *A; - DGNonLinearForm *A; + DGNonLinearForm* A; - FaceIntegrator *faceIntegrator; + FaceIntegrator* faceIntegrator; - MixedBilinearForm *Aflux; - DomainIntegrator *domainIntegrator; + MixedBilinearForm* Aflux; + DomainIntegrator* domainIntegrator; // Boundary condition non-linear integrator - BCintegrator *bcIntegrator; + BCintegrator* bcIntegrator; // Conservative variables - ParGridFunction *U; + ParGridFunction* U; // Primitive variables - ParGridFunction *Up; + ParGridFunction* Up; // Visualization functions (these are pointers to Up) ParGridFunction *temperature, *dens, *vel, *vtheta, *passiveScalar; - ParGridFunction *electron_temp_field; - ParGridFunction *press; - std::vector visualizationVariables_; + ParGridFunction* electron_temp_field; + ParGridFunction* press; + std::vector visualizationVariables_; std::vector visualizationNames_; AuxiliaryVisualizationIndexes visualizationIndexes_; - ParGridFunction *plasma_conductivity_; - ParGridFunction *joule_heating_; + ParGridFunction* plasma_conductivity_; + ParGridFunction* joule_heating_; // gradient of primitive variables - ParGridFunction *gradUp; - ParFiniteElementSpace *gradUpfes; + ParGridFunction* gradUp; + ParFiniteElementSpace* gradUpfes; // ParNonlinearForm *gradUp_A; - GradNonLinearForm *gradUp_A; + GradNonLinearForm* gradUp_A; // Auxiliary grid function to store external reaction rates std::unique_ptr externalReactionRates; // Average handler - Averaging *average; + Averaging* average; // time variable double time; @@ -289,11 +289,11 @@ class M2ulPhyS : public TPS::PlasmaSolver { int exit_status_; // mapping from local to global element index - int *locToGlobElem; + int* locToGlobElem; // a serial mesh, finite element space, and grid function // for use if we want to write a serial file - Mesh *serial_mesh; + Mesh* serial_mesh; // I/O organizer IODataOrganizer ioData; @@ -302,12 +302,12 @@ class M2ulPhyS : public TPS::PlasmaSolver { #ifdef HAVE_MASA VectorFunctionCoefficient *DenMMS_, *VelMMS_, *PreMMS_; - VectorFunctionCoefficient *stateMMS_; - std::vector componentWindow_; + VectorFunctionCoefficient* stateMMS_; + std::vector componentWindow_; - ParGridFunction *zeroU_; // to compute L2 norm of exact solution via ComputeLpError. - ParGridFunction *masaU_; // for visualization of the exact solution. - ParGridFunction *masaRhs_; // for visualization of the right-hand side. + ParGridFunction* zeroU_; // to compute L2 norm of exact solution via ComputeLpError. + ParGridFunction* masaU_; // for visualization of the exact solution. + ParGridFunction* masaRhs_; // for visualization of the right-hand side. BlockVector *zeroUBlock_, *masaUBlock_; #endif @@ -315,7 +315,7 @@ class M2ulPhyS : public TPS::PlasmaSolver { Array loc_print; #endif - void getAttributesInPartition(Array &local_attr); + void getAttributesInPartition(Array& local_attr); /** @brief Fill precomputedIntegrationData struct * @@ -341,8 +341,8 @@ class M2ulPhyS : public TPS::PlasmaSolver { void initSolutionAndVisualizationVectors(); void initialTimeStep(); - static void InitialConditionEulerVortex(const Vector &x, Vector &y); - static void testInitialCondition(const Vector &x, Vector &y); + static void InitialConditionEulerVortex(const Vector& x, Vector& y); + static void testInitialCondition(const Vector& x, Vector& y); // void dryAirUniformInitialConditions(); void uniformInitialConditions(); void initGradUp(); @@ -360,14 +360,14 @@ class M2ulPhyS : public TPS::PlasmaSolver { #ifdef HAVE_MASA void initMasaHandler(); - void projectExactSolution(const double _time, ParGridFunction *prjU); + void projectExactSolution(const double _time, ParGridFunction* prjU); void initMMSCoefficients(); void checkSolutionError(const double _time, const bool final = false); #endif public: - M2ulPhyS(string &inputFileName, TPS::Tps *tps); - M2ulPhyS(TPS::Tps *tps); + M2ulPhyS(string& inputFileName, TPS::Tps* tps); + M2ulPhyS(TPS::Tps* tps); ~M2ulPhyS(); void parseSolverOptions() override; @@ -395,11 +395,11 @@ class M2ulPhyS : public TPS::PlasmaSolver { void parsePostProcessVisualizationInputs(); void parseRadiationInputs(); void parsePlaneDump(); - void readTableWrapper(std::string inputPath, TableInput &result); + void readTableWrapper(std::string inputPath, TableInput& result); void packUpGasMixtureInput(); - void identifySpeciesType(Array &speciesType); - void identifyCollisionType(const Array &speciesType, GasColl *collisionIndex); + void identifySpeciesType(Array& speciesType); + void identifyCollisionType(const Array& speciesType, GasColl* collisionIndex); void checkSolverOptions() const; void projectInitialSolution(); @@ -416,39 +416,39 @@ class M2ulPhyS : public TPS::PlasmaSolver { void solveBegin() override; void solveEnd() override; void visualization() override; - ParMesh *getMesh() const override { return mesh; } - ParFiniteElementSpace *getFESpace() const override { return vfes; } - const FiniteElementCollection *getFEC() const override { return fec; } + ParMesh* getMesh() const override { return mesh; } + ParFiniteElementSpace* getFESpace() const override { return vfes; } + const FiniteElementCollection* getFEC() const override { return fec; } - ParGridFunction *getPlasmaConductivityGF() override { return plasma_conductivity_; } - ParGridFunction *getJouleHeatingGF() override { return joule_heating_; } + ParGridFunction* getPlasmaConductivityGF() override { return plasma_conductivity_; } + ParGridFunction* getJouleHeatingGF() override { return joule_heating_; } void evaluatePlasmaConductivityGF() override; void updateVisualizationVariables(); // Accessors - RHSoperator *getRHSoperator() { return rhsOperator; } - ParFiniteElementSpace *GetScalarFES() { return fes; } - ParFiniteElementSpace *GetVectorFES() { return dfes; } - ParaViewDataCollection *GetParaviewColl() { return paraviewColl; } - ParGridFunction *GetSolutionGF() { return U; } - ParGridFunction *getPrimitiveGF() { return Up; } - ParGridFunction *getGradientGF() { return gradUp; } - ParGridFunction *getPressureGF() { return press; } - IntegrationRules *getIntegrationRules() { return intRules; } - RunConfiguration &GetConfig() { return config; } - GasMixture *getMixture() { return mixture; } - Chemistry *getChemistry() { return chemistry_; } - - const ParGridFunction *getDistanceFcn() { return distance_; } + RHSoperator* getRHSoperator() { return rhsOperator; } + ParFiniteElementSpace* GetScalarFES() { return fes; } + ParFiniteElementSpace* GetVectorFES() { return dfes; } + ParaViewDataCollection* GetParaviewColl() { return paraviewColl; } + ParGridFunction* GetSolutionGF() { return U; } + ParGridFunction* getPrimitiveGF() { return Up; } + ParGridFunction* getGradientGF() { return gradUp; } + ParGridFunction* getPressureGF() { return press; } + IntegrationRules* getIntegrationRules() { return intRules; } + RunConfiguration& GetConfig() { return config; } + GasMixture* getMixture() { return mixture; } + Chemistry* getChemistry() { return chemistry_; } + + const ParGridFunction* getDistanceFcn() { return distance_; } void updatePrimitives(); - static int Check_NaN_GPU(ParGridFunction *U, int lengthU, Array &loc_print); + static int Check_NaN_GPU(ParGridFunction* U, int lengthU, Array& loc_print); void Check_Undershoot(); void setConstantPlasmaConductivityGF() { - ParGridFunction *coordsDof = new ParGridFunction(dfes); + ParGridFunction* coordsDof = new ParGridFunction(dfes); mesh->GetNodes(*coordsDof); mixture->SetConstantPlasmaConductivity(plasma_conductivity_, Up, coordsDof); delete coordsDof; @@ -456,9 +456,9 @@ class M2ulPhyS : public TPS::PlasmaSolver { // tps2Boltzmann interface (implemented in M2ulPhyS2Boltzmann.cpp) /// Push solver variables to interface - void push(TPS::Tps2Boltzmann &interface) override; + void push(TPS::Tps2Boltzmann& interface) override; /// Fetch solver variables from interface - void fetch(TPS::Tps2Boltzmann &interface) override; + void fetch(TPS::Tps2Boltzmann& interface) override; // Exit code access void SetStatus(int code) { diff --git a/src/M2ulPhyS2Boltzmann.cpp b/src/M2ulPhyS2Boltzmann.cpp index 8bdf6a5c..7dbbdf97 100644 --- a/src/M2ulPhyS2Boltzmann.cpp +++ b/src/M2ulPhyS2Boltzmann.cpp @@ -37,28 +37,28 @@ #include "tps2Boltzmann.hpp" // CPU version (just for starting up) -void M2ulPhyS::push(TPS::Tps2Boltzmann &interface) { +void M2ulPhyS::push(TPS::Tps2Boltzmann& interface) { assert(interface.IsInitialized()); int nscalardofs = vfes->GetNDofs(); - const double *solver_data = U->HostRead(); + const double* solver_data = U->HostRead(); - mfem::ParGridFunction *species = + mfem::ParGridFunction* species = new mfem::ParGridFunction(&interface.NativeFes(TPS::Tps2Boltzmann::Index::SpeciesDensities)); - mfem::ParGridFunction *heavyTemperature = + mfem::ParGridFunction* heavyTemperature = new mfem::ParGridFunction(&interface.NativeFes(TPS::Tps2Boltzmann::Index::HeavyTemperature)); - mfem::ParGridFunction *electronTemperature = + mfem::ParGridFunction* electronTemperature = new mfem::ParGridFunction(&interface.NativeFes(TPS::Tps2Boltzmann::Index::ElectronTemperature)); - double *species_data = species->HostWrite(); - double *heavyTemperature_data = heavyTemperature->HostWrite(); - double *electronTemperature_data = electronTemperature->HostWrite(); + double* species_data = species->HostWrite(); + double* heavyTemperature_data = heavyTemperature->HostWrite(); + double* electronTemperature_data = electronTemperature->HostWrite(); double state_local[gpudata::MAXEQUATIONS]; double species_local[gpudata::MAXSPECIES]; - PerfectMixture *pmixture = dynamic_cast(mixture); + PerfectMixture* pmixture = dynamic_cast(mixture); assert(pmixture); for (int i = 0; i < nscalardofs; i++) { @@ -86,12 +86,12 @@ void M2ulPhyS::push(TPS::Tps2Boltzmann &interface) { delete electronTemperature; } -void M2ulPhyS::fetch(TPS::Tps2Boltzmann &interface) { - mfem::ParFiniteElementSpace *reaction_rates_fes(&(interface.NativeFes(TPS::Tps2Boltzmann::Index::ReactionRates))); +void M2ulPhyS::fetch(TPS::Tps2Boltzmann& interface) { + mfem::ParFiniteElementSpace* reaction_rates_fes(&(interface.NativeFes(TPS::Tps2Boltzmann::Index::ReactionRates))); externalReactionRates.reset(new mfem::ParGridFunction(reaction_rates_fes)); interface.interpolateToNativeFES(*externalReactionRates, TPS::Tps2Boltzmann::Index::ReactionRates); #if defined(_CUDA_) || defined(_HIP_) - const double *data(externalReactionRates->Read()); + const double* data(externalReactionRates->Read()); int size(externalReactionRates->FESpace()->GetNDofs()); assert(externalReactionRates->FESpace()->GetOrdering() == mfem::Ordering::byNODES); gpu::deviceSetChemistryReactionData<<<1, 1>>>(data, size, chemistry_); diff --git a/src/algebraicSubgridModels.cpp b/src/algebraicSubgridModels.cpp index 7bb2c7be..e7187492 100644 --- a/src/algebraicSubgridModels.cpp +++ b/src/algebraicSubgridModels.cpp @@ -48,8 +48,8 @@ using namespace mfem; using namespace mfem::common; -AlgebraicSubgridModels::AlgebraicSubgridModels(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, TPS::Tps *tps, - ParGridFunction *gridScale, int sModel) +AlgebraicSubgridModels::AlgebraicSubgridModels(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, TPS::Tps* tps, + ParGridFunction* gridScale, int sModel) : tpsP_(tps), loMach_opts_(loMach_opts), pmesh_(pmesh) { rank_ = pmesh_->GetMyRank(); rank0_ = (pmesh_->GetMyRank() == 0); @@ -163,7 +163,7 @@ void AlgebraicSubgridModels::initializeOperators() { this->step(); } -void AlgebraicSubgridModels::initializeViz(ParaViewDataCollection &pvdc) { +void AlgebraicSubgridModels::initializeViz(ParaViewDataCollection& pvdc) { pvdc.RegisterField("muT", &subgridVisc_gf_); } @@ -183,12 +183,12 @@ void AlgebraicSubgridModels::step() { (thermoChem_interface_->density)->GetTrueDofs(rn_); subgridVisc_ = 0.0; - const double *dGradU = gradU_.HostRead(); - const double *dGradV = gradV_.HostRead(); - const double *dGradW = gradW_.HostRead(); - const double *rho = rn_.HostRead(); - const double *del = gridScale_->HostRead(); - double *data = subgridVisc_.HostReadWrite(); + const double* dGradU = gradU_.HostRead(); + const double* dGradV = gradV_.HostRead(); + const double* dGradW = gradW_.HostRead(); + const double* rho = rn_.HostRead(); + const double* del = gridScale_->HostRead(); + double* data = subgridVisc_.HostReadWrite(); if (sModel_ == 1) { for (int i = 0; i < SdofInt_; i++) { @@ -259,7 +259,7 @@ void AlgebraicSubgridModels::step() { subgridVisc_gf_.GetTrueDofs(subgridVisc_); // clip any small negatives resulting from filtering - double *dmuT = subgridVisc_.HostReadWrite(); + double* dmuT = subgridVisc_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { dmuT[i] = std::max(dmuT[i], 1.0e-15); } @@ -272,8 +272,8 @@ void AlgebraicSubgridModels::step() { double wt0 = 1.0 / std::min((double)aveSteps_, (double)activeSteps_); double wt1 = 1.0 - wt0; - double *dmuT = subgridVisc_.HostReadWrite(); - double *dmuT0 = muT_NM1_.HostReadWrite(); + double* dmuT = subgridVisc_.HostReadWrite(); + double* dmuT0 = muT_NM1_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { // \bar{muT}^{n} = wt0*muT' + wt1*\bar{muT}^{n-1} dmuT[i] *= wt0; @@ -289,7 +289,7 @@ void AlgebraicSubgridModels::step() { /** Basic Smagorinksy subgrid model with user-specified coefficient */ -void AlgebraicSubgridModels::sgsSmag(const DenseMatrix &gradUp, double delta, double &nu) { +void AlgebraicSubgridModels::sgsSmag(const DenseMatrix& gradUp, double delta, double& nu) { Vector Sij(6); double Smag = 0.; double Cd; @@ -321,7 +321,7 @@ void AlgebraicSubgridModels::sgsSmag(const DenseMatrix &gradUp, double delta, do WALE model, see: Weicker 2010 Note: gradUp is in (eq,dim) form */ -void AlgebraicSubgridModels::sgsWALE(const DenseMatrix &gradUp, double delta, double &nu) { +void AlgebraicSubgridModels::sgsWALE(const DenseMatrix& gradUp, double delta, double& nu) { DenseMatrix Sij(dim_, dim_); DenseMatrix Oij(dim_, dim_); DenseMatrix gij(dim_, dim_); @@ -455,7 +455,7 @@ void AlgebraicSubgridModels::sgsWALE(const DenseMatrix &gradUp, double delta, do NOT TESTED: Sigma subgrid model following Nicoud et.al., "Using singular values to build a subgrid-scale model for large eddy simulations", PoF 2011. */ -void AlgebraicSubgridModels::sgsSigma(const DenseMatrix &gradUp, double delta, double &nu) { +void AlgebraicSubgridModels::sgsSigma(const DenseMatrix& gradUp, double delta, double& nu) { DenseMatrix Qij(dim_, dim_); DenseMatrix du(dim_, dim_); DenseMatrix B(dim_, dim_); diff --git a/src/algebraicSubgridModels.hpp b/src/algebraicSubgridModels.hpp index c7e52393..376baec0 100644 --- a/src/algebraicSubgridModels.hpp +++ b/src/algebraicSubgridModels.hpp @@ -54,8 +54,8 @@ class Tps; #include "tps_mfem_wrap.hpp" #include "turb_model_base.hpp" -using VecFuncT = void(const Vector &x, double t, Vector &u); -using ScalarFuncT = double(const Vector &x, double t); +using VecFuncT = void(const Vector& x, double t, Vector& u); +using ScalarFuncT = double(const Vector& x, double t); class LoMachSolver; class LoMachOptions; @@ -66,9 +66,9 @@ class AlgebraicSubgridModels : public TurbModelBase { friend class LoMachSolver; private: - TPS::Tps *tpsP_; + TPS::Tps* tpsP_; // LoMachSolver *loMach_; - LoMachOptions *loMach_opts_ = nullptr; + LoMachOptions* loMach_opts_ = nullptr; // MPI_Groups *groupsMPI; // int nprocs_; // total number of MPI procs @@ -81,7 +81,7 @@ class AlgebraicSubgridModels : public TurbModelBase { /// Enable/disable verbose output. bool verbose = true; - ParMesh *pmesh_ = nullptr; + ParMesh* pmesh_ = nullptr; // The order of the scalar spaces int order_; @@ -100,32 +100,32 @@ class AlgebraicSubgridModels : public TurbModelBase { // const temporalSchemeCoefficients &timeCoeff_; // Scalar \f$H^1\f$ finite element collection. - FiniteElementCollection *sfec_ = nullptr; + FiniteElementCollection* sfec_ = nullptr; // Scalar \f$H^1\f$ finite element space. - ParFiniteElementSpace *sfes_ = nullptr; + ParFiniteElementSpace* sfes_ = nullptr; /// Velocity \f$H^1\f$ finite element collection. - FiniteElementCollection *vfec_ = nullptr; + FiniteElementCollection* vfec_ = nullptr; /// Velocity \f$(H^1)^d\f$ finite element space. - ParFiniteElementSpace *vfes_ = nullptr; + ParFiniteElementSpace* vfes_ = nullptr; /// spaces for filtered eddy viscosity - FiniteElementCollection *sfec_filter_ = nullptr; - ParFiniteElementSpace *sfes_filter_ = nullptr; + FiniteElementCollection* sfec_filter_ = nullptr; + ParFiniteElementSpace* sfes_filter_ = nullptr; - ParGridFunction *gradU_gf_ = nullptr; - ParGridFunction *gradV_gf_ = nullptr; - ParGridFunction *gradW_gf_ = nullptr; + ParGridFunction* gradU_gf_ = nullptr; + ParGridFunction* gradV_gf_ = nullptr; + ParGridFunction* gradW_gf_ = nullptr; Vector gradU_; Vector gradV_; Vector gradW_; - ParGridFunction *rn_gf_ = nullptr; + ParGridFunction* rn_gf_ = nullptr; Vector rn_; - ParGridFunction *delta_gf_ = nullptr; + ParGridFunction* delta_gf_ = nullptr; Vector delta_; ParGridFunction subgridVisc_gf_; @@ -138,7 +138,7 @@ class AlgebraicSubgridModels : public TurbModelBase { ParGridFunction muT_filtered_gf_; // grid information - ParGridFunction *gridScale_ = nullptr; + ParGridFunction* gridScale_ = nullptr; double sgs_model_const_; int sgs_model_nFilter_; @@ -147,7 +147,7 @@ class AlgebraicSubgridModels : public TurbModelBase { int activeSteps_; public: - AlgebraicSubgridModels(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, TPS::Tps *tps, ParGridFunction *gridScale, + AlgebraicSubgridModels(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, TPS::Tps* tps, ParGridFunction* gridScale, int sModel); virtual ~AlgebraicSubgridModels(); @@ -156,14 +156,14 @@ class AlgebraicSubgridModels : public TurbModelBase { void initializeOperators() final; void step() final; void setup() final; - void initializeViz(ParaViewDataCollection &pvdc) final; + void initializeViz(ParaViewDataCollection& pvdc) final; /// Return a pointer to the current temperature ParGridFunction. - ParGridFunction *getCurrentEddyViscosity() { return &subgridVisc_gf_; } + ParGridFunction* getCurrentEddyViscosity() { return &subgridVisc_gf_; } // subgrid scale models => move to turb model class - void sgsSmag(const DenseMatrix &gradUp, double delta, double &nu_sgs); - void sgsSigma(const DenseMatrix &gradUp, double delta, double &nu_sgs); - void sgsWALE(const DenseMatrix &gradUp, double delta, double &nu_sgs); + void sgsSmag(const DenseMatrix& gradUp, double delta, double& nu_sgs); + void sgsSigma(const DenseMatrix& gradUp, double delta, double& nu_sgs); + void sgsWALE(const DenseMatrix& gradUp, double delta, double& nu_sgs); }; #endif // ALGEBRAICSUBGRIDMODELS_HPP_ diff --git a/src/algebraic_rans.cpp b/src/algebraic_rans.cpp index 6f2854e3..46b9f3ab 100644 --- a/src/algebraic_rans.cpp +++ b/src/algebraic_rans.cpp @@ -40,8 +40,8 @@ using namespace mfem; -AlgebraicRans::AlgebraicRans(ParMesh *pmesh, const Array &partitioning, int order, TPS::Tps *tps, - ParGridFunction *distance) +AlgebraicRans::AlgebraicRans(ParMesh* pmesh, const Array& partitioning, int order, TPS::Tps* tps, + ParGridFunction* distance) : pmesh_(pmesh), order_(order), distance_(distance) { dim_ = pmesh_->Dimension(); @@ -112,7 +112,7 @@ void AlgebraicRans::initializeSelf() { toThermoChem_interface_.eddy_viscosity = mut_; } -void AlgebraicRans::initializeViz(mfem::ParaViewDataCollection &pvdc) { +void AlgebraicRans::initializeViz(mfem::ParaViewDataCollection& pvdc) { pvdc.RegisterField("muT", mut_); pvdc.RegisterField("distance", distance_); } @@ -134,9 +134,9 @@ void AlgebraicRans::step() { // mut_, since rest of operations are multiplicative if (axisym_) { int ndof = sfes_->GetNDofs(); - double *d_mut = mut_->Write(); - const double *d_omega = vorticity_gf_->Read(); - const double *d_swirl_omega = swirl_vorticity_gf_->Read(); + double* d_mut = mut_->Write(); + const double* d_omega = vorticity_gf_->Read(); + const double* d_swirl_omega = swirl_vorticity_gf_->Read(); MFEM_FORALL(i, ndof, { double omega_r = d_swirl_omega[i]; double omega_th = d_omega[i]; @@ -147,8 +147,8 @@ void AlgebraicRans::step() { } else { if (dim_ == 2) { int ndof = sfes_->GetNDofs(); - double *d_mut = mut_->Write(); - const double *d_omega = vorticity_gf_->Read(); + double* d_mut = mut_->Write(); + const double* d_omega = vorticity_gf_->Read(); MFEM_FORALL(i, ndof, { double omega_z = d_omega[i]; double magn_omega_2 = omega_z * omega_z; @@ -156,8 +156,8 @@ void AlgebraicRans::step() { }); } else { // dim_ == 3 int ndof = sfes_->GetNDofs(); - double *d_mut = mut_->Write(); - const double *d_omega = vorticity_gf_->Read(); + double* d_mut = mut_->Write(); + const double* d_omega = vorticity_gf_->Read(); MFEM_FORALL(i, ndof, { double omega_x = d_omega[i]; double omega_y = d_omega[ndof + i]; @@ -171,8 +171,8 @@ void AlgebraicRans::step() { // Evaluate the mixing length { int ndof = sfes_->GetNDofs(); - double *d_ellmix = ell_mix_gf_->Write(); - const double *d_dist = distance_->Read(); + double* d_ellmix = ell_mix_gf_->Write(); + const double* d_dist = distance_->Read(); const double kap = kappa_von_karman_; const double max_ell = max_mixing_length_; MFEM_FORALL(i, ndof, { d_ellmix[i] = min(kap * d_dist[i], max_ell); }); diff --git a/src/algebraic_rans.hpp b/src/algebraic_rans.hpp index 9a9a1f55..2a30b208 100644 --- a/src/algebraic_rans.hpp +++ b/src/algebraic_rans.hpp @@ -46,7 +46,7 @@ */ class AlgebraicRans : public TurbModelBase { protected: - mfem::ParMesh *pmesh_ = nullptr; + mfem::ParMesh* pmesh_ = nullptr; int order_; int dim_; bool axisym_; @@ -54,32 +54,32 @@ class AlgebraicRans : public TurbModelBase { double max_mixing_length_; double kappa_von_karman_; - mfem::FiniteElementCollection *sfec_ = nullptr; - mfem::ParFiniteElementSpace *sfes_ = nullptr; + mfem::FiniteElementCollection* sfec_ = nullptr; + mfem::ParFiniteElementSpace* sfes_ = nullptr; - mfem::FiniteElementCollection *vfec_ = nullptr; - mfem::ParFiniteElementSpace *vfes_ = nullptr; + mfem::FiniteElementCollection* vfec_ = nullptr; + mfem::ParFiniteElementSpace* vfes_ = nullptr; - mfem::ParGridFunction *vorticity_gf_ = nullptr; - mfem::ParGridFunction *swirl_vorticity_gf_ = nullptr; + mfem::ParGridFunction* vorticity_gf_ = nullptr; + mfem::ParGridFunction* swirl_vorticity_gf_ = nullptr; - mfem::ParGridFunction *mut_ = nullptr; - mfem::ParGridFunction *distance_ = nullptr; - mfem::ParGridFunction *ell_mix_gf_ = nullptr; + mfem::ParGridFunction* mut_ = nullptr; + mfem::ParGridFunction* distance_ = nullptr; + mfem::ParGridFunction* ell_mix_gf_ = nullptr; // Only used by filter bool filter_mut_ = false; int filter_p_ = 1; - mfem::FiniteElementCollection *sfec_filter_ = nullptr; - mfem::ParFiniteElementSpace *sfes_filter_ = nullptr; - mfem::ParGridFunction *low_order_mut_ = nullptr; + mfem::FiniteElementCollection* sfec_filter_ = nullptr; + mfem::ParFiniteElementSpace* sfes_filter_ = nullptr; + mfem::ParGridFunction* low_order_mut_ = nullptr; public: /// Constructor // AlgebraicRans(mfem::Mesh *smesh, mfem::ParMesh *pmesh, const mfem::Array &partitioning, int order, TPS::Tps // *tps); - AlgebraicRans(mfem::ParMesh *pmesh, const mfem::Array &partitioning, int order, TPS::Tps *tps, - mfem::ParGridFunction *distance); + AlgebraicRans(mfem::ParMesh* pmesh, const mfem::Array& partitioning, int order, TPS::Tps* tps, + mfem::ParGridFunction* distance); /// Destructor virtual ~AlgebraicRans(); @@ -94,7 +94,7 @@ class AlgebraicRans : public TurbModelBase { /** * @brief Add eddy viscosity and distance function to the visualization output */ - void initializeViz(mfem::ParaViewDataCollection &pvdc) override; + void initializeViz(mfem::ParaViewDataCollection& pvdc) override; /** * @brief Initialize the eddy viscosity. @@ -113,7 +113,7 @@ class AlgebraicRans : public TurbModelBase { */ void setup() override {} - mfem::ParGridFunction *getCurrentEddyViscosity() override { return mut_; } + mfem::ParGridFunction* getCurrentEddyViscosity() override { return mut_; } }; #endif // ALGEBRAIC_RANS_HPP_ diff --git a/src/averaging.cpp b/src/averaging.cpp index eb2d6e0f..4a7c5c36 100644 --- a/src/averaging.cpp +++ b/src/averaging.cpp @@ -47,7 +47,7 @@ AveragingOptions::AveragingOptions() { zero_variances_ = false; } -void AveragingOptions::read(TPS::Tps *tps, std::string prefix) { +void AveragingOptions::read(TPS::Tps* tps, std::string prefix) { std::string basename; if (!prefix.empty()) { basename = prefix + "/averaging"; @@ -61,7 +61,7 @@ void AveragingOptions::read(TPS::Tps *tps, std::string prefix) { tps->getInput((basename + "/saveMeanHist").c_str(), save_mean_history_, false); } -Averaging::Averaging(AveragingOptions &opts, std::string output_name) { +Averaging::Averaging(AveragingOptions& opts, std::string output_name) { rank0_ = false; compute_mean_ = false; @@ -89,31 +89,31 @@ Averaging::~Averaging() { } } -void Averaging::registerField(std::string name, const ParGridFunction *field_to_average, bool compute_vari, +void Averaging::registerField(std::string name, const ParGridFunction* field_to_average, bool compute_vari, int vari_start_index, int vari_components) { // quick return if not computing stats... if (!compute_mean_) return; // otherwise, set up ParGridFunction to hold mean... - ParMesh *mesh = field_to_average->ParFESpace()->GetParMesh(); + ParMesh* mesh = field_to_average->ParFESpace()->GetParMesh(); rank0_ = (mesh->GetMyRank() == 0); - ParGridFunction *mean = new ParGridFunction(field_to_average->ParFESpace()); + ParGridFunction* mean = new ParGridFunction(field_to_average->ParFESpace()); *mean = 0.0; // and maybe the vari - ParGridFunction *vari = nullptr; + ParGridFunction* vari = nullptr; if (compute_vari) { // make sure incoming field has enough components to satisfy vari request assert((vari_start_index + vari_components) <= field_to_average->ParFESpace()->GetVDim()); const int num_variance = vari_components * (vari_components + 1) / 2; - const FiniteElementCollection *fec = field_to_average->ParFESpace()->FEColl(); + const FiniteElementCollection* fec = field_to_average->ParFESpace()->FEColl(); const int order = fec->GetOrder(); - FiniteElementCollection *vari_fec = fec->Clone(order); - ParFiniteElementSpace *vari_fes = new ParFiniteElementSpace(mesh, vari_fec, num_variance, Ordering::byNODES); + FiniteElementCollection* vari_fec = fec->Clone(order); + ParFiniteElementSpace* vari_fes = new ParFiniteElementSpace(mesh, vari_fec, num_variance, Ordering::byNODES); vari = new ParGridFunction(vari_fes); vari->MakeOwner(vari_fec); @@ -132,13 +132,13 @@ void Averaging::initializeViz() { // Loop through the families and add them to the paraview output for (size_t i = 0; i < avg_families_.size(); i++) { - ParGridFunction *mean = avg_families_[i].mean_fcn_; - ParGridFunction *vari = avg_families_[i].vari_fcn_; + ParGridFunction* mean = avg_families_[i].mean_fcn_; + ParGridFunction* vari = avg_families_[i].vari_fcn_; - const FiniteElementCollection *fec = mean->ParFESpace()->FEColl(); + const FiniteElementCollection* fec = mean->ParFESpace()->FEColl(); const int order = fec->GetOrder(); - ParMesh *mesh = mean->ParFESpace()->GetParMesh(); + ParMesh* mesh = mean->ParFESpace()->GetParMesh(); // If not yet allocated paraview, do it if (pvdc_ == nullptr) { @@ -164,19 +164,19 @@ void Averaging::initializeViz() { } } -void Averaging::initializeVizForM2ulPhyS(ParFiniteElementSpace *fes, ParFiniteElementSpace *dfes, int nvel) { +void Averaging::initializeVizForM2ulPhyS(ParFiniteElementSpace* fes, ParFiniteElementSpace* dfes, int nvel) { // quick return if not computing stats... if (!compute_mean_) return; assert(avg_families_.size() == 1); - ParGridFunction *meanUp = avg_families_[0].mean_fcn_; - ParGridFunction *vari = avg_families_[0].vari_fcn_; + ParGridFunction* meanUp = avg_families_[0].mean_fcn_; + ParGridFunction* vari = avg_families_[0].vari_fcn_; - const FiniteElementCollection *fec = meanUp->ParFESpace()->FEColl(); + const FiniteElementCollection* fec = meanUp->ParFESpace()->FEColl(); const int order = fec->GetOrder(); - ParMesh *mesh = meanUp->ParFESpace()->GetParMesh(); + ParMesh* mesh = meanUp->ParFESpace()->GetParMesh(); // "helper" spaces to index into meanUp meanRho = new ParGridFunction(fes, meanUp->GetData()); @@ -195,7 +195,7 @@ void Averaging::initializeVizForM2ulPhyS(ParFiniteElementSpace *fes, ParFiniteEl pvdc_->RegisterField("rms", vari); } -void Averaging::addSample(const int &iter, GasMixture *mixture) { +void Averaging::addSample(const int& iter, GasMixture* mixture) { // quick return if not computing stats... if (!compute_mean_) return; @@ -233,7 +233,7 @@ void Averaging::addSample(const int &iter, GasMixture *mixture) { } } -void Averaging::writeViz(const int &iter, const double &time, bool save_mean_hist) { +void Averaging::writeViz(const int& iter, const double& time, bool save_mean_hist) { // quick return if not computing stats... if (!compute_mean_) return; @@ -256,15 +256,15 @@ void Averaging::addSampleInternal() { // Loop through families that have been registered and compute means and variances for (size_t ifam = 0; ifam < avg_families_.size(); ifam++) { // Extract fields for use on device (when available) - AveragingFamily &fam = avg_families_[ifam]; + AveragingFamily& fam = avg_families_[ifam]; - const ParGridFunction *inst = fam.instantaneous_fcn_; - ParGridFunction *mean = fam.mean_fcn_; - ParGridFunction *vari = fam.vari_fcn_; + const ParGridFunction* inst = fam.instantaneous_fcn_; + ParGridFunction* mean = fam.mean_fcn_; + ParGridFunction* vari = fam.vari_fcn_; - const double *d_inst = inst->Read(); - double *d_mean = mean->ReadWrite(); - double *d_vari = nullptr; + const double* d_inst = inst->Read(); + double* d_mean = mean->ReadWrite(); + double* d_vari = nullptr; if (vari != nullptr) { d_vari = vari->ReadWrite(); } @@ -328,7 +328,7 @@ void Averaging::addSampleInternal() { } } -void Averaging::addSampleInternal(GasMixture *mixture) { +void Averaging::addSampleInternal(GasMixture* mixture) { // Assert that there is something to average. In principle we don't // need this, b/c the loop below is a no-op if there are no // families. However, if you got to this point, you're expecting to @@ -339,15 +339,15 @@ void Averaging::addSampleInternal(GasMixture *mixture) { // Loop through families that have been registered and compute means and variances for (size_t ifam = 0; ifam < avg_families_.size(); ifam++) { // Extract fields for use on device (when available) - AveragingFamily &fam = avg_families_[ifam]; + AveragingFamily& fam = avg_families_[ifam]; - const ParGridFunction *inst = fam.instantaneous_fcn_; - ParGridFunction *mean = fam.mean_fcn_; - ParGridFunction *vari = fam.vari_fcn_; + const ParGridFunction* inst = fam.instantaneous_fcn_; + ParGridFunction* mean = fam.mean_fcn_; + ParGridFunction* vari = fam.vari_fcn_; - const double *d_inst = inst->Read(); - double *d_mean = mean->ReadWrite(); - double *d_vari = nullptr; + const double* d_inst = inst->Read(); + double* d_mean = mean->ReadWrite(); + double* d_vari = nullptr; if (vari != nullptr) { d_vari = vari->ReadWrite(); } @@ -359,7 +359,7 @@ void Averaging::addSampleInternal(GasMixture *mixture) { // quantity is pressure. But, in general, it may be null, in // which case, whatever data are in the state are averaged // directly. - GasMixture *d_mixture = mixture; + GasMixture* d_mixture = mixture; // Extract size information for use on device const int dof = mean->ParFESpace()->GetNDofs(); // dofs per scalar field diff --git a/src/averaging.hpp b/src/averaging.hpp index 8a027c8d..5e462c6f 100644 --- a/src/averaging.hpp +++ b/src/averaging.hpp @@ -62,7 +62,7 @@ class AveragingOptions { bool enable_mean_continuation_; /**< Enable / disable continuation of statistics calculations from restart file */ bool zero_variances_; /**< Enable / disable zeroing out the variances at the beginning of a run */ - void read(TPS::Tps *tps, std::string prefix = std::string("")); + void read(TPS::Tps* tps, std::string prefix = std::string("")); }; /** @@ -97,13 +97,13 @@ class AveragingFamily { int vari_components_; /** Pointer to function containing the instantaneous field being averaged (not owned) */ - const ParGridFunction *instantaneous_fcn_; + const ParGridFunction* instantaneous_fcn_; /** Pointer to mean field (owned) */ - ParGridFunction *mean_fcn_; + ParGridFunction* mean_fcn_; /** Pointer to variance field (owned) */ - ParGridFunction *vari_fcn_; + ParGridFunction* vari_fcn_; /** * @brief Constructor @@ -112,7 +112,7 @@ class AveragingFamily { * constructing the AveragingFamily, but AveragingFamily then takes * ownership. */ - AveragingFamily(std::string name, const ParGridFunction *instant, ParGridFunction *mean, ParGridFunction *vari, + AveragingFamily(std::string name, const ParGridFunction* instant, ParGridFunction* mean, ParGridFunction* vari, int vari_start_index = 0, int vari_components = 1) { name_ = name; vari_start_index_ = vari_start_index; @@ -123,7 +123,7 @@ class AveragingFamily { } /// Move constructor (required for emplace_back) - AveragingFamily(AveragingFamily &&fam) { + AveragingFamily(AveragingFamily&& fam) { this->name_ = fam.name_; this->vari_start_index_ = fam.vari_start_index_; this->vari_components_ = fam.vari_components_; @@ -184,16 +184,16 @@ class Averaging { bool zero_variances_; /// mfem paraview data collection, used to write viz files - ParaViewDataCollection *pvdc_ = nullptr; + ParaViewDataCollection* pvdc_ = nullptr; /// time averaged p, rho, vel (pointers to meanUp) for visualization (M2ulPhyS only!) - ParGridFunction *meanP = nullptr; - ParGridFunction *meanRho = nullptr; - ParGridFunction *meanV = nullptr; + ParGridFunction* meanP = nullptr; + ParGridFunction* meanRho = nullptr; + ParGridFunction* meanV = nullptr; public: /// Constructor - Averaging(AveragingOptions &opts, std::string output_name); + Averaging(AveragingOptions& opts, std::string output_name); /// Destructor ~Averaging(); @@ -207,7 +207,7 @@ class Averaging { * @param vari_start_index Variable index at which to start variances (see AveragingFamily) * @param vari_components Number of variables in variances (see AveragingFamily) */ - void registerField(std::string name, const ParGridFunction *field_to_average, bool compute_vari = true, + void registerField(std::string name, const ParGridFunction* field_to_average, bool compute_vari = true, int vari_start_index = 0, int vari_components = 1); /** @@ -222,12 +222,12 @@ class Averaging { * returns. If so, farms work out to appropriate addSampleInternal * variant. */ - void addSample(const int &iter, GasMixture *mixture = nullptr); + void addSample(const int& iter, GasMixture* mixture = nullptr); /** * @brief Write paraview visualization files with statistics */ - void writeViz(const int &iter, const double &time, bool save_mean_hist); + void writeViz(const int& iter, const double& time, bool save_mean_hist); /** * @brief Internal implementation of sample addition @@ -245,7 +245,7 @@ class Averaging { * requirement on device lambdas. Instead of this method, you * should call addSample (with mixture = a valid GasMixture object). */ - void addSampleInternal(GasMixture *mixture); + void addSampleInternal(GasMixture* mixture); /** * @brief Initialize visualiztion for statistics (M2ulPhyS version) @@ -254,7 +254,7 @@ class Averaging { * with how stats viz files were originally labeled. It should only * be used inside M2ulPhyS. */ - void initializeVizForM2ulPhyS(ParFiniteElementSpace *fes, ParFiniteElementSpace *dfes, int nvel); + void initializeVizForM2ulPhyS(ParFiniteElementSpace* fes, ParFiniteElementSpace* dfes, int nvel); int getFamilyIndex(std::string name) const { for (size_t i = 0; i < avg_families_.size(); i++) { @@ -268,7 +268,7 @@ class Averaging { * * @param name Name of the family */ - ParGridFunction *GetMeanField(std::string name) { + ParGridFunction* GetMeanField(std::string name) { const int i = getFamilyIndex(name); assert(i >= 0); return avg_families_[i].mean_fcn_; @@ -279,7 +279,7 @@ class Averaging { * * @param name Name of the family */ - ParGridFunction *GetVariField(std::string name) { + ParGridFunction* GetVariField(std::string name) { const int i = getFamilyIndex(name); assert(i >= 0); return avg_families_[i].vari_fcn_; @@ -294,9 +294,9 @@ class Averaging { bool ContinueMean() { return enable_mean_continuation_; } bool RestartRMS() { return zero_variances_; } - void SetSamplesMean(int &samples) { ns_mean_ = samples; } - void SetSamplesRMS(int &samples) { ns_vari_ = samples; } - void SetSamplesInterval(int &interval) { sample_interval_ = interval; } + void SetSamplesMean(int& samples) { ns_mean_ = samples; } + void SetSamplesRMS(int& samples) { ns_vari_ = samples; } + void SetSamplesInterval(int& interval) { sample_interval_ = interval; } }; #endif // AVERAGING_HPP_ diff --git a/src/calorically_perfect.cpp b/src/calorically_perfect.cpp index a25b5308..18e41c5e 100644 --- a/src/calorically_perfect.cpp +++ b/src/calorically_perfect.cpp @@ -57,9 +57,9 @@ MFEM_HOST_DEVICE double Sutherland(const double T, const double mu_star, const d return mu_star * T_rat_32 * S_rat; } -CaloricallyPerfectThermoChem::CaloricallyPerfectThermoChem(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, - temporalSchemeCoefficients &time_coeff, - ParGridFunction *gridScale, TPS::Tps *tps) +CaloricallyPerfectThermoChem::CaloricallyPerfectThermoChem(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, + temporalSchemeCoefficients& time_coeff, + ParGridFunction* gridScale, TPS::Tps* tps) : tpsP_(tps), pmesh_(pmesh), time_coeff_(time_coeff) { rank0_ = (pmesh_->GetMyRank() == 0); order_ = loMach_opts->order; @@ -68,12 +68,14 @@ CaloricallyPerfectThermoChem::CaloricallyPerfectThermoChem(mfem::ParMesh *pmesh, tps->getInput("loMach/axisymmetric", axisym_, false); if (axisym_) { if (rank0_) { - std::cout << "ERROR: axisymmetric is not currently implemented in calorically_perfect. Either implement or use LTE or reacting..." << std::endl; + std::cout << "ERROR: axisymmetric is not currently implemented in calorically_perfect. Either implement or use " + "LTE or reacting..." + << std::endl; } assert(false); - exit(1); + exit(1); } - + std::string visc_model; tpsP_->getInput("loMach/calperfect/viscosity-model", visc_model, std::string("sutherland")); if (visc_model == "sutherland") { @@ -367,7 +369,7 @@ void CaloricallyPerfectThermoChem::initializeSelf() { std::cout << "Calorically Perfect: Setting uniform Dirichlet temperature on patch = " << patch << std::endl; } AddTempDirichletBC(temperature_value, inlet_attr); - + } else if (type == "interpolate") { Array inlet_attr(pmesh_->bdr_attributes.Max()); inlet_attr = 0; @@ -435,11 +437,11 @@ void CaloricallyPerfectThermoChem::initializeSelf() { double Twall; tpsP_->getRequiredInput((basepath + "/temperature").c_str(), Twall); - ConstantCoefficient *Twall_coeff = new ConstantCoefficient(); + ConstantCoefficient* Twall_coeff = new ConstantCoefficient(); Twall_coeff->constant = Twall; AddTempDirichletBC(Twall_coeff, attr_wall); - ConstantCoefficient *Qt_bc_coeff = new ConstantCoefficient(); + ConstantCoefficient* Qt_bc_coeff = new ConstantCoefficient(); Qt_bc_coeff->constant = 0.0; AddQtDirichletBC(Qt_bc_coeff, attr_wall); } @@ -464,9 +466,9 @@ void CaloricallyPerfectThermoChem::initializeOperators() { // unsteady: p+p [+p] = 2p [3p] // convection: p+p+(p-1) [+p] = 3p-1 [4p-1] // diffusion: (p-1)+(p-1) [+p] = 2p-2 [3p-2] - const IntegrationRule &ir_i = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ + 1); - const IntegrationRule &ir_nli = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 4 * order_); - const IntegrationRule &ir_di = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * order_ - 1); + const IntegrationRule& ir_i = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ + 1); + const IntegrationRule& ir_nli = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 4 * order_); + const IntegrationRule& ir_di = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * order_ - 1); if (rank0_) std::cout << "Integration rules set" << endl; // coefficients for operators @@ -518,7 +520,7 @@ void CaloricallyPerfectThermoChem::initializeOperators() { } At_form_ = new ParBilinearForm(sfes_); - auto *at_blfi = new ConvectionIntegrator(*rhou_coeff_); + auto* at_blfi = new ConvectionIntegrator(*rhou_coeff_); if (numerical_integ_) { at_blfi->SetIntRule(&ir_nli); } @@ -529,7 +531,7 @@ void CaloricallyPerfectThermoChem::initializeOperators() { // mass matrix Ms_form_ = new ParBilinearForm(sfes_); - auto *ms_blfi = new MassIntegrator; + auto* ms_blfi = new MassIntegrator; if (numerical_integ_) { ms_blfi->SetIntRule(&ir_i); } @@ -542,7 +544,7 @@ void CaloricallyPerfectThermoChem::initializeOperators() { // mass matrix with rho MsRho_form_ = new ParBilinearForm(sfes_); - auto *msrho_blfi = new MassIntegrator(*rho_coeff_); + auto* msrho_blfi = new MassIntegrator(*rho_coeff_); if (numerical_integ_) { msrho_blfi->SetIntRule(&ir_i); // msrho_blfi->SetIntRule(&ir_di); @@ -554,15 +556,15 @@ void CaloricallyPerfectThermoChem::initializeOperators() { // Helmholtz Ht_form_ = new ParBilinearForm(sfes_); - auto *hmt_blfi = new MassIntegrator(*rho_over_dt_coeff_); - auto *hdt_blfi = new DiffusionIntegrator(*thermal_diff_total_coeff_); + auto* hmt_blfi = new MassIntegrator(*rho_over_dt_coeff_); + auto* hdt_blfi = new DiffusionIntegrator(*thermal_diff_total_coeff_); if (numerical_integ_) { hmt_blfi->SetIntRule(&ir_di); hdt_blfi->SetIntRule(&ir_di); } // SUPG diffusion if (sw_stab_) { - auto *sdt_blfi = new DiffusionIntegrator(*supg_coeff_); + auto* sdt_blfi = new DiffusionIntegrator(*supg_coeff_); if (numerical_integ_) { sdt_blfi->SetIntRule(&ir_di); } @@ -580,10 +582,10 @@ void CaloricallyPerfectThermoChem::initializeOperators() { MsInvPC_ = new OperatorJacobiSmoother(diag_pa, empty); } else { MsInvPC_ = new HypreSmoother(*Ms_.As()); - dynamic_cast(MsInvPC_)->SetType(HypreSmoother::Jacobi, smoother_passes_); - dynamic_cast(MsInvPC_)->SetSOROptions(smoother_relax_weight_, smoother_relax_omega_); - dynamic_cast(MsInvPC_)->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, - smoother_eig_est_); + dynamic_cast(MsInvPC_)->SetType(HypreSmoother::Jacobi, smoother_passes_); + dynamic_cast(MsInvPC_)->SetSOROptions(smoother_relax_weight_, smoother_relax_omega_); + dynamic_cast(MsInvPC_)->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, + smoother_eig_est_); } MsInv_ = new CGSolver(sfes_->GetComm()); MsInv_->iterative_mode = false; @@ -595,10 +597,10 @@ void CaloricallyPerfectThermoChem::initializeOperators() { MsInv_->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_); - dynamic_cast(HtInvPC_)->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, - smoother_eig_est_); + dynamic_cast(HtInvPC_)->SetType(HypreSmoother::Jacobi, smoother_passes_); + dynamic_cast(HtInvPC_)->SetSOROptions(hsmoother_relax_weight_, hsmoother_relax_omega_); + dynamic_cast(HtInvPC_)->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, + smoother_eig_est_); HtInv_ = new CGSolver(sfes_->GetComm()); HtInv_->iterative_mode = true; @@ -612,7 +614,7 @@ void CaloricallyPerfectThermoChem::initializeOperators() { // Qt ..................................... Mq_form_ = new ParBilinearForm(sfes_); - auto *mq_blfi = new MassIntegrator; + auto* mq_blfi = new MassIntegrator; if (numerical_integ_) { mq_blfi->SetIntRule(&ir_i); } @@ -631,10 +633,10 @@ void CaloricallyPerfectThermoChem::initializeOperators() { MqInvPC_ = new OperatorJacobiSmoother(diag_pa, empty); } else { MqInvPC_ = new HypreSmoother(*Mq_.As()); - dynamic_cast(MqInvPC_)->SetType(HypreSmoother::Jacobi, smoother_passes_); - dynamic_cast(MqInvPC_)->SetSOROptions(smoother_relax_weight_, smoother_relax_omega_); - dynamic_cast(MqInvPC_)->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, - smoother_eig_est_); + dynamic_cast(MqInvPC_)->SetType(HypreSmoother::Jacobi, smoother_passes_); + dynamic_cast(MqInvPC_)->SetSOROptions(smoother_relax_weight_, smoother_relax_omega_); + dynamic_cast(MqInvPC_)->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, + smoother_eig_est_); } MqInv_ = new CGSolver(sfes_->GetComm()); MqInv_->iterative_mode = false; @@ -646,18 +648,18 @@ void CaloricallyPerfectThermoChem::initializeOperators() { MqInv_->SetMaxIter(mass_inverse_max_iter_); LQ_form_ = new ParBilinearForm(sfes_); - //auto *lqd_blfi = new DiffusionIntegrator(*thermal_diff_total_coeff_); - //if (axisym_) { - // auto *lqd_blfi = new DiffusionIntegrator(*rad_thermal_diff_total_coeff_); - //} else { - auto *lqd_blfi = new DiffusionIntegrator(*thermal_diff_total_coeff_); - //} + // auto *lqd_blfi = new DiffusionIntegrator(*thermal_diff_total_coeff_); + // if (axisym_) { + // auto *lqd_blfi = new DiffusionIntegrator(*rad_thermal_diff_total_coeff_); + // } else { + auto* lqd_blfi = new DiffusionIntegrator(*thermal_diff_total_coeff_); + //} if (numerical_integ_) { lqd_blfi->SetIntRule(&ir_di); } LQ_form_->AddDomainIntegrator(lqd_blfi); - // NO, this is not consistent and will degrade stability + // NO, this is not consistent and will degrade stability // if (sw_stab_) { // auto *slqd_blfi = new DiffusionIntegrator(*supg_coeff_); // if (numerical_integ_) { @@ -673,7 +675,7 @@ void CaloricallyPerfectThermoChem::initializeOperators() { LQ_form_->FormSystemMatrix(empty, LQ_); LQ_bdry_ = new ParLinearForm(sfes_); - auto *lq_bdry_lfi = new BoundaryNormalLFIntegrator(*kap_gradT_coeff_, 2, -1); + auto* lq_bdry_lfi = new BoundaryNormalLFIntegrator(*kap_gradT_coeff_, 2, -1); if (numerical_integ_) { lq_bdry_lfi->SetIntRule(&ir_di); } @@ -729,7 +731,7 @@ void CaloricallyPerfectThermoChem::step() { time_ = time_coeff_.time; // Set current time for velocity Dirichlet boundary conditions. - for (auto &temp_dbc : temp_dbcs_) { + for (auto& temp_dbc : temp_dbcs_) { temp_dbc.coeff->SetTime(time_ + dt_); } @@ -771,7 +773,7 @@ void CaloricallyPerfectThermoChem::step() { HtInv_->SetOperator(*Ht_); // Prepare for the solve - for (auto &temp_dbc : temp_dbcs_) { + for (auto& temp_dbc : temp_dbcs_) { Tn_next_gf_.ProjectBdrCoefficient(*temp_dbc.coeff, temp_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(resT_, resT_gf_); @@ -827,19 +829,19 @@ void CaloricallyPerfectThermoChem::computeExplicitTempConvectionOP(bool extrap) } } -void CaloricallyPerfectThermoChem::initializeIO(IODataOrganizer &io) { +void CaloricallyPerfectThermoChem::initializeIO(IODataOrganizer& io) { io.registerIOFamily("Temperature", "/temperature", &Tn_gf_, true, true, sfec_); io.registerIOVar("/temperature", "temperature", 0); } -void CaloricallyPerfectThermoChem::initializeViz(ParaViewDataCollection &pvdc) { +void CaloricallyPerfectThermoChem::initializeViz(ParaViewDataCollection& pvdc) { pvdc.RegisterField("temperature", &Tn_gf_); pvdc.RegisterField("density", &rn_gf_); pvdc.RegisterField("kappa", &kappa_gf_); pvdc.RegisterField("Qt", &Qt_gf_); } -void CaloricallyPerfectThermoChem::initializeStats(Averaging &average, IODataOrganizer &io, bool continuation) { +void CaloricallyPerfectThermoChem::initializeStats(Averaging& average, IODataOrganizer& io, bool continuation) { if (average.ComputeMean()) { // fields for averaging average.registerField(std::string("temperature"), &Tn_gf_, false, 0, 1); @@ -906,8 +908,8 @@ void CaloricallyPerfectThermoChem::updateThermoP() { void CaloricallyPerfectThermoChem::updateDiffusivity() { // viscosity if (!constant_viscosity_) { - double *d_visc = visc_.Write(); - const double *d_T = Tn_.Read(); + double* d_visc = visc_.Write(); + const double* d_T = Tn_.Read(); const double mu_star = mu0_; const double T_star = sutherland_T0_; const double S_star = sutherland_S0_; @@ -1003,7 +1005,7 @@ void CaloricallyPerfectThermoChem::computeSystemMass() { } /// Add a Dirichlet boundary condition to the temperature field -void CaloricallyPerfectThermoChem::AddTempDirichletBC(const double &temp, Array &attr) { +void CaloricallyPerfectThermoChem::AddTempDirichletBC(const double& temp, Array& attr) { temp_dbcs_.emplace_back(attr, new ConstantCoefficient(temp)); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -1013,7 +1015,7 @@ void CaloricallyPerfectThermoChem::AddTempDirichletBC(const double &temp, Array< } } -void CaloricallyPerfectThermoChem::AddTempDirichletBC(Coefficient *coeff, Array &attr) { +void CaloricallyPerfectThermoChem::AddTempDirichletBC(Coefficient* coeff, Array& attr) { temp_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -1043,11 +1045,11 @@ void CaloricallyPerfectThermoChem::AddTempDirichletBC(Coefficient *coeff, Array< */ } -void CaloricallyPerfectThermoChem::AddTempDirichletBC(ScalarFuncT *f, Array &attr) { +void CaloricallyPerfectThermoChem::AddTempDirichletBC(ScalarFuncT* f, Array& attr) { AddTempDirichletBC(new FunctionCoefficient(f), attr); } -void CaloricallyPerfectThermoChem::AddQtDirichletBC(Coefficient *coeff, Array &attr) { +void CaloricallyPerfectThermoChem::AddQtDirichletBC(Coefficient* coeff, Array& attr) { Qt_dbcs_.emplace_back(attr, coeff); if (rank0_ && pmesh_->GetMyRank() == 0) { @@ -1068,7 +1070,7 @@ void CaloricallyPerfectThermoChem::AddQtDirichletBC(Coefficient *coeff, Array &attr) { +void CaloricallyPerfectThermoChem::AddQtDirichletBC(ScalarFuncT* f, Array& attr) { AddQtDirichletBC(new FunctionCoefficient(f), attr); } @@ -1099,17 +1101,16 @@ void CaloricallyPerfectThermoChem::computeQtTO() { Qt_gf_.GetTrueDofs(Qt_); Qt_ *= -Rgas_ / thermo_pressure_; Qt_gf_.SetFromTrueDofs(Qt_); - } -void CaloricallyPerfectThermoChem::screenHeader(std::vector &header) const { +void CaloricallyPerfectThermoChem::screenHeader(std::vector& header) const { if (!domain_is_open_) { header.resize(1); header[0] = "P/P0"; } } -void CaloricallyPerfectThermoChem::screenValues(std::vector &values) { +void CaloricallyPerfectThermoChem::screenValues(std::vector& values) { if (!domain_is_open_) { values.resize(1); values[0] = thermo_pressure_ / ambient_pressure_; diff --git a/src/calorically_perfect.hpp b/src/calorically_perfect.hpp index c86ba853..1265d4dc 100644 --- a/src/calorically_perfect.hpp +++ b/src/calorically_perfect.hpp @@ -50,8 +50,8 @@ class Tps; #include "tps_mfem_wrap.hpp" #include "utils.hpp" -using VecFuncT = void(const Vector &x, double t, Vector &u); -using ScalarFuncT = double(const Vector &x, double t); +using VecFuncT = void(const Vector& x, double t, Vector& u); +using ScalarFuncT = double(const Vector& x, double t); class LoMachOptions; struct temporalSchemeCoefficients; @@ -62,13 +62,13 @@ struct temporalSchemeCoefficients; class CaloricallyPerfectThermoChem : public ThermoChemModelBase { private: // Options-related structures - TPS::Tps *tpsP_ = nullptr; + TPS::Tps* tpsP_ = nullptr; // Mesh and discretization scheme info - ParMesh *pmesh_ = nullptr; + ParMesh* pmesh_ = nullptr; int order_; IntegrationRules gll_rules_; - const temporalSchemeCoefficients &time_coeff_; + const temporalSchemeCoefficients& time_coeff_; double dt_; double time_; @@ -143,14 +143,14 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { // not currently implemented but we need to yell if someone tries this bool axisym_; - + // FEM related fields and objects // Scalar \f$H^1\f$ finite element collection. - FiniteElementCollection *sfec_ = nullptr; + FiniteElementCollection* sfec_ = nullptr; // Scalar \f$H^1\f$ finite element space. - ParFiniteElementSpace *sfes_ = nullptr; + ParFiniteElementSpace* sfes_ = nullptr; // Fields ParGridFunction Tnm1_gf_, Tnm2_gf_; @@ -163,46 +163,46 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { ParGridFunction R0PM0_gf_; ParGridFunction Qt_gf_; - ParGridFunction *gridScale_gf_ = nullptr; + ParGridFunction* gridScale_gf_ = nullptr; // ParGridFunction *buffer_tInlet_ = nullptr; - GridFunctionCoefficient *temperature_bc_field_ = nullptr; - - VectorGridFunctionCoefficient *un_next_coeff_ = nullptr; - GridFunctionCoefficient *rhon_next_coeff_ = nullptr; - ScalarVectorProductCoefficient *rhou_coeff_ = nullptr; - GridFunctionCoefficient *thermal_diff_coeff_ = nullptr; - GridFunctionCoefficient *mut_coeff_ = nullptr; - GridFunctionCoefficient *mult_coeff_ = nullptr; - SumCoefficient *thermal_diff_sum_coeff_ = nullptr; - ProductCoefficient *thermal_diff_total_coeff_ = nullptr; - GradientGridFunctionCoefficient *gradT_coeff_ = nullptr; - ScalarVectorProductCoefficient *kap_gradT_coeff_ = nullptr; - GridFunctionCoefficient *rho_over_dt_coeff_ = nullptr; - GridFunctionCoefficient *rho_coeff_ = nullptr; - - VectorMagnitudeCoefficient *umag_coeff_ = nullptr; - GridFunctionCoefficient *gscale_coeff_ = nullptr; - GridFunctionCoefficient *visc_coeff_ = nullptr; - PowerCoefficient *visc_inv_coeff_ = nullptr; - ProductCoefficient *reh1_coeff_ = nullptr; - ProductCoefficient *reh2_coeff_ = nullptr; - ProductCoefficient *Reh_coeff_ = nullptr; - ExtTransformedCoefficient *csupg_coeff_ = nullptr; - ProductCoefficient *uw1_coeff_ = nullptr; - ProductCoefficient *uw2_coeff_ = nullptr; - ProductCoefficient *upwind_coeff_ = nullptr; - TransformedMatrixVectorCoefficient *swdiff_coeff_ = nullptr; - ScalarMatrixProductCoefficient *supg_coeff_ = nullptr; + GridFunctionCoefficient* temperature_bc_field_ = nullptr; + + VectorGridFunctionCoefficient* un_next_coeff_ = nullptr; + GridFunctionCoefficient* rhon_next_coeff_ = nullptr; + ScalarVectorProductCoefficient* rhou_coeff_ = nullptr; + GridFunctionCoefficient* thermal_diff_coeff_ = nullptr; + GridFunctionCoefficient* mut_coeff_ = nullptr; + GridFunctionCoefficient* mult_coeff_ = nullptr; + SumCoefficient* thermal_diff_sum_coeff_ = nullptr; + ProductCoefficient* thermal_diff_total_coeff_ = nullptr; + GradientGridFunctionCoefficient* gradT_coeff_ = nullptr; + ScalarVectorProductCoefficient* kap_gradT_coeff_ = nullptr; + GridFunctionCoefficient* rho_over_dt_coeff_ = nullptr; + GridFunctionCoefficient* rho_coeff_ = nullptr; + + VectorMagnitudeCoefficient* umag_coeff_ = nullptr; + GridFunctionCoefficient* gscale_coeff_ = nullptr; + GridFunctionCoefficient* visc_coeff_ = nullptr; + PowerCoefficient* visc_inv_coeff_ = nullptr; + ProductCoefficient* reh1_coeff_ = nullptr; + ProductCoefficient* reh2_coeff_ = nullptr; + ProductCoefficient* Reh_coeff_ = nullptr; + ExtTransformedCoefficient* csupg_coeff_ = nullptr; + ProductCoefficient* uw1_coeff_ = nullptr; + ProductCoefficient* uw2_coeff_ = nullptr; + ProductCoefficient* upwind_coeff_ = nullptr; + TransformedMatrixVectorCoefficient* swdiff_coeff_ = nullptr; + ScalarMatrixProductCoefficient* supg_coeff_ = nullptr; // operators and solvers - ParBilinearForm *At_form_ = nullptr; - ParBilinearForm *Ms_form_ = nullptr; - ParBilinearForm *MsRho_form_ = nullptr; - ParBilinearForm *Ht_form_ = nullptr; - ParBilinearForm *Mq_form_ = nullptr; - ParBilinearForm *LQ_form_ = nullptr; - ParLinearForm *LQ_bdry_ = nullptr; + ParBilinearForm* At_form_ = nullptr; + ParBilinearForm* Ms_form_ = nullptr; + ParBilinearForm* MsRho_form_ = nullptr; + ParBilinearForm* Ht_form_ = nullptr; + ParBilinearForm* Mq_form_ = nullptr; + ParBilinearForm* LQ_form_ = nullptr; + ParLinearForm* LQ_bdry_ = nullptr; OperatorHandle LQ_; OperatorHandle At_; @@ -211,12 +211,12 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { OperatorHandle MsRho_; OperatorHandle Mq_; - mfem::Solver *MsInvPC_ = nullptr; - mfem::CGSolver *MsInv_ = nullptr; - mfem::Solver *MqInvPC_ = nullptr; - mfem::CGSolver *MqInv_ = nullptr; - mfem::Solver *HtInvPC_ = nullptr; - mfem::CGSolver *HtInv_ = nullptr; + mfem::Solver* MsInvPC_ = nullptr; + mfem::CGSolver* MsInv_ = nullptr; + mfem::Solver* MqInvPC_ = nullptr; + mfem::CGSolver* MqInv_ = nullptr; + mfem::Solver* HtInvPC_ = nullptr; + mfem::CGSolver* HtInv_ = nullptr; // Vectors Vector Tn_, Tn_next_, Tnm1_, Tnm2_; @@ -235,8 +235,8 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { int filter_cutoff_modes_ = 0; double filter_alpha_ = 0.0; - FiniteElementCollection *sfec_filter_ = nullptr; - ParFiniteElementSpace *sfes_filter_ = nullptr; + FiniteElementCollection* sfec_filter_ = nullptr; + ParFiniteElementSpace* sfes_filter_ = nullptr; ParGridFunction Tn_NM1_gf_; ParGridFunction Tn_filtered_gf_; @@ -256,20 +256,20 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { #endif public: - CaloricallyPerfectThermoChem(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalSchemeCoefficients &timeCoeff, - ParGridFunction *gridScale, TPS::Tps *tps); + CaloricallyPerfectThermoChem(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalSchemeCoefficients& timeCoeff, + ParGridFunction* gridScale, TPS::Tps* tps); virtual ~CaloricallyPerfectThermoChem(); // Functions overriden from base class void initializeSelf() final; void initializeOperators() final; void step() final; - void initializeIO(IODataOrganizer &io) final; - void initializeViz(ParaViewDataCollection &pvdc) final; - void initializeStats(Averaging &average, IODataOrganizer &io, bool continuation) final; + void initializeIO(IODataOrganizer& io) final; + void initializeViz(ParaViewDataCollection& pvdc) final; + void initializeStats(Averaging& average, IODataOrganizer& io, bool continuation) final; - void screenHeader(std::vector &header) const final; - void screenValues(std::vector &values) final; + void screenHeader(std::vector& header) const final; + void screenValues(std::vector& values) final; // Functions added here void updateThermoP(); @@ -283,19 +283,19 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { void computeQtTO(); /// Return a pointer to the current temperature ParGridFunction. - ParGridFunction *GetCurrentTemperature() { return &Tn_gf_; } + ParGridFunction* GetCurrentTemperature() { return &Tn_gf_; } /// Return a pointer to the current density ParGridFunction. - ParGridFunction *GetCurrentDensity() { return &rn_gf_; } + ParGridFunction* GetCurrentDensity() { return &rn_gf_; } /// Return a pointer to the current total viscosity ParGridFunction. - ParGridFunction *GetCurrentViscosity() { return &visc_gf_; } + ParGridFunction* GetCurrentViscosity() { return &visc_gf_; } /// Return a pointer to the current total thermal diffusivity ParGridFunction. - ParGridFunction *GetCurrentThermalDiffusivity() { return &kappa_gf_; } + ParGridFunction* GetCurrentThermalDiffusivity() { return &kappa_gf_; } /// Return a pointer to the current total thermal diffusivity ParGridFunction. - ParGridFunction *GetCurrentThermalDiv() { return &Qt_gf_; } + ParGridFunction* GetCurrentThermalDiv() { return &Qt_gf_; } /// Return thermodynamic pressure for restarts // double GetCurrentThermoPressure() { return thermo_pressure_; } @@ -305,10 +305,10 @@ class CaloricallyPerfectThermoChem : public ThermoChemModelBase { void UpdateTimestepHistory(double dt); /// Add a Dirichlet boundary condition to the temperature and Qt field. - void AddTempDirichletBC(const double &temp, Array &attr); - void AddTempDirichletBC(Coefficient *coeff, Array &attr); - void AddTempDirichletBC(ScalarFuncT *f, Array &attr); - void AddQtDirichletBC(Coefficient *coeff, Array &attr); - void AddQtDirichletBC(ScalarFuncT *f, Array &attr); + void AddTempDirichletBC(const double& temp, Array& attr); + void AddTempDirichletBC(Coefficient* coeff, Array& attr); + void AddTempDirichletBC(ScalarFuncT* f, Array& attr); + void AddQtDirichletBC(Coefficient* coeff, Array& attr); + void AddQtDirichletBC(ScalarFuncT* f, Array& attr); }; #endif // CALORICALLY_PERFECT_HPP_ diff --git a/src/cases.cpp b/src/cases.cpp index 7a0c80c4..51a4b90b 100644 --- a/src/cases.cpp +++ b/src/cases.cpp @@ -54,28 +54,28 @@ using namespace mfem; /// generic user-specified vel ic -void velIC_user(const Vector &x, double t, Vector &u) { +void velIC_user(const Vector& x, double t, Vector& u) { u(0) = 0.0; u(1) = 0.0; u(2) = 0.0; } /// generic user-specified vel bc -void velBC_user(const Vector &x, double t, Vector &u) { +void velBC_user(const Vector& x, double t, Vector& u) { u(0) = 0.0; u(1) = 0.0; u(2) = 0.0; } /// generic user-specified temp ic -double tempIC_user(const Vector &coords, double t) { +double tempIC_user(const Vector& coords, double t) { double temp; temp = -1.0; return temp; } /// Used to set the velocity IC (and to check error) -void vel_exact_tgv2d(const Vector &x, double t, Vector &u) { +void vel_exact_tgv2d(const Vector& x, double t, Vector& u) { const double nu = 1.0; const double F = std::exp(-2 * nu * t); @@ -85,7 +85,7 @@ void vel_exact_tgv2d(const Vector &x, double t, Vector &u) { } /// Used to set the velocity IC with TG field and uniform -void vel_tgv2d_uniform(const Vector &x, double t, Vector &u) { +void vel_tgv2d_uniform(const Vector& x, double t, Vector& u) { const double u0 = 1.0; const double F = 0.1; const double PI = 3.14159265359; @@ -100,7 +100,7 @@ void vel_tgv2d_uniform(const Vector &x, double t, Vector &u) { } /// Used to set the channel IC -void vel_channel(const Vector &x, double t, Vector &u) { +void vel_channel(const Vector& x, double t, Vector& u) { double PI = 3.14159265359; double Lx = 25.0; double Ly = 2.0; @@ -157,13 +157,13 @@ vfptr vel_ic(std::string ic_string_) { } /// Used for pipe flow test case -void vel_exact_pipe(const Vector &x, double t, Vector &u) { +void vel_exact_pipe(const Vector& x, double t, Vector& u) { u(0) = 0.0; u(1) = 2.0 * (1 - x[0] * x[0]); } /// Used for pipe with swirl -double swirl_pipe(const Vector &x, double t) { +double swirl_pipe(const Vector& x, double t) { double rt = 0.9; double R = 1.0; double u_th_max = 1.0; @@ -176,7 +176,7 @@ double swirl_pipe(const Vector &x, double t) { } /// rough tke bc for pipe flow test case -double tke_pipe(const Vector &x, double t) { +double tke_pipe(const Vector& x, double t) { // return 0.05 * std::exp(-50. * (x[0] - 0.75) * (x[0] - 0.75)); return 0.005 * std::exp(-50. * (x[0] - 0.75) * (x[0] - 0.75)); } @@ -195,7 +195,7 @@ vfptr vel_bc(std::string type) { } /// Rayleigh-Taylor ic -double temp_rt3d(const Vector &x, double t) { +double temp_rt3d(const Vector& x, double t) { double CC = 0.05; double twoPi = 6.28318530718; double yWidth = 0.1; @@ -218,7 +218,7 @@ double temp_rt3d(const Vector &x, double t) { } /// Hot/Cold wall channel -double temp_channel(const Vector &coords, double t) { +double temp_channel(const Vector& coords, double t) { double Thi = 400.0; double Tlo = 200.0; double y = coords(1); @@ -228,7 +228,7 @@ double temp_channel(const Vector &coords, double t) { } /// Bouyancy-driven cavity -double temp_lequereBox(const Vector &coords, double t) { +double temp_lequereBox(const Vector& coords, double t) { double Thi = 480.0; double Tlo = 120.0; double Tmean; diff --git a/src/cases.hpp b/src/cases.hpp index a49b911c..a6ba60aa 100644 --- a/src/cases.hpp +++ b/src/cases.hpp @@ -44,27 +44,27 @@ #include "tps_mfem_wrap.hpp" -typedef std::function vfptr; +typedef std::function vfptr; vfptr vel_ic(std::string ic_string_); vfptr vel_bc(std::string type); -typedef std::function sfptr; +typedef std::function sfptr; sfptr temp_ic(std::string ic_string_); sfptr temp_bc(std::string type); -void velIC_user(const mfem::Vector &x, double t, mfem::Vector &u); -void velBC_user(const mfem::Vector &x, double t, mfem::Vector &u); -void vel_exact_tgv2d(const mfem::Vector &x, double t, mfem::Vector &u); -void vel_tgv2d_uniform(const mfem::Vector &x, double t, mfem::Vector &u); -void vel_channel(const mfem::Vector &x, double t, mfem::Vector &u); -void vel_exact_pipe(const mfem::Vector &x, double t, mfem::Vector &u); +void velIC_user(const mfem::Vector& x, double t, mfem::Vector& u); +void velBC_user(const mfem::Vector& x, double t, mfem::Vector& u); +void vel_exact_tgv2d(const mfem::Vector& x, double t, mfem::Vector& u); +void vel_tgv2d_uniform(const mfem::Vector& x, double t, mfem::Vector& u); +void vel_channel(const mfem::Vector& x, double t, mfem::Vector& u); +void vel_exact_pipe(const mfem::Vector& x, double t, mfem::Vector& u); -double swirl_pipe(const mfem::Vector &x, double t); -double tke_pipe(const mfem::Vector &x, double t); +double swirl_pipe(const mfem::Vector& x, double t); +double tke_pipe(const mfem::Vector& x, double t); -double tempIC_user(const mfem::Vector &x, double t); -double temp_rt3d(const mfem::Vector &x, double t); -double temp_channel(const mfem::Vector &x, double t); -double temp_lequereBox(const mfem::Vector &x, double t); +double tempIC_user(const mfem::Vector& x, double t); +double temp_rt3d(const mfem::Vector& x, double t); +double temp_channel(const mfem::Vector& x, double t); +double temp_lequereBox(const mfem::Vector& x, double t); #endif // CASES_HPP_ diff --git a/src/chemistry.cpp b/src/chemistry.cpp index c21e88a5..ad94b1bb 100644 --- a/src/chemistry.cpp +++ b/src/chemistry.cpp @@ -35,9 +35,9 @@ using namespace mfem; using namespace std; -Chemistry::Chemistry(GasMixture *mixture, RunConfiguration &config) : Chemistry(mixture, config.chemistryInput) {} +Chemistry::Chemistry(GasMixture* mixture, RunConfiguration& config) : Chemistry(mixture, config.chemistryInput) {} -MFEM_HOST_DEVICE Chemistry::Chemistry(GasMixture *mixture, const ChemistryInput &inputs) : mixture_(mixture) { +MFEM_HOST_DEVICE Chemistry::Chemistry(GasMixture* mixture, const ChemistryInput& inputs) : mixture_(mixture) { numEquations_ = mixture->GetNumEquations(); numSpecies_ = mixture->GetNumSpecies(); numActiveSpecies_ = mixture->GetNumActiveSpecies(); @@ -121,19 +121,19 @@ MFEM_HOST_DEVICE Chemistry::~Chemistry() { } } -MFEM_HOST_DEVICE void Chemistry::setRates(const double *data, int size) { +MFEM_HOST_DEVICE void Chemistry::setRates(const double* data, int size) { for (int r = 0; r < numReactions_; r++) { if (reactions_[r]->reactionModel == GRIDFUNCTION_RXN) { - GridFunctionReaction *rx = (GridFunctionReaction *)(reactions_[r]); + GridFunctionReaction* rx = (GridFunctionReaction*)(reactions_[r]); rx->setData(data, size); } } } -void Chemistry::setGridFunctionRates(mfem::GridFunction &f) { +void Chemistry::setGridFunctionRates(mfem::GridFunction& f) { for (int r = 0; r < numReactions_; r++) { if (reactions_[r]->reactionModel == GRIDFUNCTION_RXN) { - GridFunctionReaction *rx = dynamic_cast(reactions_[r]); + GridFunctionReaction* rx = dynamic_cast(reactions_[r]); rx->setGridFunction(f); } } @@ -158,8 +158,8 @@ void Chemistry::computeForwardRateCoeffs(const mfem::Vector &ns, const double &T } #endif -MFEM_HOST_DEVICE void Chemistry::computeForwardRateCoeffs(const double *ns, const double &T_h, const double &T_e, - const int &dofindex, double *kfwd) { +MFEM_HOST_DEVICE void Chemistry::computeForwardRateCoeffs(const double* ns, const double& T_h, const double& T_e, + const int& dofindex, double* kfwd) { // kfwd.SetSize(numReactions_); for (int r = 0; r < numReactions_; r++) kfwd[r] = 0.0; @@ -198,7 +198,7 @@ void Chemistry::computeEquilibriumConstants(const double &T_h, const double &T_e } #endif -MFEM_HOST_DEVICE void Chemistry::computeEquilibriumConstants(const double &T_h, const double &T_e, double *kC) { +MFEM_HOST_DEVICE void Chemistry::computeEquilibriumConstants(const double& T_h, const double& T_e, double* kC) { for (int r = 0; r < numReactions_; r++) kC[r] = 0.0; const double Thlim = max(T_h, min_temperature_); @@ -217,8 +217,8 @@ MFEM_HOST_DEVICE void Chemistry::computeEquilibriumConstants(const double &T_h, } // compute progress rate based on mass-action law. -void Chemistry::computeProgressRate(const mfem::Vector &ns, const mfem::Vector &kfwd, const mfem::Vector &keq, - mfem::Vector &progressRate) { +void Chemistry::computeProgressRate(const mfem::Vector& ns, const mfem::Vector& kfwd, const mfem::Vector& keq, + mfem::Vector& progressRate) { progressRate.SetSize(numReactions_); computeProgressRate(&ns[0], &kfwd[0], &keq[0], &progressRate[0]); // for (int r = 0; r < numReactions_; r++) { @@ -235,8 +235,8 @@ void Chemistry::computeProgressRate(const mfem::Vector &ns, const mfem::Vector & // } } -MFEM_HOST_DEVICE void Chemistry::computeProgressRate(const double *ns, const double *kfwd, const double *keq, - double *progressRate) { +MFEM_HOST_DEVICE void Chemistry::computeProgressRate(const double* ns, const double* kfwd, const double* keq, + double* progressRate) { // progressRate.SetSize(numReactions_); for (int r = 0; r < numReactions_; r++) { // forward reaction rate @@ -253,8 +253,8 @@ MFEM_HOST_DEVICE void Chemistry::computeProgressRate(const double *ns, const dou } // compute creation rate based on progress rates. -void Chemistry::computeCreationRate(const mfem::Vector &progressRate, mfem::Vector &creationRate, - mfem::Vector &emissionRate) { +void Chemistry::computeCreationRate(const mfem::Vector& progressRate, mfem::Vector& creationRate, + mfem::Vector& emissionRate) { creationRate.SetSize(numSpecies_); emissionRate.SetSize(numSpecies_); computeCreationRate(&progressRate[0], &creationRate[0], &emissionRate[0]); @@ -274,8 +274,8 @@ void Chemistry::computeCreationRate(const mfem::Vector &progressRate, mfem::Vect // // assert(fabs(totMass) < 1e-7); } -MFEM_HOST_DEVICE void Chemistry::computeCreationRate(const double *progressRate, double *creationRate, - double *emissionRate) { +MFEM_HOST_DEVICE void Chemistry::computeCreationRate(const double* progressRate, double* creationRate, + double* emissionRate) { // creationRate.SetSize(numSpecies_); for (int sp = 0; sp < numSpecies_; sp++) creationRate[sp] = 0.; for (int sp = 0; sp < numSpecies_; sp++) emissionRate[sp] = 0.; diff --git a/src/chemistry.hpp b/src/chemistry.hpp index b38fe7b4..6f334dbe 100644 --- a/src/chemistry.hpp +++ b/src/chemistry.hpp @@ -66,7 +66,7 @@ class Chemistry { productStoich_[gpudata::MAXSPECIES * gpudata::MAXREACTIONS]; // std::vector reactions_; - Reaction *reactions_[gpudata::MAXREACTIONS]; + Reaction* reactions_[gpudata::MAXREACTIONS]; double reactionEnergies_[gpudata::MAXREACTIONS]; // std::map *mixtureToInputMap_; @@ -85,55 +85,55 @@ class Chemistry { // // Kevin: should we use a vector of function pointers? // Kevin: currently, I doubt we need mixture class here. but left it just in case. - GasMixture *mixture_ = NULL; + GasMixture* mixture_ = NULL; double min_temperature_; ReactionModel reactionModels_[gpudata::MAXREACTIONS]; public: - Chemistry(GasMixture *mixture, RunConfiguration &config); - MFEM_HOST_DEVICE Chemistry(GasMixture *mixture, const ChemistryInput &inputs); + Chemistry(GasMixture* mixture, RunConfiguration& config); + MFEM_HOST_DEVICE Chemistry(GasMixture* mixture, const ChemistryInput& inputs); MFEM_HOST_DEVICE ~Chemistry(); // Set the grid function rates for GRIDFUNCTION_RXN reaction types - void setGridFunctionRates(mfem::GridFunction &f); - MFEM_HOST_DEVICE void setRates(const double *data, int size); + void setGridFunctionRates(mfem::GridFunction& f); + MFEM_HOST_DEVICE void setRates(const double* data, int size); // return Vector of reaction rate coefficients, with the size of numReaction_. // WARNING(marc) I have removed "virtual" qualifier here assuming these functions will not // change for child classes. Correct if wrong - void computeForwardRateCoeffs(const Vector &ns, const double &T_h, const double &T_e, Vector &kfwd); - MFEM_HOST_DEVICE void computeForwardRateCoeffs(const double *ns, const double &T_h, const double &T_e, - const int &dofindex, double *kfwd); + void computeForwardRateCoeffs(const Vector& ns, const double& T_h, const double& T_e, Vector& kfwd); + MFEM_HOST_DEVICE void computeForwardRateCoeffs(const double* ns, const double& T_h, const double& T_e, + const int& dofindex, double* kfwd); // void computeEquilibriumConstants(const double &T_h, const double &T_e, Vector &kC); - MFEM_HOST_DEVICE void computeEquilibriumConstants(const double &T_h, const double &T_e, double *kC); + MFEM_HOST_DEVICE void computeEquilibriumConstants(const double& T_h, const double& T_e, double* kC); // return rate coefficients of (reactionIndex)-th reaction. (start from 0) // reactionIndex is taken from reactionMapping.right. // virtual Vector computeRateCoeffOf(const int reactionIndex, const double T_h, const double T_e) {}; - const double *getReactantStoichiometry(const int reactionIndex) { + const double* getReactantStoichiometry(const int reactionIndex) { return &reactantStoich_[reactionIndex * numSpecies_]; } - const double *getProductStoichiometry(const int reactionIndex) { + const double* getProductStoichiometry(const int reactionIndex) { return &productStoich_[reactionIndex * numSpecies_]; } // compute progress rate by mass-action law. - void computeProgressRate(const Vector &ns, const Vector &kfwd, const Vector &keq, Vector &progressRate); - MFEM_HOST_DEVICE void computeProgressRate(const double *ns, const double *kfwd, const double *keq, - double *progressRate); - void computeCreationRate(const Vector &progressRate, Vector &creationRate, Vector &emmisionRate); - MFEM_HOST_DEVICE void computeCreationRate(const double *progressRate, double *creationRate, double *emmisionRate); + void computeProgressRate(const Vector& ns, const Vector& kfwd, const Vector& keq, Vector& progressRate); + MFEM_HOST_DEVICE void computeProgressRate(const double* ns, const double* kfwd, const double* keq, + double* progressRate); + void computeCreationRate(const Vector& progressRate, Vector& creationRate, Vector& emmisionRate); + MFEM_HOST_DEVICE void computeCreationRate(const double* progressRate, double* creationRate, double* emmisionRate); - MFEM_HOST_DEVICE double getReactionEnergy(const int &reactionIndex) { return reactionEnergies_[reactionIndex]; } + MFEM_HOST_DEVICE double getReactionEnergy(const int& reactionIndex) { return reactionEnergies_[reactionIndex]; } int getNumReactions() { return numReactions_; } - MFEM_HOST_DEVICE bool isElectronInvolvedAt(const int &reactionIndex) { + MFEM_HOST_DEVICE bool isElectronInvolvedAt(const int& reactionIndex) { return (electronIndex_ < 0) ? false : (reactantStoich_[electronIndex_ + reactionIndex * numSpecies_] != 0); } diff --git a/src/collision_integrals.cpp b/src/collision_integrals.cpp index 83c28a4f..7cecde7b 100644 --- a/src/collision_integrals.cpp +++ b/src/collision_integrals.cpp @@ -50,67 +50,67 @@ namespace charged { laser-plasma interactions. Journal of Computational Physics, 406, 109190. https://doi.org/10.1016/j.jcp.2019.109190 */ -MFEM_HOST_DEVICE double att11(const double &Tp) { +MFEM_HOST_DEVICE double att11(const double& Tp) { return 0.2150 * pow(log(1.0 + 5.2194 * pow(Tp, 1.0472)), 1.2435) / Tp / Tp; } -MFEM_HOST_DEVICE double att12(const double &Tp) { +MFEM_HOST_DEVICE double att12(const double& Tp) { return 0.0991 * pow(log(1.0 + 7.4684 * pow(Tp, 1.0155)), 1.1536) / Tp / Tp; } -MFEM_HOST_DEVICE double att13(const double &Tp) { +MFEM_HOST_DEVICE double att13(const double& Tp) { return 0.0616 * pow(log(1.0 + 7.8271 * pow(Tp, 0.9452)), 1.1105) / Tp / Tp; } -MFEM_HOST_DEVICE double att14(const double &Tp) { +MFEM_HOST_DEVICE double att14(const double& Tp) { return 0.0308 * pow(log(1.0 + 13.9567 * pow(Tp, 0.9511)), 1.1803) / Tp / Tp; } -MFEM_HOST_DEVICE double att15(const double &Tp) { +MFEM_HOST_DEVICE double att15(const double& Tp) { return 0.0232 * pow(log(1.0 + 13.7888 * pow(Tp, 0.9148)), 1.1532) / Tp / Tp; } -MFEM_HOST_DEVICE double att22(const double &Tp) { +MFEM_HOST_DEVICE double att22(const double& Tp) { return 0.2423 * pow(log(1.0 + 4.6796 * pow(Tp, 1.3290)), 1.1279) / Tp / Tp; } -MFEM_HOST_DEVICE double att23(const double &Tp) { +MFEM_HOST_DEVICE double att23(const double& Tp) { return 0.1221 * pow(log(1.0 + 8.7542 * pow(Tp, 1.3875)), 1.1110) / Tp / Tp; } -MFEM_HOST_DEVICE double att24(const double &Tp) { +MFEM_HOST_DEVICE double att24(const double& Tp) { return 0.0619 * pow(log(1.0 + 18.2538 * pow(Tp, 1.4341)), 1.1618) / Tp / Tp; } -MFEM_HOST_DEVICE double rep11(const double &Tp) { +MFEM_HOST_DEVICE double rep11(const double& Tp) { return 0.3904 * pow(log(1.0 + 0.9100 * pow(Tp, 1.1025)), 1.0544) / Tp / Tp; } -MFEM_HOST_DEVICE double rep12(const double &Tp) { +MFEM_HOST_DEVICE double rep12(const double& Tp) { return 0.1547 * pow(log(1.0 + 1.6597 * pow(Tp, 1.1725)), 0.9792) / Tp / Tp; } -MFEM_HOST_DEVICE double rep13(const double &Tp) { +MFEM_HOST_DEVICE double rep13(const double& Tp) { return 0.0814 * pow(log(1.0 + 2.5815 * pow(Tp, 1.1948)), 0.9570) / Tp / Tp; } -MFEM_HOST_DEVICE double rep14(const double &Tp) { +MFEM_HOST_DEVICE double rep14(const double& Tp) { return 0.0683 * pow(log(1.0 + 1.9774 * pow(Tp, 1.2033)), 0.8264) / Tp / Tp; } -MFEM_HOST_DEVICE double rep15(const double &Tp) { +MFEM_HOST_DEVICE double rep15(const double& Tp) { return 0.0346 * pow(log(1.0 + 4.5177 * pow(Tp, 1.2132)), 0.9294) / Tp / Tp; } -MFEM_HOST_DEVICE double rep22(const double &Tp) { +MFEM_HOST_DEVICE double rep22(const double& Tp) { return 0.4128 * pow(log(1.0 + 1.2436 * pow(Tp, 1.1830)), 1.0123) / Tp / Tp; } -MFEM_HOST_DEVICE double rep23(const double &Tp) { +MFEM_HOST_DEVICE double rep23(const double& Tp) { return 0.2203 * pow(log(1.0 + 1.8832 * pow(Tp, 1.2059)), 0.9851) / Tp / Tp; } -MFEM_HOST_DEVICE double rep24(const double &Tp) { +MFEM_HOST_DEVICE double rep24(const double& Tp) { return 0.1323 * pow(log(1.0 + 2.7248 * pow(Tp, 1.2129)), 0.9847) / Tp / Tp; } @@ -121,13 +121,13 @@ MFEM_HOST_DEVICE double rep24(const double &Tp) { // Takes T in Kelvin, returns in unit of m^2. namespace argon { -MFEM_HOST_DEVICE double ArAr11(const double &T) { +MFEM_HOST_DEVICE double ArAr11(const double& T) { // Reference : fitted from tabulated data of Amdur, I., & Mason, E. A. (1958). Properties of gases at very high // temperatures. Physics of Fluids, 1(5), 370–383. https://doi.org/10.1063/1.1724353 return 2.2910e-18 * pow(T, -0.3032); } -MFEM_HOST_DEVICE double ArAr22(const double &T) { +MFEM_HOST_DEVICE double ArAr22(const double& T) { // Reference : Liu, W. S., Whitten, B. T., & Glass, I. I. (1978). Ionizing argon boundary layers. Part 1. Quasi-steady // flat-plate laminar boundary-layer flows. Journal of Fluid Mechanics, 87(4), 609–640. // https://doi.org/10.1017/S0022112078001792 @@ -135,7 +135,7 @@ MFEM_HOST_DEVICE double ArAr22(const double &T) { } // argon neutral (Ar) - argon positive ion (Ar1P) -MFEM_HOST_DEVICE double ArAr1P11(const double &T) { +MFEM_HOST_DEVICE double ArAr1P11(const double& T) { // Reference: fitted from tabulated data of Devoto, R. S. (1973). Transport coefficients of ionized argon. Physics of // Fluids, 16(5), 616–623. https://doi.org/10.1063/1.1694396 return 4.574321e-18 * pow(T, -0.1805); @@ -165,35 +165,35 @@ MFEM_HOST_DEVICE double logT_fit(const double logT, const double coeff[9]) { Q_{e,Ar}^(1), elastic momentum transfer cross section, is determined by a 7-parameter shifted MERT model, fitted over BSR LXCat dataset. */ -MFEM_HOST_DEVICE double eAr11(const double &T) { +MFEM_HOST_DEVICE double eAr11(const double& T) { const double logT = log(T); const double coeff[9] = {6.36254140e-18, 1.84835040e-18, -5.87727093e-18, 3.20023027e-18, -8.50509054e-19, 1.28163820e-19, -1.11712910e-20, 5.25649382e-22, -1.03296658e-23}; return logT_fit(logT, coeff); } -MFEM_HOST_DEVICE double eAr12(const double &T) { +MFEM_HOST_DEVICE double eAr12(const double& T) { const double logT = log(T); const double coeff[9] = {1.91338172e-17, 5.45418129e-18, -1.78361685e-17, 9.75657946e-18, -2.61115722e-18, 3.98310268e-19, -3.53503678e-20, 1.70375066e-21, -3.45211955e-23}; return logT_fit(logT, coeff); } -MFEM_HOST_DEVICE double eAr13(const double &T) { +MFEM_HOST_DEVICE double eAr13(const double& T) { const double logT = log(T); const double coeff[9] = {3.04685398e-17, 8.39750994e-18, -2.88132528e-17, 1.60147037e-17, -4.34837891e-18, 6.73136845e-19, -6.06704580e-20, 2.97216168e-21, -6.12760944e-23}; return logT_fit(logT, coeff); } -MFEM_HOST_DEVICE double eAr14(const double &T) { +MFEM_HOST_DEVICE double eAr14(const double& T) { const double logT = log(T); const double coeff[9] = {3.90777949e-17, 1.04696956e-17, -3.73774204e-17, 2.10610498e-17, -5.79029566e-18, 9.07573157e-19, -8.28466766e-20, 4.11188110e-21, -8.59225098e-23}; return logT_fit(logT, coeff); } -MFEM_HOST_DEVICE double eAr15(const double &T) { +MFEM_HOST_DEVICE double eAr15(const double& T) { const double logT = log(T); const double coeff[9] = {4.41333290e-17, 1.15696010e-17, -4.25651305e-17, 2.42442440e-17, -6.73359258e-18, 1.06641697e-18, -9.83933863e-20, 4.93775812e-21, -1.04362372e-22}; @@ -211,7 +211,7 @@ namespace nitrogen { // Reference : Levin et. al. (1990). "Collision Integrals and High Temperature Transport Properties for N-N, O-O, and // N-O". -MFEM_HOST_DEVICE double NiNi11(const double &T) { +MFEM_HOST_DEVICE double NiNi11(const double& T) { /* double logT = log(T); double c[5]; @@ -238,7 +238,7 @@ MFEM_HOST_DEVICE double NiNi11(const double &T) { // Reference : Levin et. al. (1990). "Collision Integrals and High Temperature Transport Properties for N-N, O-O, and // N-O". -MFEM_HOST_DEVICE double NiNi22(const double &T) { +MFEM_HOST_DEVICE double NiNi22(const double& T) { /* double logT = log(T); double c[5]; @@ -266,7 +266,7 @@ MFEM_HOST_DEVICE double NiNi22(const double &T) { // N-N+: NO DATA (using N-N) // see: su 2023 -MFEM_HOST_DEVICE double NiNi1P11(const double &T) { +MFEM_HOST_DEVICE double NiNi1P11(const double& T) { /* double logT = log(T); double c[5]; @@ -296,7 +296,7 @@ MFEM_HOST_DEVICE double NiNi1P11(const double &T) { // Reference : A. V. Phelps. (1991). "Cross Sections and Swarm Coefficients for Nitrogen Ions and Neutrals in N2 and // Argon Ions and Neutrals in Ar for Energies from 0.1 eV to 10 keV" see also: Capitelli 2000 -MFEM_HOST_DEVICE double N2N211(const double &T) { +MFEM_HOST_DEVICE double N2N211(const double& T) { /* double logT = log(T); double c[5]; @@ -324,7 +324,7 @@ MFEM_HOST_DEVICE double N2N211(const double &T) { // Reference : A. V. Phelps. (1991). "Cross Sections and Swarm Coefficients for Nitrogen Ions and Neutrals in N2 and // Argon Ions and Neutrals in Ar for Energies from 0.1 eV to 10 keV" see also: Capitelli 2000 -MFEM_HOST_DEVICE double N2N222(const double &T) { +MFEM_HOST_DEVICE double N2N222(const double& T) { /* double logT = log(T); double c[5]; @@ -352,7 +352,7 @@ MFEM_HOST_DEVICE double N2N222(const double &T) { // Reference : A. V. Phelps. (1991). "Cross Sections and Swarm Coefficients for Nitrogen Ions and Neutrals in N2 and // Argon Ions and Neutrals in Ar for Energies from 0.1 eV to 10 keV" -MFEM_HOST_DEVICE double N2N21P11(const double &T) { +MFEM_HOST_DEVICE double N2N21P11(const double& T) { double logT = log(T); double c[5]; c[0] = -96.770585022102779; @@ -366,7 +366,7 @@ MFEM_HOST_DEVICE double N2N21P11(const double &T) { // Reference : A. V. Phelps. (1991). "Cross Sections and Swarm Coefficients for Nitrogen Ions and Neutrals in N2 and // Argon Ions and Neutrals in Ar for Energies from 0.1 eV to 10 keV" -MFEM_HOST_DEVICE double N2Ni1P11(const double &T) { +MFEM_HOST_DEVICE double N2Ni1P11(const double& T) { double logT = log(T); double c[7]; c[0] = -7.070758182949830; @@ -383,7 +383,7 @@ MFEM_HOST_DEVICE double N2Ni1P11(const double &T) { // N-N2+ : NO DATA (using N2-N+) // NOTE: this one doesnt really matter as N2 is all N by the temp of N2+ -MFEM_HOST_DEVICE double NiN21P11(const double &T) { +MFEM_HOST_DEVICE double NiN21P11(const double& T) { double logT = log(T); double c[7]; c[0] = -7.070758182949830; @@ -400,7 +400,7 @@ MFEM_HOST_DEVICE double NiN21P11(const double &T) { // N2-N : NO DATA (using N2-N+) // see: su2023 -MFEM_HOST_DEVICE double N2Ni11(const double &T) { +MFEM_HOST_DEVICE double N2Ni11(const double& T) { /* double logT = log(T); double c[5]; @@ -430,7 +430,7 @@ MFEM_HOST_DEVICE double N2Ni11(const double &T) { // N2-N : NO DATA (using N-N 22) // see: su2023 -MFEM_HOST_DEVICE double N2Ni22(const double &T) { +MFEM_HOST_DEVICE double N2Ni22(const double& T) { /* double logT = log(T); double c[5]; @@ -463,7 +463,7 @@ MFEM_HOST_DEVICE double N2Ni22(const double &T) { Q_{e,N}^(1), elastic momentum transfer cross section, fitted over IAA LXCat dataset. */ -MFEM_HOST_DEVICE double eNi11(const double &T) { +MFEM_HOST_DEVICE double eNi11(const double& T) { double logT = log(T); double c[7]; c[0] = 2.583657310241357; @@ -479,7 +479,7 @@ MFEM_HOST_DEVICE double eNi11(const double &T) { return exp(expOmega); } -MFEM_HOST_DEVICE double eNi12(const double &T) { +MFEM_HOST_DEVICE double eNi12(const double& T) { double logT = log(T); double c[7]; c[0] = -1.934755833917042; @@ -495,7 +495,7 @@ MFEM_HOST_DEVICE double eNi12(const double &T) { return exp(expOmega); } -MFEM_HOST_DEVICE double eNi13(const double &T) { +MFEM_HOST_DEVICE double eNi13(const double& T) { double logT = log(T); double c[7]; c[0] = -2.837349005539165; @@ -511,7 +511,7 @@ MFEM_HOST_DEVICE double eNi13(const double &T) { return exp(expOmega); } -MFEM_HOST_DEVICE double eNi14(const double &T) { +MFEM_HOST_DEVICE double eNi14(const double& T) { double logT = log(T); double c[7]; c[0] = -1.673254218486384; @@ -527,7 +527,7 @@ MFEM_HOST_DEVICE double eNi14(const double &T) { return exp(expOmega); } -MFEM_HOST_DEVICE double eNi15(const double &T) { +MFEM_HOST_DEVICE double eNi15(const double& T) { double logT = log(T); double c[7]; c[0] = -1.245791078716272; @@ -543,7 +543,7 @@ MFEM_HOST_DEVICE double eNi15(const double &T) { return exp(expOmega); } -MFEM_HOST_DEVICE double eN211(const double &T) { +MFEM_HOST_DEVICE double eN211(const double& T) { double logT = log(T); double c[6]; c[0] = -3.847278097767338; @@ -558,7 +558,7 @@ MFEM_HOST_DEVICE double eN211(const double &T) { return exp(expOmega); } -MFEM_HOST_DEVICE double eN212(const double &T) { +MFEM_HOST_DEVICE double eN212(const double& T) { double logT = log(T); double c[6]; c[0] = -5.337534425696322; @@ -573,7 +573,7 @@ MFEM_HOST_DEVICE double eN212(const double &T) { return exp(expOmega); } -MFEM_HOST_DEVICE double eN213(const double &T) { +MFEM_HOST_DEVICE double eN213(const double& T) { double logT = log(T); double c[6]; c[0] = -6.527006679994851; @@ -588,7 +588,7 @@ MFEM_HOST_DEVICE double eN213(const double &T) { return exp(expOmega); } -MFEM_HOST_DEVICE double eN214(const double &T) { +MFEM_HOST_DEVICE double eN214(const double& T) { double logT = log(T); double c[6]; c[0] = -6.527006679994851; @@ -603,7 +603,7 @@ MFEM_HOST_DEVICE double eN214(const double &T) { return exp(expOmega); } -MFEM_HOST_DEVICE double eN215(const double &T) { +MFEM_HOST_DEVICE double eN215(const double& T) { double logT = log(T); double c[6]; c[0] = -5.131403805671025; diff --git a/src/collision_integrals.hpp b/src/collision_integrals.hpp index f8682071..31a2646b 100644 --- a/src/collision_integrals.hpp +++ b/src/collision_integrals.hpp @@ -56,25 +56,25 @@ namespace charged { laser-plasma interactions. Journal of Computational Physics, 406, 109190. https://doi.org/10.1016/j.jcp.2019.109190 */ -MFEM_HOST_DEVICE double att11(const double &Tp); -MFEM_HOST_DEVICE double att12(const double &Tp); -MFEM_HOST_DEVICE double att13(const double &Tp); -MFEM_HOST_DEVICE double att14(const double &Tp); -MFEM_HOST_DEVICE double att15(const double &Tp); - -MFEM_HOST_DEVICE double att22(const double &Tp); -MFEM_HOST_DEVICE double att23(const double &Tp); -MFEM_HOST_DEVICE double att24(const double &Tp); - -MFEM_HOST_DEVICE double rep11(const double &Tp); -MFEM_HOST_DEVICE double rep12(const double &Tp); -MFEM_HOST_DEVICE double rep13(const double &Tp); -MFEM_HOST_DEVICE double rep14(const double &Tp); -MFEM_HOST_DEVICE double rep15(const double &Tp); - -MFEM_HOST_DEVICE double rep22(const double &Tp); -MFEM_HOST_DEVICE double rep23(const double &Tp); -MFEM_HOST_DEVICE double rep24(const double &Tp); +MFEM_HOST_DEVICE double att11(const double& Tp); +MFEM_HOST_DEVICE double att12(const double& Tp); +MFEM_HOST_DEVICE double att13(const double& Tp); +MFEM_HOST_DEVICE double att14(const double& Tp); +MFEM_HOST_DEVICE double att15(const double& Tp); + +MFEM_HOST_DEVICE double att22(const double& Tp); +MFEM_HOST_DEVICE double att23(const double& Tp); +MFEM_HOST_DEVICE double att24(const double& Tp); + +MFEM_HOST_DEVICE double rep11(const double& Tp); +MFEM_HOST_DEVICE double rep12(const double& Tp); +MFEM_HOST_DEVICE double rep13(const double& Tp); +MFEM_HOST_DEVICE double rep14(const double& Tp); +MFEM_HOST_DEVICE double rep15(const double& Tp); + +MFEM_HOST_DEVICE double rep22(const double& Tp); +MFEM_HOST_DEVICE double rep23(const double& Tp); +MFEM_HOST_DEVICE double rep24(const double& Tp); } // namespace charged @@ -83,23 +83,23 @@ MFEM_HOST_DEVICE double rep24(const double &Tp); // Takes T in Kelvin, returns in unit of m^2. namespace argon { -MFEM_HOST_DEVICE double ArAr11(const double &T); +MFEM_HOST_DEVICE double ArAr11(const double& T); -MFEM_HOST_DEVICE double ArAr22(const double &T); +MFEM_HOST_DEVICE double ArAr22(const double& T); // argon neutral (Ar) - argon positive ion (Ar1P) -MFEM_HOST_DEVICE double ArAr1P11(const double &T); +MFEM_HOST_DEVICE double ArAr1P11(const double& T); /* e-Ar (l,r) are fitted over numerical quadrature of definitions. Q_{e,Ar}^(1), elastic momentum transfer cross section, is determined by a 7-parameter shifted MERT model, fitted over BSR LXCat dataset. */ -MFEM_HOST_DEVICE double eAr11(const double &T); -MFEM_HOST_DEVICE double eAr12(const double &T); -MFEM_HOST_DEVICE double eAr13(const double &T); -MFEM_HOST_DEVICE double eAr14(const double &T); -MFEM_HOST_DEVICE double eAr15(const double &T); +MFEM_HOST_DEVICE double eAr11(const double& T); +MFEM_HOST_DEVICE double eAr12(const double& T); +MFEM_HOST_DEVICE double eAr13(const double& T); +MFEM_HOST_DEVICE double eAr14(const double& T); +MFEM_HOST_DEVICE double eAr15(const double& T); } // namespace argon @@ -109,37 +109,37 @@ MFEM_HOST_DEVICE double eAr15(const double &T); namespace nitrogen { // atmoic nitrogen neutral (Ar) - atomic nitrogen positive ion (Ni1P) -MFEM_HOST_DEVICE double NiNi1P11(const double &T); -MFEM_HOST_DEVICE double NiNi11(const double &T); -MFEM_HOST_DEVICE double NiNi22(const double &T); +MFEM_HOST_DEVICE double NiNi1P11(const double& T); +MFEM_HOST_DEVICE double NiNi11(const double& T); +MFEM_HOST_DEVICE double NiNi22(const double& T); // molecular nitrogen neutral (N2) - molecular nitrogen positive ion (N21P) -MFEM_HOST_DEVICE double N2N21P11(const double &T); -MFEM_HOST_DEVICE double N2N211(const double &T); -MFEM_HOST_DEVICE double N2N222(const double &T); +MFEM_HOST_DEVICE double N2N21P11(const double& T); +MFEM_HOST_DEVICE double N2N211(const double& T); +MFEM_HOST_DEVICE double N2N222(const double& T); // mixed -MFEM_HOST_DEVICE double N2Ni11(const double &T); -MFEM_HOST_DEVICE double N2Ni22(const double &T); -MFEM_HOST_DEVICE double N2Ni1P11(const double &T); -MFEM_HOST_DEVICE double NiN21P11(const double &T); +MFEM_HOST_DEVICE double N2Ni11(const double& T); +MFEM_HOST_DEVICE double N2Ni22(const double& T); +MFEM_HOST_DEVICE double N2Ni1P11(const double& T); +MFEM_HOST_DEVICE double NiN21P11(const double& T); /* e-Ar (l,r) are fitted over numerical quadrature of definitions. Q_{e,Ar}^(1), elastic momentum transfer cross section, is determined by a 7-parameter shifted MERT model, fitted over BSR LXCat dataset. */ -MFEM_HOST_DEVICE double eNi11(const double &T); -MFEM_HOST_DEVICE double eNi12(const double &T); -MFEM_HOST_DEVICE double eNi13(const double &T); -MFEM_HOST_DEVICE double eNi14(const double &T); -MFEM_HOST_DEVICE double eNi15(const double &T); - -MFEM_HOST_DEVICE double eN211(const double &T); -MFEM_HOST_DEVICE double eN212(const double &T); -MFEM_HOST_DEVICE double eN213(const double &T); -MFEM_HOST_DEVICE double eN214(const double &T); -MFEM_HOST_DEVICE double eN215(const double &T); +MFEM_HOST_DEVICE double eNi11(const double& T); +MFEM_HOST_DEVICE double eNi12(const double& T); +MFEM_HOST_DEVICE double eNi13(const double& T); +MFEM_HOST_DEVICE double eNi14(const double& T); +MFEM_HOST_DEVICE double eNi15(const double& T); + +MFEM_HOST_DEVICE double eN211(const double& T); +MFEM_HOST_DEVICE double eN212(const double& T); +MFEM_HOST_DEVICE double eN213(const double& T); +MFEM_HOST_DEVICE double eN214(const double& T); +MFEM_HOST_DEVICE double eN215(const double& T); } // namespace nitrogen diff --git a/src/cycle_avg_joule_coupling.cpp b/src/cycle_avg_joule_coupling.cpp index 7e1bcc64..530ec0db 100644 --- a/src/cycle_avg_joule_coupling.cpp +++ b/src/cycle_avg_joule_coupling.cpp @@ -36,7 +36,7 @@ #include "loMach.hpp" #include "quasimagnetostatic.hpp" -CycleAvgJouleCoupling::CycleAvgJouleCoupling(string &inputFileName, TPS::Tps *tps) +CycleAvgJouleCoupling::CycleAvgJouleCoupling(string& inputFileName, TPS::Tps* tps) : em_opt_(), qmsa_solver_(nullptr), flow_solver_(nullptr), @@ -90,7 +90,7 @@ CycleAvgJouleCoupling::CycleAvgJouleCoupling(string &inputFileName, TPS::Tps *tp #endif } -CycleAvgJouleCoupling::CycleAvgJouleCoupling(string &inputFileName, TPS::Tps *tps, int max_out, bool axisym, +CycleAvgJouleCoupling::CycleAvgJouleCoupling(string& inputFileName, TPS::Tps* tps, int max_out, bool axisym, double input_power, double initial_input_power) : em_opt_(), qmsa_solver_(nullptr), @@ -145,8 +145,8 @@ void CycleAvgJouleCoupling::initializeInterpolationData() { if (verbose) grvy_printf(ginfo, "Initializing interpolation data.\n"); #ifdef HAVE_GSLIB - ParMesh *flow_mesh = flow_solver_->getMesh(); - ParMesh *em_mesh = qmsa_solver_->getMesh(); + ParMesh* flow_mesh = flow_solver_->getMesh(); + ParMesh* em_mesh = qmsa_solver_->getMesh(); assert(flow_mesh != NULL); assert(em_mesh != NULL); @@ -163,14 +163,14 @@ void CycleAvgJouleCoupling::initializeInterpolationData() { interp_em_to_flow_->SetDefaultInterpolationValue(0); // Determine numbers of points to interpolate to - const ParFiniteElementSpace *em_fespace = qmsa_solver_->getFESpace(); + const ParFiniteElementSpace* em_fespace = qmsa_solver_->getFESpace(); n_em_interp_nodes_ = 0; for (int i = 0; i < em_mesh->GetNE(); i++) { n_em_interp_nodes_ += em_fespace->GetFE(i)->GetNodes().GetNPoints(); } // Determine numbers of points to interpolate to - const ParFiniteElementSpace *flow_fespace = flow_solver_->getFESpace(); + const ParFiniteElementSpace* flow_fespace = flow_solver_->getFESpace(); n_flow_interp_nodes_ = 0; for (int i = 0; i < flow_mesh->GetNE(); i++) { n_flow_interp_nodes_ += flow_fespace->GetFE(i)->GetNodes().GetNPoints(); @@ -187,8 +187,8 @@ void CycleAvgJouleCoupling::interpConductivityFromFlowToEM() { if (verbose) grvy_printf(ginfo, "Interpolating conductivity to EM mesh.\n"); #ifdef HAVE_GSLIB - const ParMesh *em_mesh = qmsa_solver_->getMesh(); - const ParFiniteElementSpace *em_fespace = qmsa_solver_->getFESpace(); + const ParMesh* em_mesh = qmsa_solver_->getMesh(); + const ParFiniteElementSpace* em_fespace = qmsa_solver_->getFESpace(); const int NE = em_mesh->GetNE(); const int dim = em_mesh->Dimension(); @@ -200,9 +200,9 @@ void CycleAvgJouleCoupling::interpConductivityFromFlowToEM() { int n0 = 0; // running total of starting index for (int i = 0; i < NE; i++) { - const FiniteElement *fe = em_fespace->GetFE(i); + const FiniteElement* fe = em_fespace->GetFE(i); const IntegrationRule ir = fe->GetNodes(); - ElementTransformation *et = em_fespace->GetElementTransformation(i); + ElementTransformation* et = em_fespace->GetElementTransformation(i); const int nsp = ir.GetNPoints(); @@ -226,11 +226,11 @@ void CycleAvgJouleCoupling::interpConductivityFromFlowToEM() { // Interpolate Vector conductivity_em(n_em_interp_nodes_); - const ParGridFunction *conductivity_flow_gf = flow_solver_->getPlasmaConductivityGF(); + const ParGridFunction* conductivity_flow_gf = flow_solver_->getPlasmaConductivityGF(); interp_flow_to_em_->Interpolate(vxyz, *conductivity_flow_gf, conductivity_em); // Set grid function - ParGridFunction *conductivity_em_gf = qmsa_solver_->getPlasmaConductivityGF(); + ParGridFunction* conductivity_em_gf = qmsa_solver_->getPlasmaConductivityGF(); Array vdofs; Vector elem_dof_vals; @@ -255,16 +255,16 @@ void CycleAvgJouleCoupling::interpConductivityFromFlowToEM() { #endif } -void CycleAvgJouleCoupling::interpolationPoints(Vector &vxyz, int n_interp_nodes, const ParFiniteElementSpace *fes) { - const ParMesh *mesh = fes->GetParMesh(); +void CycleAvgJouleCoupling::interpolationPoints(Vector& vxyz, int n_interp_nodes, const ParFiniteElementSpace* fes) { + const ParMesh* mesh = fes->GetParMesh(); const int NE = mesh->GetNE(); const int dim = mesh->Dimension(); vxyz.SetSize(n_interp_nodes * dim); int n0 = 0; for (int i = 0; i < NE; i++) { - const FiniteElement *fe = fes->GetFE(i); + const FiniteElement* fe = fes->GetFE(i); const IntegrationRule ir = fe->GetNodes(); - ElementTransformation *et = fes->GetElementTransformation(i); + ElementTransformation* et = fes->GetElementTransformation(i); const int nsp = ir.GetNPoints(); @@ -292,7 +292,7 @@ void CycleAvgJouleCoupling::interpJouleHeatingFromEMToFlow() { if (verbose) grvy_printf(ginfo, "Interpolating Joule heating to flow mesh.\n"); #ifdef HAVE_GSLIB - const ParFiniteElementSpace *flow_fespace = flow_solver_->getFESpace(); + const ParFiniteElementSpace* flow_fespace = flow_solver_->getFESpace(); // Generate list of points where the grid function will be evaluated. Vector vxyz; @@ -301,12 +301,12 @@ void CycleAvgJouleCoupling::interpJouleHeatingFromEMToFlow() { // Evaluate source grid function. Vector interp_vals(n_flow_interp_nodes_); - const ParGridFunction *joule_heating_gf = qmsa_solver_->getJouleHeatingGF(); + const ParGridFunction* joule_heating_gf = qmsa_solver_->getJouleHeatingGF(); assert(joule_heating_gf != NULL); interp_em_to_flow_->Interpolate(vxyz, *joule_heating_gf, interp_vals); - ParGridFunction *joule_heating_flow = flow_solver_->getJouleHeatingGF(); + ParGridFunction* joule_heating_flow = flow_solver_->getJouleHeatingGF(); if (flow_fespace->IsDGSpace()) { joule_heating_flow->SetFromTrueDofs(interp_vals); } else { @@ -346,10 +346,10 @@ void CycleAvgJouleCoupling::interpElectricFieldFromEMToFlow() { // Evaluate source grid function. Vector interp_vals(n_flow_interp_nodes_ * efield_ncomp_); - const ParGridFunction *efield_real_gf = qmsa_solver_->getElectricFieldreal(); + const ParGridFunction* efield_real_gf = qmsa_solver_->getElectricFieldreal(); interp_em_to_flow_->Interpolate(vxyz, *efield_real_gf, interp_vals); - const ParFiniteElementSpace *flow_fespace = flow_solver_->getFESpace(); + const ParFiniteElementSpace* flow_fespace = flow_solver_->getFESpace(); if (flow_fespace->IsDGSpace()) { efieldR_->SetFromTrueDofs(interp_vals); } else { @@ -357,7 +357,7 @@ void CycleAvgJouleCoupling::interpElectricFieldFromEMToFlow() { } efieldR_->HostRead(); - const ParGridFunction *efield_imag_gf = qmsa_solver_->getElectricFieldimag(); + const ParGridFunction* efield_imag_gf = qmsa_solver_->getElectricFieldimag(); interp_em_to_flow_->Interpolate(vxyz, *efield_imag_gf, interp_vals); if (flow_fespace->IsDGSpace()) { efieldI_->SetFromTrueDofs(interp_vals); @@ -523,7 +523,7 @@ void CycleAvgJouleCoupling::solveEnd() { } /// Push solver variables to interface -void CycleAvgJouleCoupling::initInterface(TPS::Tps2Boltzmann &interface) { +void CycleAvgJouleCoupling::initInterface(TPS::Tps2Boltzmann& interface) { assert(!interface.IsInitialized()); interface.init(flow_solver_); qmsa_solver_->setStoreE(true); @@ -546,10 +546,10 @@ void CycleAvgJouleCoupling::initInterface(TPS::Tps2Boltzmann &interface) { } /// Push solver variables to interface -void CycleAvgJouleCoupling::push(TPS::Tps2Boltzmann &interface) { +void CycleAvgJouleCoupling::push(TPS::Tps2Boltzmann& interface) { flow_solver_->push(interface); interface.interpolateFromNativeFES(*efield_, TPS::Tps2Boltzmann::Index::ElectricField); } /// Fetch solver variables from interface -void CycleAvgJouleCoupling::fetch(TPS::Tps2Boltzmann &interface) { flow_solver_->fetch(interface); } +void CycleAvgJouleCoupling::fetch(TPS::Tps2Boltzmann& interface) { flow_solver_->fetch(interface); } diff --git a/src/cycle_avg_joule_coupling.hpp b/src/cycle_avg_joule_coupling.hpp index beea1a6c..0c611658 100644 --- a/src/cycle_avg_joule_coupling.hpp +++ b/src/cycle_avg_joule_coupling.hpp @@ -49,17 +49,17 @@ class Tps; class CycleAvgJouleCoupling : public TPS::Solver { private: ElectromagneticOptions em_opt_; - QuasiMagnetostaticSolverBase *qmsa_solver_; - TPS::PlasmaSolver *flow_solver_; + QuasiMagnetostaticSolverBase* qmsa_solver_; + TPS::PlasmaSolver* flow_solver_; // Only needed for Boltzmann interface int efield_ncomp_; - const mfem::FiniteElementCollection *efieldFEC_; - mfem::ParFiniteElementSpace *efieldFES_; - mfem::ParFiniteElementSpace *efieldFES1_; - mfem::ParGridFunction *efield_; - mfem::ParGridFunction *efieldR_; - mfem::ParGridFunction *efieldI_; + const mfem::FiniteElementCollection* efieldFEC_; + mfem::ParFiniteElementSpace* efieldFES_; + mfem::ParFiniteElementSpace* efieldFES1_; + mfem::ParGridFunction* efield_; + mfem::ParGridFunction* efieldR_; + mfem::ParGridFunction* efieldI_; //! Maximum number of iterations int max_iters_; @@ -73,8 +73,8 @@ class CycleAvgJouleCoupling : public TPS::Solver { bool fixed_conductivity_; #ifdef HAVE_GSLIB - FindPointsGSLIB *interp_flow_to_em_; - FindPointsGSLIB *interp_em_to_flow_; + FindPointsGSLIB* interp_flow_to_em_; + FindPointsGSLIB* interp_em_to_flow_; #endif int n_em_interp_nodes_; @@ -101,14 +101,14 @@ class CycleAvgJouleCoupling : public TPS::Solver { * input-power = target power of em field [double, default = -1.] * initial-input-power = the starting power of em field [double, default = -1.] */ - CycleAvgJouleCoupling(string &inputFileName, TPS::Tps *tps); + CycleAvgJouleCoupling(string& inputFileName, TPS::Tps* tps); [[deprecated("Use CycleAvgJouleCoupling(string &inputFileName, TPS::Tps *tps instead")]] CycleAvgJouleCoupling( - string &inputFileName, TPS::Tps *tps, int max_out, bool axisym, double input_power = -1., + string& inputFileName, TPS::Tps* tps, int max_out, bool axisym, double input_power = -1., double initial_input_power = -1.); ~CycleAvgJouleCoupling(); void initializeInterpolationData(); - void interpolationPoints(mfem::Vector &vxyz, int n_interp_nodes, const mfem::ParFiniteElementSpace *fes); + void interpolationPoints(mfem::Vector& vxyz, int n_interp_nodes, const mfem::ParFiniteElementSpace* fes); void interpConductivityFromFlowToEM(); void interpJouleHeatingFromEMToFlow(); void interpElectricFieldFromEMToFlow(); @@ -122,13 +122,13 @@ class CycleAvgJouleCoupling : public TPS::Solver { void solveEnd() override; /// Push solver variables to interface - void initInterface(TPS::Tps2Boltzmann &interface) override; + void initInterface(TPS::Tps2Boltzmann& interface) override; /// Push solver variables to interface - void push(TPS::Tps2Boltzmann &interface) override; + void push(TPS::Tps2Boltzmann& interface) override; /// Fetch solver variables from interface - void fetch(TPS::Tps2Boltzmann &interface) override; + void fetch(TPS::Tps2Boltzmann& interface) override; - TPS::PlasmaSolver *getFlowSolver() { return flow_solver_; } - QuasiMagnetostaticSolverBase *getEMSolver() { return qmsa_solver_; } + TPS::PlasmaSolver* getFlowSolver() { return flow_solver_; } + QuasiMagnetostaticSolverBase* getEMSolver() { return qmsa_solver_; } }; #endif // CYCLE_AVG_JOULE_COUPLING_HPP_ diff --git a/src/dataStructures.hpp b/src/dataStructures.hpp index a555c1fe..61990b31 100644 --- a/src/dataStructures.hpp +++ b/src/dataStructures.hpp @@ -512,8 +512,8 @@ struct dataTransferArrays { // MPI communicators data int num_face_nbrs; - MPI_Request *requests; - MPI_Status *statuses; + MPI_Request* requests; + MPI_Status* statuses; }; // structure to encapsulate passive scalar data @@ -582,7 +582,7 @@ struct BoundaryViscousFluxData { // NOTE(kevin): while auto-generated operator= works in the same way, // the function is still defined to be safe. - MFEM_HOST_DEVICE BoundaryViscousFluxData &operator=(const BoundaryViscousFluxData &rhs) { + MFEM_HOST_DEVICE BoundaryViscousFluxData& operator=(const BoundaryViscousFluxData& rhs) { for (int eq = 0; eq < gpudata::MAXEQUATIONS; eq++) { primFlux[eq] = rhs.primFlux[eq]; primFluxIdxs[eq] = rhs.primFluxIdxs[eq]; @@ -596,7 +596,7 @@ struct BoundaryPrimitiveData { double prim[gpudata::MAXEQUATIONS]; bool primIdxs[gpudata::MAXEQUATIONS]; - MFEM_HOST_DEVICE BoundaryPrimitiveData &operator=(const BoundaryPrimitiveData &rhs) { + MFEM_HOST_DEVICE BoundaryPrimitiveData& operator=(const BoundaryPrimitiveData& rhs) { for (int eq = 0; eq < gpudata::MAXEQUATIONS; eq++) { prim[eq] = rhs.prim[eq]; primIdxs[eq] = rhs.primIdxs[eq]; @@ -667,8 +667,8 @@ struct GasTransportInput { struct TableInput { int Ndata; - const double *xdata; - const double *fdata; + const double* xdata; + const double* fdata; bool xLogScale; bool fLogScale; @@ -681,7 +681,7 @@ struct TableInput { struct ReactionInput { TableInput tableInput; // NOTE(kevin): with gpu, this pointer is only valid on the device. - const double *modelParams; + const double* modelParams; int indexInput; }; diff --git a/src/dgNonlinearForm.cpp b/src/dgNonlinearForm.cpp index a291bcdd..4156c48e 100644 --- a/src/dgNonlinearForm.cpp +++ b/src/dgNonlinearForm.cpp @@ -35,11 +35,11 @@ #include "riemann_solver.hpp" -DGNonLinearForm::DGNonLinearForm(RiemannSolverTPS *rsolver, Fluxes *_flux, ParFiniteElementSpace *_vfes, - ParFiniteElementSpace *_gradFes, ParGridFunction *_gradUp, BCintegrator *_bcIntegrator, - IntegrationRules *_intRules, const int _dim, const int _num_equation, - GasMixture *_mixture, const precomputedIntegrationData &gpu_precomputed_data, - const int &_maxIntPoints, const int &_maxDofs) +DGNonLinearForm::DGNonLinearForm(RiemannSolverTPS* rsolver, Fluxes* _flux, ParFiniteElementSpace* _vfes, + ParFiniteElementSpace* _gradFes, ParGridFunction* _gradUp, BCintegrator* _bcIntegrator, + IntegrationRules* _intRules, const int _dim, const int _num_equation, + GasMixture* _mixture, const precomputedIntegrationData& gpu_precomputed_data, + const int& _maxIntPoints, const int& _maxDofs) : ParNonlinearForm(_vfes), rsolver_(rsolver), fluxes(_flux), @@ -74,7 +74,7 @@ DGNonLinearForm::DGNonLinearForm(RiemannSolverTPS *rsolver, Fluxes *_flux, ParFi face_flux_ = 0.; } -void DGNonLinearForm::setParallelData(dataTransferArrays *_transferU, dataTransferArrays *_transferGradUp) { +void DGNonLinearForm::setParallelData(dataTransferArrays* _transferU, dataTransferArrays* _transferGradUp) { transferU = _transferU; transferGradUp = _transferGradUp; @@ -87,8 +87,8 @@ void DGNonLinearForm::setParallelData(dataTransferArrays *_transferU, dataTransf } #ifdef _GPU_ -void DGNonLinearForm::Mult_domain(const Vector &x, Vector &y) { - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; +void DGNonLinearForm::Mult_domain(const Vector& x, Vector& y) { + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto h_num_elems_of_type = elem_data.num_elems_of_type.HostRead(); auto h_elem_dof_num = elem_data.dof_number.HostRead(); @@ -119,8 +119,8 @@ void DGNonLinearForm::Mult_domain(const Vector &x, Vector &y) { if (bfnfi.Size()) bcIntegrator->integrateBCs(y, x, elem_data); } -void DGNonLinearForm::Mult_bdr(const Vector &x, Vector &y) { - ParMesh *pmesh = vfes->GetParMesh(); +void DGNonLinearForm::Mult_bdr(const Vector& x, Vector& y) { + ParMesh* pmesh = vfes->GetParMesh(); const int Nshared = pmesh->GetNSharedFaces(); if (Nshared > 0) { sharedFaceInterpolation_gpu(x); @@ -128,23 +128,23 @@ void DGNonLinearForm::Mult_bdr(const Vector &x, Vector &y) { } } -void DGNonLinearForm::setToZero_gpu(Vector &x, const int size) { - double *d_x = x.Write(); +void DGNonLinearForm::setToZero_gpu(Vector& x, const int size) { + double* d_x = x.Write(); MFEM_FORALL(i, size, { d_x[i] = 0.; }); } -void DGNonLinearForm::faceIntegration_gpu(Vector &y, int elType, int elemOffset, int elDof) { - double *d_y = y.ReadWrite(); - const double *d_f = face_flux_.Read(); +void DGNonLinearForm::faceIntegration_gpu(Vector& y, int elType, int elemOffset, int elDof) { + double* d_y = y.ReadWrite(); + const double* d_f = face_flux_.Read(); - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto h_num_elems_of_type = elem_data.num_elems_of_type.HostRead(); auto d_elem_dofs_list = elem_data.dofs_list.Read(); auto d_elem_dof_off = elem_data.dof_offset.Read(); - const interiorFaceIntegrationData &face_data = gpu_precomputed_data_.interior_face_data; + const interiorFaceIntegrationData& face_data = gpu_precomputed_data_.interior_face_data; auto d_element_to_faces = face_data.element_to_faces.Read(); auto d_shape1 = face_data.el1_shape.Read(); auto d_weight = face_data.quad_weight.Read(); @@ -231,13 +231,13 @@ void DGNonLinearForm::faceIntegration_gpu(Vector &y, int elType, int elemOffset, } void DGNonLinearForm::evalFaceFlux_gpu() { - double *d_f = face_flux_.Write(); - const double *d_uk_el1 = uk_el1.Read(); - const double *d_uk_el2 = uk_el2.Read(); - const double *d_grad_uk_el1 = grad_upk_el1.Read(); - const double *d_grad_uk_el2 = grad_upk_el2.Read(); + double* d_f = face_flux_.Write(); + const double* d_uk_el1 = uk_el1.Read(); + const double* d_uk_el2 = uk_el2.Read(); + const double* d_grad_uk_el1 = grad_upk_el1.Read(); + const double* d_grad_uk_el2 = grad_upk_el2.Read(); - const interiorFaceIntegrationData &face_data = gpu_precomputed_data_.interior_face_data; + const interiorFaceIntegrationData& face_data = gpu_precomputed_data_.interior_face_data; auto d_normal = face_data.normal.Read(); auto d_face_nqp = face_data.num_quad.Read(); @@ -247,15 +247,15 @@ void DGNonLinearForm::evalFaceFlux_gpu() { auto d_dist1 = face_data.dist1.Read(); auto d_dist2 = face_data.dist2.Read(); - Mesh *mesh = fes->GetMesh(); + Mesh* mesh = fes->GetMesh(); const int Nf = mesh->GetNumFaces(); const int dim = dim_; const int num_equation = num_equation_; const int maxIntPoints = maxIntPoints_; - const RiemannSolverTPS *d_rsolver = rsolver_; - Fluxes *d_flux = fluxes; + const RiemannSolverTPS* d_rsolver = rsolver_; + Fluxes* d_flux = fluxes; // clang-format off MFEM_FORALL(iface, Nf, @@ -346,26 +346,26 @@ void DGNonLinearForm::evalFaceFlux_gpu() { // clang-format on } -void DGNonLinearForm::interpFaceData_gpu(const Vector &x, int elType, int elemOffset, int elDof) { - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; - const interiorFaceIntegrationData &face_data = gpu_precomputed_data_.interior_face_data; +void DGNonLinearForm::interpFaceData_gpu(const Vector& x, int elType, int elemOffset, int elDof) { + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; + const interiorFaceIntegrationData& face_data = gpu_precomputed_data_.interior_face_data; auto h_num_elems_of_type = elem_data.num_elems_of_type.HostRead(); auto d_x = x.Read(); - double *d_uk_el1 = uk_el1.Write(); - double *d_uk_el2 = uk_el2.Write(); - double *d_grad_uk_el1 = grad_upk_el1.Write(); - double *d_grad_uk_el2 = grad_upk_el2.Write(); + double* d_uk_el1 = uk_el1.Write(); + double* d_uk_el2 = uk_el2.Write(); + double* d_grad_uk_el1 = grad_upk_el1.Write(); + double* d_grad_uk_el2 = grad_upk_el2.Write(); - const ParGridFunction *gradUp = gradUp_; + const ParGridFunction* gradUp = gradUp_; - const double *d_gradUp = gradUp->Read(); + const double* d_gradUp = gradUp->Read(); auto d_element_to_faces = face_data.element_to_faces.Read(); auto d_elem_dofs_list = elem_data.dofs_list.Read(); auto d_elem_dof_off = elem_data.dof_offset.Read(); auto d_shape1 = face_data.el1_shape.Read(); - const double *d_shape2 = face_data.el2_shape.Read(); + const double* d_shape2 = face_data.el2_shape.Read(); auto d_face_el1 = face_data.el1.Read(); auto d_face_nqp = face_data.num_quad.Read(); @@ -376,7 +376,7 @@ void DGNonLinearForm::interpFaceData_gpu(const Vector &x, int elType, int elemOf const int maxIntPoints = maxIntPoints_; const int maxDofs = maxDofs_; - Fluxes *d_fluxes = fluxes; + Fluxes* d_fluxes = fluxes; // clang-format off MFEM_FORALL_2D(el, NumElemsType, maxIntPoints, 1, 1, @@ -571,27 +571,27 @@ void DGNonLinearForm::sharedFaceIntegration_gpu(Vector &y) { } // clang-format on -void DGNonLinearForm::sharedFaceInterpolation_gpu(const Vector &x) { - const double *d_x = x.Read(); - const double *d_gradUp = gradUp_->Read(); - const double *d_faceGradUp = transferGradUp->face_nbr_data.Read(); - const double *d_faceData = transferU->face_nbr_data.Read(); +void DGNonLinearForm::sharedFaceInterpolation_gpu(const Vector& x) { + const double* d_x = x.Read(); + const double* d_gradUp = gradUp_->Read(); + const double* d_faceGradUp = transferGradUp->face_nbr_data.Read(); + const double* d_faceData = transferU->face_nbr_data.Read(); - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto d_elem_dofs_list = elem_data.dofs_list.Read(); auto d_elem_dof_off = elem_data.dof_offset.Read(); auto d_elem_dof_num = elem_data.dof_number.Read(); - const sharedFaceIntegrationData &shared_face_data = gpu_precomputed_data_.shared_face_data; - const double *d_normal = shared_face_data.normal.Read(); - const double *d_xyz = shared_face_data.xyz.Read(); - const double *d_shape1 = shared_face_data.el1_shape.Read(); - const double *d_shape2 = shared_face_data.el2_shape.Read(); - const int *d_face_num_quad = shared_face_data.num_quad.Read(); - const int *d_face_num_dof2 = shared_face_data.num_dof2.Read(); - const int *d_elem2_dofs = shared_face_data.elem2_dofs.Read(); - const int *d_elem2_grad_dofs = shared_face_data.elem2_grad_dofs.Read(); - const int *d_shared_elements_to_shared_faces = shared_face_data.shared_elements_to_shared_faces.Read(); + const sharedFaceIntegrationData& shared_face_data = gpu_precomputed_data_.shared_face_data; + const double* d_normal = shared_face_data.normal.Read(); + const double* d_xyz = shared_face_data.xyz.Read(); + const double* d_shape1 = shared_face_data.el1_shape.Read(); + const double* d_shape2 = shared_face_data.el2_shape.Read(); + const int* d_face_num_quad = shared_face_data.num_quad.Read(); + const int* d_face_num_dof2 = shared_face_data.num_dof2.Read(); + const int* d_elem2_dofs = shared_face_data.elem2_dofs.Read(); + const int* d_elem2_grad_dofs = shared_face_data.elem2_grad_dofs.Read(); + const int* d_shared_elements_to_shared_faces = shared_face_data.shared_elements_to_shared_faces.Read(); auto d_delta_el1 = shared_face_data.delta_el1.Read(); auto d_delta_el2 = shared_face_data.delta_el2.Read(); @@ -605,10 +605,10 @@ void DGNonLinearForm::sharedFaceInterpolation_gpu(const Vector &x) { const int maxIntPoints = maxIntPoints_; const int maxDofs = maxDofs_; - double *d_shared_flux = shared_flux.Write(); + double* d_shared_flux = shared_flux.Write(); - const RiemannSolverTPS *d_rsolver = rsolver_; - Fluxes *d_flux = fluxes; + const RiemannSolverTPS* d_rsolver = rsolver_; + Fluxes* d_flux = fluxes; MFEM_FORALL_2D(el, maxNumElems, maxIntPoints, 1, 1, { double l1[gpudata::MAXDOFS], l2[gpudata::MAXDOFS]; // double l1[216], l2[216]; diff --git a/src/dgNonlinearForm.hpp b/src/dgNonlinearForm.hpp index 6c7c8cc3..90b39bd8 100644 --- a/src/dgNonlinearForm.hpp +++ b/src/dgNonlinearForm.hpp @@ -48,27 +48,27 @@ using namespace std; // so that we can use GPU class DGNonLinearForm : public ParNonlinearForm { private: - RiemannSolverTPS *rsolver_; - Fluxes *fluxes; - ParFiniteElementSpace *vfes; - ParFiniteElementSpace *gradFes; + RiemannSolverTPS* rsolver_; + Fluxes* fluxes; + ParFiniteElementSpace* vfes; + ParFiniteElementSpace* gradFes; - ParGridFunction *gradUp_; + ParGridFunction* gradUp_; - BCintegrator *bcIntegrator; + BCintegrator* bcIntegrator; - IntegrationRules *intRules; + IntegrationRules* intRules; const int dim_; const int num_equation_; - GasMixture *mixture; + GasMixture* mixture; - const precomputedIntegrationData &gpu_precomputed_data_; + const precomputedIntegrationData& gpu_precomputed_data_; - mutable dataTransferArrays *transferU; - mutable dataTransferArrays *transferGradUp; + mutable dataTransferArrays* transferU; + mutable dataTransferArrays* transferGradUp; - const int &maxIntPoints_; - const int &maxDofs_; + const int& maxIntPoints_; + const int& maxDofs_; Vector uk_el1, grad_upk_el1; Vector uk_el2, grad_upk_el2; @@ -77,26 +77,26 @@ class DGNonLinearForm : public ParNonlinearForm { Vector shared_flux; public: - DGNonLinearForm(RiemannSolverTPS *rsolver, Fluxes *_flux, ParFiniteElementSpace *f, ParFiniteElementSpace *gradFes, - ParGridFunction *_gradUp, BCintegrator *_bcIntegrator, IntegrationRules *intRules, const int dim, - const int num_equation, GasMixture *mixture, const precomputedIntegrationData &gpu_precomputed_data, - const int &maxIntPoints, const int &maxDofs); + DGNonLinearForm(RiemannSolverTPS* rsolver, Fluxes* _flux, ParFiniteElementSpace* f, ParFiniteElementSpace* gradFes, + ParGridFunction* _gradUp, BCintegrator* _bcIntegrator, IntegrationRules* intRules, const int dim, + const int num_equation, GasMixture* mixture, const precomputedIntegrationData& gpu_precomputed_data, + const int& maxIntPoints, const int& maxDofs); - void setParallelData(dataTransferArrays *_transferU, dataTransferArrays *_transferGradUp); + void setParallelData(dataTransferArrays* _transferU, dataTransferArrays* _transferGradUp); - void faceIntegration_gpu(Vector &y, int elType, int elemOffset, int elDof); + void faceIntegration_gpu(Vector& y, int elType, int elemOffset, int elDof); - void sharedFaceIntegration_gpu(Vector &y); + void sharedFaceIntegration_gpu(Vector& y); - void interpFaceData_gpu(const Vector &x, int elType, int elemOffset, int elDof); + void interpFaceData_gpu(const Vector& x, int elType, int elemOffset, int elDof); - void sharedFaceInterpolation_gpu(const Vector &x); + void sharedFaceInterpolation_gpu(const Vector& x); void evalFaceFlux_gpu(); #ifdef _GPU_ - void Mult_domain(const Vector &x, Vector &y); - void Mult_bdr(const Vector &x, Vector &y); - static void setToZero_gpu(Vector &x, const int size); + void Mult_domain(const Vector& x, Vector& y); + void Mult_bdr(const Vector& x, Vector& y); + static void setToZero_gpu(Vector& x, const int size); #endif }; diff --git a/src/dirichlet_bc_helper.hpp b/src/dirichlet_bc_helper.hpp index fe41078b..c3b68333 100644 --- a/src/dirichlet_bc_helper.hpp +++ b/src/dirichlet_bc_helper.hpp @@ -39,10 +39,10 @@ template class DirichletBC_T { public: - DirichletBC_T(mfem::Array attr, Tcoeff *coeff) : attr(attr), coeff(coeff) {} + DirichletBC_T(mfem::Array attr, Tcoeff* coeff) : attr(attr), coeff(coeff) {} // Move constructor (required for emplace_back) - DirichletBC_T(DirichletBC_T &&obj) { + DirichletBC_T(DirichletBC_T&& obj) { // Deep copy the attribute array this->attr = obj.attr; @@ -54,6 +54,6 @@ class DirichletBC_T { ~DirichletBC_T() { delete coeff; } mfem::Array attr; - Tcoeff *coeff; + Tcoeff* coeff; }; #endif // DIRICHLET_BC_HELPER_HPP_ diff --git a/src/domain_integrator.cpp b/src/domain_integrator.cpp index 050933c8..c713b96f 100644 --- a/src/domain_integrator.cpp +++ b/src/domain_integrator.cpp @@ -33,7 +33,7 @@ #include "domain_integrator.hpp" // Implementation of class DomainIntegrator -DomainIntegrator::DomainIntegrator(Fluxes *_fluxClass, IntegrationRules *_intRules, int _intRuleType, const int _dim, +DomainIntegrator::DomainIntegrator(Fluxes* _fluxClass, IntegrationRules* _intRules, int _intRuleType, const int _dim, const int _num_equation, bool axisym) : fluxClass(_fluxClass), dim(_dim), @@ -42,8 +42,8 @@ DomainIntegrator::DomainIntegrator(Fluxes *_fluxClass, IntegrationRules *_intRul intRuleType(_intRuleType), axisymmetric_(axisym) {} -void DomainIntegrator::AssembleElementMatrix2(const FiniteElement &trial_fe, const FiniteElement &test_fe, - ElementTransformation &Tr, DenseMatrix &elmat) { +void DomainIntegrator::AssembleElementMatrix2(const FiniteElement& trial_fe, const FiniteElement& test_fe, + ElementTransformation& Tr, DenseMatrix& elmat) { // Assemble the form (vec(v), grad(w)) Vector shape; shape.UseDevice(false); @@ -67,9 +67,9 @@ void DomainIntegrator::AssembleElementMatrix2(const FiniteElement &trial_fe, con const int maxorder = max(trial_fe.GetOrder(), test_fe.GetOrder()); int intorder = 2 * maxorder; - const IntegrationRule *ir = &intRules->Get(trial_fe.GetGeomType(), intorder); + const IntegrationRule* ir = &intRules->Get(trial_fe.GetGeomType(), intorder); for (int i = 0; i < ir->GetNPoints(); i++) { - const IntegrationPoint &ip = ir->IntPoint(i); + const IntegrationPoint& ip = ir->IntPoint(i); // Calculate the shape functions trial_fe.CalcShape(ip, shape); diff --git a/src/domain_integrator.hpp b/src/domain_integrator.hpp index e777233b..01a65910 100644 --- a/src/domain_integrator.hpp +++ b/src/domain_integrator.hpp @@ -50,20 +50,20 @@ using namespace std; // dim) and test space = scalar L2 space. class DomainIntegrator : public BilinearFormIntegrator { private: - Fluxes *fluxClass; + Fluxes* fluxClass; const int dim; const int num_equation; - IntegrationRules *intRules; + IntegrationRules* intRules; const int intRuleType; const bool axisymmetric_; public: - DomainIntegrator(Fluxes *_fluxClass, IntegrationRules *_intRules, int _intRuleType, const int _dim, + DomainIntegrator(Fluxes* _fluxClass, IntegrationRules* _intRules, int _intRuleType, const int _dim, const int _num_equation, bool axisym); - virtual void AssembleElementMatrix2(const FiniteElement &trial_fe, const FiniteElement &test_fe, - ElementTransformation &Tr, DenseMatrix &elmat); + virtual void AssembleElementMatrix2(const FiniteElement& trial_fe, const FiniteElement& test_fe, + ElementTransformation& Tr, DenseMatrix& elmat); }; #endif // DOMAIN_INTEGRATOR_HPP_ diff --git a/src/em_options.hpp b/src/em_options.hpp index d192c88f..a379c48b 100644 --- a/src/em_options.hpp +++ b/src/em_options.hpp @@ -95,7 +95,7 @@ class ElectromagneticOptions { variable_current = false; } - void print(std::ostream &out) { + void print(std::ostream& out) { out << std::endl; out << "Electromagnetics options:" << std::endl; out << " mesh_file = " << mesh_file << std::endl; diff --git a/src/equation_of_state.cpp b/src/equation_of_state.cpp index fe432d67..22f944ba 100644 --- a/src/equation_of_state.cpp +++ b/src/equation_of_state.cpp @@ -34,7 +34,7 @@ // EquationOfState::EquationOfState() {} -GasMixture::GasMixture(RunConfiguration &_runfile, int _dim, int nvel) +GasMixture::GasMixture(RunConfiguration& _runfile, int _dim, int nvel) : GasMixture(_runfile.workFluid, _dim, nvel, _runfile.const_plasma_conductivity_) {} MFEM_HOST_DEVICE GasMixture::GasMixture(WorkingFluid f, int _dim, int nvel, double pc) { @@ -44,13 +44,13 @@ MFEM_HOST_DEVICE GasMixture::GasMixture(WorkingFluid f, int _dim, int nvel, doub const_plasma_conductivity_ = pc; } -void GasMixture::SetConstantPlasmaConductivity(ParGridFunction *pc, const ParGridFunction *Up, - const ParGridFunction *coords) { +void GasMixture::SetConstantPlasmaConductivity(ParGridFunction* pc, const ParGridFunction* Up, + const ParGridFunction* coords) { // quick return if pc is NULL (nothing to set) if (pc == NULL) return; // otherwise, set plasma conductivity - double *plasma_conductivity_gf = pc->HostWrite(); + double* plasma_conductivity_gf = pc->HostWrite(); // To a constant const int nnode = pc->FESpace()->GetNDofs(); @@ -79,9 +79,9 @@ void GasMixture::SetConstantPlasmaConductivity(ParGridFunction *pc, const ParGri // } } -void GasMixture::UpdatePressureGridFunction(ParGridFunction *press, const ParGridFunction *Up) { - double *pGridFunc = press->HostWrite(); - const double *UpData = Up->HostRead(); +void GasMixture::UpdatePressureGridFunction(ParGridFunction* press, const ParGridFunction* Up) { + double* pGridFunc = press->HostWrite(); + const double* UpData = Up->HostRead(); const int nnode = press->FESpace()->GetNDofs(); @@ -97,7 +97,7 @@ void GasMixture::UpdatePressureGridFunction(ParGridFunction *press, const ParGri // total energy of stagnation state is essentially the same as // the total energy of input state subtracted by its bulk kinetic energy. // Do not necessarily need mixture-specific routines. -void GasMixture::computeStagnationState(const mfem::Vector &stateIn, mfem::Vector &stagnationState) { +void GasMixture::computeStagnationState(const mfem::Vector& stateIn, mfem::Vector& stagnationState) { stagnationState.SetSize(num_equation); stagnationState = stateIn; @@ -114,8 +114,8 @@ void GasMixture::computeStagnationState(const mfem::Vector &stateIn, mfem::Vecto // NOTE: electron energy is purely internal energy, so no change. } -void GasMixture::modifyStateFromPrimitive(const Vector &state, const BoundaryPrimitiveData &bcState, - Vector &outputState) { +void GasMixture::modifyStateFromPrimitive(const Vector& state, const BoundaryPrimitiveData& bcState, + Vector& outputState) { outputState.SetSize(num_equation); // assert(bcState.prim.Size() == num_equation); @@ -128,8 +128,8 @@ void GasMixture::modifyStateFromPrimitive(const Vector &state, const BoundaryPri GetConservativesFromPrimitives(prim, outputState); } -MFEM_HOST_DEVICE void GasMixture::modifyStateFromPrimitive(const double *state, const BoundaryPrimitiveData &bcState, - double *outputState) { +MFEM_HOST_DEVICE void GasMixture::modifyStateFromPrimitive(const double* state, const BoundaryPrimitiveData& bcState, + double* outputState) { double prim[gpudata::MAXEQUATIONS]; GetPrimitivesFromConservatives(state, prim); for (int i = 0; i < num_equation; i++) { @@ -143,7 +143,7 @@ MFEM_HOST_DEVICE void GasMixture::modifyStateFromPrimitive(const double *state, //////// Dry Air mixture ////////////////////////////////////////////////////// -DryAir::DryAir(RunConfiguration &_runfile, int _dim, int nvel) +DryAir::DryAir(RunConfiguration& _runfile, int _dim, int nvel) // : DryAir(_runfile.workFluid, _runfile.GetEquationSystem(), _runfile.visc_mult, _runfile.bulk_visc, _dim, nvel) {} : DryAir(_runfile.dryAirInput, _dim, nvel) {} @@ -217,19 +217,19 @@ void DryAir::setNumEquations() { // } // } -void DryAir::computeSpeciesEnthalpies(const Vector &state, Vector &speciesEnthalpies) { +void DryAir::computeSpeciesEnthalpies(const Vector& state, Vector& speciesEnthalpies) { speciesEnthalpies.SetSize(numSpecies); speciesEnthalpies = 0.0; return; } -MFEM_HOST_DEVICE void DryAir::computeSpeciesEnthalpies(const double *state, double *speciesEnthalpies) { +MFEM_HOST_DEVICE void DryAir::computeSpeciesEnthalpies(const double* state, double* speciesEnthalpies) { for (int sp = 0; sp < numSpecies; sp++) speciesEnthalpies[sp] = 0.0; return; } -bool DryAir::StateIsPhysical(const mfem::Vector &state) { +bool DryAir::StateIsPhysical(const mfem::Vector& state) { const double den = state(0); const Vector den_vel(state.GetData() + 1, nvel_); const double den_energy = state(iTh); @@ -273,9 +273,9 @@ bool DryAir::StateIsPhysical(const mfem::Vector &state) { // TODO(kevin): We need to move this routine to upper level, i.e. M2ulPhys. // Diffusion velocity contributes to the characteristic speed, which mixture cannot handle or know. // Compute the maximum characteristic speed. -double DryAir::ComputeMaxCharSpeed(const Vector &state) { return ComputeMaxCharSpeed(state.GetData()); } +double DryAir::ComputeMaxCharSpeed(const Vector& state) { return ComputeMaxCharSpeed(state.GetData()); } -MFEM_HOST_DEVICE double DryAir::ComputeMaxCharSpeed(const double *state) { +MFEM_HOST_DEVICE double DryAir::ComputeMaxCharSpeed(const double* state) { const double den = state[0]; double den_vel2 = 0; @@ -291,11 +291,11 @@ MFEM_HOST_DEVICE double DryAir::ComputeMaxCharSpeed(const double *state) { return vel + sound; } -void DryAir::GetConservativesFromPrimitives(const Vector &primit, Vector &conserv) { +void DryAir::GetConservativesFromPrimitives(const Vector& primit, Vector& conserv) { GetConservativesFromPrimitives(primit.GetData(), conserv.GetData()); } -MFEM_HOST_DEVICE void DryAir::GetConservativesFromPrimitives(const double *primit, double *conserv) { +MFEM_HOST_DEVICE void DryAir::GetConservativesFromPrimitives(const double* primit, double* conserv) { for (int eq = 0; eq < num_equation; eq++) conserv[eq] = primit[eq]; double v2 = 0.; @@ -314,11 +314,11 @@ MFEM_HOST_DEVICE void DryAir::GetConservativesFromPrimitives(const double *primi } } -void DryAir::GetPrimitivesFromConservatives(const Vector &conserv, Vector &primit) { +void DryAir::GetPrimitivesFromConservatives(const Vector& conserv, Vector& primit) { GetPrimitivesFromConservatives(conserv.GetData(), primit.GetData()); } -MFEM_HOST_DEVICE void DryAir::GetPrimitivesFromConservatives(const double *conserv, double *primit) { +MFEM_HOST_DEVICE void DryAir::GetPrimitivesFromConservatives(const double* conserv, double* primit) { double T = ComputeTemperature(conserv); for (int eq = 0; eq < num_equation; eq++) primit[eq] = conserv[eq]; @@ -334,7 +334,7 @@ MFEM_HOST_DEVICE void DryAir::GetPrimitivesFromConservatives(const double *conse } } -double DryAir::ComputeSpeedOfSound(const mfem::Vector &Uin, bool primitive) { +double DryAir::ComputeSpeedOfSound(const mfem::Vector& Uin, bool primitive) { double T; if (primitive) { @@ -347,7 +347,7 @@ double DryAir::ComputeSpeedOfSound(const mfem::Vector &Uin, bool primitive) { return sqrt(specific_heat_ratio * gas_constant * T); } -double DryAir::ComputePressureDerivative(const Vector &dUp_dx, const Vector &Uin, bool primitive) { +double DryAir::ComputePressureDerivative(const Vector& dUp_dx, const Vector& Uin, bool primitive) { double T; if (primitive) { T = Uin[iTh]; @@ -358,13 +358,13 @@ double DryAir::ComputePressureDerivative(const Vector &dUp_dx, const Vector &Uin return gas_constant * (T * dUp_dx[0] + Uin[0] * dUp_dx[iTh]); } -double DryAir::ComputePressureFromPrimitives(const mfem::Vector &Up) { return gas_constant * Up[0] * Up[iTh]; } +double DryAir::ComputePressureFromPrimitives(const mfem::Vector& Up) { return gas_constant * Up[0] * Up[iTh]; } -MFEM_HOST_DEVICE double DryAir::ComputePressureFromPrimitives(const double *Up) { +MFEM_HOST_DEVICE double DryAir::ComputePressureFromPrimitives(const double* Up) { return gas_constant * Up[0] * Up[iTh]; } -void DryAir::computeStagnationState(const mfem::Vector &stateIn, mfem::Vector &stagnationState) { +void DryAir::computeStagnationState(const mfem::Vector& stateIn, mfem::Vector& stagnationState) { const double p = ComputePressure(stateIn); stagnationState.SetSize(num_equation); @@ -377,7 +377,7 @@ void DryAir::computeStagnationState(const mfem::Vector &stateIn, mfem::Vector &s stagnationState(iTh) = p / (specific_heat_ratio - 1.); } -void DryAir::computeStagnantStateWithTemp(const mfem::Vector &stateIn, const double Temp, mfem::Vector &stateOut) { +void DryAir::computeStagnantStateWithTemp(const mfem::Vector& stateIn, const double Temp, mfem::Vector& stateOut) { stateOut.SetSize(num_equation); stateOut = stateIn; @@ -387,7 +387,7 @@ void DryAir::computeStagnantStateWithTemp(const mfem::Vector &stateIn, const dou } // NOTE: modifyElectronEnergy will not be used for DryAir. -void DryAir::modifyEnergyForPressure(const mfem::Vector &stateIn, mfem::Vector &stateOut, const double &p, +void DryAir::modifyEnergyForPressure(const mfem::Vector& stateIn, mfem::Vector& stateOut, const double& p, bool modifyElectronEnergy) { stateOut.SetSize(num_equation); stateOut = stateIn; @@ -399,7 +399,7 @@ void DryAir::modifyEnergyForPressure(const mfem::Vector &stateIn, mfem::Vector & stateOut(iTh) = p / (specific_heat_ratio - 1.) + ke; } -MFEM_HOST_DEVICE void DryAir::modifyEnergyForPressure(const double *stateIn, double *stateOut, const double &p, +MFEM_HOST_DEVICE void DryAir::modifyEnergyForPressure(const double* stateIn, double* stateOut, const double& p, bool modifyElectronEnergy) { for (int eq = 0; eq < num_equation; eq++) stateOut[eq] = stateIn[eq]; @@ -411,8 +411,8 @@ MFEM_HOST_DEVICE void DryAir::modifyEnergyForPressure(const double *stateIn, dou } // TODO(kevin): check if this works for axisymmetric case. -void DryAir::computeConservedStateFromConvectiveFlux(const Vector &meanNormalFluxes, const Vector &normal, - Vector &conservedState) { +void DryAir::computeConservedStateFromConvectiveFlux(const Vector& meanNormalFluxes, const Vector& normal, + Vector& conservedState) { const double gamma = specific_heat_ratio; double temp = 0.; @@ -472,7 +472,7 @@ double EquationOfState::pressure( double *state, ////// Perfect Mixture GasMixture //////////////////// ////////////////////////////////////////////////////////////////////////// -PerfectMixture::PerfectMixture(RunConfiguration &_runfile, int _dim, int nvel) +PerfectMixture::PerfectMixture(RunConfiguration& _runfile, int _dim, int nvel) : PerfectMixture(_runfile.perfectMixtureInput, _dim, nvel, _runfile.const_plasma_conductivity_) {} MFEM_HOST_DEVICE PerfectMixture::PerfectMixture(PerfectMixtureInput inputs, int _dim, int nvel, double pc) @@ -573,7 +573,7 @@ MFEM_HOST_DEVICE PerfectMixture::PerfectMixture(PerfectMixtureInput inputs, int } // compute heavy-species heat capacity from number densities. -MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesHeatCapacity(const double *n_sp, const double &nB) const { +MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesHeatCapacity(const double* n_sp, const double& nB) const { double heatCapacity = 0.0; for (int sp = 0; sp < numActiveSpecies; sp++) { if (sp == iElectron) continue; // neglect electron. @@ -583,7 +583,7 @@ MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesHeatCapacity(const double return heatCapacity; } -MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesCp(const double *n_sp, const double &nB) const { +MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesCp(const double* n_sp, const double& nB) const { double heatCapacity = 0.0; for (int sp = 0; sp < numActiveSpecies; sp++) { if (sp == iElectron) continue; // neglect electron. @@ -594,7 +594,7 @@ MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesCp(const double *n_sp, con return heatCapacity; } -MFEM_HOST_DEVICE double PerfectMixture::computeSpeciesCp(const double *n_sp, const double &nB, int sp) { +MFEM_HOST_DEVICE double PerfectMixture::computeSpeciesCp(const double* n_sp, const double& nB, int sp) { double heatCapacity; if (sp == iBackground) { heatCapacity = nB * molarCP_[iBackground]; @@ -604,7 +604,7 @@ MFEM_HOST_DEVICE double PerfectMixture::computeSpeciesCp(const double *n_sp, con return heatCapacity; } -MFEM_HOST_DEVICE double PerfectMixture::computeAmbipolarElectronNumberDensity(const double *n_sp) const { +MFEM_HOST_DEVICE double PerfectMixture::computeAmbipolarElectronNumberDensity(const double* n_sp) const { double n_e = 0.0; for (int sp = 0; sp < numActiveSpecies; sp++) { @@ -617,7 +617,7 @@ MFEM_HOST_DEVICE double PerfectMixture::computeAmbipolarElectronNumberDensity(co return n_e; } -MFEM_HOST_DEVICE double PerfectMixture::computeBackgroundMassDensity(const double &rho, const double *n_sp, double &n_e, +MFEM_HOST_DEVICE double PerfectMixture::computeBackgroundMassDensity(const double& rho, const double* n_sp, double& n_e, bool isElectronComputed) const { if ((!isElectronComputed) && (ambipolar)) { n_e = computeAmbipolarElectronNumberDensity(n_sp); @@ -653,7 +653,7 @@ MFEM_HOST_DEVICE double PerfectMixture::computeBackgroundMassDensity(const doubl // Right now, it's alwasy the same as conserved variables, to minimize gradient computation. // Additional primitive variables (such as temperature currently) needs to be evaluated every time it is needed. // Gradient computation can still keep the same number, while expanding the primitive variables. -void PerfectMixture::GetPrimitivesFromConservatives(const Vector &conserv, Vector &primit) { +void PerfectMixture::GetPrimitivesFromConservatives(const Vector& conserv, Vector& primit) { // Vector n_sp; // computeNumberDensities(conserv, n_sp); // @@ -676,7 +676,7 @@ void PerfectMixture::GetPrimitivesFromConservatives(const Vector &conserv, Vecto GetPrimitivesFromConservatives(&conserv[0], &primit[0]); } -MFEM_HOST_DEVICE void PerfectMixture::GetPrimitivesFromConservatives(const double *conserv, double *primit) { +MFEM_HOST_DEVICE void PerfectMixture::GetPrimitivesFromConservatives(const double* conserv, double* primit) { double n_sp[gpudata::MAXSPECIES]; computeNumberDensities(conserv, n_sp); @@ -699,7 +699,7 @@ MFEM_HOST_DEVICE void PerfectMixture::GetPrimitivesFromConservatives(const doubl primit[iTe] = T_e; } -void PerfectMixture::GetConservativesFromPrimitives(const Vector &primit, Vector &conserv) { +void PerfectMixture::GetConservativesFromPrimitives(const Vector& primit, Vector& conserv) { // conserv[0] = primit[0]; // for (int d = 0; d < nvel_; d++) conserv[d + 1] = primit[d + 1] * primit[0]; // @@ -741,7 +741,7 @@ void PerfectMixture::GetConservativesFromPrimitives(const Vector &primit, Vector GetConservativesFromPrimitives(&primit[0], &conserv[0]); } -MFEM_HOST_DEVICE void PerfectMixture::GetConservativesFromPrimitives(const double *primit, double *conserv) { +MFEM_HOST_DEVICE void PerfectMixture::GetConservativesFromPrimitives(const double* primit, double* conserv) { conserv[0] = primit[0]; for (int d = 0; d < nvel_; d++) conserv[d + 1] = primit[d + 1] * primit[0]; @@ -782,11 +782,11 @@ MFEM_HOST_DEVICE void PerfectMixture::GetConservativesFromPrimitives(const doubl conserv[iTh] = totalEnergy; } -void PerfectMixture::GetMixtureCp(const Vector &ns, const double &rho, double &CpMix) { +void PerfectMixture::GetMixtureCp(const Vector& ns, const double& rho, double& CpMix) { GetMixtureCp(&ns[0], &rho, &CpMix); } -MFEM_HOST_DEVICE void PerfectMixture::GetMixtureCp(const double *ns, const double *rho, double *CpMix) { +MFEM_HOST_DEVICE void PerfectMixture::GetMixtureCp(const double* ns, const double* rho, double* CpMix) { double n_e = 0.0; if (ambipolar) { n_e = computeAmbipolarElectronNumberDensity(ns); @@ -803,11 +803,11 @@ MFEM_HOST_DEVICE void PerfectMixture::GetMixtureCp(const double *ns, const doubl *CpMix = totalHeatCapacity; } -void PerfectMixture::GetSpeciesCp(const Vector &ns, const double &rho, int sp, double &CpY) { +void PerfectMixture::GetSpeciesCp(const Vector& ns, const double& rho, int sp, double& CpY) { GetSpeciesCp(&ns[0], &rho, sp, &CpY); } -MFEM_HOST_DEVICE void PerfectMixture::GetSpeciesCp(const double *ns, const double *rho, int sp, double *CpY) { +MFEM_HOST_DEVICE void PerfectMixture::GetSpeciesCp(const double* ns, const double* rho, int sp, double* CpY) { double n_e = 0.0; if (ambipolar) { n_e = computeAmbipolarElectronNumberDensity(ns); @@ -831,7 +831,7 @@ MFEM_HOST_DEVICE void PerfectMixture::GetSpeciesCp(const double *ns, const doubl // Mole fraction X will be needed almost everywhere, though it requires Y and n to be evaluated first. // TODO(kevin): It is better to include all X, Y, n into primitive variable Up, // in order to reduce repeated evaluation. -void PerfectMixture::computeSpeciesPrimitives(const Vector &conservedState, Vector &X_sp, Vector &Y_sp, Vector &n_sp) { +void PerfectMixture::computeSpeciesPrimitives(const Vector& conservedState, Vector& X_sp, Vector& Y_sp, Vector& n_sp) { X_sp.SetSize(numSpecies); Y_sp.SetSize(numSpecies); n_sp.SetSize(numSpecies); @@ -879,8 +879,8 @@ void PerfectMixture::computeSpeciesPrimitives(const Vector &conservedState, Vect computeSpeciesPrimitives(&conservedState[0], &X_sp[0], &Y_sp[0], &n_sp[0]); } -MFEM_HOST_DEVICE void PerfectMixture::computeSpeciesPrimitives(const double *conservedState, double *X_sp, double *Y_sp, - double *n_sp) { +MFEM_HOST_DEVICE void PerfectMixture::computeSpeciesPrimitives(const double* conservedState, double* X_sp, double* Y_sp, + double* n_sp) { for (int sp = 0; sp < numSpecies; sp++) { X_sp[sp] = 0.0; Y_sp[sp] = 0.0; @@ -926,7 +926,7 @@ MFEM_HOST_DEVICE void PerfectMixture::computeSpeciesPrimitives(const double *con for (int sp = 0; sp < numSpecies; sp++) X_sp[sp] = n_sp[sp] / n; } -void PerfectMixture::computeNumberDensities(const Vector &conservedState, Vector &n_sp) { +void PerfectMixture::computeNumberDensities(const Vector& conservedState, Vector& n_sp) { n_sp.SetSize(numSpecies); // n_sp = 0.0; // @@ -944,7 +944,7 @@ void PerfectMixture::computeNumberDensities(const Vector &conservedState, Vector computeNumberDensities(&conservedState[0], &n_sp[0]); } -MFEM_HOST_DEVICE void PerfectMixture::computeNumberDensities(const double *conservedState, double *n_sp) const { +MFEM_HOST_DEVICE void PerfectMixture::computeNumberDensities(const double* conservedState, double* n_sp) const { for (int sp = 0; sp < numSpecies; sp++) n_sp[sp] = 0.0; double n_e = 0.0; @@ -960,7 +960,7 @@ MFEM_HOST_DEVICE void PerfectMixture::computeNumberDensities(const double *conse n_sp[iBackground] = rhoB / GetGasParams(iBackground, GasParams::SPECIES_MW); } -double PerfectMixture::ComputePressureFromPrimitives(const mfem::Vector &Up) { +double PerfectMixture::ComputePressureFromPrimitives(const mfem::Vector& Up) { // // NOTE: For now, we do not include all species number densities into Up. // // This requires us to re-evaluate electron/background-species number density. // double n_e = 0.0; @@ -985,7 +985,7 @@ double PerfectMixture::ComputePressureFromPrimitives(const mfem::Vector &Up) { return ComputePressureFromPrimitives(&Up[0]); } -MFEM_HOST_DEVICE double PerfectMixture::ComputePressureFromPrimitives(const double *Up) { +MFEM_HOST_DEVICE double PerfectMixture::ComputePressureFromPrimitives(const double* Up) { // NOTE: For now, we do not include all species number densities into Up. // This requires us to re-evaluate electron/background-species number density. double n_e = 0.0; @@ -1010,7 +1010,7 @@ MFEM_HOST_DEVICE double PerfectMixture::ComputePressureFromPrimitives(const doub } // NOTE: This is almost the same as GetPrimitivesFromConservatives except storing other primitive variables. -double PerfectMixture::ComputePressure(const Vector &state, double *electronPressure) { +double PerfectMixture::ComputePressure(const Vector& state, double* electronPressure) { // Vector n_sp; // computeNumberDensities(state, n_sp); // @@ -1026,7 +1026,7 @@ double PerfectMixture::ComputePressure(const Vector &state, double *electronPres return ComputePressure(&state[0], electronPressure); } -MFEM_HOST_DEVICE double PerfectMixture::ComputePressure(const double *state, double *electronPressure) { +MFEM_HOST_DEVICE double PerfectMixture::ComputePressure(const double* state, double* electronPressure) { double n_sp[gpudata::MAXSPECIES]; computeNumberDensities(state, n_sp); @@ -1041,7 +1041,7 @@ MFEM_HOST_DEVICE double PerfectMixture::ComputePressure(const double *state, dou return p; } -MFEM_HOST_DEVICE double PerfectMixture::computePressureBase(const double *n_sp, const double n_e, const double n_B, +MFEM_HOST_DEVICE double PerfectMixture::computePressureBase(const double* n_sp, const double n_e, const double n_B, const double T_h, const double T_e) const { // NOTE: compute pressure. double n_h = 0.0; // total number density of all heavy species. @@ -1062,7 +1062,7 @@ MFEM_HOST_DEVICE double PerfectMixture::computePressureBase(const double *n_sp, return p; } -bool PerfectMixture::StateIsPhysical(const Vector &state) { +bool PerfectMixture::StateIsPhysical(const Vector& state) { bool physical = true; if (state(0) < 0) { @@ -1116,7 +1116,7 @@ bool PerfectMixture::StateIsPhysical(const Vector &state) { } // NOTE: this routine only return heavy-species temperature. Need name-change. -double PerfectMixture::ComputeTemperature(const Vector &state) { +double PerfectMixture::ComputeTemperature(const Vector& state) { // Vector n_sp; // computeNumberDensities(state, n_sp); // @@ -1128,7 +1128,7 @@ double PerfectMixture::ComputeTemperature(const Vector &state) { } // NOTE: this routine only return heavy-species temperature. Need name-change. -MFEM_HOST_DEVICE double PerfectMixture::ComputeTemperature(const double *state) { +MFEM_HOST_DEVICE double PerfectMixture::ComputeTemperature(const double* state) { double n_sp[gpudata::MAXSPECIES]; computeNumberDensities(state, n_sp); @@ -1138,9 +1138,9 @@ MFEM_HOST_DEVICE double PerfectMixture::ComputeTemperature(const double *state) return T_h; } -MFEM_HOST_DEVICE void PerfectMixture::computeTemperaturesBase(const double *conservedState, const double *n_sp, - const double n_e, const double n_B, double &T_h, - double &T_e) const { +MFEM_HOST_DEVICE void PerfectMixture::computeTemperaturesBase(const double* conservedState, const double* n_sp, + const double n_e, const double n_B, double& T_h, + double& T_e) const { // compute mixture heat capacity. double totalHeatCapacity = computeHeaviesHeatCapacity(&n_sp[0], n_B); if (!twoTemperature_) totalHeatCapacity += n_e * molarCV_[iElectron]; @@ -1171,7 +1171,7 @@ MFEM_HOST_DEVICE void PerfectMixture::computeTemperaturesBase(const double *cons return; } -void PerfectMixture::computeSpeciesEnthalpies(const Vector &state, Vector &speciesEnthalpies) { +void PerfectMixture::computeSpeciesEnthalpies(const Vector& state, Vector& speciesEnthalpies) { speciesEnthalpies.SetSize(numSpecies); // Vector n_sp; @@ -1189,7 +1189,7 @@ void PerfectMixture::computeSpeciesEnthalpies(const Vector &state, Vector &speci return; } -MFEM_HOST_DEVICE void PerfectMixture::computeSpeciesEnthalpies(const double *state, double *speciesEnthalpies) { +MFEM_HOST_DEVICE void PerfectMixture::computeSpeciesEnthalpies(const double* state, double* speciesEnthalpies) { for (int sp = 0; sp < numSpecies; sp++) speciesEnthalpies[sp] = 0.0; double n_sp[gpudata::MAXSPECIES]; @@ -1206,7 +1206,7 @@ MFEM_HOST_DEVICE void PerfectMixture::computeSpeciesEnthalpies(const double *sta return; } -double PerfectMixture::ComputePressureDerivative(const Vector &dUp_dx, const Vector &Uin, bool primitive) { +double PerfectMixture::ComputePressureDerivative(const Vector& dUp_dx, const Vector& Uin, bool primitive) { if (primitive) { return computePressureDerivativeFromPrimitives(dUp_dx, Uin); } else { @@ -1215,7 +1215,7 @@ double PerfectMixture::ComputePressureDerivative(const Vector &dUp_dx, const Vec } // NOTE(kevin): normal-vector-related parts are already handled. -double PerfectMixture::computePressureDerivativeFromPrimitives(const Vector &dUp_dx, const Vector &Uin) { +double PerfectMixture::computePressureDerivativeFromPrimitives(const Vector& dUp_dx, const Vector& Uin) { double pressureGradient = 0.0; double n_e = 0.0; @@ -1263,7 +1263,7 @@ double PerfectMixture::computePressureDerivativeFromPrimitives(const Vector &dUp } // NOTE(kevin): normal-vector-related parts are already handled. -double PerfectMixture::computePressureDerivativeFromConservatives(const Vector &dUp_dx, const Vector &Uin) { +double PerfectMixture::computePressureDerivativeFromConservatives(const Vector& dUp_dx, const Vector& Uin) { double pressureGradient = 0.0; Vector n_sp; @@ -1308,7 +1308,7 @@ double PerfectMixture::computePressureDerivativeFromConservatives(const Vector & return pressureGradient; } -MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesMixtureCV(const double *n_sp, const double n_B) const { +MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesMixtureCV(const double* n_sp, const double n_B) const { double mixtureCV = 0.0; for (int sp = 0; sp < numActiveSpecies; sp++) { @@ -1320,7 +1320,7 @@ MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesMixtureCV(const double *n_ return mixtureCV; } -MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesMixtureHeatRatio(const double *n_sp, const double n_B) const { +MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesMixtureHeatRatio(const double* n_sp, const double n_B) const { double mixtureCV = computeHeaviesMixtureCV(n_sp, n_B); double n_h = n_B; for (int sp = 0; sp < numActiveSpecies; sp++) { @@ -1331,7 +1331,7 @@ MFEM_HOST_DEVICE double PerfectMixture::computeHeaviesMixtureHeatRatio(const dou return 1.0 + n_h * UNIVERSALGASCONSTANT / mixtureCV; } -MFEM_HOST_DEVICE double PerfectMixture::computeSpeedOfSoundBase(const double *n_sp, const double n_B, const double rho, +MFEM_HOST_DEVICE double PerfectMixture::computeSpeedOfSoundBase(const double* n_sp, const double n_B, const double rho, const double p) const { double gamma = computeHeaviesMixtureHeatRatio(n_sp, n_B); @@ -1339,7 +1339,7 @@ MFEM_HOST_DEVICE double PerfectMixture::computeSpeedOfSoundBase(const double *n_ } // Compute the maximum characteristic speed. -double PerfectMixture::ComputeMaxCharSpeed(const Vector &state) { +double PerfectMixture::ComputeMaxCharSpeed(const Vector& state) { // const double den = state(0); // const Vector den_vel(state.GetData() + 1, nvel_); // @@ -1356,7 +1356,7 @@ double PerfectMixture::ComputeMaxCharSpeed(const Vector &state) { return ComputeMaxCharSpeed(&state[0]); } -MFEM_HOST_DEVICE double PerfectMixture::ComputeMaxCharSpeed(const double *state) { +MFEM_HOST_DEVICE double PerfectMixture::ComputeMaxCharSpeed(const double* state) { const double den = state[0]; // const double den_vel(state.GetData() + 1, nvel_); @@ -1372,7 +1372,7 @@ MFEM_HOST_DEVICE double PerfectMixture::ComputeMaxCharSpeed(const double *state) return vel + sound; } -double PerfectMixture::ComputeSpeedOfSound(const mfem::Vector &Uin, bool primitive) { +double PerfectMixture::ComputeSpeedOfSound(const mfem::Vector& Uin, bool primitive) { // if (primitive) { // double n_e = 0.0; // if (ambipolar) { @@ -1402,7 +1402,7 @@ double PerfectMixture::ComputeSpeedOfSound(const mfem::Vector &Uin, bool primiti return ComputeSpeedOfSound(&Uin[0], primitive); } -MFEM_HOST_DEVICE double PerfectMixture::ComputeSpeedOfSound(const double *Uin, bool primitive) const { +MFEM_HOST_DEVICE double PerfectMixture::ComputeSpeedOfSound(const double* Uin, bool primitive) const { if (primitive) { double n_e = 0.0; if (ambipolar) { @@ -1433,8 +1433,8 @@ MFEM_HOST_DEVICE double PerfectMixture::ComputeSpeedOfSound(const double *Uin, b // NOTE: numberDensities have all species number density. // NOTE(kevin): for axisymmetric case, this handles only r- and z-direction. -void PerfectMixture::ComputeMassFractionGradient(const double rho, const Vector &numberDensities, - const DenseMatrix &gradUp, DenseMatrix &massFractionGrad) { +void PerfectMixture::ComputeMassFractionGradient(const double rho, const Vector& numberDensities, + const DenseMatrix& gradUp, DenseMatrix& massFractionGrad) { massFractionGrad.SetSize(numSpecies, dim); massFractionGrad = 0.0; for (int sp = 0; sp < numActiveSpecies; sp++) { // if not ambipolar, electron is included. @@ -1472,8 +1472,8 @@ void PerfectMixture::ComputeMassFractionGradient(const double rho, const Vector } // NOTE(kevin): for axisymmetric case, this handles only r- and z-direction. -void PerfectMixture::ComputeMoleFractionGradient(const Vector &numberDensities, const DenseMatrix &gradUp, - DenseMatrix &moleFractionGrad) { +void PerfectMixture::ComputeMoleFractionGradient(const Vector& numberDensities, const DenseMatrix& gradUp, + DenseMatrix& moleFractionGrad) { moleFractionGrad.SetSize(numSpecies, dim); // double totalN = 0.0; // for (int sp = 0; sp < numSpecies; sp++) totalN += numberDensities(sp); @@ -1526,13 +1526,13 @@ void PerfectMixture::ComputeMoleFractionGradient(const Vector &numberDensities, // for (int d = 0; d < dim; d++) { // moleFractionGrad(sp, d) = nBGrad(d) / totalN - numberDensities(sp) / totalN / totalN * totalNGrad(d); // } - const double *d_gradUp = gradUp.Read(); - double *d_moleFractionGrad = moleFractionGrad.Write(); + const double* d_gradUp = gradUp.Read(); + double* d_moleFractionGrad = moleFractionGrad.Write(); ComputeMoleFractionGradient(&numberDensities[0], d_gradUp, d_moleFractionGrad); } -MFEM_HOST_DEVICE void PerfectMixture::ComputeMoleFractionGradient(const double *numberDensities, const double *gradUp, - double *moleFractionGrad) { +MFEM_HOST_DEVICE void PerfectMixture::ComputeMoleFractionGradient(const double* numberDensities, const double* gradUp, + double* moleFractionGrad) { // moleFractionGrad.SetSize(numSpecies, dim); for (int d = 0; d < dim; d++) { for (int sp = 0; sp < numSpecies; sp++) moleFractionGrad[sp + d * numSpecies] = 0.0; @@ -1593,8 +1593,8 @@ MFEM_HOST_DEVICE void PerfectMixture::ComputeMoleFractionGradient(const double * // NOTE: this is used in isothermal wall, where gas temperature and electron temperature is assumed equal. // i.e. it assumes single temperature at the wall regardless of two temperature condition inside the domain. -void PerfectMixture::computeStagnantStateWithTemp(const mfem::Vector &stateIn, const double Temp, - mfem::Vector &stateOut) { +void PerfectMixture::computeStagnantStateWithTemp(const mfem::Vector& stateIn, const double Temp, + mfem::Vector& stateOut) { stateOut.SetSize(num_equation); stateOut = stateIn; @@ -1621,7 +1621,7 @@ void PerfectMixture::computeStagnantStateWithTemp(const mfem::Vector &stateIn, c // At Inlet BC, for two-temperature, electron temperature is set to be equal to gas temperature, where the total // pressure is p. -void PerfectMixture::modifyEnergyForPressure(const mfem::Vector &stateIn, mfem::Vector &stateOut, const double &p, +void PerfectMixture::modifyEnergyForPressure(const mfem::Vector& stateIn, mfem::Vector& stateOut, const double& p, bool modifyElectronEnergy) { // // will change the total energy to adjust to p // stateOut.SetSize(num_equation); @@ -1695,7 +1695,7 @@ void PerfectMixture::modifyEnergyForPressure(const mfem::Vector &stateIn, mfem:: modifyEnergyForPressure(&stateIn[0], &stateOut[0], p, modifyElectronEnergy); } -MFEM_HOST_DEVICE void PerfectMixture::modifyEnergyForPressure(const double *stateIn, double *stateOut, const double &p, +MFEM_HOST_DEVICE void PerfectMixture::modifyEnergyForPressure(const double* stateIn, double* stateOut, const double& p, bool modifyElectronEnergy) { // will change the total energy to adjust to p for (int eq = 0; eq < num_equation; eq++) stateOut[eq] = stateIn[eq]; @@ -1741,8 +1741,8 @@ MFEM_HOST_DEVICE void PerfectMixture::modifyEnergyForPressure(const double *stat } // TODO(kevin): check if this works for axisymmetric case. -void PerfectMixture::computeConservedStateFromConvectiveFlux(const Vector &meanNormalFluxes, const Vector &normal, - Vector &conservedState) { +void PerfectMixture::computeConservedStateFromConvectiveFlux(const Vector& meanNormalFluxes, const Vector& normal, + Vector& conservedState) { Vector Up(num_equation); Vector numberDensityFluxes(numActiveSpecies); @@ -1820,8 +1820,8 @@ void PerfectMixture::computeConservedStateFromConvectiveFlux(const Vector &meanN } // NOTE(kevin): for axisymmetric case, this handles only r- and z-direction. -void PerfectMixture::computeElectronPressureGrad(const double n_e, const double T_e, const DenseMatrix &gradUp, - Vector &gradPe) { +void PerfectMixture::computeElectronPressureGrad(const double n_e, const double T_e, const DenseMatrix& gradUp, + Vector& gradPe) { gradPe.SetSize(dim); // Vector neGrad; @@ -1840,12 +1840,12 @@ void PerfectMixture::computeElectronPressureGrad(const double n_e, const double // gradPe(d) = (neGrad(d) * T_e + n_e * gradUp(iTe, d)) * UNIVERSALGASCONSTANT; // // return; - const double *d_gradUp = gradUp.Read(); + const double* d_gradUp = gradUp.Read(); computeElectronPressureGrad(n_e, T_e, d_gradUp, &gradPe[0]); } MFEM_HOST_DEVICE void PerfectMixture::computeElectronPressureGrad(const double n_e, const double T_e, - const double *gradUp, double *gradPe) { + const double* gradUp, double* gradPe) { for (int d = 0; d < dim; d++) gradPe[d] = 0.0; double neGrad[gpudata::MAXDIM]; @@ -1870,7 +1870,7 @@ MFEM_HOST_DEVICE void PerfectMixture::computeElectronPressureGrad(const double n // are recombined with electron into the background species. // For air plasma, we will need specific reaction inputs. // We may need to move this to rather chemistry class. -void PerfectMixture::computeSheathBdrFlux(const Vector &state, BoundaryViscousFluxData &bcFlux) { +void PerfectMixture::computeSheathBdrFlux(const Vector& state, BoundaryViscousFluxData& bcFlux) { // Vector n_sp(numSpecies); // computeNumberDensities(state, n_sp); // @@ -1906,7 +1906,7 @@ void PerfectMixture::computeSheathBdrFlux(const Vector &state, BoundaryViscousFl computeSheathBdrFlux(&state[0], bcFlux); } -MFEM_HOST_DEVICE void PerfectMixture::computeSheathBdrFlux(const double *state, BoundaryViscousFluxData &bcFlux) { +MFEM_HOST_DEVICE void PerfectMixture::computeSheathBdrFlux(const double* state, BoundaryViscousFluxData& bcFlux) { double n_sp[gpudata::MAXSPECIES]; computeNumberDensities(state, n_sp); @@ -1941,9 +1941,9 @@ MFEM_HOST_DEVICE void PerfectMixture::computeSheathBdrFlux(const double *state, } } -void PerfectMixture::GetSpeciesFromLTE(double *conserv, double *primit, TableInterpolator2D *energy_table, - TableInterpolator2D *R_table, TableInterpolator2D *c_table, - TableInterpolator2D *T_table) { +void PerfectMixture::GetSpeciesFromLTE(double* conserv, double* primit, TableInterpolator2D* energy_table, + TableInterpolator2D* R_table, TableInterpolator2D* c_table, + TableInterpolator2D* T_table) { for (int sp = 0; sp < numActiveSpecies; sp++) { conserv[nvel_ + 2 + sp] = 0.0; primit[nvel_ + 2 + sp] = 0.0; @@ -2093,7 +2093,7 @@ void PerfectMixture::GetSpeciesFromLTE(double *conserv, double *primit, TableInt primit[iTh] = T; } -void PerfectMixture::GetSpeciesFromLTE(const double T, const double p, double *n_sp) { +void PerfectMixture::GetSpeciesFromLTE(const double T, const double p, double* n_sp) { // This routine makes the following assumptions: // // 1) There is only 1 charged specie and it is a positive ion with diff --git a/src/equation_of_state.hpp b/src/equation_of_state.hpp index a2796577..2f0d2ab9 100644 --- a/src/equation_of_state.hpp +++ b/src/equation_of_state.hpp @@ -146,7 +146,7 @@ class GasMixture { } public: - GasMixture(RunConfiguration &_runfile, int _dim, int nvel); + GasMixture(RunConfiguration& _runfile, int _dim, int nvel); MFEM_HOST_DEVICE GasMixture(WorkingFluid f, int _dim, int nvel, double pc = 0); GasMixture() {} @@ -181,20 +181,20 @@ class GasMixture { int GetNumConservativeVariables() { return Nconservative; } int GetNumPrimitiveVariables() { return Nprimitive; } - virtual double ComputePressure(const Vector &state, - double *electronPressure = NULL) = 0; // pressure from conservatives - MFEM_HOST_DEVICE virtual double ComputePressure(const double *state, double *electronPressure = NULL) { + virtual double ComputePressure(const Vector& state, + double* electronPressure = NULL) = 0; // pressure from conservatives + MFEM_HOST_DEVICE virtual double ComputePressure(const double* state, double* electronPressure = NULL) { printf("ComputePressure not implemented"); return 0; } - virtual double ComputePressureFromPrimitives(const Vector &Up) = 0; // pressure from primitive variables - MFEM_HOST_DEVICE virtual double ComputePressureFromPrimitives(const double *Up) { + virtual double ComputePressureFromPrimitives(const Vector& Up) = 0; // pressure from primitive variables + MFEM_HOST_DEVICE virtual double ComputePressureFromPrimitives(const double* Up) { // mfem_error("ComputePressureFromPrimitives is not implemented."); return -1.0; } - virtual double ComputeTemperature(const Vector &state) = 0; - MFEM_HOST_DEVICE virtual double ComputeTemperature(const double *state) { + virtual double ComputeTemperature(const Vector& state) = 0; + MFEM_HOST_DEVICE virtual double ComputeTemperature(const double* state) { // mfem_error("ComputeTemperature is not implemented."); return -1.0; } @@ -202,53 +202,53 @@ class GasMixture { // virtual double Temperature(double *rho, double *p, // int nsp) = 0; // temperature given densities and pressures of all species - virtual void computeSpeciesPrimitives(const Vector &conservedState, Vector &X_sp, Vector &Y_sp, Vector &n_sp) { + virtual void computeSpeciesPrimitives(const Vector& conservedState, Vector& X_sp, Vector& Y_sp, Vector& n_sp) { mfem_error("computeSpeciesPrimitives not implemented"); } - MFEM_HOST_DEVICE virtual void computeSpeciesPrimitives(const double *conservedState, double *X_sp, double *Y_sp, - double *n_sp) { + MFEM_HOST_DEVICE virtual void computeSpeciesPrimitives(const double* conservedState, double* X_sp, double* Y_sp, + double* n_sp) { printf("ERROR: computeSpeciesPrimitives is not implemented!\n"); assert(false); // device-compatible exit? } - virtual void computeSpeciesEnthalpies(const Vector &state, Vector &speciesEnthalpies) = 0; - MFEM_HOST_DEVICE virtual void computeSpeciesEnthalpies(const double *state, double *speciesEnthalpies) = 0; + virtual void computeSpeciesEnthalpies(const Vector& state, Vector& speciesEnthalpies) = 0; + MFEM_HOST_DEVICE virtual void computeSpeciesEnthalpies(const double* state, double* speciesEnthalpies) = 0; - virtual void GetPrimitivesFromConservatives(const Vector &conserv, Vector &primit) = 0; - virtual void GetConservativesFromPrimitives(const Vector &primit, Vector &conserv) = 0; + virtual void GetPrimitivesFromConservatives(const Vector& conserv, Vector& primit) = 0; + virtual void GetConservativesFromPrimitives(const Vector& primit, Vector& conserv) = 0; - MFEM_HOST_DEVICE virtual void GetPrimitivesFromConservatives(const double *conserv, double *primit) { + MFEM_HOST_DEVICE virtual void GetPrimitivesFromConservatives(const double* conserv, double* primit) { printf("GetPrimitivesFromConservatives is not implemented."); return; } - MFEM_HOST_DEVICE virtual void GetConservativesFromPrimitives(const double *primit, double *conserv) { + MFEM_HOST_DEVICE virtual void GetConservativesFromPrimitives(const double* primit, double* conserv) { printf("GetPrimitivesFromConservatives is not implemented."); return; } - virtual double ComputeSpeedOfSound(const Vector &Uin, bool primitive = true) = 0; + virtual double ComputeSpeedOfSound(const Vector& Uin, bool primitive = true) = 0; // Compute the maximum characteristic speed. - virtual double ComputeMaxCharSpeed(const Vector &state) = 0; - MFEM_HOST_DEVICE virtual double ComputeMaxCharSpeed(const double *state) { + virtual double ComputeMaxCharSpeed(const Vector& state) = 0; + MFEM_HOST_DEVICE virtual double ComputeMaxCharSpeed(const double* state) { printf("ComputeMaxCharSpeed not implemented"); return 0; } - virtual double ComputePressureDerivative(const Vector &dUp_dx, const Vector &Uin, bool primitive = true) = 0; + virtual double ComputePressureDerivative(const Vector& dUp_dx, const Vector& Uin, bool primitive = true) = 0; // Physicality check (at end) - virtual bool StateIsPhysical(const Vector &state) = 0; + virtual bool StateIsPhysical(const Vector& state) = 0; // Compute X, Y gradients from number density gradient. // NOTE(kevin): for axisymmetric case, these handle only r- and z-direction. - virtual void ComputeMassFractionGradient(const double rho, const Vector &numberDensities, const DenseMatrix &gradUp, - DenseMatrix &massFractionGrad) = 0; - virtual void ComputeMoleFractionGradient(const Vector &numberDensities, const DenseMatrix &gradUp, - DenseMatrix &moleFractionGrad) = 0; - MFEM_HOST_DEVICE virtual void ComputeMoleFractionGradient(const double *numberDensities, const double *gradUp, - double *moleFractionGrad) = 0; + virtual void ComputeMassFractionGradient(const double rho, const Vector& numberDensities, const DenseMatrix& gradUp, + DenseMatrix& massFractionGrad) = 0; + virtual void ComputeMoleFractionGradient(const Vector& numberDensities, const DenseMatrix& gradUp, + DenseMatrix& moleFractionGrad) = 0; + MFEM_HOST_DEVICE virtual void ComputeMoleFractionGradient(const double* numberDensities, const double* gradUp, + double* moleFractionGrad) = 0; // TODO(kevin): Compute pressure gradient from temperature gradient. - virtual void ComputePressureGradient(const Vector &state, const DenseMatrix &gradUp, DenseMatrix &PressureGrad) { + virtual void ComputePressureGradient(const Vector& state, const DenseMatrix& gradUp, DenseMatrix& PressureGrad) { mfem_error("ComputePressureGradient not implemented"); } @@ -264,13 +264,13 @@ class GasMixture { virtual double GetGasConstant() = 0; #endif - virtual void computeNumberDensities(const Vector &conservedState, Vector &n_sp) { + virtual void computeNumberDensities(const Vector& conservedState, Vector& n_sp) { mfem::mfem_error("GasMixture::computeNumberDensities not implemented"); } - void SetConstantPlasmaConductivity(ParGridFunction *pc, const ParGridFunction *Up, const ParGridFunction *coords); + void SetConstantPlasmaConductivity(ParGridFunction* pc, const ParGridFunction* Up, const ParGridFunction* coords); - virtual void UpdatePressureGridFunction(ParGridFunction *press, const ParGridFunction *Up); + virtual void UpdatePressureGridFunction(ParGridFunction* press, const ParGridFunction* Up); // TODO(kevin): GPU routines are not yet fully gas-agnostic. Need to be removed. #ifdef _GPU_ @@ -290,15 +290,15 @@ class GasMixture { } // BC related functions - virtual void computeStagnationState(const Vector &stateIn, Vector &stagnationState); - virtual void computeStagnantStateWithTemp(const Vector &stateIn, const double Temp, Vector &stateOut) { + virtual void computeStagnationState(const Vector& stateIn, Vector& stagnationState); + virtual void computeStagnantStateWithTemp(const Vector& stateIn, const double Temp, Vector& stateOut) { mfem_error("computeStagnantStateWithTemp not implemented"); } - virtual void modifyEnergyForPressure(const Vector &stateIn, Vector &stateOut, const double &p, + virtual void modifyEnergyForPressure(const Vector& stateIn, Vector& stateOut, const double& p, bool modifyElectronEnergy = false) { mfem_error("modifyEnergyForPressure not implemented"); } - MFEM_HOST_DEVICE virtual void modifyEnergyForPressure(const double *stateIn, double *stateOut, const double &p, + MFEM_HOST_DEVICE virtual void modifyEnergyForPressure(const double* stateIn, double* stateOut, const double& p, bool modifyElectronEnergy = false) { // mfem_error("modifyEnergyForPressure not implemented"); return; @@ -306,11 +306,11 @@ class GasMixture { // Modify state with a prescribed condition at boundary. // TODO(kevin): it is possible to use this routine for all BCs, so no need of making so many functions as above. - void modifyStateFromPrimitive(const Vector &state, const BoundaryPrimitiveData &bcState, Vector &outputState); - MFEM_HOST_DEVICE void modifyStateFromPrimitive(const double *state, const BoundaryPrimitiveData &bcState, - double *outputState); - virtual void computeSheathBdrFlux(const Vector &state, BoundaryViscousFluxData &bcFlux) = 0; - MFEM_HOST_DEVICE virtual void computeSheathBdrFlux(const double *state, BoundaryViscousFluxData &bcFlux) { + void modifyStateFromPrimitive(const Vector& state, const BoundaryPrimitiveData& bcState, Vector& outputState); + MFEM_HOST_DEVICE void modifyStateFromPrimitive(const double* state, const BoundaryPrimitiveData& bcState, + double* outputState); + virtual void computeSheathBdrFlux(const Vector& state, BoundaryViscousFluxData& bcFlux) = 0; + MFEM_HOST_DEVICE virtual void computeSheathBdrFlux(const double* state, BoundaryViscousFluxData& bcFlux) { // mfem_error("computeSheathBdrFlux is not implemented"); return; } @@ -326,26 +326,26 @@ class GasMixture { // } // TODO(kevin): check if this works for axisymmetric case. - virtual void computeConservedStateFromConvectiveFlux(const Vector &meanNormalFluxes, const Vector &normal, - Vector &conservedState) { + virtual void computeConservedStateFromConvectiveFlux(const Vector& meanNormalFluxes, const Vector& normal, + Vector& conservedState) { mfem_error("computeConservedStateFromConvectiveFlux not implemented"); } virtual double computeElectronEnergy(const double n_e, const double T_e) = 0; virtual double computeElectronPressure(const double n_e, const double T_e) = 0; // NOTE(kevin): for axisymmetric case, this handles only r- and z-direction. - virtual void computeElectronPressureGrad(const double n_e, const double T_e, const DenseMatrix &gradUp, - Vector &gradPe) = 0; - MFEM_HOST_DEVICE virtual void computeElectronPressureGrad(const double n_e, const double T_e, const double *gradUp, - double *gradPe) = 0; - - virtual void GetSpeciesFromLTE(double *conserv, double *primit, TableInterpolator2D *energy_table, - TableInterpolator2D *R_table, TableInterpolator2D *c_table, - TableInterpolator2D *T_table) { + virtual void computeElectronPressureGrad(const double n_e, const double T_e, const DenseMatrix& gradUp, + Vector& gradPe) = 0; + MFEM_HOST_DEVICE virtual void computeElectronPressureGrad(const double n_e, const double T_e, const double* gradUp, + double* gradPe) = 0; + + virtual void GetSpeciesFromLTE(double* conserv, double* primit, TableInterpolator2D* energy_table, + TableInterpolator2D* R_table, TableInterpolator2D* c_table, + TableInterpolator2D* T_table) { printf("GetSpeciesFromLTE is not implemented."); return; } - virtual void GetSpeciesFromLTE(const double T, const double p, double *n_sp) { + virtual void GetSpeciesFromLTE(const double T, const double p, double* n_sp) { printf("GetSpeciesFromLTE is not implemented."); return; } @@ -363,7 +363,7 @@ class DryAir : public GasMixture { virtual void setNumEquations(); public: - DryAir(RunConfiguration &_runfile, int _dim, int nvel); + DryAir(RunConfiguration& _runfile, int _dim, int nvel); // MFEM_HOST_DEVICE DryAir(const WorkingFluid f, const Equations eq_sys, const double viscosity_multiplier, // const double bulk_viscosity, int _dim, int nvel); MFEM_HOST_DEVICE DryAir(const DryAirInput inputs, int _dim, int nvel); @@ -378,47 +378,47 @@ class DryAir : public GasMixture { } // implementation virtual methods - virtual double ComputePressure(const Vector &state, double *electronPressure = NULL); - MFEM_HOST_DEVICE virtual double ComputePressure(const double *state, double *electronPressure = NULL); + virtual double ComputePressure(const Vector& state, double* electronPressure = NULL); + MFEM_HOST_DEVICE virtual double ComputePressure(const double* state, double* electronPressure = NULL); - virtual double ComputePressureFromPrimitives(const Vector &Up); - MFEM_HOST_DEVICE virtual double ComputePressureFromPrimitives(const double *Up); - virtual double ComputeTemperature(const Vector &state); - MFEM_HOST_DEVICE virtual double ComputeTemperature(const double *state); + virtual double ComputePressureFromPrimitives(const Vector& Up); + MFEM_HOST_DEVICE virtual double ComputePressureFromPrimitives(const double* Up); + virtual double ComputeTemperature(const Vector& state); + MFEM_HOST_DEVICE virtual double ComputeTemperature(const double* state); // virtual double Temperature(double *rho, double *p, int nsp = 1) { return p[0] / gas_constant / rho[0]; } - virtual void computeSpeciesEnthalpies(const Vector &state, Vector &speciesEnthalpies); - MFEM_HOST_DEVICE virtual void computeSpeciesEnthalpies(const double *state, double *speciesEnthalpies); + virtual void computeSpeciesEnthalpies(const Vector& state, Vector& speciesEnthalpies); + MFEM_HOST_DEVICE virtual void computeSpeciesEnthalpies(const double* state, double* speciesEnthalpies); - virtual void GetPrimitivesFromConservatives(const Vector &conserv, Vector &primit); - MFEM_HOST_DEVICE virtual void GetPrimitivesFromConservatives(const double *conserv, double *primit); - virtual void GetConservativesFromPrimitives(const Vector &primit, Vector &conserv); - MFEM_HOST_DEVICE virtual void GetConservativesFromPrimitives(const double *primit, double *conserv); + virtual void GetPrimitivesFromConservatives(const Vector& conserv, Vector& primit); + MFEM_HOST_DEVICE virtual void GetPrimitivesFromConservatives(const double* conserv, double* primit); + virtual void GetConservativesFromPrimitives(const Vector& primit, Vector& conserv); + MFEM_HOST_DEVICE virtual void GetConservativesFromPrimitives(const double* primit, double* conserv); - virtual double ComputeSpeedOfSound(const Vector &Uin, bool primitive = true); + virtual double ComputeSpeedOfSound(const Vector& Uin, bool primitive = true); // Compute the maximum characteristic speed. - virtual double ComputeMaxCharSpeed(const Vector &state); - MFEM_HOST_DEVICE virtual double ComputeMaxCharSpeed(const double *state); + virtual double ComputeMaxCharSpeed(const Vector& state); + MFEM_HOST_DEVICE virtual double ComputeMaxCharSpeed(const double* state); - virtual double ComputePressureDerivative(const Vector &dUp_dx, const Vector &Uin, bool primitive = true); + virtual double ComputePressureDerivative(const Vector& dUp_dx, const Vector& Uin, bool primitive = true); // Physicality check (at end) - virtual bool StateIsPhysical(const Vector &state); + virtual bool StateIsPhysical(const Vector& state); MFEM_HOST_DEVICE virtual double GetSpecificHeatRatio() { return specific_heat_ratio; } MFEM_HOST_DEVICE virtual double GetGasConstant() { return gas_constant; } - virtual void ComputeMassFractionGradient(const double rho, const Vector &numberDensities, const DenseMatrix &gradUp, - DenseMatrix &massFractionGrad) { + virtual void ComputeMassFractionGradient(const double rho, const Vector& numberDensities, const DenseMatrix& gradUp, + DenseMatrix& massFractionGrad) { mfem_error("computeMassFractionGradient not implemented"); } - virtual void ComputeMoleFractionGradient(const Vector &numberDensities, const DenseMatrix &gradUp, - DenseMatrix &moleFractionGrad) { + virtual void ComputeMoleFractionGradient(const Vector& numberDensities, const DenseMatrix& gradUp, + DenseMatrix& moleFractionGrad) { mfem_error("computeMoleFractionGradient not implemented"); } - MFEM_HOST_DEVICE virtual void ComputeMoleFractionGradient(const double *numberDensities, const double *gradUp, - double *moleFractionGrad) { + MFEM_HOST_DEVICE virtual void ComputeMoleFractionGradient(const double* numberDensities, const double* gradUp, + double* moleFractionGrad) { printf("computeMoleFractionGradient not implemented"); assert(false); } @@ -426,23 +426,23 @@ class DryAir : public GasMixture { // virtual void UpdatePressureGridFunction(ParGridFunction *press, const ParGridFunction *Up); // BC related functions - virtual void computeStagnationState(const Vector &stateIn, Vector &stagnationState); - virtual void computeStagnantStateWithTemp(const Vector &stateIn, const double Temp, Vector &stateOut); - virtual void modifyEnergyForPressure(const Vector &stateIn, Vector &stateOut, const double &p, + virtual void computeStagnationState(const Vector& stateIn, Vector& stagnationState); + virtual void computeStagnantStateWithTemp(const Vector& stateIn, const double Temp, Vector& stateOut); + virtual void modifyEnergyForPressure(const Vector& stateIn, Vector& stateOut, const double& p, bool modifyElectronEnergy = false); - MFEM_HOST_DEVICE virtual void modifyEnergyForPressure(const double *stateIn, double *stateOut, const double &p, + MFEM_HOST_DEVICE virtual void modifyEnergyForPressure(const double* stateIn, double* stateOut, const double& p, bool modifyElectronEnergy = false); - virtual void computeSheathBdrFlux(const Vector &state, BoundaryViscousFluxData &bcFlux) { + virtual void computeSheathBdrFlux(const Vector& state, BoundaryViscousFluxData& bcFlux) { mfem_error("computeSheathBdrFlux not implemented"); } - MFEM_HOST_DEVICE virtual void computeSheathBdrFlux(const double *state, BoundaryViscousFluxData &bcFlux) { + MFEM_HOST_DEVICE virtual void computeSheathBdrFlux(const double* state, BoundaryViscousFluxData& bcFlux) { printf("ERROR: computeSheathBdrFlux is not supposed to be executed for DryAir!"); return; } - virtual void computeConservedStateFromConvectiveFlux(const Vector &meanNormalFluxes, const Vector &normal, - Vector &conservedState); + virtual void computeConservedStateFromConvectiveFlux(const Vector& meanNormalFluxes, const Vector& normal, + Vector& conservedState); virtual double computeElectronEnergy(const double n_e, const double T_e) { mfem_error("computeElectronEnergy not implemented"); @@ -452,39 +452,39 @@ class DryAir : public GasMixture { mfem_error("computeElectronPressure not implemented"); return 0; } - virtual void computeElectronPressureGrad(const double n_e, const double T_e, const DenseMatrix &gradUp, - Vector &gradPe) { + virtual void computeElectronPressureGrad(const double n_e, const double T_e, const DenseMatrix& gradUp, + Vector& gradPe) { mfem_error("computeElectronPressureGrad not implemented"); } - MFEM_HOST_DEVICE virtual void computeElectronPressureGrad(const double n_e, const double T_e, const double *gradUp, - double *gradPe) { + MFEM_HOST_DEVICE virtual void computeElectronPressureGrad(const double n_e, const double T_e, const double* gradUp, + double* gradPe) { printf("computeElectronPressureGrad not implemented"); } // GPU functions // TODO(kevin): GPU part is not refactored for axisymmetric case. #ifdef _GPU_ - static MFEM_HOST_DEVICE double pressure(const double *state, double *KE, const double &gamma, const int &dim, - const int &num_equation) { + static MFEM_HOST_DEVICE double pressure(const double* state, double* KE, const double& gamma, const int& dim, + const int& num_equation) { double p = 0.; for (int k = 0; k < dim; k++) p += KE[k]; return (gamma - 1.) * (state[1 + dim] - p); } - static MFEM_HOST_DEVICE double ComputePressureFromPrimitives_gpu(const double *Up, const double &Rg, const int &dim) { + static MFEM_HOST_DEVICE double ComputePressureFromPrimitives_gpu(const double* Up, const double& Rg, const int& dim) { return Up[0] * Rg * Up[1 + dim]; } - static MFEM_HOST_DEVICE double temperature(const double *state, double *KE, const double &gamma, const double &Rgas, - const int &dim, const int &num_equation) { + static MFEM_HOST_DEVICE double temperature(const double* state, double* KE, const double& gamma, const double& Rgas, + const int& dim, const int& num_equation) { double temp = 0.; for (int k = 0; k < dim; k++) temp += KE[k]; temp /= state[0]; return (gamma - 1.0) / Rgas * (state[1 + dim] / state[0] - temp); } - static MFEM_HOST_DEVICE double temperatureFromConservative(const double *u, const double &gamma, const double &Rg, - const int &dim, const int &num_equation) { + static MFEM_HOST_DEVICE double temperatureFromConservative(const double* u, const double& gamma, const double& Rg, + const int& dim, const int& num_equation) { double k = 0.; for (int d = 0; d < dim; d++) k += u[1 + d] * u[1 + d]; k /= u[0] * u[0]; @@ -492,38 +492,38 @@ class DryAir : public GasMixture { } // Sutherland's law - static MFEM_HOST_DEVICE double GetViscosity_gpu(const double &temp) { + static MFEM_HOST_DEVICE double GetViscosity_gpu(const double& temp) { return 1.458e-6 * pow(temp, 1.5) / (temp + 110.4); } - static MFEM_HOST_DEVICE double GetThermalConductivity_gpu(const double &visc, const double &gamma, const double &Rg, - const double &Pr) { + static MFEM_HOST_DEVICE double GetThermalConductivity_gpu(const double& visc, const double& gamma, const double& Rg, + const double& Pr) { const double cp = gamma * Rg / (gamma - 1.); return visc * cp / Pr; } - static MFEM_HOST_DEVICE void computeStagnantStateWithTemp_gpu(const double *stateIn, double *stagState, - const double &Temp, const double &gamma, - const double &Rg, const int &num_equation, - const int &dim, const int &thrd, - const int &maxThreads) { + static MFEM_HOST_DEVICE void computeStagnantStateWithTemp_gpu(const double* stateIn, double* stagState, + const double& Temp, const double& gamma, + const double& Rg, const int& num_equation, + const int& dim, const int& thrd, + const int& maxThreads) { if (thrd > 0 && thrd <= dim) stagState[thrd] = 0.; if (thrd == 1 + dim) stagState[thrd] = Rg / (gamma - 1.) * stateIn[0] * Temp; } - static MFEM_HOST_DEVICE void computeStagnantStateWithTemp_gpu_serial(const double *stateIn, double *stagState, - const double &Temp, const double &gamma, - const double &Rg, const int &num_equation, - const int &dim) { + static MFEM_HOST_DEVICE void computeStagnantStateWithTemp_gpu_serial(const double* stateIn, double* stagState, + const double& Temp, const double& gamma, + const double& Rg, const int& num_equation, + const int& dim) { for (int d = 0; d < dim; d++) stagState[1 + d] = 0.; stagState[1 + dim] = Rg / (gamma - 1.) * stateIn[0] * Temp; } - static MFEM_HOST_DEVICE void modifyEnergyForPressure_gpu(const double *stateIn, double *stateOut, const double &p, - const double &gamma, const double &Rg, - const int &num_equation, const int &dim, const int &thrd, - const int &maxThreads) { + static MFEM_HOST_DEVICE void modifyEnergyForPressure_gpu(const double* stateIn, double* stateOut, const double& p, + const double& gamma, const double& Rg, + const int& num_equation, const int& dim, const int& thrd, + const int& maxThreads) { MFEM_SHARED double ke; if (thrd == maxThreads - 1) { ke = 0.; @@ -536,10 +536,10 @@ class DryAir : public GasMixture { if (thrd == 0) stateOut[1 + dim] = p / (gamma - 1.) + ke; } - static MFEM_HOST_DEVICE void modifyEnergyForPressure_gpu_serial(const double *stateIn, double *stateOut, - const double &p, const double &gamma, - const double &Rg, const int &num_equation, - const int &dim) { + static MFEM_HOST_DEVICE void modifyEnergyForPressure_gpu_serial(const double* stateIn, double* stateOut, + const double& p, const double& gamma, + const double& Rg, const int& num_equation, + const int& dim) { double ke; ke = 0.; for (int d = 0; d < dim; d++) ke += stateIn[1 + d] * stateIn[1 + d]; @@ -602,12 +602,12 @@ class DryAir : public GasMixture { // }; // additional functions inlined for speed... -inline double DryAir::ComputePressure(const Vector &state, double *electronPressure) { +inline double DryAir::ComputePressure(const Vector& state, double* electronPressure) { return ComputePressure(state.GetData(), electronPressure); } // additional functions inlined for speed... -MFEM_HOST_DEVICE inline double DryAir::ComputePressure(const double *state, double *electronPressure) { +MFEM_HOST_DEVICE inline double DryAir::ComputePressure(const double* state, double* electronPressure) { if (electronPressure != NULL) *electronPressure = 0.0; double den_vel2 = 0; for (int d = 0; d < nvel_; d++) den_vel2 += state[d + 1] * state[d + 1]; @@ -616,9 +616,9 @@ MFEM_HOST_DEVICE inline double DryAir::ComputePressure(const double *state, doub return (specific_heat_ratio - 1.0) * (state[1 + nvel_] - 0.5 * den_vel2); } -inline double DryAir::ComputeTemperature(const Vector &state) { return ComputeTemperature(state.GetData()); } +inline double DryAir::ComputeTemperature(const Vector& state) { return ComputeTemperature(state.GetData()); } -MFEM_HOST_DEVICE inline double DryAir::ComputeTemperature(const double *state) { +MFEM_HOST_DEVICE inline double DryAir::ComputeTemperature(const double* state) { double den_vel2 = 0; for (int d = 0; d < nvel_; d++) den_vel2 += state[d + 1] * state[d + 1]; den_vel2 /= state[0]; @@ -648,7 +648,7 @@ class PerfectMixture : public GasMixture { // virtual void SetNumEquations(); public: - PerfectMixture(RunConfiguration &_runfile, int _dim, int nvel); + PerfectMixture(RunConfiguration& _runfile, int _dim, int nvel); MFEM_HOST_DEVICE PerfectMixture(const PerfectMixtureInput inputs, int _dim, int nvel, double pc = 0); // FIXME: Generates compiler warning b/c this dtor implicitly calls @@ -671,104 +671,104 @@ class PerfectMixture : public GasMixture { MFEM_HOST_DEVICE virtual double GetSpecificHeatRatio() { return molarCP_[iBackground] / molarCV_[iBackground]; } MFEM_HOST_DEVICE virtual double GetGasConstant() { return specificGasConstants_[iBackground]; } - MFEM_HOST_DEVICE double computeHeaviesHeatCapacity(const double *n_sp, const double &nB) const; - MFEM_HOST_DEVICE double computeHeaviesCp(const double *n_sp, const double &nB) const; - MFEM_HOST_DEVICE double computeSpeciesCp(const double *n_sp, const double &nB, int sp); - MFEM_HOST_DEVICE double computeAmbipolarElectronNumberDensity(const double *n_sp) const; - MFEM_HOST_DEVICE double computeBackgroundMassDensity(const double &rho, const double *n_sp, double &n_e, + MFEM_HOST_DEVICE double computeHeaviesHeatCapacity(const double* n_sp, const double& nB) const; + MFEM_HOST_DEVICE double computeHeaviesCp(const double* n_sp, const double& nB) const; + MFEM_HOST_DEVICE double computeSpeciesCp(const double* n_sp, const double& nB, int sp); + MFEM_HOST_DEVICE double computeAmbipolarElectronNumberDensity(const double* n_sp) const; + MFEM_HOST_DEVICE double computeBackgroundMassDensity(const double& rho, const double* n_sp, double& n_e, bool isElectronComputed = false) const; - virtual void GetPrimitivesFromConservatives(const Vector &conserv, Vector &primit); - virtual void GetConservativesFromPrimitives(const Vector &primit, Vector &conserv); + virtual void GetPrimitivesFromConservatives(const Vector& conserv, Vector& primit); + virtual void GetConservativesFromPrimitives(const Vector& primit, Vector& conserv); - MFEM_HOST_DEVICE virtual void GetPrimitivesFromConservatives(const double *conserv, double *primit); - MFEM_HOST_DEVICE virtual void GetConservativesFromPrimitives(const double *primit, double *conserv); + MFEM_HOST_DEVICE virtual void GetPrimitivesFromConservatives(const double* conserv, double* primit); + MFEM_HOST_DEVICE virtual void GetConservativesFromPrimitives(const double* primit, double* conserv); - virtual void GetMixtureCp(const Vector &ns, const double &rho, double &CpMix); - MFEM_HOST_DEVICE virtual void GetMixtureCp(const double *ns, const double *rho, double *CpMix); + virtual void GetMixtureCp(const Vector& ns, const double& rho, double& CpMix); + MFEM_HOST_DEVICE virtual void GetMixtureCp(const double* ns, const double* rho, double* CpMix); - virtual void GetSpeciesCp(const Vector &ns, const double &rho, int sp, double &CpY); - MFEM_HOST_DEVICE virtual void GetSpeciesCp(const double *ns, const double *rho, int sp, double *CpY); + virtual void GetSpeciesCp(const Vector& ns, const double& rho, int sp, double& CpY); + MFEM_HOST_DEVICE virtual void GetSpeciesCp(const double* ns, const double* rho, int sp, double* CpY); - virtual void computeSpeciesPrimitives(const Vector &conservedState, Vector &X_sp, Vector &Y_sp, Vector &n_sp); - MFEM_HOST_DEVICE virtual void computeSpeciesPrimitives(const double *conservedState, double *X_sp, double *Y_sp, - double *n_sp); - virtual void computeNumberDensities(const Vector &conservedState, Vector &n_sp); - MFEM_HOST_DEVICE void computeNumberDensities(const double *conservedState, double *n_sp) const; + virtual void computeSpeciesPrimitives(const Vector& conservedState, Vector& X_sp, Vector& Y_sp, Vector& n_sp); + MFEM_HOST_DEVICE virtual void computeSpeciesPrimitives(const double* conservedState, double* X_sp, double* Y_sp, + double* n_sp); + virtual void computeNumberDensities(const Vector& conservedState, Vector& n_sp); + MFEM_HOST_DEVICE void computeNumberDensities(const double* conservedState, double* n_sp) const; - virtual double ComputePressure(const Vector &state, double *electronPressure = NULL); - MFEM_HOST_DEVICE virtual double ComputePressure(const double *state, double *electronPressure = NULL); - virtual double ComputePressureFromPrimitives(const Vector &Up); - MFEM_HOST_DEVICE virtual double ComputePressureFromPrimitives(const double *Up); - MFEM_HOST_DEVICE virtual double computePressureBase(const double *n_sp, const double n_e, const double n_B, + virtual double ComputePressure(const Vector& state, double* electronPressure = NULL); + MFEM_HOST_DEVICE virtual double ComputePressure(const double* state, double* electronPressure = NULL); + virtual double ComputePressureFromPrimitives(const Vector& Up); + MFEM_HOST_DEVICE virtual double ComputePressureFromPrimitives(const double* Up); + MFEM_HOST_DEVICE virtual double computePressureBase(const double* n_sp, const double n_e, const double n_B, const double T_h, const double T_e) const; // Physicality check (at end) - virtual bool StateIsPhysical(const Vector &state); + virtual bool StateIsPhysical(const Vector& state); - virtual double ComputeTemperature(const Vector &state); - MFEM_HOST_DEVICE virtual double ComputeTemperature(const double *state); - MFEM_HOST_DEVICE virtual void computeTemperaturesBase(const double *conservedState, const double *n_sp, - const double n_e, const double n_B, double &T_h, - double &T_e) const; + virtual double ComputeTemperature(const Vector& state); + MFEM_HOST_DEVICE virtual double ComputeTemperature(const double* state); + MFEM_HOST_DEVICE virtual void computeTemperaturesBase(const double* conservedState, const double* n_sp, + const double n_e, const double n_B, double& T_h, + double& T_e) const; - virtual void computeSpeciesEnthalpies(const Vector &state, Vector &speciesEnthalpies); - MFEM_HOST_DEVICE virtual void computeSpeciesEnthalpies(const double *state, double *speciesEnthalpies); + virtual void computeSpeciesEnthalpies(const Vector& state, Vector& speciesEnthalpies); + MFEM_HOST_DEVICE virtual void computeSpeciesEnthalpies(const double* state, double* speciesEnthalpies); // TODO(kevin): Kevin - I don't think we should use this for boundary condition. // virtual double Temperature(double *rho, double *p, int nsp = 1) { return p[0] / rho[0] / GetGasConstant(); } - virtual double ComputePressureDerivative(const Vector &dUp_dx, const Vector &Uin, bool primitive = true); - virtual double computePressureDerivativeFromPrimitives(const Vector &dUp_dx, const Vector &Uin); - virtual double computePressureDerivativeFromConservatives(const Vector &dUp_dx, const Vector &Uin); + virtual double ComputePressureDerivative(const Vector& dUp_dx, const Vector& Uin, bool primitive = true); + virtual double computePressureDerivativeFromPrimitives(const Vector& dUp_dx, const Vector& Uin); + virtual double computePressureDerivativeFromConservatives(const Vector& dUp_dx, const Vector& Uin); // virtual void UpdatePressureGridFunction(ParGridFunction *press, const ParGridFunction *Up); // Compute the maximum characteristic speed. - virtual double ComputeMaxCharSpeed(const Vector &state); - MFEM_HOST_DEVICE virtual double ComputeMaxCharSpeed(const double *state); + virtual double ComputeMaxCharSpeed(const Vector& state); + MFEM_HOST_DEVICE virtual double ComputeMaxCharSpeed(const double* state); - virtual double ComputeSpeedOfSound(const Vector &Uin, bool primitive = true); - MFEM_HOST_DEVICE virtual double ComputeSpeedOfSound(const double *Uin, bool primitive = true) const; - MFEM_HOST_DEVICE double computeSpeedOfSoundBase(const double *n_sp, const double n_B, const double rho, + virtual double ComputeSpeedOfSound(const Vector& Uin, bool primitive = true); + MFEM_HOST_DEVICE virtual double ComputeSpeedOfSound(const double* Uin, bool primitive = true) const; + MFEM_HOST_DEVICE double computeSpeedOfSoundBase(const double* n_sp, const double n_B, const double rho, const double p) const; - MFEM_HOST_DEVICE double computeHeaviesMixtureCV(const double *n_sp, const double n_B) const; - MFEM_HOST_DEVICE double computeHeaviesMixtureHeatRatio(const double *n_sp, const double n_B) const; + MFEM_HOST_DEVICE double computeHeaviesMixtureCV(const double* n_sp, const double n_B) const; + MFEM_HOST_DEVICE double computeHeaviesMixtureHeatRatio(const double* n_sp, const double n_B) const; - virtual void ComputeMassFractionGradient(const double rho, const Vector &numberDensities, const DenseMatrix &gradUp, - DenseMatrix &massFractionGrad); - virtual void ComputeMoleFractionGradient(const Vector &numberDensities, const DenseMatrix &gradUp, - DenseMatrix &moleFractionGrad); - MFEM_HOST_DEVICE virtual void ComputeMoleFractionGradient(const double *numberDensities, const double *gradUp, - double *moleFractionGrad); + virtual void ComputeMassFractionGradient(const double rho, const Vector& numberDensities, const DenseMatrix& gradUp, + DenseMatrix& massFractionGrad); + virtual void ComputeMoleFractionGradient(const Vector& numberDensities, const DenseMatrix& gradUp, + DenseMatrix& moleFractionGrad); + MFEM_HOST_DEVICE virtual void ComputeMoleFractionGradient(const double* numberDensities, const double* gradUp, + double* moleFractionGrad); // functions needed for BCs - virtual void computeStagnantStateWithTemp(const Vector &stateIn, const double Temp, Vector &stateOut); - virtual void modifyEnergyForPressure(const Vector &stateIn, Vector &stateOut, const double &p, + virtual void computeStagnantStateWithTemp(const Vector& stateIn, const double Temp, Vector& stateOut); + virtual void modifyEnergyForPressure(const Vector& stateIn, Vector& stateOut, const double& p, bool modifyElectronEnergy = false); - MFEM_HOST_DEVICE virtual void modifyEnergyForPressure(const double *stateIn, double *stateOut, const double &p, + MFEM_HOST_DEVICE virtual void modifyEnergyForPressure(const double* stateIn, double* stateOut, const double& p, bool modifyElectronEnergy = false); - virtual void computeSheathBdrFlux(const Vector &state, BoundaryViscousFluxData &bcFlux); - MFEM_HOST_DEVICE virtual void computeSheathBdrFlux(const double *state, BoundaryViscousFluxData &bcFlux); + virtual void computeSheathBdrFlux(const Vector& state, BoundaryViscousFluxData& bcFlux); + MFEM_HOST_DEVICE virtual void computeSheathBdrFlux(const double* state, BoundaryViscousFluxData& bcFlux); - virtual void computeConservedStateFromConvectiveFlux(const Vector &meanNormalFluxes, const Vector &normal, - Vector &conservedState); + virtual void computeConservedStateFromConvectiveFlux(const Vector& meanNormalFluxes, const Vector& normal, + Vector& conservedState); virtual double computeElectronEnergy(const double n_e, const double T_e) { return n_e * molarCV_[iElectron] * T_e; } virtual double computeElectronPressure(const double n_e, const double T_e) { return n_e * UNIVERSALGASCONSTANT * T_e; } - virtual void computeElectronPressureGrad(const double n_e, const double T_e, const DenseMatrix &gradUp, - Vector &gradPe); - MFEM_HOST_DEVICE virtual void computeElectronPressureGrad(const double n_e, const double T_e, const double *gradUp, - double *gradPe); + virtual void computeElectronPressureGrad(const double n_e, const double T_e, const DenseMatrix& gradUp, + Vector& gradPe); + MFEM_HOST_DEVICE virtual void computeElectronPressureGrad(const double n_e, const double T_e, const double* gradUp, + double* gradPe); // Compute species mass densities based on LTE assumptions. - virtual void GetSpeciesFromLTE(double *conserv, double *primit, TableInterpolator2D *energy_table, - TableInterpolator2D *R_table, TableInterpolator2D *c_table, - TableInterpolator2D *T_table); - virtual void GetSpeciesFromLTE(const double T, const double p, double *n_sp); + virtual void GetSpeciesFromLTE(double* conserv, double* primit, TableInterpolator2D* energy_table, + TableInterpolator2D* R_table, TableInterpolator2D* c_table, + TableInterpolator2D* T_table); + virtual void GetSpeciesFromLTE(const double T, const double p, double* n_sp); // GPU functions #ifdef _GPU_ diff --git a/src/externalData_base.hpp b/src/externalData_base.hpp index f5dede6b..96dc4539 100644 --- a/src/externalData_base.hpp +++ b/src/externalData_base.hpp @@ -42,8 +42,8 @@ * ext data to the flow. */ struct extDataToFlow { - const mfem::ParGridFunction *Udata = nullptr; - const mfem::ParGridFunction *Thdata = nullptr; + const mfem::ParGridFunction* Udata = nullptr; + const mfem::ParGridFunction* Thdata = nullptr; }; /** @@ -51,9 +51,9 @@ struct extDataToFlow { * ext data to the thermo chem model. */ struct extDataToThermoChem { - const mfem::ParGridFunction *Tdata = nullptr; - const mfem::ParGridFunction *Ydata = nullptr; - const mfem::ParGridFunction *Yfulldata = nullptr; + const mfem::ParGridFunction* Tdata = nullptr; + const mfem::ParGridFunction* Ydata = nullptr; + const mfem::ParGridFunction* Yfulldata = nullptr; }; /** @@ -61,9 +61,9 @@ struct extDataToThermoChem { * ext data to the turb model */ struct extDataToTurbModel { - const mfem::ParGridFunction *NuTdata = nullptr; - const mfem::ParGridFunction *TKEdata = nullptr; - const mfem::ParGridFunction *V2data = nullptr; + const mfem::ParGridFunction* NuTdata = nullptr; + const mfem::ParGridFunction* TKEdata = nullptr; + const mfem::ParGridFunction* V2data = nullptr; }; /** @@ -84,7 +84,7 @@ class ExternalDataBase { /** * @brief Hook to let derived classes register visualization fields with ParaViewDataCollection */ - virtual void initializeViz(mfem::ParaViewDataCollection &pvdc) {} + virtual void initializeViz(mfem::ParaViewDataCollection& pvdc) {} /** * @brief Take a single time step diff --git a/src/faceGradientIntegration.cpp b/src/faceGradientIntegration.cpp index 1fed2061..62f877af 100644 --- a/src/faceGradientIntegration.cpp +++ b/src/faceGradientIntegration.cpp @@ -33,12 +33,12 @@ #include "faceGradientIntegration.hpp" // Implementation of class FaceIntegrator -GradFaceIntegrator::GradFaceIntegrator(IntegrationRules *_intRules, const int _dim, const int _num_equation, - BCintegrator *bc, bool useBCinGrad) +GradFaceIntegrator::GradFaceIntegrator(IntegrationRules* _intRules, const int _dim, const int _num_equation, + BCintegrator* bc, bool useBCinGrad) : dim(_dim), num_equation(_num_equation), intRules(_intRules), bc_(bc), useBCinGrad_(useBCinGrad) {} -void GradFaceIntegrator::AssembleFaceVector(const FiniteElement &el1, const FiniteElement &el2, - FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect) { +void GradFaceIntegrator::AssembleFaceVector(const FiniteElement& el1, const FiniteElement& el2, + FaceElementTransformations& Tr, const Vector& elfun, Vector& elvect) { // Compute the term on the interior faces. Vector nor(dim); Vector mean(num_equation); @@ -75,11 +75,11 @@ void GradFaceIntegrator::AssembleFaceVector(const FiniteElement &el1, const Fini if (el1.Space() == FunctionSpace::Pk) { intorder++; } - const IntegrationRule *ir = &intRules->Get(Tr.GetGeometryType(), intorder); + const IntegrationRule* ir = &intRules->Get(Tr.GetGeometryType(), intorder); // Quadrature point loop for (int i = 0; i < ir->GetNPoints(); i++) { - const IntegrationPoint &ip = ir->IntPoint(i); + const IntegrationPoint& ip = ir->IntPoint(i); Tr.SetAllIntPoints(&ip); // set face and element int. points @@ -98,9 +98,9 @@ void GradFaceIntegrator::AssembleFaceVector(const FiniteElement &el1, const Fini if (useBCinGrad_) { const int attr = Tr.Attribute; - std::unordered_map::const_iterator ibc = bc_->inletBCmap.find(attr); - std::unordered_map::const_iterator obc = bc_->outletBCmap.find(attr); - std::unordered_map::const_iterator wbc = bc_->wallBCmap.find(attr); + std::unordered_map::const_iterator ibc = bc_->inletBCmap.find(attr); + std::unordered_map::const_iterator obc = bc_->outletBCmap.find(attr); + std::unordered_map::const_iterator wbc = bc_->wallBCmap.find(attr); if (ibc != bc_->inletBCmap.end()) { ibc->second->computeBdrPrimitiveStateForGradient(iUp1, iUp2); } diff --git a/src/faceGradientIntegration.hpp b/src/faceGradientIntegration.hpp index f2a16f0a..b5c3f4d8 100644 --- a/src/faceGradientIntegration.hpp +++ b/src/faceGradientIntegration.hpp @@ -44,17 +44,17 @@ class GradFaceIntegrator : public NonlinearFormIntegrator { private: const int dim; const int num_equation; - IntegrationRules *intRules; + IntegrationRules* intRules; - BCintegrator *bc_; // NB: GradFaceIntegrator is a friend of BCintegrator + BCintegrator* bc_; // NB: GradFaceIntegrator is a friend of BCintegrator const bool useBCinGrad_; public: - GradFaceIntegrator(IntegrationRules *_intRules, const int _dim, const int _num_equation, BCintegrator *bc = NULL, + GradFaceIntegrator(IntegrationRules* _intRules, const int _dim, const int _num_equation, BCintegrator* bc = NULL, bool useBCinGrad = false); - virtual void AssembleFaceVector(const FiniteElement &el1, const FiniteElement &el2, FaceElementTransformations &Tr, - const Vector &elfun, Vector &elvect); + virtual void AssembleFaceVector(const FiniteElement& el1, const FiniteElement& el2, FaceElementTransformations& Tr, + const Vector& elfun, Vector& elvect); }; #endif // FACEGRADIENTINTEGRATION_HPP_ diff --git a/src/face_integrator.cpp b/src/face_integrator.cpp index 7c1897a8..50dd4a3a 100644 --- a/src/face_integrator.cpp +++ b/src/face_integrator.cpp @@ -33,10 +33,10 @@ #include "face_integrator.hpp" // Implementation of class FaceIntegrator -FaceIntegrator::FaceIntegrator(IntegrationRules *_intRules, RiemannSolverTPS *rsolver_, Fluxes *_fluxClass, - ParFiniteElementSpace *_vfes, bool _useLinear, const int _dim, const int _num_equation, - ParGridFunction *_gradUp, ParFiniteElementSpace *_gradUpfes, double &_max_char_speed, - bool axisym, ParGridFunction *distance) +FaceIntegrator::FaceIntegrator(IntegrationRules* _intRules, RiemannSolverTPS* rsolver_, Fluxes* _fluxClass, + ParFiniteElementSpace* _vfes, bool _useLinear, const int _dim, const int _num_equation, + ParGridFunction* _gradUp, ParFiniteElementSpace* _gradUpfes, double& _max_char_speed, + bool axisym, ParGridFunction* distance) : rsolver(rsolver_), fluxClass(_fluxClass), vfes(_vfes), @@ -60,9 +60,9 @@ FaceIntegrator::~FaceIntegrator() { } } -void FaceIntegrator::getElementsGrads_cpu(FaceElementTransformations &Tr, const FiniteElement &el1, - const FiniteElement &el2, DenseTensor &gradUp1, DenseTensor &gradUp2) { - double *dataGradUp = gradUp->GetData(); +void FaceIntegrator::getElementsGrads_cpu(FaceElementTransformations& Tr, const FiniteElement& el1, + const FiniteElement& el2, DenseTensor& gradUp1, DenseTensor& gradUp2) { + double* dataGradUp = gradUp->GetData(); vfes->GetElementVDofs(Tr.Elem1->ElementNo, vdofs1); int eldDof = el1.GetDof(); @@ -101,13 +101,13 @@ void FaceIntegrator::getElementsGrads_cpu(FaceElementTransformations &Tr, const } } -void FaceIntegrator::getElementsGrads_gpu(const ParGridFunction *gradUp, ParFiniteElementSpace *vfes, - const ParFiniteElementSpace *gradUpfes, FaceElementTransformations &Tr, - const FiniteElement &el1, const FiniteElement &el2, DenseTensor &gradUp1, - DenseTensor &gradUp2, const int &num_equation, const int &totalDofs, - const int &dim) { - const double *d_gradUp = gradUp->Read(); - double *d_gradUp1 = gradUp1.ReadWrite(); +void FaceIntegrator::getElementsGrads_gpu(const ParGridFunction* gradUp, ParFiniteElementSpace* vfes, + const ParFiniteElementSpace* gradUpfes, FaceElementTransformations& Tr, + const FiniteElement& el1, const FiniteElement& el2, DenseTensor& gradUp1, + DenseTensor& gradUp2, const int& num_equation, const int& totalDofs, + const int& dim) { + const double* d_gradUp = gradUp->Read(); + double* d_gradUp1 = gradUp1.ReadWrite(); Array vdofs1; vfes->GetElementVDofs(Tr.Elem1->ElementNo, vdofs1); @@ -144,7 +144,7 @@ void FaceIntegrator::getElementsGrads_gpu(const ParGridFunction *gradUp, ParFini } else { vfes->GetElementVDofs(no2, vdofs2); - double *d_gradUp2 = gradUp2.Write(); + double* d_gradUp2 = gradUp2.Write(); auto d_vdofs2 = vdofs2.Read(); MFEM_FORALL(n, eldDof, { @@ -159,11 +159,11 @@ void FaceIntegrator::getElementsGrads_gpu(const ParGridFunction *gradUp, ParFini } } -void FaceIntegrator::getDistanceDofs(FaceElementTransformations &Tr, const FiniteElement &el1, const FiniteElement &el2, - Vector &dist1, Vector &dist2) { +void FaceIntegrator::getDistanceDofs(FaceElementTransformations& Tr, const FiniteElement& el1, const FiniteElement& el2, + Vector& dist1, Vector& dist2) { assert(distance_ != NULL); - const ParFiniteElementSpace *pfes = distance_->ParFESpace(); + const ParFiniteElementSpace* pfes = distance_->ParFESpace(); Array dofs1; pfes->GetElementVDofs(Tr.Elem1->ElementNo, dofs1); @@ -186,13 +186,13 @@ void FaceIntegrator::getDistanceDofs(FaceElementTransformations &Tr, const Finit } } -void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1, const FiniteElement &el2, - FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect) { +void FaceIntegrator::AssembleFaceVector(const FiniteElement& el1, const FiniteElement& el2, + FaceElementTransformations& Tr, const Vector& elfun, Vector& elvect) { NonLinearFaceIntegration(el1, el2, Tr, elfun, elvect); } -void FaceIntegrator::NonLinearFaceIntegration(const FiniteElement &el1, const FiniteElement &el2, - FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect) { +void FaceIntegrator::NonLinearFaceIntegration(const FiniteElement& el1, const FiniteElement& el2, + FaceElementTransformations& Tr, const Vector& elfun, Vector& elvect) { // Compute the term on the interior faces. funval1.SetSize(num_equation); @@ -240,7 +240,7 @@ void FaceIntegrator::NonLinearFaceIntegration(const FiniteElement &el1, const Fi intorder++; } // IntegrationRules IntRules2(0, Quadrature1D::GaussLobatto); - const IntegrationRule *ir = &intRules->Get(Tr.GetGeometryType(), intorder); + const IntegrationRule* ir = &intRules->Get(Tr.GetGeometryType(), intorder); gradUp1i.SetSize(num_equation, dim); gradUp2i.SetSize(num_equation, dim); @@ -249,7 +249,7 @@ void FaceIntegrator::NonLinearFaceIntegration(const FiniteElement &el1, const Fi viscF2.SetSize(num_equation, dim); // element size - Mesh *mesh = vfes->GetMesh(); + Mesh* mesh = vfes->GetMesh(); const double delta1 = mesh->GetElementSize(Tr.Elem1No, 1) / el1.GetOrder(); double delta2 = delta1; @@ -262,7 +262,7 @@ void FaceIntegrator::NonLinearFaceIntegration(const FiniteElement &el1, const Fi // below is from the variant of Mesh::GetElementSize that takes an // ElementTransformation as input, rather than an element index. // We should simply call that function, but it is not public. - ElementTransformation *T = Tr.Elem2; + ElementTransformation* T = Tr.Elem2; DenseMatrix J(dim, dim); Geometry::Type geom = T->GetGeometryType(); @@ -280,7 +280,7 @@ void FaceIntegrator::NonLinearFaceIntegration(const FiniteElement &el1, const Fi const int nvel = fluxClass->GetNumVels(); for (int i = 0; i < ir->GetNPoints(); i++) { - const IntegrationPoint &ip = ir->IntPoint(i); + const IntegrationPoint& ip = ir->IntPoint(i); Tr.SetAllIntPoints(&ip); // set face and element int. points diff --git a/src/face_integrator.hpp b/src/face_integrator.hpp index 1548d822..fc117272 100644 --- a/src/face_integrator.hpp +++ b/src/face_integrator.hpp @@ -52,21 +52,21 @@ using namespace mfem; // Interior face term: class FaceIntegrator : public NonlinearFormIntegrator { private: - RiemannSolverTPS *rsolver; - Fluxes *fluxClass; - ParFiniteElementSpace *vfes; + RiemannSolverTPS* rsolver; + Fluxes* fluxClass; + ParFiniteElementSpace* vfes; const int dim; const int num_equation; - double &max_char_speed; + double& max_char_speed; - const ParGridFunction *gradUp; - const ParFiniteElementSpace *gradUpfes; + const ParGridFunction* gradUp; + const ParFiniteElementSpace* gradUpfes; - const ParGridFunction *distance_; + const ParGridFunction* distance_; - IntegrationRules *intRules; + IntegrationRules* intRules; DenseMatrix *faceMassMatrix1, *faceMassMatrix2; int faceNum; @@ -96,29 +96,29 @@ class FaceIntegrator : public NonlinearFormIntegrator { DenseMatrix elvect1_mat; DenseMatrix elvect2_mat; - void getElementsGrads_cpu(FaceElementTransformations &Tr, const FiniteElement &el1, const FiniteElement &el2, - DenseTensor &gradUp1, DenseTensor &gradUp2); + void getElementsGrads_cpu(FaceElementTransformations& Tr, const FiniteElement& el1, const FiniteElement& el2, + DenseTensor& gradUp1, DenseTensor& gradUp2); - void NonLinearFaceIntegration(const FiniteElement &el1, const FiniteElement &el2, FaceElementTransformations &Tr, - const Vector &elfun, Vector &elvect); + void NonLinearFaceIntegration(const FiniteElement& el1, const FiniteElement& el2, FaceElementTransformations& Tr, + const Vector& elfun, Vector& elvect); - void getDistanceDofs(FaceElementTransformations &Tr, const FiniteElement &el1, const FiniteElement &el2, - Vector &dist1, Vector &dist2); + void getDistanceDofs(FaceElementTransformations& Tr, const FiniteElement& el1, const FiniteElement& el2, + Vector& dist1, Vector& dist2); public: - FaceIntegrator(IntegrationRules *_intRules, RiemannSolverTPS *rsolver_, Fluxes *_fluxClass, - ParFiniteElementSpace *_vfes, bool _useLinear, const int _dim, const int _num_equation, - ParGridFunction *_gradUp, ParFiniteElementSpace *_gradUpfes, double &_max_char_speed, bool axisym, - ParGridFunction *distance); + FaceIntegrator(IntegrationRules* _intRules, RiemannSolverTPS* rsolver_, Fluxes* _fluxClass, + ParFiniteElementSpace* _vfes, bool _useLinear, const int _dim, const int _num_equation, + ParGridFunction* _gradUp, ParFiniteElementSpace* _gradUpfes, double& _max_char_speed, bool axisym, + ParGridFunction* distance); ~FaceIntegrator(); - virtual void AssembleFaceVector(const FiniteElement &el1, const FiniteElement &el2, FaceElementTransformations &Tr, - const Vector &elfun, Vector &elvect); + virtual void AssembleFaceVector(const FiniteElement& el1, const FiniteElement& el2, FaceElementTransformations& Tr, + const Vector& elfun, Vector& elvect); - static void getElementsGrads_gpu(const ParGridFunction *gradUp, ParFiniteElementSpace *vfes, - const ParFiniteElementSpace *gradUpfes, FaceElementTransformations &Tr, - const FiniteElement &el1, const FiniteElement &el2, DenseTensor &gradUp1, - DenseTensor &gradUp2, const int &num_equation, const int &totalDofs, const int &dim); + static void getElementsGrads_gpu(const ParGridFunction* gradUp, ParFiniteElementSpace* vfes, + const ParFiniteElementSpace* gradUpfes, FaceElementTransformations& Tr, + const FiniteElement& el1, const FiniteElement& el2, DenseTensor& gradUp1, + DenseTensor& gradUp2, const int& num_equation, const int& totalDofs, const int& dim); }; #endif // FACE_INTEGRATOR_HPP_ diff --git a/src/fluxes.cpp b/src/fluxes.cpp index 4ba41676..01c8f1c2 100644 --- a/src/fluxes.cpp +++ b/src/fluxes.cpp @@ -31,7 +31,7 @@ // -----------------------------------------------------------------------------------el- #include "fluxes.hpp" -Fluxes::Fluxes(GasMixture *_mixture, Equations _eqSystem, TransportProperties *_transport, const int _num_equation, +Fluxes::Fluxes(GasMixture* _mixture, Equations _eqSystem, TransportProperties* _transport, const int _num_equation, const int _dim, bool axisym) : mixture(_mixture), eqSystem(_eqSystem), @@ -54,8 +54,8 @@ Fluxes::Fluxes(GasMixture *_mixture, Equations _eqSystem, TransportProperties *_ numActiveSpecies = mixture->GetNumActiveSpecies(); } -Fluxes::Fluxes(GasMixture *_mixture, Equations _eqSystem, TransportProperties *_transport, const int _num_equation, - const int _dim, bool axisym, RunConfiguration *config) +Fluxes::Fluxes(GasMixture* _mixture, Equations _eqSystem, TransportProperties* _transport, const int _num_equation, + const int _dim, bool axisym, RunConfiguration* config) : mixture(_mixture), eqSystem(_eqSystem), config_(config), @@ -94,7 +94,7 @@ Fluxes::Fluxes(GasMixture *_mixture, Equations _eqSystem, TransportProperties *_ numActiveSpecies = mixture->GetNumActiveSpecies(); } -MFEM_HOST_DEVICE Fluxes::Fluxes(GasMixture *_mixture, Equations _eqSystem, TransportProperties *_transport, +MFEM_HOST_DEVICE Fluxes::Fluxes(GasMixture* _mixture, Equations _eqSystem, TransportProperties* _transport, const int _num_equation, const int _dim, bool axisym, int sgs_type, double sgs_floor, double sgs_const, viscositySpongeData vsd) : mixture(_mixture), @@ -128,11 +128,11 @@ MFEM_HOST_DEVICE Fluxes::Fluxes(GasMixture *_mixture, Equations _eqSystem, Trans numActiveSpecies = mixture->GetNumActiveSpecies(); } -void Fluxes::ComputeConvectiveFluxes(const Vector &state, DenseMatrix &flux) { +void Fluxes::ComputeConvectiveFluxes(const Vector& state, DenseMatrix& flux) { ComputeConvectiveFluxes(state.GetData(), flux.GetData()); } -MFEM_HOST_DEVICE void Fluxes::ComputeConvectiveFluxes(const double *state, double *flux) const { +MFEM_HOST_DEVICE void Fluxes::ComputeConvectiveFluxes(const double* state, double* flux) const { double Pe = 0.0; const double pres = mixture->ComputePressure(state, &Pe); const int numActiveSpecies = mixture->GetNumActiveSpecies(); @@ -170,13 +170,13 @@ MFEM_HOST_DEVICE void Fluxes::ComputeConvectiveFluxes(const double *state, doubl } // TODO(kevin): check/complete axisymmetric setting for multi-component flow. -void Fluxes::ComputeViscousFluxes(const Vector &state, const DenseMatrix &gradUp, Vector transip, double delta, - double distance, DenseMatrix &flux) { +void Fluxes::ComputeViscousFluxes(const Vector& state, const DenseMatrix& gradUp, Vector transip, double delta, + double distance, DenseMatrix& flux) { ComputeViscousFluxes(state.GetData(), gradUp.GetData(), transip.GetData(), delta, distance, flux.GetData()); } -MFEM_HOST_DEVICE void Fluxes::ComputeViscousFluxes(const double *state, const double *gradUp, double *transip, - double delta, double distance, double *flux) { +MFEM_HOST_DEVICE void Fluxes::ComputeViscousFluxes(const double* state, const double* gradUp, double* transip, + double delta, double distance, double* flux) { for (int d = 0; d < dim; d++) { for (int eq = 0; eq < num_equation; eq++) { flux[eq + d * num_equation] = 0.; @@ -334,16 +334,16 @@ MFEM_HOST_DEVICE void Fluxes::ComputeViscousFluxes(const double *state, const do } } -void Fluxes::ComputeBdrViscousFluxes(const Vector &state, const DenseMatrix &gradUp, Vector transip, double delta, - double distance, const BoundaryViscousFluxData &bcFlux, Vector &normalFlux) { +void Fluxes::ComputeBdrViscousFluxes(const Vector& state, const DenseMatrix& gradUp, Vector transip, double delta, + double distance, const BoundaryViscousFluxData& bcFlux, Vector& normalFlux) { normalFlux.SetSize(num_equation); ComputeBdrViscousFluxes(state.GetData(), gradUp.GetData(), transip.GetData(), delta, distance, bcFlux, normalFlux.GetData()); } -MFEM_HOST_DEVICE void Fluxes::ComputeBdrViscousFluxes(const double *state, const double *gradUp, double *transip, +MFEM_HOST_DEVICE void Fluxes::ComputeBdrViscousFluxes(const double* state, const double* gradUp, double* transip, double delta, double distance, - const BoundaryViscousFluxData &bcFlux, double *normalFlux) { + const BoundaryViscousFluxData& bcFlux, double* normalFlux) { // normalFlux.SetSize(num_equation); for (int eq = 0; eq < num_equation; eq++) normalFlux[eq] = 0.; if (eqSystem == EULER) { @@ -506,11 +506,11 @@ MFEM_HOST_DEVICE void Fluxes::ComputeBdrViscousFluxes(const double *state, const /** Basic Smagorinksy subgrid model with user-specified cutoff grid length */ -void Fluxes::sgsSmag(const Vector &state, const DenseMatrix &gradUp, double delta, double &mu) { +void Fluxes::sgsSmag(const Vector& state, const DenseMatrix& gradUp, double delta, double& mu) { sgsSmag(state.GetData(), gradUp.GetData(), delta, mu); } -MFEM_HOST_DEVICE void Fluxes::sgsSmag(const double *state, const double *gradUp, double delta, double &mu) { +MFEM_HOST_DEVICE void Fluxes::sgsSmag(const double* state, const double* gradUp, double delta, double& mu) { double Sij[6]; double Smag = 0.; double Cd = sgs_model_const_; // user-set, defaults to 0.12 @@ -540,11 +540,11 @@ MFEM_HOST_DEVICE void Fluxes::sgsSmag(const double *state, const double *gradUp, Sigma subgrid model following Nicoud et.al., "Using singular values to build a subgrid-scale model for large eddy simulations", PoF 2011. */ -void Fluxes::sgsSigma(const Vector &state, const DenseMatrix &gradUp, double delta, double &mu) { +void Fluxes::sgsSigma(const Vector& state, const DenseMatrix& gradUp, double delta, double& mu) { sgsSigma(state.GetData(), gradUp.GetData(), delta, mu); } -MFEM_HOST_DEVICE void Fluxes::sgsSigma(const double *state, const double *gradUp, double delta, double &mu) { +MFEM_HOST_DEVICE void Fluxes::sgsSigma(const double* state, const double* gradUp, double delta, double& mu) { double Cd = sgs_model_const_; // user-set, defaults to 0.135 double sml = 1.0e-12; double l_floor, d_model, d4; @@ -666,7 +666,7 @@ MFEM_HOST_DEVICE void Fluxes::sgsSigma(const double *state, const double *gradUp Simple planar viscous sponge layer with smooth tanh-transtion using user-specified width and total amplification. Note: duplicate in M2 */ -MFEM_HOST_DEVICE void Fluxes::viscSpongePlanar(double *x, double &wgt) { +MFEM_HOST_DEVICE void Fluxes::viscSpongePlanar(double* x, double& wgt) { double s[3]; double factor, width, dist; diff --git a/src/fluxes.hpp b/src/fluxes.hpp index fb9499a8..b8decd8a 100644 --- a/src/fluxes.hpp +++ b/src/fluxes.hpp @@ -64,10 +64,10 @@ struct viscositySpongeData { // Need to discuss further. class Fluxes { private: - GasMixture *mixture; + GasMixture* mixture; Equations eqSystem; - RunConfiguration *config_; - TransportProperties *transport; + RunConfiguration* config_; + TransportProperties* transport; int nvel; const int dim; @@ -83,39 +83,39 @@ class Fluxes { viscositySpongeData vsd_; public: - Fluxes(GasMixture *_mixture, Equations _eqSystem, TransportProperties *_transport, const int _num_equation, + Fluxes(GasMixture* _mixture, Equations _eqSystem, TransportProperties* _transport, const int _num_equation, const int _dim, bool axisym); - Fluxes(GasMixture *_mixture, Equations _eqSystem, TransportProperties *_transport, const int _num_equation, - const int _dim, bool axisym, RunConfiguration *config); - MFEM_HOST_DEVICE Fluxes(GasMixture *_mixture, Equations _eqSystem, TransportProperties *_transport, + Fluxes(GasMixture* _mixture, Equations _eqSystem, TransportProperties* _transport, const int _num_equation, + const int _dim, bool axisym, RunConfiguration* config); + MFEM_HOST_DEVICE Fluxes(GasMixture* _mixture, Equations _eqSystem, TransportProperties* _transport, const int _num_equation, const int _dim, bool axisym, int sgs_type, double sgs_floor, double sgs_const, viscositySpongeData vsd); Equations GetEquationSystem() { return eqSystem; } - void ComputeConvectiveFluxes(const Vector &state, DenseMatrix &flux); - MFEM_HOST_DEVICE void ComputeConvectiveFluxes(const double *state, double *flux) const; + void ComputeConvectiveFluxes(const Vector& state, DenseMatrix& flux); + MFEM_HOST_DEVICE void ComputeConvectiveFluxes(const double* state, double* flux) const; - void ComputeViscousFluxes(const Vector &state, const DenseMatrix &gradUp, Vector transip, double delta, - double distance, DenseMatrix &flux); + void ComputeViscousFluxes(const Vector& state, const DenseMatrix& gradUp, Vector transip, double delta, + double distance, DenseMatrix& flux); - MFEM_HOST_DEVICE void ComputeViscousFluxes(const double *state, const double *gradUp, double *transip, double delta, - double distance, double *flux); + MFEM_HOST_DEVICE void ComputeViscousFluxes(const double* state, const double* gradUp, double* transip, double delta, + double distance, double* flux); - void sgsSmag(const Vector &state, const DenseMatrix &gradUp, double delta, double &mu_sgs); - MFEM_HOST_DEVICE void sgsSmag(const double *state, const double *gradUp, double delta, double &mu_sgs); - void sgsSigma(const Vector &state, const DenseMatrix &gradUp, double delta, double &mu_sgs); - MFEM_HOST_DEVICE void sgsSigma(const double *state, const double *gradUp, double delta, double &mu_sgs); + void sgsSmag(const Vector& state, const DenseMatrix& gradUp, double delta, double& mu_sgs); + MFEM_HOST_DEVICE void sgsSmag(const double* state, const double* gradUp, double delta, double& mu_sgs); + void sgsSigma(const Vector& state, const DenseMatrix& gradUp, double delta, double& mu_sgs); + MFEM_HOST_DEVICE void sgsSigma(const double* state, const double* gradUp, double delta, double& mu_sgs); - MFEM_HOST_DEVICE void viscSpongePlanar(double *x, double &wgt); + MFEM_HOST_DEVICE void viscSpongePlanar(double* x, double& wgt); // Compute viscous flux with prescribed boundary flux. - void ComputeBdrViscousFluxes(const Vector &state, const DenseMatrix &gradUp, Vector transip, double delta, - double distance, const BoundaryViscousFluxData &bcFlux, Vector &normalFlux); + void ComputeBdrViscousFluxes(const Vector& state, const DenseMatrix& gradUp, Vector transip, double delta, + double distance, const BoundaryViscousFluxData& bcFlux, Vector& normalFlux); - MFEM_HOST_DEVICE void ComputeBdrViscousFluxes(const double *state, const double *gradUp, double *transip, - double delta, double distance, const BoundaryViscousFluxData &bcFlux, - double *normalFlux); + MFEM_HOST_DEVICE void ComputeBdrViscousFluxes(const double* state, const double* gradUp, double* transip, + double delta, double distance, const BoundaryViscousFluxData& bcFlux, + double* normalFlux); MFEM_HOST_DEVICE bool isAxisymmetric() const { return axisymmetric_; } diff --git a/src/forcing_terms.cpp b/src/forcing_terms.cpp index c7f1603c..c39cddb8 100644 --- a/src/forcing_terms.cpp +++ b/src/forcing_terms.cpp @@ -33,10 +33,10 @@ #include -ForcingTerms::ForcingTerms(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, ParGridFunction *U, - ParGridFunction *_Up, ParGridFunction *_gradUp, - const precomputedIntegrationData &gpu_precomputed_data, bool axisym) +ForcingTerms::ForcingTerms(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, ParGridFunction* U, + ParGridFunction* _Up, ParGridFunction* _gradUp, + const precomputedIntegrationData& gpu_precomputed_data, bool axisym) : dim(_dim), nvel(axisym ? 3 : _dim), num_equation(_num_equation), @@ -49,7 +49,7 @@ ForcingTerms::ForcingTerms(const int &_dim, const int &_num_equation, const int Up_(_Up), gradUp_(_gradUp), gpu_precomputed_data_(gpu_precomputed_data) { - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; h_num_elems_of_type = elem_data.num_elems_of_type.HostRead(); // b = new ParGridFunction(vfes); @@ -85,12 +85,12 @@ ForcingTerms::~ForcingTerms() { // } // TODO(kevin): gpu capability. -ConstantPressureGradient::ConstantPressureGradient(const int &_dim, const int &_num_equation, const int &_order, - const int &_intRuleType, IntegrationRules *_intRules, - ParFiniteElementSpace *_vfes, ParGridFunction *U, - ParGridFunction *_Up, ParGridFunction *_gradUp, - const precomputedIntegrationData &gpu_precomputed_data, - RunConfiguration &_config, GasMixture *mixture) +ConstantPressureGradient::ConstantPressureGradient(const int& _dim, const int& _num_equation, const int& _order, + const int& _intRuleType, IntegrationRules* _intRules, + ParFiniteElementSpace* _vfes, ParGridFunction* U, + ParGridFunction* _Up, ParGridFunction* _gradUp, + const precomputedIntegrationData& gpu_precomputed_data, + RunConfiguration& _config, GasMixture* mixture) : ForcingTerms(_dim, _num_equation, _order, _intRuleType, _intRules, _vfes, U, _Up, _gradUp, gpu_precomputed_data, _config.isAxisymmetric()), mixture_(mixture) { @@ -102,9 +102,9 @@ ConstantPressureGradient::ConstantPressureGradient(const int &_dim, const int &_ pressGrad.UseDevice(true); pressGrad.SetSize(3); pressGrad = 0.; - double *h_pressGrad = pressGrad.HostWrite(); + double* h_pressGrad = pressGrad.HostWrite(); { - double *data = _config.GetImposedPressureGradient(); + double* data = _config.GetImposedPressureGradient(); for (int jj = 0; jj < 3; jj++) h_pressGrad[jj] = data[jj]; } pressGrad.ReadWrite(); @@ -112,9 +112,9 @@ ConstantPressureGradient::ConstantPressureGradient(const int &_dim, const int &_ // ConstantPressureGradient::~ConstantPressureGradient() { delete mixture; } -void ConstantPressureGradient::updateTerms(Vector &in) { +void ConstantPressureGradient::updateTerms(Vector& in) { #ifdef _GPU_ - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto h_elem_dof_number = elem_data.dof_number.HostRead(); @@ -132,9 +132,9 @@ void ConstantPressureGradient::updateTerms(Vector &in) { int numElem = vfes->GetNE(); int dof = vfes->GetNDofs(); - double *data = in.GetData(); - const double *dataUp = Up_->GetData(); - const double *dataGradUp = gradUp_->GetData(); + double* data = in.GetData(); + const double* dataUp = Up_->GetData(); + const double* dataGradUp = gradUp_->GetData(); Vector gradUpk; // interpolated gradient gradUpk.SetSize(num_equation * dim); @@ -142,7 +142,7 @@ void ConstantPressureGradient::updateTerms(Vector &in) { upk.SetSize(num_equation); for (int el = 0; el < numElem; el++) { - const FiniteElement *elem = vfes->GetFE(el); + const FiniteElement* elem = vfes->GetFE(el); // ElementTransformation *Tr = vfes->GetElementTransformation(el); const int dof_elem = elem->GetDof(); @@ -173,16 +173,16 @@ void ConstantPressureGradient::updateTerms(Vector &in) { #ifdef _GPU_ void ConstantPressureGradient::updateTerms_gpu(const int numElems, const int offsetElems, const int elDof, - const int totalDofs, Vector &pressGrad, Vector &in, const Vector &Up, - Vector &gradUp, const int num_equation, const int dim, - const precomputedIntegrationData &gpu_precomputed_data) { - const double *d_pressGrad = pressGrad.Read(); - double *d_in = in.ReadWrite(); + const int totalDofs, Vector& pressGrad, Vector& in, const Vector& Up, + Vector& gradUp, const int num_equation, const int dim, + const precomputedIntegrationData& gpu_precomputed_data) { + const double* d_pressGrad = pressGrad.Read(); + double* d_in = in.ReadWrite(); - const double *d_Up = Up.Read(); - double *d_gradUp = gradUp.ReadWrite(); + const double* d_Up = Up.Read(); + double* d_gradUp = gradUp.ReadWrite(); - const elementIndexingData &elem_data = gpu_precomputed_data.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data.element_indexing_data; auto d_elem_dof_off = elem_data.dof_offset.Read(); auto d_elem_dofs_list = elem_data.dofs_list.Read(); @@ -235,13 +235,13 @@ void ConstantPressureGradient::updateTerms_gpu(const int numElems, const int off #endif -AxisymmetricSource::AxisymmetricSource(const int &_dim, const int &_num_equation, const int &_order, - GasMixture *_mixture, TransportProperties *_transport, - const Equations &_eqSystem, const int &_intRuleType, IntegrationRules *_intRules, - ParFiniteElementSpace *_vfes, ParGridFunction *U, ParGridFunction *_Up, - ParGridFunction *_gradUp, ParGridFunction *spaceVaryViscMult, - const precomputedIntegrationData &gpu_precomputed_data, - RunConfiguration &_config, ParGridFunction *distance) +AxisymmetricSource::AxisymmetricSource(const int& _dim, const int& _num_equation, const int& _order, + GasMixture* _mixture, TransportProperties* _transport, + const Equations& _eqSystem, const int& _intRuleType, IntegrationRules* _intRules, + ParFiniteElementSpace* _vfes, ParGridFunction* U, ParGridFunction* _Up, + ParGridFunction* _gradUp, ParGridFunction* spaceVaryViscMult, + const precomputedIntegrationData& gpu_precomputed_data, + RunConfiguration& _config, ParGridFunction* distance) : ForcingTerms(_dim, _num_equation, _order, _intRuleType, _intRules, _vfes, U, _Up, _gradUp, gpu_precomputed_data, _config.isAxisymmetric()), mixture(_mixture), @@ -252,26 +252,26 @@ AxisymmetricSource::AxisymmetricSource(const int &_dim, const int &_num_equation // no-op } -void AxisymmetricSource::updateTerms(Vector &in) { +void AxisymmetricSource::updateTerms(Vector& in) { assert(dim == 2); assert(nvel == 3); - double *d_y = in.ReadWrite(); - const double *d_U = U_->Read(); - const double *d_Up = Up_->Read(); - const double *d_gradUp = gradUp_->Read(); + double* d_y = in.ReadWrite(); + const double* d_U = U_->Read(); + const double* d_Up = Up_->Read(); + const double* d_gradUp = gradUp_->Read(); int dof = vfes->GetNDofs(); // get coords - const FiniteElementCollection *fec = vfes->FEColl(); - ParMesh *mesh = vfes->GetParMesh(); + const FiniteElementCollection* fec = vfes->FEColl(); + ParMesh* mesh = vfes->GetParMesh(); ParFiniteElementSpace dfes(mesh, fec, dim, Ordering::byNODES); ParGridFunction coordsDof(&dfes); mesh->GetNodes(coordsDof); auto d_coords = coordsDof.Read(); - const double *alpha; + const double* alpha; if (space_vary_viscosity_mult_ != NULL) { alpha = space_vary_viscosity_mult_->Read(); } else { @@ -279,7 +279,7 @@ void AxisymmetricSource::updateTerms(Vector &in) { } // and distance - const double *d_dist; + const double* d_dist; if (distance_ != NULL) { d_dist = distance_->Read(); } else { @@ -291,8 +291,8 @@ void AxisymmetricSource::updateTerms(Vector &in) { const Equations eqSys = eqSystem; - GasMixture *d_mix = mixture; - TransportProperties *d_trans = transport_; + GasMixture* d_mix = mixture; + TransportProperties* d_trans = transport_; MFEM_FORALL(n, dof, { double U[gpudata::MAXEQUATIONS]; @@ -427,11 +427,11 @@ void AxisymmetricSource::updateTerms(Vector &in) { // } } -JouleHeating::JouleHeating(const int &_dim, const int &_num_equation, const int &_order, GasMixture *_mixture, - const Equations &_eqSystem, const int &_intRuleType, IntegrationRules *_intRules, - ParFiniteElementSpace *_vfes, ParGridFunction *U, ParGridFunction *_Up, - ParGridFunction *_gradUp, const precomputedIntegrationData &gpu_precomputed_data, - RunConfiguration &_config, ParGridFunction *jh_) +JouleHeating::JouleHeating(const int& _dim, const int& _num_equation, const int& _order, GasMixture* _mixture, + const Equations& _eqSystem, const int& _intRuleType, IntegrationRules* _intRules, + ParFiniteElementSpace* _vfes, ParGridFunction* U, ParGridFunction* _Up, + ParGridFunction* _gradUp, const precomputedIntegrationData& gpu_precomputed_data, + RunConfiguration& _config, ParGridFunction* jh_) : ForcingTerms(_dim, _num_equation, _order, _intRuleType, _intRules, _vfes, U, _Up, _gradUp, gpu_precomputed_data, _config.isAxisymmetric()), eqSystem(_eqSystem), @@ -440,15 +440,15 @@ JouleHeating::JouleHeating(const int &_dim, const int &_num_equation, const int // no-op } -void JouleHeating::updateTerms(Vector &in) { +void JouleHeating::updateTerms(Vector& in) { assert(nvel == 3); const int dof = vfes->GetNDofs(); const int nvel_ = nvel; const int neqn = num_equation; - double *data = in.ReadWrite(); - const double *jh = joule_heating_->Read(); + double* data = in.ReadWrite(); + const double* jh = joule_heating_->Read(); // NB: This GasMixture is valid on the HOST! const bool twoT = mixture_->IsTwoTemperature(); @@ -472,10 +472,10 @@ void JouleHeating::updateTerms(Vector &in) { } // TODO(kevin): implment gpu -SpongeZone::SpongeZone(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - Fluxes *_fluxClass, GasMixture *_mixture, IntegrationRules *_intRules, - ParFiniteElementSpace *_vfes, ParGridFunction *U, ParGridFunction *_Up, ParGridFunction *_gradUp, - const precomputedIntegrationData &gpu_precomputed_data, RunConfiguration &_config, const int sz) +SpongeZone::SpongeZone(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + Fluxes* _fluxClass, GasMixture* _mixture, IntegrationRules* _intRules, + ParFiniteElementSpace* _vfes, ParGridFunction* U, ParGridFunction* _Up, ParGridFunction* _gradUp, + const precomputedIntegrationData& gpu_precomputed_data, RunConfiguration& _config, const int sz) : ForcingTerms(_dim, _num_equation, _order, _intRuleType, _intRules, _vfes, U, _Up, _gradUp, gpu_precomputed_data, _config.isAxisymmetric()), fluxes(_fluxClass), @@ -534,13 +534,13 @@ SpongeZone::SpongeZone(const int &_dim, const int &_num_equation, const int &_or meanNormalFluxes.SetSize(num_equation + 1); - ParMesh *mesh = vfes->GetParMesh(); - const FiniteElementCollection *fec = vfes->FEColl(); + ParMesh* mesh = vfes->GetParMesh(); + const FiniteElementCollection* fec = vfes->FEColl(); ParFiniteElementSpace dfes(mesh, fec, dim, Ordering::byNODES); ParFiniteElementSpace fes(mesh, fec); sigma = new ParGridFunction(&fes); - double *hSigma = sigma->HostWrite(); + double* hSigma = sigma->HostWrite(); ParGridFunction coords(&dfes); mesh->GetNodes(coords); @@ -628,16 +628,16 @@ SpongeZone::SpongeZone(const int &_dim, const int &_num_equation, const int &_or SpongeZone::~SpongeZone() { delete sigma; } -void SpongeZone::updateTerms(Vector &in) { +void SpongeZone::updateTerms(Vector& in) { if (szData.szSolType == SpongeZoneSolution::MIXEDOUT) computeMixedOutValues(); addSpongeZoneForcing(in); } -void SpongeZone::addSpongeZoneForcing(Vector &in) { - const double *ds = sigma->HostRead(); - double *dataIn = in.HostReadWrite(); - const double *dataUp = Up_->HostRead(); +void SpongeZone::addSpongeZoneForcing(Vector& in) { + const double* ds = sigma->HostRead(); + double* dataIn = in.HostReadWrite(); + const double* dataUp = Up_->HostRead(); int nnodes = vfes->GetNDofs(); @@ -712,7 +712,7 @@ void SpongeZone::addSpongeZoneForcing(Vector &in) { // TODO(kevin): change to conserved variables. void SpongeZone::computeMixedOutValues() { int nnodes = vfes->GetNDofs(); - const double *dataUp = Up_->HostRead(); + const double* dataUp = Up_->HostRead(); // double gamma = mixture->GetSpecificHeatRatio(); // compute mean normal fluxes @@ -765,10 +765,10 @@ void SpongeZone::computeMixedOutValues() { // mixture->GetConservativesFromPrimitives(Up, targetU); } -PassiveScalar::PassiveScalar(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, GasMixture *_mixture, - ParGridFunction *U, ParGridFunction *_Up, ParGridFunction *_gradUp, - const precomputedIntegrationData &gpu_precomputed_data, RunConfiguration &_config) +PassiveScalar::PassiveScalar(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, GasMixture* _mixture, + ParGridFunction* U, ParGridFunction* _Up, ParGridFunction* _gradUp, + const precomputedIntegrationData& gpu_precomputed_data, RunConfiguration& _config) : ForcingTerms(_dim, _num_equation, _order, _intRuleType, _intRules, _vfes, U, _Up, _gradUp, gpu_precomputed_data, _config.isAxisymmetric()), mixture(_mixture) { @@ -817,7 +817,7 @@ PassiveScalar::~PassiveScalar() { for (int i = 0; i < psData_.Size(); i++) delete psData_[i]; } -void PassiveScalar::updateTerms(Vector &in) { +void PassiveScalar::updateTerms(Vector& in) { #ifdef _GPU_ updateTerms_gpu(in, Up_, psData_, vfes->GetNDofs(), num_equation); #else @@ -841,11 +841,11 @@ void PassiveScalar::updateTerms(Vector &in) { #endif } -void PassiveScalar::updateTerms_gpu(Vector &in, ParGridFunction *Up, Array &psData, - const int nnode, const int num_equation) { +void PassiveScalar::updateTerms_gpu(Vector& in, ParGridFunction* Up, Array& psData, const int nnode, + const int num_equation) { #ifdef _GPU_ - double *d_in = in.ReadWrite(); - const double *d_Up = Up_->Read(); + double* d_in = in.ReadWrite(); + const double* d_Up = Up_->Read(); double Z = 0.; double radius = 1.; @@ -855,7 +855,7 @@ void PassiveScalar::updateTerms_gpu(Vector &in, ParGridFunction *Up, Arrayvalue; radius = psData[i]->radius; - const int *d_nodes = psData[i]->nodes.Read(); + const int* d_nodes = psData[i]->nodes.Read(); const int size = psData[i]->nodes.Size(); MFEM_FORALL(n, size, { @@ -870,11 +870,11 @@ void PassiveScalar::updateTerms_gpu(Vector &in, ParGridFunction *Up, ArrayGetNDofs(); @@ -954,10 +954,10 @@ void HeatSource::updateTerms_gpu(mfem::Vector &in) { } #ifdef HAVE_MASA -MASA_forcings::MASA_forcings(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, ParGridFunction *U, - ParGridFunction *_Up, ParGridFunction *_gradUp, - const precomputedIntegrationData &gpu_precomputed_data, RunConfiguration &_config) +MASA_forcings::MASA_forcings(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, ParGridFunction* U, + ParGridFunction* _Up, ParGridFunction* _gradUp, + const precomputedIntegrationData& gpu_precomputed_data, RunConfiguration& _config) : ForcingTerms(_dim, _num_equation, _order, _intRuleType, _intRules, _vfes, U, _Up, _gradUp, gpu_precomputed_data, _config.isAxisymmetric()) { // NOTE: This has been taken care of by M2ulPhyS.masaHandler_. @@ -976,22 +976,22 @@ MASA_forcings::MASA_forcings(const int &_dim, const int &_num_equation, const in } } -void MASA_forcings::updateTerms(Vector &in) { +void MASA_forcings::updateTerms(Vector& in) { int numElem = vfes->GetNE(); int dof = vfes->GetNDofs(); - double *data = in.HostReadWrite(); + double* data = in.HostReadWrite(); // const double *dataUp = Up->GetData(); // get coords - const FiniteElementCollection *fec = vfes->FEColl(); - ParMesh *mesh = vfes->GetParMesh(); + const FiniteElementCollection* fec = vfes->FEColl(); + ParMesh* mesh = vfes->GetParMesh(); ParFiniteElementSpace dfes(mesh, fec, dim, Ordering::byNODES); ParGridFunction coordsDof(&dfes); mesh->GetNodes(coordsDof); for (int el = 0; el < numElem; el++) { - const FiniteElement *elem = vfes->GetFE(el); + const FiniteElement* elem = vfes->GetFE(el); // ElementTransformation *Tr = vfes->GetElementTransformation(el); const int dof_elem = elem->GetDof(); diff --git a/src/forcing_terms.hpp b/src/forcing_terms.hpp index 5ac3b7b2..0b6b49ae 100644 --- a/src/forcing_terms.hpp +++ b/src/forcing_terms.hpp @@ -55,32 +55,32 @@ class ForcingTerms { protected: double time; - const int &dim; + const int& dim; const int nvel; - const int &num_equation; + const int& num_equation; const bool axisymmetric_; - const int ℴ - const int &intRuleType; - IntegrationRules *intRules; - ParFiniteElementSpace *vfes; - ParGridFunction *U_; - ParGridFunction *Up_; - ParGridFunction *gradUp_; + const int& order; + const int& intRuleType; + IntegrationRules* intRules; + ParFiniteElementSpace* vfes; + ParGridFunction* U_; + ParGridFunction* Up_; + ParGridFunction* gradUp_; - const precomputedIntegrationData &gpu_precomputed_data_; - const int *h_num_elems_of_type; + const precomputedIntegrationData& gpu_precomputed_data_; + const int* h_num_elems_of_type; // added term // ParGridFunction *b; public: - ForcingTerms(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, ParGridFunction *U, ParGridFunction *_Up, - ParGridFunction *_gradUp, const precomputedIntegrationData &gpu_precomputed_data, bool axisym); + ForcingTerms(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, ParGridFunction* U, ParGridFunction* _Up, + ParGridFunction* _gradUp, const precomputedIntegrationData& gpu_precomputed_data, bool axisym); virtual ~ForcingTerms(); void setTime(double _time) { time = _time; } - virtual void updateTerms(Vector &in) = 0; + virtual void updateTerms(Vector& in) = 0; // virtual void addForcingIntegrals(Vector &in); }; @@ -89,74 +89,74 @@ class ConstantPressureGradient : public ForcingTerms { private: // RunConfiguration &config; Vector pressGrad; - GasMixture *mixture_; + GasMixture* mixture_; public: - ConstantPressureGradient(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, ParGridFunction *U, - ParGridFunction *_Up, ParGridFunction *_gradUp, - const precomputedIntegrationData &gpu_precomputed_data, RunConfiguration &_config, - GasMixture *mixture); + ConstantPressureGradient(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, ParGridFunction* U, + ParGridFunction* _Up, ParGridFunction* _gradUp, + const precomputedIntegrationData& gpu_precomputed_data, RunConfiguration& _config, + GasMixture* mixture); virtual ~ConstantPressureGradient() {} // Terms do not need updating - virtual void updateTerms(Vector &in); + virtual void updateTerms(Vector& in); // GPU functions #ifdef _GPU_ static void updateTerms_gpu(const int numElems, const int offsetElems, const int elDof, const int totalDofs, - Vector &pressGrad, Vector &in, const Vector &Up, Vector &gradUp, const int num_equation, - const int dim, const precomputedIntegrationData &gpu_precomputed_data); + Vector& pressGrad, Vector& in, const Vector& Up, Vector& gradUp, const int num_equation, + const int dim, const precomputedIntegrationData& gpu_precomputed_data); #endif }; class AxisymmetricSource : public ForcingTerms { private: - GasMixture *mixture; - TransportProperties *transport_; - const Equations &eqSystem; - ParGridFunction *space_vary_viscosity_mult_; - ParGridFunction *distance_; + GasMixture* mixture; + TransportProperties* transport_; + const Equations& eqSystem; + ParGridFunction* space_vary_viscosity_mult_; + ParGridFunction* distance_; public: - AxisymmetricSource(const int &_dim, const int &_num_equation, const int &_order, GasMixture *_mixture, - TransportProperties *_transport, const Equations &_eqSystem, const int &_intRuleType, - IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, ParGridFunction *U, - ParGridFunction *_Up, ParGridFunction *_gradUp, ParGridFunction *spaceVaryViscMult, - const precomputedIntegrationData &gpu_precomputed_data, RunConfiguration &_config, - ParGridFunction *distance); + AxisymmetricSource(const int& _dim, const int& _num_equation, const int& _order, GasMixture* _mixture, + TransportProperties* _transport, const Equations& _eqSystem, const int& _intRuleType, + IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, ParGridFunction* U, + ParGridFunction* _Up, ParGridFunction* _gradUp, ParGridFunction* spaceVaryViscMult, + const precomputedIntegrationData& gpu_precomputed_data, RunConfiguration& _config, + ParGridFunction* distance); virtual ~AxisymmetricSource() {} - virtual void updateTerms(Vector &in); + virtual void updateTerms(Vector& in); }; class JouleHeating : public ForcingTerms { private: - const Equations &eqSystem; - ParGridFunction *joule_heating_; - GasMixture *mixture_; + const Equations& eqSystem; + ParGridFunction* joule_heating_; + GasMixture* mixture_; public: - JouleHeating(const int &_dim, const int &_num_equation, const int &_order, GasMixture *_mixture, - const Equations &_eqSystem, const int &_intRuleType, IntegrationRules *_intRules, - ParFiniteElementSpace *_vfes, ParGridFunction *U, ParGridFunction *_Up, ParGridFunction *_gradUp, - const precomputedIntegrationData &gpu_precomputed_data, RunConfiguration &_config, ParGridFunction *jh_); + JouleHeating(const int& _dim, const int& _num_equation, const int& _order, GasMixture* _mixture, + const Equations& _eqSystem, const int& _intRuleType, IntegrationRules* _intRules, + ParFiniteElementSpace* _vfes, ParGridFunction* U, ParGridFunction* _Up, ParGridFunction* _gradUp, + const precomputedIntegrationData& gpu_precomputed_data, RunConfiguration& _config, ParGridFunction* jh_); virtual ~JouleHeating() {} - virtual void updateTerms(Vector &in); + virtual void updateTerms(Vector& in); }; class SpongeZone : public ForcingTerms { private: - Fluxes *fluxes; - GasMixture *mixture; + Fluxes* fluxes; + GasMixture* mixture; - SpongeZoneData &szData; + SpongeZoneData& szData; Vector targetU; Array nodesInMixedOutPlane; - ParGridFunction *sigma; // linearly varying factor + ParGridFunction* sigma; // linearly varying factor Vector radialNormal; Array nodesInAnnulus; @@ -165,35 +165,35 @@ class SpongeZone : public ForcingTerms { bool singleTemperature_; void computeMixedOutValues(); - void addSpongeZoneForcing(Vector &in); + void addSpongeZoneForcing(Vector& in); public: - SpongeZone(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, Fluxes *_fluxClass, - GasMixture *_mixture, IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, ParGridFunction *U, - ParGridFunction *_Up, ParGridFunction *_gradUp, const precomputedIntegrationData &gpu_precomputed_data, - RunConfiguration &_config, const int sz); + SpongeZone(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, Fluxes* _fluxClass, + GasMixture* _mixture, IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, ParGridFunction* U, + ParGridFunction* _Up, ParGridFunction* _gradUp, const precomputedIntegrationData& gpu_precomputed_data, + RunConfiguration& _config, const int sz); virtual ~SpongeZone(); - virtual void updateTerms(Vector &in); + virtual void updateTerms(Vector& in); }; // Forcing that adds a passive scalar class PassiveScalar : public ForcingTerms { private: - GasMixture *mixture; + GasMixture* mixture; - Array psData_; + Array psData_; public: - PassiveScalar(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, GasMixture *_mixture, ParGridFunction *U, - ParGridFunction *_Up, ParGridFunction *_gradUp, const precomputedIntegrationData &gpu_precomputed_data, - RunConfiguration &_config); + PassiveScalar(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, GasMixture* _mixture, ParGridFunction* U, + ParGridFunction* _Up, ParGridFunction* _gradUp, const precomputedIntegrationData& gpu_precomputed_data, + RunConfiguration& _config); // Terms do not need updating - virtual void updateTerms(Vector &in); + virtual void updateTerms(Vector& in); - void updateTerms_gpu(Vector &in, ParGridFunction *Up, Array &psData, const int nnode, + void updateTerms_gpu(Vector& in, ParGridFunction* Up, Array& psData, const int nnode, const int num_equation); virtual ~PassiveScalar(); @@ -201,37 +201,37 @@ class PassiveScalar : public ForcingTerms { class HeatSource : public ForcingTerms { private: - GasMixture *mixture_; + GasMixture* mixture_; - heatSourceData &heatSource_; + heatSourceData& heatSource_; Array nodeList_; public: - HeatSource(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - heatSourceData &heatSource, GasMixture *_mixture, IntegrationRules *_intRules, - ParFiniteElementSpace *_vfes, ParGridFunction *U, ParGridFunction *_Up, ParGridFunction *_gradUp, - const precomputedIntegrationData &gpu_precomputed_data, RunConfiguration &_config); + HeatSource(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + heatSourceData& heatSource, GasMixture* _mixture, IntegrationRules* _intRules, + ParFiniteElementSpace* _vfes, ParGridFunction* U, ParGridFunction* _Up, ParGridFunction* _gradUp, + const precomputedIntegrationData& gpu_precomputed_data, RunConfiguration& _config); virtual ~HeatSource() {} - virtual void updateTerms(Vector &in); + virtual void updateTerms(Vector& in); - void updateTerms_gpu(Vector &in); + void updateTerms_gpu(Vector& in); }; #ifdef HAVE_MASA // Manufactured Solution using MASA class MASA_forcings : public ForcingTerms { private: - void (*evaluateForcing_)(const Vector &, const double, Array &) = 0; + void (*evaluateForcing_)(const Vector&, const double, Array&) = 0; public: - MASA_forcings(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, ParGridFunction *U, ParGridFunction *_Up, - ParGridFunction *_gradUp, const precomputedIntegrationData &gpu_precomputed_data, - RunConfiguration &_config); + MASA_forcings(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, ParGridFunction* U, ParGridFunction* _Up, + ParGridFunction* _gradUp, const precomputedIntegrationData& gpu_precomputed_data, + RunConfiguration& _config); - virtual void updateTerms(Vector &in); + virtual void updateTerms(Vector& in); }; #endif // HAVE_MASA diff --git a/src/gas_transport.cpp b/src/gas_transport.cpp index 5366bdd2..8ca7fd6c 100644 --- a/src/gas_transport.cpp +++ b/src/gas_transport.cpp @@ -36,10 +36,10 @@ //////// Gas Minimal Transport (ternary mixture) ////////////////////////////////////////////////////// -GasMinimalTransport::GasMinimalTransport(GasMixture *_mixture, RunConfiguration &_runfile) +GasMinimalTransport::GasMinimalTransport(GasMixture* _mixture, RunConfiguration& _runfile) : GasMinimalTransport(_mixture, _runfile.gasTransportInput) {} -MFEM_HOST_DEVICE GasMinimalTransport::GasMinimalTransport(GasMixture *_mixture, const GasTransportInput &inputs) +MFEM_HOST_DEVICE GasMinimalTransport::GasMinimalTransport(GasMixture* _mixture, const GasTransportInput& inputs) : MolecularTransport(_mixture) { viscosityFactor_ = 5. / 16. * sqrt(PI_ * kB_); kOverEtaFactor_ = 15. / 4. * kB_; @@ -148,7 +148,7 @@ MFEM_HOST_DEVICE GasMinimalTransport::GasMinimalTransport(GasMixture *_mixture, setArtificialMultipliers(inputs); } -MFEM_HOST_DEVICE GasMinimalTransport::GasMinimalTransport(GasMixture *_mixture) : MolecularTransport(_mixture) { +MFEM_HOST_DEVICE GasMinimalTransport::GasMinimalTransport(GasMixture* _mixture) : MolecularTransport(_mixture) { viscosityFactor_ = 5. / 16. * sqrt(PI_ * kB_); kOverEtaFactor_ = 15. / 4. * kB_; diffusivityFactor_ = 3. / 16. * sqrt(2.0 * PI_ * kB_) / AVOGADRONUMBER; @@ -156,7 +156,7 @@ MFEM_HOST_DEVICE GasMinimalTransport::GasMinimalTransport(GasMixture *_mixture) } // void GasMinimalTransport::computeEffectiveMass(const Vector &mw, DenseSymmetricMatrix &muw) { -MFEM_HOST_DEVICE void GasMinimalTransport::computeEffectiveMass(const double *mw, double *muw) { +MFEM_HOST_DEVICE void GasMinimalTransport::computeEffectiveMass(const double* mw, double* muw) { // muw.SetSize(numSpecies); // muw = 0.0; @@ -168,7 +168,7 @@ MFEM_HOST_DEVICE void GasMinimalTransport::computeEffectiveMass(const double *mw } } -MFEM_HOST_DEVICE void GasMinimalTransport::setArtificialMultipliers(const GasTransportInput &inputs) { +MFEM_HOST_DEVICE void GasMinimalTransport::setArtificialMultipliers(const GasTransportInput& inputs) { multiply_ = inputs.multiply; if (multiply_) { for (int t = 0; t < FluxTrns::NUM_FLUX_TRANS; t++) fluxTrnsMultiplier_[t] = inputs.fluxTrnsMultiplier[t]; @@ -178,12 +178,12 @@ MFEM_HOST_DEVICE void GasMinimalTransport::setArtificialMultipliers(const GasTra } } -collisionInputs GasMinimalTransport::computeCollisionInputs(const Vector &primitive, const Vector &n_sp) { +collisionInputs GasMinimalTransport::computeCollisionInputs(const Vector& primitive, const Vector& n_sp) { return computeCollisionInputs(&primitive[0], &n_sp[0]); } -MFEM_HOST_DEVICE collisionInputs GasMinimalTransport::computeCollisionInputs(const double *primitive, - const double *n_sp) { +MFEM_HOST_DEVICE collisionInputs GasMinimalTransport::computeCollisionInputs(const double* primitive, + const double* n_sp) { collisionInputs collInputs; collInputs.Te = (twoTemperature_) ? primitive[num_equation - 1] : primitive[nvel_ + 1]; collInputs.Th = primitive[nvel_ + 1]; @@ -203,9 +203,9 @@ MFEM_HOST_DEVICE collisionInputs GasMinimalTransport::computeCollisionInputs(con return collInputs; } -MFEM_HOST_DEVICE void GasMinimalTransport::ComputeFluxMolecularTransport(const double *state, const double *gradUp, - const double *Efield, double *transportBuffer, - double *diffusionVelocity) { +MFEM_HOST_DEVICE void GasMinimalTransport::ComputeFluxMolecularTransport(const double* state, const double* gradUp, + const double* Efield, double* transportBuffer, + double* diffusionVelocity) { // transportBuffer.SetSize(FluxTrns::NUM_FLUX_TRANS); for (int p = 0; p < FluxTrns::NUM_FLUX_TRANS; p++) transportBuffer[p] = 0.0; @@ -397,7 +397,7 @@ MFEM_HOST_DEVICE void GasMinimalTransport::ComputeFluxMolecularTransport(const d // std::cout << "max diff. vel: " << charSpeed << std::endl; } -MFEM_HOST_DEVICE double GasMinimalTransport::computeThirdOrderElectronThermalConductivity(const double *X_sp, +MFEM_HOST_DEVICE double GasMinimalTransport::computeThirdOrderElectronThermalConductivity(const double* X_sp, const double debyeLength, const double Te, const double nondimTe) { @@ -488,15 +488,15 @@ MFEM_HOST_DEVICE double GasMinimalTransport::computeThirdOrderElectronThermalCon } /**/ -void GasMinimalTransport::computeMixtureAverageDiffusivity(const Vector &state, const Vector &Efield, - Vector &diffusivity, bool unused) { +void GasMinimalTransport::computeMixtureAverageDiffusivity(const Vector& state, const Vector& Efield, + Vector& diffusivity, bool unused) { diffusivity.SetSize(3); diffusivity = 0.0; computeMixtureAverageDiffusivity(&state[0], &Efield[0], &diffusivity[0], unused); } -MFEM_HOST_DEVICE void GasMinimalTransport::computeMixtureAverageDiffusivity(const double *state, const double *Efield, - double *diffusivity, bool unused) { +MFEM_HOST_DEVICE void GasMinimalTransport::computeMixtureAverageDiffusivity(const double* state, const double* Efield, + double* diffusivity, bool unused) { double primitiveState[gpudata::MAXEQUATIONS]; mixture->GetPrimitivesFromConservatives(state, primitiveState); @@ -589,11 +589,11 @@ MFEM_HOST_DEVICE void GasMinimalTransport::computeMixtureAverageDiffusivity(cons } /**/ -MFEM_HOST_DEVICE void GasMinimalTransport::ComputeSourceMolecularTransport(const double *state, const double *Up, - const double *gradUp, const double *Efield, - double *globalTransport, - double *speciesTransport, - double *diffusionVelocity, double *n_sp) { +MFEM_HOST_DEVICE void GasMinimalTransport::ComputeSourceMolecularTransport(const double* state, const double* Up, + const double* gradUp, const double* Efield, + double* globalTransport, + double* speciesTransport, + double* diffusionVelocity, double* n_sp) { for (int p = 0; p < SrcTrns::NUM_SRC_TRANS; p++) globalTransport[p] = 0.0; for (int p = 0; p < SpeciesTrns::NUM_SPECIES_COEFFS; p++) for (int sp = 0; sp < numSpecies; sp++) speciesTransport[sp + p * numSpecies] = 0.0; @@ -772,8 +772,8 @@ MFEM_HOST_DEVICE void GasMinimalTransport::ComputeSourceMolecularTransport(const // std::cout << "max diff. vel: " << charSpeed << std::endl; } -MFEM_HOST_DEVICE void GasMinimalTransport::GetViscosities(const double *conserved, const double *primitive, - double *visc) { +MFEM_HOST_DEVICE void GasMinimalTransport::GetViscosities(const double* conserved, const double* primitive, + double* visc) { double n_sp[3], X_sp[3], Y_sp[3]; mixture->computeSpeciesPrimitives(conserved, X_sp, Y_sp, n_sp); // double nTotal = 0.0; @@ -871,10 +871,10 @@ collInputs); kappa[1] = computeThirdOrderElectronThermalConductivity(X_sp, collI //////// Gas Mixture Transport ////////////////////////////////////////////////////// -GasMixtureTransport::GasMixtureTransport(GasMixture *_mixture, RunConfiguration &_runfile) +GasMixtureTransport::GasMixtureTransport(GasMixture* _mixture, RunConfiguration& _runfile) : GasMixtureTransport(_mixture, _runfile.gasTransportInput) {} -MFEM_HOST_DEVICE GasMixtureTransport::GasMixtureTransport(GasMixture *_mixture, const GasTransportInput &inputs) +MFEM_HOST_DEVICE GasMixtureTransport::GasMixtureTransport(GasMixture* _mixture, const GasTransportInput& inputs) : GasMinimalTransport(_mixture) { electronIndex_ = inputs.electronIndex; neutralIndex_ = inputs.neutralIndex; @@ -1281,9 +1281,9 @@ MFEM_HOST_DEVICE double GasMixtureTransport::collisionIntegral(const int _spI, c return -1; } -MFEM_HOST_DEVICE void GasMixtureTransport::ComputeFluxMolecularTransport(const double *state, const double *gradUp, - const double *Efield, double *transportBuffer, - double *diffusionVelocity) { +MFEM_HOST_DEVICE void GasMixtureTransport::ComputeFluxMolecularTransport(const double* state, const double* gradUp, + const double* Efield, double* transportBuffer, + double* diffusionVelocity) { for (int p = 0; p < FluxTrns::NUM_FLUX_TRANS; p++) transportBuffer[p] = 0.0; double primitiveState[gpudata::MAXEQUATIONS]; @@ -1385,7 +1385,7 @@ MFEM_HOST_DEVICE void GasMixtureTransport::ComputeFluxMolecularTransport(const d } MFEM_HOST_DEVICE double GasMixtureTransport::computeThirdOrderElectronThermalConductivity( - const double *X_sp, const collisionInputs &collInputs) { + const double* X_sp, const collisionInputs& collInputs) { double Q2[3]; for (int r = 0; r < 3; r++) Q2[r] = collisionIntegral(electronIndex_, electronIndex_, 2, r + 2, collInputs); @@ -1405,11 +1405,11 @@ MFEM_HOST_DEVICE double GasMixtureTransport::computeThirdOrderElectronThermalCon (L11 - L12 * L12 / L22); } -MFEM_HOST_DEVICE void GasMixtureTransport::ComputeSourceMolecularTransport(const double *state, const double *Up, - const double *gradUp, const double *Efield, - double *globalTransport, - double *speciesTransport, - double *diffusionVelocity, double *n_sp) { +MFEM_HOST_DEVICE void GasMixtureTransport::ComputeSourceMolecularTransport(const double* state, const double* Up, + const double* gradUp, const double* Efield, + double* globalTransport, + double* speciesTransport, + double* diffusionVelocity, double* n_sp) { for (int p = 0; p < SrcTrns::NUM_SRC_TRANS; p++) globalTransport[p] = 0.0; for (int p = 0; p < SpeciesTrns::NUM_SPECIES_COEFFS; p++) for (int sp = 0; sp < numSpecies; sp++) speciesTransport[sp + p * numSpecies] = 0.0; @@ -1495,8 +1495,8 @@ MFEM_HOST_DEVICE void GasMixtureTransport::ComputeSourceMolecularTransport(const // std::cout << "max diff. vel: " << charSpeed << std::endl; } -MFEM_HOST_DEVICE void GasMixtureTransport::GetViscosities(const double *conserved, const double *primitive, - double *visc) { +MFEM_HOST_DEVICE void GasMixtureTransport::GetViscosities(const double* conserved, const double* primitive, + double* visc) { if (constantTransport_) { visc[0] = viscosity_; visc[1] = bulkViscosity_; @@ -1544,8 +1544,8 @@ MFEM_HOST_DEVICE void GasMixtureTransport::GetViscosities(const double *conserve return; } -MFEM_HOST_DEVICE void GasMixtureTransport::GetThermalConductivities(const double *conserved, const double *primitive, - double *kappa) { +MFEM_HOST_DEVICE void GasMixtureTransport::GetThermalConductivities(const double* conserved, const double* primitive, + double* kappa) { double n_sp[gpudata::MAXSPECIES], X_sp[gpudata::MAXSPECIES], Y_sp[gpudata::MAXSPECIES]; if (constantTransport_) { @@ -1588,8 +1588,8 @@ MFEM_HOST_DEVICE void GasMixtureTransport::GetThermalConductivities(const double } } -void GasMixtureTransport::computeMixtureAverageDiffusivity(const Vector &state, const Vector &Efield, - Vector &diffusivity, bool unused) { +void GasMixtureTransport::computeMixtureAverageDiffusivity(const Vector& state, const Vector& Efield, + Vector& diffusivity, bool unused) { // diffusivity.SetSize(3); // diffusivity.SetSize(numSpecies); diffusivity.SetSize(gpudata::MAXSPECIES); // should already be set coming in @@ -1597,8 +1597,8 @@ void GasMixtureTransport::computeMixtureAverageDiffusivity(const Vector &state, computeMixtureAverageDiffusivity(&state[0], &Efield[0], &diffusivity[0], unused); } -MFEM_HOST_DEVICE void GasMixtureTransport::computeMixtureAverageDiffusivity(const double *state, const double *Efield, - double *diffusivity, bool unused) { +MFEM_HOST_DEVICE void GasMixtureTransport::computeMixtureAverageDiffusivity(const double* state, const double* Efield, + double* diffusivity, bool unused) { if (constantTransport_) { for (int sp = 0; sp < numSpecies; sp++) { diffusivity[sp] = diffusivity_[sp]; @@ -1648,7 +1648,7 @@ MFEM_HOST_DEVICE void GasMixtureTransport::computeMixtureAverageDiffusivity(cons } } -MFEM_HOST_DEVICE void GasMixtureTransport::ComputeElectricalConductivity(const double *state, double &sigma) { +MFEM_HOST_DEVICE void GasMixtureTransport::ComputeElectricalConductivity(const double* state, double& sigma) { if (constantTransport_) { sigma = electronThermalConductivity_; return; diff --git a/src/gas_transport.hpp b/src/gas_transport.hpp index bebe046a..dfd035b9 100644 --- a/src/gas_transport.hpp +++ b/src/gas_transport.hpp @@ -99,40 +99,40 @@ class GasMinimalTransport : public MolecularTransport { double mobilMult_; public: - GasMinimalTransport(GasMixture *_mixture, RunConfiguration &_runfile); - MFEM_HOST_DEVICE GasMinimalTransport(GasMixture *_mixture, const GasTransportInput &inputs); - MFEM_HOST_DEVICE GasMinimalTransport(GasMixture *_mixture); + GasMinimalTransport(GasMixture* _mixture, RunConfiguration& _runfile); + MFEM_HOST_DEVICE GasMinimalTransport(GasMixture* _mixture, const GasTransportInput& inputs); + MFEM_HOST_DEVICE GasMinimalTransport(GasMixture* _mixture); MFEM_HOST_DEVICE virtual ~GasMinimalTransport() {} - MFEM_HOST_DEVICE double getMuw(const int &spI, const int &spJ) { return muw_[spI + spJ * numSpecies]; } + MFEM_HOST_DEVICE double getMuw(const int& spI, const int& spJ) { return muw_[spI + spJ * numSpecies]; } int getIonIndex() { return ionIndex_; } - virtual collisionInputs computeCollisionInputs(const Vector &primitive, const Vector &n_sp); - MFEM_HOST_DEVICE collisionInputs computeCollisionInputs(const double *primitive, const double *n_sp); + virtual collisionInputs computeCollisionInputs(const Vector& primitive, const Vector& n_sp); + MFEM_HOST_DEVICE collisionInputs computeCollisionInputs(const double* primitive, const double* n_sp); - MFEM_HOST_DEVICE void ComputeFluxMolecularTransport(const double *state, const double *gradUp, const double *Efield, - double *transportBuffer, double *diffusionVelocity) override; + MFEM_HOST_DEVICE void ComputeFluxMolecularTransport(const double* state, const double* gradUp, const double* Efield, + double* transportBuffer, double* diffusionVelocity) override; - MFEM_HOST_DEVICE void ComputeSourceMolecularTransport(const double *state, const double *Up, const double *gradUp, - const double *Efield, double *globalTransport, - double *speciesTransport, double *diffusionVelocity, - double *n_sp) override; + MFEM_HOST_DEVICE void ComputeSourceMolecularTransport(const double* state, const double* Up, const double* gradUp, + const double* Efield, double* globalTransport, + double* speciesTransport, double* diffusionVelocity, + double* n_sp) override; // NOTE(kevin): only for AxisymmetricSource using MolecularTransport::GetViscosities; - MFEM_HOST_DEVICE void GetViscosities(const double *conserved, const double *primitive, double *visc) override; + MFEM_HOST_DEVICE void GetViscosities(const double* conserved, const double* primitive, double* visc) override; // virtual double computeThirdOrderElectronThermalConductivity(const Vector &X_sp, const double debyeLength, // const double Te, const double nondimTe); - MFEM_HOST_DEVICE double computeThirdOrderElectronThermalConductivity(const double *X_sp, const double debyeLength, + MFEM_HOST_DEVICE double computeThirdOrderElectronThermalConductivity(const double* X_sp, const double debyeLength, const double Te, const double nondimTe); - virtual void computeMixtureAverageDiffusivity(const Vector &state, const Vector &Efield, Vector &diffusivity, + virtual void computeMixtureAverageDiffusivity(const Vector& state, const Vector& Efield, Vector& diffusivity, bool unused); - MFEM_HOST_DEVICE virtual void computeMixtureAverageDiffusivity(const double *state, const double *Efield, - double *diffusivity, bool unused); + MFEM_HOST_DEVICE virtual void computeMixtureAverageDiffusivity(const double* state, const double* Efield, + double* diffusivity, bool unused); // here HERE // virtual void computeMixtureAverageDiffusivity(const Vector &state, const Vector &Efield, Vector &diffusivity, bool @@ -145,21 +145,21 @@ class GasMinimalTransport : public MolecularTransport { // override; // These are used to compute third-order electron thermal conductivity based on standard Chapman--Enskog method. - MFEM_HOST_DEVICE double L11ee(const double *Q2) { return Q2[0]; } - MFEM_HOST_DEVICE double L11ea(const double *Q1) { return 6.25 * Q1[0] - 15. * Q1[1] + 12. * Q1[2]; } - MFEM_HOST_DEVICE double L12ee(const double *Q2) { return 1.75 * Q2[0] - 2.0 * Q2[1]; } - MFEM_HOST_DEVICE double L12ea(const double *Q1) { + MFEM_HOST_DEVICE double L11ee(const double* Q2) { return Q2[0]; } + MFEM_HOST_DEVICE double L11ea(const double* Q1) { return 6.25 * Q1[0] - 15. * Q1[1] + 12. * Q1[2]; } + MFEM_HOST_DEVICE double L12ee(const double* Q2) { return 1.75 * Q2[0] - 2.0 * Q2[1]; } + MFEM_HOST_DEVICE double L12ea(const double* Q1) { return 10.9375 * Q1[0] - 39.375 * Q1[1] + 57. * Q1[2] - 30. * Q1[3]; } - MFEM_HOST_DEVICE double L22ee(const double *Q2) { return 4.8125 * Q2[0] - 7.0 * Q2[1] + 5. * Q2[2]; } - MFEM_HOST_DEVICE double L22ea(const double *Q1) { + MFEM_HOST_DEVICE double L22ee(const double* Q2) { return 4.8125 * Q2[0] - 7.0 * Q2[1] + 5. * Q2[2]; } + MFEM_HOST_DEVICE double L22ea(const double* Q1) { return 19.140625 * Q1[0] - 91.875 * Q1[1] + 199.5 * Q1[2] - 210. * Q1[3] + 90. * Q1[4]; } - MFEM_HOST_DEVICE void computeEffectiveMass(const double *mw, double *muw); + MFEM_HOST_DEVICE void computeEffectiveMass(const double* mw, double* muw); // For artificial multipliers - MFEM_HOST_DEVICE void setArtificialMultipliers(const GasTransportInput &inputs); + MFEM_HOST_DEVICE void setArtificialMultipliers(const GasTransportInput& inputs); }; ////////////////////////////////////////////////////// @@ -191,39 +191,39 @@ class GasMixtureTransport : public GasMinimalTransport { // void identifyCollisionType(); public: - GasMixtureTransport(GasMixture *_mixture, RunConfiguration &_runfile); - MFEM_HOST_DEVICE GasMixtureTransport(GasMixture *_mixture, const GasTransportInput &inputs); + GasMixtureTransport(GasMixture* _mixture, RunConfiguration& _runfile); + MFEM_HOST_DEVICE GasMixtureTransport(GasMixture* _mixture, const GasTransportInput& inputs); MFEM_HOST_DEVICE virtual ~GasMixtureTransport() {} MFEM_HOST_DEVICE double collisionIntegral(const int _spI, const int _spJ, const int l, const int r, const collisionInputs collInputs); - MFEM_HOST_DEVICE void ComputeFluxMolecularTransport(const double *state, const double *gradUp, const double *Efield, - double *transportBuffer, double *diffusionVelocity) final; + MFEM_HOST_DEVICE void ComputeFluxMolecularTransport(const double* state, const double* gradUp, const double* Efield, + double* transportBuffer, double* diffusionVelocity) final; - MFEM_HOST_DEVICE void ComputeSourceMolecularTransport(const double *state, const double *Up, const double *gradUp, - const double *Efield, double *globalTransport, - double *speciesTransport, double *diffusionVelocity, - double *n_sp) final; + MFEM_HOST_DEVICE void ComputeSourceMolecularTransport(const double* state, const double* Up, const double* gradUp, + const double* Efield, double* globalTransport, + double* speciesTransport, double* diffusionVelocity, + double* n_sp) final; // NOTE(kevin): only for AxisymmetricSource using GasMinimalTransport::GetViscosities; - MFEM_HOST_DEVICE void GetViscosities(const double *conserved, const double *primitive, double *visc) final; + MFEM_HOST_DEVICE void GetViscosities(const double* conserved, const double* primitive, double* visc) final; - MFEM_HOST_DEVICE double computeThirdOrderElectronThermalConductivity(const double *X_sp, - const collisionInputs &collInputs); + MFEM_HOST_DEVICE double computeThirdOrderElectronThermalConductivity(const double* X_sp, + const collisionInputs& collInputs); // here HERE - virtual void computeMixtureAverageDiffusivity(const Vector &state, const Vector &Efield, Vector &diffusivity, + virtual void computeMixtureAverageDiffusivity(const Vector& state, const Vector& Efield, Vector& diffusivity, bool unused); - MFEM_HOST_DEVICE virtual void computeMixtureAverageDiffusivity(const double *state, const double *Efield, - double *diffusivity, bool unused); + MFEM_HOST_DEVICE virtual void computeMixtureAverageDiffusivity(const double* state, const double* Efield, + double* diffusivity, bool unused); - MFEM_HOST_DEVICE void GetThermalConductivities(const double *conserved, const double *primitive, double *kappa); + MFEM_HOST_DEVICE void GetThermalConductivities(const double* conserved, const double* primitive, double* kappa); - MFEM_HOST_DEVICE void ComputeElectricalConductivity(const double *state, double &sigma); + MFEM_HOST_DEVICE void ComputeElectricalConductivity(const double* state, double& sigma); // virtual void computeMixtureAverageDiffusivity(const Vector &state, const Vector &Efield, Vector &diffusivity, bool // unused); // final; //override; using GasMinimalTransport::computeMixtureAverageDiffusivity; MFEM_HOST_DEVICE void diff --git a/src/gaussianInterpExtData.cpp b/src/gaussianInterpExtData.cpp index 1f4224d4..f0d91fcf 100644 --- a/src/gaussianInterpExtData.cpp +++ b/src/gaussianInterpExtData.cpp @@ -49,8 +49,8 @@ using namespace mfem; using namespace mfem::common; -GaussianInterpExtData::GaussianInterpExtData(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, - temporalSchemeCoefficients &coeff, TPS::Tps *tps) +GaussianInterpExtData::GaussianInterpExtData(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, + temporalSchemeCoefficients& coeff, TPS::Tps* tps) : tpsP_(tps), loMach_opts_(loMach_opts), pmesh_(pmesh), coeff_(coeff) { nprocs_ = pmesh_->GetNRanks(); rank_ = pmesh_->GetMyRank(); @@ -218,7 +218,7 @@ void GaussianInterpExtData::initializeSelf() { } } -void GaussianInterpExtData::initializeViz(ParaViewDataCollection &pvdc) { +void GaussianInterpExtData::initializeViz(ParaViewDataCollection& pvdc) { if (isInterpInlet_) { pvdc.RegisterField("externalTemp", &temperature_gf_); pvdc.RegisterField("externalU", &velocity_gf_); @@ -279,13 +279,13 @@ void GaussianInterpExtData::setInlet() { } } - double *Tdata = temperature_gf_.HostReadWrite(); - double *Udata = velocity_gf_.HostReadWrite(); - double *U0 = vel0_gf_.HostReadWrite(); - double *Thdata = swirl_gf_.HostReadWrite(); - double *Th0 = swirl0_gf_.HostReadWrite(); - double *Ydata = Yn_gf_.HostReadWrite(); - double *hcoords = coordsDof.HostReadWrite(); + double* Tdata = temperature_gf_.HostReadWrite(); + double* Udata = velocity_gf_.HostReadWrite(); + double* U0 = vel0_gf_.HostReadWrite(); + double* Thdata = swirl_gf_.HostReadWrite(); + double* Th0 = swirl0_gf_.HostReadWrite(); + double* Ydata = Yn_gf_.HostReadWrite(); + double* hcoords = coordsDof.HostReadWrite(); struct inlet_profile { // double x, y, z, rho, temp, u, v, w; @@ -295,14 +295,14 @@ void GaussianInterpExtData::setInlet() { string fnameBase; std::string basepath("./inputs/"); fnameBase = (basepath + fname_); - const char *fnameRead = fnameBase.c_str(); + const char* fnameRead = fnameBase.c_str(); int nCount = 0; // find size if (rank0_) { std::cout << " Attempting to open inlet file for counting... " << fnameRead << " "; - FILE *inlet_file; + FILE* inlet_file; if ((inlet_file = fopen(fnameRead, "r"))) { std::cout << " ...and open" << endl; fflush(stdout); @@ -561,8 +561,8 @@ void GaussianInterpExtData::setFieldInitSpec() { pmesh_->GetNodes(coordsDof); // now repeat for the spec field data // TODO(garobed1): no support for 3D - double *Yfulldata = Yfull_gf_.HostReadWrite(); - double *hcoords = coordsDof.HostReadWrite(); + double* Yfulldata = Yfull_gf_.HostReadWrite(); + double* hcoords = coordsDof.HostReadWrite(); const int maxSpec = 10; @@ -573,14 +573,14 @@ void GaussianInterpExtData::setFieldInitSpec() { string fnamespecBase; std::string basepathspec("./inputs/"); fnamespecBase = (basepathspec + fname_spec_); - const char *fnamespecRead = fnamespecBase.c_str(); + const char* fnamespecRead = fnamespecBase.c_str(); int nCountSpec = 0; // find size if (rank0_) { std::cout << " Attempting to open species file for counting... " << fnamespecRead << " "; - FILE *field_file; + FILE* field_file; if ((field_file = fopen(fnamespecRead, "r"))) { std::cout << " ...and open" << endl; fflush(stdout); @@ -752,8 +752,8 @@ void GaussianInterpExtData::setFieldTurbVisc() { pmesh_->GetNodes(coordsDof); // now repeat for the turb field data // TODO(garobed1): no support for 3D - double *NuTdata = nut_gf_.HostReadWrite(); - double *hcoords = coordsDof.HostReadWrite(); + double* NuTdata = nut_gf_.HostReadWrite(); + double* hcoords = coordsDof.HostReadWrite(); struct turb_profile { double x, y, z, nut; @@ -762,14 +762,14 @@ void GaussianInterpExtData::setFieldTurbVisc() { string fnameturbBase; std::string basepathturb("./inputs/"); fnameturbBase = (basepathturb + fname_turb_); - const char *fnameturbRead = fnameturbBase.c_str(); + const char* fnameturbRead = fnameturbBase.c_str(); int nCountTurb = 0; // find size if (rank0_) { std::cout << " Attempting to open turb file for counting... " << fnameturbRead << " "; - FILE *inlet_file; + FILE* inlet_file; if ((inlet_file = fopen(fnameturbRead, "r"))) { std::cout << " ...and open" << endl; fflush(stdout); @@ -913,9 +913,9 @@ void GaussianInterpExtData::setInletTurbScalars() { ParGridFunction coordsDof(vfes_); pmesh_->GetNodes(coordsDof); - double *TKEdata = tke_gf_.HostReadWrite(); - double *V2data = v2_gf_.HostReadWrite(); - double *hcoords = coordsDof.HostReadWrite(); + double* TKEdata = tke_gf_.HostReadWrite(); + double* V2data = v2_gf_.HostReadWrite(); + double* hcoords = coordsDof.HostReadWrite(); struct tke_profile { double x, y, z, tke, v2; @@ -924,14 +924,14 @@ void GaussianInterpExtData::setInletTurbScalars() { string fnametkeBase; std::string basepathtke("./inputs/"); fnametkeBase = (basepathtke + fname_tke_); - const char *fnametkeRead = fnametkeBase.c_str(); + const char* fnametkeRead = fnametkeBase.c_str(); int nCountTKE = 0; // find size if (rank0_) { std::cout << " Attempting to open zeta-f file for counting... " << fnametkeRead << " "; - FILE *inlet_file; + FILE* inlet_file; if ((inlet_file = fopen(fnametkeRead, "r"))) { std::cout << " ...and open" << endl; fflush(stdout); @@ -1105,10 +1105,10 @@ void GaussianInterpExtData::step() { return; } - double *Udata = velocity_gf_.HostReadWrite(); - double *U0 = vel0_gf_.HostReadWrite(); - double *Thdata = swirl_gf_.HostReadWrite(); - double *Th0 = swirl0_gf_.HostReadWrite(); + double* Udata = velocity_gf_.HostReadWrite(); + double* U0 = vel0_gf_.HostReadWrite(); + double* Thdata = swirl_gf_.HostReadWrite(); + double* Th0 = swirl0_gf_.HostReadWrite(); // only addressing velocity for now and assume ic is zero for (int eq = 0; eq < dim_; eq++) { diff --git a/src/gaussianInterpExtData.hpp b/src/gaussianInterpExtData.hpp index e12d04f9..bb9a3a31 100644 --- a/src/gaussianInterpExtData.hpp +++ b/src/gaussianInterpExtData.hpp @@ -65,13 +65,13 @@ class GaussianInterpExtData : public ExternalDataBase { private: // pointer to parent Tps class - TPS::Tps *tpsP_ = nullptr; + TPS::Tps* tpsP_ = nullptr; // Run options - LoMachOptions *loMach_opts_; // = nullptr; + LoMachOptions* loMach_opts_; // = nullptr; // MPI helpers - MPI_Groups *groupsMPI_ = nullptr; + MPI_Groups* groupsMPI_ = nullptr; int nprocs_; // total number of MPI procs int rank_; // local MPI rank bool rank0_; // flag to indicate rank 0 @@ -85,7 +85,7 @@ class GaussianInterpExtData : public ExternalDataBase { /// Enable/disable verbose output. bool verbose = true; - ParMesh *pmesh_; // = nullptr; + ParMesh* pmesh_; // = nullptr; // The order of the scalar spaces int order_; @@ -96,7 +96,7 @@ class GaussianInterpExtData : public ExternalDataBase { // Coefficients necessary to take a time step (including dt). // Assumed to be externally managed and determined, so just get a // reference here. - const temporalSchemeCoefficients &coeff_; + const temporalSchemeCoefficients& coeff_; // to-be used fro time or timestep dep bc // double dt; @@ -122,18 +122,18 @@ class GaussianInterpExtData : public ExternalDataBase { double tke_bc_fac_; // Scalar \f$H^1\f$ finite element collection. - FiniteElementCollection *sfec_ = nullptr; + FiniteElementCollection* sfec_ = nullptr; // Scalar \f$H^1\f$ finite element space. - ParFiniteElementSpace *sfes_ = nullptr; + ParFiniteElementSpace* sfes_ = nullptr; // Vector \f$H^1\f$ finite element collection & space - FiniteElementCollection *vfec_ = nullptr; - ParFiniteElementSpace *vfes_ = nullptr; + FiniteElementCollection* vfec_ = nullptr; + ParFiniteElementSpace* vfes_ = nullptr; // for species dirichlet bc - FiniteElementCollection *yfec_ = nullptr; - ParFiniteElementSpace *yfes_ = nullptr; + FiniteElementCollection* yfec_ = nullptr; + ParFiniteElementSpace* yfes_ = nullptr; ParGridFunction temperature_gf_; ParGridFunction velocity_gf_; @@ -153,12 +153,12 @@ class GaussianInterpExtData : public ExternalDataBase { const int maxSpec_ = 10; public: - GaussianInterpExtData(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalSchemeCoefficients &coeff, - TPS::Tps *tps); + GaussianInterpExtData(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalSchemeCoefficients& coeff, + TPS::Tps* tps); virtual ~GaussianInterpExtData(); void initializeSelf(); - void initializeViz(ParaViewDataCollection &pvdc) final; + void initializeViz(ParaViewDataCollection& pvdc) final; void setup(); void setInlet(); void setInletTurbScalars(); @@ -167,18 +167,18 @@ class GaussianInterpExtData : public ExternalDataBase { void step(); /// Return a pointer to the current temperature ParGridFunction. - ParGridFunction *GetExternalInterpolatedTemperature() { return &temperature_gf_; } + ParGridFunction* GetExternalInterpolatedTemperature() { return &temperature_gf_; } /// Return a pointer to the current velocity ParGridFunction. - ParGridFunction *GetExternalInterpolatedVelocity() { return &velocity_gf_; } + ParGridFunction* GetExternalInterpolatedVelocity() { return &velocity_gf_; } /// Return a pointer to the current TKE ParGridFunction. - ParGridFunction *GetExternalInterpolatedTurbKineticEnergy() { return &tke_gf_; } + ParGridFunction* GetExternalInterpolatedTurbKineticEnergy() { return &tke_gf_; } /// Return a pointer to the current v2 ParGridFunction. - ParGridFunction *GetExternalInterpolatedTurbV2() { return &v2_gf_; } + ParGridFunction* GetExternalInterpolatedTurbV2() { return &v2_gf_; } /// Return a pointer to the current eddy viscosity ParGridFunction. - ParGridFunction *GetExternalInterpolatedEddyViscosity() { return &nut_gf_; } + ParGridFunction* GetExternalInterpolatedEddyViscosity() { return &nut_gf_; } }; #endif // GAUSSIANINTERPEXTDATA_HPP_ diff --git a/src/geometricSponge.cpp b/src/geometricSponge.cpp index 4d3e66ba..f359965e 100644 --- a/src/geometricSponge.cpp +++ b/src/geometricSponge.cpp @@ -49,7 +49,7 @@ using namespace mfem; using namespace mfem::common; -GeometricSponge::GeometricSponge(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, TPS::Tps *tps) +GeometricSponge::GeometricSponge(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, TPS::Tps* tps) : tpsP_(tps), loMach_opts_(loMach_opts), pmesh_(pmesh) { rank_ = pmesh_->GetMyRank(); rank0_ = (pmesh_->GetMyRank() == 0); @@ -138,14 +138,14 @@ void GeometricSponge::initializeSelf() { toTurbModel_interface_.diff_multiplier = &mult_gf_; } -void GeometricSponge::initializeViz(ParaViewDataCollection &pvdc) { pvdc.RegisterField("sponge", &mult_gf_); } +void GeometricSponge::initializeViz(ParaViewDataCollection& pvdc) { pvdc.RegisterField("sponge", &mult_gf_); } void GeometricSponge::setup() { ParGridFunction coordsDof(vfes_); pmesh_->GetNodes(coordsDof); - double *data = mult_gf_.HostReadWrite(); - const double *hcoords = coordsDof.HostRead(); + double* data = mult_gf_.HostReadWrite(); + const double* hcoords = coordsDof.HostRead(); for (int i = 0; i < Sdof_; i++) { double coords[3]; @@ -162,7 +162,7 @@ void GeometricSponge::setup() { } } -void GeometricSponge::spongeUniform(double &wgt) { +void GeometricSponge::spongeUniform(double& wgt) { double factor, wgt_lcl; factor = uniform.mult; factor = max(factor, 1.0); @@ -170,7 +170,7 @@ void GeometricSponge::spongeUniform(double &wgt) { wgt = max(wgt, wgt_lcl); } -void GeometricSponge::spongePlane(double *x, double &wgt) { +void GeometricSponge::spongePlane(double* x, double& wgt) { double normal[3]; double point[3]; double s[3]; @@ -201,7 +201,7 @@ void GeometricSponge::spongePlane(double *x, double &wgt) { } // TODO(swh): add suppport for arbitrary orientation of cylinder axis -void GeometricSponge::spongeCylinder(double *xGlobal, double &wgt) { +void GeometricSponge::spongeCylinder(double* xGlobal, double& wgt) { // C++ standard frowns on use of non-compile time arrays, e.g. // point[dim_], hence the requirement for hard-codes here and // elsewhere in this class @@ -264,7 +264,7 @@ void GeometricSponge::spongeCylinder(double *xGlobal, double &wgt) { } // TODO(swh): NOT GENERAL, only for annulus aligned with y -void GeometricSponge::spongeAnnulus(double *xGlobal, double &wgt) { +void GeometricSponge::spongeAnnulus(double* xGlobal, double& wgt) { double wgtAnn; double s[3]; double x[3]; diff --git a/src/geometricSponge.hpp b/src/geometricSponge.hpp index 46b4ca0c..15cf46cd 100644 --- a/src/geometricSponge.hpp +++ b/src/geometricSponge.hpp @@ -94,13 +94,13 @@ class LoMachOptions; class GeometricSponge : public SpongeBase { private: // pointer to parent Tps class - TPS::Tps *tpsP_ = nullptr; + TPS::Tps* tpsP_ = nullptr; // Run options - LoMachOptions *loMach_opts_; + LoMachOptions* loMach_opts_; // MPI helpers - MPI_Groups *groupsMPI_ = nullptr; + MPI_Groups* groupsMPI_ = nullptr; int nprocs_; // total number of MPI procs int rank_; // local MPI rank bool rank0_; // flag to indicate rank 0 @@ -111,7 +111,7 @@ class GeometricSponge : public SpongeBase { /// Enable/disable verbose output. bool verbose = true; - ParMesh *pmesh_; + ParMesh* pmesh_; // The order of the scalar spaces int order_; @@ -129,33 +129,33 @@ class GeometricSponge : public SpongeBase { geomAnnulus annulus; // Scalar \f$H^1\f$ finite element collection. - FiniteElementCollection *sfec_ = nullptr; + FiniteElementCollection* sfec_ = nullptr; // Scalar \f$H^1\f$ finite element space. - ParFiniteElementSpace *sfes_ = nullptr; + ParFiniteElementSpace* sfes_ = nullptr; // Vector \f$H^1\f$ finite element collection & space - FiniteElementCollection *vfec_ = nullptr; - ParFiniteElementSpace *vfes_ = nullptr; + FiniteElementCollection* vfec_ = nullptr; + ParFiniteElementSpace* vfes_ = nullptr; ParGridFunction mult_gf_; // Vector mult_; public: - GeometricSponge(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, TPS::Tps *tps); + GeometricSponge(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, TPS::Tps* tps); virtual ~GeometricSponge(); void initializeSelf(); - void initializeViz(ParaViewDataCollection &pvdc) final; + void initializeViz(ParaViewDataCollection& pvdc) final; void setup(); void step(); - void spongeUniform(double &wgt); - void spongePlane(double *x, double &wgt); - void spongeCylinder(double *x, double &wgt); - void spongeAnnulus(double *x, double &wgt); + void spongeUniform(double& wgt); + void spongePlane(double* x, double& wgt); + void spongeCylinder(double* x, double& wgt); + void spongeAnnulus(double* x, double& wgt); /// Return a pointer to the current temperature ParGridFunction. - ParGridFunction *GetCurrentMultiplier() { return &mult_gf_; } + ParGridFunction* GetCurrentMultiplier() { return &mult_gf_; } }; #endif // GEOMETRICSPONGE_HPP_ diff --git a/src/gpu_constructor.cpp b/src/gpu_constructor.cpp index 54e5f0e3..7e0c993a 100644 --- a/src/gpu_constructor.cpp +++ b/src/gpu_constructor.cpp @@ -42,93 +42,93 @@ namespace gpu { //--------------------------------------------------- // Constructors first //--------------------------------------------------- -__global__ void instantiateDeviceDryAir(const DryAirInput inputs, int _dim, int nvel, void *mix) { +__global__ void instantiateDeviceDryAir(const DryAirInput inputs, int _dim, int nvel, void* mix) { mix = new (mix) DryAir(inputs, _dim, nvel); } -__global__ void instantiateDevicePerfectMixture(const PerfectMixtureInput inputs, int _dim, int nvel, void *mix) { +__global__ void instantiateDevicePerfectMixture(const PerfectMixtureInput inputs, int _dim, int nvel, void* mix) { mix = new (mix) PerfectMixture(inputs, _dim, nvel); } __global__ void instantiateDeviceLteMixture(WorkingFluid f, int _dim, int nvel, double pc, TableInput energy_table_input, TableInput R_table_input, - TableInput c_table_input, TableInput T_table_input, void *mix) { + TableInput c_table_input, TableInput T_table_input, void* mix) { mix = new (mix) LteMixture(f, _dim, nvel, pc, energy_table_input, R_table_input, c_table_input, T_table_input); } -__global__ void instantiateDeviceDryAirTransport(GasMixture *mixture, const double viscosity_multiplier, +__global__ void instantiateDeviceDryAirTransport(GasMixture* mixture, const double viscosity_multiplier, const double bulk_viscosity, const double C1, const double S0, - const double Pr, void *transport) { + const double Pr, void* transport) { transport = new (transport) DryAirTransport(mixture, viscosity_multiplier, bulk_viscosity, C1, S0, Pr); } -__global__ void instantiateDeviceConstantTransport(GasMixture *mixture, const constantTransportData inputs, - void *trans) { +__global__ void instantiateDeviceConstantTransport(GasMixture* mixture, const constantTransportData inputs, + void* trans) { trans = new (trans) ConstantTransport(mixture, inputs); } -__global__ void instantiateDeviceGasMinimalTransport(GasMixture *mixture, const GasTransportInput inputs, void *trans) { +__global__ void instantiateDeviceGasMinimalTransport(GasMixture* mixture, const GasTransportInput inputs, void* trans) { trans = new (trans) GasMinimalTransport(mixture, inputs); } -__global__ void instantiateDeviceGasMixtureTransport(GasMixture *mixture, const GasTransportInput inputs, void *trans) { +__global__ void instantiateDeviceGasMixtureTransport(GasMixture* mixture, const GasTransportInput inputs, void* trans) { trans = new (trans) GasMixtureTransport(mixture, inputs); } -__global__ void instantiateDeviceLteTransport(GasMixture *mixture, TableInput mu_table_input, - TableInput kappa_table_input, TableInput sigma_table_input, void *trans) { +__global__ void instantiateDeviceLteTransport(GasMixture* mixture, TableInput mu_table_input, + TableInput kappa_table_input, TableInput sigma_table_input, void* trans) { trans = new (trans) LteTransport(mixture, mu_table_input, kappa_table_input, sigma_table_input); } -__global__ void instantiateDeviceMixingLengthTransport(GasMixture *mixture, const mixingLengthTransportData inputs, - TransportProperties *mol_trans, void *trans) { +__global__ void instantiateDeviceMixingLengthTransport(GasMixture* mixture, const mixingLengthTransportData inputs, + TransportProperties* mol_trans, void* trans) { // can't dynamic_cast on the device, so regular cast here - MolecularTransport *temporary_transport = (MolecularTransport *)mol_trans; + MolecularTransport* temporary_transport = (MolecularTransport*)mol_trans; trans = new (trans) MixingLengthTransport(mixture, inputs, temporary_transport); } -__global__ void instantiateDeviceFluxes(GasMixture *_mixture, Equations _eqSystem, TransportProperties *_transport, +__global__ void instantiateDeviceFluxes(GasMixture* _mixture, Equations _eqSystem, TransportProperties* _transport, const int _num_equation, const int _dim, bool axisym, int sgs_model, - double sgs_floor, double sgs_const, viscositySpongeData vsd, void *f) { + double sgs_floor, double sgs_const, viscositySpongeData vsd, void* f) { f = new (f) Fluxes(_mixture, _eqSystem, _transport, _num_equation, _dim, axisym, sgs_model, sgs_floor, sgs_const, vsd); } -__global__ void instantiateDeviceRiemann(int _num_equation, GasMixture *_mixture, Equations _eqSystem, - Fluxes *_fluxClass, bool _useRoe, bool axisym, void *r) { +__global__ void instantiateDeviceRiemann(int _num_equation, GasMixture* _mixture, Equations _eqSystem, + Fluxes* _fluxClass, bool _useRoe, bool axisym, void* r) { r = new (r) RiemannSolverTPS(_num_equation, _mixture, _eqSystem, _fluxClass, _useRoe, axisym); } -__global__ void instantiateDeviceChemistry(GasMixture *mixture, const ChemistryInput inputs, void *chem) { +__global__ void instantiateDeviceChemistry(GasMixture* mixture, const ChemistryInput inputs, void* chem) { chem = new (chem) Chemistry(mixture, inputs); } -__global__ void instantiateDeviceNetEmission(const RadiationInput inputs, void *radiation) { +__global__ void instantiateDeviceNetEmission(const RadiationInput inputs, void* radiation) { radiation = new (radiation) NetEmission(inputs); } //--------------------------------------------------- // And then destructors //--------------------------------------------------- -__global__ void freeDeviceFluxes(Fluxes *f) { f->~Fluxes(); } -__global__ void freeDeviceRiemann(RiemannSolverTPS *r) { r->~RiemannSolverTPS(); } -__global__ void freeDeviceMixture(GasMixture *mix) { mix->~GasMixture(); } -__global__ void freeDeviceTransport(TransportProperties *transport) { transport->~TransportProperties(); } -__global__ void freeDeviceChemistry(Chemistry *chem) { +__global__ void freeDeviceFluxes(Fluxes* f) { f->~Fluxes(); } +__global__ void freeDeviceRiemann(RiemannSolverTPS* r) { r->~RiemannSolverTPS(); } +__global__ void freeDeviceMixture(GasMixture* mix) { mix->~GasMixture(); } +__global__ void freeDeviceTransport(TransportProperties* transport) { transport->~TransportProperties(); } +__global__ void freeDeviceChemistry(Chemistry* chem) { if (chem != NULL) chem->~Chemistry(); } -__global__ void freeDeviceRadiation(Radiation *radiation) { +__global__ void freeDeviceRadiation(Radiation* radiation) { if (radiation != NULL) radiation->~Radiation(); } //--------------------------------------------------- // And finally device setters //--------------------------------------------------- -__global__ void deviceSetGridFunctionReactionData(const double *data, int size, GridFunctionReaction *reaction) { +__global__ void deviceSetGridFunctionReactionData(const double* data, int size, GridFunctionReaction* reaction) { reaction->setData(data, size); } -__global__ void deviceSetChemistryReactionData(const double *data, int size, Chemistry *chem) { +__global__ void deviceSetChemistryReactionData(const double* data, int size, Chemistry* chem) { chem->setRates(data, size); } diff --git a/src/gpu_constructor.hpp b/src/gpu_constructor.hpp index 9ec46687..0d8c741b 100644 --- a/src/gpu_constructor.hpp +++ b/src/gpu_constructor.hpp @@ -92,75 +92,75 @@ namespace gpu { #if defined(_CUDA_) || defined(_HIP_) //! Instantiate DryAir object on the device with placement new -__global__ void instantiateDeviceDryAir(const DryAirInput inputs, int _dim, int nvel, void *mix); +__global__ void instantiateDeviceDryAir(const DryAirInput inputs, int _dim, int nvel, void* mix); //! Instantiate PerfectMixture object on the device with placement new -__global__ void instantiateDevicePerfectMixture(const PerfectMixtureInput inputs, int _dim, int nvel, void *mix); +__global__ void instantiateDevicePerfectMixture(const PerfectMixtureInput inputs, int _dim, int nvel, void* mix); //! Instantiate LteMixture object on the device with placement new __global__ void instantiateDeviceLteMixture(WorkingFluid f, int _dim, int nvel, double pc, TableInput energy_table_input, TableInput R_table_input, - TableInput c_table_input, TableInput T_table_input, void *mix); + TableInput c_table_input, TableInput T_table_input, void* mix); //! Instantiate DryAirTransport object on the device with placement new -__global__ void instantiateDeviceDryAirTransport(GasMixture *mixture, const double viscosity_multiplier, +__global__ void instantiateDeviceDryAirTransport(GasMixture* mixture, const double viscosity_multiplier, const double bulk_viscosity, const double C1, const double S0, - const double Pr, void *transport); + const double Pr, void* transport); //! Instantiate ConstantTransport object on the device with placement new -__global__ void instantiateDeviceConstantTransport(GasMixture *mixture, const constantTransportData inputs, - void *trans); +__global__ void instantiateDeviceConstantTransport(GasMixture* mixture, const constantTransportData inputs, + void* trans); //! Instantiate GasMinimalTransport object on the device with placement new -__global__ void instantiateDeviceGasMinimalTransport(GasMixture *mixture, const GasTransportInput inputs, void *trans); +__global__ void instantiateDeviceGasMinimalTransport(GasMixture* mixture, const GasTransportInput inputs, void* trans); //! Instantiate GasMixtureTransport object on the device with placement new -__global__ void instantiateDeviceGasMixtureTransport(GasMixture *mixture, const GasTransportInput inputs, void *trans); +__global__ void instantiateDeviceGasMixtureTransport(GasMixture* mixture, const GasTransportInput inputs, void* trans); //! Instantiate ConstantTransport object on the device with placement new -__global__ void instantiateDeviceLteTransport(GasMixture *mixture, TableInput mu_table_input, - TableInput kappa_table_input, TableInput sigma_table_input, void *trans); +__global__ void instantiateDeviceLteTransport(GasMixture* mixture, TableInput mu_table_input, + TableInput kappa_table_input, TableInput sigma_table_input, void* trans); //! Instantiate MixingLengthTransport object on the device with placement new -__global__ void instantiateDeviceMixingLengthTransport(GasMixture *mixture, const mixingLengthTransportData inputs, - TransportProperties *mol_trans, void *trans); +__global__ void instantiateDeviceMixingLengthTransport(GasMixture* mixture, const mixingLengthTransportData inputs, + TransportProperties* mol_trans, void* trans); //! Instantiate Fluxes object on the device with placement new -__global__ void instantiateDeviceFluxes(GasMixture *_mixture, Equations _eqSystem, TransportProperties *_transport, +__global__ void instantiateDeviceFluxes(GasMixture* _mixture, Equations _eqSystem, TransportProperties* _transport, const int _num_equation, const int _dim, bool axisym, int sgs_model, - double sgs_floor, double sgs_const, viscositySpongeData vsd, void *f); + double sgs_floor, double sgs_const, viscositySpongeData vsd, void* f); //! Instantiate RiemannSolverTPS object on the device with placement new -__global__ void instantiateDeviceRiemann(int _num_equation, GasMixture *_mixture, Equations _eqSystem, - Fluxes *_fluxClass, bool _useRoe, bool axisym, void *r); +__global__ void instantiateDeviceRiemann(int _num_equation, GasMixture* _mixture, Equations _eqSystem, + Fluxes* _fluxClass, bool _useRoe, bool axisym, void* r); //! Instantiate Chemistry object on the device with placement new -__global__ void instantiateDeviceChemistry(GasMixture *mixture, const ChemistryInput inputs, void *chem); +__global__ void instantiateDeviceChemistry(GasMixture* mixture, const ChemistryInput inputs, void* chem); //! Instantiate NetEmission object on the device with placement new -__global__ void instantiateDeviceNetEmission(const RadiationInput inputs, void *radiation); +__global__ void instantiateDeviceNetEmission(const RadiationInput inputs, void* radiation); //! Explicit call to GasMixture destructor on the device -__global__ void freeDeviceMixture(GasMixture *mix); +__global__ void freeDeviceMixture(GasMixture* mix); //! Explicit call to TransportProperties destructor on the device -__global__ void freeDeviceTransport(TransportProperties *transport); +__global__ void freeDeviceTransport(TransportProperties* transport); //! Explicit call to Fluxes destructor on the device -__global__ void freeDeviceFluxes(Fluxes *f); +__global__ void freeDeviceFluxes(Fluxes* f); //! Explicit call to RiemannSolverTPS destructor on the device -__global__ void freeDeviceRiemann(RiemannSolverTPS *r); +__global__ void freeDeviceRiemann(RiemannSolverTPS* r); //! Explicit call to Chemistry destructor on the device -__global__ void freeDeviceChemistry(Chemistry *chem); +__global__ void freeDeviceChemistry(Chemistry* chem); //! Explicit call to Radiation destructor on the device -__global__ void freeDeviceRadiation(Radiation *radiation); +__global__ void freeDeviceRadiation(Radiation* radiation); //! Set the data to a GridFunctionReaction -__global__ void deviceSetGridFunctionReactionData(const double *data, int size, GridFunctionReaction *reaction); -__global__ void deviceSetChemistryReactionData(const double *data, int size, Chemistry *chem); +__global__ void deviceSetGridFunctionReactionData(const double* data, int size, GridFunctionReaction* reaction); +__global__ void deviceSetChemistryReactionData(const double* data, int size, Chemistry* chem); #endif // cuda or hip } // namespace gpu diff --git a/src/gradNonLinearForm.cpp b/src/gradNonLinearForm.cpp index 764a4b54..af4617cd 100644 --- a/src/gradNonLinearForm.cpp +++ b/src/gradNonLinearForm.cpp @@ -33,13 +33,13 @@ #include "riemann_solver.hpp" -GradNonLinearForm::GradNonLinearForm(ParFiniteElementSpace *_vfes, IntegrationRules *_intRules, const int _dim, +GradNonLinearForm::GradNonLinearForm(ParFiniteElementSpace* _vfes, IntegrationRules* _intRules, const int _dim, const int _num_equation) : ParNonlinearForm(_vfes), vfes(_vfes), intRules(_intRules), dim(_dim), num_equation(_num_equation) {} -void GradNonLinearForm::Apply(const ParGridFunction *Up, Vector &y) { +void GradNonLinearForm::Apply(const ParGridFunction* Up, Vector& y) { Vector x; - const double *data = Up->GetData(); + const double* data = Up->GetData(); // NB: Setting x here accounts for the fact that the space Up lives // in is different from the space of the gradient. diff --git a/src/gradNonLinearForm.hpp b/src/gradNonLinearForm.hpp index 63c9ad6e..5788731f 100644 --- a/src/gradNonLinearForm.hpp +++ b/src/gradNonLinearForm.hpp @@ -42,15 +42,15 @@ using namespace std; class GradNonLinearForm : public ParNonlinearForm { private: - ParFiniteElementSpace *vfes; - IntegrationRules *intRules; + ParFiniteElementSpace* vfes; + IntegrationRules* intRules; const int dim; const int num_equation; public: - GradNonLinearForm(ParFiniteElementSpace *f, IntegrationRules *intRules, const int dim, const int num_equation); + GradNonLinearForm(ParFiniteElementSpace* f, IntegrationRules* intRules, const int dim, const int num_equation); - void Apply(const ParGridFunction *Up, Vector &y); + void Apply(const ParGridFunction* Up, Vector& y); }; #endif // GRADNONLINEARFORM_HPP_ diff --git a/src/gradients.cpp b/src/gradients.cpp index 67337b35..cf579767 100644 --- a/src/gradients.cpp +++ b/src/gradients.cpp @@ -33,11 +33,11 @@ #include "dgNonlinearForm.hpp" -Gradients::Gradients(ParFiniteElementSpace *_vfes, ParFiniteElementSpace *_gradUpfes, int _dim, int _num_equation, - ParGridFunction *_Up, ParGridFunction *_gradUp, GasMixture *_mixture, GradNonLinearForm *_gradUp_A, - IntegrationRules *_intRules, int _intRuleType, - const precomputedIntegrationData &gpu_precomputed_data, Array &_Me_inv, - Vector &_invMArray, Array &_posDofInvM, const int &_maxIntPoints, const int &_maxDofs, +Gradients::Gradients(ParFiniteElementSpace* _vfes, ParFiniteElementSpace* _gradUpfes, int _dim, int _num_equation, + ParGridFunction* _Up, ParGridFunction* _gradUp, GasMixture* _mixture, GradNonLinearForm* _gradUp_A, + IntegrationRules* _intRules, int _intRuleType, + const precomputedIntegrationData& gpu_precomputed_data, Array& _Me_inv, + Vector& _invMArray, Array& _posDofInvM, const int& _maxIntPoints, const int& _maxDofs, int nvel) : ParNonlinearForm(_vfes), vfes(_vfes), @@ -57,7 +57,7 @@ Gradients::Gradients(ParFiniteElementSpace *_vfes, ParFiniteElementSpace *_gradU posDofInvM(_posDofInvM), maxIntPoints_(_maxIntPoints), maxDofs_(_maxDofs) { - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; h_num_elems_of_type = elem_data.num_elems_of_type.HostRead(); uk_el1.UseDevice(true); @@ -87,15 +87,15 @@ Gradients::Gradients(ParFiniteElementSpace *_vfes, ParFiniteElementSpace *_gradU // element derivative stiffness matrix Ke.SetSize(vfes->GetNE()); for (int el = 0; el < vfes->GetNE(); el++) { - const FiniteElement *elem = vfes->GetFE(el); - ElementTransformation *Tr = vfes->GetElementTransformation(el); + const FiniteElement* elem = vfes->GetFE(el); + ElementTransformation* Tr = vfes->GetElementTransformation(el); const int eldDof = elem->GetDof(); Ke[el] = new DenseMatrix(eldDof, dim_ * eldDof); // element volume integral int intorder = 2 * elem->GetOrder(); - const IntegrationRule *ir = &intRules->Get(elem->GetGeomType(), intorder); + const IntegrationRule* ir = &intRules->Get(elem->GetGeomType(), intorder); Vector shape(eldDof); DenseMatrix dshape(eldDof, dim_); @@ -143,8 +143,8 @@ Gradients::~Gradients() { void Gradients::computeGradients() { const int totalDofs = vfes->GetNDofs(); - double *dataUp = Up->GetData(); - double *dataGradUp = gradUp->GetData(); + double* dataUp = Up->GetData(); + double* dataGradUp = gradUp->GetData(); // Vars for face contributions Vector faceContrib(dim_ * num_equation_ * totalDofs); @@ -153,7 +153,7 @@ void Gradients::computeGradients() { // compute volume integral and fill out above vectors DenseMatrix elGradUp; for (int el = 0; el < vfes->GetNE(); el++) { - const FiniteElement *elem = vfes->GetFE(el); + const FiniteElement* elem = vfes->GetFE(el); // get local primitive variables Array vdofs; @@ -197,7 +197,7 @@ void Gradients::computeGradients() { // Add contributions and multiply by invers mass matrix for (int el = 0; el < vfes->GetNE(); el++) { - const FiniteElement *elem = vfes->GetFE(el); + const FiniteElement* elem = vfes->GetFE(el); const int eldDof = elem->GetDof(); Array vdofs; @@ -235,7 +235,7 @@ void Gradients::computeGradients() { void Gradients::computeGradients_domain() { DGNonLinearForm::setToZero_gpu(*gradUp, gradUp->Size()); - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto h_elem_dof_num = elem_data.dof_number.HostRead(); // Interpolate state info the faces (loops over elements) @@ -255,7 +255,7 @@ void Gradients::computeGradients_domain() { faceContrib_gpu(elType, elemOffset, dof_el); } - ParMesh *pmesh = vfes->GetParMesh(); + ParMesh* pmesh = vfes->GetParMesh(); const int Nbdry = pmesh->GetNFbyType(FaceType::Boundary); if (Nbdry > 0) { interpGradBdryFace_gpu(); @@ -271,13 +271,13 @@ void Gradients::computeGradients_domain() { } void Gradients::computeGradients_bdr() { - ParMesh *pmesh = vfes->GetParMesh(); + ParMesh* pmesh = vfes->GetParMesh(); const int Nshared = pmesh->GetNSharedFaces(); if (Nshared > 0) { interpGradSharedFace_gpu(); integrationGradSharedFace_gpu(); } - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto h_elem_dof_num = elem_data.dof_number.HostRead(); // Multiply by inverse mass matrix @@ -289,16 +289,16 @@ void Gradients::computeGradients_bdr() { } } -void Gradients::interpFaceData_gpu(const Vector &Up, int elType, int elemOffset, int elDof) { - const double *d_x = Up.Read(); // Primitives! - double *d_uk_el1 = uk_el1.Write(); - double *d_uk_el2 = uk_el2.Write(); +void Gradients::interpFaceData_gpu(const Vector& Up, int elType, int elemOffset, int elDof) { + const double* d_x = Up.Read(); // Primitives! + double* d_uk_el1 = uk_el1.Write(); + double* d_uk_el2 = uk_el2.Write(); - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto d_elem_dofs_list = elem_data.dofs_list.Read(); auto d_elem_dof_off = elem_data.dof_offset.Read(); - const interiorFaceIntegrationData &face_data = gpu_precomputed_data_.interior_face_data; + const interiorFaceIntegrationData& face_data = gpu_precomputed_data_.interior_face_data; auto d_element_to_faces = face_data.element_to_faces.Read(); auto d_shape1 = face_data.el1_shape.Read(); auto d_shape2 = face_data.el2_shape.Read(); @@ -384,10 +384,10 @@ void Gradients::interpFaceData_gpu(const Vector &Up, int elType, int elemOffset, } void Gradients::computeGradients_gpu(const int elType, const int offsetElems, const int elDof) { - const double *d_Up = Up->Read(); - double *d_gradUp = gradUp->ReadWrite(); + const double* d_Up = Up->Read(); + double* d_gradUp = gradUp->ReadWrite(); - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto d_elem_dof_off = elem_data.dof_offset.Read(); auto d_elem_dofs_list = elem_data.dofs_list.Read(); @@ -449,15 +449,15 @@ void Gradients::computeGradients_gpu(const int elType, const int offsetElems, co // clang-format on void Gradients::evalFaceIntegrand_gpu() { auto d_dun = dun_face.Write(); - const double *d_uk_el1 = uk_el1.Read(); - const double *d_uk_el2 = uk_el2.Read(); + const double* d_uk_el1 = uk_el1.Read(); + const double* d_uk_el2 = uk_el2.Read(); - const interiorFaceIntegrationData &face_data = gpu_precomputed_data_.interior_face_data; + const interiorFaceIntegrationData& face_data = gpu_precomputed_data_.interior_face_data; auto d_weight = face_data.quad_weight.Read(); auto d_normal = face_data.normal.Read(); auto d_face_nqp = face_data.num_quad.Read(); - Mesh *mesh = fes->GetMesh(); + Mesh* mesh = fes->GetMesh(); const int Nf = mesh->GetNumFaces(); const int dim = dim_; @@ -496,15 +496,15 @@ void Gradients::evalFaceIntegrand_gpu() { // clang-format on void Gradients::faceContrib_gpu(const int elType, const int offsetElems, const int elDof) { - const double *d_dun = dun_face.Read(); + const double* d_dun = dun_face.Read(); - double *d_gradUp = gradUp->Write(); // NB: I assume this comes in set to zero! + double* d_gradUp = gradUp->Write(); // NB: I assume this comes in set to zero! - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto d_elem_dof_off = elem_data.dof_offset.Read(); auto d_elem_dofs_list = elem_data.dofs_list.Read(); - const interiorFaceIntegrationData &face_data = gpu_precomputed_data_.interior_face_data; + const interiorFaceIntegrationData& face_data = gpu_precomputed_data_.interior_face_data; auto d_element_to_faces = face_data.element_to_faces.Read(); auto d_shape1 = face_data.el1_shape.Read(); auto d_shape2 = face_data.el2_shape.Read(); @@ -525,7 +525,7 @@ void Gradients::faceContrib_gpu(const int elType, const int offsetElems, const i MFEM_FOREACH_THREAD(i, x, elDof) { const int idx = d_elem_dofs_list[offsetIDs + i]; - double const *shape; + double const* shape; // ================ FACE CONTRIBUTION ================ const int elFaces = d_element_to_faces[7 * eli]; @@ -565,25 +565,25 @@ void Gradients::faceContrib_gpu(const int elType, const int offsetElems, const i } void Gradients::interpGradSharedFace_gpu() { - const double *d_up = Up->Read(); - const double *d_faceData = transferUp->face_nbr_data.Read(); - - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; - const int *d_elem_dofs_list = elem_data.dofs_list.Read(); - const int *d_elem_dof_off = elem_data.dof_offset.Read(); - const int *d_elem_dof_num = elem_data.dof_number.Read(); - - const sharedFaceIntegrationData &shared_face_data = gpu_precomputed_data_.shared_face_data; - const double *d_weight = shared_face_data.quad_weight.Read(); - const double *d_normal = shared_face_data.normal.Read(); - const double *d_shape1 = shared_face_data.el1_shape.Read(); - const double *d_shape2 = shared_face_data.el2_shape.Read(); - const int *d_face_num_quad = shared_face_data.num_quad.Read(); - const int *d_face_num_dof2 = shared_face_data.num_dof2.Read(); - const int *d_elem2_dofs = shared_face_data.elem2_dofs.Read(); - const int *d_shared_elements_to_shared_faces = shared_face_data.shared_elements_to_shared_faces.Read(); - - double *d_dun = dun_shared_face.Write(); + const double* d_up = Up->Read(); + const double* d_faceData = transferUp->face_nbr_data.Read(); + + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; + const int* d_elem_dofs_list = elem_data.dofs_list.Read(); + const int* d_elem_dof_off = elem_data.dof_offset.Read(); + const int* d_elem_dof_num = elem_data.dof_number.Read(); + + const sharedFaceIntegrationData& shared_face_data = gpu_precomputed_data_.shared_face_data; + const double* d_weight = shared_face_data.quad_weight.Read(); + const double* d_normal = shared_face_data.normal.Read(); + const double* d_shape1 = shared_face_data.el1_shape.Read(); + const double* d_shape2 = shared_face_data.el2_shape.Read(); + const int* d_face_num_quad = shared_face_data.num_quad.Read(); + const int* d_face_num_dof2 = shared_face_data.num_dof2.Read(); + const int* d_elem2_dofs = shared_face_data.elem2_dofs.Read(); + const int* d_shared_elements_to_shared_faces = shared_face_data.shared_elements_to_shared_faces.Read(); + + double* d_dun = dun_shared_face.Write(); const int maxNumElems = shared_face_data.shared_elements_to_shared_faces.Size() / 7; // elements with shared faces const int dim = dim_; @@ -658,19 +658,19 @@ void Gradients::interpGradSharedFace_gpu() { } void Gradients::integrationGradSharedFace_gpu() { - double *d_gradUp = gradUp->ReadWrite(); + double* d_gradUp = gradUp->ReadWrite(); - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; - const int *d_elem_dofs_list = elem_data.dofs_list.Read(); - const int *d_elem_dof_off = elem_data.dof_offset.Read(); - const int *d_elem_dof_num = elem_data.dof_number.Read(); + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; + const int* d_elem_dofs_list = elem_data.dofs_list.Read(); + const int* d_elem_dof_off = elem_data.dof_offset.Read(); + const int* d_elem_dof_num = elem_data.dof_number.Read(); - const sharedFaceIntegrationData &shared_face_data = gpu_precomputed_data_.shared_face_data; - const double *d_shape1 = shared_face_data.el1_shape.Read(); - const int *d_face_num_quad = shared_face_data.num_quad.Read(); - const int *d_shared_elements_to_shared_faces = shared_face_data.shared_elements_to_shared_faces.Read(); + const sharedFaceIntegrationData& shared_face_data = gpu_precomputed_data_.shared_face_data; + const double* d_shape1 = shared_face_data.el1_shape.Read(); + const int* d_face_num_quad = shared_face_data.num_quad.Read(); + const int* d_shared_elements_to_shared_faces = shared_face_data.shared_elements_to_shared_faces.Read(); - const double *d_dun = dun_shared_face.Read(); + const double* d_dun = dun_shared_face.Read(); const int dim = dim_; const int num_equation = num_equation_; @@ -713,28 +713,28 @@ void Gradients::integrationGradSharedFace_gpu() { } void Gradients::interpGradBdryFace_gpu() { - const double *d_up = Up->Read(); + const double* d_up = Up->Read(); - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; - const int *d_elem_dofs_list = elem_data.dofs_list.Read(); - const int *d_elem_dof_off = elem_data.dof_offset.Read(); - const int *d_elem_dof_num = elem_data.dof_number.Read(); + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; + const int* d_elem_dofs_list = elem_data.dofs_list.Read(); + const int* d_elem_dof_off = elem_data.dof_offset.Read(); + const int* d_elem_dof_num = elem_data.dof_number.Read(); - const boundaryFaceIntegrationData &bdry_face_data = gpu_precomputed_data_.boundary_face_data; - const double *d_weight = bdry_face_data.quad_weight.Read(); - const double *d_normal = bdry_face_data.normal.Read(); - const double *d_shape = bdry_face_data.shape.Read(); - const int *d_face_num_quad = bdry_face_data.num_quad.Read(); - const int *d_el_index = bdry_face_data.el.Read(); - const boundaryCategory *d_bc_cat = bdry_face_data.bc_category.Read(); - const bool *d_bc_use = bdry_face_data.use_bc_in_grad.Read(); - const double *d_wall_bc_temperature = bdry_face_data.wall_bc_temperature.Read(); + const boundaryFaceIntegrationData& bdry_face_data = gpu_precomputed_data_.boundary_face_data; + const double* d_weight = bdry_face_data.quad_weight.Read(); + const double* d_normal = bdry_face_data.normal.Read(); + const double* d_shape = bdry_face_data.shape.Read(); + const int* d_face_num_quad = bdry_face_data.num_quad.Read(); + const int* d_el_index = bdry_face_data.el.Read(); + const boundaryCategory* d_bc_cat = bdry_face_data.bc_category.Read(); + const bool* d_bc_use = bdry_face_data.use_bc_in_grad.Read(); + const double* d_wall_bc_temperature = bdry_face_data.wall_bc_temperature.Read(); - const int *d_rbf_to_abf = bdry_face_data.rbf_to_abf.Read(); + const int* d_rbf_to_abf = bdry_face_data.rbf_to_abf.Read(); // const double *d_xyz = bdry_face_data.xyz.Read(); - double *d_dun = dun_bdry_face.Write(); + double* d_dun = dun_bdry_face.Write(); const int dim = dim_; const int nvel = nvel_; @@ -815,19 +815,19 @@ void Gradients::interpGradBdryFace_gpu() { } void Gradients::integrationGradBdryFace_gpu() { - double *d_gradUp = gradUp->ReadWrite(); + double* d_gradUp = gradUp->ReadWrite(); - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; - const int *d_elem_dofs_list = elem_data.dofs_list.Read(); - const int *d_elem_dof_off = elem_data.dof_offset.Read(); - const int *d_elem_dof_num = elem_data.dof_number.Read(); + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; + const int* d_elem_dofs_list = elem_data.dofs_list.Read(); + const int* d_elem_dof_off = elem_data.dof_offset.Read(); + const int* d_elem_dof_num = elem_data.dof_number.Read(); - const boundaryFaceIntegrationData &bdry_face_data = gpu_precomputed_data_.boundary_face_data; - const double *d_shape = bdry_face_data.shape.Read(); - const int *d_face_num_quad = bdry_face_data.num_quad.Read(); - const int *d_elem_to_face = bdry_face_data.elements_to_faces.Read(); + const boundaryFaceIntegrationData& bdry_face_data = gpu_precomputed_data_.boundary_face_data; + const double* d_shape = bdry_face_data.shape.Read(); + const int* d_face_num_quad = bdry_face_data.num_quad.Read(); + const int* d_elem_to_face = bdry_face_data.elements_to_faces.Read(); - const double *d_dun = dun_bdry_face.Read(); + const double* d_dun = dun_bdry_face.Read(); const int dim = dim_; const int num_equation = num_equation_; @@ -877,13 +877,13 @@ void Gradients::integrationGradBdryFace_gpu() { } void Gradients::multInverse_gpu(const int numElems, const int offsetElems, const int elDof) { - double *d_gradUp = gradUp->ReadWrite(); + double* d_gradUp = gradUp->ReadWrite(); - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto d_elem_dof_off = elem_data.dof_offset.Read(); auto d_elem_dofs_list = elem_data.dofs_list.Read(); - const double *d_invMArray = invMArray.Read(); + const double* d_invMArray = invMArray.Read(); auto d_posDofInvM = posDofInvM.Read(); const int totalDofs = vfes->GetNDofs(); diff --git a/src/gradients.hpp b/src/gradients.hpp index e889dc9f..3e780cde 100644 --- a/src/gradients.hpp +++ b/src/gradients.hpp @@ -46,67 +46,67 @@ using namespace std; class Gradients : public ParNonlinearForm { private: - ParFiniteElementSpace *vfes; - ParFiniteElementSpace *gradUpfes; + ParFiniteElementSpace* vfes; + ParFiniteElementSpace* gradUpfes; const int dim_; const int num_equation_; const int nvel_; - ParGridFunction *Up; - ParGridFunction *gradUp; + ParGridFunction* Up; + ParGridFunction* gradUp; - GasMixture *mixture; + GasMixture* mixture; // ParNonlinearForm *gradUp_A; - GradNonLinearForm *gradUp_A; + GradNonLinearForm* gradUp_A; - IntegrationRules *intRules; + IntegrationRules* intRules; const int intRuleType; - const precomputedIntegrationData &gpu_precomputed_data_; + const precomputedIntegrationData& gpu_precomputed_data_; Vector uk_el1; Vector uk_el2; Vector dun_face; - const int *h_num_elems_of_type; + const int* h_num_elems_of_type; // DenseMatrix *Me_inv; - Array &Me_inv; - Array Ke; + Array& Me_inv; + Array Ke; Vector Ke_array_; Array Ke_positions_; - Vector &invMArray; - Array &posDofInvM; + Vector& invMArray; + Array& posDofInvM; - const int &maxIntPoints_; - const int &maxDofs_; + const int& maxIntPoints_; + const int& maxDofs_; // gradients of shape functions for all nodes and weight multiplied by det(Jac) // at each integration point // Vector elemShapeDshapeWJ; // [...l_0(i),...,l_dof(i),l_0_x(i),...,l_dof_d(i), w_i*detJac_i ...] // Array elemPosQ_shapeDshapeWJ; // position and num. of integration points for each element - dataTransferArrays *transferUp; + dataTransferArrays* transferUp; Vector dun_shared_face; Vector dun_bdry_face; public: - Gradients(ParFiniteElementSpace *_vfes, ParFiniteElementSpace *_gradUpfes, int _dim, int _num_equation, - ParGridFunction *_Up, ParGridFunction *_gradUp, GasMixture *_mixture, GradNonLinearForm *_gradUp_A, - IntegrationRules *_intRules, int _intRuleType, const precomputedIntegrationData &gpu_precomputed_data, - Array &Me_inv, Vector &_invMArray, Array &_posDofInvM, const int &_maxIntPoints, - const int &_maxDofs, int nvel); + Gradients(ParFiniteElementSpace* _vfes, ParFiniteElementSpace* _gradUpfes, int _dim, int _num_equation, + ParGridFunction* _Up, ParGridFunction* _gradUp, GasMixture* _mixture, GradNonLinearForm* _gradUp_A, + IntegrationRules* _intRules, int _intRuleType, const precomputedIntegrationData& gpu_precomputed_data, + Array& Me_inv, Vector& _invMArray, Array& _posDofInvM, const int& _maxIntPoints, + const int& _maxDofs, int nvel); ~Gradients(); - void setParallelData(dataTransferArrays *_transferUp) { + void setParallelData(dataTransferArrays* _transferUp) { transferUp = _transferUp; dun_shared_face.UseDevice(true); - const sharedFaceIntegrationData &shared_face_data = gpu_precomputed_data_.shared_face_data; + const sharedFaceIntegrationData& shared_face_data = gpu_precomputed_data_.shared_face_data; // number of elements with shared faces int maxNumElems = shared_face_data.shared_elements_to_shared_faces.Size() / 7; @@ -133,7 +133,7 @@ class Gradients : public ParNonlinearForm { void multInverse_gpu(const int numElems, const int offsetElems, const int elDof); - void interpFaceData_gpu(const Vector &x, int elType, int elemOffset, int elDof); + void interpFaceData_gpu(const Vector& x, int elType, int elemOffset, int elDof); void evalFaceIntegrand_gpu(); #endif }; diff --git a/src/gslib_interpolator.cpp b/src/gslib_interpolator.cpp index 5046e57e..7016b7aa 100644 --- a/src/gslib_interpolator.cpp +++ b/src/gslib_interpolator.cpp @@ -50,7 +50,7 @@ InterpolatorBase::~InterpolatorBase() { #endif } -void InterpolatorBase::initializeFinder(ParMesh *mesh) { +void InterpolatorBase::initializeFinder(ParMesh* mesh) { dim_ = mesh->Dimension(); #ifdef HAVE_GSLIB finder_ = new FindPointsGSLIB(mesh->GetComm()); @@ -66,7 +66,7 @@ void InterpolatorBase::setInterpolationPoints() { mfem_error("InterpolatorBase::setInterpolationPoints() is not implemented"); } -void InterpolatorBase::interpolate(ParGridFunction *u) { +void InterpolatorBase::interpolate(ParGridFunction* u) { assert(dim_ == 2 || dim_ == 3); const int totalPts = xyz_.Size(); diff --git a/src/gslib_interpolator.hpp b/src/gslib_interpolator.hpp index 44bb1ae8..e8ce859e 100644 --- a/src/gslib_interpolator.hpp +++ b/src/gslib_interpolator.hpp @@ -56,7 +56,7 @@ class InterpolatorBase { #ifdef HAVE_GSLIB // mfem interpolator - mfem::FindPointsGSLIB *finder_; + mfem::FindPointsGSLIB* finder_; #endif public: @@ -71,7 +71,7 @@ class InterpolatorBase { virtual ~InterpolatorBase(); /** Initialize the internal FindPointsGSLIB object */ - void initializeFinder(mfem::ParMesh *mesh); + void initializeFinder(mfem::ParMesh* mesh); /** Sets the interpolation points from user input */ void setInterpolationPoints(mfem::Vector xyz); @@ -82,7 +82,7 @@ class InterpolatorBase { * * Must call initializeFinder and setInterpolationPoints prior. */ - void interpolate(mfem::ParGridFunction *u); + void interpolate(mfem::ParGridFunction* u); /** Write the data to an ascii file */ virtual void writeAscii(std::string oname, bool rank0 = true) const; diff --git a/src/independent_coupling.cpp b/src/independent_coupling.cpp index 32112ec3..778f07a6 100644 --- a/src/independent_coupling.cpp +++ b/src/independent_coupling.cpp @@ -35,7 +35,7 @@ #include "em_options.hpp" #include "quasimagnetostatic.hpp" -IndependentCoupling::IndependentCoupling(string &inputFileName, TPS::Tps *tps) : em_opt_() { +IndependentCoupling::IndependentCoupling(string& inputFileName, TPS::Tps* tps) : em_opt_() { qmsa_solver_ = new QuasiMagnetostaticSolverAxiSym(em_opt_, tps); flow_solver_ = new M2ulPhyS(inputFileName, tps); } diff --git a/src/independent_coupling.hpp b/src/independent_coupling.hpp index b95136af..cc90e68e 100644 --- a/src/independent_coupling.hpp +++ b/src/independent_coupling.hpp @@ -48,11 +48,11 @@ class Tps; class IndependentCoupling : public TPS::Solver { private: ElectromagneticOptions em_opt_; - QuasiMagnetostaticSolverAxiSym *qmsa_solver_; - M2ulPhyS *flow_solver_; + QuasiMagnetostaticSolverAxiSym* qmsa_solver_; + M2ulPhyS* flow_solver_; public: - IndependentCoupling(string &inputFileName, TPS::Tps *tps); + IndependentCoupling(string& inputFileName, TPS::Tps* tps); ~IndependentCoupling(); void parseSolverOptions() override; diff --git a/src/inletBC.cpp b/src/inletBC.cpp index e0f08e0a..3d416fc0 100644 --- a/src/inletBC.cpp +++ b/src/inletBC.cpp @@ -35,10 +35,10 @@ #include "riemann_solver.hpp" // TODO(kevin): non-reflecting bc for plasam. -InletBC::InletBC(MPI_Groups *_groupsMPI, Equations _eqSystem, RiemannSolverTPS *_rsolver, GasMixture *_mixture, - GasMixture *d_mixture, ParFiniteElementSpace *_vfes, IntegrationRules *_intRules, double &_dt, +InletBC::InletBC(MPI_Groups* _groupsMPI, Equations _eqSystem, RiemannSolverTPS* _rsolver, GasMixture* _mixture, + GasMixture* d_mixture, ParFiniteElementSpace* _vfes, IntegrationRules* _intRules, double& _dt, const int _dim, const int _num_equation, int _patchNumber, double _refLength, InletType _bcType, - const Array &_inputData, const int &_maxIntPoints, const int &_maxDofs, bool axisym) + const Array& _inputData, const int& _maxIntPoints, const int& _maxDofs, bool axisym) : BoundaryCondition(_rsolver, _mixture, _eqSystem, _vfes, _intRules, _dt, _dim, _num_equation, _patchNumber, _refLength, axisym), groupsMPI(_groupsMPI), @@ -111,7 +111,7 @@ InletBC::InletBC(MPI_Groups *_groupsMPI, Equations _eqSystem, RiemannSolverTPS * for (int bel = 0; bel < vfes->GetNBE(); bel++) { int attr = vfes->GetBdrAttribute(bel); if (attr == patchNumber) { - FaceElementTransformations *Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); + FaceElementTransformations* Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); Array dofs; vfes->GetElementVDofs(Tr->Elem1No, dofs); @@ -254,7 +254,7 @@ void InletBC::initBdrElemsShape() { for (int bel = 0; bel < vfes->GetNBE(); bel++) { int attr = vfes->GetBdrAttribute(bel); if (attr == patchNumber) { - FaceElementTransformations *Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); + FaceElementTransformations* Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); int elDofs = vfes->GetFE(Tr->Elem1No)->GetDof(); Array dofs; vfes->GetElementVDofs(Tr->Elem1No, dofs); @@ -323,16 +323,16 @@ void InletBC::initBCs() { } } -void InletBC::updateMean_gpu(ParGridFunction *Up, Vector &localMeanUp, const int num_equation, const int numBdrElems, - const int totDofs, Vector &bdrUp, Array &bdrElemsQ, Array &bdrDofs, - Vector &bdrShape, const int &maxIntPoints, const int &maxDofs) { +void InletBC::updateMean_gpu(ParGridFunction* Up, Vector& localMeanUp, const int num_equation, const int numBdrElems, + const int totDofs, Vector& bdrUp, Array& bdrElemsQ, Array& bdrDofs, + Vector& bdrShape, const int& maxIntPoints, const int& maxDofs) { #ifdef _GPU_ - const double *d_Up = Up->Read(); - double *d_localMeanUp = localMeanUp.Write(); - double *d_bdrUp = bdrUp.Write(); + const double* d_Up = Up->Read(); + double* d_localMeanUp = localMeanUp.Write(); + double* d_bdrUp = bdrUp.Write(); auto d_bdrElemQ = bdrElemsQ.Read(); auto d_bdrDofs = bdrDofs.Read(); - const double *d_bdrShape = bdrShape.Read(); + const double* d_bdrShape = bdrShape.Read(); int groupAveraging = numBdrElems; if (groupAveraging % 2 != 0) groupAveraging++; @@ -391,7 +391,7 @@ void InletBC::updateMean_gpu(ParGridFunction *Up, Vector &localMeanUp, const int #endif } -void InletBC::initBoundaryU(ParGridFunction *Up) { +void InletBC::initBoundaryU(ParGridFunction* Up) { Vector elUp; elUp.UseDevice(false); Vector shape; @@ -403,7 +403,7 @@ void InletBC::initBoundaryU(ParGridFunction *Up) { for (int bel = 0; bel < vfes->GetNBE(); bel++) { int attr = vfes->GetBdrAttribute(bel); if (attr == patchNumber) { - FaceElementTransformations *Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); + FaceElementTransformations* Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); int elDofs = vfes->GetFE(Tr->Elem1No)->GetDof(); @@ -442,8 +442,8 @@ void InletBC::initBoundaryU(ParGridFunction *Up) { boundaryUp.Read(); } -void InletBC::computeBdrFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - double time, double distance, Vector &bdrFlux) { +void InletBC::computeBdrFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + double time, double distance, Vector& bdrFlux) { Vector tangentW(dim_); for (int d = 0; d < dim_; d++) tangentW[d] = 0.0; switch (inletType_) { @@ -479,7 +479,7 @@ void InletBC::computeBdrFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradS } } -void InletBC::updateMean(IntegrationRules *intRules, ParGridFunction *Up) { +void InletBC::updateMean(IntegrationRules* intRules, ParGridFunction* Up) { if (inletType_ == SUB_DENS_VEL) return; bdrN = 0; @@ -504,7 +504,7 @@ void InletBC::updateMean(IntegrationRules *intRules, ParGridFunction *Up) { for (int bel = 0; bel < vfes->GetNBE(); bel++) { int attr = vfes->GetBdrAttribute(bel); if (attr == patchNumber) { - FaceElementTransformations *Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); + FaceElementTransformations* Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); int elDofs = vfes->GetFE(Tr->Elem1No)->GetDof(); @@ -541,11 +541,11 @@ void InletBC::updateMean(IntegrationRules *intRules, ParGridFunction *Up) { } #endif - double *h_localMeanUp = localMeanUp.HostReadWrite(); + double* h_localMeanUp = localMeanUp.HostReadWrite(); int totNbdr = boundaryU.Size() / num_equation_; h_localMeanUp[num_equation_] = static_cast(totNbdr); - double *h_sum = glob_sum.HostWrite(); + double* h_sum = glob_sum.HostWrite(); MPI_Allreduce(h_localMeanUp, h_sum, num_equation_ + 1, MPI_DOUBLE, MPI_SUM, groupsMPI->getComm(patchNumber)); BoundaryCondition::copyValues(glob_sum, meanUp, 1. / h_sum[num_equation_]); @@ -563,18 +563,18 @@ void InletBC::updateMean(IntegrationRules *intRules, ParGridFunction *Up) { } } -void InletBC::integrationBC(Vector &y, // output - const Vector &x, const elementIndexingData &elem_index_data, ParGridFunction *Up, - ParGridFunction *gradUp, const boundaryFaceIntegrationData &boundary_face_data, - const int &maxIntPoints, const int &maxDofs) { +void InletBC::integrationBC(Vector& y, // output + const Vector& x, const elementIndexingData& elem_index_data, ParGridFunction* Up, + ParGridFunction* gradUp, const boundaryFaceIntegrationData& boundary_face_data, + const int& maxIntPoints, const int& maxDofs) { interpInlet_gpu(x, elem_index_data, boundary_face_data, listElems, offsetsBoundaryU); integrateInlets_gpu(y, // output x, elem_index_data, boundary_face_data, listElems, offsetsBoundaryU); } -void InletBC::subsonicNonReflectingDensityVelocity(Vector &normal, Vector &stateIn, DenseMatrix &gradState, - Vector &bdrFlux) { +void InletBC::subsonicNonReflectingDensityVelocity(Vector& normal, Vector& stateIn, DenseMatrix& gradState, + Vector& bdrFlux) { const double gamma = mixture->GetSpecificHeatRatio(); // const double p = eqState->ComputePressure(stateIn, dim); @@ -726,7 +726,7 @@ void InletBC::subsonicNonReflectingDensityVelocity(Vector &normal, Vector &state rsolver->Eval(stateIn, state2, normal, bdrFlux, true); } -void InletBC::subsonicReflectingDensityVelocity(Vector &normal, Vector &stateIn, Vector &bdrFlux) { +void InletBC::subsonicReflectingDensityVelocity(Vector& normal, Vector& stateIn, Vector& bdrFlux) { // NOTE: it is likely that for two-temperature case inlet will also specify electron temperature, // whether it is equal to the gas temperature or not. const double p = mixture->ComputePressure(stateIn); @@ -757,8 +757,8 @@ void InletBC::subsonicReflectingDensityVelocity(Vector &normal, Vector &stateIn, /// Specifying subsonic vel and rho wher v is relative to the FACE-coordinate system specifyied by the face normal and /// tangentW -void InletBC::subsonicReflectingDensityVelocityFace(Vector &normal, Vector tangentW, Vector &stateIn, Vector transip, - double time, Vector &bdrFlux) { +void InletBC::subsonicReflectingDensityVelocityFace(Vector& normal, Vector tangentW, Vector& stateIn, Vector transip, + double time, Vector& bdrFlux) { const double p = mixture->ComputePressure(stateIn); Vector state2(num_equation_); @@ -863,22 +863,22 @@ void InletBC::subsonicReflectingDensityVelocityFace(Vector &normal, Vector tange bdrN++; } -void InletBC::integrateInlets_gpu(Vector &y, const Vector &x, const elementIndexingData &elem_index_data, - const boundaryFaceIntegrationData &boundary_face_data, Array &listElems, - Array &offsetsBoundaryU) { +void InletBC::integrateInlets_gpu(Vector& y, const Vector& x, const elementIndexingData& elem_index_data, + const boundaryFaceIntegrationData& boundary_face_data, Array& listElems, + Array& offsetsBoundaryU) { #ifdef _GPU_ - double *d_y = y.ReadWrite(); - const int *d_elem_dofs_list = elem_index_data.dofs_list.Read(); - const int *d_elem_dof_off = elem_index_data.dof_offset.Read(); - const int *d_elem_dof_num = elem_index_data.dof_number.Read(); - const double *d_face_shape = boundary_face_data.shape.Read(); - const double *d_weight = boundary_face_data.quad_weight.Read(); - const int *d_face_el = boundary_face_data.el.Read(); - const int *d_face_num_quad = boundary_face_data.num_quad.Read(); - const int *d_listElems = listElems.Read(); + double* d_y = y.ReadWrite(); + const int* d_elem_dofs_list = elem_index_data.dofs_list.Read(); + const int* d_elem_dof_off = elem_index_data.dof_offset.Read(); + const int* d_elem_dof_num = elem_index_data.dof_number.Read(); + const double* d_face_shape = boundary_face_data.shape.Read(); + const double* d_weight = boundary_face_data.quad_weight.Read(); + const int* d_face_el = boundary_face_data.el.Read(); + const int* d_face_num_quad = boundary_face_data.num_quad.Read(); + const int* d_listElems = listElems.Read(); // const int *d_offsetBoundaryU = offsetsBoundaryU.Read(); - const double *d_flux = face_flux_.Read(); + const double* d_flux = face_flux_.Read(); const int totDofs = x.Size() / num_equation_; const int numBdrElem = listElems.Size(); @@ -928,24 +928,24 @@ void InletBC::integrateInlets_gpu(Vector &y, const Vector &x, const elementIndex #endif } -void InletBC::interpInlet_gpu(const mfem::Vector &x, const elementIndexingData &elem_index_data, - const boundaryFaceIntegrationData &boundary_face_data, Array &listElems, - Array &offsetsBoundaryU) { +void InletBC::interpInlet_gpu(const mfem::Vector& x, const elementIndexingData& elem_index_data, + const boundaryFaceIntegrationData& boundary_face_data, Array& listElems, + Array& offsetsBoundaryU) { #ifdef _GPU_ - const double *d_inputState = inputState.Read(); - const double *d_U = x.Read(); - const int *d_elem_dofs_list = elem_index_data.dofs_list.Read(); - const int *d_elem_dof_off = elem_index_data.dof_offset.Read(); - const int *d_elem_dof_num = elem_index_data.dof_number.Read(); - const double *d_face_shape = boundary_face_data.shape.Read(); - const double *d_normal = boundary_face_data.normal.Read(); - const double *d_xyz = boundary_face_data.xyz.Read(); - const int *d_face_el = boundary_face_data.el.Read(); - const int *d_face_num_quad = boundary_face_data.num_quad.Read(); - const int *d_listElems = listElems.Read(); + const double* d_inputState = inputState.Read(); + const double* d_U = x.Read(); + const int* d_elem_dofs_list = elem_index_data.dofs_list.Read(); + const int* d_elem_dof_off = elem_index_data.dof_offset.Read(); + const int* d_elem_dof_num = elem_index_data.dof_number.Read(); + const double* d_face_shape = boundary_face_data.shape.Read(); + const double* d_normal = boundary_face_data.normal.Read(); + const double* d_xyz = boundary_face_data.xyz.Read(); + const int* d_face_el = boundary_face_data.el.Read(); + const int* d_face_num_quad = boundary_face_data.num_quad.Read(); + const int* d_listElems = listElems.Read(); // const int *d_offsetBoundaryU = offsetsBoundaryU.Read(); - double *d_flux = face_flux_.Write(); + double* d_flux = face_flux_.Write(); const int totDofs = x.Size() / num_equation_; const int numBdrElem = listElems.Size(); @@ -966,8 +966,8 @@ void InletBC::interpInlet_gpu(const mfem::Vector &x, const elementIndexingData & const int maxIntPoints = maxIntPoints_; const int maxDofs = maxDofs_; - const RiemannSolverTPS *d_rsolver = rsolver; - GasMixture *d_mix = d_mixture_; + const RiemannSolverTPS* d_rsolver = rsolver; + GasMixture* d_mix = d_mixture_; // MFEM_FORALL(n, numBdrElem, { MFEM_FORALL_2D(n, numBdrElem, maxIntPoints, 1, 1, { diff --git a/src/inletBC.hpp b/src/inletBC.hpp index 0d41ddfb..dbb43791 100644 --- a/src/inletBC.hpp +++ b/src/inletBC.hpp @@ -45,9 +45,9 @@ using namespace mfem; class InletBC : public BoundaryCondition { private: - MPI_Groups *groupsMPI; + MPI_Groups* groupsMPI; - GasMixture *d_mixture_; // used only in the device + GasMixture* d_mixture_; // used only in the device const InletType inletType_; @@ -68,8 +68,8 @@ class InletBC : public BoundaryCondition { Array bdrElemsQ; // element dofs and face num. of integration points Array bdrDofs; // indexes of the D Vector bdrShape; // shape functions evaluated at the integration points - const int &maxIntPoints_; - const int &maxDofs_; + const int& maxIntPoints_; + const int& maxDofs_; // local vector for mean calculation Vector localMeanUp; @@ -82,50 +82,50 @@ class InletBC : public BoundaryCondition { Vector inverseNorm2cartesian; void initBdrElemsShape(); - void initBoundaryU(ParGridFunction *Up); + void initBoundaryU(ParGridFunction* Up); - void subsonicReflectingDensityVelocity(Vector &normal, Vector &stateIn, Vector &bdrFlux); + void subsonicReflectingDensityVelocity(Vector& normal, Vector& stateIn, Vector& bdrFlux); - void subsonicReflectingDensityVelocityFace(Vector &normal, Vector tangentW, Vector &stateIn, Vector transip, - double time, Vector &bdrFlux); + void subsonicReflectingDensityVelocityFace(Vector& normal, Vector tangentW, Vector& stateIn, Vector transip, + double time, Vector& bdrFlux); - void subsonicNonReflectingDensityVelocity(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector &bdrFlux); + void subsonicNonReflectingDensityVelocity(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector& bdrFlux); - virtual void updateMean(IntegrationRules *intRules, ParGridFunction *Up); + virtual void updateMean(IntegrationRules* intRules, ParGridFunction* Up); public: - InletBC(MPI_Groups *_groupsMPI, Equations _eqSystem, RiemannSolverTPS *rsolver_, GasMixture *_mixture, - GasMixture *d_mixture, ParFiniteElementSpace *_vfes, IntegrationRules *_intRules, double &_dt, const int _dim, + InletBC(MPI_Groups* _groupsMPI, Equations _eqSystem, RiemannSolverTPS* rsolver_, GasMixture* _mixture, + GasMixture* d_mixture, ParFiniteElementSpace* _vfes, IntegrationRules* _intRules, double& _dt, const int _dim, const int _num_equation, int _patchNumber, double _refLength, InletType _bcType, - const Array &_inputData, const int &_maxIntPoints, const int &maxDofs, bool axisym); + const Array& _inputData, const int& _maxIntPoints, const int& maxDofs, bool axisym); ~InletBC(); - void computeBdrFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - double time, double distance, Vector &bdrFlux); + void computeBdrFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + double time, double distance, Vector& bdrFlux); virtual void initBCs(); - virtual void integrationBC(Vector &y, // output - const Vector &x, const elementIndexingData &elem_index_data, ParGridFunction *Up, - ParGridFunction *gradUp, const boundaryFaceIntegrationData &boundary_face_data, - const int &maxIntPoints, const int &maxDofs); + virtual void integrationBC(Vector& y, // output + const Vector& x, const elementIndexingData& elem_index_data, ParGridFunction* Up, + ParGridFunction* gradUp, const boundaryFaceIntegrationData& boundary_face_data, + const int& maxIntPoints, const int& maxDofs); - static void updateMean_gpu(ParGridFunction *Up, Vector &localMeanUp, const int _num_equation, const int numBdrElems, - const int totalDofs, Vector &bdrUp, Array &bdrElemsQ, Array &bdrDofs, - Vector &bdrShape, const int &maxIntPoints, const int &maxDofs); + static void updateMean_gpu(ParGridFunction* Up, Vector& localMeanUp, const int _num_equation, const int numBdrElems, + const int totalDofs, Vector& bdrUp, Array& bdrElemsQ, Array& bdrDofs, + Vector& bdrShape, const int& maxIntPoints, const int& maxDofs); // functions for BC integration on GPU - void integrateInlets_gpu(Vector &y, // output - const Vector &x, const elementIndexingData &elem_index_data, - const boundaryFaceIntegrationData &boundary_face_data, Array &listElems, - Array &offsetsBoundaryU); - void interpInlet_gpu(const Vector &x, const elementIndexingData &elem_index_data, - const boundaryFaceIntegrationData &boundary_face_data, Array &listElems, - Array &offsetsBoundaryU); + void integrateInlets_gpu(Vector& y, // output + const Vector& x, const elementIndexingData& elem_index_data, + const boundaryFaceIntegrationData& boundary_face_data, Array& listElems, + Array& offsetsBoundaryU); + void interpInlet_gpu(const Vector& x, const elementIndexingData& elem_index_data, + const boundaryFaceIntegrationData& boundary_face_data, Array& listElems, + Array& offsetsBoundaryU); #ifdef _GPU_ - MFEM_HOST_DEVICE void pluginInputState(const double *inputState, double *u2, const int nvel, + MFEM_HOST_DEVICE void pluginInputState(const double* inputState, double* u2, const int nvel, const int numActiveSpecies) { u2[0] = inputState[0]; for (int v = 0; v < nvel; v++) u2[1 + v] = inputState[0] * inputState[1 + v]; @@ -135,10 +135,10 @@ class InletBC : public BoundaryCondition { return; } - static MFEM_HOST_DEVICE void computeSubDenseVel(const double *u1, double *u2, const double *nor, - const double *inputState, const double &gamma, const double &Rg, - const int &dim, const int &num_equation, const WorkingFluid &fluid, - const Equations &eqSystem, const int &thrd, const int &maxThread) { + static MFEM_HOST_DEVICE void computeSubDenseVel(const double* u1, double* u2, const double* nor, + const double* inputState, const double& gamma, const double& Rg, + const int& dim, const int& num_equation, const WorkingFluid& fluid, + const Equations& eqSystem, const int& thrd, const int& maxThread) { // assumes there at least as many threads as number of equations MFEM_SHARED double KE[3]; MFEM_SHARED double p; @@ -165,10 +165,10 @@ class InletBC : public BoundaryCondition { } } - static MFEM_HOST_DEVICE void computeSubDenseVel_gpu_serial(const double *u1, double *u2, const double *nor, - const double *inputState, const double &gamma, - const double &Rg, const int &dim, const int &num_equation, - const WorkingFluid &fluid) { + static MFEM_HOST_DEVICE void computeSubDenseVel_gpu_serial(const double* u1, double* u2, const double* nor, + const double* inputState, const double& gamma, + const double& Rg, const int& dim, const int& num_equation, + const WorkingFluid& fluid) { // assumes there at least as many threads as number of equations double KE[3]; double p; diff --git a/src/io.cpp b/src/io.cpp index f7f92509..4171c0e4 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -179,8 +179,8 @@ void M2ulPhyS::read_restart_files_hdf5(hid_t file, bool serialized_read) { // rhsOperator has not been constructed yet. As a workaround, // that code is duplicated here. // TODO(kevin): use mixture comptue primitive. - double *dataUp = Up->HostReadWrite(); - const double *x = U->HostRead(); + double* dataUp = Up->HostReadWrite(); + const double* x = U->HostRead(); for (int i = 0; i < vfes->GetNDofs(); i++) { Vector conserved(num_equation); Vector primitive(num_equation); @@ -270,7 +270,7 @@ void M2ulPhyS::restart_files_hdf5(string mode, string inputFileName) { return; } -void partitioning_file_hdf5(std::string mode, MPI_Groups *groupsMPI, int nelemGlobal, Array &partitioning, +void partitioning_file_hdf5(std::string mode, MPI_Groups* groupsMPI, int nelemGlobal, Array& partitioning, std::string pathName) { MPI_Comm TPSCommWorld = groupsMPI->getTPSCommWorld(); const bool rank0 = groupsMPI->isWorldRoot(); @@ -396,7 +396,7 @@ hsize_t get_variable_size_hdf5(hid_t file, std::string name) { } // convenience function to read solution data for parallel restarts -void read_variable_data_hdf5(hid_t file, string varName, size_t index, double *data) { +void read_variable_data_hdf5(hid_t file, string varName, size_t index, double* data) { hid_t data_soln; herr_t status; @@ -409,7 +409,7 @@ void read_variable_data_hdf5(hid_t file, string varName, size_t index, double *d IOOptions::IOOptions() : output_dir_("output"), restart_dir_("./"), restart_mode_("standard") {} -void IOOptions::read(TPS::Tps *tps, std::string prefix) { +void IOOptions::read(TPS::Tps* tps, std::string prefix) { std::string basename; if (!prefix.empty()) { basename = prefix + "/io"; @@ -458,7 +458,7 @@ void IOOptions::setRestartFlags() { } // convenience function to read and distribute solution data for serialized restarts -void IOFamily::readDistributeSerializedVariable(hid_t file, const IOVar &var, int numDof, double *data) { +void IOFamily::readDistributeSerializedVariable(hid_t file, const IOVar& var, int numDof, double* data) { std::string varName = group_ + "/" + var.varName_; if (rank0_) grvy_printf(ginfo, "--> Reading h5 path = %s\n", varName.c_str()); @@ -468,7 +468,7 @@ void IOFamily::readDistributeSerializedVariable(hid_t file, const IOVar &var, in const int myrank = pfunc_->ParFESpace()->GetMyRank(); const int nprocs = pfunc_->ParFESpace()->GetNRanks(); - Array &partitioning = *partitioning_; + Array& partitioning = *partitioning_; assert(partitioning.Size() == global_ne_); const unsigned int numStateVars = pfunc_->Size() / pfunc_->ParFESpace()->GetNDofs(); @@ -565,7 +565,7 @@ void IOFamily::readDistributeSerializedVariable(hid_t file, const IOVar &var, in } // convenience function to write HDF5 data -void write_variable_data_hdf5(hid_t group, string varName, hid_t dataspace, const double *data) { +void write_variable_data_hdf5(hid_t group, string varName, hid_t dataspace, const double* data) { hid_t data_soln; herr_t status; assert(group >= 0); @@ -582,7 +582,7 @@ void write_variable_data_hdf5(hid_t group, string varName, hid_t dataspace, cons // Routines for I/O data organizer helper class // --------------------------------------------- -IOFamily::IOFamily(std::string desc, std::string grp, mfem::ParGridFunction *pf) +IOFamily::IOFamily(std::string desc, std::string grp, mfem::ParGridFunction* pf) : description_(desc), group_(grp), pfunc_(pf) { rank0_ = (pfunc_->ParFESpace()->GetMyRank() == 0); @@ -600,13 +600,13 @@ IOFamily::IOFamily(std::string desc, std::string grp, mfem::ParGridFunction *pf) void IOFamily::serializeForWrite() { MPI_Comm comm = this->pfunc_->ParFESpace()->GetComm(); - const Array &partitioning = *(this->partitioning_); + const Array& partitioning = *(this->partitioning_); assert(partitioning.Size() == global_ne_); - const int *locToGlobElem = this->local_to_global_elem_; + const int* locToGlobElem = this->local_to_global_elem_; assert(locToGlobElem != NULL); - ParGridFunction *pfunc = this->pfunc_; + ParGridFunction* pfunc = this->pfunc_; if (rank0_) { grvy_printf(ginfo, "Generating serialized restart file (group %s...)\n", this->group_.c_str()); // copy my own data @@ -637,7 +637,7 @@ void IOFamily::serializeForWrite() { } // Second, receive the messages - Vector *soln = new Vector[nprocs]; + Vector* soln = new Vector[nprocs]; for (int irank = 1; irank < nprocs; irank++) { soln[irank].SetSize(nvar[irank]); MPI_Recv(soln[irank].HostReadWrite(), nvar[irank], MPI_DOUBLE, irank, 0, comm, MPI_STATUS_IGNORE); @@ -649,11 +649,11 @@ void IOFamily::serializeForWrite() { for (int gelem = 0; gelem < global_ne_; gelem++) { int from_rank = partitioning[gelem]; if (from_rank != 0) { - const double *d_soln = soln[from_rank].HostRead(); + const double* d_soln = soln[from_rank].HostRead(); this->serial_fes_->GetElementVDofs(gelem, gvdofs); lsoln.SetSize(gvdofs.Size()); - double *d_lsoln = lsoln.HostWrite(); + double* d_lsoln = lsoln.HostWrite(); for (int i = 0; i < lsoln.Size(); i++) { d_lsoln[i] = d_soln[nvar[from_rank] + i]; @@ -681,12 +681,12 @@ void IOFamily::serializeForWrite() { // Second, fill the send buffer Vector send_buffer(nvar); - double *h_send_buffer = send_buffer.HostWrite(); + double* h_send_buffer = send_buffer.HostWrite(); int n = 0; for (int elem = 0; elem < local_ne_; elem++) { this->pfunc_->ParFESpace()->GetElementVDofs(elem, lvdofs); pfunc->GetSubVector(lvdofs, lsoln); // work for gpu build? - const double *h_lsoln = lsoln.HostRead(); + const double* h_lsoln = lsoln.HostRead(); for (int i = 0; i < lsoln.Size(); i++) { h_send_buffer[n + i] = h_lsoln[i]; } @@ -711,7 +711,7 @@ void IOFamily::writePartitioned(hid_t file) { assert(group >= 0); // get pointer to raw data - const double *data = pfunc_->HostRead(); + const double* data = pfunc_->HostRead(); // save raw data for (auto var : vars_) { @@ -743,7 +743,7 @@ void IOFamily::writeSerial(hid_t file) { // get pointer to raw data assert(serial_sol_ != NULL); - const double *data = serial_sol_->HostRead(); + const double* data = serial_sol_->HostRead(); // save raw data for (auto var : vars_) { @@ -763,7 +763,7 @@ void IOFamily::readPartitioned(hid_t file) { assert((int)numInSoln == local_ndofs_); // get pointer to raw data - double *data = pfunc_->HostWrite(); + double* data = pfunc_->HostWrite(); // read from file into appropriate spot in data for (auto var : vars_) { @@ -784,7 +784,7 @@ void IOFamily::readSerial(hid_t file) { } // get pointer to raw data - double *data = pfunc_->HostWrite(); + double* data = pfunc_->HostWrite(); // read on rank 0 and distribute into data for (auto var : vars_) { @@ -803,7 +803,7 @@ void IOFamily::readChangeOrder(hid_t file, int read_order) { // Set up "auxilliary" ParGridFunction, to read data into before order change const int nvars = vars_.size(); aux_pfes_ = new ParFiniteElementSpace(pfunc_->ParFESpace()->GetParMesh(), aux_fec_, nvars, Ordering::byNODES); - double *aux_U_data = new double[nvars * aux_pfes_->GetNDofs()]; + double* aux_U_data = new double[nvars * aux_pfes_->GetNDofs()]; aux_pfunc_ = new ParGridFunction(aux_pfes_, aux_U_data); const int aux_dof = aux_pfes_->GetNDofs(); @@ -813,7 +813,7 @@ void IOFamily::readChangeOrder(hid_t file, int read_order) { assert((int)numInSoln == aux_dof); // get pointer to raw data - double *data = aux_pfunc_->HostWrite(); + double* data = aux_pfunc_->HostWrite(); for (auto var : vars_) { if (var.inRestartFile_) { @@ -848,8 +848,8 @@ void IOFamily::readChangeOrder(hid_t file, int read_order) { } // register a new IO family which maps to a ParGridFunction -void IODataOrganizer::registerIOFamily(std::string description, std::string group, ParGridFunction *pfunc, - bool auxRestart, bool inRestartFile, FiniteElementCollection *fec) { +void IODataOrganizer::registerIOFamily(std::string description, std::string group, ParGridFunction* pfunc, + bool auxRestart, bool inRestartFile, FiniteElementCollection* fec) { IOFamily family(description, group, pfunc); family.allowsAuxRestart_ = auxRestart; family.inRestartFile_ = inRestartFile; @@ -877,12 +877,12 @@ int IODataOrganizer::getIOFamilyIndex(std::string group) const { return (-1); } -void IODataOrganizer::initializeSerial(bool root, bool serial, Mesh *serial_mesh, int *locToGlob, Array *part) { +void IODataOrganizer::initializeSerial(bool root, bool serial, Mesh* serial_mesh, int* locToGlob, Array* part) { supports_serial_ = serial; // loop through families for (size_t n = 0; n < families_.size(); n++) { - IOFamily &fam = families_[n]; + IOFamily& fam = families_[n]; fam.serial_fes_ = NULL; fam.serial_sol_ = NULL; @@ -891,7 +891,7 @@ void IODataOrganizer::initializeSerial(bool root, bool serial, Mesh *serial_mesh fam.local_to_global_elem_ = locToGlob; fam.partitioning_ = part; if (root) { - const FiniteElementCollection *fec = fam.pfunc_->ParFESpace()->FEColl(); + const FiniteElementCollection* fec = fam.pfunc_->ParFESpace()->FEColl(); int numVars = fam.pfunc_->Size() / fam.pfunc_->ParFESpace()->GetNDofs(); fam.serial_fes_ = new FiniteElementSpace(serial_mesh, fec, numVars, Ordering::byNODES); diff --git a/src/io.hpp b/src/io.hpp index 4685132b..f2b7f8ad 100644 --- a/src/io.hpp +++ b/src/io.hpp @@ -72,7 +72,7 @@ class IOOptions { bool restart_serial_read_ = false; bool restart_serial_write_ = false; - void read(TPS::Tps *tps, std::string prefix = std::string("")); + void read(TPS::Tps* tps, std::string prefix = std::string("")); void setRestartFlags(); }; @@ -135,7 +135,7 @@ class IOFamily { std::string group_; /** mfem::ParGridFunction owning the data to be written or read into */ - mfem::ParGridFunction *pfunc_ = nullptr; + mfem::ParGridFunction* pfunc_ = nullptr; /** Variables that make up the family */ std::vector vars_; @@ -147,28 +147,28 @@ class IOFamily { bool inRestartFile_; /** mfem::FiniteElementSpace for serial mesh (used if serial read and/or write requested) */ - mfem::FiniteElementSpace *serial_fes_ = nullptr; + mfem::FiniteElementSpace* serial_fes_ = nullptr; /** mfem::GridFunction on serial mesh (used if serial read and/or write requested) */ - mfem::GridFunction *serial_sol_ = nullptr; + mfem::GridFunction* serial_sol_ = nullptr; /** Map from local to global element numbering (used for serial read/write) */ - int *local_to_global_elem_ = nullptr; + int* local_to_global_elem_ = nullptr; /** Partition array; partitioning[i] = mpi rank that owns the ith element (global numbering) */ - mfem::Array *partitioning_ = nullptr; + mfem::Array* partitioning_ = nullptr; /** mfem::FiniteElementCollection used by pfunc_ (used for variable order read) */ - mfem::FiniteElementCollection *fec_ = nullptr; + mfem::FiniteElementCollection* fec_ = nullptr; /** mfem::FiniteElementCollection with read order (used for variable order read) */ - mfem::FiniteElementCollection *aux_fec_ = nullptr; + mfem::FiniteElementCollection* aux_fec_ = nullptr; /** mfem::FiniteElementCollection with read order elements (used for variable order read) */ - mfem::ParFiniteElementSpace *aux_pfes_ = nullptr; + mfem::ParFiniteElementSpace* aux_pfes_ = nullptr; /** mfem::ParGridFunction with read order elements (used for variable order read) */ - mfem::ParGridFunction *aux_pfunc_ = nullptr; + mfem::ParGridFunction* aux_pfunc_ = nullptr; /** * @brief Prepare for serial write by collecting data onto rank 0 @@ -185,7 +185,7 @@ class IOFamily { * @param file Open HDF5 file handle (e.g., as returned by H5Fcreate or H5Fopen) * @param var IOVar for the variable being read */ - void readDistributeSerializedVariable(hid_t file, const IOVar &var, int numDof, double *data); + void readDistributeSerializedVariable(hid_t file, const IOVar& var, int numDof, double* data); public: /** @@ -195,7 +195,7 @@ class IOFamily { * @param grp Group name * @param pf Pointer to mfem::ParGridFunction that owns the data */ - IOFamily(std::string desc, std::string grp, mfem::ParGridFunction *pf); + IOFamily(std::string desc, std::string grp, mfem::ParGridFunction* pf); /** @brief "Partitioned" write (each mpi rank writes its local part of the ParGridFunction to a separate file) */ void writePartitioned(hid_t file); @@ -258,8 +258,8 @@ class IODataOrganizer { * @param inRestartFile If false, skip family on read (optional, defaults to true) * @param fec FiniteElementCollection for grid function (optional, only used for different order read) */ - void registerIOFamily(std::string description, std::string group, mfem::ParGridFunction *pfunc, - bool auxRestart = true, bool inRestartFile = true, mfem::FiniteElementCollection *fec = NULL); + void registerIOFamily(std::string description, std::string group, mfem::ParGridFunction* pfunc, + bool auxRestart = true, bool inRestartFile = true, mfem::FiniteElementCollection* fec = NULL); /** Destructor */ ~IODataOrganizer(); @@ -282,7 +282,7 @@ class IODataOrganizer { * @param locToGlob Map from local element index to global element index * @param part Map from global element index to mpi rank owning that element */ - void initializeSerial(bool root, bool serial, mfem::Mesh *serial_mesh, int *locToGlob, mfem::Array *part); + void initializeSerial(bool root, bool serial, mfem::Mesh* serial_mesh, int* locToGlob, mfem::Array* part); /** * @brief Write data from all families @@ -339,7 +339,7 @@ hsize_t get_variable_size_hdf5(hid_t file, std::string name); * @param index Starting location within data buffer * @param data Data buffer */ -void read_variable_data_hdf5(hid_t file, std::string varName, size_t index, double *data); +void read_variable_data_hdf5(hid_t file, std::string varName, size_t index, double* data); /** * @brief Write data to an hdf5 file @@ -349,7 +349,7 @@ void read_variable_data_hdf5(hid_t file, std::string varName, size_t index, doub * @param dataspace HDF5 dataspace (e.g., as returned by H5Screate_simple) * @param data Buffer with data to write */ -void write_variable_data_hdf5(hid_t group, std::string varName, hid_t dataspace, const double *data); +void write_variable_data_hdf5(hid_t group, std::string varName, hid_t dataspace, const double* data); /** * @brief Read/write partitioning information @@ -362,6 +362,6 @@ void write_variable_data_hdf5(hid_t group, std::string varName, hid_t dataspace, * @todo Refactor this function to make it more generic and fit better * into the IODataOrganizer paradigm. */ -void partitioning_file_hdf5(std::string mode, MPI_Groups *groupsMPI, int nelemGlobal, mfem::Array &partitioning, +void partitioning_file_hdf5(std::string mode, MPI_Groups* groupsMPI, int nelemGlobal, mfem::Array& partitioning, std::string fileName = "./"); #endif // IO_HPP_ diff --git a/src/loMach.cpp b/src/loMach.cpp index 7bc685f4..a782a2b9 100644 --- a/src/loMach.cpp +++ b/src/loMach.cpp @@ -61,7 +61,7 @@ using namespace mfem; using namespace mfem::common; -LoMachSolver::LoMachSolver(TPS::Tps *tps) +LoMachSolver::LoMachSolver(TPS::Tps* tps) : tpsP_(tps), groupsMPI(new MPI_Groups(tps->getTPSCommWorld())), nprocs_(groupsMPI->getTPSWorldSize()), @@ -568,7 +568,7 @@ void LoMachSolver::updateTimestep() { auto dataU = flow_->getCurrentVelocity()->HostRead(); // comes in divided by order - const double *dataD = (meshData_->getGridScale())->HostRead(); + const double* dataD = (meshData_->getGridScale())->HostRead(); int Sdof = meshData_->getDofSize(); for (int n = 0; n < Sdof; n++) { @@ -585,7 +585,7 @@ void LoMachSolver::updateTimestep() { double dtInst_conv = CFL_ / std::max(max_speed, 1.0e-12); double dtInst = dtInst_conv; - double &dt = temporal_coeff_.dt; + double& dt = temporal_coeff_.dt; if (dtInst > dt) { dt = dt * (1.0 + dtFactor); dt = std::min(dt, dtInst); @@ -613,7 +613,7 @@ double LoMachSolver::computeCFL() { // comes in divided by order auto dataU = flow_->getCurrentVelocity()->HostRead(); - const double *dataD = (meshData_->getGridScale())->HostRead(); + const double* dataD = (meshData_->getGridScale())->HostRead(); int Sdof = meshData_->getDofSize(); MPI_Barrier(groupsMPI->getTPSCommWorld()); @@ -638,7 +638,7 @@ void LoMachSolver::setTimestep() { double convT_lcl = 1.0e-12; double min_convT = 1.0; double Umag; - const double *dataD = (meshData_->getGridScale())->HostRead(); + const double* dataD = (meshData_->getGridScale())->HostRead(); int Sdof = meshData_->getDofSize(); // dt_fixed is initialized to -1, so if it is positive, diff --git a/src/loMach.hpp b/src/loMach.hpp index 7034df7c..54263738 100644 --- a/src/loMach.hpp +++ b/src/loMach.hpp @@ -109,13 +109,13 @@ struct temporalSchemeCoefficients { class LoMachSolver : public TPS::PlasmaSolver { protected: // pointer to parent Tps class - TPS::Tps *tpsP_ = nullptr; + TPS::Tps* tpsP_ = nullptr; // Run options LoMachOptions loMach_opts_; // MPI helpers - MPI_Groups *groupsMPI = nullptr; + MPI_Groups* groupsMPI = nullptr; int nprocs_; // total number of MPI procs int rank_; // local MPI rank bool rank0_; // flag to indicate rank 0 @@ -126,18 +126,18 @@ class LoMachSolver : public TPS::PlasmaSolver { bool disable_flow_; // Model classes - MeshBase *meshData_ = nullptr; - TurbModelBase *turbModel_ = nullptr; - ThermoChemModelBase *thermo_ = nullptr; - FlowBase *flow_ = nullptr; - SpongeBase *sponge_ = nullptr; - ExternalDataBase *extData_ = nullptr; - AveragingOptions *avg_opts_ = nullptr; - Averaging *average_ = nullptr; + MeshBase* meshData_ = nullptr; + TurbModelBase* turbModel_ = nullptr; + ThermoChemModelBase* thermo_ = nullptr; + FlowBase* flow_ = nullptr; + SpongeBase* sponge_ = nullptr; + ExternalDataBase* extData_ = nullptr; + AveragingOptions* avg_opts_ = nullptr; + Averaging* average_ = nullptr; // Mesh and geometry related - ParMesh *pmesh_ = nullptr; - Mesh *serial_mesh_ = nullptr; + ParMesh* pmesh_ = nullptr; + Mesh* serial_mesh_ = nullptr; int dim_; int nvel_; @@ -160,10 +160,10 @@ class LoMachSolver : public TPS::PlasmaSolver { double xmax_, ymax_, zmax_; /// Scalar \f$H^1\f$ finite element collection. - FiniteElementCollection *sfec_ = nullptr; + FiniteElementCollection* sfec_ = nullptr; /// Scalar \f$H^1\f$ finite element space. - ParFiniteElementSpace *sfes_ = nullptr; + ParFiniteElementSpace* sfes_ = nullptr; /* Vector gridScaleSml; @@ -197,7 +197,7 @@ class LoMachSolver : public TPS::PlasmaSolver { double tlast_; // I/O helpers - ParaViewDataCollection *pvdc_ = nullptr; // visualization + ParaViewDataCollection* pvdc_ = nullptr; // visualization IODataOrganizer ioData; // restart /// Update the EXTk/BDF time integration coefficient. @@ -205,7 +205,7 @@ class LoMachSolver : public TPS::PlasmaSolver { public: /// Ctor - LoMachSolver(TPS::Tps *tps); + LoMachSolver(TPS::Tps* tps); /// Dtor virtual ~LoMachSolver(); @@ -237,8 +237,8 @@ class LoMachSolver : public TPS::PlasmaSolver { // Functions necessary for coupled EM+plasma simulations // These are overriden from TPS::Solver or TPS::PlasmaSolver - mfem::ParMesh *getMesh() const override { return pmesh_; } - const mfem::FiniteElementCollection *getFEC() const override { + mfem::ParMesh* getMesh() const override { return pmesh_; } + const mfem::FiniteElementCollection* getFEC() const override { if (thermo_->getJouleHeatingGF() != nullptr) { return thermo_->getJouleHeatingGF()->ParFESpace()->FEColl(); } else { @@ -246,7 +246,7 @@ class LoMachSolver : public TPS::PlasmaSolver { } } - mfem::ParFiniteElementSpace *getFESpace() const override { + mfem::ParFiniteElementSpace* getFESpace() const override { if (thermo_->getJouleHeatingGF() != nullptr) { return thermo_->getJouleHeatingGF()->ParFESpace(); } else { @@ -254,11 +254,11 @@ class LoMachSolver : public TPS::PlasmaSolver { } } - mfem::ParGridFunction *getPlasmaConductivityGF() override { return thermo_->getPlasmaConductivityGF(); } + mfem::ParGridFunction* getPlasmaConductivityGF() override { return thermo_->getPlasmaConductivityGF(); } void evaluatePlasmaConductivityGF() override { thermo_->evaluatePlasmaConductivityGF(); } - mfem::ParGridFunction *getJouleHeatingGF() override { return thermo_->getJouleHeatingGF(); } + mfem::ParGridFunction* getJouleHeatingGF() override { return thermo_->getJouleHeatingGF(); } }; #endif // LOMACH_HPP_ diff --git a/src/loMach_options.cpp b/src/loMach_options.cpp index 08a04379..65721509 100644 --- a/src/loMach_options.cpp +++ b/src/loMach_options.cpp @@ -47,7 +47,7 @@ TurbulenceModelOptions::TurbulenceModelOptions() turb_model_type_ = turb_model_map_[turb_model_string_]; } -void TurbulenceModelOptions::read(TPS::Tps *tps, std::string prefix) { +void TurbulenceModelOptions::read(TPS::Tps* tps, std::string prefix) { // At the moment, SGS model options are under either "flow" or // "loMach", so we must have a prefix assert(!prefix.empty()); @@ -88,7 +88,7 @@ LoMachTemporalOptions::LoMachTemporalOptions() integrator_map_["deltaP"] = DELTA_P; } -void LoMachTemporalOptions::read(TPS::Tps *tps, std::string prefix) { +void LoMachTemporalOptions::read(TPS::Tps* tps, std::string prefix) { std::string basename; if (!prefix.empty()) { basename = prefix + "/time"; diff --git a/src/loMach_options.hpp b/src/loMach_options.hpp index 630dec18..5f8eb2c7 100644 --- a/src/loMach_options.hpp +++ b/src/loMach_options.hpp @@ -46,7 +46,7 @@ class Tps; class TurbulenceModelOptions { public: TurbulenceModelOptions(); - void read(TPS::Tps *tps, std::string prefix = std::string("")); + void read(TPS::Tps* tps, std::string prefix = std::string("")); enum TurbulenceModelType { NONE, SMAGORINSKY, SIGMA, WALE, ALGEBRAIC_RANS, STATIC_RANS, ZETA_F }; @@ -61,7 +61,7 @@ class TurbulenceModelOptions { class LoMachTemporalOptions { public: LoMachTemporalOptions(); - void read(TPS::Tps *tps, std::string prefix = std::string("")); + void read(TPS::Tps* tps, std::string prefix = std::string("")); enum IntegratorType { CURL_CURL, STAGGERED_TIME, DELTA_P }; @@ -151,7 +151,7 @@ class LoMachOptions { nSpec = 0; } - void print(std::ostream &out) { + void print(std::ostream& out) { out << std::endl; out << "LoMach options:" << std::endl; out << " mesh_file = " << mesh_file << std::endl; diff --git a/src/lte_mixture.cpp b/src/lte_mixture.cpp index 5db56a04..c15b3fc9 100644 --- a/src/lte_mixture.cpp +++ b/src/lte_mixture.cpp @@ -36,7 +36,7 @@ #include "lte_mixture.hpp" #ifndef _GPU_ -LteMixture::LteMixture(RunConfiguration &_runfile, int _dim, int nvel) +LteMixture::LteMixture(RunConfiguration& _runfile, int _dim, int nvel) : GasMixture(_runfile.lteMixtureInput.f, _dim, nvel, _runfile.const_plasma_conductivity_) { numSpecies = 1; ambipolar = false; @@ -116,11 +116,11 @@ MFEM_HOST_DEVICE LteMixture::~LteMixture() { } /// Compute pressure from conserved state -double LteMixture::ComputePressure(const Vector &state, double *electronPressure) { +double LteMixture::ComputePressure(const Vector& state, double* electronPressure) { return ComputePressure(state.GetData(), electronPressure); } -MFEM_HOST_DEVICE double LteMixture::ComputePressure(const double *state, double *electronPressure) { +MFEM_HOST_DEVICE double LteMixture::ComputePressure(const double* state, double* electronPressure) { const double rho = state[0]; // const double T = ComputeTemperature(state); double T; @@ -135,11 +135,11 @@ MFEM_HOST_DEVICE double LteMixture::ComputePressure(const double *state, double } /// Compute pressure from primitive state -double LteMixture::ComputePressureFromPrimitives(const Vector &Up) { +double LteMixture::ComputePressureFromPrimitives(const Vector& Up) { return ComputePressureFromPrimitives(Up.GetData()); } -MFEM_HOST_DEVICE double LteMixture::ComputePressureFromPrimitives(const double *Up) { +MFEM_HOST_DEVICE double LteMixture::ComputePressureFromPrimitives(const double* Up) { const double rho = Up[0]; const double T = Up[1 + nvel_]; #ifdef _GPU_ @@ -158,7 +158,7 @@ MFEM_HOST_DEVICE double LteMixture::ComputePressureFromPrimitives(const double * * internal energy given by the thermodynamic equilibrium look-up * table. */ -MFEM_HOST_DEVICE bool LteMixture::ComputeTemperatureInternal(const double *state, double &T) { +MFEM_HOST_DEVICE bool LteMixture::ComputeTemperatureInternal(const double* state, double& T) { const double rho = state[0]; double den_vel2 = 0; @@ -222,9 +222,9 @@ MFEM_HOST_DEVICE bool LteMixture::ComputeTemperatureInternal(const double *state return true; } -double LteMixture::ComputeTemperature(const Vector &state) { return ComputeTemperature(state.GetData()); } +double LteMixture::ComputeTemperature(const Vector& state) { return ComputeTemperature(state.GetData()); } -MFEM_HOST_DEVICE double LteMixture::ComputeTemperature(const double *state) { +MFEM_HOST_DEVICE double LteMixture::ComputeTemperature(const double* state) { double T; const bool success = ComputeTemperatureInternal(state, T); assert(success); @@ -304,19 +304,19 @@ MFEM_HOST_DEVICE double LteMixture::ComputeTemperatureFromDensityPressure(const } // TODO(trevilo): move this into the base class -void LteMixture::computeSpeciesEnthalpies(const Vector &state, Vector &speciesEnthalpies) { +void LteMixture::computeSpeciesEnthalpies(const Vector& state, Vector& speciesEnthalpies) { speciesEnthalpies.SetSize(numSpecies); speciesEnthalpies = 0.0; return; } /// Compute primitive variables (rho, u, T) from conserved (rho, rho*u, rho*E) -void LteMixture::GetPrimitivesFromConservatives(const Vector &conserv, Vector &primit) { +void LteMixture::GetPrimitivesFromConservatives(const Vector& conserv, Vector& primit) { primit.SetSize(conserv.Size()); GetPrimitivesFromConservatives(conserv.GetData(), primit.GetData()); } -MFEM_HOST_DEVICE void LteMixture::GetPrimitivesFromConservatives(const double *conserv, double *primit) { +MFEM_HOST_DEVICE void LteMixture::GetPrimitivesFromConservatives(const double* conserv, double* primit) { const double T = ComputeTemperature(conserv); for (int i = 0; i < num_equation; i++) { @@ -329,12 +329,12 @@ MFEM_HOST_DEVICE void LteMixture::GetPrimitivesFromConservatives(const double *c } /// Compute conserved variables (rho, rho*u, rho*E) from primitive (rho, u, T) -void LteMixture::GetConservativesFromPrimitives(const Vector &primit, Vector &conserv) { +void LteMixture::GetConservativesFromPrimitives(const Vector& primit, Vector& conserv) { conserv.SetSize(primit.Size()); GetConservativesFromPrimitives(primit.GetData(), conserv.GetData()); } -MFEM_HOST_DEVICE void LteMixture::GetConservativesFromPrimitives(const double *primit, double *conserv) { +MFEM_HOST_DEVICE void LteMixture::GetConservativesFromPrimitives(const double* primit, double* conserv) { for (int i = 0; i < num_equation; i++) { conserv[i] = primit[i]; } @@ -358,12 +358,12 @@ MFEM_HOST_DEVICE void LteMixture::GetConservativesFromPrimitives(const double *p } /// Compute the speed of sound (from look-up table) -double LteMixture::ComputeSpeedOfSound(const Vector &Uin, bool primitive) { +double LteMixture::ComputeSpeedOfSound(const Vector& Uin, bool primitive) { return ComputeSpeedOfSound(Uin.GetData(), primitive); } /// Compute the speed of sound (from look-up table) -MFEM_HOST_DEVICE double LteMixture::ComputeSpeedOfSound(const double *Uin, bool primitive) { +MFEM_HOST_DEVICE double LteMixture::ComputeSpeedOfSound(const double* Uin, bool primitive) { const double rho = Uin[0]; double T; if (primitive) { @@ -381,10 +381,10 @@ MFEM_HOST_DEVICE double LteMixture::ComputeSpeedOfSound(const double *Uin, bool } /// Compute the maximum characteristic speed (u+a) -double LteMixture::ComputeMaxCharSpeed(const Vector &state) { return ComputeMaxCharSpeed(state.GetData()); } +double LteMixture::ComputeMaxCharSpeed(const Vector& state) { return ComputeMaxCharSpeed(state.GetData()); } /// Compute the maximum characteristic speed (u+a) -MFEM_HOST_DEVICE double LteMixture::ComputeMaxCharSpeed(const double *state) { +MFEM_HOST_DEVICE double LteMixture::ComputeMaxCharSpeed(const double* state) { const double den = state[0]; double den_vel2 = 0; @@ -400,13 +400,13 @@ MFEM_HOST_DEVICE double LteMixture::ComputeMaxCharSpeed(const double *state) { } // only used in non-reflecting BCs... don't implement for now -double LteMixture::ComputePressureDerivative(const Vector &dUp_dx, const Vector &Uin, bool primitive) { +double LteMixture::ComputePressureDerivative(const Vector& dUp_dx, const Vector& Uin, bool primitive) { assert(false); return 0.0; } /// Check if the density, temperature, and pressure are positive -bool LteMixture::StateIsPhysical(const Vector &state) { +bool LteMixture::StateIsPhysical(const Vector& state) { const double rho = state[0]; const double T = ComputeTemperature(state); #ifdef _GPU_ @@ -422,13 +422,13 @@ bool LteMixture::StateIsPhysical(const Vector &state) { } // BC related functions -void LteMixture::computeStagnantStateWithTemp(const Vector &stateIn, const double Temp, Vector &stateOut) { +void LteMixture::computeStagnantStateWithTemp(const Vector& stateIn, const double Temp, Vector& stateOut) { stateOut.SetSize(num_equation); computeStagnantStateWithTemp(stateIn.GetData(), Temp, stateOut.GetData()); } -MFEM_HOST_DEVICE void LteMixture::computeStagnantStateWithTemp(const double *stateIn, const double Temp, - double *stateOut) { +MFEM_HOST_DEVICE void LteMixture::computeStagnantStateWithTemp(const double* stateIn, const double Temp, + double* stateOut) { for (int i = 0; i < num_equation; i++) { stateOut[i] = stateIn[i]; } @@ -445,12 +445,12 @@ MFEM_HOST_DEVICE void LteMixture::computeStagnantStateWithTemp(const double *sta stateOut[1 + nvel_] = rho * energy; } -void LteMixture::modifyEnergyForPressure(const Vector &stateIn, Vector &stateOut, const double &p, +void LteMixture::modifyEnergyForPressure(const Vector& stateIn, Vector& stateOut, const double& p, bool modifyElectronEnergy) { modifyEnergyForPressure(stateIn.GetData(), stateOut.GetData(), p, modifyElectronEnergy); } -MFEM_HOST_DEVICE void LteMixture::modifyEnergyForPressure(const double *stateIn, double *stateOut, const double &p, +MFEM_HOST_DEVICE void LteMixture::modifyEnergyForPressure(const double* stateIn, double* stateOut, const double& p, bool modifyElectronEnergy) { for (int eq = 0; eq < num_equation; eq++) stateOut[eq] = stateIn[eq]; diff --git a/src/lte_mixture.hpp b/src/lte_mixture.hpp index 74d5e9f2..88fe332f 100644 --- a/src/lte_mixture.hpp +++ b/src/lte_mixture.hpp @@ -64,31 +64,31 @@ class LteMixture : public GasMixture { LinearTable T_table_; #else // On the cpu path, simultaneously support LinearTable and GslTableInterpolator2D - TableInterface *energy_table_; - TableInterface *R_table_; - TableInterface *c_table_; - TableInterface *T_table_; + TableInterface* energy_table_; + TableInterface* R_table_; + TableInterface* c_table_; + TableInterface* T_table_; #endif - MFEM_HOST_DEVICE bool ComputeTemperatureInternal(const double *state, double &T); + MFEM_HOST_DEVICE bool ComputeTemperatureInternal(const double* state, double& T); public: MFEM_HOST_DEVICE LteMixture(WorkingFluid f, int _dim, int nvel, double pc, TableInput energy_table_input, TableInput R_table_input, TableInput c_table_input, TableInput T_table_input); #ifndef _GPU_ - LteMixture(RunConfiguration &_runfile, int _dim, int nvel); + LteMixture(RunConfiguration& _runfile, int _dim, int nvel); #endif MFEM_HOST_DEVICE virtual ~LteMixture(); - MFEM_HOST_DEVICE double evaluateInternalEnergy(const double &T, const double &rho) { + MFEM_HOST_DEVICE double evaluateInternalEnergy(const double& T, const double& rho) { #ifdef _GPU_ return energy_table_.eval(T, rho); #else return energy_table_->eval(T, rho); #endif } - MFEM_HOST_DEVICE double evaluateGasConstant(const double &T, const double &rho) { + MFEM_HOST_DEVICE double evaluateGasConstant(const double& T, const double& rho) { #ifdef _GPU_ return R_table_.eval(T, rho); #else @@ -96,51 +96,51 @@ class LteMixture : public GasMixture { #endif } - virtual double ComputePressure(const Vector &state, double *electronPressure = NULL); - MFEM_HOST_DEVICE virtual double ComputePressure(const double *state, double *electronPressure = NULL); + virtual double ComputePressure(const Vector& state, double* electronPressure = NULL); + MFEM_HOST_DEVICE virtual double ComputePressure(const double* state, double* electronPressure = NULL); - virtual double ComputePressureFromPrimitives(const Vector &Up); - MFEM_HOST_DEVICE virtual double ComputePressureFromPrimitives(const double *Up); + virtual double ComputePressureFromPrimitives(const Vector& Up); + MFEM_HOST_DEVICE virtual double ComputePressureFromPrimitives(const double* Up); - virtual double ComputeTemperature(const Vector &state); - MFEM_HOST_DEVICE virtual double ComputeTemperature(const double *state); + virtual double ComputeTemperature(const Vector& state); + MFEM_HOST_DEVICE virtual double ComputeTemperature(const double* state); MFEM_HOST_DEVICE double ComputeTemperatureFromDensityPressure(const double rho, const double p); - virtual void computeSpeciesEnthalpies(const Vector &state, Vector &speciesEnthalpies); - MFEM_HOST_DEVICE virtual void computeSpeciesEnthalpies(const double *state, double *speciesEnthalpies) { + virtual void computeSpeciesEnthalpies(const Vector& state, Vector& speciesEnthalpies); + MFEM_HOST_DEVICE virtual void computeSpeciesEnthalpies(const double* state, double* speciesEnthalpies) { for (int sp = 0; sp < numSpecies; sp++) speciesEnthalpies[sp] = 0.0; return; } - virtual void GetPrimitivesFromConservatives(const Vector &conserv, Vector &primit); - MFEM_HOST_DEVICE virtual void GetPrimitivesFromConservatives(const double *conserv, double *primit); + virtual void GetPrimitivesFromConservatives(const Vector& conserv, Vector& primit); + MFEM_HOST_DEVICE virtual void GetPrimitivesFromConservatives(const double* conserv, double* primit); - virtual void GetConservativesFromPrimitives(const Vector &primit, Vector &conserv); - MFEM_HOST_DEVICE virtual void GetConservativesFromPrimitives(const double *primit, double *conserv); + virtual void GetConservativesFromPrimitives(const Vector& primit, Vector& conserv); + MFEM_HOST_DEVICE virtual void GetConservativesFromPrimitives(const double* primit, double* conserv); - virtual double ComputeSpeedOfSound(const Vector &Uin, bool primitive = true); - MFEM_HOST_DEVICE virtual double ComputeSpeedOfSound(const double *Uin, bool primitive = true); + virtual double ComputeSpeedOfSound(const Vector& Uin, bool primitive = true); + MFEM_HOST_DEVICE virtual double ComputeSpeedOfSound(const double* Uin, bool primitive = true); - virtual double ComputeMaxCharSpeed(const Vector &state); - MFEM_HOST_DEVICE virtual double ComputeMaxCharSpeed(const double *state); + virtual double ComputeMaxCharSpeed(const Vector& state); + MFEM_HOST_DEVICE virtual double ComputeMaxCharSpeed(const double* state); /// only used in non-reflecting BCs... don't implement for now - virtual double ComputePressureDerivative(const Vector &dUp_dx, const Vector &Uin, bool primitive = true); + virtual double ComputePressureDerivative(const Vector& dUp_dx, const Vector& Uin, bool primitive = true); // Physicality check (at end) - virtual bool StateIsPhysical(const Vector &state); + virtual bool StateIsPhysical(const Vector& state); - virtual void ComputeMassFractionGradient(const double rho, const Vector &numberDensities, const DenseMatrix &gradUp, - DenseMatrix &massFractionGrad) { + virtual void ComputeMassFractionGradient(const double rho, const Vector& numberDensities, const DenseMatrix& gradUp, + DenseMatrix& massFractionGrad) { mfem_error("computeMassFractionGradient not implemented"); } - virtual void ComputeMoleFractionGradient(const Vector &numberDensities, const DenseMatrix &gradUp, - DenseMatrix &moleFractionGrad) { + virtual void ComputeMoleFractionGradient(const Vector& numberDensities, const DenseMatrix& gradUp, + DenseMatrix& moleFractionGrad) { mfem_error("computeMoleFractionGradient not implemented"); } - MFEM_HOST_DEVICE virtual void ComputeMoleFractionGradient(const double *numberDensities, const double *gradUp, - double *moleFractionGrad) { + MFEM_HOST_DEVICE virtual void ComputeMoleFractionGradient(const double* numberDensities, const double* gradUp, + double* moleFractionGrad) { printf("computeMoleFractionGradient not implemented"); assert(false); } @@ -149,21 +149,21 @@ class LteMixture : public GasMixture { MFEM_HOST_DEVICE virtual double GetGasConstant() { return 0; } // BC related functions - virtual void computeStagnantStateWithTemp(const Vector &stateIn, const double Temp, Vector &stateOut); - MFEM_HOST_DEVICE virtual void computeStagnantStateWithTemp(const double *stateIn, const double Temp, - double *stateOut); + virtual void computeStagnantStateWithTemp(const Vector& stateIn, const double Temp, Vector& stateOut); + MFEM_HOST_DEVICE virtual void computeStagnantStateWithTemp(const double* stateIn, const double Temp, + double* stateOut); - virtual void modifyEnergyForPressure(const Vector &stateIn, Vector &stateOut, const double &p, + virtual void modifyEnergyForPressure(const Vector& stateIn, Vector& stateOut, const double& p, bool modifyElectronEnergy = false); - MFEM_HOST_DEVICE virtual void modifyEnergyForPressure(const double *stateIn, double *stateOut, const double &p, + MFEM_HOST_DEVICE virtual void modifyEnergyForPressure(const double* stateIn, double* stateOut, const double& p, bool modifyElectronEnergy = false); - virtual void computeSheathBdrFlux(const Vector &state, BoundaryViscousFluxData &bcFlux) { + virtual void computeSheathBdrFlux(const Vector& state, BoundaryViscousFluxData& bcFlux) { mfem_error("computeSheathBdrFlux not implemented"); } - MFEM_HOST_DEVICE virtual void computeSheathBdrFlux(const double *state, BoundaryViscousFluxData &bcFlux) { + MFEM_HOST_DEVICE virtual void computeSheathBdrFlux(const double* state, BoundaryViscousFluxData& bcFlux) { printf("ERROR: computeSheathBdrFlux is not supposed to be executed for LteMixture!"); return; } @@ -176,12 +176,12 @@ class LteMixture : public GasMixture { mfem_error("computeElectronPressure not implemented"); return 0; } - virtual void computeElectronPressureGrad(const double n_e, const double T_e, const DenseMatrix &gradUp, - Vector &gradPe) { + virtual void computeElectronPressureGrad(const double n_e, const double T_e, const DenseMatrix& gradUp, + Vector& gradPe) { mfem_error("computeElectronPressureGrad not implemented"); } - MFEM_HOST_DEVICE virtual void computeElectronPressureGrad(const double n_e, const double T_e, const double *gradUp, - double *gradPe) { + MFEM_HOST_DEVICE virtual void computeElectronPressureGrad(const double n_e, const double T_e, const double* gradUp, + double* gradPe) { printf("computeElectronPressureGrad not implemented"); assert(false); } diff --git a/src/lte_thermo_chem.cpp b/src/lte_thermo_chem.cpp index e95f6269..bde5a725 100644 --- a/src/lte_thermo_chem.cpp +++ b/src/lte_thermo_chem.cpp @@ -48,15 +48,15 @@ using namespace mfem; using namespace mfem::common; -static double radius(const Vector &pos) { return pos[0]; } +static double radius(const Vector& pos) { return pos[0]; } static FunctionCoefficient radius_coeff(radius); -static double sigmaTorchStartUp(const Vector &pos) { +static double sigmaTorchStartUp(const Vector& pos) { // const double x = pos[0]; // radial location const double x = std::sqrt(pos[0] * pos[0] + pos[2] * pos[2]); // radial location const double y = pos[1]; // axial location - //const double r0 = 0.005; + // const double r0 = 0.005; const double r0 = 0.0067; const double y0 = 0.135; const double ysig = 0.015; @@ -69,8 +69,8 @@ static double sigmaTorchStartUp(const Vector &pos) { static FunctionCoefficient sigma_start_up(sigmaTorchStartUp); -LteThermoChem::LteThermoChem(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalSchemeCoefficients &time_coeff, - ParGridFunction *gridScale, TPS::Tps *tps) +LteThermoChem::LteThermoChem(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalSchemeCoefficients& time_coeff, + ParGridFunction* gridScale, TPS::Tps* tps) : tpsP_(tps), pmesh_(pmesh), gll_rules_(0, Quadrature1D::GaussLobatto), @@ -406,12 +406,12 @@ void LteThermoChem::initializeSelf() { // Initialize the gas constant and Cp { - const double *d_T = Tn_next_.Read(); + const double* d_T = Tn_next_.Read(); - double *d_Rgas = Rgas_.Write(); + double* d_Rgas = Rgas_.Write(); MFEM_FORALL(i, Tn_.Size(), { d_Rgas[i] = Rgas_table_->eval(d_T[i]); }); - double *d_Cp = Cp_.Write(); + double* d_Cp = Cp_.Write(); MFEM_FORALL(i, Tn_.Size(), { d_Cp[i] = Cp_table_->eval(d_T[i]); }); } Rgas_gf_.SetFromTrueDofs(Rgas_); @@ -419,12 +419,12 @@ void LteThermoChem::initializeSelf() { // Initialize the transport properties { - const double *d_T = Tn_.Read(); + const double* d_T = Tn_.Read(); - double *d_visc = visc_.Write(); + double* d_visc = visc_.Write(); MFEM_FORALL(i, Tn_.Size(), { d_visc[i] = mu_table_->eval(d_T[i]); }); - double *d_kap = kappa_.Write(); + double* d_kap = kappa_.Write(); MFEM_FORALL(i, Tn_.Size(), { d_kap[i] = kappa_table_->eval(d_T[i]); }); } mu_gf_.SetFromTrueDofs(visc_); @@ -479,7 +479,7 @@ void LteThermoChem::initializeSelf() { std::cout << "Calorically Perfect: Setting uniform Dirichlet temperature on patch = " << patch << std::endl; } AddTempDirichletBC(temperature_value, inlet_attr); - + } else if (type == "interpolate") { temperature_bc_field_ = new GridFunctionCoefficient(extData_interface_->Tdata); if (!neumann_temp_) { @@ -549,12 +549,12 @@ void LteThermoChem::initializeSelf() { double Twall; tpsP_->getRequiredInput((basepath + "/temperature").c_str(), Twall); - ConstantCoefficient *Twall_coeff = new ConstantCoefficient(); + ConstantCoefficient* Twall_coeff = new ConstantCoefficient(); Twall_coeff->constant = Twall; AddTempDirichletBC(Twall_coeff, attr_wall); - ConstantCoefficient *Qt_bc_coeff = new ConstantCoefficient(); + ConstantCoefficient* Qt_bc_coeff = new ConstantCoefficient(); Qt_bc_coeff->constant = 0.0; AddQtDirichletBC(Qt_bc_coeff, attr_wall); } @@ -582,9 +582,9 @@ void LteThermoChem::initializeOperators() { // const IntegrationRule &ir_i = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ + 1); // const IntegrationRule &ir_nli = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 4 * order_); // const IntegrationRule &ir_di = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * order_ - 1); - const IntegrationRule &ir_i = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ - 1); - const IntegrationRule &ir_nli = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ - 1); - const IntegrationRule &ir_di = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ - 1); + const IntegrationRule& ir_i = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ - 1); + const IntegrationRule& ir_nli = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ - 1); + const IntegrationRule& ir_di = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ - 1); if (rank0_) std::cout << "Integration rules set" << endl; // coefficients for operators @@ -669,7 +669,7 @@ void LteThermoChem::initializeOperators() { // Convection: Atemperature(i,j) = \int_{\Omega} \phi_i \rho Cp u \cdot \nabla \phi_j At_form_ = new ParBilinearForm(sfes_); - ConvectionIntegrator *at_blfi; + ConvectionIntegrator* at_blfi; if (axisym_) { at_blfi = new ConvectionIntegrator(*rad_rho_Cp_u_coeff_); } else { @@ -688,7 +688,7 @@ void LteThermoChem::initializeOperators() { // mass matrix Ms_form_ = new ParBilinearForm(sfes_); - MassIntegrator *ms_blfi; + MassIntegrator* ms_blfi; if (axisym_) { ms_blfi = new MassIntegrator(radius_coeff); } else { @@ -706,7 +706,7 @@ void LteThermoChem::initializeOperators() { // mass matrix with rho * Cp weight M_rho_Cp_form_ = new ParBilinearForm(sfes_); - MassIntegrator *mrc_blfi; + MassIntegrator* mrc_blfi; if (axisym_) { mrc_blfi = new MassIntegrator(*rad_rho_Cp_coeff_); } else { @@ -724,7 +724,7 @@ void LteThermoChem::initializeOperators() { // mass matrix with rho weight (used in Qt solve) M_rho_form_ = new ParBilinearForm(sfes_); - MassIntegrator *msrho_blfi; + MassIntegrator* msrho_blfi; if (axisym_) { msrho_blfi = new MassIntegrator(*rad_rho_coeff_); } else { @@ -742,8 +742,8 @@ void LteThermoChem::initializeOperators() { // helmholtz Ht_form_ = new ParBilinearForm(sfes_); - MassIntegrator *hmt_blfi; - DiffusionIntegrator *hdt_blfi; + MassIntegrator* hmt_blfi; + DiffusionIntegrator* hdt_blfi; if (axisym_) { hmt_blfi = new MassIntegrator(*rad_rho_Cp_over_dt_coeff_); hdt_blfi = new DiffusionIntegrator(*rad_thermal_diff_total_coeff_); @@ -759,7 +759,7 @@ void LteThermoChem::initializeOperators() { Ht_form_->AddDomainIntegrator(hdt_blfi); if (sw_stab_) { - auto *sdt_blfi = new DiffusionIntegrator(*supg_coeff_); + auto* sdt_blfi = new DiffusionIntegrator(*supg_coeff_); if (numerical_integ_) { sdt_blfi->SetIntRule(&ir_di); } @@ -778,7 +778,7 @@ void LteThermoChem::initializeOperators() { MsInvPC_ = new OperatorJacobiSmoother(diag_pa, empty); } else { MsInvPC_ = new HypreSmoother(*Ms_.As()); - dynamic_cast(MsInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(MsInvPC_)->SetType(HypreSmoother::Jacobi, 1); } MsInv_ = new CGSolver(sfes_->GetComm()); MsInv_->iterative_mode = false; @@ -794,7 +794,7 @@ void LteThermoChem::initializeOperators() { MrhoInvPC_ = new OperatorJacobiSmoother(diag_pa, empty); } else { MrhoInvPC_ = new HypreSmoother(*M_rho_.As()); - dynamic_cast(MrhoInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(MrhoInvPC_)->SetType(HypreSmoother::Jacobi, 1); } MrhoInv_ = new CGSolver(sfes_->GetComm()); MrhoInv_->iterative_mode = false; @@ -810,7 +810,7 @@ void LteThermoChem::initializeOperators() { HtInvPC_ = new OperatorJacobiSmoother(diag_pa, temp_ess_tdof_); } else { HtInvPC_ = new HypreSmoother(*Ht_.As()); - dynamic_cast(HtInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(HtInvPC_)->SetType(HypreSmoother::Jacobi, 1); } HtInv_ = new CGSolver(sfes_->GetComm()); @@ -824,8 +824,8 @@ void LteThermoChem::initializeOperators() { if (rank0_) std::cout << "Temperature operators set" << endl; jh_form_ = new ParLinearForm(sfes_); - DomainLFIntegrator *jh_dlfi; - DomainLFIntegrator *rad_dlfi; + DomainLFIntegrator* jh_dlfi; + DomainLFIntegrator* rad_dlfi; if (axisym_) { jh_dlfi = new DomainLFIntegrator(*rad_jh_coeff_); rad_dlfi = new DomainLFIntegrator(*rad_radiation_sink_coeff_); @@ -844,7 +844,7 @@ void LteThermoChem::initializeOperators() { // Convection (for rho): Arho(i,j) = \int_{\Omega} \phi_i u \cdot \nabla \phi_j A_rho_form_ = new ParBilinearForm(sfes_); - ConvectionIntegrator *ar_blfi; + ConvectionIntegrator* ar_blfi; if (axisym_) { ar_blfi = new ConvectionIntegrator(*rad_un_next_coeff_); } else { @@ -861,7 +861,7 @@ void LteThermoChem::initializeOperators() { A_rho_form_->FormSystemMatrix(empty, A_rho_); Mq_form_ = new ParBilinearForm(sfes_); - MassIntegrator *mq_blfi; + MassIntegrator* mq_blfi; if (axisym_) { mq_blfi = new MassIntegrator(radius_coeff); } else { @@ -873,7 +873,7 @@ void LteThermoChem::initializeOperators() { Mq_form_->AddDomainIntegrator(mq_blfi); if (qt_filter_) { - DiffusionIntegrator *qtf_blfi; + DiffusionIntegrator* qtf_blfi; qtf_blfi = new DiffusionIntegrator(*gscale2_coeff_); if (numerical_integ_) { qtf_blfi->SetIntRule(&ir_i); @@ -893,7 +893,7 @@ void LteThermoChem::initializeOperators() { MqInvPC_ = new OperatorJacobiSmoother(diag_pa, empty); } else { MqInvPC_ = new HypreSmoother(*Mq_.As()); - dynamic_cast(MqInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(MqInvPC_)->SetType(HypreSmoother::Jacobi, 1); } MqInv_ = new CGSolver(sfes_->GetComm()); MqInv_->iterative_mode = false; @@ -904,7 +904,7 @@ void LteThermoChem::initializeOperators() { MqInv_->SetMaxIter(max_iter_); LQ_form_ = new ParBilinearForm(sfes_); - DiffusionIntegrator *lqd_blfi; + DiffusionIntegrator* lqd_blfi; if (axisym_) { lqd_blfi = new DiffusionIntegrator(*rad_thermal_diff_total_coeff_); } else { @@ -915,24 +915,24 @@ void LteThermoChem::initializeOperators() { } LQ_form_->AddDomainIntegrator(lqd_blfi); - // NO, this is not consistent and will degrade stability - //if (sw_stab_) { + // NO, this is not consistent and will degrade stability + // if (sw_stab_) { // auto *slqd_blfi = new DiffusionIntegrator(*supg_coeff_); // if (numerical_integ_) { // slqd_blfi->SetIntRule(&ir_di); // } // LQ_form_->AddDomainIntegrator(slqd_blfi); // } - + if (partial_assembly_) { - LQ_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); + LQ_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); } LQ_form_->Assemble(); LQ_form_->FormSystemMatrix(empty, LQ_); LQ_bdry_ = new ParLinearForm(sfes_); // auto *lq_bdry_lfi = new BoundaryNormalLFIntegrator(*kap_gradT_coeff_, 2, -1); - BoundaryNormalLFIntegrator *lq_bdry_lfi; + BoundaryNormalLFIntegrator* lq_bdry_lfi; if (axisym_) { lq_bdry_lfi = new BoundaryNormalLFIntegrator(*rad_kap_gradT_coeff_, 2, -1); } else { @@ -957,7 +957,7 @@ void LteThermoChem::initializeOperators() { Ms_->AddMult(Tn_, resT_); // Prepare for the solve - for (auto &temp_dbc : temp_dbcs_) { + for (auto& temp_dbc : temp_dbcs_) { Tn_next_gf_.ProjectBdrCoefficient(*temp_dbc.coeff, temp_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(resT_, resT_gf_); @@ -976,7 +976,7 @@ void LteThermoChem::initializeOperators() { Tn_gf_.GetTrueDofs(Tn_); Tn_next_gf_.SetFromTrueDofs(Tn_); Tn_next_gf_.GetTrueDofs(Tn_next_); - + } else if (filter_restart_) { if (rank0_) std::cout << "************ Filtering temperature restart ******************" << std::endl; // Build the right-hand-side @@ -1000,14 +1000,14 @@ void LteThermoChem::initializeOperators() { } // Prepare for the solve - for (auto &temp_dbc : temp_dbcs_) { + for (auto& temp_dbc : temp_dbcs_) { Tn_next_gf_.ProjectBdrCoefficient(*temp_dbc.coeff, temp_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(resT_, resT_gf_); Vector Xt2, Bt2; if (partial_assembly_) { - auto *HC = Ht_.As(); + auto* HC = Ht_.As(); EliminateRHS(*Ht_form_, *HC, temp_ess_tdof_, Tn_next_gf_, resT_gf_, Xt2, Bt2, 1); } else { Ht_form_->FormLinearSystem(temp_ess_tdof_, Tn_next_gf_, resT_gf_, Ht_, Xt2, Bt2, 1); @@ -1054,7 +1054,7 @@ void LteThermoChem::initializeOperators() { updateProperties(); } -void LteThermoChem::initializeStats(Averaging &average, IODataOrganizer &io, bool continuation) { +void LteThermoChem::initializeStats(Averaging& average, IODataOrganizer& io, bool continuation) { if (average.ComputeMean()) { // fields for averaging average.registerField(std::string("temperature"), &Tn_gf_, false, 0, 1); @@ -1092,7 +1092,7 @@ void LteThermoChem::step() { const double time_ = time_coeff_.time; // Set current time for velocity Dirichlet boundary conditions. - for (auto &temp_dbc : temp_dbcs_) { + for (auto& temp_dbc : temp_dbcs_) { temp_dbc.coeff->SetTime(time_ + dt_); } @@ -1112,9 +1112,9 @@ void LteThermoChem::step() { // Update radiation sink if (radiation_ != nullptr) { - const double *d_T = Tn_next_.Read(); - double *d_rad = radiation_sink_.Write(); - Radiation *rmodel = radiation_; + const double* d_T = Tn_next_.Read(); + double* d_rad = radiation_sink_.Write(); + Radiation* rmodel = radiation_; MFEM_FORALL(i, Tn_next_.Size(), { d_rad[i] = rmodel->computeEnergySink(d_T[i]); }); } radiation_sink_gf_.SetFromTrueDofs(radiation_sink_); @@ -1159,14 +1159,14 @@ void LteThermoChem::step() { } // Prepare for the solve - for (auto &temp_dbc : temp_dbcs_) { + for (auto& temp_dbc : temp_dbcs_) { Tn_next_gf_.ProjectBdrCoefficient(*temp_dbc.coeff, temp_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(resT_, resT_gf_); Vector Xt2, Bt2; if (partial_assembly_) { - auto *HC = Ht_.As(); + auto* HC = Ht_.As(); EliminateRHS(*Ht_form_, *HC, temp_ess_tdof_, Tn_next_gf_, resT_gf_, Xt2, Bt2, 1); } else { Ht_form_->FormLinearSystem(temp_ess_tdof_, Tn_next_gf_, resT_gf_, Ht_, Xt2, Bt2, 1); @@ -1228,12 +1228,12 @@ void LteThermoChem::computeExplicitTempConvectionOP() { tmpR0_.Add(time_coeff_.ab3, NTnm2_); } -void LteThermoChem::initializeIO(IODataOrganizer &io) { +void LteThermoChem::initializeIO(IODataOrganizer& io) { io.registerIOFamily("Temperature", "/temperature", &Tn_gf_, true, true, sfec_); io.registerIOVar("/temperature", "temperature", 0); } -void LteThermoChem::initializeViz(ParaViewDataCollection &pvdc) { +void LteThermoChem::initializeViz(ParaViewDataCollection& pvdc) { pvdc.RegisterField("temperature", &Tn_gf_); pvdc.RegisterField("density", &rn_gf_); pvdc.RegisterField("kappa", &kappa_gf_); @@ -1284,12 +1284,12 @@ void LteThermoChem::updateProperties() { // TODO(trevilo): Refactor for gpu support { // const double *d_T = Tn_.Read(); - const double *d_T = Tn_next_.Read(); + const double* d_T = Tn_next_.Read(); - double *d_visc = visc_.Write(); + double* d_visc = visc_.Write(); MFEM_FORALL(i, Tn_.Size(), { d_visc[i] = mu_table_->eval(d_T[i]); }); - double *d_kap = kappa_.Write(); + double* d_kap = kappa_.Write(); MFEM_FORALL(i, Tn_.Size(), { d_kap[i] = kappa_table_->eval(d_T[i]); }); } mu_gf_.SetFromTrueDofs(visc_); @@ -1297,12 +1297,12 @@ void LteThermoChem::updateProperties() { // Update the gas constant and Cp { - const double *d_T = Tn_next_.Read(); + const double* d_T = Tn_next_.Read(); - double *d_Rgas = Rgas_.Write(); + double* d_Rgas = Rgas_.Write(); MFEM_FORALL(i, Tn_.Size(), { d_Rgas[i] = Rgas_table_->eval(d_T[i]); }); - double *d_Cp = Cp_.Write(); + double* d_Cp = Cp_.Write(); MFEM_FORALL(i, Tn_.Size(), { d_Cp[i] = Cp_table_->eval(d_T[i]); }); } Rgas_gf_.SetFromTrueDofs(Rgas_); @@ -1316,9 +1316,9 @@ void LteThermoChem::updateProperties() { void LteThermoChem::evaluatePlasmaConductivityGF() { { - const double *d_T = Tn_next_.Read(); + const double* d_T = Tn_next_.Read(); - double *d_sigma = sigma_.Write(); + double* d_sigma = sigma_.Write(); MFEM_FORALL(i, Tn_.Size(), { d_sigma[i] = sigma_table_->eval(d_T[i]); }); } sigma_gf_.SetFromTrueDofs(sigma_); @@ -1349,7 +1349,7 @@ void LteThermoChem::computeSystemMass() { } /// Add a Dirichlet boundary condition to the temperature field -void LteThermoChem::AddTempDirichletBC(const double &temp, Array &attr) { +void LteThermoChem::AddTempDirichletBC(const double& temp, Array& attr) { temp_dbcs_.emplace_back(attr, new ConstantCoefficient(temp)); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -1359,7 +1359,7 @@ void LteThermoChem::AddTempDirichletBC(const double &temp, Array &attr) { } } -void LteThermoChem::AddTempDirichletBC(Coefficient *coeff, Array &attr) { +void LteThermoChem::AddTempDirichletBC(Coefficient* coeff, Array& attr) { temp_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -1370,11 +1370,11 @@ void LteThermoChem::AddTempDirichletBC(Coefficient *coeff, Array &attr) { } } -void LteThermoChem::AddTempDirichletBC(ScalarFuncT *f, Array &attr) { +void LteThermoChem::AddTempDirichletBC(ScalarFuncT* f, Array& attr) { AddTempDirichletBC(new FunctionCoefficient(f), attr); } -void LteThermoChem::AddQtDirichletBC(Coefficient *coeff, Array &attr) { +void LteThermoChem::AddQtDirichletBC(Coefficient* coeff, Array& attr) { Qt_dbcs_.emplace_back(attr, coeff); if (rank0_ && pmesh_->GetMyRank() == 0) { @@ -1395,7 +1395,7 @@ void LteThermoChem::AddQtDirichletBC(Coefficient *coeff, Array &attr) { } } -void LteThermoChem::AddQtDirichletBC(ScalarFuncT *f, Array &attr) { +void LteThermoChem::AddQtDirichletBC(ScalarFuncT* f, Array& attr) { AddQtDirichletBC(new FunctionCoefficient(f), attr); } diff --git a/src/lte_thermo_chem.hpp b/src/lte_thermo_chem.hpp index 32c606a4..e5cfc1ce 100644 --- a/src/lte_thermo_chem.hpp +++ b/src/lte_thermo_chem.hpp @@ -51,8 +51,8 @@ class Tps; #include "tps_mfem_wrap.hpp" #include "utils.hpp" -using VecFuncT = void(const Vector &x, double t, Vector &u); -using ScalarFuncT = double(const Vector &x, double t); +using VecFuncT = void(const Vector& x, double t, Vector& u); +using ScalarFuncT = double(const Vector& x, double t); class LoMachOptions; struct temporalSchemeCoefficients; @@ -76,13 +76,13 @@ class Radiation; class LteThermoChem final : public ThermoChemModelBase { private: // Options-related structures - TPS::Tps *tpsP_ = nullptr; + TPS::Tps* tpsP_ = nullptr; // Mesh and discretization scheme info - ParMesh *pmesh_ = nullptr; + ParMesh* pmesh_ = nullptr; int order_; IntegrationRules gll_rules_; - const temporalSchemeCoefficients &time_coeff_; + const temporalSchemeCoefficients& time_coeff_; // Flags bool rank0_; /**< true if this is rank 0 */ @@ -111,13 +111,13 @@ class LteThermoChem final : public ThermoChemModelBase { std::vector> temp_dbcs_; /**< vector of Dirichlet BC coefficients for T*/ std::vector> Qt_dbcs_; /**< vector of Dirichlet BC coefficients for Q*/ - LinearTable *mu_table_; // dynamic viscosity - LinearTable *kappa_table_; // thermal conductivity - LinearTable *sigma_table_; // electrical conductivity - LinearTable *Rgas_table_; // specific gas constant - LinearTable *Cp_table_; // specific heat at constant pressure + LinearTable* mu_table_; // dynamic viscosity + LinearTable* kappa_table_; // thermal conductivity + LinearTable* sigma_table_; // electrical conductivity + LinearTable* Rgas_table_; // specific gas constant + LinearTable* Cp_table_; // specific heat at constant pressure - Radiation *radiation_ = nullptr; + Radiation* radiation_ = nullptr; /// pressure-related, closed-system thermo pressure changes double ambient_pressure_, thermo_pressure_, system_mass_; @@ -136,10 +136,10 @@ class LteThermoChem final : public ThermoChemModelBase { // FEM related fields and objects // Scalar \f$H^1\f$ finite element collection. - FiniteElementCollection *sfec_ = nullptr; + FiniteElementCollection* sfec_ = nullptr; // Scalar \f$H^1\f$ finite element space. - ParFiniteElementSpace *sfes_ = nullptr; + ParFiniteElementSpace* sfes_ = nullptr; // Fields ParGridFunction Tnm1_gf_, Tnm2_gf_; @@ -158,69 +158,69 @@ class LteThermoChem final : public ThermoChemModelBase { ParGridFunction R0PM0_gf_; ParGridFunction Qt_gf_; - ParGridFunction *gridScale_gf_ = nullptr; + ParGridFunction* gridScale_gf_ = nullptr; // ParGridFunction *buffer_tInlet_ = nullptr; - GridFunctionCoefficient *temperature_bc_field_ = nullptr; + GridFunctionCoefficient* temperature_bc_field_ = nullptr; ConstantCoefficient bd0_over_dt; - VectorGridFunctionCoefficient *un_next_coeff_ = nullptr; - GridFunctionCoefficient *rhon_next_coeff_ = nullptr; - ScalarVectorProductCoefficient *rho_Cp_u_coeff_ = nullptr; - GridFunctionCoefficient *thermal_diff_coeff_ = nullptr; - GridFunctionCoefficient *mut_coeff_ = nullptr; - ProductCoefficient *kapt_coeff_ = nullptr; - GridFunctionCoefficient *mult_coeff_ = nullptr; - SumCoefficient *thermal_diff_sum_coeff_ = nullptr; - ProductCoefficient *thermal_diff_total_coeff_ = nullptr; - GradientGridFunctionCoefficient *gradT_coeff_ = nullptr; - ScalarVectorProductCoefficient *kap_gradT_coeff_ = nullptr; - GridFunctionCoefficient *rho_coeff_ = nullptr; - GridFunctionCoefficient *Cp_coeff_ = nullptr; - ProductCoefficient *rho_Cp_over_dt_coeff_ = nullptr; - ProductCoefficient *rho_Cp_coeff_ = nullptr; - GridFunctionCoefficient *jh_coeff_ = nullptr; - GridFunctionCoefficient *radiation_sink_coeff_ = nullptr; - - ProductCoefficient *rad_rho_coeff_ = nullptr; - ProductCoefficient *rad_rho_Cp_coeff_ = nullptr; - ScalarVectorProductCoefficient *rad_rho_Cp_u_coeff_ = nullptr; - ProductCoefficient *rad_rho_Cp_over_dt_coeff_ = nullptr; - ProductCoefficient *rad_thermal_diff_total_coeff_ = nullptr; - ScalarVectorProductCoefficient *rad_un_next_coeff_ = nullptr; - ProductCoefficient *rad_jh_coeff_ = nullptr; - ProductCoefficient *rad_radiation_sink_coeff_ = nullptr; - ScalarVectorProductCoefficient *rad_kap_gradT_coeff_ = nullptr; - - VectorMagnitudeCoefficient *umag_coeff_ = nullptr; - GridFunctionCoefficient *gscale_coeff_ = nullptr; - ProductCoefficient *gscale2_coeff_ = nullptr; - GridFunctionCoefficient *visc_coeff_ = nullptr; - PowerCoefficient *visc_inv_coeff_ = nullptr; - ProductCoefficient *reh1_coeff_ = nullptr; - ProductCoefficient *reh2_coeff_ = nullptr; - ProductCoefficient *Reh_coeff_ = nullptr; - ExtTransformedCoefficient *csupg_coeff_ = nullptr; - ProductCoefficient *uw1_coeff_ = nullptr; - ProductCoefficient *uw2_coeff_ = nullptr; - ProductCoefficient *upwind_coeff_ = nullptr; - TransformedMatrixVectorCoefficient *swdiff_coeff_ = nullptr; - ScalarMatrixProductCoefficient *supg_coeff_ = nullptr; + VectorGridFunctionCoefficient* un_next_coeff_ = nullptr; + GridFunctionCoefficient* rhon_next_coeff_ = nullptr; + ScalarVectorProductCoefficient* rho_Cp_u_coeff_ = nullptr; + GridFunctionCoefficient* thermal_diff_coeff_ = nullptr; + GridFunctionCoefficient* mut_coeff_ = nullptr; + ProductCoefficient* kapt_coeff_ = nullptr; + GridFunctionCoefficient* mult_coeff_ = nullptr; + SumCoefficient* thermal_diff_sum_coeff_ = nullptr; + ProductCoefficient* thermal_diff_total_coeff_ = nullptr; + GradientGridFunctionCoefficient* gradT_coeff_ = nullptr; + ScalarVectorProductCoefficient* kap_gradT_coeff_ = nullptr; + GridFunctionCoefficient* rho_coeff_ = nullptr; + GridFunctionCoefficient* Cp_coeff_ = nullptr; + ProductCoefficient* rho_Cp_over_dt_coeff_ = nullptr; + ProductCoefficient* rho_Cp_coeff_ = nullptr; + GridFunctionCoefficient* jh_coeff_ = nullptr; + GridFunctionCoefficient* radiation_sink_coeff_ = nullptr; + + ProductCoefficient* rad_rho_coeff_ = nullptr; + ProductCoefficient* rad_rho_Cp_coeff_ = nullptr; + ScalarVectorProductCoefficient* rad_rho_Cp_u_coeff_ = nullptr; + ProductCoefficient* rad_rho_Cp_over_dt_coeff_ = nullptr; + ProductCoefficient* rad_thermal_diff_total_coeff_ = nullptr; + ScalarVectorProductCoefficient* rad_un_next_coeff_ = nullptr; + ProductCoefficient* rad_jh_coeff_ = nullptr; + ProductCoefficient* rad_radiation_sink_coeff_ = nullptr; + ScalarVectorProductCoefficient* rad_kap_gradT_coeff_ = nullptr; + + VectorMagnitudeCoefficient* umag_coeff_ = nullptr; + GridFunctionCoefficient* gscale_coeff_ = nullptr; + ProductCoefficient* gscale2_coeff_ = nullptr; + GridFunctionCoefficient* visc_coeff_ = nullptr; + PowerCoefficient* visc_inv_coeff_ = nullptr; + ProductCoefficient* reh1_coeff_ = nullptr; + ProductCoefficient* reh2_coeff_ = nullptr; + ProductCoefficient* Reh_coeff_ = nullptr; + ExtTransformedCoefficient* csupg_coeff_ = nullptr; + ProductCoefficient* uw1_coeff_ = nullptr; + ProductCoefficient* uw2_coeff_ = nullptr; + ProductCoefficient* upwind_coeff_ = nullptr; + TransformedMatrixVectorCoefficient* swdiff_coeff_ = nullptr; + ScalarMatrixProductCoefficient* supg_coeff_ = nullptr; // operators and solvers - ParBilinearForm *At_form_ = nullptr; - ParBilinearForm *Ms_form_ = nullptr; - ParBilinearForm *M_rho_Cp_form_ = nullptr; - ParBilinearForm *Ht_form_ = nullptr; + ParBilinearForm* At_form_ = nullptr; + ParBilinearForm* Ms_form_ = nullptr; + ParBilinearForm* M_rho_Cp_form_ = nullptr; + ParBilinearForm* Ht_form_ = nullptr; - ParBilinearForm *M_rho_form_ = nullptr; - ParBilinearForm *A_rho_form_ = nullptr; + ParBilinearForm* M_rho_form_ = nullptr; + ParBilinearForm* A_rho_form_ = nullptr; - ParLinearForm *jh_form_ = nullptr; + ParLinearForm* jh_form_ = nullptr; - ParBilinearForm *Mq_form_ = nullptr; - ParBilinearForm *LQ_form_ = nullptr; - ParLinearForm *LQ_bdry_ = nullptr; + ParBilinearForm* Mq_form_ = nullptr; + ParBilinearForm* LQ_form_ = nullptr; + ParLinearForm* LQ_bdry_ = nullptr; OperatorHandle At_; OperatorHandle Ht_; @@ -231,14 +231,14 @@ class LteThermoChem final : public ThermoChemModelBase { OperatorHandle M_rho_; OperatorHandle A_rho_; - mfem::Solver *MsInvPC_ = nullptr; - mfem::CGSolver *MsInv_ = nullptr; - mfem::Solver *MqInvPC_ = nullptr; - mfem::CGSolver *MqInv_ = nullptr; - mfem::Solver *MrhoInvPC_ = nullptr; - mfem::CGSolver *MrhoInv_ = nullptr; - mfem::Solver *HtInvPC_ = nullptr; - mfem::CGSolver *HtInv_ = nullptr; + mfem::Solver* MsInvPC_ = nullptr; + mfem::CGSolver* MsInv_ = nullptr; + mfem::Solver* MqInvPC_ = nullptr; + mfem::CGSolver* MqInv_ = nullptr; + mfem::Solver* MrhoInvPC_ = nullptr; + mfem::CGSolver* MrhoInv_ = nullptr; + mfem::Solver* HtInvPC_ = nullptr; + mfem::CGSolver* HtInv_ = nullptr; // Vectors Vector Tn_, Tn_next_, Tnm1_, Tnm2_; @@ -262,23 +262,23 @@ class LteThermoChem final : public ThermoChemModelBase { int filter_cutoff_modes_ = 0; double filter_alpha_ = 0.0; - FiniteElementCollection *sfec_filter_ = nullptr; - ParFiniteElementSpace *sfes_filter_ = nullptr; + FiniteElementCollection* sfec_filter_ = nullptr; + ParFiniteElementSpace* sfes_filter_ = nullptr; ParGridFunction Tn_NM1_gf_; ParGridFunction Tn_filtered_gf_; public: - LteThermoChem(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalSchemeCoefficients &timeCoeff, - ParGridFunction *gridScale, TPS::Tps *tps); + LteThermoChem(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalSchemeCoefficients& timeCoeff, + ParGridFunction* gridScale, TPS::Tps* tps); virtual ~LteThermoChem(); // Functions overriden from base class void initializeSelf() final; void initializeOperators() final; - void initializeStats(Averaging &average, IODataOrganizer &io, bool continuation) final; + void initializeStats(Averaging& average, IODataOrganizer& io, bool continuation) final; void step() final; - void initializeIO(IODataOrganizer &io) final; - void initializeViz(ParaViewDataCollection &pvdc) final; + void initializeIO(IODataOrganizer& io) final; + void initializeViz(ParaViewDataCollection& pvdc) final; void evaluatePlasmaConductivityGF() final; // Functions added here @@ -292,25 +292,25 @@ class LteThermoChem final : public ThermoChemModelBase { void updateHistory(); /// Return a pointer to the current temperature ParGridFunction. - ParGridFunction *GetCurrentTemperature() { return &Tn_gf_; } + ParGridFunction* GetCurrentTemperature() { return &Tn_gf_; } /// Return a pointer to the current density ParGridFunction. - ParGridFunction *GetCurrentDensity() { return &rn_gf_; } + ParGridFunction* GetCurrentDensity() { return &rn_gf_; } /// Return a pointer to the current total viscosity ParGridFunction. - ParGridFunction *GetCurrentViscosity() { return &mu_gf_; } + ParGridFunction* GetCurrentViscosity() { return &mu_gf_; } /// Return a pointer to the current total thermal diffusivity ParGridFunction. - ParGridFunction *GetCurrentThermalDiffusivity() { return &kappa_gf_; } + ParGridFunction* GetCurrentThermalDiffusivity() { return &kappa_gf_; } /// Return a pointer to the current total thermal diffusivity ParGridFunction. - ParGridFunction *GetCurrentThermalDiv() { return &Qt_gf_; } + ParGridFunction* GetCurrentThermalDiv() { return &Qt_gf_; } /// Add a Dirichlet boundary condition to the temperature and Qt field. - void AddTempDirichletBC(const double &temp, Array &attr); - void AddTempDirichletBC(Coefficient *coeff, Array &attr); - void AddTempDirichletBC(ScalarFuncT *f, Array &attr); - void AddQtDirichletBC(Coefficient *coeff, Array &attr); - void AddQtDirichletBC(ScalarFuncT *f, Array &attr); + void AddTempDirichletBC(const double& temp, Array& attr); + void AddTempDirichletBC(Coefficient* coeff, Array& attr); + void AddTempDirichletBC(ScalarFuncT* f, Array& attr); + void AddQtDirichletBC(Coefficient* coeff, Array& attr); + void AddQtDirichletBC(ScalarFuncT* f, Array& attr); }; #endif // LTE_THERMO_CHEM_HPP_ diff --git a/src/lte_transport_properties.cpp b/src/lte_transport_properties.cpp index 15b22536..ab0b629b 100644 --- a/src/lte_transport_properties.cpp +++ b/src/lte_transport_properties.cpp @@ -33,7 +33,7 @@ #include "lte_transport_properties.hpp" #ifndef _GPU_ -LteTransport::LteTransport(GasMixture *_mixture, RunConfiguration &_runfile) : MolecularTransport(_mixture) { +LteTransport::LteTransport(GasMixture* _mixture, RunConfiguration& _runfile) : MolecularTransport(_mixture) { #ifdef HAVE_GSL mu_table_ = new GslTableInterpolator2D(_runfile.lteMixtureInput.trans_file_name, 0, /* temperature column */ 1, /* density column */ @@ -57,7 +57,7 @@ LteTransport::LteTransport(GasMixture *_mixture, RunConfiguration &_runfile) : M #endif // HAVE_GSL } -LteTransport::LteTransport(GasMixture *_mixture, TableInput mu_table_input, TableInput kappa_table_input, +LteTransport::LteTransport(GasMixture* _mixture, TableInput mu_table_input, TableInput kappa_table_input, TableInput sigma_table_input) : MolecularTransport(_mixture) { mu_table_ = new LinearTable(mu_table_input); @@ -65,7 +65,7 @@ LteTransport::LteTransport(GasMixture *_mixture, TableInput mu_table_input, Tabl sigma_table_ = new LinearTable(sigma_table_input); } #else -MFEM_HOST_DEVICE LteTransport::LteTransport(GasMixture *_mixture, TableInput mu_table_input, +MFEM_HOST_DEVICE LteTransport::LteTransport(GasMixture* _mixture, TableInput mu_table_input, TableInput kappa_table_input, TableInput sigma_table_input) : MolecularTransport(_mixture), mu_table_(LinearTable(mu_table_input)), @@ -81,9 +81,9 @@ MFEM_HOST_DEVICE LteTransport::~LteTransport() { #endif } -MFEM_HOST_DEVICE void LteTransport::ComputeFluxMolecularTransport(const double *state, const double *gradUp, - const double *Efield, double *transportBuffer, - double *diffusionVelocity) { +MFEM_HOST_DEVICE void LteTransport::ComputeFluxMolecularTransport(const double* state, const double* gradUp, + const double* Efield, double* transportBuffer, + double* diffusionVelocity) { const double rho = state[0]; const double T = mixture->ComputeTemperature(state); @@ -104,10 +104,10 @@ MFEM_HOST_DEVICE void LteTransport::ComputeFluxMolecularTransport(const double * } } -MFEM_HOST_DEVICE void LteTransport::ComputeSourceMolecularTransport(const double *state, const double *Up, - const double *gradUp, const double *Efield, - double *globalTransport, double *speciesTransport, - double *diffusionVelocity, double *n_sp) { +MFEM_HOST_DEVICE void LteTransport::ComputeSourceMolecularTransport(const double* state, const double* Up, + const double* gradUp, const double* Efield, + double* globalTransport, double* speciesTransport, + double* diffusionVelocity, double* n_sp) { const double rho = Up[0]; const double T = Up[1 + nvel_]; #ifdef _GPU_ @@ -122,7 +122,7 @@ MFEM_HOST_DEVICE void LteTransport::ComputeSourceMolecularTransport(const double globalTransport[SrcTrns::ELECTRIC_CONDUCTIVITY] = sigma; } -MFEM_HOST_DEVICE void LteTransport::GetViscosities(const double *conserved, const double *primitive, double *visc) { +MFEM_HOST_DEVICE void LteTransport::GetViscosities(const double* conserved, const double* primitive, double* visc) { const double rho = primitive[0]; const double T = primitive[1 + nvel_]; diff --git a/src/lte_transport_properties.hpp b/src/lte_transport_properties.hpp index 9b53242a..ab0f8921 100644 --- a/src/lte_transport_properties.hpp +++ b/src/lte_transport_properties.hpp @@ -59,30 +59,30 @@ class LteTransport : public MolecularTransport { LinearTable kappa_table_; // thermal conductivity LinearTable sigma_table_; // electrical conductivity #else - TableInterface *mu_table_; // dynamic viscosity - TableInterface *kappa_table_; // thermal conductivity - TableInterface *sigma_table_; // electrical conductivity + TableInterface* mu_table_; // dynamic viscosity + TableInterface* kappa_table_; // thermal conductivity + TableInterface* sigma_table_; // electrical conductivity #endif public: #ifndef _GPU_ - LteTransport(GasMixture *_mixture, RunConfiguration &_runfile); + LteTransport(GasMixture* _mixture, RunConfiguration& _runfile); #endif - MFEM_HOST_DEVICE LteTransport(GasMixture *_mixture, TableInput mu_table_input, TableInput kappa_table_input, + MFEM_HOST_DEVICE LteTransport(GasMixture* _mixture, TableInput mu_table_input, TableInput kappa_table_input, TableInput sigma_table_input); MFEM_HOST_DEVICE virtual ~LteTransport(); - MFEM_HOST_DEVICE void ComputeFluxMolecularTransport(const double *state, const double *gradUp, const double *Efield, - double *transportBuffer, double *diffusionVelocity) final; + MFEM_HOST_DEVICE void ComputeFluxMolecularTransport(const double* state, const double* gradUp, const double* Efield, + double* transportBuffer, double* diffusionVelocity) final; - MFEM_HOST_DEVICE void ComputeSourceMolecularTransport(const double *state, const double *Up, const double *gradUp, - const double *Efield, double *globalTransport, - double *speciesTransport, double *diffusionVelocity, - double *n_sp) final; + MFEM_HOST_DEVICE void ComputeSourceMolecularTransport(const double* state, const double* Up, const double* gradUp, + const double* Efield, double* globalTransport, + double* speciesTransport, double* diffusionVelocity, + double* n_sp) final; using MolecularTransport::GetViscosities; - MFEM_HOST_DEVICE void GetViscosities(const double *conserved, const double *primitive, double *visc) final; + MFEM_HOST_DEVICE void GetViscosities(const double* conserved, const double* primitive, double* visc) final; }; #endif // LTE_TRANSPORT_PROPERTIES_HPP_ diff --git a/src/main.cpp b/src/main.cpp index a324951b..b548c189 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,7 @@ #include "tps.hpp" -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { mfem::Mpi::Init(argc, argv); int status; { diff --git a/src/masa_handler.cpp b/src/masa_handler.cpp index c330eeb2..de39bf3b 100644 --- a/src/masa_handler.cpp +++ b/src/masa_handler.cpp @@ -87,8 +87,8 @@ void M2ulPhyS::initMasaHandler() { initMMSCoefficients(); } -void M2ulPhyS::projectExactSolution(const double _time, ParGridFunction *prjU) { - void (*exactSolnFunction)(const Vector &, double, Vector &); +void M2ulPhyS::projectExactSolution(const double _time, ParGridFunction* prjU) { + void (*exactSolnFunction)(const Vector&, double, Vector&); if (config.workFluid == DRY_AIR || config.workFluid == LTE_FLUID) { if (dim == 2) { @@ -124,7 +124,7 @@ void M2ulPhyS::initMMSCoefficients() { // set up origin vector to compute L2 norm via ComputeLpError. zeroUBlock_ = new BlockVector(*offsets); zeroU_ = new ParGridFunction(vfes, zeroUBlock_->HostReadWrite()); - double *dataZeros = zeroU_->HostReadWrite(); + double* dataZeros = zeroU_->HostReadWrite(); int NDof = vfes->GetNDofs(); for (int i = 0; i < NDof; i++) { for (int eq = 0; eq < num_equation; eq++) { @@ -150,7 +150,7 @@ void M2ulPhyS::checkSolutionError(const double _time, const bool final) { cout << "time step: " << iter << ", physical time " << _time << "s" << ", Dens. error: " << errorDen << " Vel. " << errorVel << " press. " << errorPre << endl; } else { - Coefficient *nullPtr = NULL; + Coefficient* nullPtr = NULL; stateMMS_->SetTime(_time); Vector componentErrors(num_equation), componentRelErrors(num_equation); @@ -196,13 +196,13 @@ void M2ulPhyS::checkSolutionError(const double _time, const bool final) { namespace mms { -void exactSolnFunction(const Vector &x, double tin, Vector &y) { +void exactSolnFunction(const Vector& x, double tin, Vector& y) { std::vector y1(y.Size()); MASA::masa_eval_exact_state(x[0], x[1], y1); for (int eq = 0; eq < y.Size(); eq++) y[eq] = y1[eq]; } -void evaluateForcing(const Vector &x, double time, Array &y) { +void evaluateForcing(const Vector& x, double time, Array& y) { std::vector y1(y.Size()); MASA::masa_eval_source_state(x[0], x[1], y1); for (int eq = 0; eq < y.Size(); eq++) y[eq] = y1[eq]; @@ -212,14 +212,14 @@ void evaluateForcing(const Vector &x, double time, Array &y) { namespace dryair2d { -void evaluateForcing(const Vector &x, double time, Array &y) { +void evaluateForcing(const Vector& x, double time, Array& y) { y[0] = MASA::masa_eval_source_rho(x[0], x[1]); // rho y[1] = MASA::masa_eval_source_rho_u(x[0], x[1]); // rho*u y[2] = MASA::masa_eval_source_rho_v(x[0], x[1]); // rho*v y[3] = MASA::masa_eval_source_rho_e(x[0], x[1]); // rhp*e } -void exactSolnFunction(const Vector &x, double tin, Vector &y) { +void exactSolnFunction(const Vector& x, double tin, Vector& y) { // TODO(kevin): make one for NS2DCompressible. MFEM_ASSERT(x.Size() == 2, ""); @@ -237,7 +237,7 @@ void exactSolnFunction(const Vector &x, double tin, Vector &y) { y[3] += k; } -void initEuler2D(const int dim, RunConfiguration &config) { +void initEuler2D(const int dim, RunConfiguration& config) { assert(dim == 2); assert(config.workFluid == DRY_AIR); assert(config.GetEquationSystem() == EULER); @@ -262,7 +262,7 @@ void initEuler2D(const int dim, RunConfiguration &config) { MASA::masa_set_param("a_py", 2.); } -void initCNS2DSutherlands(const int dim, RunConfiguration &config) { +void initCNS2DSutherlands(const int dim, RunConfiguration& config) { assert(dim == 2); assert(config.workFluid == DRY_AIR); assert(config.mms_name_ == "ad_cns_2d_sutherlands"); @@ -303,7 +303,7 @@ void initCNS2DSutherlands(const int dim, RunConfiguration &config) { namespace dryair3d { -void evaluateForcing(const Vector &x, double time, Array &y) { +void evaluateForcing(const Vector& x, double time, Array& y) { y[0] = MASA::masa_eval_source_rho(x[0], x[1], x[2], time); // rho y[1] = MASA::masa_eval_source_u(x[0], x[1], x[2], time); // rho*u y[2] = MASA::masa_eval_source_v(x[0], x[1], x[2], time); // rho*v @@ -311,7 +311,7 @@ void evaluateForcing(const Vector &x, double time, Array &y) { y[4] = MASA::masa_eval_source_e(x[0], x[1], x[2], time); // rhp*e } -void exactSolnFunction(const Vector &x, double tin, Vector &y) { +void exactSolnFunction(const Vector& x, double tin, Vector& y) { // TODO(kevin): make one for NS2DCompressible. MFEM_ASSERT(x.Size() == 3, ""); @@ -330,24 +330,24 @@ void exactSolnFunction(const Vector &x, double tin, Vector &y) { y[4] += k; } -void exactDenFunction(const Vector &x, double tin, Vector &y) { +void exactDenFunction(const Vector& x, double tin, Vector& y) { MFEM_ASSERT(x.Size() == 3, ""); y(0) = MASA::masa_eval_exact_rho(x[0], x[1], x[2], tin); // rho } -void exactVelFunction(const Vector &x, double tin, Vector &y) { +void exactVelFunction(const Vector& x, double tin, Vector& y) { MFEM_ASSERT(x.Size() == 3, ""); y(0) = MASA::masa_eval_exact_u(x[0], x[1], x[2], tin); y(1) = MASA::masa_eval_exact_v(x[0], x[1], x[2], tin); y(2) = MASA::masa_eval_exact_w(x[0], x[1], x[2], tin); } -void exactPreFunction(const Vector &x, double tin, Vector &y) { +void exactPreFunction(const Vector& x, double tin, Vector& y) { MFEM_ASSERT(x.Size() == 3, ""); y(0) = MASA::masa_eval_exact_p(x[0], x[1], x[2], tin); } -void initEuler3DTransient(const int dim, RunConfiguration &config) { +void initEuler3DTransient(const int dim, RunConfiguration& config) { assert(dim == 3); assert(config.workFluid == DRY_AIR || config.workFluid == LTE_FLUID); assert(config.GetEquationSystem() == EULER); @@ -417,7 +417,7 @@ void initEuler3DTransient(const int dim, RunConfiguration &config) { MASA::masa_set_param("a_pt", 400.); } -void initNS3DTransient(const int dim, RunConfiguration &config) { +void initNS3DTransient(const int dim, RunConfiguration& config) { assert(dim == 3); assert(config.workFluid == DRY_AIR); assert(config.GetEquationSystem() == NS); @@ -498,7 +498,7 @@ void initNS3DTransient(const int dim, RunConfiguration &config) { namespace ternary2d { -void initTernary2DBase(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly) { +void initTernary2DBase(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly) { assert(config.numSpecies == 3); assert(config.transportModel == CONSTANT); assert(config.gasModel == PERFECT_MIXTURE); @@ -618,7 +618,7 @@ void initTernary2DBase(GasMixture *mixture, RunConfiguration &config, const doub MASA::masa_set_param("rE", rE); } -void initTernary2DPeriodic(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly) { +void initTernary2DPeriodic(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly) { assert(config.mms_name_ == "ternary_2d_periodic"); assert(!config.ambipolar); assert(!config.twoTemperature); @@ -635,7 +635,7 @@ void initTernary2DPeriodic(GasMixture *mixture, RunConfiguration &config, const MASA::masa_set_param("offset_y1", 0.29); } -void initTernary2DPeriodicAmbipolar(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly) { +void initTernary2DPeriodicAmbipolar(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly) { assert(config.mms_name_ == "ternary_2d_periodic_ambipolar"); assert(config.ambipolar); assert(!config.twoTemperature); @@ -644,7 +644,7 @@ void initTernary2DPeriodicAmbipolar(GasMixture *mixture, RunConfiguration &confi ternary2d::initTernary2DBase(mixture, config, Lx, Ly); } -void initTernary2D2TPeriodicAmbipolar(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly) { +void initTernary2D2TPeriodicAmbipolar(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly) { assert(config.mms_name_ == "ternary_2d_2t_periodic_ambipolar"); assert(config.ambipolar); assert(config.twoTemperature); @@ -669,7 +669,7 @@ void initTernary2D2TPeriodicAmbipolar(GasMixture *mixture, RunConfiguration &con MASA::masa_set_param("nu_A", config.constantTransport.mtFreq[numSpecies - 1]); } -void initTernary2D2TAmbipolarWall(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly) { +void initTernary2D2TAmbipolarWall(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly) { assert(config.mms_name_ == "ternary_2d_2t_ambipolar_wall"); assert(config.ambipolar); assert(config.twoTemperature); @@ -717,7 +717,7 @@ void initTernary2D2TAmbipolarWall(GasMixture *mixture, RunConfiguration &config, MASA::masa_set_param("dX0y", 0.045); } -void initTernary2D2TAmbipolarInoutlet(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly) { +void initTernary2D2TAmbipolarInoutlet(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly) { assert(config.mms_name_ == "ternary_2d_2t_ambipolar_inoutlet"); assert(config.ambipolar); assert(config.twoTemperature); @@ -787,7 +787,7 @@ void initTernary2D2TAmbipolarInoutlet(GasMixture *mixture, RunConfiguration &con MASA::masa_set_param("offset_py", 0.87); } -void initTernary2DSheath(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly) { +void initTernary2DSheath(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly) { assert(config.mms_name_ == "ternary_2d_sheath"); assert(config.ambipolar); assert(config.twoTemperature); diff --git a/src/masa_handler.hpp b/src/masa_handler.hpp index 5994a520..fb6a6dd1 100644 --- a/src/masa_handler.hpp +++ b/src/masa_handler.hpp @@ -46,49 +46,49 @@ using namespace std; namespace mms { -void exactSolnFunction(const Vector &x, double tin, Vector &y); -void evaluateForcing(const Vector &x, double time, Array &y); +void exactSolnFunction(const Vector& x, double tin, Vector& y); +void evaluateForcing(const Vector& x, double time, Array& y); } // namespace mms namespace dryair2d { -void evaluateForcing(const Vector &x, double time, Array &y); -void exactSolnFunction(const Vector &x, double tin, Vector &y); -void initEuler2D(const int dim, RunConfiguration &config); -void initCNS2DSutherlands(const int dim, RunConfiguration &config); +void evaluateForcing(const Vector& x, double time, Array& y); +void exactSolnFunction(const Vector& x, double tin, Vector& y); +void initEuler2D(const int dim, RunConfiguration& config); +void initCNS2DSutherlands(const int dim, RunConfiguration& config); } // namespace dryair2d namespace dryair3d { -void evaluateForcing(const Vector &x, double time, Array &y); +void evaluateForcing(const Vector& x, double time, Array& y); -void exactSolnFunction(const Vector &x, double tin, Vector &y); -void exactDenFunction(const Vector &x, double tin, Vector &y); -void exactVelFunction(const Vector &x, double tin, Vector &y); -void exactPreFunction(const Vector &x, double tin, Vector &y); +void exactSolnFunction(const Vector& x, double tin, Vector& y); +void exactDenFunction(const Vector& x, double tin, Vector& y); +void exactVelFunction(const Vector& x, double tin, Vector& y); +void exactPreFunction(const Vector& x, double tin, Vector& y); -void initEuler3DTransient(const int dim, RunConfiguration &config); -void initNS3DTransient(const int dim, RunConfiguration &config); +void initEuler3DTransient(const int dim, RunConfiguration& config); +void initNS3DTransient(const int dim, RunConfiguration& config); } // namespace dryair3d namespace ternary2d { -void initTernary2DBase(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly); +void initTernary2DBase(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly); -void initTernary2DPeriodic(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly); +void initTernary2DPeriodic(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly); -void initTernary2DPeriodicAmbipolar(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly); +void initTernary2DPeriodicAmbipolar(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly); -void initTernary2D2TPeriodicAmbipolar(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly); +void initTernary2D2TPeriodicAmbipolar(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly); -void initTernary2D2TAmbipolarWall(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly); +void initTernary2D2TAmbipolarWall(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly); -void initTernary2D2TAmbipolarInoutlet(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly); +void initTernary2D2TAmbipolarInoutlet(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly); -void initTernary2DSheath(GasMixture *mixture, RunConfiguration &config, const double Lx, const double Ly); +void initTernary2DSheath(GasMixture* mixture, RunConfiguration& config, const double Lx, const double Ly); } // namespace ternary2d diff --git a/src/mesh_base.cpp b/src/mesh_base.cpp index 122e45a8..a10ca128 100644 --- a/src/mesh_base.cpp +++ b/src/mesh_base.cpp @@ -47,7 +47,7 @@ using namespace mfem; -MeshBase::MeshBase(TPS::Tps *tps, LoMachOptions *loMach_opts, int order) +MeshBase::MeshBase(TPS::Tps* tps, LoMachOptions* loMach_opts, int order) : tpsP_(tps), groupsMPI(new MPI_Groups(tps->getTPSCommWorld())), rank0_(groupsMPI->isWorldRoot()), @@ -155,7 +155,7 @@ void MeshBase::initializeMesh() { if (loMach_opts_->scale_mesh != 1) { if (rank0_) grvy_printf(ginfo, "Scaling mesh factor of scale_mesh = %.6e\n", loMach_opts_->scale_mesh); serial_mesh_->EnsureNodes(); - GridFunction *nodes = serial_mesh_->GetNodes(); + GridFunction* nodes = serial_mesh_->GetNodes(); *nodes *= loMach_opts_->scale_mesh; } @@ -272,7 +272,7 @@ void MeshBase::initializeMesh() { } } -void MeshBase::initializeViz(ParaViewDataCollection &pvdc) { +void MeshBase::initializeViz(ParaViewDataCollection& pvdc) { pvdc.RegisterField("resolution", gridScale_); if (loMach_opts_->compute_wallDistance) { pvdc.RegisterField("wall_dist", distance_); @@ -296,8 +296,8 @@ void MeshBase::computeGridScale() { zones_per_vdofALL.SetSize(fes_->GetVSize()); zones_per_vdofALL = 0; - double *data = gridScale_->HostReadWrite(); - double *count = dofCount.HostReadWrite(); + double* data = gridScale_->HostReadWrite(); + double* count = dofCount.HostReadWrite(); for (int i = 0; i < fes_->GetNDofs(); i++) { data[i] = 0.0; @@ -308,14 +308,14 @@ void MeshBase::computeGridScale() { for (int e = 0; e < fes_->GetNE(); ++e) { fes_->GetElementVDofs(e, vdofs); vals.SetSize(vdofs.Size()); - ElementTransformation *tr = fes_->GetElementTransformation(e); - const FiniteElement *el = fes_->GetFE(e); + ElementTransformation* tr = fes_->GetElementTransformation(e); + const FiniteElement* el = fes_->GetFE(e); elndofs = el->GetDof(); double delta; // element dof for (int dof = 0; dof < elndofs; ++dof) { - const IntegrationPoint &ip = el->GetNodes().IntPoint(dof); + const IntegrationPoint& ip = el->GetNodes().IntPoint(dof); tr->SetIntPoint(&ip); delta = pmesh_->GetElementSize(tr->ElementNo, 1); delta = delta / ((double)order_); @@ -335,7 +335,7 @@ void MeshBase::computeGridScale() { } // Count the zones globally. - GroupCommunicator &gcomm = gridScale_->ParFESpace()->GroupComm(); + GroupCommunicator& gcomm = gridScale_->ParFESpace()->GroupComm(); gcomm.Reduce(zones_per_vdof, GroupCommunicator::Sum); gcomm.Bcast(zones_per_vdof); diff --git a/src/mesh_base.hpp b/src/mesh_base.hpp index 2ccd4745..5f56c051 100644 --- a/src/mesh_base.hpp +++ b/src/mesh_base.hpp @@ -45,19 +45,19 @@ class LoMachOptions; class MeshBase { private: - TPS::Tps *tpsP_ = nullptr; + TPS::Tps* tpsP_ = nullptr; - MPI_Groups *groupsMPI = nullptr; + MPI_Groups* groupsMPI = nullptr; bool rank0_; int nprocs_; // total number of MPI procs int rank_; // local MPI rank - LoMachOptions *loMach_opts_ = nullptr; + LoMachOptions* loMach_opts_ = nullptr; const int order_; int dim_; - ParMesh *pmesh_ = nullptr; - Mesh *serial_mesh_ = nullptr; + ParMesh* pmesh_ = nullptr; + Mesh* serial_mesh_ = nullptr; // mapping from local to global element index // int *locToGlobElem = nullptr; @@ -70,7 +70,7 @@ class MeshBase { const int defaultPartMethod = 1; // mapping from local to global element index - int *local_to_global_element_ = nullptr; + int* local_to_global_element_ = nullptr; // min/max element size double hmin_, hmax_; @@ -79,32 +79,32 @@ class MeshBase { double xmin_, ymin_, zmin_; double xmax_, ymax_, zmax_; - mfem::FiniteElementCollection *fec_ = nullptr; - mfem::ParFiniteElementSpace *fes_ = nullptr; - mfem::ParGridFunction *gridScale_ = nullptr; - mfem::ParGridFunction *distance_ = nullptr; + mfem::FiniteElementCollection* fec_ = nullptr; + mfem::ParFiniteElementSpace* fes_ = nullptr; + mfem::ParGridFunction* gridScale_ = nullptr; + mfem::ParGridFunction* distance_ = nullptr; // used in loMach int sDof_; public: - MeshBase(TPS::Tps *tps, LoMachOptions *loMach_opts, int order); + MeshBase(TPS::Tps* tps, LoMachOptions* loMach_opts, int order); virtual ~MeshBase(); virtual void initializeMesh(); virtual void computeGridScale(); virtual void computeWallDistance(); - virtual void initializeViz(mfem::ParaViewDataCollection &pvdc); + virtual void initializeViz(mfem::ParaViewDataCollection& pvdc); - virtual ParMesh *getMesh() { return pmesh_; } - virtual Mesh *getSerialMesh() { return serial_mesh_; } - virtual ParGridFunction *getGridScale() { return gridScale_; } - virtual ParGridFunction *getWallDistance() { return distance_; } + virtual ParMesh* getMesh() { return pmesh_; } + virtual Mesh* getSerialMesh() { return serial_mesh_; } + virtual ParGridFunction* getGridScale() { return gridScale_; } + virtual ParGridFunction* getWallDistance() { return distance_; } virtual int getDofSize() { return sDof_; } virtual double getMinGridScale() { return hmin_; } virtual Array getPartition() { return partitioning_; } // virtual int getDim() final { return dim_; } - int *getLocalToGlobalElementMap() const { return local_to_global_element_; } + int* getLocalToGlobalElementMap() const { return local_to_global_element_; } }; #endif // MESH_BASE_HPP_ diff --git a/src/mixing_length_transport.cpp b/src/mixing_length_transport.cpp index 8abe2ebb..acdc63b2 100644 --- a/src/mixing_length_transport.cpp +++ b/src/mixing_length_transport.cpp @@ -37,12 +37,12 @@ using namespace std; using namespace mfem; -MixingLengthTransport::MixingLengthTransport(GasMixture *mix, RunConfiguration &runfile, - MolecularTransport *molecular_transport) +MixingLengthTransport::MixingLengthTransport(GasMixture* mix, RunConfiguration& runfile, + MolecularTransport* molecular_transport) : MixingLengthTransport(mix, runfile.mix_length_trans_input_, molecular_transport) {} -MFEM_HOST_DEVICE MixingLengthTransport::MixingLengthTransport(GasMixture *mix, const mixingLengthTransportData &inputs, - MolecularTransport *molecular_transport) +MFEM_HOST_DEVICE MixingLengthTransport::MixingLengthTransport(GasMixture* mix, const mixingLengthTransportData& inputs, + MolecularTransport* molecular_transport) : TransportProperties(mix), max_mixing_length_(inputs.max_mixing_length_), Prt_(inputs.Prt_), @@ -50,19 +50,19 @@ MFEM_HOST_DEVICE MixingLengthTransport::MixingLengthTransport(GasMixture *mix, c bulk_mult_(inputs.bulk_multiplier_), molecular_transport_(molecular_transport) {} -void MixingLengthTransport::ComputeFluxTransportProperties(const Vector &state, const DenseMatrix &gradUp, - const Vector &Efield, double radius, double distance, - Vector &transportBuffer, DenseMatrix &diffusionVelocity) { +void MixingLengthTransport::ComputeFluxTransportProperties(const Vector& state, const DenseMatrix& gradUp, + const Vector& Efield, double radius, double distance, + Vector& transportBuffer, DenseMatrix& diffusionVelocity) { transportBuffer.SetSize(FluxTrns::NUM_FLUX_TRANS); diffusionVelocity.SetSize(numSpecies, nvel_); ComputeFluxTransportProperties(&state[0], gradUp.Read(), &Efield[0], radius, distance, &transportBuffer[0], diffusionVelocity.Write()); } -MFEM_HOST_DEVICE void MixingLengthTransport::ComputeFluxTransportProperties(const double *state, const double *gradUp, - const double *Efield, double radius, - double distance, double *transportBuffer, - double *diffusionVelocity) { +MFEM_HOST_DEVICE void MixingLengthTransport::ComputeFluxTransportProperties(const double* state, const double* gradUp, + const double* Efield, double radius, + double distance, double* transportBuffer, + double* diffusionVelocity) { molecular_transport_->ComputeFluxMolecularTransport(state, gradUp, Efield, transportBuffer, diffusionVelocity); const double kappa = transportBuffer[FluxTrns::HEAVY_THERMAL_CONDUCTIVITY]; @@ -134,11 +134,11 @@ MFEM_HOST_DEVICE void MixingLengthTransport::ComputeFluxTransportProperties(cons // TODO(trevilo): Deal with species diffusivities } -void MixingLengthTransport::ComputeSourceTransportProperties(const Vector &state, const Vector &Up, - const DenseMatrix &gradUp, const Vector &Efield, - double distance, Vector &globalTransport, - DenseMatrix &speciesTransport, - DenseMatrix &diffusionVelocity, Vector &n_sp) { +void MixingLengthTransport::ComputeSourceTransportProperties(const Vector& state, const Vector& Up, + const DenseMatrix& gradUp, const Vector& Efield, + double distance, Vector& globalTransport, + DenseMatrix& speciesTransport, + DenseMatrix& diffusionVelocity, Vector& n_sp) { globalTransport.SetSize(SrcTrns::NUM_SRC_TRANS); speciesTransport.SetSize(numSpecies, SpeciesTrns::NUM_SPECIES_COEFFS); n_sp.SetSize(numSpecies); @@ -157,8 +157,8 @@ void MixingLengthTransport::ComputeSourceTransportProperties(const Vector &state } MFEM_HOST_DEVICE void MixingLengthTransport::ComputeSourceTransportProperties( - const double *state, const double *Up, const double *gradUp, const double *Efield, double distance, - double *globalTransport, double *speciesTransport, double *diffusionVelocity, double *n_sp) { + const double* state, const double* Up, const double* gradUp, const double* Efield, double distance, + double* globalTransport, double* speciesTransport, double* diffusionVelocity, double* n_sp) { molecular_transport_->ComputeSourceMolecularTransport(state, Up, gradUp, Efield, globalTransport, speciesTransport, diffusionVelocity, n_sp); } diff --git a/src/mixing_length_transport.hpp b/src/mixing_length_transport.hpp index dd86e925..9ceecc95 100644 --- a/src/mixing_length_transport.hpp +++ b/src/mixing_length_transport.hpp @@ -50,43 +50,43 @@ class MixingLengthTransport : public TransportProperties { const double bulk_mult_; // bulk viscosity multiplier // for molecular transport (owned) - MolecularTransport *molecular_transport_; + MolecularTransport* molecular_transport_; public: - MixingLengthTransport(GasMixture *mix, RunConfiguration &runfile, MolecularTransport *molecular_transport); - MFEM_HOST_DEVICE MixingLengthTransport(GasMixture *mix, const mixingLengthTransportData &inputs, - MolecularTransport *molecular_transport); + MixingLengthTransport(GasMixture* mix, RunConfiguration& runfile, MolecularTransport* molecular_transport); + MFEM_HOST_DEVICE MixingLengthTransport(GasMixture* mix, const mixingLengthTransportData& inputs, + MolecularTransport* molecular_transport); MFEM_HOST_DEVICE virtual ~MixingLengthTransport() { delete molecular_transport_; } - void ComputeFluxTransportProperties(const Vector &state, const DenseMatrix &gradUp, const Vector &Efield, - double radius, double distance, Vector &transportBuffer, - DenseMatrix &diffusionVelocity) final; - MFEM_HOST_DEVICE void ComputeFluxTransportProperties(const double *state, const double *gradUp, const double *Efield, - double radius, double distance, double *transportBuffer, - double *diffusionVelocity) final; - void ComputeSourceTransportProperties(const Vector &state, const Vector &Up, const DenseMatrix &gradUp, - const Vector &Efield, double distance, Vector &globalTransport, - DenseMatrix &speciesTransport, DenseMatrix &diffusionVelocity, - Vector &n_sp) final; - MFEM_HOST_DEVICE void ComputeSourceTransportProperties(const double *state, const double *Up, const double *gradUp, - const double *Efield, double distance, double *globalTransport, - double *speciesTransport, double *diffusionVelocity, - double *n_sp) final; - - MFEM_HOST_DEVICE void GetViscosities(const double *conserved, const double *primitive, double *visc) final; - MFEM_HOST_DEVICE void GetViscosities(const double *conserved, const double *primitive, const double *gradUp, - double radius, double distance, double *visc) final; + void ComputeFluxTransportProperties(const Vector& state, const DenseMatrix& gradUp, const Vector& Efield, + double radius, double distance, Vector& transportBuffer, + DenseMatrix& diffusionVelocity) final; + MFEM_HOST_DEVICE void ComputeFluxTransportProperties(const double* state, const double* gradUp, const double* Efield, + double radius, double distance, double* transportBuffer, + double* diffusionVelocity) final; + void ComputeSourceTransportProperties(const Vector& state, const Vector& Up, const DenseMatrix& gradUp, + const Vector& Efield, double distance, Vector& globalTransport, + DenseMatrix& speciesTransport, DenseMatrix& diffusionVelocity, + Vector& n_sp) final; + MFEM_HOST_DEVICE void ComputeSourceTransportProperties(const double* state, const double* Up, const double* gradUp, + const double* Efield, double distance, double* globalTransport, + double* speciesTransport, double* diffusionVelocity, + double* n_sp) final; + + MFEM_HOST_DEVICE void GetViscosities(const double* conserved, const double* primitive, double* visc) final; + MFEM_HOST_DEVICE void GetViscosities(const double* conserved, const double* primitive, const double* gradUp, + double radius, double distance, double* visc) final; }; -MFEM_HOST_DEVICE inline void MixingLengthTransport::GetViscosities(const double *conserved, const double *primitive, - double *visc) { +MFEM_HOST_DEVICE inline void MixingLengthTransport::GetViscosities(const double* conserved, const double* primitive, + double* visc) { assert(false); } -MFEM_HOST_DEVICE inline void MixingLengthTransport::GetViscosities(const double *conserved, const double *primitive, - const double *gradUp, double radius, double distance, - double *visc) { +MFEM_HOST_DEVICE inline void MixingLengthTransport::GetViscosities(const double* conserved, const double* primitive, + const double* gradUp, double radius, double distance, + double* visc) { molecular_transport_->GetViscosities(conserved, primitive, visc); const double rho = conserved[0]; diff --git a/src/outletBC.cpp b/src/outletBC.cpp index aded15aa..a8fd3a88 100644 --- a/src/outletBC.cpp +++ b/src/outletBC.cpp @@ -35,10 +35,10 @@ #include "riemann_solver.hpp" // TODO(kevin): non-reflecting BC for plasma. -OutletBC::OutletBC(MPI_Groups *_groupsMPI, Equations _eqSystem, RiemannSolverTPS *_rsolver, GasMixture *_mixture, - GasMixture *d_mixture, ParFiniteElementSpace *_vfes, IntegrationRules *_intRules, double &_dt, +OutletBC::OutletBC(MPI_Groups* _groupsMPI, Equations _eqSystem, RiemannSolverTPS* _rsolver, GasMixture* _mixture, + GasMixture* d_mixture, ParFiniteElementSpace* _vfes, IntegrationRules* _intRules, double& _dt, const int _dim, const int _num_equation, int _patchNumber, double _refLength, OutletType _bcType, - const Array &_inputData, const int &_maxIntPoints, const int &_maxDofs, bool axisym) + const Array& _inputData, const int& _maxIntPoints, const int& _maxDofs, bool axisym) : BoundaryCondition(_rsolver, _mixture, _eqSystem, _vfes, _intRules, _dt, _dim, _num_equation, _patchNumber, _refLength, axisym), groupsMPI(_groupsMPI), @@ -96,7 +96,7 @@ OutletBC::OutletBC(MPI_Groups *_groupsMPI, Equations _eqSystem, RiemannSolverTPS for (int bel = 0; bel < vfes->GetNBE(); bel++) { int attr = vfes->GetBdrAttribute(bel); if (attr == patchNumber) { - FaceElementTransformations *Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); + FaceElementTransformations* Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); Array dofs; vfes->GetElementVDofs(Tr->Elem1No, dofs); @@ -244,7 +244,7 @@ void OutletBC::initBdrElemsShape() { for (int bel = 0; bel < vfes->GetNBE(); bel++) { int attr = vfes->GetBdrAttribute(bel); if (attr == patchNumber) { - FaceElementTransformations *Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); + FaceElementTransformations* Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); int elDofs = vfes->GetFE(Tr->Elem1No)->GetDof(); Array dofs; vfes->GetElementVDofs(Tr->Elem1No, dofs); @@ -304,8 +304,8 @@ void OutletBC::initBCs() { } } -void OutletBC::computeBdrFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - double time, double distance, Vector &bdrFlux) { +void OutletBC::computeBdrFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + double time, double distance, Vector& bdrFlux) { switch (outletType_) { case SUB_P: subsonicReflectingPressure(normal, stateIn, bdrFlux); @@ -342,16 +342,16 @@ void OutletBC::computeParallelArea() { } } -void OutletBC::updateMean_gpu(ParGridFunction *Up, Vector &localMeanUp, const int num_equation, const int numBdrElems, - const int totDofs, Vector &bdrUp, Array &bdrElemsQ, Array &bdrDofs, - Vector &bdrShape, const int &maxIntPoints, const int &maxDofs) { +void OutletBC::updateMean_gpu(ParGridFunction* Up, Vector& localMeanUp, const int num_equation, const int numBdrElems, + const int totDofs, Vector& bdrUp, Array& bdrElemsQ, Array& bdrDofs, + Vector& bdrShape, const int& maxIntPoints, const int& maxDofs) { #ifdef _GPU_ - const double *d_Up = Up->Read(); - double *d_localMeanUp = localMeanUp.Write(); - double *d_bdrUp = bdrUp.Write(); + const double* d_Up = Up->Read(); + double* d_localMeanUp = localMeanUp.Write(); + double* d_bdrUp = bdrUp.Write(); auto d_bdrElemQ = bdrElemsQ.Read(); auto d_bdrDofs = bdrDofs.Read(); - const double *d_bdrShape = bdrShape.Read(); + const double* d_bdrShape = bdrShape.Read(); int groupAveraging = numBdrElems; if (groupAveraging % 2 != 0) groupAveraging++; @@ -417,7 +417,7 @@ void OutletBC::updateMean_gpu(ParGridFunction *Up, Vector &localMeanUp, const in #endif } -void OutletBC::initBoundaryU(ParGridFunction *Up) { +void OutletBC::initBoundaryU(ParGridFunction* Up) { Vector elUp; elUp.UseDevice(false); Vector shape; @@ -429,7 +429,7 @@ void OutletBC::initBoundaryU(ParGridFunction *Up) { for (int bel = 0; bel < vfes->GetNBE(); bel++) { int attr = vfes->GetBdrAttribute(bel); if (attr == patchNumber) { - FaceElementTransformations *Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); + FaceElementTransformations* Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); int elDofs = vfes->GetFE(Tr->Elem1No)->GetDof(); @@ -467,7 +467,7 @@ void OutletBC::initBoundaryU(ParGridFunction *Up) { boundaryU.ReadWrite(); } -void OutletBC::updateMean(IntegrationRules *intRules, ParGridFunction *Up) { +void OutletBC::updateMean(IntegrationRules* intRules, ParGridFunction* Up) { if (outletType_ == SUB_P) return; bdrN = 0; @@ -493,7 +493,7 @@ void OutletBC::updateMean(IntegrationRules *intRules, ParGridFunction *Up) { for (int bel = 0; bel < vfes->GetNBE(); bel++) { int attr = vfes->GetBdrAttribute(bel); if (attr == patchNumber) { - FaceElementTransformations *Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); + FaceElementTransformations* Tr = vfes->GetMesh()->GetBdrFaceTransformations(bel); int elDofs = vfes->GetFE(Tr->Elem1No)->GetDof(); @@ -530,11 +530,11 @@ void OutletBC::updateMean(IntegrationRules *intRules, ParGridFunction *Up) { } #endif - double *h_localMeanUp = localMeanUp.HostReadWrite(); + double* h_localMeanUp = localMeanUp.HostReadWrite(); int totNbdr = boundaryU.Size() / num_equation_; h_localMeanUp[num_equation_] = static_cast(totNbdr); - double *h_sum = glob_sum.HostWrite(); + double* h_sum = glob_sum.HostWrite(); MPI_Allreduce(h_localMeanUp, h_sum, num_equation_ + 1, MPI_DOUBLE, MPI_SUM, groupsMPI->getComm(patchNumber)); BoundaryCondition::copyValues(glob_sum, meanUp, 1. / h_sum[num_equation_]); @@ -560,17 +560,17 @@ void OutletBC::updateMean(IntegrationRules *intRules, ParGridFunction *Up) { } } -void OutletBC::integrationBC(Vector &y, const Vector &x, const elementIndexingData &elem_index_data, - ParGridFunction *Up, ParGridFunction *gradUp, - const boundaryFaceIntegrationData &boundary_face_data, const int &maxIntPoints, - const int &maxDofs) { +void OutletBC::integrationBC(Vector& y, const Vector& x, const elementIndexingData& elem_index_data, + ParGridFunction* Up, ParGridFunction* gradUp, + const boundaryFaceIntegrationData& boundary_face_data, const int& maxIntPoints, + const int& maxDofs) { interpOutlet_gpu(x, elem_index_data, Up, gradUp, boundary_face_data, listElems, offsetsBoundaryU); integrateOutlets_gpu(y, // output x, elem_index_data, boundary_face_data, listElems, offsetsBoundaryU); } -void OutletBC::subsonicNonReflectingPressure(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector &bdrFlux) { +void OutletBC::subsonicNonReflectingPressure(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector& bdrFlux) { const double gamma = mixture->GetSpecificHeatRatio(); Vector unitNorm = normal; @@ -728,7 +728,7 @@ void OutletBC::subsonicNonReflectingPressure(Vector &normal, Vector &stateIn, De } // This is more or less right formulation even for two-temperature case. -void OutletBC::subsonicReflectingPressure(Vector &normal, Vector &stateIn, Vector &bdrFlux) { +void OutletBC::subsonicReflectingPressure(Vector& normal, Vector& stateIn, Vector& bdrFlux) { Vector state2(num_equation_); mixture->modifyEnergyForPressure(stateIn, state2, inputState[0]); @@ -736,7 +736,7 @@ void OutletBC::subsonicReflectingPressure(Vector &normal, Vector &stateIn, Vecto rsolver->Eval(stateIn, state2, normal, bdrFlux, true); } -void OutletBC::subsonicNonRefMassFlow(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector &bdrFlux) { +void OutletBC::subsonicNonRefMassFlow(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector& bdrFlux) { const double gamma = mixture->GetSpecificHeatRatio(); Vector unitNorm = normal; @@ -891,7 +891,7 @@ void OutletBC::subsonicNonRefMassFlow(Vector &normal, Vector &stateIn, DenseMatr rsolver->Eval(stateIn, state2, normal, bdrFlux, true); } -void OutletBC::subsonicNonRefPWMassFlow(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector &bdrFlux) { +void OutletBC::subsonicNonRefPWMassFlow(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector& bdrFlux) { const double gamma = mixture->GetSpecificHeatRatio(); Vector unitNorm = normal; @@ -1026,20 +1026,20 @@ void OutletBC::subsonicNonRefPWMassFlow(Vector &normal, Vector &stateIn, DenseMa rsolver->Eval(stateIn, state2, normal, bdrFlux, true); } -void OutletBC::integrateOutlets_gpu(Vector &y, const Vector &x, const elementIndexingData &elem_index_data, - const boundaryFaceIntegrationData &boundary_face_data, Array &listElems, - Array &offsetsBoundaryU) { +void OutletBC::integrateOutlets_gpu(Vector& y, const Vector& x, const elementIndexingData& elem_index_data, + const boundaryFaceIntegrationData& boundary_face_data, Array& listElems, + Array& offsetsBoundaryU) { #ifdef _GPU_ - double *d_y = y.ReadWrite(); - const int *d_elem_dofs_list = elem_index_data.dofs_list.Read(); - const int *d_elem_dof_off = elem_index_data.dof_offset.Read(); - const int *d_elem_dof_num = elem_index_data.dof_number.Read(); - - const double *d_face_shape = boundary_face_data.shape.Read(); - const double *d_weight = boundary_face_data.quad_weight.Read(); - const int *d_face_el = boundary_face_data.el.Read(); - const int *d_face_num_quad = boundary_face_data.num_quad.Read(); - const int *d_listElems = listElems.Read(); + double* d_y = y.ReadWrite(); + const int* d_elem_dofs_list = elem_index_data.dofs_list.Read(); + const int* d_elem_dof_off = elem_index_data.dof_offset.Read(); + const int* d_elem_dof_num = elem_index_data.dof_number.Read(); + + const double* d_face_shape = boundary_face_data.shape.Read(); + const double* d_weight = boundary_face_data.quad_weight.Read(); + const int* d_face_el = boundary_face_data.el.Read(); + const int* d_face_num_quad = boundary_face_data.num_quad.Read(); + const int* d_listElems = listElems.Read(); // const int *d_offsetBoundaryU = offsetsBoundaryU.Read(); const int totDofs = x.Size() / num_equation_; @@ -1049,7 +1049,7 @@ void OutletBC::integrateOutlets_gpu(Vector &y, const Vector &x, const elementInd const int maxIntPoints = maxIntPoints_; const int maxDofs = maxDofs_; - const double *d_flux = face_flux_.Read(); + const double* d_flux = face_flux_.Read(); // clang-format off MFEM_FORALL_2D(n, numBdrElem, maxDofs, 1, 1, @@ -1096,31 +1096,31 @@ void OutletBC::integrateOutlets_gpu(Vector &y, const Vector &x, const elementInd // clang-format on } -void OutletBC::interpOutlet_gpu(const mfem::Vector &x, const elementIndexingData &elem_index_data, - mfem::ParGridFunction *Up, mfem::ParGridFunction *gradUp, - const boundaryFaceIntegrationData &boundary_face_data, Array &listElems, - Array &offsetsBoundaryU) { +void OutletBC::interpOutlet_gpu(const mfem::Vector& x, const elementIndexingData& elem_index_data, + mfem::ParGridFunction* Up, mfem::ParGridFunction* gradUp, + const boundaryFaceIntegrationData& boundary_face_data, Array& listElems, + Array& offsetsBoundaryU) { #ifdef _GPU_ - const double *d_inputState = inputState.Read(); - const double *d_U = x.Read(); - const double *d_gradUp = gradUp->Read(); - const int *d_elem_dofs_list = elem_index_data.dofs_list.Read(); - const int *d_elem_dof_off = elem_index_data.dof_offset.Read(); - const int *d_elem_dof_num = elem_index_data.dof_number.Read(); - const double *d_face_shape = boundary_face_data.shape.Read(); - const double *d_normal = boundary_face_data.normal.Read(); - const double *d_xyz = boundary_face_data.xyz.Read(); - const int *d_face_el = boundary_face_data.el.Read(); - const int *d_face_num_quad = boundary_face_data.num_quad.Read(); - const int *d_listElems = listElems.Read(); - const int *d_offsetBoundaryU = offsetsBoundaryU.Read(); - const double *d_meanUp = meanUp.Read(); - double *d_boundaryU = boundaryU.ReadWrite(); - const double *d_tang1 = tangent1.Read(); - const double *d_tang2 = tangent2.Read(); - const double *d_inv = inverseNorm2cartesian.Read(); - - double *d_flux = face_flux_.Write(); + const double* d_inputState = inputState.Read(); + const double* d_U = x.Read(); + const double* d_gradUp = gradUp->Read(); + const int* d_elem_dofs_list = elem_index_data.dofs_list.Read(); + const int* d_elem_dof_off = elem_index_data.dof_offset.Read(); + const int* d_elem_dof_num = elem_index_data.dof_number.Read(); + const double* d_face_shape = boundary_face_data.shape.Read(); + const double* d_normal = boundary_face_data.normal.Read(); + const double* d_xyz = boundary_face_data.xyz.Read(); + const int* d_face_el = boundary_face_data.el.Read(); + const int* d_face_num_quad = boundary_face_data.num_quad.Read(); + const int* d_listElems = listElems.Read(); + const int* d_offsetBoundaryU = offsetsBoundaryU.Read(); + const double* d_meanUp = meanUp.Read(); + double* d_boundaryU = boundaryU.ReadWrite(); + const double* d_tang1 = tangent1.Read(); + const double* d_tang2 = tangent2.Read(); + const double* d_inv = inverseNorm2cartesian.Read(); + + double* d_flux = face_flux_.Write(); const int totDofs = x.Size() / num_equation_; const int numBdrElem = listElems.Size(); @@ -1148,8 +1148,8 @@ void OutletBC::interpOutlet_gpu(const mfem::Vector &x, const elementIndexingData const int maxDofs = maxDofs_; const int nvel = nvel_; - const RiemannSolverTPS *d_rsolver = rsolver; - GasMixture *d_mix = d_mixture_; + const RiemannSolverTPS* d_rsolver = rsolver; + GasMixture* d_mix = d_mixture_; // MFEM_FORALL(n, numBdrElem, { MFEM_FORALL_2D(n, numBdrElem, maxIntPoints, 1, 1, { diff --git a/src/outletBC.hpp b/src/outletBC.hpp index e81f0f5e..67bdf29d 100644 --- a/src/outletBC.hpp +++ b/src/outletBC.hpp @@ -44,8 +44,8 @@ using namespace mfem; class OutletBC : public BoundaryCondition { private: - MPI_Groups *groupsMPI; - GasMixture *d_mixture_; + MPI_Groups* groupsMPI; + GasMixture* d_mixture_; const OutletType outletType_; @@ -64,8 +64,8 @@ class OutletBC : public BoundaryCondition { Array bdrElemsQ; // element dofs and face num. of integration points Array bdrDofs; // indexes of the D Vector bdrShape; // shape functions evaluated at the integration points - const int &maxIntPoints_; - const int &maxDofs_; + const int& maxIntPoints_; + const int& maxDofs_; // local vector for mean calculation Vector localMeanUp; @@ -82,57 +82,57 @@ class OutletBC : public BoundaryCondition { Vector inverseNorm2cartesian; void initBdrElemsShape(); - void initBoundaryU(ParGridFunction *Up); + void initBoundaryU(ParGridFunction* Up); - void subsonicReflectingPressure(Vector &normal, Vector &stateIn, Vector &bdrFlux); + void subsonicReflectingPressure(Vector& normal, Vector& stateIn, Vector& bdrFlux); - void subsonicNonReflectingPressure(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector &bdrFlux); + void subsonicNonReflectingPressure(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector& bdrFlux); - void subsonicNonRefMassFlow(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector &bdrFlux); + void subsonicNonRefMassFlow(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector& bdrFlux); - void subsonicNonRefPWMassFlow(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector &bdrFlux); + void subsonicNonRefPWMassFlow(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector& bdrFlux); - virtual void updateMean(IntegrationRules *intRules, ParGridFunction *Up); + virtual void updateMean(IntegrationRules* intRules, ParGridFunction* Up); void computeParallelArea(); public: - OutletBC(MPI_Groups *_groupsMPI, Equations _eqSystem, RiemannSolverTPS *rsolver_, GasMixture *mixture, - GasMixture *d_mixture, ParFiniteElementSpace *_vfes, IntegrationRules *_intRules, double &_dt, + OutletBC(MPI_Groups* _groupsMPI, Equations _eqSystem, RiemannSolverTPS* rsolver_, GasMixture* mixture, + GasMixture* d_mixture, ParFiniteElementSpace* _vfes, IntegrationRules* _intRules, double& _dt, const int _dim, const int _num_equation, int _patchNumber, double _refLength, OutletType _bcType, - const Array &_inputData, const int &_maxIntPoints, const int &maxDofs, bool axisym); + const Array& _inputData, const int& _maxIntPoints, const int& maxDofs, bool axisym); ~OutletBC(); - void computeBdrFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - double time, double distance, Vector &bdrFlux); + void computeBdrFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + double time, double distance, Vector& bdrFlux); virtual void initBCs(); - virtual void integrationBC(Vector &y, // output - const Vector &x, const elementIndexingData &elem_index_data, ParGridFunction *Up, - ParGridFunction *gradUp, const boundaryFaceIntegrationData &boundary_face_data, - const int &maxIntPoints, const int &maxDofs); + virtual void integrationBC(Vector& y, // output + const Vector& x, const elementIndexingData& elem_index_data, ParGridFunction* Up, + ParGridFunction* gradUp, const boundaryFaceIntegrationData& boundary_face_data, + const int& maxIntPoints, const int& maxDofs); - static void updateMean_gpu(ParGridFunction *Up, Vector &localMeanUp, const int _num_equation, const int numBdrElems, - const int totalDofs, Vector &bdrUp, Array &bdrElemsQ, Array &bdrDofs, - Vector &bdrShape, const int &maxIntPoints, const int &maxDofs); + static void updateMean_gpu(ParGridFunction* Up, Vector& localMeanUp, const int _num_equation, const int numBdrElems, + const int totalDofs, Vector& bdrUp, Array& bdrElemsQ, Array& bdrDofs, + Vector& bdrShape, const int& maxIntPoints, const int& maxDofs); // functions for BC integration on GPU - void integrateOutlets_gpu(Vector &y, // output - const Vector &x, const elementIndexingData &elem_index_data, - const boundaryFaceIntegrationData &boundary_face_data, Array &listElems, - Array &offsetBoundaryU); + void integrateOutlets_gpu(Vector& y, // output + const Vector& x, const elementIndexingData& elem_index_data, + const boundaryFaceIntegrationData& boundary_face_data, Array& listElems, + Array& offsetBoundaryU); - void interpOutlet_gpu(const Vector &x, const elementIndexingData &elem_index_data, ParGridFunction *Up, - ParGridFunction *gradUp, const boundaryFaceIntegrationData &boundary_face_data, - Array &listElems, Array &offsetsBoundaryU); + void interpOutlet_gpu(const Vector& x, const elementIndexingData& elem_index_data, ParGridFunction* Up, + ParGridFunction* gradUp, const boundaryFaceIntegrationData& boundary_face_data, + Array& listElems, Array& offsetsBoundaryU); #ifdef _GPU_ // GPU functions - static MFEM_HOST_DEVICE void computeSubPressure(const double *u1, double *u2, const double *nor, const double &press, - const double &gamma, const double &Rg, const int &dim, - const int &num_equation, const WorkingFluid &fluid, - const Equations &eqSystem, const int &thrd, const int &maxThreads) { + static MFEM_HOST_DEVICE void computeSubPressure(const double* u1, double* u2, const double* nor, const double& press, + const double& gamma, const double& Rg, const int& dim, + const int& num_equation, const WorkingFluid& fluid, + const Equations& eqSystem, const int& thrd, const int& maxThreads) { if (fluid == WorkingFluid::DRY_AIR) { DryAir::modifyEnergyForPressure_gpu(u1, u2, press, gamma, Rg, num_equation, dim, thrd, maxThreads); } @@ -147,10 +147,10 @@ class OutletBC : public BoundaryCondition { // } } - static MFEM_HOST_DEVICE void computeSubPressure_gpu_serial(const double *u1, double *u2, const double *nor, - const double &press, const double &gamma, const double &Rg, - const int &dim, const int &num_equation, - const WorkingFluid &fluid) { + static MFEM_HOST_DEVICE void computeSubPressure_gpu_serial(const double* u1, double* u2, const double* nor, + const double& press, const double& gamma, const double& Rg, + const int& dim, const int& num_equation, + const WorkingFluid& fluid) { if (fluid == WorkingFluid::DRY_AIR) { DryAir::modifyEnergyForPressure_gpu_serial(u1, u2, press, gamma, Rg, num_equation, dim); } @@ -165,12 +165,12 @@ class OutletBC : public BoundaryCondition { // } } - static MFEM_HOST_DEVICE void computeNRSubPress(const int &thrd, const int &n, const double *u1, const double *gradUp, - const double *meanUp, const double &dt, double *u2, double *boundaryU, - const double *inputState, const double *nor, const double *d_tang1, - const double *d_tang2, const double *d_inv, const double &refLength, - const double &gamma, const double &Rg, const int &elDof, - const int &dim, const int &num_equation, const Equations &eqSystem) { + static MFEM_HOST_DEVICE void computeNRSubPress(const int& thrd, const int& n, const double* u1, const double* gradUp, + const double* meanUp, const double& dt, double* u2, double* boundaryU, + const double* inputState, const double* nor, const double* d_tang1, + const double* d_tang2, const double* d_inv, const double& refLength, + const double& gamma, const double& Rg, const int& elDof, + const int& dim, const int& num_equation, const Equations& eqSystem) { MFEM_SHARED double unitNorm[3], meanVel[3], normGrad[20]; MFEM_SHARED double mod; MFEM_SHARED double speedSound, meanK, dpdn; @@ -312,10 +312,10 @@ class OutletBC : public BoundaryCondition { } static MFEM_HOST_DEVICE void computeNRSubPress_serial( - const int &n, const double *u1, const double *gradUp, const double *meanUp, const double &dt, double *u2, - double *boundaryU, const double *inputState, const double *nor, const double *d_tang1, const double *d_tang2, - const double *d_inv, const double &refLength, const double &gamma, const double &Rg, const int &elDof, - const int &dim, const int &num_equation, const Equations &eqSystem) { + const int& n, const double* u1, const double* gradUp, const double* meanUp, const double& dt, double* u2, + double* boundaryU, const double* inputState, const double* nor, const double* d_tang1, const double* d_tang2, + const double* d_inv, const double& refLength, const double& gamma, const double& Rg, const int& elDof, + const int& dim, const int& num_equation, const Equations& eqSystem) { double unitNorm[3], meanVel[3], normGrad[20]; double mod; double speedSound, meanK, dpdn; @@ -434,10 +434,10 @@ class OutletBC : public BoundaryCondition { } static MFEM_HOST_DEVICE void computeNRSubMassFlow( - const int &thrd, const int &n, const double *u1, const double *gradUp, const double *meanUp, const double &dt, - double *u2, double *boundaryU, const double *inputState, const double *nor, const double *d_tang1, - const double *d_tang2, const double *d_inv, const double &refLength, const double &area, const double &gamma, - const double &Rg, const int &elDof, const int &dim, const int &num_equation, const Equations &eqSystem) { + const int& thrd, const int& n, const double* u1, const double* gradUp, const double* meanUp, const double& dt, + double* u2, double* boundaryU, const double* inputState, const double* nor, const double* d_tang1, + const double* d_tang2, const double* d_inv, const double& refLength, const double& area, const double& gamma, + const double& Rg, const int& elDof, const int& dim, const int& num_equation, const Equations& eqSystem) { MFEM_SHARED double unitNorm[3], meanVel[3], normGrad[20]; MFEM_SHARED double mod; MFEM_SHARED double speedSound, meanK, dpdn; @@ -580,10 +580,10 @@ class OutletBC : public BoundaryCondition { } static MFEM_HOST_DEVICE void computeNRSubMassFlow_serial( - const int &n, const double *u1, const double *gradUp, const double *meanUp, const double &dt, double *u2, - double *boundaryU, const double *inputState, const double *nor, const double *d_tang1, const double *d_tang2, - const double *d_inv, const double &refLength, const double &area, const double &gamma, const double &Rg, - const int &elDof, const int &dim, const int &num_equation, const Equations &eqSystem) { + const int& n, const double* u1, const double* gradUp, const double* meanUp, const double& dt, double* u2, + double* boundaryU, const double* inputState, const double* nor, const double* d_tang1, const double* d_tang2, + const double* d_inv, const double& refLength, const double& area, const double& gamma, const double& Rg, + const int& elDof, const int& dim, const int& num_equation, const Equations& eqSystem) { double unitNorm[3], meanVel[3], normGrad[20]; double mod; double speedSound, meanK, dpdn; @@ -705,13 +705,13 @@ class OutletBC : public BoundaryCondition { } } - static MFEM_HOST_DEVICE void computeNR_PW_SubMF(const int &thrd, const int &n, const double *u1, const double *gradUp, - const double *meanUp, const double &dt, double *u2, double *boundaryU, - const double *inputState, const double *nor, const double *d_tang1, - const double *d_tang2, const double *d_inv, const double &refLength, - const double &area, const double &gamma, const double &Rg, - const int &elDof, const int &dim, const int &num_equation, - const Equations &eqSystem) { + static MFEM_HOST_DEVICE void computeNR_PW_SubMF(const int& thrd, const int& n, const double* u1, const double* gradUp, + const double* meanUp, const double& dt, double* u2, double* boundaryU, + const double* inputState, const double* nor, const double* d_tang1, + const double* d_tang2, const double* d_inv, const double& refLength, + const double& area, const double& gamma, const double& Rg, + const int& elDof, const int& dim, const int& num_equation, + const Equations& eqSystem) { MFEM_SHARED double unitNorm[3], meanVel[3], normGrad[20]; MFEM_SHARED double mod; MFEM_SHARED double speedSound, meanK, dpdn; diff --git a/src/quasimagnetostatic.cpp b/src/quasimagnetostatic.cpp index a27a4d27..ecfb45ce 100644 --- a/src/quasimagnetostatic.cpp +++ b/src/quasimagnetostatic.cpp @@ -43,9 +43,9 @@ using namespace mfem; using namespace mfem::common; static Vector axis(3); -void JFun(const Vector &x, Vector &f); +void JFun(const Vector& x, Vector& f); -QuasiMagnetostaticSolverBase::QuasiMagnetostaticSolverBase(ElectromagneticOptions em_opts, TPS::Tps *tps) +QuasiMagnetostaticSolverBase::QuasiMagnetostaticSolverBase(ElectromagneticOptions em_opts, TPS::Tps* tps) : em_opts_(em_opts), offsets_(3), storeE_(false), Ereal_(NULL), Eimag_(NULL) { MPI_Comm_size(tps->getTPSCommWorld(), &nprocs_); MPI_Comm_rank(tps->getTPSCommWorld(), &rank_); @@ -69,7 +69,7 @@ QuasiMagnetostaticSolverBase::QuasiMagnetostaticSolverBase(ElectromagneticOption joule_heating_ = NULL; } -double JouleHeatingCoefficient3D::Eval(ElementTransformation &T, const IntegrationPoint &ip) { +double JouleHeatingCoefficient3D::Eval(ElementTransformation& T, const IntegrationPoint& ip) { Vector Er, Ei; double sig; Ereal_.GetVectorValue(T, ip, Er); @@ -78,7 +78,7 @@ double JouleHeatingCoefficient3D::Eval(ElementTransformation &T, const Integrati return sig * (Er * Er + Ei * Ei); } -QuasiMagnetostaticSolver3D::QuasiMagnetostaticSolver3D(ElectromagneticOptions em_opts, TPS::Tps *tps) +QuasiMagnetostaticSolver3D::QuasiMagnetostaticSolver3D(ElectromagneticOptions em_opts, TPS::Tps* tps) : QuasiMagnetostaticSolverBase(em_opts, tps) { hcurl_ = NULL; h1_ = NULL; @@ -142,7 +142,7 @@ void QuasiMagnetostaticSolver3D::initialize() { //----------------------------------------------------- // 1a) Read the serial mesh (on each mpi rank) - Mesh *mesh = new Mesh(em_opts_.mesh_file.c_str(), 1, 1); + Mesh* mesh = new Mesh(em_opts_.mesh_file.c_str(), 1, 1); dim_ = mesh->Dimension(); if (dim_ != 3) { if (verbose) { @@ -222,7 +222,7 @@ void QuasiMagnetostaticSolver3D::initialize() { joule_heating_ = new ParGridFunction(jh_space_); *joule_heating_ = 0.0; - if (rank0_) std::cout << "QM3D initialize okay..." << endl; + if (rank0_) std::cout << "QM3D initialize okay..." << endl; } void QuasiMagnetostaticSolver3D::InitializeCurrent() { @@ -278,13 +278,13 @@ void QuasiMagnetostaticSolver3D::InitializeCurrent() { PWConstCoefficient J0coef(J0); VectorFunctionCoefficient current(dim_, JFun, &J0coef); - + // 2) Build a discretely divergence-free approximation of the source // current that lives in the Nedelec FE space defined in // Initialize() - ParGridFunction *Jorig = new ParGridFunction(Aspace_); - ParGridFunction *Jproj = new ParGridFunction(Aspace_); - + ParGridFunction* Jorig = new ParGridFunction(Aspace_); + ParGridFunction* Jproj = new ParGridFunction(Aspace_); + r_ = new ParLinearForm(Aspace_); // This call (i.e., GlobalProjectDiscCoefficient) replaces the @@ -306,7 +306,7 @@ void QuasiMagnetostaticSolver3D::InitializeCurrent() { delete Jorig; // 3) Multiply by the mass matrix to get the RHS vector - ParBilinearForm *mass = new ParBilinearForm(Aspace_); + ParBilinearForm* mass = new ParBilinearForm(Aspace_); mass->AddDomainIntegrator(new VectorFEMassIntegrator); mass->Assemble(); mass->Finalize(); @@ -317,7 +317,7 @@ void QuasiMagnetostaticSolver3D::InitializeCurrent() { delete Jproj; current_initialized_ = true; - if (rank0_) std::cout << "InitializeCurrent okay..." << endl; + if (rank0_) std::cout << "InitializeCurrent okay..." << endl; } // query solver-specific runtime controls @@ -420,8 +420,8 @@ void QuasiMagnetostaticSolver3D::solveStep() { OperatorPtr Koffd; Kconductivity->FormSystemMatrix(ess_bdr_tdofs_, Koffd); - HypreParMatrix *Kdiag_mat = Kdiag.As(); - HypreParMatrix *Koffd_mat = Koffd.As(); + HypreParMatrix* Kdiag_mat = Kdiag.As(); + HypreParMatrix* Koffd_mat = Koffd.As(); Koffd_mat->EliminateRows(ess_bdr_tdofs_); @@ -488,7 +488,7 @@ void QuasiMagnetostaticSolver3D::solveStep() { if (Bimag_ == NULL) Bimag_ = new ParGridFunction(Bspace_); *Breal_ = 0; - ParDiscreteLinearOperator *curl = new ParDiscreteLinearOperator(Aspace_, Bspace_); + ParDiscreteLinearOperator* curl = new ParDiscreteLinearOperator(Aspace_, Bspace_); curl->AddDomainInterpolator(new CurlInterpolator); curl->Assemble(); curl->Finalize(); @@ -573,8 +573,8 @@ void QuasiMagnetostaticSolver3D::InterpolateToYAxis() const { Array eid; Array ips; - double *Byloc = new double[em_opts_.nBy]; - double *By = new double[em_opts_.nBy]; + double* Byloc = new double[em_opts_.nBy]; + double* By = new double[em_opts_.nBy]; Vector Bpoint(dim_); // Get element numbers and integration points @@ -662,8 +662,8 @@ void QuasiMagnetostaticSolver3D::setStoreE(bool storeE) { } } -double QuasiMagnetostaticSolver3D::elementJouleHeating(const FiniteElement &el, ElementTransformation &Tr, - const Vector &elfun) { +double QuasiMagnetostaticSolver3D::elementJouleHeating(const FiniteElement& el, ElementTransformation& Tr, + const Vector& elfun) { // Get size info const int dof = el.GetDof(); const int nvar = 1; @@ -680,13 +680,13 @@ double QuasiMagnetostaticSolver3D::elementJouleHeating(const FiniteElement &el, // Get quadrature rule const int order = el.GetOrder(); const int intorder = order + 1; - const IntegrationRule *ir = &IntRules.Get(el.GetGeomType(), intorder); + const IntegrationRule* ir = &IntRules.Get(el.GetGeomType(), intorder); double elem_jh = 0; // for every quadrature point... for (int i = 0; i < ir->GetNPoints(); i++) { - const IntegrationPoint &ip = ir->IntPoint(i); + const IntegrationPoint& ip = ir->IntPoint(i); Tr.SetIntPoint(&ip); // evaluate basis functions @@ -706,7 +706,7 @@ double QuasiMagnetostaticSolver3D::elementJouleHeating(const FiniteElement &el, // this is a problem-specific hack (HACK) double rCyl = 0.028; double x, y, z, dist; - double wgt = 1.0; + double wgt = 1.0; Vector coords(Tr.GetSpaceDim()); Tr.Transform(ip, coords); x = coords[0]; @@ -716,10 +716,9 @@ double QuasiMagnetostaticSolver3D::elementJouleHeating(const FiniteElement &el, z = coords[2]; dist += z * z; } - dist = std::sqrt(dist); - if (dist > rCyl) wgt = 0.0; - elem_jh *= wgt; - + dist = std::sqrt(dist); + if (dist > rCyl) wgt = 0.0; + elem_jh *= wgt; } return elem_jh; @@ -727,7 +726,7 @@ double QuasiMagnetostaticSolver3D::elementJouleHeating(const FiniteElement &el, double QuasiMagnetostaticSolver3D::totalJouleHeating() { const int NE = pmesh_->GetNE(); - const ParFiniteElementSpace *fes = jh_space_; + const ParFiniteElementSpace* fes = jh_space_; double int_jh = 0; @@ -736,10 +735,10 @@ double QuasiMagnetostaticSolver3D::totalJouleHeating() { // loop over elements on this mpi rank and integrate joule heating for (int ielem = 0; ielem < NE; ielem++) { - const FiniteElement *fe = fes->GetFE(ielem); - ElementTransformation *T = fes->GetElementTransformation(ielem); + const FiniteElement* fe = fes->GetFE(ielem); + ElementTransformation* T = fes->GetElementTransformation(ielem); #if MFEM_VERSION >= 40400 - DofTransformation *doftrans = fes->GetElementVDofs(ielem, vdofs); + DofTransformation* doftrans = fes->GetElementVDofs(ielem, vdofs); joule_heating_->GetSubVector(vdofs, el_x); if (doftrans) { doftrans->InvTransformPrimal(el_x); @@ -750,7 +749,6 @@ double QuasiMagnetostaticSolver3D::totalJouleHeating() { // following bad fields here (el_x has the actual data)... int_jh += elementJouleHeating(*fe, *T, el_x); - } // sum over mpi ranks @@ -760,7 +758,7 @@ double QuasiMagnetostaticSolver3D::totalJouleHeating() { return total_int_jh; } -void JFun(const Vector &x, Vector &J) { +void JFun(const Vector& x, Vector& J) { Vector axx(3); axx(0) = axis(1) * x(2) - axis(2) * x(1); @@ -771,11 +769,11 @@ void JFun(const Vector &x, Vector &J) { J = axx; } -static double radius(const Vector &x) { return x[0]; } +static double radius(const Vector& x) { return x[0]; } -static double oneOverRadius(const Vector &x) { return 1.0 / x[0]; } +static double oneOverRadius(const Vector& x) { return 1.0 / x[0]; } -QuasiMagnetostaticSolverAxiSym::QuasiMagnetostaticSolverAxiSym(ElectromagneticOptions em_opts, TPS::Tps *tps) +QuasiMagnetostaticSolverAxiSym::QuasiMagnetostaticSolverAxiSym(ElectromagneticOptions em_opts, TPS::Tps* tps) : QuasiMagnetostaticSolverBase(em_opts, tps) { h1_ = NULL; Atheta_space_ = NULL; @@ -822,7 +820,7 @@ void QuasiMagnetostaticSolverAxiSym::initialize() { // 1a) Read the serial mesh (on each mpi rank) if (verbose) grvy_printf(ginfo, "Reading EM mesh file: %s\n", em_opts_.mesh_file.c_str()); - Mesh *mesh = new Mesh(em_opts_.mesh_file.c_str(), 1, 1); + Mesh* mesh = new Mesh(em_opts_.mesh_file.c_str(), 1, 1); dim_ = mesh->Dimension(); if (dim_ != 2) { if (verbose) { @@ -1045,8 +1043,8 @@ void QuasiMagnetostaticSolverAxiSym::solveStep() { OperatorPtr Koffd; Kconductivity->FormSystemMatrix(ess_bdr_tdofs_, Koffd); - HypreParMatrix *Kdiag_mat = Kdiag.As(); - HypreParMatrix *Koffd_mat = Koffd.As(); + HypreParMatrix* Kdiag_mat = Kdiag.As(); + HypreParMatrix* Koffd_mat = Koffd.As(); Koffd_mat->EliminateRows(ess_bdr_tdofs_); @@ -1154,8 +1152,8 @@ void QuasiMagnetostaticSolverAxiSym::setStoreE(bool storeE) { } } -double QuasiMagnetostaticSolverAxiSym::elementJouleHeating(const FiniteElement &el, ElementTransformation &Tr, - const Vector &elfun) { +double QuasiMagnetostaticSolverAxiSym::elementJouleHeating(const FiniteElement& el, ElementTransformation& Tr, + const Vector& elfun) { // Get size info const int dof = el.GetDof(); const int dim = el.GetDim(); @@ -1175,13 +1173,13 @@ double QuasiMagnetostaticSolverAxiSym::elementJouleHeating(const FiniteElement & // Get quadrature rule const int order = el.GetOrder(); const int intorder = order + 1; - const IntegrationRule *ir = &IntRules.Get(el.GetGeomType(), intorder); + const IntegrationRule* ir = &IntRules.Get(el.GetGeomType(), intorder); double elem_jh = 0; // for every quadrature point... for (int i = 0; i < ir->GetNPoints(); i++) { - const IntegrationPoint &ip = ir->IntPoint(i); + const IntegrationPoint& ip = ir->IntPoint(i); Tr.SetIntPoint(&ip); // evaluate radius @@ -1208,7 +1206,7 @@ double QuasiMagnetostaticSolverAxiSym::elementJouleHeating(const FiniteElement & double QuasiMagnetostaticSolverAxiSym::totalJouleHeating() { const int NE = pmesh_->GetNE(); - const ParFiniteElementSpace *fes = this->getFESpace(); + const ParFiniteElementSpace* fes = this->getFESpace(); double int_jh = 0; @@ -1217,10 +1215,10 @@ double QuasiMagnetostaticSolverAxiSym::totalJouleHeating() { // loop over elements on this mpi rank and integrate joule heating for (int ielem = 0; ielem < NE; ielem++) { - const FiniteElement *fe = fes->GetFE(ielem); - ElementTransformation *T = fes->GetElementTransformation(ielem); + const FiniteElement* fe = fes->GetFE(ielem); + ElementTransformation* T = fes->GetElementTransformation(ielem); #if MFEM_VERSION >= 40400 - DofTransformation *doftrans = fes->GetElementVDofs(ielem, vdofs); + DofTransformation* doftrans = fes->GetElementVDofs(ielem, vdofs); joule_heating_->GetSubVector(vdofs, el_x); if (doftrans) { doftrans->InvTransformPrimal(el_x); @@ -1264,18 +1262,18 @@ double QuasiMagnetostaticSolverAxiSym::coilCurrent() const { // factor of 2 \pi radius double current = 0; const int NE = pmesh_->GetNE(); - const ParFiniteElementSpace *fes = Atheta_space_; + const ParFiniteElementSpace* fes = Atheta_space_; for (int ielem = 0; ielem < NE; ielem++) { - const FiniteElement *fe = fes->GetFE(ielem); - ElementTransformation *T = fes->GetElementTransformation(ielem); + const FiniteElement* fe = fes->GetFE(ielem); + ElementTransformation* T = fes->GetElementTransformation(ielem); // B/c the current is piecewise constant, first order rule is sufficient const int intorder = 1; - const IntegrationRule *ir = &IntRules.Get(fe->GetGeomType(), intorder); + const IntegrationRule* ir = &IntRules.Get(fe->GetGeomType(), intorder); for (int i = 0; i < ir->GetNPoints(); i++) { - const IntegrationPoint &ip = ir->IntPoint(i); + const IntegrationPoint& ip = ir->IntPoint(i); T->SetIntPoint(&ip); current += ip.weight * T->Weight() * J0coef.Eval(*T, ip); } @@ -1293,11 +1291,11 @@ double QuasiMagnetostaticSolverAxiSym::magneticEnergy() const { const double mu0 = em_opts_.mu0; const int NE = pmesh_->GetNE(); - const ParFiniteElementSpace *fes = Atheta_space_; + const ParFiniteElementSpace* fes = Atheta_space_; for (int ielem = 0; ielem < NE; ielem++) { - const FiniteElement *fe = fes->GetFE(ielem); - ElementTransformation *T = fes->GetElementTransformation(ielem); + const FiniteElement* fe = fes->GetFE(ielem); + ElementTransformation* T = fes->GetElementTransformation(ielem); // Get size info const int dof = fe->GetDof(); @@ -1330,7 +1328,7 @@ double QuasiMagnetostaticSolverAxiSym::magneticEnergy() const { Vector el_Areal; Vector el_Aimag; - DofTransformation *doftrans = fes->GetElementVDofs(ielem, vdofs); + DofTransformation* doftrans = fes->GetElementVDofs(ielem, vdofs); Atheta_real_->GetSubVector(vdofs, el_Areal); if (doftrans) { doftrans->InvTransformPrimal(el_Areal); @@ -1347,11 +1345,11 @@ double QuasiMagnetostaticSolverAxiSym::magneticEnergy() const { // Get quadrature rule const int order = fe->GetOrder(); const int intorder = 2 * order + 1; - const IntegrationRule *ir = &IntRules.Get(fe->GetGeomType(), intorder); + const IntegrationRule* ir = &IntRules.Get(fe->GetGeomType(), intorder); // for every quadrature point... for (int i = 0; i < ir->GetNPoints(); i++) { - const IntegrationPoint &ip = ir->IntPoint(i); + const IntegrationPoint& ip = ir->IntPoint(i); T->SetIntPoint(&ip); // evaluate radius @@ -1374,13 +1372,13 @@ double QuasiMagnetostaticSolverAxiSym::magneticEnergy() const { MultAtB(el_Areal_mat, dshape, Areal_x); MultAtB(el_Aimag_mat, dshape, Aimag_x); - const double *hAr = Areal.HostRead(); - const double *hAi = Aimag.HostRead(); - const double *hAr_x = Areal_x.HostRead(); - const double *hAi_x = Aimag_x.HostRead(); + const double* hAr = Areal.HostRead(); + const double* hAi = Aimag.HostRead(); + const double* hAr_x = Areal_x.HostRead(); + const double* hAi_x = Aimag_x.HostRead(); - double *hBr = Breal.HostWrite(); - double *hBi = Bimag.HostWrite(); + double* hBr = Breal.HostWrite(); + double* hBi = Bimag.HostWrite(); // B = curl(A) hBr[0] = -hAr_x[1]; diff --git a/src/quasimagnetostatic.hpp b/src/quasimagnetostatic.hpp index b32253cc..7cb26612 100644 --- a/src/quasimagnetostatic.hpp +++ b/src/quasimagnetostatic.hpp @@ -53,28 +53,28 @@ class QuasiMagnetostaticSolverBase : public TPS::Solver { ElectromagneticOptions em_opts_; // pointer to parent Tps class - TPS::Tps *tpsP_; + TPS::Tps* tpsP_; - mfem::ParMesh *pmesh_; + mfem::ParMesh* pmesh_; int dim_; int true_size_; Array offsets_; - mfem::ParGridFunction *plasma_conductivity_; - mfem::GridFunctionCoefficient *plasma_conductivity_coef_; + mfem::ParGridFunction* plasma_conductivity_; + mfem::GridFunctionCoefficient* plasma_conductivity_coef_; - mfem::ParGridFunction *joule_heating_; + mfem::ParGridFunction* joule_heating_; bool storeE_; - mfem::ParGridFunction *Ereal_; - mfem::ParGridFunction *Eimag_; + mfem::ParGridFunction* Ereal_; + mfem::ParGridFunction* Eimag_; int rank_; int nprocs_; bool rank0_; public: - QuasiMagnetostaticSolverBase(ElectromagneticOptions em_opts, TPS::Tps *tps); + QuasiMagnetostaticSolverBase(ElectromagneticOptions em_opts, TPS::Tps* tps); virtual ~QuasiMagnetostaticSolverBase() {} /** Initialize current for axisymmetric quasi-magnetostatic problem @@ -83,21 +83,21 @@ class QuasiMagnetostaticSolverBase : public TPS::Solver { */ virtual void InitializeCurrent() = 0; - mfem::ParMesh *getMesh() const override { return pmesh_; } - mfem::ParGridFunction *getPlasmaConductivityGF() { return plasma_conductivity_; } - mfem::ParGridFunction *getJouleHeatingGF() { return joule_heating_; } - mfem::ParGridFunction *getElectricFieldreal() { + mfem::ParMesh* getMesh() const override { return pmesh_; } + mfem::ParGridFunction* getPlasmaConductivityGF() { return plasma_conductivity_; } + mfem::ParGridFunction* getJouleHeatingGF() { return joule_heating_; } + mfem::ParGridFunction* getElectricFieldreal() { assert(storeE_); return Ereal_; } - mfem::ParGridFunction *getElectricFieldimag() { + mfem::ParGridFunction* getElectricFieldimag() { assert(storeE_); return Eimag_; } virtual void setStoreE(bool storeE) = 0; - virtual double elementJouleHeating(const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun) = 0; + virtual double elementJouleHeating(const FiniteElement& el, ElementTransformation& Tr, const Vector& elfun) = 0; virtual double totalJouleHeating() = 0; void scaleJouleHeating(const double val) { (*joule_heating_) *= val; } @@ -129,14 +129,14 @@ class QuasiMagnetostaticSolverBase : public TPS::Solver { */ class JouleHeatingCoefficient3D : public Coefficient { private: - GridFunctionCoefficient &sigma_; - ParGridFunction &Ereal_; - ParGridFunction &Eimag_; + GridFunctionCoefficient& sigma_; + ParGridFunction& Ereal_; + ParGridFunction& Eimag_; public: - JouleHeatingCoefficient3D(GridFunctionCoefficient &sigma, ParGridFunction &Ereal, ParGridFunction &Eimag) + JouleHeatingCoefficient3D(GridFunctionCoefficient& sigma, ParGridFunction& Ereal, ParGridFunction& Eimag) : sigma_(sigma), Ereal_(Ereal), Eimag_(Eimag) {} - virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); + virtual double Eval(ElementTransformation& T, const IntegrationPoint& ip); virtual ~JouleHeatingCoefficient3D() {} }; @@ -149,29 +149,29 @@ class JouleHeatingCoefficient3D : public Coefficient { // class QuasiMagnetostaticSolver3D : public TPS::Solver { class QuasiMagnetostaticSolver3D : public QuasiMagnetostaticSolverBase { protected: - mfem::FiniteElementCollection *hcurl_; - mfem::FiniteElementCollection *h1_; - mfem::FiniteElementCollection *hdiv_; - mfem::FiniteElementCollection *L2_; + mfem::FiniteElementCollection* hcurl_; + mfem::FiniteElementCollection* h1_; + mfem::FiniteElementCollection* hdiv_; + mfem::FiniteElementCollection* L2_; - mfem::ParFiniteElementSpace *Aspace_; - mfem::ParFiniteElementSpace *pspace_; - mfem::ParFiniteElementSpace *Bspace_; - mfem::ParFiniteElementSpace *jh_space_; + mfem::ParFiniteElementSpace* Aspace_; + mfem::ParFiniteElementSpace* pspace_; + mfem::ParFiniteElementSpace* Bspace_; + mfem::ParFiniteElementSpace* jh_space_; mfem::Array ess_bdr_tdofs_; - mfem::ParBilinearForm *K_; - mfem::ParLinearForm *r_; + mfem::ParBilinearForm* K_; + mfem::ParLinearForm* r_; - mfem::common::ParDiscreteGradOperator *grad_; - mfem::common::DivergenceFreeProjector *div_free_; + mfem::common::ParDiscreteGradOperator* grad_; + mfem::common::DivergenceFreeProjector* div_free_; - mfem::ParGridFunction *Areal_; - mfem::ParGridFunction *Aimag_; + mfem::ParGridFunction* Areal_; + mfem::ParGridFunction* Aimag_; - mfem::ParGridFunction *Breal_; - mfem::ParGridFunction *Bimag_; + mfem::ParGridFunction* Breal_; + mfem::ParGridFunction* Bimag_; // mfem::ParGridFunction *plasma_conductivity_; // mfem::GridFunctionCoefficient *plasma_conductivity_coef_; @@ -182,7 +182,7 @@ class QuasiMagnetostaticSolver3D : public QuasiMagnetostaticSolverBase { void InterpolateToYAxis() const; public: - QuasiMagnetostaticSolver3D(ElectromagneticOptions em_opts, TPS::Tps *tps); + QuasiMagnetostaticSolver3D(ElectromagneticOptions em_opts, TPS::Tps* tps); ~QuasiMagnetostaticSolver3D(); /** Initialize quasi-magnetostatic problem @@ -214,10 +214,10 @@ class QuasiMagnetostaticSolver3D : public QuasiMagnetostaticSolverBase { /** Does nothing */ void solveEnd() override; - mfem::ParFiniteElementSpace *getFESpace() const override { return pspace_; } + mfem::ParFiniteElementSpace* getFESpace() const override { return pspace_; } void setStoreE(bool storeE) override; - double elementJouleHeating(const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun) override; + double elementJouleHeating(const FiniteElement& el, ElementTransformation& Tr, const Vector& elfun) override; double totalJouleHeating() override; }; @@ -229,17 +229,17 @@ class QuasiMagnetostaticSolver3D : public QuasiMagnetostaticSolverBase { */ class QuasiMagnetostaticSolverAxiSym : public QuasiMagnetostaticSolverBase { // public TPS::Solver { protected: - mfem::FiniteElementCollection *h1_; + mfem::FiniteElementCollection* h1_; - mfem::ParFiniteElementSpace *Atheta_space_; + mfem::ParFiniteElementSpace* Atheta_space_; mfem::Array ess_bdr_tdofs_; - mfem::ParBilinearForm *K_; - mfem::ParLinearForm *r_; + mfem::ParBilinearForm* K_; + mfem::ParLinearForm* r_; - mfem::ParGridFunction *Atheta_real_; - mfem::ParGridFunction *Atheta_imag_; + mfem::ParGridFunction* Atheta_real_; + mfem::ParGridFunction* Atheta_imag_; bool operator_initialized_; bool current_initialized_; @@ -247,7 +247,7 @@ class QuasiMagnetostaticSolverAxiSym : public QuasiMagnetostaticSolverBase { // void InterpolateToYAxis() const; public: - QuasiMagnetostaticSolverAxiSym(ElectromagneticOptions em_opts, TPS::Tps *tps); + QuasiMagnetostaticSolverAxiSym(ElectromagneticOptions em_opts, TPS::Tps* tps); ~QuasiMagnetostaticSolverAxiSym(); /** Initialize axisymmetric quasi-magnetostatic problem @@ -278,10 +278,10 @@ class QuasiMagnetostaticSolverAxiSym : public QuasiMagnetostaticSolverBase { // /** Does nothing */ void solveEnd() override; - mfem::ParFiniteElementSpace *getFESpace() const override { return Atheta_space_; } + mfem::ParFiniteElementSpace* getFESpace() const override { return Atheta_space_; } void setStoreE(bool storeE) override; - double elementJouleHeating(const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun) override; + double elementJouleHeating(const FiniteElement& el, ElementTransformation& Tr, const Vector& elfun) override; double totalJouleHeating() override; double coilCurrent() const final; diff --git a/src/radiation.cpp b/src/radiation.cpp index cd5fc5f3..de0c596d 100644 --- a/src/radiation.cpp +++ b/src/radiation.cpp @@ -32,7 +32,7 @@ #include "radiation.hpp" -MFEM_HOST_DEVICE NetEmission::NetEmission(const RadiationInput &inputs) +MFEM_HOST_DEVICE NetEmission::NetEmission(const RadiationInput& inputs) : Radiation(), necTable_(LinearTable(inputs.necTableInput)) { assert(inputs.model == NET_EMISSION); assert(inputs.necModel == TABULATED_NEC); diff --git a/src/radiation.hpp b/src/radiation.hpp index 392e4532..caaf726a 100644 --- a/src/radiation.hpp +++ b/src/radiation.hpp @@ -47,7 +47,7 @@ class Radiation { MFEM_HOST_DEVICE virtual ~Radiation() {} // Currently has the minimal format required for NEC model. - MFEM_HOST_DEVICE virtual double computeEnergySink(const double &T_h) { + MFEM_HOST_DEVICE virtual double computeEnergySink(const double& T_h) { printf("computeEnergySink not implemented"); assert(false); return 0; @@ -62,11 +62,11 @@ class NetEmission : public Radiation { LinearTable necTable_; public: - MFEM_HOST_DEVICE NetEmission(const RadiationInput &inputs); + MFEM_HOST_DEVICE NetEmission(const RadiationInput& inputs); MFEM_HOST_DEVICE ~NetEmission(); - MFEM_HOST_DEVICE double computeEnergySink(const double &T_h) override { return -4.0 * PI_ * necTable_.eval(T_h); } + MFEM_HOST_DEVICE double computeEnergySink(const double& T_h) override { return -4.0 * PI_ * necTable_.eval(T_h); } }; #endif // RADIATION_HPP_ diff --git a/src/reactingFlow.cpp b/src/reactingFlow.cpp index 065eb5b6..7085533a 100644 --- a/src/reactingFlow.cpp +++ b/src/reactingFlow.cpp @@ -46,15 +46,15 @@ using namespace mfem; using namespace mfem::common; /// forward declarations -double species_stepLeft(const Vector &coords, double t); -double species_stepRight(const Vector &coords, double t); -double species_uniform(const Vector &coords, double t); -double binaryTest(const Vector &coords, double t); +double species_stepLeft(const Vector& coords, double t); +double species_stepRight(const Vector& coords, double t); +double species_uniform(const Vector& coords, double t); +double binaryTest(const Vector& coords, double t); -static double radius(const Vector &pos) { return pos[0]; } +static double radius(const Vector& pos) { return pos[0]; } static FunctionCoefficient radius_coeff(radius); -static double sigmaTorchStartUp(const Vector &pos) { +static double sigmaTorchStartUp(const Vector& pos) { // const double x = pos[0]; // radial location const double x = std::sqrt(pos[0] * pos[0] + pos[2] * pos[2]); // radial location const double y = pos[1]; // axial location @@ -71,7 +71,7 @@ static double sigmaTorchStartUp(const Vector &pos) { // additions for 3d, this should just use "SetConstantPlasmaConductivity" in equation_of_state.cpp const double z = pos[2]; const double rCyl = 0.029; - //const double rsig = 0.005; // 5mm + // const double rsig = 0.005; // 5mm const double rsig = 0.0075; const double ysig = 0.1; const double y0 = 0.15; // step location @@ -91,9 +91,9 @@ static double sigmaTorchStartUp(const Vector &pos) { return sigma; } -static double sigmaTorchStartUp2D(const Vector &pos) { +static double sigmaTorchStartUp2D(const Vector& pos) { const double x = std::sqrt(pos[0] * pos[0]); // radial location - const double y = pos[1]; // axial location + const double y = pos[1]; // axial location // additions for 3d, this should just use "SetConstantPlasmaConductivity" in equation_of_state.cpp const double rCyl = 0.029; @@ -112,12 +112,11 @@ static double sigmaTorchStartUp2D(const Vector &pos) { return sigma; } - static FunctionCoefficient sigma_start_up(sigmaTorchStartUp); static FunctionCoefficient sigma_start_up_2d(sigmaTorchStartUp2D); -ReactingFlow::ReactingFlow(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalSchemeCoefficients &time_coeff, - ParGridFunction *gridScale, TPS::Tps *tps) +ReactingFlow::ReactingFlow(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalSchemeCoefficients& time_coeff, + ParGridFunction* gridScale, TPS::Tps* tps) : tpsP_(tps), pmesh_(pmesh), dim_(pmesh->Dimension()), time_coeff_(time_coeff) { rank0_ = (pmesh_->GetMyRank() == 0); order_ = loMach_opts->order; @@ -1414,12 +1413,12 @@ void ReactingFlow::initializeSelf() { double Twall; tpsP_->getRequiredInput((basepath + "/temperature").c_str(), Twall); - ConstantCoefficient *Twall_coeff = new ConstantCoefficient(); + ConstantCoefficient* Twall_coeff = new ConstantCoefficient(); Twall_coeff->constant = Twall; AddTempDirichletBC(Twall_coeff, attr_wall); - ConstantCoefficient *Qt_bc_coeff = new ConstantCoefficient(); + ConstantCoefficient* Qt_bc_coeff = new ConstantCoefficient(); Qt_bc_coeff->constant = 0.0; AddQtDirichletBC(Qt_bc_coeff, attr_wall); @@ -1448,9 +1447,8 @@ void ReactingFlow::initializeOperators() { if (dim_ == 3) { sigma_gf_.ProjectCoefficient(sigma_start_up); } else { - sigma_gf_.ProjectCoefficient(sigma_start_up_2d); + sigma_gf_.ProjectCoefficient(sigma_start_up_2d); } - } Array empty; @@ -1459,9 +1457,9 @@ void ReactingFlow::initializeOperators() { // unsteady: p+p [+p] = 2p [3p] // convection: p+p+(p-1) [+p] = 3p-1 [4p-1] // diffusion: (p-1)+(p-1) [+p] = 2p-2 [3p-2] - const IntegrationRule &ir_i = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ + 1); - const IntegrationRule &ir_nli = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 4 * order_); - const IntegrationRule &ir_di = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * order_ - 1); + const IntegrationRule& ir_i = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ + 1); + const IntegrationRule& ir_nli = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 4 * order_); + const IntegrationRule& ir_di = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * order_ - 1); // coefficients for operators cpMix_coeff_ = new GridFunctionCoefficient(&CpMix_gf_); @@ -1553,7 +1551,7 @@ void ReactingFlow::initializeOperators() { } At_form_ = new ParBilinearForm(sfes_); - ConvectionIntegrator *at_blfi; + ConvectionIntegrator* at_blfi; if (axisym_) { at_blfi = new ConvectionIntegrator(*rad_rho_Cp_u_coeff_); } else { @@ -1570,7 +1568,7 @@ void ReactingFlow::initializeOperators() { At_form_->FormSystemMatrix(empty, At_); Ay_form_ = new ParBilinearForm(sfes_); - ConvectionIntegrator *ay_blfi; + ConvectionIntegrator* ay_blfi; if (axisym_) { ay_blfi = new ConvectionIntegrator(*rad_rho_u_coeff_); } else { @@ -1588,7 +1586,7 @@ void ReactingFlow::initializeOperators() { // mass matrix Ms_form_ = new ParBilinearForm(sfes_); - MassIntegrator *ms_blfi; + MassIntegrator* ms_blfi; if (axisym_) { ms_blfi = new MassIntegrator(radius_coeff); } else { @@ -1606,7 +1604,7 @@ void ReactingFlow::initializeOperators() { // mass matrix with rho MsRho_form_ = new ParBilinearForm(sfes_); - MassIntegrator *msrho_blfi; + MassIntegrator* msrho_blfi; if (axisym_) { msrho_blfi = new MassIntegrator(*rad_rho_coeff_); } else { @@ -1624,7 +1622,7 @@ void ReactingFlow::initializeOperators() { // mass matrix with rho and Cp MsRhoCp_form_ = new ParBilinearForm(sfes_); - MassIntegrator *msrhocp_blfi; + MassIntegrator* msrhocp_blfi; if (axisym_) { msrhocp_blfi = new MassIntegrator(*rad_rho_Cp_coeff_); } else { @@ -1642,13 +1640,13 @@ void ReactingFlow::initializeOperators() { // temperature Helmholtz Ht_form_ = new ParBilinearForm(sfes_); - MassIntegrator *hmt_blfi; + MassIntegrator* hmt_blfi; if (axisym_) { hmt_blfi = new MassIntegrator(*rad_rho_Cp_over_dt_coeff_); } else { hmt_blfi = new MassIntegrator(*rhoCp_over_dt_coeff_); } - DiffusionIntegrator *hdt_blfi; + DiffusionIntegrator* hdt_blfi; if (axisym_) { hdt_blfi = new DiffusionIntegrator(*rad_thermal_diff_total_coeff_); } else { @@ -1676,13 +1674,13 @@ void ReactingFlow::initializeOperators() { // species Helmholtz Hy_form_ = new ParBilinearForm(sfes_); - MassIntegrator *hmy_blfi; + MassIntegrator* hmy_blfi; if (axisym_) { hmy_blfi = new MassIntegrator(*rad_rho_over_dt_coeff_); } else { hmy_blfi = new MassIntegrator(*rho_over_dt_coeff_); } - DiffusionIntegrator *hdy_blfi; + DiffusionIntegrator* hdy_blfi; if (axisym_) { hdy_blfi = new DiffusionIntegrator(*rad_species_diff_total_coeff_); } else { @@ -1714,7 +1712,7 @@ void ReactingFlow::initializeOperators() { MsInvPC_ = new OperatorJacobiSmoother(diag_pa, empty); } else { MsInvPC_ = new HypreSmoother(*Ms_.As()); - dynamic_cast(MsInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(MsInvPC_)->SetType(HypreSmoother::Jacobi, 1); } MsInv_ = new CGSolver(sfes_->GetComm()); MsInv_->iterative_mode = false; @@ -1730,7 +1728,7 @@ void ReactingFlow::initializeOperators() { HtInvPC_ = new OperatorJacobiSmoother(diag_pa, temp_ess_tdof_); } else { HtInvPC_ = new HypreSmoother(*Ht_.As()); - dynamic_cast(HtInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(HtInvPC_)->SetType(HypreSmoother::Jacobi, 1); } HtInv_ = new CGSolver(sfes_->GetComm()); @@ -1747,7 +1745,7 @@ void ReactingFlow::initializeOperators() { HyInvPC_ = new OperatorJacobiSmoother(diag_pa, spec_ess_tdof_); } else { HyInvPC_ = new HypreSmoother(*Hy_.As()); - dynamic_cast(HyInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(HyInvPC_)->SetType(HypreSmoother::Jacobi, 1); } HyInv_ = new CGSolver(sfes_->GetComm()); @@ -1760,7 +1758,7 @@ void ReactingFlow::initializeOperators() { // Vector space mass matrix (used in gradient calcs) Mv_form_ = new ParBilinearForm(vfes_); - VectorMassIntegrator *mv_blfi; + VectorMassIntegrator* mv_blfi; if (axisym_) { mv_blfi = new VectorMassIntegrator(radius_coeff); } else { @@ -1783,7 +1781,7 @@ void ReactingFlow::initializeOperators() { Mv_inv_pc_ = new OperatorJacobiSmoother(diag_pa, empty); } else { Mv_inv_pc_ = new HypreSmoother(*Mv_op_.As()); - dynamic_cast(Mv_inv_pc_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(Mv_inv_pc_)->SetType(HypreSmoother::Jacobi, 1); } Mv_inv_ = new CGSolver(vfes_->GetComm()); Mv_inv_->iterative_mode = false; @@ -1796,8 +1794,8 @@ void ReactingFlow::initializeOperators() { // Energy sink/source terms: Joule heating and radiation sink jh_form_ = new ParLinearForm(sfes_); - DomainLFIntegrator *jh_dlfi; - DomainLFIntegrator *rad_dlfi; + DomainLFIntegrator* jh_dlfi; + DomainLFIntegrator* rad_dlfi; if (axisym_) { jh_dlfi = new DomainLFIntegrator(*rad_jh_coeff_); rad_dlfi = new DomainLFIntegrator(*rad_radiation_sink_coeff_); @@ -1814,7 +1812,7 @@ void ReactingFlow::initializeOperators() { // Qt ..................................... Mq_form_ = new ParBilinearForm(sfes_); - MassIntegrator *mq_blfi; + MassIntegrator* mq_blfi; if (axisym_) { mq_blfi = new MassIntegrator(radius_coeff); } else { @@ -1836,7 +1834,7 @@ void ReactingFlow::initializeOperators() { MqInvPC_ = new OperatorJacobiSmoother(diag_pa, empty); } else { MqInvPC_ = new HypreSmoother(*Mq_.As()); - dynamic_cast(MqInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(MqInvPC_)->SetType(HypreSmoother::Jacobi, 1); } MqInv_ = new CGSolver(sfes_->GetComm()); MqInv_->iterative_mode = false; @@ -1847,7 +1845,7 @@ void ReactingFlow::initializeOperators() { MqInv_->SetMaxIter(max_iter_); LQ_form_ = new ParBilinearForm(sfes_); - DiffusionIntegrator *lqd_blfi; + DiffusionIntegrator* lqd_blfi; if (axisym_) { lqd_blfi = new DiffusionIntegrator(*rad_thermal_diff_total_coeff_); } else { @@ -1858,8 +1856,7 @@ void ReactingFlow::initializeOperators() { } LQ_form_->AddDomainIntegrator(lqd_blfi); - - // NO, this is not consistent and will degrade stability + // NO, this is not consistent and will degrade stability // DiffusionIntegrator *slqd_blfi; // if (sw_stab_) { // slqd_blfi = new DiffusionIntegrator(*supg_coeff_); @@ -1868,7 +1865,7 @@ void ReactingFlow::initializeOperators() { // } // LQ_form_->AddDomainIntegrator(slqd_blfi); // } - + if (partial_assembly_) { LQ_form_->SetAssemblyLevel(AssemblyLevel::PARTIAL); } @@ -1876,7 +1873,7 @@ void ReactingFlow::initializeOperators() { LQ_form_->FormSystemMatrix(empty, LQ_); LQ_bdry_ = new ParLinearForm(sfes_); - BoundaryNormalLFIntegrator *lq_bdry_lfi; + BoundaryNormalLFIntegrator* lq_bdry_lfi; if (axisym_) { lq_bdry_lfi = new BoundaryNormalLFIntegrator(*rad_kap_gradT_coeff_, 2, -1); } else { @@ -1890,7 +1887,7 @@ void ReactingFlow::initializeOperators() { // for explicit species-diff source term in energy (inv not needed) // TODO(trevilo): This operator is not used. Can we eliminate it? LY_form_ = new ParBilinearForm(sfes_); - auto *lyd_blfi = new DiffusionIntegrator(*species_diff_Cp_coeff_); + auto* lyd_blfi = new DiffusionIntegrator(*species_diff_Cp_coeff_); if (numerical_integ_) { lyd_blfi->SetIntRule(&ir_di); } @@ -1912,7 +1909,7 @@ void ReactingFlow::initializeOperators() { // gradient of scalar G_form_ = new ParMixedBilinearForm(sfes_, vfes_); - GradientIntegrator *g_mblfi; + GradientIntegrator* g_mblfi; if (axisym_) { g_mblfi = new GradientIntegrator(radius_coeff); } else { @@ -1952,8 +1949,8 @@ void ReactingFlow::initializeOperators() { if (restart_from_lte) { Vector n_sp(nSpecies_); Vector rho_sp(nSpecies_); - const double *h_T = Tn_.HostRead(); - double *h_Yn = Yn_.HostWrite(); + const double* h_T = Tn_.HostRead(); + double* h_Yn = Yn_.HostWrite(); for (int i = 0; i < sDofInt_; i++) { const double Ti = h_T[i]; @@ -2042,8 +2039,8 @@ void ReactingFlow::step() { // spark flow at specified location if triggered // TODO(swh) move to seperate function if (spark_) { - if(rank0_) std::cout << "Sparking flow" << endl; - + if (rank0_) std::cout << "Sparking flow" << endl; + // TODO(swh) confirm that this check is alreay enforced elsewhere int nSlot = nSpecies_ - 1; int eSlot = nSpecies_ - 2; @@ -2057,7 +2054,6 @@ void ReactingFlow::step() { pmesh_->GetNodes(coordsDof); auto h_Yn = Yn_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { - // spark volume weight double x, y, z, dist; double wgt; @@ -2073,15 +2069,13 @@ void ReactingFlow::step() { } dist = std::sqrt(dist); wgt = std::exp(-0.5 * (dist / spark_radius_) * (dist / spark_radius_)); - //if (rank0_) std::cout << "SPARK WGT: " << wgt << " | dist: " << dist << " | spark_radius: " << spark_radius_ << endl; - //wgt = 1.0; - //if(wgt < 0) { - //std::cout << "BAD WGT: " << wgt << endl; - //} - //if(wgt >1) { - //std::cout << "BAD WGT: " << wgt << endl; - //} - + // if (rank0_) std::cout << "SPARK WGT: " << wgt << " | dist: " << dist << " | spark_radius: " << spark_radius_ << + // endl; wgt = 1.0; if(wgt < 0) { std::cout << "BAD WGT: " << wgt << endl; + // } + // if(wgt >1) { + // std::cout << "BAD WGT: " << wgt << endl; + // } + // free electron value (mass-fraction) h_Yn[eSlot * sDofInt_ + i] += wgt * spark_peak_; @@ -2098,7 +2092,7 @@ void ReactingFlow::step() { } // end spark loop // Set current time for velocity Dirichlet boundary conditions. - for (auto &temp_dbc : temp_dbcs_) { + for (auto& temp_dbc : temp_dbcs_) { temp_dbc.coeff->SetTime(time_ + dt_); } @@ -2191,7 +2185,7 @@ void ReactingFlow::step() { if (implicit_chemistry_) { auto h_Yn = Yn_next_.HostReadWrite(); auto h_Tn = Tn_next_.HostReadWrite(); - double *YT = new double[nActiveSpecies_ + 1]; + double* YT = new double[nActiveSpecies_ + 1]; for (int i = 0; i < sDofInt_; i++) { // Extract point state for (int sp = 0; sp < nActiveSpecies_; sp++) { @@ -2326,8 +2320,8 @@ void ReactingFlow::evalSubstepNumber() { speciesProduction(); { - const double *dataProd = prodY_.HostRead(); - const double *dataYn = Yn_.HostRead(); + const double* dataProd = prodY_.HostRead(); + const double* dataYn = Yn_.HostRead(); for (int i = 0; i < sDofInt_; i++) { for (int sp = 0; sp < nSpecies_; sp++) { // basic based on max production @@ -2365,9 +2359,9 @@ void ReactingFlow::temperatureStep() { // Update radiation sink if (radiation_ != nullptr) { - const double *d_T = Tn_next_.Read(); - double *d_rad = radiation_sink_.Write(); - Radiation *rmodel = radiation_; + const double* d_T = Tn_next_.Read(); + double* d_rad = radiation_sink_.Write(); + Radiation* rmodel = radiation_; MFEM_FORALL(i, Tn_next_.Size(), { d_rad[i] = rmodel->computeEnergySink(d_T[i]); }); } radiation_sink_gf_.SetFromTrueDofs(radiation_sink_); @@ -2406,36 +2400,30 @@ void ReactingFlow::temperatureStep() { jh_form_->Assemble(); jh_form_->ParallelAssemble(jh_); - - - // this bit is to prevent joule heating bleed -> make more elegant and then move to separate routine - ParGridFunction coordsDof(vfes_); - pmesh_->GetNodes(coordsDof); - double rCyl = 0.029; - { - double *djh = jh_.HostReadWrite(); - for (int i = 0; i < sDofInt_; i++) { - - double x, y, z, dist; - double wgt; - x = coordsDof(0 * sDofInt_ + i); - // y = coordsDof(1 * sDofInt_ + i); - dist = x * x; - if (dim_ == 3) { - z = coordsDof(2 * sDofInt_ + i); - z = z - spark_center_[2]; - dist += z * z; - } - dist = std::sqrt(dist); - wgt = 1.0; - if (dist > rCyl) wgt = 0.0; - djh[i] *= wgt; - + // this bit is to prevent joule heating bleed -> make more elegant and then move to separate routine + ParGridFunction coordsDof(vfes_); + pmesh_->GetNodes(coordsDof); + double rCyl = 0.029; + { + double* djh = jh_.HostReadWrite(); + for (int i = 0; i < sDofInt_; i++) { + double x, y, z, dist; + double wgt; + x = coordsDof(0 * sDofInt_ + i); + // y = coordsDof(1 * sDofInt_ + i); + dist = x * x; + if (dim_ == 3) { + z = coordsDof(2 * sDofInt_ + i); + z = z - spark_center_[2]; + dist += z * z; } + dist = std::sqrt(dist); + wgt = 1.0; + if (dist > rCyl) wgt = 0.0; + djh[i] *= wgt; } + } - - resT_ += jh_; // species-temp diffusion term, already in int-weak form @@ -2463,14 +2451,14 @@ void ReactingFlow::temperatureStep() { } // Prepare for the solve - for (auto &temp_dbc : temp_dbcs_) { + for (auto& temp_dbc : temp_dbcs_) { Tn_next_gf_.ProjectBdrCoefficient(*temp_dbc.coeff, temp_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(resT_, resT_gf_); Vector Xt2, Bt2; if (partial_assembly_) { - auto *HC = Ht_.As(); + auto* HC = Ht_.As(); EliminateRHS(*Ht_form_, *HC, temp_ess_tdof_, Tn_next_gf_, resT_gf_, Xt2, Bt2, 1); } else { Ht_form_->FormLinearSystem(temp_ess_tdof_, Tn_next_gf_, resT_gf_, Ht_, Xt2, Bt2, 1); @@ -2560,9 +2548,9 @@ void ReactingFlow::temperatureSubstep(int iSub) { // tmpR0_.Add(1.0, TnStar_); // tmpR0_.Add(1.0, Tn_); - double *data = tmpR0_.HostReadWrite(); - double *dTstar = TnStar_.HostReadWrite(); - double *dTn = Tn_.HostReadWrite(); + double* data = tmpR0_.HostReadWrite(); + double* dTstar = TnStar_.HostReadWrite(); + double* dTn = Tn_.HostReadWrite(); if (explicit_destruction_) { for (int i = 0; i < sDofInt_; i++) { @@ -2596,8 +2584,8 @@ void ReactingFlow::temperatureSubstep(int iSub) { void ReactingFlow::speciesLastStep() { tmpR0_ = 0.0; - double *dataYn = Yn_next_.HostReadWrite(); - double *dataYsum = tmpR0_.HostReadWrite(); + double* dataYn = Yn_next_.HostReadWrite(); + double* dataYsum = tmpR0_.HostReadWrite(); for (int n = 0; n < nSpecies_ - 1; n++) { for (int i = 0; i < sDofInt_; i++) { dataYsum[i] += dataYn[i + n * sDofInt_]; @@ -2610,8 +2598,8 @@ void ReactingFlow::speciesLastStep() { void ReactingFlow::speciesLastSubstep() { tmpR0_ = 0.0; - double *dataYn = Yn_.HostReadWrite(); - double *dataYsum = tmpR0_.HostReadWrite(); + double* dataYn = Yn_.HostReadWrite(); + double* dataYsum = tmpR0_.HostReadWrite(); for (int n = 0; n < nSpecies_ - 1; n++) { for (int i = 0; i < sDofInt_; i++) { dataYsum[i] += dataYn[i + n * sDofInt_]; @@ -2681,14 +2669,14 @@ void ReactingFlow::speciesStep(int iSpec) { setScalarFromVector(Yn_, iSpec, &tmpR0a_); Yn_next_gf_.SetFromTrueDofs(tmpR0a_); - for (auto &spec_dbc : spec_dbcs_) { + for (auto& spec_dbc : spec_dbcs_) { Yn_next_gf_.ProjectBdrCoefficient(*spec_dbc.coeff, spec_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(resY_, resY_gf_); Vector Xt2, Bt2; if (partial_assembly_) { - auto *HC = Hy_.As(); + auto* HC = Hy_.As(); EliminateRHS(*Hy_form_, *HC, spec_ess_tdof_, Yn_next_gf_, resY_gf_, Xt2, Bt2, 1); } else { Hy_form_->FormLinearSystem(spec_ess_tdof_, Yn_next_gf_, resY_gf_, Hy_, Xt2, Bt2, 1); @@ -2741,10 +2729,10 @@ void ReactingFlow::speciesSubstep(int iSpec, int iSub) { // setScalarFromVector(Yn_, iSpec, &tmpR0a_); // tmpR0_.Add(1.0, tmpR0a_); - const double *dYstar = YnStar_.HostRead(); - const double *dYn = Yn_.HostRead(); + const double* dYstar = YnStar_.HostRead(); + const double* dYn = Yn_.HostRead(); // const double *dRho = rn_.HostRead(); - double *data = tmpR0_.HostReadWrite(); + double* data = tmpR0_.HostReadWrite(); if (explicit_destruction_) { for (int i = 0; i < sDofInt_; i++) { @@ -2773,7 +2761,7 @@ void ReactingFlow::speciesSubstep(int iSpec, int iSub) { // clip any small negative values { - double *data = tmpR0_.HostReadWrite(); + double* data = tmpR0_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { data[i] = max(data[i], 0.0); } @@ -2785,11 +2773,11 @@ void ReactingFlow::speciesSubstep(int iSpec, int iSub) { /**/ void ReactingFlow::speciesProduction() { - const double *dataT = Tn_.HostRead(); - const double *dataRho = rn_.HostRead(); - const double *dataY = Yn_.HostRead(); - double *dataProd = prodY_.HostWrite(); - double *dataEmit = prodE_.HostWrite(); + const double* dataT = Tn_.HostRead(); + const double* dataRho = rn_.HostRead(); + const double* dataY = Yn_.HostRead(); + double* dataProd = prodY_.HostWrite(); + double* dataEmit = prodE_.HostWrite(); // const int nEq = dim_ + 2 + nActiveSpecies_; Vector state(gpudata::MAXEQUATIONS); @@ -2861,12 +2849,12 @@ void ReactingFlow::speciesProduction() { void ReactingFlow::heatOfFormation() { hw_ = 0.0; tmpR0_ = 0.0; - double *h_hw = hw_.HostReadWrite(); - double *h_em = tmpR0_.HostReadWrite(); + double* h_hw = hw_.HostReadWrite(); + double* h_em = tmpR0_.HostReadWrite(); - const double *dataT = Tn_.HostRead(); - const double *h_prodY = prodY_.HostRead(); - const double *h_prodE = prodE_.HostRead(); + const double* dataT = Tn_.HostRead(); + const double* h_prodY = prodY_.HostRead(); + const double* h_prodE = prodE_.HostRead(); double hspecies; @@ -2976,7 +2964,7 @@ void ReactingFlow::computeExplicitSpecConvectionOP(int iSpec, bool extrap) { setVectorFromScalar(tmpR0a_, iSpec, &NYn_); } -void ReactingFlow::initializeIO(IODataOrganizer &io) { +void ReactingFlow::initializeIO(IODataOrganizer& io) { io.registerIOFamily("Temperature", "/temperature", &Tn_gf_, true, true, sfec_); io.registerIOVar("/temperature", "temperature", 0); @@ -2998,7 +2986,7 @@ void ReactingFlow::initializeIO(IODataOrganizer &io) { } } -void ReactingFlow::initializeViz(ParaViewDataCollection &pvdc) { +void ReactingFlow::initializeViz(ParaViewDataCollection& pvdc) { pvdc.RegisterField("temperature", &Tn_gf_); pvdc.RegisterField("density", &rn_gf_); pvdc.RegisterField("sigma", &sigma_gf_); @@ -3082,9 +3070,9 @@ void ReactingFlow::substepState() { void ReactingFlow::updateMixture() { { - double *dataY = Yn_gf_.HostReadWrite(); - double *dataR = Rmix_gf_.HostReadWrite(); - double *dataM = Mmix_gf_.HostReadWrite(); + double* dataY = Yn_gf_.HostReadWrite(); + double* dataR = Rmix_gf_.HostReadWrite(); + double* dataM = Mmix_gf_.HostReadWrite(); Mmix_gf_ = 0.0; for (int sp = 0; sp < nSpecies_; sp++) { @@ -3108,9 +3096,9 @@ void ReactingFlow::updateMixture() { setScalarFromVector(Yn_, sp, &tmpR0a_); setScalarFromVector(Xn_, sp, &tmpR0b_); Mmix_gf_.GetTrueDofs(tmpR0c_); - double *d_Y = tmpR0a_.HostReadWrite(); - double *d_X = tmpR0b_.HostReadWrite(); - double *d_M = tmpR0c_.HostReadWrite(); + double* d_Y = tmpR0a_.HostReadWrite(); + double* d_X = tmpR0b_.HostReadWrite(); + double* d_M = tmpR0c_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { d_X[i] = d_Y[i] * d_M[i] / gasParams_(sp, GasParams::SPECIES_MW); } @@ -3119,10 +3107,10 @@ void ReactingFlow::updateMixture() { // mixture Cp { - double *d_CMix = tmpR0c_.HostReadWrite(); - double *d_Yn = Yn_.HostReadWrite(); - double *d_Rho = rn_.HostReadWrite(); - double *d_Cp = CpY_.HostReadWrite(); + double* d_CMix = tmpR0c_.HostReadWrite(); + double* d_Yn = Yn_.HostReadWrite(); + double* d_Rho = rn_.HostReadWrite(); + double* d_Cp = CpY_.HostReadWrite(); // int nEq = dim_ + 2 + nActiveSpecies_; Vector state(gpudata::MAXEQUATIONS); @@ -3200,14 +3188,14 @@ void ReactingFlow::updateThermoP() { void ReactingFlow::updateDiffusivity() { (flow_interface_->velocity)->GetTrueDofs(tmpR1_); - const double *dataTemp = Tn_.HostRead(); - const double *dataRho = rn_.HostRead(); - const double *dataU = tmpR1_.HostRead(); + const double* dataTemp = Tn_.HostRead(); + const double* dataRho = rn_.HostRead(); + const double* dataU = tmpR1_.HostRead(); double diffY_min = 1.0e-8; // make readable // species diffusivities { - double *dataDiff = diffY_.HostReadWrite(); + double* dataDiff = diffY_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { double Efield[gpudata::MAXDIM]; for (int v = 0; v < dim_; v++) Efield[v] = 0.0; @@ -3237,7 +3225,7 @@ void ReactingFlow::updateDiffusivity() { // viscosity { - double *dataVisc = visc_.HostReadWrite(); + double* dataVisc = visc_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { double state[gpudata::MAXEQUATIONS]; double conservedState[gpudata::MAXEQUATIONS]; @@ -3262,7 +3250,7 @@ void ReactingFlow::updateDiffusivity() { // thermal conductivity (kappa = alpha*rho*Cp = (nu/Pr)*(rho*Cp)) { - double *dataKappa = kappa_.HostReadWrite(); + double* dataKappa = kappa_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { // int nEq = dim_ + 2 + nActiveSpecies_; double state[gpudata::MAXEQUATIONS]; @@ -3288,16 +3276,14 @@ void ReactingFlow::updateDiffusivity() { // electrical conductivity if (!torch_cold_start_ && !fixed_conductivity_) { + // this bit is to prevent joule heating bleed + // ParGridFunction coordsDof(vfes_); + // pmesh_->GetNodes(coordsDof); + // double rCyl = 0.029; - // this bit is to prevent joule heating bleed - //ParGridFunction coordsDof(vfes_); - //pmesh_->GetNodes(coordsDof); - //double rCyl = 0.029; - { - double *h_sig = sigma_.HostReadWrite(); + double* h_sig = sigma_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { - // int nEq = dim_ + 2 + nActiveSpecies_; double state[gpudata::MAXEQUATIONS]; double conservedState[gpudata::MAXEQUATIONS]; @@ -3317,23 +3303,22 @@ void ReactingFlow::updateDiffusivity() { double sig; transport_->ComputeElectricalConductivity(conservedState, sig); - h_sig[i] = sig; - - // this is hack to prevent heating in outflow tank - //double x, y, z, dist; - //double wgt; - //x = coordsDof(0 * sDofInt_ + i); - //y = coordsDof(1 * sDofInt_ + i); - //dist = x * x; - //if (dim_ == 3) { + h_sig[i] = sig; + + // this is hack to prevent heating in outflow tank + // double x, y, z, dist; + // double wgt; + // x = coordsDof(0 * sDofInt_ + i); + // y = coordsDof(1 * sDofInt_ + i); + // dist = x * x; + // if (dim_ == 3) { // z = coordsDof(2 * sDofInt_ + i); // dist += z * z; //} - //dist = std::sqrt(dist); - //wgt = 1.0; - //if (dist > rCyl) wgt = 0.0; - //h_sig[i] = wgt * sig; - + // dist = std::sqrt(dist); + // wgt = 1.0; + // if (dist > rCyl) wgt = 0.0; + // h_sig[i] = wgt * sig; } } @@ -3342,15 +3327,14 @@ void ReactingFlow::updateDiffusivity() { } void ReactingFlow::evaluatePlasmaConductivityGF() { - if (rank0_) std::cout << " ...we are in evaluatePlasmaConductivityGF " << endl; (flow_interface_->velocity)->GetTrueDofs(tmpR1_); - const double *dataTemp = Tn_.HostRead(); - const double *dataRho = rn_.HostRead(); - const double *dataU = tmpR1_.HostRead(); + const double* dataTemp = Tn_.HostRead(); + const double* dataRho = rn_.HostRead(); + const double* dataU = tmpR1_.HostRead(); - double *h_sig = sigma_.HostReadWrite(); + double* h_sig = sigma_.HostReadWrite(); if (!torch_cold_start_) { for (int i = 0; i < sDofInt_; i++) { @@ -3441,7 +3425,7 @@ void ReactingFlow::computeSystemMass() { } /// Add a Dirichlet boundary condition to the temperature field -void ReactingFlow::AddTempDirichletBC(const double &temp, Array &attr) { +void ReactingFlow::AddTempDirichletBC(const double& temp, Array& attr) { temp_dbcs_.emplace_back(attr, new ConstantCoefficient(temp)); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -3463,7 +3447,7 @@ void ReactingFlow::AddSpecDirichletBC(const double &Y, Array &attr) { } */ -void ReactingFlow::AddTempDirichletBC(Coefficient *coeff, Array &attr) { +void ReactingFlow::AddTempDirichletBC(Coefficient* coeff, Array& attr) { temp_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -3473,12 +3457,12 @@ void ReactingFlow::AddTempDirichletBC(Coefficient *coeff, Array &attr) { } } -void ReactingFlow::AddTempDirichletBC(ScalarFuncT *f, Array &attr) { +void ReactingFlow::AddTempDirichletBC(ScalarFuncT* f, Array& attr) { AddTempDirichletBC(new FunctionCoefficient(f), attr); } /// Add a Dirichlet boundary condition to the species field -void ReactingFlow::AddSpecDirichletBC(const double &spec, Array &attr) { +void ReactingFlow::AddSpecDirichletBC(const double& spec, Array& attr) { spec_dbcs_.emplace_back(attr, new ConstantCoefficient(spec)); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -3488,7 +3472,7 @@ void ReactingFlow::AddSpecDirichletBC(const double &spec, Array &attr) { } } -void ReactingFlow::AddSpecDirichletBC(Coefficient *coeff, Array &attr) { +void ReactingFlow::AddSpecDirichletBC(Coefficient* coeff, Array& attr) { spec_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -3498,12 +3482,12 @@ void ReactingFlow::AddSpecDirichletBC(Coefficient *coeff, Array &attr) { } } -void ReactingFlow::AddSpecDirichletBC(ScalarFuncT *f, Array &attr) { +void ReactingFlow::AddSpecDirichletBC(ScalarFuncT* f, Array& attr) { AddSpecDirichletBC(new FunctionCoefficient(f), attr); } // thermal divergence term -void ReactingFlow::AddQtDirichletBC(Coefficient *coeff, Array &attr) { +void ReactingFlow::AddQtDirichletBC(Coefficient* coeff, Array& attr) { Qt_dbcs_.emplace_back(attr, coeff); if (rank0_ && pmesh_->GetMyRank() == 0) { @@ -3524,7 +3508,7 @@ void ReactingFlow::AddQtDirichletBC(Coefficient *coeff, Array &attr) { } } -void ReactingFlow::AddQtDirichletBC(ScalarFuncT *f, Array &attr) { +void ReactingFlow::AddQtDirichletBC(ScalarFuncT* f, Array& attr) { AddQtDirichletBC(new FunctionCoefficient(f), attr); } @@ -3566,34 +3550,30 @@ void ReactingFlow::computeQtTO() { jh_form_->Assemble(); jh_form_->ParallelAssemble(jh_); - - // this bit is to prevent joule heating bleed -> make more elegant and then move to separate routine - ParGridFunction coordsDof(vfes_); - pmesh_->GetNodes(coordsDof); - double rCyl = 0.029; - { - double *djh = jh_.HostReadWrite(); - for (int i = 0; i < sDofInt_; i++) { - - double x, y, z, dist; - double wgt; - x = coordsDof(0 * sDofInt_ + i); - // y = coordsDof(1 * sDofInt_ + i); - dist = x * x; - if (dim_ == 3) { - z = coordsDof(2 * sDofInt_ + i); - z = z - spark_center_[2]; - dist += z * z; - } - dist = std::sqrt(dist); - wgt = 1.0; - if (dist > rCyl) wgt = 0.0; - djh[i] *= wgt; - + // this bit is to prevent joule heating bleed -> make more elegant and then move to separate routine + ParGridFunction coordsDof(vfes_); + pmesh_->GetNodes(coordsDof); + double rCyl = 0.029; + { + double* djh = jh_.HostReadWrite(); + for (int i = 0; i < sDofInt_; i++) { + double x, y, z, dist; + double wgt; + x = coordsDof(0 * sDofInt_ + i); + // y = coordsDof(1 * sDofInt_ + i); + dist = x * x; + if (dim_ == 3) { + z = coordsDof(2 * sDofInt_ + i); + z = z - spark_center_[2]; + dist += z * z; } + dist = std::sqrt(dist); + wgt = 1.0; + if (dist > rCyl) wgt = 0.0; + djh[i] *= wgt; } + } - tmpR0_ -= jh_; // rhsqt_jh_.SetFromTrueDofs(jh_); // rhsqt_jh_.Neg(); @@ -3645,7 +3625,7 @@ void ReactingFlow::computeQtTO() { /// identifySpeciesType and identifyCollisionType copies from M2ulPhyS // note: this is rather convoluted and messy, is it even used? -void ReactingFlow::identifySpeciesType(Array &speciesType) { +void ReactingFlow::identifySpeciesType(Array& speciesType) { speciesType.SetSize(nSpecies_); switch (gasType_) { @@ -3787,7 +3767,7 @@ void ReactingFlow::identifySpeciesType(Array &speciesType) { return; } -void ReactingFlow::readTableWrapper(std::string inputPath, TableInput &result) { +void ReactingFlow::readTableWrapper(std::string inputPath, TableInput& result) { std::string filename; tpsP_->getInput((inputPath + "/x_log").c_str(), result.xLogScale, false); tpsP_->getInput((inputPath + "/f_log").c_str(), result.fLogScale, false); @@ -3796,7 +3776,7 @@ void ReactingFlow::readTableWrapper(std::string inputPath, TableInput &result) { readTable(tpsP_->getTPSCommWorld(), filename, result.xLogScale, result.fLogScale, result.order, tableHost_, result); } -void ReactingFlow::identifyCollisionType(const Array &speciesType, GasColl *collisionIndex) { +void ReactingFlow::identifyCollisionType(const Array& speciesType, GasColl* collisionIndex) { for (int spI = 0; spI < nSpecies_; spI++) { for (int spJ = spI; spJ < nSpecies_; spJ++) { // If not initialized, will raise an error. @@ -3890,7 +3870,7 @@ void ReactingFlow::identifyCollisionType(const Array &speciesType, GasC return; } -void ReactingFlow::evaluateReactingSource(const double *YT, const int dofindex, double *omega) { +void ReactingFlow::evaluateReactingSource(const double* YT, const int dofindex, double* omega) { // This function evaluates the reacting flow source terms at a given // state (i.e., at a point in the grid) which is necessary for a // nonlinear solve for an implicit time step at each point. The @@ -4047,14 +4027,14 @@ void ReactingFlow::evaluateReactingSource(const double *YT, const int dofindex, omega[nActiveSpecies_] = hw / rho / Cpmix; } -void ReactingFlow::solveChemistryStep(double *YT, const int dofindex, const double dt) { +void ReactingFlow::solveChemistryStep(double* YT, const int dofindex, const double dt) { const int nState = nActiveSpecies_ + 1; // Number of variables in YT const double eps = implicit_chemistry_fd_eps_; // Perturbation for finite difference Jacobian - double *YT1 = new double[nState]; - double *YT0 = new double[nState]; - double *rhs1 = new double[nState]; - double *rhs = new double[nState]; + double* YT1 = new double[nState]; + double* YT0 = new double[nState]; + double* rhs1 = new double[nState]; + double* rhs = new double[nState]; mfem::DenseMatrix Jac(nState); @@ -4174,7 +4154,7 @@ void ReactingFlow::solveChemistryStep(double *YT, const int dofindex, const doub delete[] rhs; } -double binaryTest(const Vector &coords, double t) { +double binaryTest(const Vector& coords, double t) { double x = coords(0); double y = coords(1); // double z = coords(2); @@ -4193,7 +4173,7 @@ double binaryTest(const Vector &coords, double t) { return yn; } -double species_stepLeft(const Vector &coords, double t) { +double species_stepLeft(const Vector& coords, double t) { double x = coords(0); // douable y = coords(1); // double z = coords(2); @@ -4205,7 +4185,7 @@ double species_stepLeft(const Vector &coords, double t) { return yn; } -double species_stepRight(const Vector &coords, double t) { +double species_stepRight(const Vector& coords, double t) { double x = coords(0); // double y = coords(1); // double z = coords(2); @@ -4218,7 +4198,7 @@ double species_stepRight(const Vector &coords, double t) { return yn; } -double species_uniform(const Vector &coords, double t) { +double species_uniform(const Vector& coords, double t) { // double x = coords(0); // double y = coords(1); // double z = coords(2); diff --git a/src/reactingFlow.hpp b/src/reactingFlow.hpp index 26e7e575..45b0b7a7 100644 --- a/src/reactingFlow.hpp +++ b/src/reactingFlow.hpp @@ -57,8 +57,8 @@ class Tps; #include "tps_mfem_wrap.hpp" #include "utils.hpp" -using VecFuncT = void(const Vector &x, double t, Vector &u); -using ScalarFuncT = double(const Vector &x, double t); +using VecFuncT = void(const Vector& x, double t, Vector& u); +using ScalarFuncT = double(const Vector& x, double t); class LoMachOptions; struct temporalSchemeCoefficients; @@ -70,14 +70,14 @@ class Radiation; class ReactingFlow : public ThermoChemModelBase { private: // Options-related structures - TPS::Tps *tpsP_ = nullptr; + TPS::Tps* tpsP_ = nullptr; // Mesh and discretization scheme info - ParMesh *pmesh_ = nullptr; + ParMesh* pmesh_ = nullptr; int dim_; int order_; IntegrationRules gll_rules_; - const temporalSchemeCoefficients &time_coeff_; + const temporalSchemeCoefficients& time_coeff_; double dt_; double time_; @@ -93,7 +93,7 @@ class ReactingFlow : public ThermoChemModelBase { GasModel gasModel_; TransportModel transportModel_; ChemistryModel chemistryModel_; - Radiation *radiation_ = nullptr; + Radiation* radiation_ = nullptr; // packaged inputs PerfectMixtureInput mixtureInput_; @@ -101,10 +101,10 @@ class ReactingFlow : public ThermoChemModelBase { ChemistryInput chemistryInput_; ChemistryInput chemistryInputBase_; - PerfectMixture *mixture_ = NULL; - GasMixtureTransport *transport_ = NULL; - Chemistry *chemistry_ = NULL; - Chemistry *chemistryBase_ = NULL; + PerfectMixture* mixture_ = NULL; + GasMixtureTransport* transport_ = NULL; + Chemistry* chemistry_ = NULL; + Chemistry* chemistryBase_ = NULL; std::vector speciesNames_; std::map atomMap_; @@ -180,24 +180,24 @@ class ReactingFlow : public ThermoChemModelBase { // FEM related fields and objects // Scalar \f$H^1\f$ finite element collection. - FiniteElementCollection *sfec_ = nullptr; + FiniteElementCollection* sfec_ = nullptr; // Scalar \f$H^1\f$ finite element space. - ParFiniteElementSpace *sfes_ = nullptr; + ParFiniteElementSpace* sfes_ = nullptr; // Species \f$H^1\f$ finite element collection. - FiniteElementCollection *yfec_ = nullptr; + FiniteElementCollection* yfec_ = nullptr; // Species \f$H^1\f$ finite element space. - ParFiniteElementSpace *yfes_ = nullptr; + ParFiniteElementSpace* yfes_ = nullptr; // Vector \f$H^1\f$ finite element collection. - FiniteElementCollection *vfec_ = nullptr; + FiniteElementCollection* vfec_ = nullptr; // Vector \f$H^1\f$ finite element space. - ParFiniteElementSpace *vfes_ = nullptr; + ParFiniteElementSpace* vfes_ = nullptr; - ParGridFunction *gridScale_gf_ = nullptr; + ParGridFunction* gridScale_gf_ = nullptr; // Fields ParGridFunction Tnm1_gf_, Tnm2_gf_; @@ -239,80 +239,80 @@ class ReactingFlow : public ThermoChemModelBase { // ParGridFunction Xqt_gf_; // ParGridFunction *buffer_tInlet_ = nullptr; - GridFunctionCoefficient *temperature_bc_field_ = nullptr; - GridFunctionCoefficient *species_bc_field_ = nullptr; - VectorGridFunctionCoefficient *species_init_field_ = nullptr; - - VectorGridFunctionCoefficient *un_next_coeff_ = nullptr; - GridFunctionCoefficient *rhon_next_coeff_ = nullptr; - ScalarVectorProductCoefficient *rhou_coeff_ = nullptr; - GridFunctionCoefficient *thermal_diff_coeff_ = nullptr; - GridFunctionCoefficient *mut_coeff_ = nullptr; - GridFunctionCoefficient *mult_coeff_ = nullptr; - SumCoefficient *thermal_diff_sum_coeff_ = nullptr; - ProductCoefficient *thermal_diff_total_coeff_ = nullptr; - GradientGridFunctionCoefficient *gradT_coeff_ = nullptr; - ScalarVectorProductCoefficient *kap_gradT_coeff_ = nullptr; - GridFunctionCoefficient *rho_over_dt_coeff_ = nullptr; - GridFunctionCoefficient *rho_coeff_ = nullptr; - GridFunctionCoefficient *cpMix_coeff_ = nullptr; - ProductCoefficient *rhoCp_coeff_ = nullptr; - ScalarVectorProductCoefficient *rhouCp_coeff_ = nullptr; - ProductCoefficient *rhoCp_over_dt_coeff_ = nullptr; - - GridFunctionCoefficient *species_diff_coeff_ = nullptr; - SumCoefficient *species_diff_sum_coeff_ = nullptr; - ProductCoefficient *species_diff_total_coeff_ = nullptr; - - GridFunctionCoefficient *species_Cp_coeff_ = nullptr; - ProductCoefficient *species_diff_Cp_coeff_ = nullptr; - - GridFunctionCoefficient *jh_coeff_ = nullptr; - GridFunctionCoefficient *radiation_sink_coeff_ = nullptr; - - ProductCoefficient *rad_rho_coeff_ = nullptr; - ProductCoefficient *rad_rho_Cp_coeff_ = nullptr; - ScalarVectorProductCoefficient *rad_rho_u_coeff_ = nullptr; - ScalarVectorProductCoefficient *rad_rho_Cp_u_coeff_ = nullptr; - ProductCoefficient *rad_rho_over_dt_coeff_ = nullptr; - ProductCoefficient *rad_species_diff_total_coeff_ = nullptr; - ProductCoefficient *rad_rho_Cp_over_dt_coeff_ = nullptr; - ProductCoefficient *rad_thermal_diff_total_coeff_ = nullptr; - ProductCoefficient *rad_jh_coeff_ = nullptr; - ProductCoefficient *rad_radiation_sink_coeff_ = nullptr; - ScalarVectorProductCoefficient *rad_kap_gradT_coeff_ = nullptr; - - VectorMagnitudeCoefficient *umag_coeff_ = nullptr; - GridFunctionCoefficient *gscale_coeff_ = nullptr; - GridFunctionCoefficient *visc_coeff_ = nullptr; - PowerCoefficient *visc_inv_coeff_ = nullptr; - ProductCoefficient *reh1_coeff_ = nullptr; - ProductCoefficient *reh2_coeff_ = nullptr; - ProductCoefficient *Reh_coeff_ = nullptr; - ExtTransformedCoefficient *csupg_coeff_ = nullptr; - ProductCoefficient *uw1_coeff_ = nullptr; - ProductCoefficient *uw2_coeff_ = nullptr; - ProductCoefficient *upwind_coeff_ = nullptr; - TransformedMatrixVectorCoefficient *swdiff_coeff_ = nullptr; - ScalarMatrixProductCoefficient *supg_coeff_ = nullptr; - ScalarMatrixProductCoefficient *supg_cp_coeff_ = nullptr; + GridFunctionCoefficient* temperature_bc_field_ = nullptr; + GridFunctionCoefficient* species_bc_field_ = nullptr; + VectorGridFunctionCoefficient* species_init_field_ = nullptr; + + VectorGridFunctionCoefficient* un_next_coeff_ = nullptr; + GridFunctionCoefficient* rhon_next_coeff_ = nullptr; + ScalarVectorProductCoefficient* rhou_coeff_ = nullptr; + GridFunctionCoefficient* thermal_diff_coeff_ = nullptr; + GridFunctionCoefficient* mut_coeff_ = nullptr; + GridFunctionCoefficient* mult_coeff_ = nullptr; + SumCoefficient* thermal_diff_sum_coeff_ = nullptr; + ProductCoefficient* thermal_diff_total_coeff_ = nullptr; + GradientGridFunctionCoefficient* gradT_coeff_ = nullptr; + ScalarVectorProductCoefficient* kap_gradT_coeff_ = nullptr; + GridFunctionCoefficient* rho_over_dt_coeff_ = nullptr; + GridFunctionCoefficient* rho_coeff_ = nullptr; + GridFunctionCoefficient* cpMix_coeff_ = nullptr; + ProductCoefficient* rhoCp_coeff_ = nullptr; + ScalarVectorProductCoefficient* rhouCp_coeff_ = nullptr; + ProductCoefficient* rhoCp_over_dt_coeff_ = nullptr; + + GridFunctionCoefficient* species_diff_coeff_ = nullptr; + SumCoefficient* species_diff_sum_coeff_ = nullptr; + ProductCoefficient* species_diff_total_coeff_ = nullptr; + + GridFunctionCoefficient* species_Cp_coeff_ = nullptr; + ProductCoefficient* species_diff_Cp_coeff_ = nullptr; + + GridFunctionCoefficient* jh_coeff_ = nullptr; + GridFunctionCoefficient* radiation_sink_coeff_ = nullptr; + + ProductCoefficient* rad_rho_coeff_ = nullptr; + ProductCoefficient* rad_rho_Cp_coeff_ = nullptr; + ScalarVectorProductCoefficient* rad_rho_u_coeff_ = nullptr; + ScalarVectorProductCoefficient* rad_rho_Cp_u_coeff_ = nullptr; + ProductCoefficient* rad_rho_over_dt_coeff_ = nullptr; + ProductCoefficient* rad_species_diff_total_coeff_ = nullptr; + ProductCoefficient* rad_rho_Cp_over_dt_coeff_ = nullptr; + ProductCoefficient* rad_thermal_diff_total_coeff_ = nullptr; + ProductCoefficient* rad_jh_coeff_ = nullptr; + ProductCoefficient* rad_radiation_sink_coeff_ = nullptr; + ScalarVectorProductCoefficient* rad_kap_gradT_coeff_ = nullptr; + + VectorMagnitudeCoefficient* umag_coeff_ = nullptr; + GridFunctionCoefficient* gscale_coeff_ = nullptr; + GridFunctionCoefficient* visc_coeff_ = nullptr; + PowerCoefficient* visc_inv_coeff_ = nullptr; + ProductCoefficient* reh1_coeff_ = nullptr; + ProductCoefficient* reh2_coeff_ = nullptr; + ProductCoefficient* Reh_coeff_ = nullptr; + ExtTransformedCoefficient* csupg_coeff_ = nullptr; + ProductCoefficient* uw1_coeff_ = nullptr; + ProductCoefficient* uw2_coeff_ = nullptr; + ProductCoefficient* upwind_coeff_ = nullptr; + TransformedMatrixVectorCoefficient* swdiff_coeff_ = nullptr; + ScalarMatrixProductCoefficient* supg_coeff_ = nullptr; + ScalarMatrixProductCoefficient* supg_cp_coeff_ = nullptr; // operators and solvers - ParBilinearForm *At_form_ = nullptr; - ParBilinearForm *Ay_form_ = nullptr; - ParBilinearForm *Ms_form_ = nullptr; - ParBilinearForm *MsRho_form_ = nullptr; - ParBilinearForm *MsRhoCp_form_ = nullptr; - ParBilinearForm *Ht_form_ = nullptr; - ParBilinearForm *Hy_form_ = nullptr; - ParBilinearForm *Mq_form_ = nullptr; - ParBilinearForm *LQ_form_ = nullptr; - ParLinearForm *LQ_bdry_ = nullptr; - ParBilinearForm *LY_form_ = nullptr; - ParMixedBilinearForm *G_form_ = nullptr; - ParBilinearForm *Mv_form_ = nullptr; - - ParLinearForm *jh_form_ = nullptr; + ParBilinearForm* At_form_ = nullptr; + ParBilinearForm* Ay_form_ = nullptr; + ParBilinearForm* Ms_form_ = nullptr; + ParBilinearForm* MsRho_form_ = nullptr; + ParBilinearForm* MsRhoCp_form_ = nullptr; + ParBilinearForm* Ht_form_ = nullptr; + ParBilinearForm* Hy_form_ = nullptr; + ParBilinearForm* Mq_form_ = nullptr; + ParBilinearForm* LQ_form_ = nullptr; + ParLinearForm* LQ_bdry_ = nullptr; + ParBilinearForm* LY_form_ = nullptr; + ParMixedBilinearForm* G_form_ = nullptr; + ParBilinearForm* Mv_form_ = nullptr; + + ParLinearForm* jh_form_ = nullptr; OperatorHandle LQ_; OperatorHandle LY_; @@ -327,16 +327,16 @@ class ReactingFlow : public ThermoChemModelBase { OperatorHandle G_; OperatorHandle Mv_op_; - mfem::Solver *MsInvPC_ = nullptr; - mfem::CGSolver *MsInv_ = nullptr; - mfem::Solver *MqInvPC_ = nullptr; - mfem::CGSolver *MqInv_ = nullptr; - mfem::Solver *HtInvPC_ = nullptr; - mfem::CGSolver *HtInv_ = nullptr; - mfem::Solver *HyInvPC_ = nullptr; - mfem::CGSolver *HyInv_ = nullptr; - mfem::Solver *Mv_inv_pc_ = nullptr; - mfem::CGSolver *Mv_inv_ = nullptr; + mfem::Solver* MsInvPC_ = nullptr; + mfem::CGSolver* MsInv_ = nullptr; + mfem::Solver* MqInvPC_ = nullptr; + mfem::CGSolver* MqInv_ = nullptr; + mfem::Solver* HtInvPC_ = nullptr; + mfem::CGSolver* HtInv_ = nullptr; + mfem::Solver* HyInvPC_ = nullptr; + mfem::CGSolver* HyInv_ = nullptr; + mfem::Solver* Mv_inv_pc_ = nullptr; + mfem::CGSolver* Mv_inv_ = nullptr; // Vectors Vector Tn_, Tn_next_, Tnm1_, Tnm2_; @@ -405,28 +405,28 @@ class ReactingFlow : public ThermoChemModelBase { // set a static sigma field bool torch_cold_start_ = false; - FiniteElementCollection *sfec_filter_ = nullptr; - ParFiniteElementSpace *sfes_filter_ = nullptr; + FiniteElementCollection* sfec_filter_ = nullptr; + ParFiniteElementSpace* sfes_filter_ = nullptr; ParGridFunction Tn_NM1_gf_; ParGridFunction Tn_filtered_gf_; double Pnm1_, Pnm2_, Pnm3_; std::list tableHost_; - std::vector vizSpecFields_; + std::vector vizSpecFields_; std::vector vizSpecNames_; public: - ReactingFlow(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalSchemeCoefficients &timeCoeff, - ParGridFunction *gridScale, TPS::Tps *tps); + ReactingFlow(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalSchemeCoefficients& timeCoeff, + ParGridFunction* gridScale, TPS::Tps* tps); virtual ~ReactingFlow(); // Functions overriden from base class void initializeSelf() final; void initializeOperators() final; void step() final; - void initializeIO(IODataOrganizer &io) final; - void initializeViz(ParaViewDataCollection &pvdc) final; + void initializeIO(IODataOrganizer& io) final; + void initializeViz(ParaViewDataCollection& pvdc) final; void evaluatePlasmaConductivityGF() final; // Functions added here @@ -460,7 +460,7 @@ class ReactingFlow : public ThermoChemModelBase { * The incoming YT must contain the nActiveSpecies_ mass fractions * for the active species and temperature. */ - void evaluateReactingSource(const double *YT, const int dofindex, double *omega); + void evaluateReactingSource(const double* YT, const int dofindex, double* omega); /** * @brief Solve the thermochemistry update @@ -472,7 +472,7 @@ class ReactingFlow : public ThermoChemModelBase { * for the active species and temperature. This state is * overwritten with the new local state at the end of the time step. */ - void solveChemistryStep(double *YT, const int dofindex, const double dt); + void solveChemistryStep(double* YT, const int dofindex, const double dt); // time-splitting void substepState(); @@ -481,40 +481,40 @@ class ReactingFlow : public ThermoChemModelBase { void temperatureSubstep(int iSub); /// for creation of structs to interface with old plasma/chem stuff - void identifySpeciesType(Array &speciesType); - void identifyCollisionType(const Array &speciesType, GasColl *collisionIndex); + void identifySpeciesType(Array& speciesType); + void identifyCollisionType(const Array& speciesType, GasColl* collisionIndex); /// Return a pointer to the current temperature ParGridFunction. - ParGridFunction *GetCurrentTemperature() { return &Tn_gf_; } + ParGridFunction* GetCurrentTemperature() { return &Tn_gf_; } /// Return a pointer to the current density ParGridFunction. - ParGridFunction *GetCurrentDensity() { return &rn_gf_; } + ParGridFunction* GetCurrentDensity() { return &rn_gf_; } /// Return a pointer to the current total viscosity ParGridFunction. - ParGridFunction *GetCurrentViscosity() { return &visc_gf_; } + ParGridFunction* GetCurrentViscosity() { return &visc_gf_; } /// Return a pointer to the current total thermal diffusivity ParGridFunction. - ParGridFunction *GetCurrentThermalDiffusivity() { return &kappa_gf_; } + ParGridFunction* GetCurrentThermalDiffusivity() { return &kappa_gf_; } /// Return a pointer to the current total thermal diffusivity ParGridFunction. - ParGridFunction *GetCurrentThermalDiv() { return &Qt_gf_; } + ParGridFunction* GetCurrentThermalDiv() { return &Qt_gf_; } /// Rotate entries in the time step and solution history arrays. void UpdateTimestepHistory(double dt); /// Add a Dirichlet boundary condition to the temperature and Qt field. - void AddTempDirichletBC(const double &temp, Array &attr); - void AddTempDirichletBC(Coefficient *coeff, Array &attr); - void AddTempDirichletBC(ScalarFuncT *f, Array &attr); + void AddTempDirichletBC(const double& temp, Array& attr); + void AddTempDirichletBC(Coefficient* coeff, Array& attr); + void AddTempDirichletBC(ScalarFuncT* f, Array& attr); - void AddQtDirichletBC(Coefficient *coeff, Array &attr); - void AddQtDirichletBC(ScalarFuncT *f, Array &attr); + void AddQtDirichletBC(Coefficient* coeff, Array& attr); + void AddQtDirichletBC(ScalarFuncT* f, Array& attr); - void AddSpecDirichletBC(const double &spec, Array &attr); - void AddSpecDirichletBC(Coefficient *coeff, Array &attr); - void AddSpecDirichletBC(ScalarFuncT *f, Array &attr); + void AddSpecDirichletBC(const double& spec, Array& attr); + void AddSpecDirichletBC(Coefficient* coeff, Array& attr); + void AddSpecDirichletBC(ScalarFuncT* f, Array& attr); void evalSubstepNumber(); - void readTableWrapper(std::string inputPath, TableInput &result); + void readTableWrapper(std::string inputPath, TableInput& result); }; #endif // REACTINGFLOW_HPP_ diff --git a/src/reaction.cpp b/src/reaction.cpp index d119f58b..97e0351f 100644 --- a/src/reaction.cpp +++ b/src/reaction.cpp @@ -35,32 +35,32 @@ using namespace mfem; using namespace std; -MFEM_HOST_DEVICE Arrhenius::Arrhenius(const double &A, const double &b, const double &E) +MFEM_HOST_DEVICE Arrhenius::Arrhenius(const double& A, const double& b, const double& E) : Reaction(ARRHENIUS), A_(A), b_(b), E_(E) {} -MFEM_HOST_DEVICE double Arrhenius::computeRateCoefficient(const double &T_h, const double &T_e, - [[maybe_unused]] const int &dofindex, +MFEM_HOST_DEVICE double Arrhenius::computeRateCoefficient(const double& T_h, const double& T_e, + [[maybe_unused]] const int& dofindex, const bool isElectronInvolved, - [[maybe_unused]] const double *nsp) { + [[maybe_unused]] const double* nsp) { double temp = (isElectronInvolved) ? T_e : T_h; return A_ * pow(temp, b_) * exp(-E_ / UNIVERSALGASCONSTANT / temp); } -MFEM_HOST_DEVICE HoffertLien::HoffertLien(const double &A, const double &b, const double &E) +MFEM_HOST_DEVICE HoffertLien::HoffertLien(const double& A, const double& b, const double& E) : Reaction(HOFFERTLIEN), A_(A), b_(b), E_(E) {} -MFEM_HOST_DEVICE double HoffertLien::computeRateCoefficient(const double &T_h, const double &T_e, - [[maybe_unused]] const int &dofindex, +MFEM_HOST_DEVICE double HoffertLien::computeRateCoefficient(const double& T_h, const double& T_e, + [[maybe_unused]] const int& dofindex, const bool isElectronInvolved, - [[maybe_unused]] const double *nsp) { + [[maybe_unused]] const double* nsp) { double temp = (isElectronInvolved) ? T_e : T_h; double tempFactor = E_ / BOLTZMANNCONSTANT / temp; return A_ * pow(temp, b_) * (tempFactor + 2.0) * exp(-tempFactor); } -MFEM_HOST_DEVICE Tabulated::Tabulated(const TableInput &input) : Reaction(TABULATED_RXN) { +MFEM_HOST_DEVICE Tabulated::Tabulated(const TableInput& input) : Reaction(TABULATED_RXN) { switch (input.order) { case 1: { table_ = new LinearTable(input); @@ -74,10 +74,10 @@ MFEM_HOST_DEVICE Tabulated::Tabulated(const TableInput &input) : Reaction(TABULA MFEM_HOST_DEVICE Tabulated::~Tabulated() { delete table_; } -MFEM_HOST_DEVICE double Tabulated::computeRateCoefficient(const double &T_h, const double &T_e, - [[maybe_unused]] const int &dofindex, +MFEM_HOST_DEVICE double Tabulated::computeRateCoefficient(const double& T_h, const double& T_e, + [[maybe_unused]] const int& dofindex, const bool isElectronInvolved, - [[maybe_unused]] const double *nsp) { + [[maybe_unused]] const double* nsp) { double temp = (isElectronInvolved) ? T_e : T_h; return table_->eval(temp); } @@ -87,12 +87,12 @@ MFEM_HOST_DEVICE GridFunctionReaction::GridFunctionReaction(int comp) MFEM_HOST_DEVICE GridFunctionReaction::~GridFunctionReaction() {} -MFEM_HOST_DEVICE void GridFunctionReaction::setData(const double *data, int size) { +MFEM_HOST_DEVICE void GridFunctionReaction::setData(const double* data, int size) { data_ = data + comp_ * size_; size_ = size; } -void GridFunctionReaction::setGridFunction(const mfem::GridFunction &f) { +void GridFunctionReaction::setGridFunction(const mfem::GridFunction& f) { size_ = f.FESpace()->GetNDofs(); assert(comp_ < f.FESpace()->GetVDim()); assert(f.FESpace()->GetOrdering() == mfem::Ordering::byNODES); @@ -103,11 +103,11 @@ void GridFunctionReaction::setGridFunction(const mfem::GridFunction &f) { #endif } -MFEM_HOST_DEVICE double GridFunctionReaction::computeRateCoefficient([[maybe_unused]] const double &T_h, - [[maybe_unused]] const double &T_e, - const int &dofindex, +MFEM_HOST_DEVICE double GridFunctionReaction::computeRateCoefficient([[maybe_unused]] const double& T_h, + [[maybe_unused]] const double& T_e, + const int& dofindex, [[maybe_unused]] const bool isElectronInvolved, - [[maybe_unused]] const double *nsp) { + [[maybe_unused]] const double* nsp) { if (data_) { assert(dofindex < size_); return data_[dofindex]; @@ -118,9 +118,9 @@ MFEM_HOST_DEVICE double GridFunctionReaction::computeRateCoefficient([[maybe_unu #ifndef _GPU_ // Radiative decay portion: extracted from commit (de27f14) -MFEM_HOST_DEVICE RadiativeDecay::RadiativeDecay(const double _R, const std::map *_speciesMapping, - const std::vector *_speciesNames, const int *numSpecies, - const double *_reactantStoich, const double *_productStoich) +MFEM_HOST_DEVICE RadiativeDecay::RadiativeDecay(const double _R, const std::map* _speciesMapping, + const std::vector* _speciesNames, const int* numSpecies, + const double* _reactantStoich, const double* _productStoich) : Reaction(RADIATIVE_DECAY), Rcyl(_R) { rank0_ = Mpi::Root(); Lcyl = 2.0 * Rcyl; @@ -190,10 +190,10 @@ MFEM_HOST_DEVICE RadiativeDecay::RadiativeDecay(const double _R, const std::map< MFEM_HOST_DEVICE RadiativeDecay::~RadiativeDecay() {} -MFEM_HOST_DEVICE double RadiativeDecay::computeRateCoefficient(const double &T_h, const double &T_e, - const int &dofindex, +MFEM_HOST_DEVICE double RadiativeDecay::computeRateCoefficient(const double& T_h, const double& T_e, + const int& dofindex, [[maybe_unused]] const bool isElectronInvolved, - const double *nsp) { + const double* nsp) { double n_sp_u = nsp[iAr_u]; // Find the index corresponding to the correct species double n_sp_l = nsp[iAr_l]; @@ -214,8 +214,8 @@ MFEM_HOST_DEVICE double RadiativeDecay::computeRateCoefficient(const double &T_h return effAcoef; } -MFEM_HOST_DEVICE void RadiativeDecay::GetNumDensityOfInteralLevels(const int NumOfInteral_lvl, const double &n_sp, - const double &T_e, double *n_sp_internal) { +MFEM_HOST_DEVICE void RadiativeDecay::GetNumDensityOfInteralLevels(const int NumOfInteral_lvl, const double& n_sp, + const double& T_e, double* n_sp_internal) { // n_sp in [mol/m^3] is the number concentration of a lumped state/level. // Here, we evaluate the number concentration of the internal levels assuming that they // are Boltzmann distributed. @@ -235,7 +235,7 @@ MFEM_HOST_DEVICE void RadiativeDecay::GetNumDensityOfInteralLevels(const int Num } } -MFEM_HOST_DEVICE void RadiativeDecay::GetEinsteinACoefficient(const double &T_h, const double &T_e, double *effAcoef) { +MFEM_HOST_DEVICE void RadiativeDecay::GetEinsteinACoefficient(const double& T_h, const double& T_e, double* effAcoef) { for (int i_lvl = 0; i_lvl < NumOfInteral_lvl_u; i_lvl++) { for (int itrans = 0; itrans < int((*Aji)[i_lvl].size()); itrans++) { double Acoef = (*Aji)[i_lvl][itrans]; @@ -246,9 +246,9 @@ MFEM_HOST_DEVICE void RadiativeDecay::GetEinsteinACoefficient(const double &T_h, } } -MFEM_HOST_DEVICE double RadiativeDecay::escapeFactCalc(const double &n_i, const double &E_j, const double &E_i, - const double &g_j, const double &g_i, const double &A_ji, - const double &T_g) { +MFEM_HOST_DEVICE double RadiativeDecay::escapeFactCalc(const double& n_i, const double& E_j, const double& E_i, + const double& g_j, const double& g_i, const double& A_ji, + const double& T_g) { // Calculations for escape factor // i -> lower level // j -> upper level diff --git a/src/reaction.hpp b/src/reaction.hpp index d46194c5..96023a99 100644 --- a/src/reaction.hpp +++ b/src/reaction.hpp @@ -58,10 +58,10 @@ class Reaction { MFEM_HOST_DEVICE virtual ~Reaction() {} - MFEM_HOST_DEVICE virtual double computeRateCoefficient(const double &T_h, const double &T_e, - [[maybe_unused]] const int &dofindex, + MFEM_HOST_DEVICE virtual double computeRateCoefficient(const double& T_h, const double& T_e, + [[maybe_unused]] const int& dofindex, const bool isElectronInvolved = false, - [[maybe_unused]] const double *nsp = 0) { + [[maybe_unused]] const double* nsp = 0) { printf("computeRateCoefficient not implemented"); return 0; } @@ -75,14 +75,14 @@ class Arrhenius : public Reaction { double E_; public: - MFEM_HOST_DEVICE Arrhenius(const double &A, const double &b, const double &E); + MFEM_HOST_DEVICE Arrhenius(const double& A, const double& b, const double& E); MFEM_HOST_DEVICE virtual ~Arrhenius() {} - MFEM_HOST_DEVICE virtual double computeRateCoefficient(const double &T_h, const double &T_e, - [[maybe_unused]] const int &dofindex, + MFEM_HOST_DEVICE virtual double computeRateCoefficient(const double& T_h, const double& T_e, + [[maybe_unused]] const int& dofindex, const bool isElectronInvolved = false, - [[maybe_unused]] const double *nsp = 0); + [[maybe_unused]] const double* nsp = 0); }; class HoffertLien : public Reaction { @@ -97,34 +97,34 @@ class HoffertLien : public Reaction { double E_; public: - MFEM_HOST_DEVICE HoffertLien(const double &A, const double &b, const double &E); + MFEM_HOST_DEVICE HoffertLien(const double& A, const double& b, const double& E); MFEM_HOST_DEVICE virtual ~HoffertLien() {} - MFEM_HOST_DEVICE virtual double computeRateCoefficient(const double &T_h, const double &T_e, - [[maybe_unused]] const int &dofindex, + MFEM_HOST_DEVICE virtual double computeRateCoefficient(const double& T_h, const double& T_e, + [[maybe_unused]] const int& dofindex, const bool isElectronInvolved = false, - [[maybe_unused]] const double *nsp = 0); + [[maybe_unused]] const double* nsp = 0); }; class Tabulated : public Reaction { private: - TableInterpolator *table_ = NULL; + TableInterpolator* table_ = NULL; public: - MFEM_HOST_DEVICE Tabulated(const TableInput &input); + MFEM_HOST_DEVICE Tabulated(const TableInput& input); MFEM_HOST_DEVICE virtual ~Tabulated(); - MFEM_HOST_DEVICE virtual double computeRateCoefficient(const double &T_h, const double &T_e, - [[maybe_unused]] const int &dofindex, + MFEM_HOST_DEVICE virtual double computeRateCoefficient(const double& T_h, const double& T_e, + [[maybe_unused]] const int& dofindex, const bool isElectronInvolved = false, - [[maybe_unused]] const double *nsp = 0); + [[maybe_unused]] const double* nsp = 0); }; class GridFunctionReaction : public Reaction { private: - const double *data_; + const double* data_; const int comp_; int size_; @@ -133,14 +133,14 @@ class GridFunctionReaction : public Reaction { MFEM_HOST_DEVICE virtual ~GridFunctionReaction(); - void setGridFunction(const mfem::GridFunction &f); + void setGridFunction(const mfem::GridFunction& f); - MFEM_HOST_DEVICE void setData(const double *data, int size); + MFEM_HOST_DEVICE void setData(const double* data, int size); - MFEM_HOST_DEVICE virtual double computeRateCoefficient([[maybe_unused]] const double &T_h, - [[maybe_unused]] const double &T_e, const int &dofindex, + MFEM_HOST_DEVICE virtual double computeRateCoefficient([[maybe_unused]] const double& T_h, + [[maybe_unused]] const double& T_e, const int& dofindex, [[maybe_unused]] const bool isElectronInvolved = false, - [[maybe_unused]] const double *nsp = 0); + [[maybe_unused]] const double* nsp = 0); }; class RadiativeDecay : public Reaction { @@ -167,13 +167,13 @@ class RadiativeDecay : public Reaction { // Variables int NumOfInteral_lvl_u; - std::vector *E_lvl_u; - std::vector *g_lvl_u; + std::vector* E_lvl_u; + std::vector* g_lvl_u; std::vector n_sp_lvl_u; - std::vector> *Aji; + std::vector>* Aji; std::vector effAcoef_lvl; - std::vector *E_lvl_l; - std::vector *g_lvl_l; + std::vector* E_lvl_l; + std::vector* g_lvl_l; std::vector n_sp_lvl_l; int numSpecies_; @@ -287,23 +287,23 @@ class RadiativeDecay : public Reaction { // 750.59 Ar(4p'[1/2]0) -> Ar(4s'[1/2]1) 45000000.0 public: - MFEM_HOST_DEVICE RadiativeDecay(const double _R, const std::map *_speciesMapping, - const std::vector *_speciesNames, const int *numSpecies, - const double *_reactantStoich, const double *_productStoich); + MFEM_HOST_DEVICE RadiativeDecay(const double _R, const std::map* _speciesMapping, + const std::vector* _speciesNames, const int* numSpecies, + const double* _reactantStoich, const double* _productStoich); MFEM_HOST_DEVICE virtual ~RadiativeDecay(); - MFEM_HOST_DEVICE virtual double computeRateCoefficient(const double &T_h, const double &T_e, const int &dofindex, + MFEM_HOST_DEVICE virtual double computeRateCoefficient(const double& T_h, const double& T_e, const int& dofindex, [[maybe_unused]] const bool isElectronInvolved = false, - const double *nsp = 0); + const double* nsp = 0); - MFEM_HOST_DEVICE void GetEinsteinACoefficient(const double &T_h, const double &T_e, double *effAcoef); + MFEM_HOST_DEVICE void GetEinsteinACoefficient(const double& T_h, const double& T_e, double* effAcoef); - MFEM_HOST_DEVICE void GetNumDensityOfInteralLevels(const int NumOfInteral_lvl, const double &n_sp, const double &T_e, - double *n_sp_internal); + MFEM_HOST_DEVICE void GetNumDensityOfInteralLevels(const int NumOfInteral_lvl, const double& n_sp, const double& T_e, + double* n_sp_internal); - MFEM_HOST_DEVICE double escapeFactCalc(const double &n_i, const double &E_j, const double &E_i, const double &g_j, - const double &g_i, const double &A_ji, const double &T_g); + MFEM_HOST_DEVICE double escapeFactCalc(const double& n_i, const double& E_j, const double& E_i, const double& g_j, + const double& g_i, const double& A_ji, const double& T_g); }; #endif // REACTION_HPP_ diff --git a/src/rhs_operator.cpp b/src/rhs_operator.cpp index bb556b0e..498e1970 100644 --- a/src/rhs_operator.cpp +++ b/src/rhs_operator.cpp @@ -31,21 +31,21 @@ // -----------------------------------------------------------------------------------el- #include "rhs_operator.hpp" -double getRadius(const Vector &pos) { return pos[0]; } +double getRadius(const Vector& pos) { return pos[0]; } FunctionCoefficient radiusFcn(getRadius); // Implementation of class RHSoperator -RHSoperator::RHSoperator(int &_iter, const int _dim, const int &_num_equation, const int &_order, - const Equations &_eqSystem, double &_max_char_speed, IntegrationRules *_intRules, - int _intRuleType, Fluxes *_fluxClass, GasMixture *_mixture, GasMixture *d_mixture, - Chemistry *_chemistry, TransportProperties *_transport, Radiation *_radiation, - ParFiniteElementSpace *_vfes, ParFiniteElementSpace *_fes, - const precomputedIntegrationData &gpu_precomputed_data, const int &_maxIntPoints, - const int &_maxDofs, DGNonLinearForm *_A, MixedBilinearForm *_Aflux, ParMesh *_mesh, - ParGridFunction *_spaceVaryViscMult, ParGridFunction *U, ParGridFunction *_Up, - ParGridFunction *_gradUp, ParFiniteElementSpace *_gradUpfes, GradNonLinearForm *_gradUp_A, - BCintegrator *_bcIntegrator, RunConfiguration &_config, ParGridFunction *pc, - ParGridFunction *jh, ParGridFunction *distance) +RHSoperator::RHSoperator(int& _iter, const int _dim, const int& _num_equation, const int& _order, + const Equations& _eqSystem, double& _max_char_speed, IntegrationRules* _intRules, + int _intRuleType, Fluxes* _fluxClass, GasMixture* _mixture, GasMixture* d_mixture, + Chemistry* _chemistry, TransportProperties* _transport, Radiation* _radiation, + ParFiniteElementSpace* _vfes, ParFiniteElementSpace* _fes, + const precomputedIntegrationData& gpu_precomputed_data, const int& _maxIntPoints, + const int& _maxDofs, DGNonLinearForm* _A, MixedBilinearForm* _Aflux, ParMesh* _mesh, + ParGridFunction* _spaceVaryViscMult, ParGridFunction* U, ParGridFunction* _Up, + ParGridFunction* _gradUp, ParFiniteElementSpace* _gradUpfes, GradNonLinearForm* _gradUp_A, + BCintegrator* _bcIntegrator, RunConfiguration& _config, ParGridFunction* pc, + ParGridFunction* jh, ParGridFunction* distance) : TimeDependentOperator(_A->Height()), config_(_config), iter(_iter), @@ -89,7 +89,7 @@ RHSoperator::RHSoperator(int &_iter, const int _dim, const int &_num_equation, c fk.SetSize(dim_ * vfes->GetNDofs()); zk.SetSize(vfes->GetNDofs()); - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; h_num_elems_of_type = elem_data.num_elems_of_type.HostRead(); Me_inv.SetSize(vfes->GetNE()); @@ -136,7 +136,7 @@ RHSoperator::RHSoperator(int &_iter, const int _dim, const int &_num_equation, c #endif // not just for axisymmetric - const FiniteElementCollection *fec = vfes->FEColl(); + const FiniteElementCollection* fec = vfes->FEColl(); dfes = new ParFiniteElementSpace(mesh, fec, dim_, Ordering::byNODES); coordsDof = new ParGridFunction(dfes); mesh->GetNodes(*coordsDof); @@ -260,11 +260,11 @@ RHSoperator::RHSoperator(int &_iter, const int _dim, const int &_num_equation, c DenseMatrix Dx(dof), Kx(dof); Dx = 0.; Kx = 0.; - ElementTransformation *Tr = vfes->GetElementTransformation(elem); + ElementTransformation* Tr = vfes->GetElementTransformation(elem); int integrationOrder = 2 * vfes->GetFE(elem)->GetOrder(); const IntegrationRule intRule = intRules->Get(vfes->GetFE(elem)->GetGeomType(), integrationOrder); for (int k = 0; k < intRule.GetNPoints(); k++) { - const IntegrationPoint &ip = intRule.IntPoint(k); + const IntegrationPoint& ip = intRule.IntPoint(k); double wk = ip.weight; Tr->SetIntPoint(&ip); @@ -340,7 +340,7 @@ RHSoperator::~RHSoperator() { if (transferGradUp.statuses != NULL) delete[] transferGradUp.statuses; } -void RHSoperator::Mult(const Vector &x, Vector &y) const { +void RHSoperator::Mult(const Vector& x, Vector& y) const { max_char_speed = 0.; // Update primite varibales @@ -409,7 +409,7 @@ void RHSoperator::Mult(const Vector &x, Vector &y) const { // 3. Multiply element-wise by the inverse mass matrices. #ifdef _GPU_ - const elementIndexingData &elem_data = gpu_precomputed_data_.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data_.element_indexing_data; auto h_elem_dof_num = elem_data.dof_number.HostRead(); for (int eltype = 0; eltype < elem_data.num_elems_of_type.Size(); eltype++) { int elemOffset = 0; @@ -463,22 +463,22 @@ void RHSoperator::Mult(const Vector &x, Vector &y) const { computeMeanTimeDerivatives(y); } -void RHSoperator::copyZk2Z_gpu(Vector &z, Vector &zk, const int eq, const int dof) { +void RHSoperator::copyZk2Z_gpu(Vector& z, Vector& zk, const int eq, const int dof) { #ifdef _GPU_ - const double *d_zk = zk.Read(); - double *d_z = z.ReadWrite(); + const double* d_zk = zk.Read(); + double* d_z = z.ReadWrite(); MFEM_FORALL(n, dof, { d_z[n + eq * dof] = d_zk[n]; }); #endif } -void RHSoperator::copyDataForFluxIntegration_gpu(const Vector &z, DenseTensor &flux, Vector &fk, Vector &zk, +void RHSoperator::copyDataForFluxIntegration_gpu(const Vector& z, DenseTensor& flux, Vector& fk, Vector& zk, const int eq, const int dof, const int dim) { #ifdef _GPU_ - const double *d_flux = flux.Read(); - const double *d_z = z.Read(); - double *d_fk = fk.Write(); - double *d_zk = zk.Write(); + const double* d_flux = flux.Read(); + const double* d_z = z.Read(); + double* d_fk = fk.Write(); + double* d_zk = zk.Write(); MFEM_FORALL(n, dof, { d_zk[n] = d_z[n + eq * dof]; @@ -490,7 +490,7 @@ void RHSoperator::copyDataForFluxIntegration_gpu(const Vector &z, DenseTensor &f } // Compute the flux at solution nodes. -void RHSoperator::GetFlux(const Vector &x, DenseTensor &flux) const { +void RHSoperator::GetFlux(const Vector& x, DenseTensor& flux) const { #ifdef _GPU_ GetFlux_gpu(x, flux); @@ -499,7 +499,7 @@ void RHSoperator::GetFlux(const Vector &x, DenseTensor &flux) const { DenseMatrix xmat(x.GetData(), vfes->GetNDofs(), num_equation_); DenseMatrix f(num_equation_, dim_); - double *dataGradUp = gradUp->GetData(); + double* dataGradUp = gradUp->GetData(); const int dof = flux.SizeI(); const int dim = flux.SizeJ(); @@ -558,7 +558,7 @@ void RHSoperator::GetFlux(const Vector &x, DenseTensor &flux) const { MPI_Allreduce(&partition_max_char, &max_char_speed, 1, MPI_DOUBLE, MPI_MAX, mesh->GetComm()); } -void RHSoperator::GetFlux_gpu(const Vector &x, DenseTensor &flux) const { +void RHSoperator::GetFlux_gpu(const Vector& x, DenseTensor& flux) const { auto dataIn = x.Read(); auto d_flux = flux.Write(); @@ -566,16 +566,16 @@ void RHSoperator::GetFlux_gpu(const Vector &x, DenseTensor &flux) const { const int dim = dim_; const int num_equation = num_equation_; - const double *d_coord = coordsDof->Read(); - const double *d_gradUp = gradUp->Read(); + const double* d_coord = coordsDof->Read(); + const double* d_gradUp = gradUp->Read(); - Fluxes *d_fluxClass = fluxClass; + Fluxes* d_fluxClass = fluxClass; // This element size is divided by element polynomial order when // elSize is set, in the RHSoperator ctor auto d_elSize = elSize->Read(); - const double *d_distance = NULL; + const double* d_distance = NULL; if (distance_ != NULL) { d_distance = distance_->Read(); } @@ -620,7 +620,7 @@ void RHSoperator::GetFlux_gpu(const Vector &x, DenseTensor &flux) const { }); } -void RHSoperator::updatePrimitives(const Vector &x_in) const { +void RHSoperator::updatePrimitives(const Vector& x_in) const { #ifdef _GPU_ auto dataUp = Up->Write(); // make sure data is available in GPU auto dataIn = x_in.Read(); // make sure data is available in GPU @@ -628,7 +628,7 @@ void RHSoperator::updatePrimitives(const Vector &x_in) const { const int ndofs = vfes->GetNDofs(); const int num_equation = num_equation_; - GasMixture *d_mix = d_mixture_; + GasMixture* d_mix = d_mixture_; MFEM_FORALL(n, ndofs, { double state[gpudata::MAXEQUATIONS], @@ -639,7 +639,7 @@ void RHSoperator::updatePrimitives(const Vector &x_in) const { for (int eq = 0; eq < num_equation; eq++) dataUp[n + eq * ndofs] = prim[eq]; }); #else - double *dataUp = Up->GetData(); + double* dataUp = Up->GetData(); for (int i = 0; i < vfes->GetNDofs(); i++) { Vector iState(num_equation_); Vector primitiveState(num_equation_); @@ -650,7 +650,7 @@ void RHSoperator::updatePrimitives(const Vector &x_in) const { #endif // _GPU_ } -void RHSoperator::updateGradients(const Vector &x, const bool &primitiveUpdated) const { +void RHSoperator::updateGradients(const Vector& x, const bool& primitiveUpdated) const { // Update primite varibales if (!primitiveUpdated) updatePrimitives(x); @@ -672,18 +672,18 @@ void RHSoperator::updateGradients(const Vector &x, const bool &primitiveUpdated) #endif } -void RHSoperator::multiPlyInvers_gpu(Vector &y, Vector &z, const precomputedIntegrationData &gpu_precomputed_data, - const Vector &invMArray, const Array &posDofInvM, const int num_equation, +void RHSoperator::multiPlyInvers_gpu(Vector& y, Vector& z, const precomputedIntegrationData& gpu_precomputed_data, + const Vector& invMArray, const Array& posDofInvM, const int num_equation, const int totNumDof, const int NE, const int elemOffset, const int dof) { #ifdef _GPU_ - double *d_y = y.ReadWrite(); - const double *d_z = z.Read(); + double* d_y = y.ReadWrite(); + const double* d_z = z.Read(); - const elementIndexingData &elem_data = gpu_precomputed_data.element_indexing_data; + const elementIndexingData& elem_data = gpu_precomputed_data.element_indexing_data; auto d_elem_dofs_list = elem_data.dofs_list.Read(); auto d_elem_dof_off = elem_data.dof_offset.Read(); auto d_posDofInvM = posDofInvM.Read(); - const double *d_invM = invMArray.Read(); + const double* d_invM = invMArray.Read(); MFEM_FORALL_2D(el, NE, dof, 1, 1, { MFEM_SHARED double data[gpudata::MAXDOFS * gpudata::MAXEQUATIONS]; // MFEM_SHARED double data[216 * 20]; @@ -714,12 +714,12 @@ void RHSoperator::multiPlyInvers_gpu(Vector &y, Vector &z, const precomputedInte } void RHSoperator::allocateTransferData() { - ParFiniteElementSpace *pfes = Up->ParFESpace(); - ParMesh *mesh = pfes->GetParMesh(); + ParFiniteElementSpace* pfes = Up->ParFESpace(); + ParMesh* mesh = pfes->GetParMesh(); mesh->ExchangeFaceNbrNodes(); mesh->ExchangeFaceNbrData(); vfes->ExchangeFaceNbrData(); - ParFiniteElementSpace *gradFes = gradUp->ParFESpace(); + ParFiniteElementSpace* gradFes = gradUp->ParFESpace(); gradFes->ExchangeFaceNbrData(); const int Nshared = mesh->GetNSharedFaces(); @@ -751,9 +751,9 @@ void RHSoperator::allocateTransferData() { transferGradUp.send_data = 0.; transferGradUp.num_face_nbrs = mesh->GetNFaceNeighbors(); - MPI_Request *requestsU = new MPI_Request[2 * mesh->GetNFaceNeighbors()]; - MPI_Request *requestsUp = new MPI_Request[2 * mesh->GetNFaceNeighbors()]; - MPI_Request *requGradUp = new MPI_Request[2 * mesh->GetNFaceNeighbors()]; + MPI_Request* requestsU = new MPI_Request[2 * mesh->GetNFaceNeighbors()]; + MPI_Request* requestsUp = new MPI_Request[2 * mesh->GetNFaceNeighbors()]; + MPI_Request* requGradUp = new MPI_Request[2 * mesh->GetNFaceNeighbors()]; transferU.requests = requestsU; transferUp.requests = requestsUp; transferGradUp.requests = requGradUp; @@ -772,20 +772,20 @@ void RHSoperator::allocateTransferData() { } } -void RHSoperator::initNBlockDataTransfer(const Vector &x, ParFiniteElementSpace *pfes, - dataTransferArrays &dataTransfer) { +void RHSoperator::initNBlockDataTransfer(const Vector& x, ParFiniteElementSpace* pfes, + dataTransferArrays& dataTransfer) { if (pfes->GetFaceNbrVSize() <= 0) { return; } - ParMesh *pmesh = pfes->GetParMesh(); + ParMesh* pmesh = pfes->GetParMesh(); // face_nbr_data.SetSize(pfes->GetFaceNbrVSize()); // send_data.SetSize(pfes->send_face_nbr_ldof.Size_of_connections()); - int *send_offset = pfes->send_face_nbr_ldof.GetI(); - const int *d_send_ldof = mfem::Read(pfes->send_face_nbr_ldof.GetJMemory(), dataTransfer.send_data.Size()); - int *recv_offset = pfes->face_nbr_ldof.GetI(); + int* send_offset = pfes->send_face_nbr_ldof.GetI(); + const int* d_send_ldof = mfem::Read(pfes->send_face_nbr_ldof.GetJMemory(), dataTransfer.send_data.Size()); + int* recv_offset = pfes->face_nbr_ldof.GetI(); MPI_Comm MyComm = pfes->GetComm(); // int num_face_nbrs = pmesh->GetNFaceNeighbors(); @@ -821,7 +821,7 @@ void RHSoperator::initNBlockDataTransfer(const Vector &x, ParFiniteElementSpace } } -void RHSoperator::waitAllDataTransfer(ParFiniteElementSpace *pfes, dataTransferArrays &dataTransfer) { +void RHSoperator::waitAllDataTransfer(ParFiniteElementSpace* pfes, dataTransferArrays& dataTransfer) { if (pfes->GetFaceNbrVSize() <= 0) { return; } @@ -830,7 +830,7 @@ void RHSoperator::waitAllDataTransfer(ParFiniteElementSpace *pfes, dataTransferA MPI_Waitall(dataTransfer.num_face_nbrs, dataTransfer.requests + dataTransfer.num_face_nbrs, dataTransfer.statuses); } -void RHSoperator::computeMeanTimeDerivatives(Vector &y) const { +void RHSoperator::computeMeanTimeDerivatives(Vector& y) const { if (iter % 100 == 0) { #ifdef _GPU_ int Ndof = y.Size() / num_equation_; @@ -848,8 +848,8 @@ void RHSoperator::computeMeanTimeDerivatives(Vector &y) const { } } -void RHSoperator::meanTimeDerivatives_gpu(Vector &y, Vector &local_timeDerivatives, Vector &tmp_vec, const int &NDof, - const int &num_equation, const int &dim) { +void RHSoperator::meanTimeDerivatives_gpu(Vector& y, Vector& local_timeDerivatives, Vector& tmp_vec, const int& NDof, + const int& num_equation, const int& dim) { #ifdef _GPU_ auto d_y = y.Read(); diff --git a/src/rhs_operator.hpp b/src/rhs_operator.hpp index 35bcf14f..ef0a38f3 100644 --- a/src/rhs_operator.hpp +++ b/src/rhs_operator.hpp @@ -58,74 +58,74 @@ using namespace mfem; // DG weak form. class RHSoperator : public TimeDependentOperator { private: - const RunConfiguration &config_; - Gradients *gradients; + const RunConfiguration& config_; + Gradients* gradients; - int &iter; + int& iter; const int dim_; const int nvel; - const Equations &eqSystem; + const Equations& eqSystem; - double &max_char_speed; - const int &num_equation_; + double& max_char_speed; + const int& num_equation_; - IntegrationRules *intRules; + IntegrationRules* intRules; const int intRuleType; - Fluxes *fluxClass; + Fluxes* fluxClass; GasMixture *mixture, *d_mixture_; - TransportProperties *transport_; + TransportProperties* transport_; - ParFiniteElementSpace *vfes; - ParFiniteElementSpace *fes; + ParFiniteElementSpace* vfes; + ParFiniteElementSpace* fes; - const precomputedIntegrationData &gpu_precomputed_data_; + const precomputedIntegrationData& gpu_precomputed_data_; - const int *h_num_elems_of_type; + const int* h_num_elems_of_type; - const int &maxIntPoints; - const int &maxDofs; + const int& maxIntPoints; + const int& maxDofs; - DGNonLinearForm *A; + DGNonLinearForm* A; - MixedBilinearForm *Aflux; + MixedBilinearForm* Aflux; - ParMesh *mesh; + ParMesh* mesh; - ParFiniteElementSpace *dfes; - ParGridFunction *coordsDof; - ParGridFunction *elSize; + ParFiniteElementSpace* dfes; + ParGridFunction* coordsDof; + ParGridFunction* elSize; - ParGridFunction *spaceVaryViscMult; - linearlyVaryingVisc &linViscData; + ParGridFunction* spaceVaryViscMult; + linearlyVaryingVisc& linViscData; - Array Me_inv; - Array Me_inv_rad; + Array Me_inv; + Array Me_inv_rad; Vector invMArray; Vector invMArray_rad; Array posDofInvM; // reference to conserved varibales - ParGridFunction *U_; + ParGridFunction* U_; // reference to primitive varibales - ParGridFunction *Up; - ParGridFunction *plasma_conductivity_; - ParGridFunction *joule_heating_; + ParGridFunction* Up; + ParGridFunction* plasma_conductivity_; + ParGridFunction* joule_heating_; // gradients of primitives and associated forms&FE space - ParGridFunction *gradUp; - ParFiniteElementSpace *gradUpfes; + ParGridFunction* gradUp; + ParFiniteElementSpace* gradUpfes; // ParNonlinearForm *gradUp_A; - GradNonLinearForm *gradUp_A; + GradNonLinearForm* gradUp_A; - BCintegrator *bcIntegrator; - ParGridFunction *distance_; + BCintegrator* bcIntegrator; + ParGridFunction* distance_; - Array forcing; + Array forcing; int masaForcingIndex_ = -1; mutable DenseTensor flux; @@ -138,49 +138,49 @@ class RHSoperator : public TimeDependentOperator { void allocateTransferData(); // void GetFlux(const DenseMatrix &state, DenseTensor &flux) const; - void GetFlux(const Vector &state, DenseTensor &flux) const; + void GetFlux(const Vector& state, DenseTensor& flux) const; mutable Vector local_timeDerivatives; - void computeMeanTimeDerivatives(Vector &y) const; + void computeMeanTimeDerivatives(Vector& y) const; public: - RHSoperator(int &_iter, const int _dim, const int &_num_equation, const int &_order, const Equations &_eqSystem, - double &_max_char_speed, IntegrationRules *_intRules, int _intRuleType, Fluxes *_fluxClass, - GasMixture *_mixture, GasMixture *d_mixture, Chemistry *_chemistry, TransportProperties *_transport, - Radiation *_radiation, ParFiniteElementSpace *_vfes, ParFiniteElementSpace *_fes, - const precomputedIntegrationData &gpu_precomputed_data, const int &_maxIntPoints, const int &_maxDofs, - DGNonLinearForm *_A, MixedBilinearForm *_Aflux, ParMesh *_mesh, ParGridFunction *_spaceVaryViscMult, - ParGridFunction *U, ParGridFunction *_Up, ParGridFunction *_gradUp, ParFiniteElementSpace *_gradUpfes, - GradNonLinearForm *_gradUp_A, BCintegrator *_bcIntegrator, RunConfiguration &_config, ParGridFunction *pc, - ParGridFunction *jh, ParGridFunction *distance); - - virtual void Mult(const Vector &x, Vector &y) const; - void updatePrimitives(const Vector &x) const; - void updateGradients(const Vector &x, const bool &primitiveUpdated) const; + RHSoperator(int& _iter, const int _dim, const int& _num_equation, const int& _order, const Equations& _eqSystem, + double& _max_char_speed, IntegrationRules* _intRules, int _intRuleType, Fluxes* _fluxClass, + GasMixture* _mixture, GasMixture* d_mixture, Chemistry* _chemistry, TransportProperties* _transport, + Radiation* _radiation, ParFiniteElementSpace* _vfes, ParFiniteElementSpace* _fes, + const precomputedIntegrationData& gpu_precomputed_data, const int& _maxIntPoints, const int& _maxDofs, + DGNonLinearForm* _A, MixedBilinearForm* _Aflux, ParMesh* _mesh, ParGridFunction* _spaceVaryViscMult, + ParGridFunction* U, ParGridFunction* _Up, ParGridFunction* _gradUp, ParFiniteElementSpace* _gradUpfes, + GradNonLinearForm* _gradUp_A, BCintegrator* _bcIntegrator, RunConfiguration& _config, ParGridFunction* pc, + ParGridFunction* jh, ParGridFunction* distance); + + virtual void Mult(const Vector& x, Vector& y) const; + void updatePrimitives(const Vector& x) const; + void updateGradients(const Vector& x, const bool& primitiveUpdated) const; virtual ~RHSoperator(); - Gradients *getGradients() { return gradients; } - DenseTensor *getFlux() { return &flux; } + Gradients* getGradients() { return gradients; } + DenseTensor* getFlux() { return &flux; } - const double *getLocalTimeDerivatives() { return local_timeDerivatives.HostRead(); } - ForcingTerms *getForcingTerm(const int index) { return forcing[index]; } + const double* getLocalTimeDerivatives() { return local_timeDerivatives.HostRead(); } + ForcingTerms* getForcingTerm(const int index) { return forcing[index]; } int getMasaForcingIndex() { return masaForcingIndex_; } - static void initNBlockDataTransfer(const Vector &x, ParFiniteElementSpace *pfes, dataTransferArrays &dataTransfer); - static void waitAllDataTransfer(ParFiniteElementSpace *pfes, dataTransferArrays &dataTransfer); + static void initNBlockDataTransfer(const Vector& x, ParFiniteElementSpace* pfes, dataTransferArrays& dataTransfer); + static void waitAllDataTransfer(ParFiniteElementSpace* pfes, dataTransferArrays& dataTransfer); // GPU functions - void GetFlux_gpu(const Vector &state, DenseTensor &flux) const; - static void copyZk2Z_gpu(Vector &z, Vector &zk, const int eq, const int dof); - static void copyDataForFluxIntegration_gpu(const Vector &z, DenseTensor &flux, Vector &fk, Vector &zk, const int eq, + void GetFlux_gpu(const Vector& state, DenseTensor& flux) const; + static void copyZk2Z_gpu(Vector& z, Vector& zk, const int eq, const int dof); + static void copyDataForFluxIntegration_gpu(const Vector& z, DenseTensor& flux, Vector& fk, Vector& zk, const int eq, const int dof, const int dim); - static void multiPlyInvers_gpu(Vector &y, Vector &z, const precomputedIntegrationData &gpu_precomputed_data, - const Vector &invMArray, const Array &posDofInvM, const int num_equation, + static void multiPlyInvers_gpu(Vector& y, Vector& z, const precomputedIntegrationData& gpu_precomputed_data, + const Vector& invMArray, const Array& posDofInvM, const int num_equation, const int totNumDof, const int NE, const int elemOffset, const int dof); - static void meanTimeDerivatives_gpu(Vector &y, Vector &local_timeDerivatives, Vector &tmp_vec, const int &NDof, - const int &num_equation, const int &dim); + static void meanTimeDerivatives_gpu(Vector& y, Vector& local_timeDerivatives, Vector& tmp_vec, const int& NDof, + const int& num_equation, const int& dim); }; #endif // RHS_OPERATOR_HPP_ diff --git a/src/riemann_solver.cpp b/src/riemann_solver.cpp index e1e23d09..89dc418b 100644 --- a/src/riemann_solver.cpp +++ b/src/riemann_solver.cpp @@ -35,8 +35,8 @@ using namespace mfem; // Implementation of class RiemannSolverTPS -MFEM_HOST_DEVICE RiemannSolverTPS::RiemannSolverTPS(int _num_equation, GasMixture *_mixture, Equations _eqSystem, - Fluxes *_fluxClass, bool _useRoe, bool axisym) +MFEM_HOST_DEVICE RiemannSolverTPS::RiemannSolverTPS(int _num_equation, GasMixture* _mixture, Equations _eqSystem, + Fluxes* _fluxClass, bool _useRoe, bool axisym) : num_equation(_num_equation), mixture(_mixture), eqSystem(_eqSystem), @@ -45,12 +45,12 @@ MFEM_HOST_DEVICE RiemannSolverTPS::RiemannSolverTPS(int _num_equation, GasMixtur axisymmetric_(axisym) {} // Compute the scalar F(u).n -void RiemannSolverTPS::ComputeFluxDotN(const Vector &state, const Vector &nor, Vector &fluxN) { +void RiemannSolverTPS::ComputeFluxDotN(const Vector& state, const Vector& nor, Vector& fluxN) { ComputeFluxDotN(state.GetData(), nor.GetData(), fluxN.GetData()); } // Compute the scalar F(u).n -MFEM_HOST_DEVICE void RiemannSolverTPS::ComputeFluxDotN(const double *state, const double *nor, double *fluxN) const { +MFEM_HOST_DEVICE void RiemannSolverTPS::ComputeFluxDotN(const double* state, const double* nor, double* fluxN) const { const int dim = mixture->GetDimension(); double fluxes[gpudata::MAXEQUATIONS * gpudata::MAXDIM]; // double fluxes[5 * 3]; @@ -63,7 +63,7 @@ MFEM_HOST_DEVICE void RiemannSolverTPS::ComputeFluxDotN(const double *state, con } } -void RiemannSolverTPS::Eval(const Vector &state1, const Vector &state2, const Vector &nor, Vector &flux, bool LF) { +void RiemannSolverTPS::Eval(const Vector& state1, const Vector& state2, const Vector& nor, Vector& flux, bool LF) { if (useRoe && !LF) { Eval_Roe(state1, state2, nor, flux); } else { @@ -71,8 +71,8 @@ void RiemannSolverTPS::Eval(const Vector &state1, const Vector &state2, const Ve } } -MFEM_HOST_DEVICE void RiemannSolverTPS::Eval(const double *state1, const double *state2, const double *nor, - double *flux, bool LF) { +MFEM_HOST_DEVICE void RiemannSolverTPS::Eval(const double* state1, const double* state2, const double* nor, + double* flux, bool LF) { if (useRoe && !LF) { // TODO(kevin): implement MFEM_HOST_DEVICE Eval_Roe. printf("Roe RiemannSolverTPS is not implmented for gpu!"); @@ -82,12 +82,12 @@ MFEM_HOST_DEVICE void RiemannSolverTPS::Eval(const double *state1, const double } } -void RiemannSolverTPS::Eval_LF(const Vector &state1, const Vector &state2, const Vector &nor, Vector &flux) { +void RiemannSolverTPS::Eval_LF(const Vector& state1, const Vector& state2, const Vector& nor, Vector& flux) { Eval_LF(state1.GetData(), state2.GetData(), nor.GetData(), flux.GetData()); } -MFEM_HOST_DEVICE void RiemannSolverTPS::Eval_LF(const double *state1, const double *state2, const double *nor, - double *flux) const { +MFEM_HOST_DEVICE void RiemannSolverTPS::Eval_LF(const double* state1, const double* state2, const double* nor, + double* flux) const { const int dim = mixture->GetDimension(); const double maxE1 = mixture->ComputeMaxCharSpeed(state1); @@ -114,7 +114,7 @@ MFEM_HOST_DEVICE void RiemannSolverTPS::Eval_LF(const double *state1, const doub } // TODO(kevin): need to write for multiple species and two temperature. -void RiemannSolverTPS::Eval_Roe(const Vector &state1, const Vector &state2, const Vector &nor, Vector &flux) { +void RiemannSolverTPS::Eval_Roe(const Vector& state1, const Vector& state2, const Vector& nor, Vector& flux) { const int dim = nor.Size(); assert(!axisymmetric_); // Roe doesn't support axisymmetric yet diff --git a/src/riemann_solver.hpp b/src/riemann_solver.hpp index eb465aa9..d4f6bbeb 100644 --- a/src/riemann_solver.hpp +++ b/src/riemann_solver.hpp @@ -52,29 +52,29 @@ class RiemannSolverTPS { private: const int num_equation; - GasMixture *mixture; + GasMixture* mixture; Equations eqSystem; - Fluxes *fluxClass; + Fluxes* fluxClass; bool useRoe; const bool axisymmetric_; - void Eval_Roe(const Vector &state1, const Vector &state2, const Vector &nor, Vector &flux); + void Eval_Roe(const Vector& state1, const Vector& state2, const Vector& nor, Vector& flux); public: - MFEM_HOST_DEVICE RiemannSolverTPS(int _num_equation, GasMixture *mixture, Equations _eqSystem, Fluxes *_fluxClass, + MFEM_HOST_DEVICE RiemannSolverTPS(int _num_equation, GasMixture* mixture, Equations _eqSystem, Fluxes* _fluxClass, bool _useRoe, bool axisym); - void Eval(const Vector &state1, const Vector &state2, const Vector &nor, Vector &flux, bool LF = false); - MFEM_HOST_DEVICE void Eval(const double *state1, const double *state2, const double *nor, double *flux, + void Eval(const Vector& state1, const Vector& state2, const Vector& nor, Vector& flux, bool LF = false); + MFEM_HOST_DEVICE void Eval(const double* state1, const double* state2, const double* nor, double* flux, bool LF = false); - void ComputeFluxDotN(const Vector &state, const Vector &nor, Vector &fluxN); + void ComputeFluxDotN(const Vector& state, const Vector& nor, Vector& fluxN); - MFEM_HOST_DEVICE void ComputeFluxDotN(const double *state, const double *nor, double *fluxN) const; + MFEM_HOST_DEVICE void ComputeFluxDotN(const double* state, const double* nor, double* fluxN) const; - void Eval_LF(const Vector &state1, const Vector &state2, const Vector &nor, Vector &flux); - MFEM_HOST_DEVICE void Eval_LF(const double *state1, const double *state2, const double *nor, double *flux) const; + void Eval_LF(const Vector& state1, const Vector& state2, const Vector& nor, Vector& flux); + MFEM_HOST_DEVICE void Eval_LF(const double* state1, const double* state2, const double* nor, double* flux) const; MFEM_HOST_DEVICE bool isAxisymmetric() const { return axisymmetric_; } }; diff --git a/src/solver.hpp b/src/solver.hpp index 87c0923d..09256048 100644 --- a/src/solver.hpp +++ b/src/solver.hpp @@ -80,37 +80,37 @@ class Solver { } /// Initialize the interface - virtual void initInterface(Tps2Boltzmann &interface) { + virtual void initInterface(Tps2Boltzmann& interface) { cout << "ERROR: " << __func__ << " remains unimplemented" << endl; exit(1); } /// Push solver variables to interface - virtual void push(Tps2Boltzmann &interface) { + virtual void push(Tps2Boltzmann& interface) { cout << "ERROR: " << __func__ << " remains unimplemented" << endl; exit(1); } /// Fetch solver variables from interface - virtual void fetch(Tps2Boltzmann &interface) { + virtual void fetch(Tps2Boltzmann& interface) { cout << "ERROR: " << __func__ << " remains unimplemented" << endl; exit(1); } /// Get the mesh used by this Solver - virtual mfem::ParMesh *getMesh() const { + virtual mfem::ParMesh* getMesh() const { cout << "ERROR: " << __func__ << " remains unimplemented" << endl; exit(1); return nullptr; } - virtual const mfem::FiniteElementCollection *getFEC() const { + virtual const mfem::FiniteElementCollection* getFEC() const { cout << "ERROR: " << __func__ << " remains unimplemented" << endl; exit(1); return nullptr; } - virtual mfem::ParFiniteElementSpace *getFESpace() const { + virtual mfem::ParFiniteElementSpace* getFESpace() const { cout << "ERROR: " << __func__ << " remains unimplemented" << endl; exit(1); return nullptr; @@ -123,7 +123,7 @@ class PlasmaSolver : public Solver { virtual ~PlasmaSolver() {} /// Fetch the plasma electrical conductivity grid function - virtual mfem::ParGridFunction *getPlasmaConductivityGF() { + virtual mfem::ParGridFunction* getPlasmaConductivityGF() { cout << "ERROR: " << __func__ << " remains unimplemented" << endl; exit(1); return nullptr; @@ -136,7 +136,7 @@ class PlasmaSolver : public Solver { } /// Fetch the Joule heating grid function - virtual mfem::ParGridFunction *getJouleHeatingGF() { + virtual mfem::ParGridFunction* getJouleHeatingGF() { cout << "ERROR: " << __func__ << " remains unimplemented" << endl; exit(1); return nullptr; diff --git a/src/source_term.cpp b/src/source_term.cpp index 6565dea2..ddfd77ce 100644 --- a/src/source_term.cpp +++ b/src/source_term.cpp @@ -33,12 +33,12 @@ #include -SourceTerm::SourceTerm(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, ParGridFunction *U, - ParGridFunction *_Up, ParGridFunction *_gradUp, - const precomputedIntegrationData &gpu_precomputed_data, RunConfiguration &_config, - GasMixture *mixture, GasMixture *d_mixture, TransportProperties *transport, Chemistry *chemistry, - Radiation *radiation, ParGridFunction *pc, ParGridFunction *distance) +SourceTerm::SourceTerm(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, ParGridFunction* U, + ParGridFunction* _Up, ParGridFunction* _gradUp, + const precomputedIntegrationData& gpu_precomputed_data, RunConfiguration& _config, + GasMixture* mixture, GasMixture* d_mixture, TransportProperties* transport, Chemistry* chemistry, + Radiation* radiation, ParGridFunction* pc, ParGridFunction* distance) : ForcingTerms(_dim, _num_equation, _order, _intRuleType, _intRules, _vfes, U, _Up, _gradUp, gpu_precomputed_data, _config.isAxisymmetric()), mixture_(mixture), @@ -59,40 +59,40 @@ SourceTerm::SourceTerm(const int &_dim, const int &_num_equation, const int &_or SourceTerm::~SourceTerm() {} -void SourceTerm::updateTerms(mfem::Vector &in) { - double *h_pc = NULL; +void SourceTerm::updateTerms(mfem::Vector& in) { + double* h_pc = NULL; #ifdef _GPU_ - const double *h_Up = Up_->Read(); - const double *h_U = U_->Read(); - const double *h_gradUp = gradUp_->Read(); - double *h_in = in.ReadWrite(); + const double* h_Up = Up_->Read(); + const double* h_U = U_->Read(); + const double* h_gradUp = gradUp_->Read(); + double* h_in = in.ReadWrite(); - GasMixture *_mixture = d_mixture_; + GasMixture* _mixture = d_mixture_; if (plasma_conductivity_ != NULL) { h_pc = plasma_conductivity_->Write(); } #else - const double *h_Up = Up_->HostRead(); - const double *h_U = U_->HostRead(); - const double *h_gradUp = gradUp_->HostRead(); - double *h_in = in.HostReadWrite(); + const double* h_Up = Up_->HostRead(); + const double* h_U = U_->HostRead(); + const double* h_gradUp = gradUp_->HostRead(); + double* h_in = in.HostReadWrite(); - GasMixture *_mixture = mixture_; + GasMixture* _mixture = mixture_; if (plasma_conductivity_ != NULL) { h_pc = plasma_conductivity_->HostWrite(); } #endif - const double *d_distance = NULL; + const double* d_distance = NULL; if (distance_ != NULL) { d_distance = distance_->Read(); } - TransportProperties *_transport = transport_; - Chemistry *_chemistry = chemistry_; - Radiation *_radiation = radiation_; + TransportProperties* _transport = transport_; + Chemistry* _chemistry = chemistry_; + Radiation* _radiation = radiation_; const bool _enableRadiation = enableRadiation_; const int nnodes = vfes->GetNDofs(); diff --git a/src/source_term.hpp b/src/source_term.hpp index eb00d69a..514338b6 100644 --- a/src/source_term.hpp +++ b/src/source_term.hpp @@ -74,24 +74,24 @@ class SourceTerm : public ForcingTerms { bool twoTemperature_; bool enableRadiation_; - GasMixture *mixture_ = NULL; - GasMixture *d_mixture_ = NULL; - TransportProperties *transport_ = NULL; - Chemistry *chemistry_ = NULL; - Radiation *radiation_ = NULL; - ParGridFunction *plasma_conductivity_; - ParGridFunction *distance_; + GasMixture* mixture_ = NULL; + GasMixture* d_mixture_ = NULL; + TransportProperties* transport_ = NULL; + Chemistry* chemistry_ = NULL; + Radiation* radiation_ = NULL; + ParGridFunction* plasma_conductivity_; + ParGridFunction* distance_; public: - SourceTerm(const int &_dim, const int &_num_equation, const int &_order, const int &_intRuleType, - IntegrationRules *_intRules, ParFiniteElementSpace *_vfes, ParGridFunction *U, ParGridFunction *_Up, - ParGridFunction *_gradUp, const precomputedIntegrationData &gpuArrays, RunConfiguration &_config, - GasMixture *mixture, GasMixture *d_mixture, TransportProperties *transport, Chemistry *chemistry, - Radiation *radiation, ParGridFunction *pc, ParGridFunction *distance); + SourceTerm(const int& _dim, const int& _num_equation, const int& _order, const int& _intRuleType, + IntegrationRules* _intRules, ParFiniteElementSpace* _vfes, ParGridFunction* U, ParGridFunction* _Up, + ParGridFunction* _gradUp, const precomputedIntegrationData& gpuArrays, RunConfiguration& _config, + GasMixture* mixture, GasMixture* d_mixture, TransportProperties* transport, Chemistry* chemistry, + Radiation* radiation, ParGridFunction* pc, ParGridFunction* distance); ~SourceTerm(); // Terms do not need updating - virtual void updateTerms(Vector &in); + virtual void updateTerms(Vector& in); }; #endif // SOURCE_TERM_HPP_ diff --git a/src/split_flow_base.cpp b/src/split_flow_base.cpp index e4673f52..49c45f27 100644 --- a/src/split_flow_base.cpp +++ b/src/split_flow_base.cpp @@ -36,7 +36,7 @@ using namespace mfem; -ZeroFlow::ZeroFlow(mfem::ParMesh *pmesh, int vorder, TPS::Tps *tps) +ZeroFlow::ZeroFlow(mfem::ParMesh* pmesh, int vorder, TPS::Tps* tps) : pmesh_(pmesh), vorder_(vorder), dim_(pmesh->Dimension()), tpsP_(tps) { // nonzero flow option tpsP_->getInput("loMach/zeroflow/nonzero-flow", nonzero_flow_, false); diff --git a/src/split_flow_base.hpp b/src/split_flow_base.hpp index 0f93f55e..a4cf22b3 100644 --- a/src/split_flow_base.hpp +++ b/src/split_flow_base.hpp @@ -50,30 +50,30 @@ struct spongeToFlow; struct extDataToFlow; struct flowToThermoChem { - const mfem::ParGridFunction *velocity = nullptr; + const mfem::ParGridFunction* velocity = nullptr; bool swirl_supported = false; - const mfem::ParGridFunction *swirl = nullptr; + const mfem::ParGridFunction* swirl = nullptr; }; struct flowToTurbModel { - const mfem::ParGridFunction *velocity = nullptr; + const mfem::ParGridFunction* velocity = nullptr; bool swirl_supported = false; - const mfem::ParGridFunction *swirl = nullptr; - const mfem::ParGridFunction *gradS = nullptr; + const mfem::ParGridFunction* swirl = nullptr; + const mfem::ParGridFunction* gradS = nullptr; - const mfem::ParGridFunction *gradU = nullptr; - const mfem::ParGridFunction *gradV = nullptr; - const mfem::ParGridFunction *gradW = nullptr; + const mfem::ParGridFunction* gradU = nullptr; + const mfem::ParGridFunction* gradV = nullptr; + const mfem::ParGridFunction* gradW = nullptr; }; class FlowBase { protected: - const thermoChemToFlow *thermo_interface_; - const turbModelToFlow *turbModel_interface_; - const spongeToFlow *sponge_interface_; - const extDataToFlow *extData_interface_; + const thermoChemToFlow* thermo_interface_; + const turbModelToFlow* turbModel_interface_; + const spongeToFlow* sponge_interface_; + const extDataToFlow* extData_interface_; public: /// Destructor @@ -83,22 +83,22 @@ class FlowBase { virtual void step() = 0; - virtual mfem::ParGridFunction *getCurrentVelocity() = 0; - virtual mfem::ParGridFunction *getCurrentVelocityGradientU() { return nullptr; } - virtual mfem::ParGridFunction *getCurrentVelocityGradientV() { return nullptr; } - virtual mfem::ParGridFunction *getCurrentVelocityGradientW() { return nullptr; } + virtual mfem::ParGridFunction* getCurrentVelocity() = 0; + virtual mfem::ParGridFunction* getCurrentVelocityGradientU() { return nullptr; } + virtual mfem::ParGridFunction* getCurrentVelocityGradientV() { return nullptr; } + virtual mfem::ParGridFunction* getCurrentVelocityGradientW() { return nullptr; } - void initializeFromThermoChem(thermoChemToFlow *thermo) { thermo_interface_ = thermo; } - void initializeFromTurbModel(turbModelToFlow *turbModel) { turbModel_interface_ = turbModel; } - void initializeFromSponge(spongeToFlow *sponge) { sponge_interface_ = sponge; } - void initializeFromExtData(extDataToFlow *extData) { extData_interface_ = extData; } + void initializeFromThermoChem(thermoChemToFlow* thermo) { thermo_interface_ = thermo; } + void initializeFromTurbModel(turbModelToFlow* turbModel) { turbModel_interface_ = turbModel; } + void initializeFromSponge(spongeToFlow* sponge) { sponge_interface_ = sponge; } + void initializeFromExtData(extDataToFlow* extData) { extData_interface_ = extData; } virtual void initializeOperators() {} - virtual void initializeIO(IODataOrganizer &io) const {} - virtual void initializeViz(mfem::ParaViewDataCollection &pvdc) const {} - virtual void initializeStats(Averaging &average, IODataOrganizer &io, bool continuation) const {} - virtual void computeDissipation(Averaging &average, const int iter) {} + virtual void initializeIO(IODataOrganizer& io) const {} + virtual void initializeViz(mfem::ParaViewDataCollection& pvdc) const {} + virtual void initializeStats(Averaging& average, IODataOrganizer& io, bool continuation) const {} + virtual void computeDissipation(Averaging& average, const int iter) {} virtual void setup() {} @@ -108,7 +108,7 @@ class FlowBase { * Provides a hook for derived classes to pass a set of header * strings that will be printed to the screen */ - virtual void screenHeader(std::vector &header) const { header.resize(0); } + virtual void screenHeader(std::vector& header) const { header.resize(0); } /** * @brief Values for screen dump @@ -116,25 +116,25 @@ class FlowBase { * Provides values that will be printed to the screen at user requested * frequency (as often as each iteration). */ - virtual void screenValues(std::vector &values) { values.resize(0); } + virtual void screenValues(std::vector& values) { values.resize(0); } /// Interface object, provides fields necessary for the thermochemistry model flowToThermoChem toThermoChem_interface_; /// Get interface provided by thermo model - const thermoChemToFlow *getThermoInterface() const { return thermo_interface_; } + const thermoChemToFlow* getThermoInterface() const { return thermo_interface_; } /// Interface object, provides fields necessary for the turbulence model flowToTurbModel toTurbModel_interface_; /// Get interface provided by thermo model - const turbModelToFlow *getTurbModelInterface() const { return turbModel_interface_; } + const turbModelToFlow* getTurbModelInterface() const { return turbModel_interface_; } /// Get interface provided by sponge - const spongeToFlow *getSpongeInterface() const { return sponge_interface_; } + const spongeToFlow* getSpongeInterface() const { return sponge_interface_; } /// Get interface provided by external data - const extDataToFlow *getExtDataInterface() const { return extData_interface_; } + const extDataToFlow* getExtDataInterface() const { return extData_interface_; } /** * @brief A hook to evaluate L2 norm of error @@ -154,21 +154,21 @@ class ZeroFlow final : public FlowBase { // Options bool nonzero_flow_; - mfem::ParMesh *pmesh_; + mfem::ParMesh* pmesh_; const int vorder_; const int dim_; // Options-related structures - TPS::Tps *tpsP_ = nullptr; + TPS::Tps* tpsP_ = nullptr; - mfem::FiniteElementCollection *fec_ = nullptr; - mfem::ParFiniteElementSpace *fes_ = nullptr; - mfem::ParGridFunction *velocity_ = nullptr; - mfem::ParGridFunction *zero_ = nullptr; + mfem::FiniteElementCollection* fec_ = nullptr; + mfem::ParFiniteElementSpace* fes_ = nullptr; + mfem::ParGridFunction* velocity_ = nullptr; + mfem::ParGridFunction* zero_ = nullptr; public: /// Constructor - ZeroFlow(mfem::ParMesh *pmesh, int vorder, TPS::Tps *tps = nullptr); + ZeroFlow(mfem::ParMesh* pmesh, int vorder, TPS::Tps* tps = nullptr); /// Destructor ~ZeroFlow() final; @@ -178,7 +178,7 @@ class ZeroFlow final : public FlowBase { /// Velocity is always zero, so nothing to do void step() {} - mfem::ParGridFunction *getCurrentVelocity() final { return velocity_; } + mfem::ParGridFunction* getCurrentVelocity() final { return velocity_; } }; #endif // SPLIT_FLOW_BASE_HPP_ diff --git a/src/sponge_base.cpp b/src/sponge_base.cpp index 34df5361..2d5bad9d 100644 --- a/src/sponge_base.cpp +++ b/src/sponge_base.cpp @@ -34,7 +34,7 @@ using namespace mfem; -UnitySponge::UnitySponge(ParMesh *pmesh, int sorder) : pmesh_(pmesh), sorder_(sorder) {} +UnitySponge::UnitySponge(ParMesh* pmesh, int sorder) : pmesh_(pmesh), sorder_(sorder) {} UnitySponge::~UnitySponge() { delete multiplier_; diff --git a/src/sponge_base.hpp b/src/sponge_base.hpp index 5603b15e..05a104cf 100644 --- a/src/sponge_base.hpp +++ b/src/sponge_base.hpp @@ -42,7 +42,7 @@ * viscousSponge to the flow. */ struct spongeToFlow { - const mfem::ParGridFunction *visc_multiplier = nullptr; + const mfem::ParGridFunction* visc_multiplier = nullptr; }; /** @@ -50,7 +50,7 @@ struct spongeToFlow { * visc sponge to the thermo chem model. */ struct spongeToThermoChem { - const mfem::ParGridFunction *diff_multiplier = nullptr; + const mfem::ParGridFunction* diff_multiplier = nullptr; }; /** @@ -58,7 +58,7 @@ struct spongeToThermoChem { * visc sponge to the turbulence model. */ struct spongeToTurbModel { - const mfem::ParGridFunction *diff_multiplier = nullptr; + const mfem::ParGridFunction* diff_multiplier = nullptr; }; /** @@ -83,7 +83,7 @@ class SpongeBase { /** * @brief Hook to let derived classes register visualization fields with ParaViewDataCollection */ - virtual void initializeViz(mfem::ParaViewDataCollection &pvdc) {} + virtual void initializeViz(mfem::ParaViewDataCollection& pvdc) {} /** * @brief Take a single time step @@ -109,13 +109,13 @@ class SpongeBase { */ class UnitySponge final : public SpongeBase { protected: - mfem::ParMesh *pmesh_; + mfem::ParMesh* pmesh_; const int sorder_; - mfem::FiniteElementCollection *fec_ = nullptr; - mfem::ParFiniteElementSpace *fes_ = nullptr; + mfem::FiniteElementCollection* fec_ = nullptr; + mfem::ParFiniteElementSpace* fes_ = nullptr; - mfem::ParGridFunction *multiplier_ = nullptr; + mfem::ParGridFunction* multiplier_ = nullptr; public: /** @@ -127,7 +127,7 @@ class UnitySponge final : public SpongeBase { * @param sorder The polynomial order for scalar fields * @param viscMult The (unity) value to use for enhancing viscosity */ - UnitySponge(mfem::ParMesh *pmesh, int sorder); + UnitySponge(mfem::ParMesh* pmesh, int sorder); /// Free the interface fields and support objects ~UnitySponge() final; diff --git a/src/static_rans.cpp b/src/static_rans.cpp index 3449b6cf..520a6f76 100644 --- a/src/static_rans.cpp +++ b/src/static_rans.cpp @@ -37,7 +37,7 @@ using namespace mfem; -StaticRans::StaticRans(ParMesh *pmesh, const Array &partitioning, int order, TPS::Tps *tps) +StaticRans::StaticRans(ParMesh* pmesh, const Array& partitioning, int order, TPS::Tps* tps) : pmesh_(pmesh), order_(order) { // tps->getInput("loMach/static-rans/visc-file", visc_file_); @@ -66,7 +66,7 @@ void StaticRans::initializeSelf() { nut_field_ = new GridFunctionCoefficient(extData_interface_->NuTdata); } -void StaticRans::initializeViz(mfem::ParaViewDataCollection &pvdc) { pvdc.RegisterField("muT", mut_); } +void StaticRans::initializeViz(mfem::ParaViewDataCollection& pvdc) { pvdc.RegisterField("muT", mut_); } void StaticRans::step() { mut_->ProjectCoefficient(*nut_field_); diff --git a/src/static_rans.hpp b/src/static_rans.hpp index a3d864e6..332c8b87 100644 --- a/src/static_rans.hpp +++ b/src/static_rans.hpp @@ -47,24 +47,24 @@ */ class StaticRans : public TurbModelBase { protected: - mfem::ParMesh *pmesh_ = nullptr; + mfem::ParMesh* pmesh_ = nullptr; int order_; int dim_; bool axisym_; - mfem::FiniteElementCollection *sfec_ = nullptr; - mfem::ParFiniteElementSpace *sfes_ = nullptr; + mfem::FiniteElementCollection* sfec_ = nullptr; + mfem::ParFiniteElementSpace* sfes_ = nullptr; - mfem::ParGridFunction *mut_ = nullptr; - mfem::GridFunctionCoefficient *nut_field_ = nullptr; + mfem::ParGridFunction* mut_ = nullptr; + mfem::GridFunctionCoefficient* nut_field_ = nullptr; - ExternalDataBase *extData_ = nullptr; + ExternalDataBase* extData_ = nullptr; public: /// Constructor // StaticRans(mfem::Mesh *smesh, mfem::ParMesh *pmesh, const mfem::Array &partitioning, int order, TPS::Tps // *tps); - StaticRans(mfem::ParMesh *pmesh, const mfem::Array &partitioning, int order, TPS::Tps *tps); + StaticRans(mfem::ParMesh* pmesh, const mfem::Array& partitioning, int order, TPS::Tps* tps); /// Destructor virtual ~StaticRans(); @@ -79,7 +79,7 @@ class StaticRans : public TurbModelBase { /** * @brief Add eddy viscosity and distance function to the visualization output */ - void initializeViz(mfem::ParaViewDataCollection &pvdc) override; + void initializeViz(mfem::ParaViewDataCollection& pvdc) override; /** * @brief Initialize the eddy viscosity. @@ -98,7 +98,7 @@ class StaticRans : public TurbModelBase { */ void setup() override {} - mfem::ParGridFunction *getCurrentEddyViscosity() override { return mut_; } + mfem::ParGridFunction* getCurrentEddyViscosity() override { return mut_; } }; #endif // STATIC_RANS_HPP_ diff --git a/src/table.cpp b/src/table.cpp index 325c68b6..f6fd1fe4 100644 --- a/src/table.cpp +++ b/src/table.cpp @@ -36,8 +36,8 @@ using namespace std; -MFEM_HOST_DEVICE TableInterpolator::TableInterpolator(const int &Ndata, const double *xdata, const double *fdata, - const bool &xLogScale, const bool &fLogScale) +MFEM_HOST_DEVICE TableInterpolator::TableInterpolator(const int& Ndata, const double* xdata, const double* fdata, + const bool& xLogScale, const bool& fLogScale) : Ndata_(Ndata), xLogScale_(xLogScale), fLogScale_(fLogScale) { assert((xdata != NULL) && (fdata != NULL)); for (int k = 0; k < Ndata_; k++) { @@ -49,7 +49,7 @@ MFEM_HOST_DEVICE TableInterpolator::TableInterpolator(const int &Ndata, const do // Find the data interval where the input value lies within. // The algorithm is a copy version of std::upper_bound, which is similar to binary search. // This has O(log_2(Ndata)) complexity. -MFEM_HOST_DEVICE int TableInterpolator::findInterval(const double &xEval) { +MFEM_HOST_DEVICE int TableInterpolator::findInterval(const double& xEval) { int count = Ndata_; int first = 0; int it, step; @@ -76,7 +76,7 @@ MFEM_HOST_DEVICE int TableInterpolator::findInterval(const double &xEval) { //////// Linear interpolation ////////////////////////////////////////////////////// -MFEM_HOST_DEVICE LinearTable::LinearTable(const TableInput &input) +MFEM_HOST_DEVICE LinearTable::LinearTable(const TableInput& input) : TableInterpolator(input.Ndata, input.xdata, input.fdata, input.xLogScale, input.fLogScale) { assert(input.order == 1); for (int k = 0; k < Ndata_ - 1; k++) { @@ -87,7 +87,7 @@ MFEM_HOST_DEVICE LinearTable::LinearTable(const TableInput &input) } } -MFEM_HOST_DEVICE double LinearTable::eval(const double &xEval) { +MFEM_HOST_DEVICE double LinearTable::eval(const double& xEval) { int index = findInterval(xEval); double xt = (xLogScale_) ? log(xEval) : xEval; double ft = a_[index] + b_[index] * xt; @@ -96,7 +96,7 @@ MFEM_HOST_DEVICE double LinearTable::eval(const double &xEval) { return ft; } -MFEM_HOST_DEVICE double LinearTable::eval_x(const double &xEval) { +MFEM_HOST_DEVICE double LinearTable::eval_x(const double& xEval) { const int index = findInterval(xEval); const double xt = (xLogScale_) ? log(xEval) : xEval; const double xt_xt = (xLogScale_) ? 1. / xEval : 1.0; @@ -174,7 +174,7 @@ GslTableInterpolator2D::GslTableInterpolator2D(std::string plato_file, int xcol, assert(fcol >= 0 && fcol < ncol); // open plato file - FILE *table_input_file; + FILE* table_input_file; table_input_file = fopen(plato_file.c_str(), "r"); if (!table_input_file) { std::cout << "Unable to open " << plato_file << std::endl; @@ -191,7 +191,7 @@ GslTableInterpolator2D::GslTableInterpolator2D(std::string plato_file, int xcol, // read data // char stmp; - double *ftmp = new double[ncol]; + double* ftmp = new double[ncol]; for (unsigned int jj = 0; jj < ny_; ++jj) { for (unsigned int ii = 0; ii < nx_; ++ii) { ierr = 0; @@ -226,8 +226,8 @@ GslTableInterpolator2D::GslTableInterpolator2D(std::string plato_file, int xcol, * Initializes data using input pointers. Allocates and initializes * all required GSL objects. */ -GslTableInterpolator2D::GslTableInterpolator2D(unsigned int nx, unsigned int ny, const double *xdata, - const double *ydata, const double *fdata) +GslTableInterpolator2D::GslTableInterpolator2D(unsigned int nx, unsigned int ny, const double* xdata, + const double* ydata, const double* fdata) : TableInterpolator2D(nx, ny), itype_(gsl_interp2d_bilinear) { for (unsigned int i = 0; i < nx_; ++i) { xdata_[i] = xdata[i]; diff --git a/src/table.hpp b/src/table.hpp index 6a9ef012..de6a41ec 100644 --- a/src/table.hpp +++ b/src/table.hpp @@ -49,12 +49,12 @@ class TableInterface { public: MFEM_HOST_DEVICE TableInterface() {} MFEM_HOST_DEVICE virtual ~TableInterface() {} - MFEM_HOST_DEVICE virtual double eval(const double &xEval) = 0; - MFEM_HOST_DEVICE virtual double eval(const double &xEval, const double &yEval) = 0; + MFEM_HOST_DEVICE virtual double eval(const double& xEval) = 0; + MFEM_HOST_DEVICE virtual double eval(const double& xEval, const double& yEval) = 0; - MFEM_HOST_DEVICE virtual double eval_x(const double &xEval) = 0; - MFEM_HOST_DEVICE virtual double eval_x(const double &xEval, const double &yEval) = 0; - MFEM_HOST_DEVICE virtual double eval_y(const double &xEval, const double &yEval) = 0; + MFEM_HOST_DEVICE virtual double eval_x(const double& xEval) = 0; + MFEM_HOST_DEVICE virtual double eval_x(const double& xEval, const double& yEval) = 0; + MFEM_HOST_DEVICE virtual double eval_y(const double& xEval, const double& yEval) = 0; }; class TableInterpolator : public TableInterface { @@ -67,12 +67,12 @@ class TableInterpolator : public TableInterface { bool fLogScale_; public: - MFEM_HOST_DEVICE TableInterpolator(const int &Ndata, const double *xdata, const double *fdata, const bool &xLogScale, - const bool &fLogScale); + MFEM_HOST_DEVICE TableInterpolator(const int& Ndata, const double* xdata, const double* fdata, const bool& xLogScale, + const bool& fLogScale); MFEM_HOST_DEVICE virtual ~TableInterpolator() {} - MFEM_HOST_DEVICE int findInterval(const double &xEval); + MFEM_HOST_DEVICE int findInterval(const double& xEval); }; ////////////////////////////////////////////////////// @@ -86,17 +86,17 @@ class LinearTable : public TableInterpolator { double b_[gpudata::MAXTABLE]; public: - MFEM_HOST_DEVICE LinearTable(const TableInput &input); + MFEM_HOST_DEVICE LinearTable(const TableInput& input); MFEM_HOST_DEVICE virtual ~LinearTable() {} - MFEM_HOST_DEVICE double eval(const double &xEval) final; - MFEM_HOST_DEVICE double eval(const double &xEval, const double &yEval) final { return eval(xEval); } + MFEM_HOST_DEVICE double eval(const double& xEval) final; + MFEM_HOST_DEVICE double eval(const double& xEval, const double& yEval) final { return eval(xEval); } - MFEM_HOST_DEVICE double eval_x(const double &xEval) final; - MFEM_HOST_DEVICE double eval_x(const double &xEval, const double &yEval) final { return eval_x(xEval); } + MFEM_HOST_DEVICE double eval_x(const double& xEval) final; + MFEM_HOST_DEVICE double eval_x(const double& xEval, const double& yEval) final { return eval_x(xEval); } - MFEM_HOST_DEVICE double eval_y(const double &xEval, const double &yEval) final { + MFEM_HOST_DEVICE double eval_y(const double& xEval, const double& yEval) final { assert(false); return nan(""); } @@ -109,9 +109,9 @@ class LinearTable : public TableInterpolator { */ class TableInterpolator2D : public TableInterface { protected: - double *xdata_; - double *ydata_; - double *fdata_; + double* xdata_; + double* ydata_; + double* fdata_; unsigned int nx_; unsigned int ny_; @@ -124,29 +124,29 @@ class TableInterpolator2D : public TableInterface { /// Reset size and re-allocate data arrays MFEM_HOST_DEVICE void resize(unsigned int nx, unsigned int ny); - MFEM_HOST_DEVICE double eval(const double &xEval) final { + MFEM_HOST_DEVICE double eval(const double& xEval) final { assert(false); return nan(""); } - MFEM_HOST_DEVICE double eval_x(const double &xEval) final { + MFEM_HOST_DEVICE double eval_x(const double& xEval) final { assert(false); return nan(""); } /// Interpolate fcn to (x,y) --- must be implemented in derived class - MFEM_HOST_DEVICE double eval(const double &x, const double &y) override { + MFEM_HOST_DEVICE double eval(const double& x, const double& y) override { printf("TableInterpolator2D not initialized!"); return -1.0; } /// Derivative of interpolant wrt x - MFEM_HOST_DEVICE double eval_x(const double &x, const double &y) override { + MFEM_HOST_DEVICE double eval_x(const double& x, const double& y) override { printf("TableInterpolator2D not initialized!"); return -1.0; } /// Derivative of interpolant wrt y - MFEM_HOST_DEVICE double eval_y(const double &x, const double &y) override { + MFEM_HOST_DEVICE double eval_y(const double& x, const double& y) override { printf("TableInterpolator2D not initialized!"); return -1.0; } @@ -164,26 +164,26 @@ class TableInterpolator2D : public TableInterface { */ class GslTableInterpolator2D : public TableInterpolator2D { protected: - const gsl_interp2d_type *itype_; - gsl_spline2d *spline_; + const gsl_interp2d_type* itype_; + gsl_spline2d* spline_; gsl_interp_accel *xacc_, *yacc_; public: GslTableInterpolator2D(std::string plato_file, int xcol, int ycol, int fcol, int ncol = 11); - GslTableInterpolator2D(unsigned int nx, unsigned int ny, const double *xdata, const double *ydata, - const double *fdata); + GslTableInterpolator2D(unsigned int nx, unsigned int ny, const double* xdata, const double* ydata, + const double* fdata); virtual ~GslTableInterpolator2D(); /// Interpolate function to (x,y) using GSL - virtual double eval(const double &x, const double &y) { return gsl_spline2d_eval(spline_, x, y, xacc_, yacc_); } + virtual double eval(const double& x, const double& y) { return gsl_spline2d_eval(spline_, x, y, xacc_, yacc_); } /// Derivative of GSL interpolant wrt x - virtual double eval_x(const double &x, const double &y) { + virtual double eval_x(const double& x, const double& y) { return gsl_spline2d_eval_deriv_x(spline_, x, y, xacc_, yacc_); } /// Derivative of GSL interpolant wrt y - virtual double eval_y(const double &x, const double &y) { + virtual double eval_y(const double& x, const double& y) { return gsl_spline2d_eval_deriv_y(spline_, x, y, xacc_, yacc_); } }; diff --git a/src/thermo_chem_base.cpp b/src/thermo_chem_base.cpp index 121a7862..2868568b 100644 --- a/src/thermo_chem_base.cpp +++ b/src/thermo_chem_base.cpp @@ -36,10 +36,10 @@ using namespace mfem; -ConstantPropertyThermoChem::ConstantPropertyThermoChem(ParMesh *pmesh, int sorder, double rho, double mu) +ConstantPropertyThermoChem::ConstantPropertyThermoChem(ParMesh* pmesh, int sorder, double rho, double mu) : pmesh_(pmesh), sorder_(sorder), rho_(rho), mu_(mu) {} -ConstantPropertyThermoChem::ConstantPropertyThermoChem(ParMesh *pmesh, int sorder, TPS::Tps *tps) +ConstantPropertyThermoChem::ConstantPropertyThermoChem(ParMesh* pmesh, int sorder, TPS::Tps* tps) : pmesh_(pmesh), sorder_(sorder) { assert(tps != nullptr); tps->getInput("loMach/constprop/rho", rho_, 1.0); diff --git a/src/thermo_chem_base.hpp b/src/thermo_chem_base.hpp index e2edbc65..1a05f33f 100644 --- a/src/thermo_chem_base.hpp +++ b/src/thermo_chem_base.hpp @@ -53,9 +53,9 @@ struct extDataToThermoChem; * thermochemistry model to the flow. */ struct thermoChemToFlow { - const mfem::ParGridFunction *density = nullptr; - const mfem::ParGridFunction *viscosity = nullptr; - const mfem::ParGridFunction *thermal_divergence = nullptr; + const mfem::ParGridFunction* density = nullptr; + const mfem::ParGridFunction* viscosity = nullptr; + const mfem::ParGridFunction* thermal_divergence = nullptr; }; /** @@ -63,8 +63,8 @@ struct thermoChemToFlow { * thermochemistry model to the flow. */ struct thermoChemToTurbModel { - const mfem::ParGridFunction *density = nullptr; - const mfem::ParGridFunction *viscosity = nullptr; + const mfem::ParGridFunction* density = nullptr; + const mfem::ParGridFunction* viscosity = nullptr; }; /** @@ -74,15 +74,15 @@ struct thermoChemToTurbModel { */ class ThermoChemModelBase { protected: - const flowToThermoChem *flow_interface_; - const turbModelToThermoChem *turbModel_interface_; - const spongeToThermoChem *sponge_interface_; - const extDataToThermoChem *extData_interface_; + const flowToThermoChem* flow_interface_; + const turbModelToThermoChem* turbModel_interface_; + const spongeToThermoChem* sponge_interface_; + const extDataToThermoChem* extData_interface_; double thermo_pressure_; - mfem::ParGridFunction *plasma_conductivity_gf_ = nullptr; - mfem::ParGridFunction *joule_heating_gf_ = nullptr; + mfem::ParGridFunction* plasma_conductivity_gf_ = nullptr; + mfem::ParGridFunction* joule_heating_gf_ = nullptr; public: /// Destructor @@ -118,17 +118,17 @@ class ThermoChemModelBase { /** * @brief Hook to let derived classes register restart fields with the IODataOrganizer. */ - virtual void initializeIO(IODataOrganizer &io) {} + virtual void initializeIO(IODataOrganizer& io) {} /** * @brief Hook to let derived classes register visualization fields with ParaViewDataCollection */ - virtual void initializeViz(mfem::ParaViewDataCollection &pvdc) {} + virtual void initializeViz(mfem::ParaViewDataCollection& pvdc) {} /** * @brief Hook to let averaging register fields and restart fields with the IODataOrganizer. */ - virtual void initializeStats(Averaging &average, IODataOrganizer &io, bool continuation) {} + virtual void initializeStats(Averaging& average, IODataOrganizer& io, bool continuation) {} /** * @brief Header strings for screen dump @@ -136,7 +136,7 @@ class ThermoChemModelBase { * Provides a hook for derived classes to pass a set of header * strings that will be printed to the screen */ - virtual void screenHeader(std::vector &header) const { header.resize(0); } + virtual void screenHeader(std::vector& header) const { header.resize(0); } /** * @brief Values for screen dump @@ -144,7 +144,7 @@ class ThermoChemModelBase { * Provides values that will be printed to the screen at user requested * frequency (as often as each iteration). */ - virtual void screenValues(std::vector &values) { values.resize(0); } + virtual void screenValues(std::vector& values) { values.resize(0); } /** * @brief Initialize data from the flow class @@ -152,10 +152,10 @@ class ThermoChemModelBase { * Initialize fields that the thermochemistry model needs from the * flow. */ - void initializeFromFlow(flowToThermoChem *flow) { flow_interface_ = flow; } + void initializeFromFlow(flowToThermoChem* flow) { flow_interface_ = flow; } /// Get interface provided by flow model - const flowToThermoChem *getFlowInterface() const { return flow_interface_; } + const flowToThermoChem* getFlowInterface() const { return flow_interface_; } /// Interface object, provides fields necessary for the flow thermoChemToFlow toFlow_interface_; @@ -166,10 +166,10 @@ class ThermoChemModelBase { * Initialize fields that the thermochemistry model needs from the * turbulence model. */ - void initializeFromTurbModel(turbModelToThermoChem *turbModel) { turbModel_interface_ = turbModel; } + void initializeFromTurbModel(turbModelToThermoChem* turbModel) { turbModel_interface_ = turbModel; } /// Get interface provided by turb model - const turbModelToThermoChem *getTurbModelInterface() const { return turbModel_interface_; } + const turbModelToThermoChem* getTurbModelInterface() const { return turbModel_interface_; } /// Interface object, provides fields necessary for the turbModel thermoChemToTurbModel toTurbModel_interface_; @@ -180,20 +180,20 @@ class ThermoChemModelBase { * Initialize fields that the thermochemistry model needs from the * sponge class. */ - void initializeFromSponge(spongeToThermoChem *sponge) { sponge_interface_ = sponge; } + void initializeFromSponge(spongeToThermoChem* sponge) { sponge_interface_ = sponge; } /// Get interface provided by flow model - const spongeToThermoChem *getSpongeInterface() const { return sponge_interface_; } + const spongeToThermoChem* getSpongeInterface() const { return sponge_interface_; } - void initializeFromExtData(extDataToThermoChem *extData) { extData_interface_ = extData; } - const extDataToThermoChem *getExtDataInterface() const { return extData_interface_; } + void initializeFromExtData(extDataToThermoChem* extData) { extData_interface_ = extData; } + const extDataToThermoChem* getExtDataInterface() const { return extData_interface_; } /// Return thermodynamic pressure for restarts double GetThermoPressure() { return thermo_pressure_; } - void SetThermoPressure(double &Po) { thermo_pressure_ = Po; } + void SetThermoPressure(double& Po) { thermo_pressure_ = Po; } - mfem::ParGridFunction *getPlasmaConductivityGF() { return plasma_conductivity_gf_; } - mfem::ParGridFunction *getJouleHeatingGF() { return joule_heating_gf_; } + mfem::ParGridFunction* getPlasmaConductivityGF() { return plasma_conductivity_gf_; } + mfem::ParGridFunction* getJouleHeatingGF() { return joule_heating_gf_; } virtual void evaluatePlasmaConductivityGF() { std::cout << "ERROR: " << __func__ << " remains unimplemented" << std::endl; exit(1); @@ -206,17 +206,17 @@ class ThermoChemModelBase { */ class ConstantPropertyThermoChem final : public ThermoChemModelBase { protected: - mfem::ParMesh *pmesh_; + mfem::ParMesh* pmesh_; const int sorder_; double rho_; double mu_; - mfem::FiniteElementCollection *fec_ = nullptr; - mfem::ParFiniteElementSpace *fes_ = nullptr; + mfem::FiniteElementCollection* fec_ = nullptr; + mfem::ParFiniteElementSpace* fes_ = nullptr; - mfem::ParGridFunction *density_ = nullptr; - mfem::ParGridFunction *viscosity_ = nullptr; - mfem::ParGridFunction *thermal_divergence_ = nullptr; + mfem::ParGridFunction* density_ = nullptr; + mfem::ParGridFunction* viscosity_ = nullptr; + mfem::ParGridFunction* thermal_divergence_ = nullptr; public: /** @@ -229,7 +229,7 @@ class ConstantPropertyThermoChem final : public ThermoChemModelBase { * @param rho The (constant) value to use for the density * @param mu The (constant) value to use for the viscosity */ - ConstantPropertyThermoChem(mfem::ParMesh *pmesh, int sorder, double rho, double mu); + ConstantPropertyThermoChem(mfem::ParMesh* pmesh, int sorder, double rho, double mu); /** * @brief Constructor @@ -238,7 +238,7 @@ class ConstantPropertyThermoChem final : public ThermoChemModelBase { * @param sorder The polynomial order for scalar fields * @param tps Pointer to Tps object so that rho and mu can be obtained from input file */ - ConstantPropertyThermoChem(mfem::ParMesh *pmesh, int sorder, TPS::Tps *tps); + ConstantPropertyThermoChem(mfem::ParMesh* pmesh, int sorder, TPS::Tps* tps); /// Free the interface fields and support objects ~ConstantPropertyThermoChem() final; diff --git a/src/tomboulides.cpp b/src/tomboulides.cpp index 80e08a59..dd06440a 100644 --- a/src/tomboulides.cpp +++ b/src/tomboulides.cpp @@ -46,16 +46,16 @@ using namespace mfem; /// forward declarations -static double radius(const Vector &pos) { return pos[0]; } +static double radius(const Vector& pos) { return pos[0]; } FunctionCoefficient radius_coeff(radius); -static double negativeRadius(const Vector &pos) { return -pos[0]; } +static double negativeRadius(const Vector& pos) { return -pos[0]; } FunctionCoefficient negative_radius_coeff(negativeRadius); /** * @brief Helper function to remove mean from a vector */ -void Orthogonalize(Vector &v, const ParFiniteElementSpace *pfes) { +void Orthogonalize(Vector& v, const ParFiniteElementSpace* pfes) { double loc_sum = v.Sum(); double global_sum = 0.0; int loc_size = v.Size(); @@ -67,8 +67,8 @@ void Orthogonalize(Vector &v, const ParFiniteElementSpace *pfes) { v -= global_sum / static_cast(global_size); } -Tomboulides::Tomboulides(mfem::ParMesh *pmesh, int vorder, int porder, temporalSchemeCoefficients &coeff, - mfem::ParGridFunction *gridScale, TPS::Tps *tps) +Tomboulides::Tomboulides(mfem::ParMesh* pmesh, int vorder, int porder, temporalSchemeCoefficients& coeff, + mfem::ParGridFunction* gridScale, TPS::Tps* tps) : gll_rules(0, Quadrature1D::GaussLobatto), tpsP_(tps), pmesh_(pmesh), @@ -568,7 +568,7 @@ void Tomboulides::initializeSelf() { int iFace = vfes_->GetMesh()->GetBdrElementFaceIndex(bel); // FaceElementTransformations *Tr = vfes_->GetMesh()->GetBdrFaceTransformations(bel); // ElementTransformation *Tr = vfes_->GetMesh()->GetBdrElementTransformation(bel); - ElementTransformation *Tr = vfes_->GetMesh()->GetFaceTransformation(iFace); + ElementTransformation* Tr = vfes_->GetMesh()->GetFaceTransformation(iFace); // changing order from 1 const IntegrationRule ir = gll_rules.Get(Tr->GetGeometryType(), 2 * vorder_ - 1); @@ -961,8 +961,8 @@ void Tomboulides::initializeOperators() { // Gauss-Lobatto quad pts correspond to the Gauss-Lobatto nodes. // For most terms this will result in an under-integration, but it // has the nice consequence that the mass matrix is diagonal. - const IntegrationRule &ir_ni_v = gll_rules.Get(vfes_->GetFE(0)->GetGeomType(), 2 * vorder_ - 1); - const IntegrationRule &ir_ni_p = gll_rules.Get(pfes_->GetFE(0)->GetGeomType(), 2 * porder_ - 1); + const IntegrationRule& ir_ni_v = gll_rules.Get(vfes_->GetFE(0)->GetGeomType(), 2 * vorder_ - 1); + const IntegrationRule& ir_ni_p = gll_rules.Get(pfes_->GetFE(0)->GetGeomType(), 2 * porder_ - 1); // Empty array, use where we want operators without BCs Array empty; @@ -978,7 +978,7 @@ void Tomboulides::initializeOperators() { // Variable coefficient Laplacian: \nabla \cdot ( (1/\rho) \nabla ) L_iorho_form_ = new ParBilinearForm(pfes_); - auto *L_iorho_blfi = new DiffusionIntegrator(*iorho_coeff_); + auto* L_iorho_blfi = new DiffusionIntegrator(*iorho_coeff_); if (numerical_integ_) { L_iorho_blfi->SetIntRule(&ir_ni_p); } @@ -1020,8 +1020,8 @@ void Tomboulides::initializeOperators() { // Forcing term in the velocity equation: du/dt + ... = ... + f forcing_form_ = new ParLinearForm(vfes_); - for (auto &force : forcing_terms_) { - auto *fdlfi = new VectorDomainLFIntegrator(*force.coeff); + for (auto& force : forcing_terms_) { + auto* fdlfi = new VectorDomainLFIntegrator(*force.coeff); if (numerical_integ_) { fdlfi->SetIntRule(&ir_ni_v); } @@ -1032,7 +1032,7 @@ void Tomboulides::initializeOperators() { // Coefficient is -1 so we can just add to rhs nlcoeff_.constant = -1.0; Nconv_form_ = new ParNonlinearForm(vfes_); - VectorConvectionNLFIntegrator *nlc_nlfi; + VectorConvectionNLFIntegrator* nlc_nlfi; if (axisym_) { nlc_nlfi = new VectorConvectionNLFIntegrator(negative_radius_coeff); } else { @@ -1053,7 +1053,7 @@ void Tomboulides::initializeOperators() { // pressure space and the Q space are the same. Need to assert this // somehow. Ms_form_ = new ParBilinearForm(pfes_); - MassIntegrator *ms_blfi; + MassIntegrator* ms_blfi; if (axisym_) { ms_blfi = new MassIntegrator(radius_coeff); } else { @@ -1070,7 +1070,7 @@ void Tomboulides::initializeOperators() { Ms_form_->FormSystemMatrix(empty, Ms_op_); Ms_rho_form_ = new ParBilinearForm(pfes_); - MassIntegrator *msr_blfi; + MassIntegrator* msr_blfi; if (axisym_) { msr_blfi = new MassIntegrator(*rad_rho_coeff_); } else { @@ -1085,7 +1085,7 @@ void Tomboulides::initializeOperators() { // Mass matrix for the velocity Mv_form_ = new ParBilinearForm(vfes_); - VectorMassIntegrator *mv_blfi; + VectorMassIntegrator* mv_blfi; if (axisym_) { mv_blfi = new VectorMassIntegrator(radius_coeff); } else { @@ -1103,7 +1103,7 @@ void Tomboulides::initializeOperators() { // Mass matrix (density weighted) for the velocity Mv_rho_form_ = new ParBilinearForm(vfes_); - VectorMassIntegrator *mvr_blfi; + VectorMassIntegrator* mvr_blfi; if (axisym_) { mvr_blfi = new VectorMassIntegrator(*rad_rho_coeff_); } else { @@ -1119,7 +1119,7 @@ void Tomboulides::initializeOperators() { // Vector mass matrix for streamwise stability of the velocity gradients if (sw_stab_) { Mv_stab_form_ = new ParBilinearForm(vfes_); - VectorMassIntegrator *mvs_blfi; + VectorMassIntegrator* mvs_blfi; mvs_blfi = new VectorMassIntegrator(*supg_coeff_); if (numerical_integ_) { mvs_blfi->SetIntRule(&ir_ni_v); @@ -1136,9 +1136,9 @@ void Tomboulides::initializeOperators() { Mv_inv_pc_ = new OperatorJacobiSmoother(diag_pa, empty); } else { Mv_inv_pc_ = new HypreSmoother(*Mv_op_.As()); - dynamic_cast(Mv_inv_pc_)->SetType(smoother_type_, smoother_passes_); - dynamic_cast(Mv_inv_pc_)->SetSOROptions(smoother_relax_weight_, smoother_relax_omega_); - dynamic_cast(Mv_inv_pc_) + dynamic_cast(Mv_inv_pc_)->SetType(smoother_type_, 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()); @@ -1151,9 +1151,9 @@ void Tomboulides::initializeOperators() { Mv_inv_->SetMaxIter(mass_inverse_max_iter_); Mv_rho_inv_pc_ = new HypreSmoother(*Mv_rho_op_.As()); - dynamic_cast(Mv_rho_inv_pc_)->SetType(smoother_type_, smoother_passes_); - dynamic_cast(Mv_rho_inv_pc_)->SetSOROptions(smoother_relax_weight_, smoother_relax_omega_); - dynamic_cast(Mv_rho_inv_pc_) + dynamic_cast(Mv_rho_inv_pc_)->SetType(smoother_type_, smoother_passes_); + dynamic_cast(Mv_rho_inv_pc_)->SetSOROptions(smoother_relax_weight_, smoother_relax_omega_); + dynamic_cast(Mv_rho_inv_pc_) ->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, smoother_eig_est_); Mv_rho_inv_ = new CGSolver(vfes_->GetComm()); @@ -1167,7 +1167,7 @@ void Tomboulides::initializeOperators() { // Divergence operator D_form_ = new ParMixedBilinearForm(vfes_, pfes_); - VectorDivergenceIntegrator *vd_mblfi; + VectorDivergenceIntegrator* vd_mblfi; if (axisym_) { vd_mblfi = new VectorDivergenceIntegrator(radius_coeff); } else { @@ -1186,7 +1186,7 @@ void Tomboulides::initializeOperators() { // Gradient G_form_ = new ParMixedBilinearForm(pfes_, vfes_); // auto *g_mblfi = new GradientIntegrator(); - GradientIntegrator *g_mblfi; + GradientIntegrator* g_mblfi; if (axisym_) { g_mblfi = new GradientIntegrator(radius_coeff); } else { @@ -1204,8 +1204,8 @@ void Tomboulides::initializeOperators() { // Helmholtz Hv_form_ = new ParBilinearForm(vfes_); - VectorMassIntegrator *hmv_blfi; - VectorDiffusionIntegrator *hdv_blfi; + VectorMassIntegrator* hmv_blfi; + VectorDiffusionIntegrator* hdv_blfi; if (axisym_) { hmv_blfi = new VectorMassIntegrator(*rad_rho_over_dt_coeff_); @@ -1221,7 +1221,7 @@ void Tomboulides::initializeOperators() { Hv_form_->AddDomainIntegrator(hmv_blfi); Hv_form_->AddDomainIntegrator(hdv_blfi); - VectorDiffusionIntegrator *shdv_blfi; + VectorDiffusionIntegrator* shdv_blfi; if (sw_stab_) { // auto *shdv_blfi = new VectorDiffusionIntegrator(*supg_coeff_); shdv_blfi = new VectorDiffusionIntegrator(*supg_coeff_); @@ -1232,7 +1232,7 @@ void Tomboulides::initializeOperators() { } if (axisym_) { - auto *hfv_blfi = new VectorMassIntegrator(*visc_forcing_coeff_); + auto* hfv_blfi = new VectorMassIntegrator(*visc_forcing_coeff_); Hv_form_->AddDomainIntegrator(hfv_blfi); } Hv_form_->Assemble(); @@ -1240,9 +1240,9 @@ void Tomboulides::initializeOperators() { // Helmholtz solver Hv_inv_pc_ = new HypreSmoother(*Hv_op_.As()); - dynamic_cast(Hv_inv_pc_)->SetType(smoother_type_, smoother_passes_); - dynamic_cast(Hv_inv_pc_)->SetSOROptions(hsmoother_relax_weight_, hsmoother_relax_omega_); - dynamic_cast(Hv_inv_pc_) + dynamic_cast(Hv_inv_pc_)->SetType(smoother_type_, smoother_passes_); + dynamic_cast(Hv_inv_pc_)->SetSOROptions(hsmoother_relax_weight_, hsmoother_relax_omega_); + dynamic_cast(Hv_inv_pc_) ->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, smoother_eig_est_); Hv_inv_ = new CGSolver(vfes_->GetComm()); @@ -1256,7 +1256,7 @@ void Tomboulides::initializeOperators() { // pp_div_bdr_form_ = new ParLinearForm(pfes_); - BoundaryNormalLFIntegrator *ppd_bnlfi; + BoundaryNormalLFIntegrator* ppd_bnlfi; if (axisym_) { rad_pp_div_coeff_ = new ScalarVectorProductCoefficient(radius_coeff, *pp_div_coeff_); ppd_bnlfi = new BoundaryNormalLFIntegrator(*rad_pp_div_coeff_); @@ -1269,8 +1269,8 @@ void Tomboulides::initializeOperators() { pp_div_bdr_form_->AddBoundaryIntegrator(ppd_bnlfi, vel_ess_attr_); u_bdr_form_ = new ParLinearForm(pfes_); - for (auto &vel_dbc : vel_dbcs_) { - BoundaryNormalLFIntegrator *ubdr_bnlfi; + for (auto& vel_dbc : vel_dbcs_) { + BoundaryNormalLFIntegrator* ubdr_bnlfi; if (axisym_) { rad_vel_coeff_.push_back(new ScalarVectorProductCoefficient(radius_coeff, *vel_dbc.coeff)); ubdr_bnlfi = new BoundaryNormalLFIntegrator(*rad_vel_coeff_[rad_vel_coeff_.size() - 1]); @@ -1284,7 +1284,7 @@ void Tomboulides::initializeOperators() { } S_poisson_form_ = new ParLinearForm(vfes_); - VectorDomainLFIntegrator *s_rhs_dlfi; + VectorDomainLFIntegrator* s_rhs_dlfi; if (axisym_) { s_rhs_dlfi = new VectorDomainLFIntegrator(*rad_S_poisson_coeff_); } else { @@ -1296,7 +1296,7 @@ void Tomboulides::initializeOperators() { S_poisson_form_->AddDomainIntegrator(s_rhs_dlfi); S_mom_form_ = new ParLinearForm(vfes_); - VectorDomainLFIntegrator *s_mom_dlfi; + VectorDomainLFIntegrator* s_mom_dlfi; if (axisym_) { s_mom_dlfi = new VectorDomainLFIntegrator(*rad_S_mom_coeff_); } else { @@ -1309,14 +1309,14 @@ void Tomboulides::initializeOperators() { if (axisym_) { Faxi_poisson_form_ = new ParLinearForm(pfes_); - auto *f_rhs_dlfi = new DomainLFIntegrator(*pp_div_rad_comp_coeff_); + auto* f_rhs_dlfi = new DomainLFIntegrator(*pp_div_rad_comp_coeff_); if (numerical_integ_) { f_rhs_dlfi->SetIntRule(&ir_ni_p); } Faxi_poisson_form_->AddDomainIntegrator(f_rhs_dlfi); ur_conv_axi_form_ = new ParLinearForm(vfes_); - auto *urca_dlfi = new VectorDomainLFIntegrator(*ur_conv_forcing_coeff_); + auto* urca_dlfi = new VectorDomainLFIntegrator(*ur_conv_forcing_coeff_); if (numerical_integ_) { urca_dlfi->SetIntRule(&ir_ni_v); } @@ -1324,11 +1324,11 @@ void Tomboulides::initializeOperators() { // Helmholtz Hs_form_ = new ParBilinearForm(pfes_); - auto *hms_blfi = new MassIntegrator(*rad_rho_over_dt_coeff_); - auto *hds_blfi = new DiffusionIntegrator(*rad_mu_coeff_); - auto *hfs_blfi = new MassIntegrator(*mu_over_rad_coeff_); + auto* hms_blfi = new MassIntegrator(*rad_rho_over_dt_coeff_); + auto* hds_blfi = new DiffusionIntegrator(*rad_mu_coeff_); + auto* hfs_blfi = new MassIntegrator(*mu_over_rad_coeff_); - DiffusionIntegrator *shds_blfi; + DiffusionIntegrator* shds_blfi; if (sw_stab_) { // auto *shds_blfi = new DiffusionIntegrator(*supg_coeff_); shds_blfi = new DiffusionIntegrator(*supg_coeff_); @@ -1343,9 +1343,9 @@ void Tomboulides::initializeOperators() { Hs_form_->FormSystemMatrix(swirl_ess_tdof_, Hs_op_); Hs_inv_pc_ = new HypreSmoother(*Hs_op_.As()); - dynamic_cast(Hs_inv_pc_)->SetType(smoother_type_, smoother_passes_); - dynamic_cast(Hs_inv_pc_)->SetSOROptions(hsmoother_relax_weight_, hsmoother_relax_omega_); - dynamic_cast(Hs_inv_pc_) + dynamic_cast(Hs_inv_pc_)->SetType(smoother_type_, smoother_passes_); + dynamic_cast(Hs_inv_pc_)->SetSOROptions(hsmoother_relax_weight_, hsmoother_relax_omega_); + dynamic_cast(Hs_inv_pc_) ->SetPolyOptions(smoother_poly_order_, smoother_poly_fraction_, smoother_eig_est_); Hs_inv_ = new CGSolver(pfes_->GetComm()); @@ -1361,18 +1361,18 @@ void Tomboulides::initializeOperators() { As_form_ = new ParBilinearForm(pfes_); // NB: -1 so that sign is correct on rhs - auto *as_blfi = new ConvectionIntegrator(*rad_rhou_coeff_, -1.0); + auto* as_blfi = new ConvectionIntegrator(*rad_rhou_coeff_, -1.0); As_form_->AddDomainIntegrator(as_blfi); As_form_->Assemble(); As_form_->FormSystemMatrix(empty, As_op_); rho_ur_ut_form_ = new ParLinearForm(pfes_); - auto *rurut_dlfi = new DomainLFIntegrator(*rho_ur_ut_coeff_); + auto* rurut_dlfi = new DomainLFIntegrator(*rho_ur_ut_coeff_); rho_ur_ut_form_->AddDomainIntegrator(rurut_dlfi); swirl_var_viscosity_form_ = new ParLinearForm(pfes_); - auto *svv_dlfi = new DomainLFIntegrator(*swirl_var_viscosity_coeff_); + auto* svv_dlfi = new DomainLFIntegrator(*swirl_var_viscosity_coeff_); swirl_var_viscosity_form_->AddDomainIntegrator(svv_dlfi); } @@ -1388,7 +1388,7 @@ void Tomboulides::initializeOperators() { evaluateVelocityGradient(); } -void Tomboulides::initializeIO(IODataOrganizer &io) const { +void Tomboulides::initializeIO(IODataOrganizer& io) const { io.registerIOFamily("Velocity", "/velocity", u_curr_gf_, true, true, vfec_); io.registerIOVar("/velocity", "x-comp", 0); if (dim_ >= 2) io.registerIOVar("/velocity", "y-comp", 1); @@ -1400,7 +1400,7 @@ void Tomboulides::initializeIO(IODataOrganizer &io) const { } } -void Tomboulides::initializeViz(mfem::ParaViewDataCollection &pvdc) const { +void Tomboulides::initializeViz(mfem::ParaViewDataCollection& pvdc) const { pvdc.RegisterField("velocity", u_curr_gf_); pvdc.RegisterField("pressure", p_gf_); if (axisym_) { @@ -1408,7 +1408,7 @@ void Tomboulides::initializeViz(mfem::ParaViewDataCollection &pvdc) const { } } -void Tomboulides::initializeStats(Averaging &average, IODataOrganizer &io, bool continuation) const { +void Tomboulides::initializeStats(Averaging& average, IODataOrganizer& io, bool continuation) const { if (average.ComputeMean()) { // fields for averaging average.registerField(std::string("velocity"), u_curr_gf_, true, 0, dim_); @@ -1451,7 +1451,7 @@ void Tomboulides::initializeStats(Averaging &average, IODataOrganizer &io, bool } } -void Tomboulides::computeDissipation(Averaging &average, const int iter) { +void Tomboulides::computeDissipation(Averaging& average, const int iter) { if (average.ComputeMean()) { int sample_interval = average.GetSamplesInterval(); int sample_start = average.GetStartMean(); @@ -1485,12 +1485,12 @@ void Tomboulides::computeDissipation(Averaging &average, const int iter) { if (dim_ == 3) gradW_gf_->SetFromTrueDofs(gradW_); // const double *dmu = (*thermo_interface_->viscosity).HostRead(); - const double *dmu = mu_total_gf_->HostRead(); - const double *drho = (*thermo_interface_->density).HostRead(); - const double *dGradU = gradU_gf_->HostRead(); - const double *dGradV = gradV_gf_->HostRead(); - const double *dGradW = gradW_gf_->HostRead(); - double *depsi = epsi_gf_->HostReadWrite(); + const double* dmu = mu_total_gf_->HostRead(); + const double* drho = (*thermo_interface_->density).HostRead(); + const double* dGradU = gradU_gf_->HostRead(); + const double* dGradV = gradV_gf_->HostRead(); + const double* dGradW = gradW_gf_->HostRead(); + double* depsi = epsi_gf_->HostReadWrite(); int Sdof = epsi_gf_->Size(); for (int dof = 0; dof < Sdof; dof++) { @@ -1632,7 +1632,7 @@ void Tomboulides::step() { // ------------------------------------------------------------------------ // Evaluate the forcing at the end of the time step - for (auto &force : forcing_terms_) { + for (auto& force : forcing_terms_) { force.coeff->SetTime(time + dt); } forcing_form_->Assemble(); @@ -1862,7 +1862,7 @@ void Tomboulides::step() { Orthogonalize(resp_vec_, pfes_); } - for (auto &pres_dbc : pres_dbcs_) { + for (auto& pres_dbc : pres_dbcs_) { p_gf_->ProjectBdrCoefficient(*pres_dbc.coeff, pres_dbc.attr); } @@ -1913,7 +1913,7 @@ void Tomboulides::step() { // rho * vstar / dt term Mv_rho_op_->AddMult(ustar_vec_, resu_vec_); - for (auto &vel_dbc : vel_dbcs_) { + for (auto& vel_dbc : vel_dbcs_) { u_next_gf_->ProjectBdrCoefficient(*vel_dbc.coeff, vel_dbc.attr); } @@ -2006,7 +2006,7 @@ void Tomboulides::step() { Ms_rho_op_->AddMult(utheta_next_vec_, resp_vec_); // Apply swirl Dirichlet BC - for (auto &swirl_dbc : swirl_dbcs_) { + for (auto& swirl_dbc : swirl_dbcs_) { utheta_next_gf_->ProjectBdrCoefficient(*swirl_dbc.coeff, swirl_dbc.attr); } @@ -2046,15 +2046,15 @@ double Tomboulides::computeL2Error() const { return err; } -void Tomboulides::meanZero(ParGridFunction &v) { +void Tomboulides::meanZero(ParGridFunction& v) { // Make sure not to recompute the inner product linear form every // application. if (mass_lform_ == nullptr) { one_coeff_.constant = 1.0; mass_lform_ = new ParLinearForm(v.ParFESpace()); - auto *dlfi = new DomainLFIntegrator(one_coeff_); + auto* dlfi = new DomainLFIntegrator(one_coeff_); if (numerical_integ_) { - const IntegrationRule &ir_ni = gll_rules.Get(vfes_->GetFE(0)->GetGeomType(), 2 * vorder_ - 1); + const IntegrationRule& ir_ni = gll_rules.Get(vfes_->GetFE(0)->GetGeomType(), 2 * vorder_ - 1); dlfi->SetIntRule(&ir_ni); } mass_lform_->AddDomainIntegrator(dlfi); @@ -2078,7 +2078,7 @@ void Tomboulides::updateTotalViscosity() { } /// Add a Dirichlet boundary condition to the velocity field -void Tomboulides::addVelDirichletBC(const Vector &u, Array &attr) { +void Tomboulides::addVelDirichletBC(const Vector& u, Array& attr) { assert(u.Size() == dim_); vel_dbcs_.emplace_back(attr, new VectorConstantCoefficient(u)); for (int i = 0; i < attr.Size(); ++i) { @@ -2089,7 +2089,7 @@ void Tomboulides::addVelDirichletBC(const Vector &u, Array &attr) { } } -void Tomboulides::addVelDirichletBC(VectorCoefficient *coeff, Array &attr) { +void Tomboulides::addVelDirichletBC(VectorCoefficient* coeff, Array& attr) { vel_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2099,16 +2099,16 @@ void Tomboulides::addVelDirichletBC(VectorCoefficient *coeff, Array &attr) } } -void Tomboulides::addVelDirichletBC(void (*f)(const Vector &, double, Vector &), Array &attr) { +void Tomboulides::addVelDirichletBC(void (*f)(const Vector&, double, Vector&), Array& attr) { addVelDirichletBC(new VectorFunctionCoefficient(dim_, f), attr); } -void Tomboulides::addVelDirichletBC(std::function f, Array &attr) { +void Tomboulides::addVelDirichletBC(std::function f, Array& attr) { addVelDirichletBC(new VectorFunctionCoefficient(dim_, f), attr); } /// Add a Dirichlet boundary condition to the pressure field. -void Tomboulides::addPresDirichletBC(double p, Array &attr) { +void Tomboulides::addPresDirichletBC(double p, Array& attr) { pres_dbcs_.emplace_back(attr, new ConstantCoefficient(p)); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2118,7 +2118,7 @@ void Tomboulides::addPresDirichletBC(double p, Array &attr) { } } -void Tomboulides::addSwirlDirichletBC(double ut, mfem::Array &attr) { +void Tomboulides::addSwirlDirichletBC(double ut, mfem::Array& attr) { assert(axisym_); swirl_dbcs_.emplace_back(attr, new ConstantCoefficient(ut)); for (int i = 0; i < attr.Size(); ++i) { @@ -2129,7 +2129,7 @@ void Tomboulides::addSwirlDirichletBC(double ut, mfem::Array &attr) { } } -void Tomboulides::addSwirlDirichletBC(Coefficient *coeff, Array &attr) { +void Tomboulides::addSwirlDirichletBC(Coefficient* coeff, Array& attr) { swirl_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2139,7 +2139,7 @@ void Tomboulides::addSwirlDirichletBC(Coefficient *coeff, Array &attr) { } } -void Tomboulides::addSwirlDirichletBC(double (*f)(const Vector &, double), Array &attr) { +void Tomboulides::addSwirlDirichletBC(double (*f)(const Vector&, double), Array& attr) { addSwirlDirichletBC(new FunctionCoefficient(f), attr); } @@ -2151,7 +2151,7 @@ double Tomboulides::maxVelocityMagnitude() { int n_scalar_dof = u_vec_.Size() / dim_; - const double *vel = u_vec_.HostRead(); + const double* vel = u_vec_.HostRead(); for (int i = 0; i < n_scalar_dof; i++) { const double ux = vel[i]; diff --git a/src/tomboulides.hpp b/src/tomboulides.hpp index 87af56bc..a816a32c 100644 --- a/src/tomboulides.hpp +++ b/src/tomboulides.hpp @@ -54,11 +54,11 @@ struct temporalSchemeCoefficients; /// Container for forcing terms to be added to velocity equation class ForcingTerm_T { public: - ForcingTerm_T(mfem::Array attr, mfem::VectorCoefficient *coeff) : attr(attr), coeff(coeff) { + ForcingTerm_T(mfem::Array attr, mfem::VectorCoefficient* coeff) : attr(attr), coeff(coeff) { // nothing here } - ForcingTerm_T(ForcingTerm_T &&obj) { + ForcingTerm_T(ForcingTerm_T&& obj) { // Deep copy the attribute array this->attr = obj.attr; @@ -70,7 +70,7 @@ class ForcingTerm_T { ~ForcingTerm_T() { delete coeff; } mfem::Array attr; - mfem::VectorCoefficient *coeff; + mfem::VectorCoefficient* coeff; }; class Tomboulides final : public FlowBase { @@ -168,10 +168,10 @@ class Tomboulides final : public FlowBase { mfem::IntegrationRules gll_rules; // Options-related structures - TPS::Tps *tpsP_ = nullptr; + TPS::Tps* tpsP_ = nullptr; // Basic info needed to create fem spaces - mfem::ParMesh *pmesh_; + mfem::ParMesh* pmesh_; const int vorder_; const int porder_; const int dim_; @@ -180,7 +180,7 @@ class Tomboulides final : public FlowBase { // Coefficients necessary to take a time step (including dt). // Assumed to be externally managed and determined, so just get a // reference here. - const temporalSchemeCoefficients &coeff_; + const temporalSchemeCoefficients& coeff_; // streamwise-stabilization bool sw_stab_; @@ -194,8 +194,8 @@ class Tomboulides final : public FlowBase { // Object used to build forcing mfem::Vector gravity_; - mfem::VectorConstantCoefficient *gravity_vec_; - mfem::ScalarVectorProductCoefficient *rad_gravity_vec_; + mfem::VectorConstantCoefficient* gravity_vec_; + mfem::ScalarVectorProductCoefficient* rad_gravity_vec_; std::vector forcing_terms_; // initial condition holders @@ -217,128 +217,128 @@ class Tomboulides final : public FlowBase { mfem::Array swirl_ess_tdof_; /// Velocity FEM objects and fields - mfem::FiniteElementCollection *vfec_ = nullptr; - mfem::ParFiniteElementSpace *vfes_ = nullptr; - mfem::FiniteElementCollection *sfec_ = nullptr; - mfem::ParFiniteElementSpace *sfes_ = nullptr; - mfem::ParGridFunction *u_curr_gf_ = nullptr; - mfem::ParGridFunction *u_next_gf_ = nullptr; - mfem::ParGridFunction *curl_gf_ = nullptr; - mfem::ParGridFunction *curlcurl_gf_ = nullptr; - mfem::ParGridFunction *resu_gf_ = nullptr; - mfem::ParGridFunction *pp_div_gf_ = nullptr; - mfem::ParGridFunction *gradU_gf_ = nullptr; - mfem::ParGridFunction *gradV_gf_ = nullptr; - mfem::ParGridFunction *gradW_gf_ = nullptr; - mfem::ParGridFunction *gradS_gf_ = nullptr; + mfem::FiniteElementCollection* vfec_ = nullptr; + mfem::ParFiniteElementSpace* vfes_ = nullptr; + mfem::FiniteElementCollection* sfec_ = nullptr; + mfem::ParFiniteElementSpace* sfes_ = nullptr; + mfem::ParGridFunction* u_curr_gf_ = nullptr; + mfem::ParGridFunction* u_next_gf_ = nullptr; + mfem::ParGridFunction* curl_gf_ = nullptr; + mfem::ParGridFunction* curlcurl_gf_ = nullptr; + mfem::ParGridFunction* resu_gf_ = nullptr; + mfem::ParGridFunction* pp_div_gf_ = nullptr; + mfem::ParGridFunction* gradU_gf_ = nullptr; + mfem::ParGridFunction* gradV_gf_ = nullptr; + mfem::ParGridFunction* gradW_gf_ = nullptr; + mfem::ParGridFunction* gradS_gf_ = nullptr; // mfem::ParGridFunction *buffer_uInlet_ = nullptr; - mfem::VectorGridFunctionCoefficient *velocity_field_ = nullptr; - mfem::GridFunctionCoefficient *swirl_field_ = nullptr; - mfem::ParGridFunction *epsi_gf_ = nullptr; + mfem::VectorGridFunctionCoefficient* velocity_field_ = nullptr; + mfem::GridFunctionCoefficient* swirl_field_ = nullptr; + mfem::ParGridFunction* epsi_gf_ = nullptr; /// Pressure FEM objects and fields - mfem::FiniteElementCollection *pfec_ = nullptr; - mfem::ParFiniteElementSpace *pfes_ = nullptr; - mfem::ParGridFunction *p_gf_ = nullptr; - mfem::ParGridFunction *iorho_gf_ = nullptr; - mfem::ParGridFunction *resp_gf_ = nullptr; - mfem::ParGridFunction *pp_div_rad_comp_gf_ = nullptr; + mfem::FiniteElementCollection* pfec_ = nullptr; + mfem::ParFiniteElementSpace* pfes_ = nullptr; + mfem::ParGridFunction* p_gf_ = nullptr; + mfem::ParGridFunction* iorho_gf_ = nullptr; + mfem::ParGridFunction* resp_gf_ = nullptr; + mfem::ParGridFunction* pp_div_rad_comp_gf_ = nullptr; - mfem::ParGridFunction *gridScale_gf_ = nullptr; + mfem::ParGridFunction* gridScale_gf_ = nullptr; /// Swirl - mfem::ParGridFunction *utheta_gf_ = nullptr; - mfem::ParGridFunction *utheta_next_gf_ = nullptr; - mfem::ParGridFunction *u_next_rad_comp_gf_ = nullptr; + mfem::ParGridFunction* utheta_gf_ = nullptr; + mfem::ParGridFunction* utheta_next_gf_ = nullptr; + mfem::ParGridFunction* u_next_rad_comp_gf_ = nullptr; /// "total" viscosity, including fluid, turbulence, sponge - mfem::ParGridFunction *mu_total_gf_ = nullptr; + mfem::ParGridFunction* mu_total_gf_ = nullptr; /// mfem::Coefficients used in forming necessary operators - mfem::GridFunctionCoefficient *rho_coeff_ = nullptr; + mfem::GridFunctionCoefficient* rho_coeff_ = nullptr; // mfem::RatioCoefficient *iorho_coeff_ = nullptr; // mfem::GridFunctionCoefficient *iorho_coeff_ = nullptr; - mfem::Coefficient *iorho_coeff_ = nullptr; + mfem::Coefficient* iorho_coeff_ = nullptr; mfem::ConstantCoefficient nlcoeff_; mfem::ConstantCoefficient one_coeff_; mfem::ConstantCoefficient Hv_bdfcoeff_; - mfem::ProductCoefficient *rho_over_dt_coeff_ = nullptr; - mfem::GridFunctionCoefficient *mu_coeff_ = nullptr; - mfem::VectorGridFunctionCoefficient *pp_div_coeff_ = nullptr; - - mfem::GradientGridFunctionCoefficient *grad_mu_coeff_ = nullptr; - mfem::GradientVectorGridFunctionCoefficient *grad_u_next_coeff_ = nullptr; - mfem::TransposeMatrixCoefficient *grad_u_next_transp_coeff_ = nullptr; - mfem::MatrixVectorProductCoefficient *gradu_gradmu_coeff_ = nullptr; - mfem::MatrixVectorProductCoefficient *graduT_gradmu_coeff_ = nullptr; - mfem::VectorSumCoefficient *twoS_gradmu_coeff_ = nullptr; - mfem::GridFunctionCoefficient *Qt_coeff_ = nullptr; - mfem::ScalarVectorProductCoefficient *gradmu_Qt_coeff_ = nullptr; - mfem::VectorSumCoefficient *S_poisson_coeff_ = nullptr; - mfem::VectorSumCoefficient *S_mom_coeff_ = nullptr; - - mfem::ProductCoefficient *rad_rho_coeff_ = nullptr; - mfem::ProductCoefficient *rad_rho_over_dt_coeff_ = nullptr; - mfem::ProductCoefficient *rad_mu_coeff_ = nullptr; - mfem::ScalarVectorProductCoefficient *rad_S_poisson_coeff_ = nullptr; - mfem::ScalarVectorProductCoefficient *rad_S_mom_coeff_ = nullptr; - mfem::RatioCoefficient *mu_over_rad_coeff_ = nullptr; - mfem::VectorArrayCoefficient *visc_forcing_coeff_ = nullptr; - mfem::GridFunctionCoefficient *pp_div_rad_comp_coeff_ = nullptr; - - mfem::ScalarVectorProductCoefficient *rad_pp_div_coeff_ = nullptr; - std::vector rad_vel_coeff_; - - mfem::GridFunctionCoefficient *utheta_coeff_ = nullptr; - mfem::ProductCoefficient *utheta2_coeff_ = nullptr; - mfem::VectorArrayCoefficient *ur_conv_forcing_coeff_ = nullptr; - mfem::VectorGridFunctionCoefficient *u_next_coeff_ = nullptr; - mfem::ScalarVectorProductCoefficient *rad_rhou_coeff_ = nullptr; - mfem::GridFunctionCoefficient *u_next_rad_coeff_ = nullptr; - mfem::ProductCoefficient *ur_ut_coeff_ = nullptr; - mfem::ProductCoefficient *rho_ur_ut_coeff_ = nullptr; - mfem::VectorArrayCoefficient *utheta_vec_coeff_ = nullptr; - mfem::InnerProductCoefficient *swirl_var_viscosity_coeff_ = nullptr; - - mfem::VectorMagnitudeCoefficient *umag_coeff_ = nullptr; - mfem::GridFunctionCoefficient *gscale_coeff_ = nullptr; - mfem::PowerCoefficient *visc_inv_coeff_ = nullptr; - mfem::ProductCoefficient *reh1_coeff_ = nullptr; - mfem::ProductCoefficient *reh2_coeff_ = nullptr; - mfem::ProductCoefficient *Reh_coeff_ = nullptr; - mfem::ExtTransformedCoefficient *csupg_coeff_ = nullptr; - mfem::ProductCoefficient *uw1_coeff_ = nullptr; - mfem::ProductCoefficient *uw2_coeff_ = nullptr; - mfem::ProductCoefficient *upwind_coeff_ = nullptr; - mfem::TransformedMatrixVectorCoefficient *swdiff_coeff_ = nullptr; - mfem::ScalarMatrixProductCoefficient *supg_coeff_ = nullptr; - mfem::GridFunctionCoefficient *visc_coeff_ = nullptr; + mfem::ProductCoefficient* rho_over_dt_coeff_ = nullptr; + mfem::GridFunctionCoefficient* mu_coeff_ = nullptr; + mfem::VectorGridFunctionCoefficient* pp_div_coeff_ = nullptr; + + mfem::GradientGridFunctionCoefficient* grad_mu_coeff_ = nullptr; + mfem::GradientVectorGridFunctionCoefficient* grad_u_next_coeff_ = nullptr; + mfem::TransposeMatrixCoefficient* grad_u_next_transp_coeff_ = nullptr; + mfem::MatrixVectorProductCoefficient* gradu_gradmu_coeff_ = nullptr; + mfem::MatrixVectorProductCoefficient* graduT_gradmu_coeff_ = nullptr; + mfem::VectorSumCoefficient* twoS_gradmu_coeff_ = nullptr; + mfem::GridFunctionCoefficient* Qt_coeff_ = nullptr; + mfem::ScalarVectorProductCoefficient* gradmu_Qt_coeff_ = nullptr; + mfem::VectorSumCoefficient* S_poisson_coeff_ = nullptr; + mfem::VectorSumCoefficient* S_mom_coeff_ = nullptr; + + mfem::ProductCoefficient* rad_rho_coeff_ = nullptr; + mfem::ProductCoefficient* rad_rho_over_dt_coeff_ = nullptr; + mfem::ProductCoefficient* rad_mu_coeff_ = nullptr; + mfem::ScalarVectorProductCoefficient* rad_S_poisson_coeff_ = nullptr; + mfem::ScalarVectorProductCoefficient* rad_S_mom_coeff_ = nullptr; + mfem::RatioCoefficient* mu_over_rad_coeff_ = nullptr; + mfem::VectorArrayCoefficient* visc_forcing_coeff_ = nullptr; + mfem::GridFunctionCoefficient* pp_div_rad_comp_coeff_ = nullptr; + + mfem::ScalarVectorProductCoefficient* rad_pp_div_coeff_ = nullptr; + std::vector rad_vel_coeff_; + + mfem::GridFunctionCoefficient* utheta_coeff_ = nullptr; + mfem::ProductCoefficient* utheta2_coeff_ = nullptr; + mfem::VectorArrayCoefficient* ur_conv_forcing_coeff_ = nullptr; + mfem::VectorGridFunctionCoefficient* u_next_coeff_ = nullptr; + mfem::ScalarVectorProductCoefficient* rad_rhou_coeff_ = nullptr; + mfem::GridFunctionCoefficient* u_next_rad_coeff_ = nullptr; + mfem::ProductCoefficient* ur_ut_coeff_ = nullptr; + mfem::ProductCoefficient* rho_ur_ut_coeff_ = nullptr; + mfem::VectorArrayCoefficient* utheta_vec_coeff_ = nullptr; + mfem::InnerProductCoefficient* swirl_var_viscosity_coeff_ = nullptr; + + mfem::VectorMagnitudeCoefficient* umag_coeff_ = nullptr; + mfem::GridFunctionCoefficient* gscale_coeff_ = nullptr; + mfem::PowerCoefficient* visc_inv_coeff_ = nullptr; + mfem::ProductCoefficient* reh1_coeff_ = nullptr; + mfem::ProductCoefficient* reh2_coeff_ = nullptr; + mfem::ProductCoefficient* Reh_coeff_ = nullptr; + mfem::ExtTransformedCoefficient* csupg_coeff_ = nullptr; + mfem::ProductCoefficient* uw1_coeff_ = nullptr; + mfem::ProductCoefficient* uw2_coeff_ = nullptr; + mfem::ProductCoefficient* upwind_coeff_ = nullptr; + mfem::TransformedMatrixVectorCoefficient* swdiff_coeff_ = nullptr; + mfem::ScalarMatrixProductCoefficient* supg_coeff_ = nullptr; + mfem::GridFunctionCoefficient* visc_coeff_ = nullptr; // mfem "form" objects used to create operators - mfem::ParBilinearForm *L_iorho_form_ = nullptr; // \int (1/\rho) \nabla \phi_i \cdot \nabla \phi_j - mfem::ParLinearForm *forcing_form_ = nullptr; // \int \phi_i f - mfem::ParNonlinearForm *Nconv_form_ = nullptr; // \int \vphi_i \cdot [(u \cdot \nabla) u] - mfem::ParBilinearForm *Ms_form_ = nullptr; // mass matrix = \int \vphi_i \cdot \vphi_j - mfem::ParBilinearForm *Mv_form_ = nullptr; // mass matrix = \int \vphi_i \cdot \vphi_j - mfem::ParMixedBilinearForm *D_form_ = nullptr; // divergence = \int \phi_i \nabla \cdot \vphi_j - mfem::ParMixedBilinearForm *G_form_ = nullptr; // gradient = \int \vphi_i \cdot \nabla \phi_j - mfem::ParBilinearForm *Mv_rho_form_ = nullptr; // mass matrix (density weighted) = \int \rho \vphi_i \cdot \vphi_j - mfem::ParBilinearForm *Hv_form_ = nullptr; - mfem::ParLinearForm *pp_div_bdr_form_ = nullptr; - mfem::ParLinearForm *u_bdr_form_ = nullptr; - mfem::ParLinearForm *S_poisson_form_ = nullptr; - mfem::ParLinearForm *S_mom_form_ = nullptr; - mfem::ParLinearForm *Faxi_poisson_form_ = nullptr; - mfem::ParLinearForm *ur_conv_axi_form_ = nullptr; - - mfem::ParBilinearForm *Ms_rho_form_ = nullptr; - mfem::ParBilinearForm *Hs_form_ = nullptr; - mfem::ParBilinearForm *As_form_ = nullptr; - mfem::ParLinearForm *rho_ur_ut_form_ = nullptr; - mfem::ParLinearForm *swirl_var_viscosity_form_ = nullptr; + mfem::ParBilinearForm* L_iorho_form_ = nullptr; // \int (1/\rho) \nabla \phi_i \cdot \nabla \phi_j + mfem::ParLinearForm* forcing_form_ = nullptr; // \int \phi_i f + mfem::ParNonlinearForm* Nconv_form_ = nullptr; // \int \vphi_i \cdot [(u \cdot \nabla) u] + mfem::ParBilinearForm* Ms_form_ = nullptr; // mass matrix = \int \vphi_i \cdot \vphi_j + mfem::ParBilinearForm* Mv_form_ = nullptr; // mass matrix = \int \vphi_i \cdot \vphi_j + mfem::ParMixedBilinearForm* D_form_ = nullptr; // divergence = \int \phi_i \nabla \cdot \vphi_j + mfem::ParMixedBilinearForm* G_form_ = nullptr; // gradient = \int \vphi_i \cdot \nabla \phi_j + mfem::ParBilinearForm* Mv_rho_form_ = nullptr; // mass matrix (density weighted) = \int \rho \vphi_i \cdot \vphi_j + mfem::ParBilinearForm* Hv_form_ = nullptr; + mfem::ParLinearForm* pp_div_bdr_form_ = nullptr; + mfem::ParLinearForm* u_bdr_form_ = nullptr; + mfem::ParLinearForm* S_poisson_form_ = nullptr; + mfem::ParLinearForm* S_mom_form_ = nullptr; + mfem::ParLinearForm* Faxi_poisson_form_ = nullptr; + mfem::ParLinearForm* ur_conv_axi_form_ = nullptr; + + mfem::ParBilinearForm* Ms_rho_form_ = nullptr; + mfem::ParBilinearForm* Hs_form_ = nullptr; + mfem::ParBilinearForm* As_form_ = nullptr; + mfem::ParLinearForm* rho_ur_ut_form_ = nullptr; + mfem::ParLinearForm* swirl_var_viscosity_form_ = nullptr; // streamwise stability - mfem::ParBilinearForm *Mv_stab_form_ = nullptr; + mfem::ParBilinearForm* Mv_stab_form_ = nullptr; // mfem operator objects mfem::OperatorHandle L_iorho_op_; @@ -356,22 +356,22 @@ class Tomboulides final : public FlowBase { mfem::OperatorHandle Mv_stab_op_; // solver objects - mfem::ParLORDiscretization *L_iorho_lor_ = nullptr; - mfem::HypreBoomerAMG *L_iorho_inv_pc_ = nullptr; - mfem::OrthoSolver *L_iorho_inv_ortho_pc_ = nullptr; - mfem::CGSolver *L_iorho_inv_ = nullptr; + mfem::ParLORDiscretization* L_iorho_lor_ = nullptr; + mfem::HypreBoomerAMG* L_iorho_inv_pc_ = nullptr; + mfem::OrthoSolver* L_iorho_inv_ortho_pc_ = nullptr; + mfem::CGSolver* L_iorho_inv_ = nullptr; - mfem::Solver *Mv_inv_pc_ = nullptr; - mfem::CGSolver *Mv_inv_ = nullptr; + mfem::Solver* Mv_inv_pc_ = nullptr; + mfem::CGSolver* Mv_inv_ = nullptr; - mfem::Solver *Mv_rho_inv_pc_ = nullptr; - mfem::CGSolver *Mv_rho_inv_ = nullptr; + mfem::Solver* Mv_rho_inv_pc_ = nullptr; + mfem::CGSolver* Mv_rho_inv_ = nullptr; - mfem::Solver *Hv_inv_pc_ = nullptr; - mfem::CGSolver *Hv_inv_ = nullptr; + mfem::Solver* Hv_inv_pc_ = nullptr; + mfem::CGSolver* Hv_inv_ = nullptr; - mfem::Solver *Hs_inv_pc_ = nullptr; - mfem::CGSolver *Hs_inv_ = nullptr; + mfem::Solver* Hs_inv_pc_ = nullptr; + mfem::CGSolver* Hs_inv_ = nullptr; // Vectors mfem::Vector forcing_vec_; @@ -414,14 +414,14 @@ class Tomboulides final : public FlowBase { // miscellaneous double volume_; - mfem::ParLinearForm *mass_lform_ = nullptr; + mfem::ParLinearForm* mass_lform_ = nullptr; // helper functions /** * @brief Zero the mean of the input function */ - void meanZero(mfem::ParGridFunction &v); + void meanZero(mfem::ParGridFunction& v); /** * @brief Update total viscosity using latest inputs @@ -430,8 +430,8 @@ class Tomboulides final : public FlowBase { public: /// Constructor - Tomboulides(mfem::ParMesh *pmesh, int vorder, int porder, temporalSchemeCoefficients &coeff, - mfem::ParGridFunction *gridScale = nullptr, TPS::Tps *tps = nullptr); + Tomboulides(mfem::ParMesh* pmesh, int vorder, int porder, temporalSchemeCoefficients& coeff, + mfem::ParGridFunction* gridScale = nullptr, TPS::Tps* tps = nullptr); /// Destructor ~Tomboulides() final; @@ -455,41 +455,41 @@ class Tomboulides final : public FlowBase { * Register the state with the IODataOrganizer object so that it can * be read/written. Must be called after initializeSelf(). */ - void initializeIO(IODataOrganizer &io) const final; + void initializeIO(IODataOrganizer& io) const final; /** * @brief Initialize Paraview outputs * * Register fields to be written to paraview visualization files. */ - void initializeViz(mfem::ParaViewDataCollection &pvdc) const final; + void initializeViz(mfem::ParaViewDataCollection& pvdc) const final; /** * @brief Initialize statistics outputs */ - void initializeStats(Averaging &average, IODataOrganizer &io, bool continuation) const final; + void initializeStats(Averaging& average, IODataOrganizer& io, bool continuation) const final; /** * @brief Compute turbulent dissipation using average u */ - void computeDissipation(Averaging &average, const int iter); + void computeDissipation(Averaging& average, const int iter); /// Advance void step() final; - void screenHeader(std::vector &header) const final { + void screenHeader(std::vector& header) const final { int nprint = 1; header.resize(nprint); header[0] = std::string("Max vel."); } - void screenValues(std::vector &values) final { + void screenValues(std::vector& values) final { int nprint = 1; values.resize(nprint); values[0] = maxVelocityMagnitude(); } - mfem::ParGridFunction *getCurrentVelocity() final { return u_curr_gf_; } + mfem::ParGridFunction* getCurrentVelocity() final { return u_curr_gf_; } /// Evaluate error (only when exact solution is known) double computeL2Error() const final; @@ -499,18 +499,18 @@ class Tomboulides final : public FlowBase { double getHelmholtzSolveTimer() { return sw_helm_.RealTime(); } /// Add a Dirichlet boundary condition to the velocity field - void addVelDirichletBC(const mfem::Vector &u, mfem::Array &attr); - void addVelDirichletBC(mfem::VectorCoefficient *coeff, mfem::Array &attr); - void addVelDirichletBC(void (*f)(const Vector &, double, Vector &), mfem::Array &attr); - void addVelDirichletBC(std::function f, mfem::Array &attr); + void addVelDirichletBC(const mfem::Vector& u, mfem::Array& attr); + void addVelDirichletBC(mfem::VectorCoefficient* coeff, mfem::Array& attr); + void addVelDirichletBC(void (*f)(const Vector&, double, Vector&), mfem::Array& attr); + void addVelDirichletBC(std::function f, mfem::Array& attr); /// Add a Dirichlet boundary condition to the pressure field. - void addPresDirichletBC(double p, mfem::Array &attr); + void addPresDirichletBC(double p, mfem::Array& attr); /// Add swirl DBCs - void addSwirlDirichletBC(double ut, mfem::Array &attr); - void addSwirlDirichletBC(mfem::Coefficient *coeff, mfem::Array &attr); - void addSwirlDirichletBC(double (*f)(const Vector &, double), Array &attr); + void addSwirlDirichletBC(double ut, mfem::Array& attr); + void addSwirlDirichletBC(mfem::Coefficient* coeff, mfem::Array& attr); + void addSwirlDirichletBC(double (*f)(const Vector&, double), Array& attr); /// Compute maximum velocity magnitude anywhere in the domain double maxVelocityMagnitude(); diff --git a/src/tps.cpp b/src/tps.cpp index 3ee945bc..0f0b14e7 100644 --- a/src/tps.cpp +++ b/src/tps.cpp @@ -125,12 +125,12 @@ void Tps::printHeader() { } /// Register and parse supported command line arguments and runtime inputs -void Tps::parseCommandLineArgs(int argc, char *argv[]) { +void Tps::parseCommandLineArgs(int argc, char* argv[]) { mfem::OptionsParser args(argc, argv); bool showVersion = false; bool debugMode = false; bool visualMode = false; - const char *astring = iFile_.c_str(); + const char* astring = iFile_.c_str(); if (isRank0_) { grvy_printf(GRVY_DEBUG, "# of command-line arguments = %i\n", argc); @@ -187,8 +187,8 @@ void Tps::parseCommandLineArgs(int argc, char *argv[]) { * It is intended for use with Python interface. */ void Tps::parseArgs(std::vector argv) { - std::vector argv_char; - for (auto &s : argv) argv_char.push_back(&s.front()); + std::vector argv_char; + for (auto& s : argv) argv_char.push_back(&s.front()); parseCommandLineArgs(argv_char.size(), argv_char.data()); } @@ -248,28 +248,28 @@ void Tps::chooseSolver() { if (input_solver_type_ == "flow") { isFlowOnlyMode_ = true; solver_ = new M2ulPhyS(iFile_, this); - if (isRank0_) std::cout << "Using compressible DG solver" << endl; + if (isRank0_) std::cout << "Using compressible DG solver" << endl; } else if (input_solver_type_ == "em") { isEMOnlyMode_ = true; ElectromagneticOptions em_opt; solver_ = new QuasiMagnetostaticSolver3D(em_opt, this); - if (isRank0_) std::cout << "Using quasi-magnetostatic solver" << endl; + if (isRank0_) std::cout << "Using quasi-magnetostatic solver" << endl; } else if (input_solver_type_ == "loMach") { solver_ = new LoMachSolver(this); - if (isRank0_) std::cout << "Using low-Mach solver" << endl; + if (isRank0_) std::cout << "Using low-Mach solver" << endl; } else if (input_solver_type_ == "em-axi") { isEMOnlyMode_ = true; ElectromagneticOptions em_opt; solver_ = new QuasiMagnetostaticSolverAxiSym(em_opt, this); - if (isRank0_) std::cout << "Using axisymmetric quasi-magnetostatic solver" << endl; + if (isRank0_) std::cout << "Using axisymmetric quasi-magnetostatic solver" << endl; } else if (input_solver_type_ == "independent-coupled") { isFlowEMCoupledMode_ = true; solver_ = new IndependentCoupling(iFile_, this); - if (isRank0_) std::cout << "Using independent-coupled solver" << endl; + if (isRank0_) std::cout << "Using independent-coupled solver" << endl; } else if (input_solver_type_ == "cycle-avg-joule-coupled") { isFlowEMCoupledMode_ = true; solver_ = new CycleAvgJouleCoupling(iFile_, this); - if (isRank0_) std::cout << "Using cycle-averaged joule-coupled solver" << endl; + if (isRank0_) std::cout << "Using cycle-averaged joule-coupled solver" << endl; } else if (input_solver_type_ == "coupled") { isFlowEMCoupledMode_ = true; grvy_printf(GRVY_ERROR, "\nSlow your roll. Solid high-five for whoever implements this coupled solver mode!\n"); @@ -353,7 +353,7 @@ void Tps::parseInput() { * keyword not present. Supported types are T={int,double,bool,std::string} */ template -void Tps::getInput(const char *name, T &var, T varDefault) { +void Tps::getInput(const char* name, T& var, T varDefault) { if (!iparse_.Read_Var(name, &var, varDefault)) { std::cout << "ERROR: Unable to read input variable -> " << name << std::endl; exit(ERROR); @@ -364,7 +364,7 @@ void Tps::getInput(const char *name, T &var, T varDefault) { /** Read an input vector for keyword [name] and store in var - use vdef if * keyword not present. Only mfem::Vector supported. */ -void Tps::getVec(const char *name, Vector &vec, size_t numElems, const Vector &vdef) { +void Tps::getVec(const char* name, Vector& vec, size_t numElems, const Vector& vdef) { if ((size_t)vdef.Size() < numElems) exit(ERROR); if ((size_t)vec.Size() < numElems) vec.SetSize(numElems); @@ -376,8 +376,8 @@ void Tps::getVec(const char *name, Vector &vec, size_t numElems, const Vector &v if (!iparse_.Read_Var_Vec(name, vec.HostWrite(), numElems)) { grvy_log_setlevel(grvy_log_level); if (isRank0_) grvy_printf(GRVY_INFO, "Setting input vector %s to default.\n", name); - double *hv = vec.HostWrite(); - const double *hd = vdef.HostRead(); + double* hv = vec.HostWrite(); + const double* hd = vdef.HostRead(); for (size_t i = 0; i < numElems; i++) { hv[i] = hd[i]; } @@ -390,7 +390,7 @@ void Tps::getVec(const char *name, Vector &vec, size_t numElems, const Vector &v * are T={int,double,bool,std::string} */ template -void Tps::getRequiredInput(const char *name, T &var) { +void Tps::getRequiredInput(const char* name, T& var) { if (!iparse_.Read_Var(name, &var)) { std::cout << "ERROR: Unable to read required input variable -> " << name << std::endl; exit(ERROR); @@ -403,7 +403,7 @@ void Tps::getRequiredInput(const char *name, T &var) { * @param[out] var vector variable to set (resized if necessary) * @param[in] numElems length of vector */ -void Tps::getRequiredVec(const char *name, std::vector &vec, size_t numElems) { +void Tps::getRequiredVec(const char* name, std::vector& vec, size_t numElems) { if (vec.size() < numElems) vec.reserve(numElems); if (!iparse_.Read_Var_Vec(name, vec.data(), numElems)) { std::cout << "ERROR: Unable to read input vector -> " << name << std::endl; @@ -412,7 +412,7 @@ void Tps::getRequiredVec(const char *name, std::vector &vec, size_t numE } /// @copydoc Tps::getRequiredVec(const char *,std::vector &,size_t) -void Tps::getRequiredVec(const char *name, Vector &vec, size_t numElems) { +void Tps::getRequiredVec(const char* name, Vector& vec, size_t numElems) { if ((size_t)vec.Size() < numElems) vec.SetSize(numElems); if (!iparse_.Read_Var_Vec(name, vec.HostWrite(), numElems)) { std::cout << "ERROR: Unable to read input vector -> " << name << std::endl; @@ -421,7 +421,7 @@ void Tps::getRequiredVec(const char *name, Vector &vec, size_t numElems) { } /// @copydoc Tps::getRequiredVec(const char *,Vector &,size_t) -void Tps::getRequiredVec(const char *name, mfem::Array &vec, size_t numElems) { +void Tps::getRequiredVec(const char* name, mfem::Array& vec, size_t numElems) { if ((size_t)vec.Size() < numElems) vec.SetSize(numElems); if (!iparse_.Read_Var_Vec(name, vec.HostWrite(), numElems)) { std::cout << "ERROR: Unable to read input vector -> " << name << std::endl; @@ -435,7 +435,7 @@ void Tps::getRequiredVec(const char *name, mfem::Array &vec, size_t numE * @param[inout] var vector variable to set * @param[in] ithElem index of element to set */ -void Tps::getRequiredVecElem(const char *name, double &value, int ithElem) { +void Tps::getRequiredVecElem(const char* name, double& value, int ithElem) { #if 1 if (!iparse_.Read_Var_iVec(name, &value, ithElem)) { grvy_printf(GRVY_ERROR, "Unable to read %ith element from input vector -> %s\n", ithElem, name); @@ -444,7 +444,7 @@ void Tps::getRequiredVecElem(const char *name, double &value, int ithElem) { #endif } -void Tps::getRequiredPairs(const char *name, std::vector> &var) { +void Tps::getRequiredPairs(const char* name, std::vector>& var) { std::string inputString; if (!iparse_.Read_Var(name, &inputString)) { std::cout << "ERROR: Unable to read required input variable -> " << name << std::endl; @@ -476,28 +476,28 @@ void Tps::getRequiredPairs(const char *name, std::vector(const char *name, int &var, int varDefault); -template void Tps::getInput(const char *name, double &var, double varDefault); -template void Tps::getInput(const char *name, std::string &var, std::string varDefault); -template void Tps::getInput(const char *name, bool &var, bool varDefault); +template void Tps::getInput(const char* name, int& var, int varDefault); +template void Tps::getInput(const char* name, double& var, double varDefault); +template void Tps::getInput(const char* name, std::string& var, std::string varDefault); +template void Tps::getInput(const char* name, bool& var, bool varDefault); // supported templates for getRequiredInput() -template void Tps::getRequiredInput(const char *name, int &var); -template void Tps::getRequiredInput(const char *name, double &var); -template void Tps::getRequiredInput(const char *name, std::string &var); +template void Tps::getRequiredInput(const char* name, int& var); +template void Tps::getRequiredInput(const char* name, double& var); +template void Tps::getRequiredInput(const char* name, std::string& var); } // end namespace TPS @@ -511,7 +511,7 @@ namespace py = pybind11; namespace tps_wrappers { -void tps(py::module &m) { +void tps(py::module& m) { #ifdef HAVE_MPI4PY // initialize mpi4py's C-API if (import_mpi4py() < 0) { @@ -537,10 +537,10 @@ void tps(py::module &m) { .def("parseCommandLineArgs", &TPS::Tps::parseArgs) .def("parseInput", &TPS::Tps::parseInput) .def("getRequiredInput", - static_cast(&TPS::Tps::getRequiredInput)) - .def("getRequiredInput", static_cast(&TPS::Tps::getRequiredInput)) - .def("getInput", static_cast(&TPS::Tps::getInput)) - .def("getInput", static_cast(&TPS::Tps::getInput)) + static_cast(&TPS::Tps::getRequiredInput)) + .def("getRequiredInput", static_cast(&TPS::Tps::getRequiredInput)) + .def("getInput", static_cast(&TPS::Tps::getInput)) + .def("getInput", static_cast(&TPS::Tps::getInput)) .def("solve", &TPS::Tps::solve) .def("solveBegin", &TPS::Tps::solveBegin) .def("solveStep", &TPS::Tps::solveStep) diff --git a/src/tps.hpp b/src/tps.hpp index 9b40ff6a..6c0c1382 100644 --- a/src/tps.hpp +++ b/src/tps.hpp @@ -96,7 +96,7 @@ class Tps { std::string meshFile_; // pointer to solver implementation chosen at runtime - TPS::Solver *solver_ = NULL; + TPS::Solver* solver_ = NULL; // post-process visualization mode bool isVisualizationMode_; @@ -115,39 +115,39 @@ class Tps { /// Input parsing support (variants with default value supplied) template - void getInput(const char *name, T &var, T varDefault); + void getInput(const char* name, T& var, T varDefault); /// Read optional mfem::Vector input (set to vdef if absent in input file) - void getVec(const char *name, Vector &vec, size_t numElems, const Vector &vdef); + void getVec(const char* name, Vector& vec, size_t numElems, const Vector& vdef); /// Parsing support for required (scalar) inputs template - void getRequiredInput(const char *name, T &var); + void getRequiredInput(const char* name, T& var); template - T getRequiredInput(const std::string &name) { + T getRequiredInput(const std::string& name) { T var; this->getRequiredInput(name.c_str(), var); return var; } template - T getInput(const std::string &name, T varDefault) { + T getInput(const std::string& name, T varDefault) { T var; this->getInput(name.c_str(), var, varDefault); return var; } /// Parsing support for required (vector) inputs - void getRequiredVec(const char *name, std::vector &var, size_t numElems); - void getRequiredVec(const char *name, Vector &var, size_t numElems); - void getRequiredVec(const char *name, Array &var, size_t numElems); + void getRequiredVec(const char* name, std::vector& var, size_t numElems); + void getRequiredVec(const char* name, Vector& var, size_t numElems); + void getRequiredVec(const char* name, Array& var, size_t numElems); /// Parsing support for required (single element of vector) inputs - void getRequiredVecElem(const char *name, double &var, int ithElem); + void getRequiredVecElem(const char* name, double& var, int ithElem); /// Read string-string pairs for keyword [name] and store in var. - void getRequiredPairs(const char *name, std::vector> &var); + void getRequiredPairs(const char* name, std::vector>& var); /// Get solver status int getStatus() { return solver_->getStatus(); } @@ -189,16 +189,16 @@ class Tps { } /// Initialize the interface - void initInterface(Tps2Boltzmann &interface) { solver_->initInterface(interface); } + void initInterface(Tps2Boltzmann& interface) { solver_->initInterface(interface); } /// Push solver variables to interface - void push(Tps2Boltzmann &interface) { solver_->push(interface); } + void push(Tps2Boltzmann& interface) { solver_->push(interface); } /// Fetch solver variables from interface - void fetch(Tps2Boltzmann &interface) { solver_->fetch(interface); } + void fetch(Tps2Boltzmann& interface) { solver_->fetch(interface); } void printHeader(); - void parseCommandLineArgs(int argc, char *argv[]); // variant used in C++ interface + void parseCommandLineArgs(int argc, char* argv[]); // variant used in C++ interface void parseArgs(std::vector argv); // variant used in python interface void parseInput(); @@ -209,15 +209,15 @@ class Tps { MPI_Comm getTPSCommWorld() { return TPSCommWorld_; } - std::string &getInputFilename() { return iFile_; } + std::string& getInputFilename() { return iFile_; } bool isFlowEMCoupled() const { return isFlowEMCoupledMode_; } bool isVisualizationMode() const { return isVisualizationMode_; } - const std::string &getSolverType() { return input_solver_type_; } + const std::string& getSolverType() { return input_solver_type_; } }; -std::string ltrim(const std::string &s); -std::string rtrim(const std::string &s); -std::string trim(const std::string &s); +std::string ltrim(const std::string& s); +std::string rtrim(const std::string& s); +std::string trim(const std::string& s); } // end namespace TPS diff --git a/src/tps2Boltzmann.cpp b/src/tps2Boltzmann.cpp index 689fded0..b0f5bbd3 100644 --- a/src/tps2Boltzmann.cpp +++ b/src/tps2Boltzmann.cpp @@ -50,35 +50,35 @@ namespace TPS { class CPUDataRead { public: - CPUDataRead(const mfem::Vector &v) : data_(v.HostRead()), size_(v.Size()), stride_(1) {} - double *data() const { return const_cast(data_); } + CPUDataRead(const mfem::Vector& v) : data_(v.HostRead()), size_(v.Size()), stride_(1) {} + double* data() const { return const_cast(data_); } size_t size() const { return size_; } size_t stride() const { return stride_; } private: - const double *data_; + const double* data_; size_t size_; size_t stride_; }; class CPUData { public: - CPUData(mfem::Vector &v, bool rw) : data_(rw ? v.HostReadWrite() : v.HostWrite()), size_(v.Size()), stride_(1) {} - double *data() { return data_; } + CPUData(mfem::Vector& v, bool rw) : data_(rw ? v.HostReadWrite() : v.HostWrite()), size_(v.Size()), stride_(1) {} + double* data() { return data_; } size_t size() const { return size_; } size_t stride() const { return stride_; } private: - double *data_; + double* data_; size_t size_; size_t stride_; }; -void idenity_fun(const Vector &x, Vector &out) { +void idenity_fun(const Vector& x, Vector& out) { for (int i(0); i < x.Size(); ++i) out[i] = x[i]; } -Tps2Boltzmann::Tps2Boltzmann(Tps *tps) +Tps2Boltzmann::Tps2Boltzmann(Tps* tps) : NIndexes(7), tps_(tps), all_fes_(nullptr), save_to_paraview_dc(false), paraview_dc(nullptr) { // Assert we have a couple solver; assert(tps->isFlowEMCoupled()); @@ -116,9 +116,9 @@ int Tps2Boltzmann::_countBTEReactions() { return bte_reactions; } -void Tps2Boltzmann::init(TPS::PlasmaSolver *flowSolver) { +void Tps2Boltzmann::init(TPS::PlasmaSolver* flowSolver) { std::cout << "Tps2Boltzmann::init is called" << std::endl; - mfem::ParMesh *pmesh(flowSolver->getMesh()); + mfem::ParMesh* pmesh(flowSolver->getMesh()); fec_ = new mfem::L2_FECollection(order_, pmesh->Dimension(), basis_type_); switch (pmesh->Dimension()) { case 2: @@ -139,7 +139,7 @@ void Tps2Boltzmann::init(TPS::PlasmaSolver *flowSolver) { scalar_fes_ = new mfem::ParFiniteElementSpace(pmesh, fec_); reaction_rates_fes_ = new mfem::ParFiniteElementSpace(pmesh, fec_, nreactions_, mfem::Ordering::byNODES); - list_fes_ = new mfem::ParFiniteElementSpace *[NIndexes + 1]; + list_fes_ = new mfem::ParFiniteElementSpace*[NIndexes + 1]; list_fes_[Index::ElectricField] = efield_fes_; ncomps[Index::ElectricField] = nEfieldComps_; list_fes_[Index::SpeciesDensities] = species_densities_fes_; @@ -157,8 +157,8 @@ void Tps2Boltzmann::init(TPS::PlasmaSolver *flowSolver) { list_fes_[Index::All] = all_fes_; ncomps[Index::All] = nfields_; - mfem::ParGridFunction *all = new mfem::ParGridFunction(all_fes_); - fields_ = new mfem::ParGridFunction *[NIndexes + 1]; + mfem::ParGridFunction* all = new mfem::ParGridFunction(all_fes_); + fields_ = new mfem::ParGridFunction*[NIndexes + 1]; offsets[0] = 0; for (std::size_t index(0); index < NIndexes; ++index) { fields_[index] = new mfem::ParGridFunction(list_fes_[index], *all, offsets[index]); @@ -167,14 +167,14 @@ void Tps2Boltzmann::init(TPS::PlasmaSolver *flowSolver) { fields_[Index::All] = all; // Native spaces - const mfem::FiniteElementCollection *fec_native(flowSolver->getFEC()); + const mfem::FiniteElementCollection* fec_native(flowSolver->getFEC()); species_densities_native_fes_ = new mfem::ParFiniteElementSpace(pmesh, fec_native, nspecies_, mfem::Ordering::byNODES); efield_native_fes_ = new mfem::ParFiniteElementSpace(pmesh, fec_native, nEfieldComps_, mfem::Ordering::byNODES); scalar_native_fes_ = new mfem::ParFiniteElementSpace(pmesh, fec_native); reaction_rates_native_fes_ = new mfem::ParFiniteElementSpace(pmesh, fec_native, nreactions_, mfem::Ordering::byNODES); - list_native_fes_ = new mfem::ParFiniteElementSpace *[NIndexes + 1]; + list_native_fes_ = new mfem::ParFiniteElementSpace*[NIndexes + 1]; list_native_fes_[Index::ElectricField] = efield_native_fes_; list_native_fes_[Index::SpeciesDensities] = species_densities_native_fes_; list_native_fes_[Index::HeavyTemperature] = scalar_native_fes_; @@ -199,7 +199,7 @@ void Tps2Boltzmann::init(TPS::PlasmaSolver *flowSolver) { spatial_coord_fes_ = new mfem::ParFiniteElementSpace(pmesh, fec_, pmesh->Dimension(), mfem::Ordering::byNODES); spatial_coordinates_ = new mfem::ParGridFunction(spatial_coord_fes_); mfem::VectorFunctionCoefficient coord_fun(pmesh->Dimension(), - std::function(idenity_fun)); + std::function(idenity_fun)); spatial_coordinates_->ProjectCoefficient(coord_fun); if (save_to_paraview_dc) { @@ -214,14 +214,14 @@ void Tps2Boltzmann::init(TPS::PlasmaSolver *flowSolver) { } } -void Tps2Boltzmann::interpolateFromNativeFES(const ParGridFunction &input, Tps2Boltzmann::Index index) { +void Tps2Boltzmann::interpolateFromNativeFES(const ParGridFunction& input, Tps2Boltzmann::Index index) { if (ncomps[index] == 1) { scalar_interpolator_->Mult(input, *(fields_[index])); } else { const int loc_size_native = list_native_fes_[index]->GetNDofs(); const int loc_size = list_fes_[index]->GetNDofs(); for (int icomp(0); icomp < ncomps[index]; ++icomp) { - const mfem::Vector view_input(const_cast(input), icomp * loc_size_native, + const mfem::Vector view_input(const_cast(input), icomp * loc_size_native, loc_size_native); mfem::Vector view_field(*(fields_[index]), icomp * loc_size, loc_size); scalar_interpolator_->Mult(view_input, view_field); @@ -229,7 +229,7 @@ void Tps2Boltzmann::interpolateFromNativeFES(const ParGridFunction &input, Tps2B } } -void Tps2Boltzmann::interpolateToNativeFES(ParGridFunction &output, Index index) { +void Tps2Boltzmann::interpolateToNativeFES(ParGridFunction& output, Index index) { if (ncomps[index] == 1) { scalar_interpolator_to_nativeFES_->Mult(*(fields_[index]), output); } else { @@ -291,10 +291,10 @@ Tps2Boltzmann::~Tps2Boltzmann() { namespace py = pybind11; namespace tps_wrappers { -void tps2bolzmann(py::module &m) { +void tps2bolzmann(py::module& m) { // Can by read in numpy as np.array(data_instance, copy = False) py::class_(m, "CPUDataRead", py::buffer_protocol()) - .def_buffer([](TPS::CPUDataRead &d) -> py::buffer_info { + .def_buffer([](TPS::CPUDataRead& d) -> py::buffer_info { return py::buffer_info(d.data(), /*pointer to buffer*/ sizeof(double), /*size of one element*/ py::format_descriptor::format(), /*python struct-style format descriptor*/ @@ -304,7 +304,7 @@ void tps2bolzmann(py::module &m) { true /*read only*/); }); - py::class_(m, "CPUData", py::buffer_protocol()).def_buffer([](TPS::CPUData &d) -> py::buffer_info { + py::class_(m, "CPUData", py::buffer_protocol()).def_buffer([](TPS::CPUData& d) -> py::buffer_info { return py::buffer_info(d.data(), /*pointer to buffer*/ sizeof(double), /*size of one element*/ py::format_descriptor::format(), /*python struct-style format descriptor*/ @@ -324,21 +324,21 @@ void tps2bolzmann(py::module &m) { .value("ReactionRates", TPS::Tps2Boltzmann::Index::ReactionRates); py::class_(m, "Tps2Boltzmann") - .def(py::init()) + .def(py::init()) .def("HostReadSpatialCoordinates", - [](const TPS::Tps2Boltzmann &interface) { + [](const TPS::Tps2Boltzmann& interface) { return std::unique_ptr(new TPS::CPUDataRead(interface.SpatialCoordinates())); }) .def("HostRead", - [](const TPS::Tps2Boltzmann &interface, TPS::Tps2Boltzmann::Index index) { + [](const TPS::Tps2Boltzmann& interface, TPS::Tps2Boltzmann::Index index) { return std::unique_ptr(new TPS::CPUDataRead(interface.Field(index))); }) .def("HostWrite", - [](TPS::Tps2Boltzmann &interface, TPS::Tps2Boltzmann::Index index) { + [](TPS::Tps2Boltzmann& interface, TPS::Tps2Boltzmann::Index index) { return std::unique_ptr(new TPS::CPUData(interface.Field(index), false)); }) .def("HostReadWrite", - [](TPS::Tps2Boltzmann &interface, TPS::Tps2Boltzmann::Index index) { + [](TPS::Tps2Boltzmann& interface, TPS::Tps2Boltzmann::Index index) { return std::unique_ptr(new TPS::CPUData(interface.Field(index), true)); }) .def("EfieldAngularFreq", &TPS::Tps2Boltzmann::EfieldAngularFreq) diff --git a/src/tps2Boltzmann.hpp b/src/tps2Boltzmann.hpp index 5dc39adb..5cf4aa19 100644 --- a/src/tps2Boltzmann.hpp +++ b/src/tps2Boltzmann.hpp @@ -89,24 +89,24 @@ class Tps2Boltzmann { //! Total number of fields const std::size_t NIndexes; - Tps2Boltzmann(Tps *tps); - void init(TPS::PlasmaSolver *flowSolver); + Tps2Boltzmann(Tps* tps); + void init(TPS::PlasmaSolver* flowSolver); bool IsInitialized() const { return all_fes_ != nullptr; } - const mfem::ParFiniteElementSpace &Fes(Index index) const { return *(list_fes_[index]); } - mfem::ParFiniteElementSpace &Fes(Index index) { return *(list_fes_[index]); } + const mfem::ParFiniteElementSpace& Fes(Index index) const { return *(list_fes_[index]); } + mfem::ParFiniteElementSpace& Fes(Index index) { return *(list_fes_[index]); } - const mfem::ParFiniteElementSpace &NativeFes(Index index) const { return *(list_native_fes_[index]); } - mfem::ParFiniteElementSpace &NativeFes(Index index) { return *(list_native_fes_[index]); } + const mfem::ParFiniteElementSpace& NativeFes(Index index) const { return *(list_native_fes_[index]); } + mfem::ParFiniteElementSpace& NativeFes(Index index) { return *(list_native_fes_[index]); } - const mfem::ParGridFunction &SpatialCoordinates() const { return *spatial_coordinates_; } - mfem::ParGridFunction &SpatialCoordinates() { return *spatial_coordinates_; } + const mfem::ParGridFunction& SpatialCoordinates() const { return *spatial_coordinates_; } + mfem::ParGridFunction& SpatialCoordinates() { return *spatial_coordinates_; } - const mfem::ParGridFunction &Field(Index index) const { return *(fields_[index]); } - mfem::ParGridFunction &Field(Index index) { return *(fields_[index]); } + const mfem::ParGridFunction& Field(Index index) const { return *(fields_[index]); } + mfem::ParGridFunction& Field(Index index) { return *(fields_[index]); } - void interpolateFromNativeFES(const ParGridFunction &input, Index index); - void interpolateToNativeFES(ParGridFunction &output, Index index); + void interpolateFromNativeFES(const ParGridFunction& input, Index index); + void interpolateToNativeFES(ParGridFunction& output, Index index); //! Get the angular Frequency \omega of the electrical field: //! E(t) = Er*cos(\omega t) + Ei*sin(\omega t) @@ -128,7 +128,7 @@ class Tps2Boltzmann { private: int _countBTEReactions(); - Tps *tps_; + Tps* tps_; int nspecies_; int nEfieldComps_; @@ -139,39 +139,39 @@ class Tps2Boltzmann { mfem::Array offsets; mfem::Array ncomps; - mfem::FiniteElementCollection *fec_; + mfem::FiniteElementCollection* fec_; //! Function spaces in the Boltzmann interface - mfem::ParFiniteElementSpace *all_fes_; - mfem::ParFiniteElementSpace *species_densities_fes_; - mfem::ParFiniteElementSpace *efield_fes_; - mfem::ParFiniteElementSpace *scalar_fes_; - mfem::ParFiniteElementSpace *reaction_rates_fes_; - mfem::ParFiniteElementSpace **list_fes_; + mfem::ParFiniteElementSpace* all_fes_; + mfem::ParFiniteElementSpace* species_densities_fes_; + mfem::ParFiniteElementSpace* efield_fes_; + mfem::ParFiniteElementSpace* scalar_fes_; + mfem::ParFiniteElementSpace* reaction_rates_fes_; + mfem::ParFiniteElementSpace** list_fes_; - mfem::ParFiniteElementSpace *spatial_coord_fes_; + mfem::ParFiniteElementSpace* spatial_coord_fes_; //! Function spaces using the native TPS fec - mfem::ParFiniteElementSpace *species_densities_native_fes_; - mfem::ParFiniteElementSpace *efield_native_fes_; - mfem::ParFiniteElementSpace *scalar_native_fes_; - mfem::ParFiniteElementSpace *reaction_rates_native_fes_; - mfem::ParFiniteElementSpace **list_native_fes_; + mfem::ParFiniteElementSpace* species_densities_native_fes_; + mfem::ParFiniteElementSpace* efield_native_fes_; + mfem::ParFiniteElementSpace* scalar_native_fes_; + mfem::ParFiniteElementSpace* reaction_rates_native_fes_; + mfem::ParFiniteElementSpace** list_native_fes_; //! Linear interpolator between native TPS fec to Interface fec - mfem::ParDiscreteLinearOperator *scalar_interpolator_; - mfem::ParDiscreteLinearOperator *scalar_interpolator_to_nativeFES_; + mfem::ParDiscreteLinearOperator* scalar_interpolator_; + mfem::ParDiscreteLinearOperator* scalar_interpolator_to_nativeFES_; //! array of fields see *Index for how to address this - mfem::ParGridFunction **fields_; - mfem::ParGridFunction *spatial_coordinates_; + mfem::ParGridFunction** fields_; + mfem::ParGridFunction* spatial_coordinates_; double EfieldAngularFreq_; double timestep_; double currentTime_; bool save_to_paraview_dc; - mfem::ParaViewDataCollection *paraview_dc; + mfem::ParaViewDataCollection* paraview_dc; std::vector reaction_eqs_; }; } // namespace TPS diff --git a/src/transport_properties.cpp b/src/transport_properties.cpp index bdc4ce99..cde165f7 100644 --- a/src/transport_properties.cpp +++ b/src/transport_properties.cpp @@ -32,7 +32,7 @@ #include "transport_properties.hpp" -MFEM_HOST_DEVICE TransportProperties::TransportProperties(GasMixture *_mixture) : mixture(_mixture) { +MFEM_HOST_DEVICE TransportProperties::TransportProperties(GasMixture* _mixture) : mixture(_mixture) { numSpecies = mixture->GetNumSpecies(); dim = mixture->GetDimension(); nvel_ = mixture->GetNumVels(); @@ -42,7 +42,7 @@ MFEM_HOST_DEVICE TransportProperties::TransportProperties(GasMixture *_mixture) num_equation = mixture->GetNumEquations(); } -void TransportProperties::correctMassDiffusionFlux(const Vector &Y_sp, DenseMatrix &diffusionVelocity) { +void TransportProperties::correctMassDiffusionFlux(const Vector& Y_sp, DenseMatrix& diffusionVelocity) { correctMassDiffusionFlux(&Y_sp[0], diffusionVelocity.Write()); // // Correction Velocity // Vector Vc(nvel_); @@ -56,7 +56,7 @@ void TransportProperties::correctMassDiffusionFlux(const Vector &Y_sp, DenseMatr // } } -MFEM_HOST_DEVICE void TransportProperties::correctMassDiffusionFlux(const double *Y_sp, double *diffusionVelocity) { +MFEM_HOST_DEVICE void TransportProperties::correctMassDiffusionFlux(const double* Y_sp, double* diffusionVelocity) { // Correction Velocity double Vc[gpudata::MAXDIM]; for (int v = 0; v < nvel_; v++) Vc[v] = 0.0; @@ -69,7 +69,7 @@ MFEM_HOST_DEVICE void TransportProperties::correctMassDiffusionFlux(const double } } -double TransportProperties::computeMixtureElectricConductivity(const Vector &mobility, const Vector &n_sp) { +double TransportProperties::computeMixtureElectricConductivity(const Vector& mobility, const Vector& n_sp) { return computeMixtureElectricConductivity(&mobility[0], &n_sp[0]); // double mho = 0.0; // electric conductivity. // @@ -80,8 +80,8 @@ double TransportProperties::computeMixtureElectricConductivity(const Vector &mob // return mho; } -MFEM_HOST_DEVICE double TransportProperties::computeMixtureElectricConductivity(const double *mobility, - const double *n_sp) { +MFEM_HOST_DEVICE double TransportProperties::computeMixtureElectricConductivity(const double* mobility, + const double* n_sp) { double mho = 0.0; // electric conductivity. for (int sp = 0; sp < numSpecies; sp++) { @@ -91,8 +91,8 @@ MFEM_HOST_DEVICE double TransportProperties::computeMixtureElectricConductivity( return mho; } -void TransportProperties::addAmbipolarEfield(const Vector &mobility, const Vector &n_sp, - DenseMatrix &diffusionVelocity) { +void TransportProperties::addAmbipolarEfield(const Vector& mobility, const Vector& n_sp, + DenseMatrix& diffusionVelocity) { addAmbipolarEfield(&mobility[0], &n_sp[0], diffusionVelocity.Write()); // double mho = computeMixtureElectricConductivity(mobility, n_sp); // @@ -112,8 +112,8 @@ void TransportProperties::addAmbipolarEfield(const Vector &mobility, const Vecto // } } -MFEM_HOST_DEVICE void TransportProperties::addAmbipolarEfield(const double *mobility, const double *n_sp, - double *diffusionVelocity) { +MFEM_HOST_DEVICE void TransportProperties::addAmbipolarEfield(const double* mobility, const double* n_sp, + double* diffusionVelocity) { double mho = computeMixtureElectricConductivity(mobility, n_sp); double ambE[gpudata::MAXDIM]; @@ -133,8 +133,8 @@ MFEM_HOST_DEVICE void TransportProperties::addAmbipolarEfield(const double *mobi } } -void TransportProperties::addMixtureDrift(const Vector &mobility, const Vector &n_sp, const Vector &Efield, - DenseMatrix &diffusionVelocity) { +void TransportProperties::addMixtureDrift(const Vector& mobility, const Vector& n_sp, const Vector& Efield, + DenseMatrix& diffusionVelocity) { addMixtureDrift(&mobility[0], &n_sp[0], &Efield[0], diffusionVelocity.Write()); // for (int sp = 0; sp < numSpecies; sp++) { // if (mixture->GetGasParams(sp, GasParams::SPECIES_CHARGES) == 0.0) continue; @@ -143,8 +143,8 @@ void TransportProperties::addMixtureDrift(const Vector &mobility, const Vector & // } } -MFEM_HOST_DEVICE void TransportProperties::addMixtureDrift(const double *mobility, const double *n_sp, - const double *Efield, double *diffusionVelocity) { +MFEM_HOST_DEVICE void TransportProperties::addMixtureDrift(const double* mobility, const double* n_sp, + const double* Efield, double* diffusionVelocity) { for (int sp = 0; sp < numSpecies; sp++) { if (mixture->GetGasParams(sp, GasParams::SPECIES_CHARGES) == 0.0) continue; @@ -152,7 +152,7 @@ MFEM_HOST_DEVICE void TransportProperties::addMixtureDrift(const double *mobilit } } -double TransportProperties::linearAverage(const Vector &X_sp, const Vector &speciesTransport) { +double TransportProperties::linearAverage(const Vector& X_sp, const Vector& speciesTransport) { return linearAverage(&X_sp[0], &speciesTransport[0]); // double average = 0.0; // @@ -161,7 +161,7 @@ double TransportProperties::linearAverage(const Vector &X_sp, const Vector &spec // return average; } -MFEM_HOST_DEVICE double TransportProperties::linearAverage(const double *X_sp, const double *speciesTransport) { +MFEM_HOST_DEVICE double TransportProperties::linearAverage(const double* X_sp, const double* speciesTransport) { double average = 0.0; for (int sp = 0; sp < numSpecies; sp++) average += X_sp[sp] * speciesTransport[sp]; @@ -169,8 +169,8 @@ MFEM_HOST_DEVICE double TransportProperties::linearAverage(const double *X_sp, c return average; } -void TransportProperties::CurtissHirschfelder(const Vector &X_sp, const Vector &Y_sp, const DenseMatrix &binaryDiff, - Vector &avgDiff) { +void TransportProperties::CurtissHirschfelder(const Vector& X_sp, const Vector& Y_sp, const DenseMatrix& binaryDiff, + Vector& avgDiff) { CurtissHirschfelder(&X_sp[0], &Y_sp[0], binaryDiff.Read(), &avgDiff[0]); // avgDiff.SetSize(numSpecies); // avgDiff = 0.0; @@ -185,8 +185,8 @@ void TransportProperties::CurtissHirschfelder(const Vector &X_sp, const Vector & // } } -MFEM_HOST_DEVICE void TransportProperties::CurtissHirschfelder(const double *X_sp, const double *Y_sp, - const double *binaryDiff, double *avgDiff) { +MFEM_HOST_DEVICE void TransportProperties::CurtissHirschfelder(const double* X_sp, const double* Y_sp, + const double* binaryDiff, double* avgDiff) { for (int sp = 0; sp < numSpecies; sp++) avgDiff[sp] = 0.0; for (int spI = 0; spI < numSpecies; spI++) { @@ -202,11 +202,11 @@ MFEM_HOST_DEVICE void TransportProperties::CurtissHirschfelder(const double *X_s //////// Dry Air mixture ////////////////////////////////////////////////////// -DryAirTransport::DryAirTransport(GasMixture *_mixture, RunConfiguration &_runfile) +DryAirTransport::DryAirTransport(GasMixture* _mixture, RunConfiguration& _runfile) : DryAirTransport(_mixture, _runfile.GetViscMult(), _runfile.GetBulkViscMult(), _runfile.sutherland_.C1, _runfile.sutherland_.S0, _runfile.sutherland_.Pr) {} -MFEM_HOST_DEVICE DryAirTransport::DryAirTransport(GasMixture *_mixture, const double viscosity_multiplier, +MFEM_HOST_DEVICE DryAirTransport::DryAirTransport(GasMixture* _mixture, const double viscosity_multiplier, const double bulk_viscosity, const double C1, const double S, const double Pr) : MolecularTransport(_mixture), @@ -221,9 +221,9 @@ MFEM_HOST_DEVICE DryAirTransport::DryAirTransport(GasMixture *_mixture, const do cp_div_pr = specific_heat_ratio * gas_constant / (Pr_ * (specific_heat_ratio - 1.)); } -MFEM_HOST_DEVICE void DryAirTransport::ComputeFluxMolecularTransport(const double *state, const double *gradUp, - const double *Efield, double *transportBuffer, - double *diffusionVelocity) { +MFEM_HOST_DEVICE void DryAirTransport::ComputeFluxMolecularTransport(const double* state, const double* gradUp, + const double* Efield, double* transportBuffer, + double* diffusionVelocity) { double p = mixture->ComputePressure(state); double temp = p / gas_constant / state[0]; @@ -269,7 +269,7 @@ MFEM_HOST_DEVICE void DryAirTransport::ComputeFluxMolecularTransport(const doubl //////// Constant transport ////////////////////////////////////////////////////// -ConstantTransport::ConstantTransport(GasMixture *_mixture, RunConfiguration &_runfile) +ConstantTransport::ConstantTransport(GasMixture* _mixture, RunConfiguration& _runfile) : ConstantTransport(_mixture, _runfile.constantTransport) {} // ConstantTransport::ConstantTransport(GasMixture *_mixture, RunConfiguration &_runfile) : // TransportProperties(_mixture) { @@ -300,7 +300,7 @@ ConstantTransport::ConstantTransport(GasMixture *_mixture, RunConfiguration &_ru // } // } -MFEM_HOST_DEVICE ConstantTransport::ConstantTransport(GasMixture *_mixture, const constantTransportData &inputs) +MFEM_HOST_DEVICE ConstantTransport::ConstantTransport(GasMixture* _mixture, const constantTransportData& inputs) : MolecularTransport(_mixture) { viscosity_ = inputs.viscosity; bulkViscosity_ = inputs.bulkViscosity; @@ -331,9 +331,9 @@ MFEM_HOST_DEVICE ConstantTransport::ConstantTransport(GasMixture *_mixture, cons } } -MFEM_HOST_DEVICE void ConstantTransport::ComputeFluxMolecularTransport(const double *state, const double *gradUp, - const double *Efield, double *transportBuffer, - double *diffusionVelocity) { +MFEM_HOST_DEVICE void ConstantTransport::ComputeFluxMolecularTransport(const double* state, const double* gradUp, + const double* Efield, double* transportBuffer, + double* diffusionVelocity) { transportBuffer[FluxTrns::VISCOSITY] = viscosity_; transportBuffer[FluxTrns::BULK_VISCOSITY] = bulkViscosity_; transportBuffer[FluxTrns::HEAVY_THERMAL_CONDUCTIVITY] = thermalConductivity_; @@ -386,11 +386,11 @@ MFEM_HOST_DEVICE void ConstantTransport::ComputeFluxMolecularTransport(const dou } } -MFEM_HOST_DEVICE void ConstantTransport::ComputeSourceMolecularTransport(const double *state, const double *Up, - const double *gradUp, const double *Efield, - double *globalTransport, - double *speciesTransport, - double *diffusionVelocity, double *n_sp) { +MFEM_HOST_DEVICE void ConstantTransport::ComputeSourceMolecularTransport(const double* state, const double* Up, + const double* gradUp, const double* Efield, + double* globalTransport, + double* speciesTransport, + double* diffusionVelocity, double* n_sp) { for (int i = 0; i < SrcTrns::NUM_SRC_TRANS; i++) globalTransport[i] = 0.0; for (int c = 0; c < SpeciesTrns::NUM_SPECIES_COEFFS; c++) for (int sp = 0; sp < numSpecies; sp++) speciesTransport[sp + c * numSpecies] = 0.0; diff --git a/src/transport_properties.hpp b/src/transport_properties.hpp index f44845b9..78b44b4a 100644 --- a/src/transport_properties.hpp +++ b/src/transport_properties.hpp @@ -59,7 +59,7 @@ class TransportProperties { bool ambipolar; bool twoTemperature_; - GasMixture *mixture; + GasMixture* mixture; // Array isComputed; // SpeciesPrimitiveType speciesPrimitiveType; @@ -69,7 +69,7 @@ class TransportProperties { public: // TransportProperties(GasMixture *_mixture); - MFEM_HOST_DEVICE TransportProperties(GasMixture *_mixture); + MFEM_HOST_DEVICE TransportProperties(GasMixture* _mixture); // virtual ~TransportProperties() {} MFEM_HOST_DEVICE virtual ~TransportProperties() {} @@ -85,25 +85,25 @@ class TransportProperties { // but do not return it as output. // TODO(kevin): need to discuss whether to reuse computed primitive variables in flux evaluation, // or in general evaluation of primitive variables. - virtual void ComputeFluxTransportProperties(const Vector &state, const DenseMatrix &gradUp, const Vector &Efield, - double radius, double distance, Vector &transportBuffer, - DenseMatrix &diffusionVelocity) = 0; - MFEM_HOST_DEVICE virtual void ComputeFluxTransportProperties(const double *state, const double *gradUp, - const double *Efield, double radius, double distance, - double *transportBuffer, double *diffusionVelocity) = 0; + virtual void ComputeFluxTransportProperties(const Vector& state, const DenseMatrix& gradUp, const Vector& Efield, + double radius, double distance, Vector& transportBuffer, + DenseMatrix& diffusionVelocity) = 0; + MFEM_HOST_DEVICE virtual void ComputeFluxTransportProperties(const double* state, const double* gradUp, + const double* Efield, double radius, double distance, + double* transportBuffer, double* diffusionVelocity) = 0; // Source term will be constructed using ForcingTerms, which have pointers to primitive variables. // So we can use them in evaluating transport properties. // If this routine evaluate additional primitive variables, can return them just as the routine above. - virtual void ComputeSourceTransportProperties(const Vector &state, const Vector &Up, const DenseMatrix &gradUp, - const Vector &Efield, double distance, Vector &globalTransport, - DenseMatrix &speciesTransport, DenseMatrix &diffusionVelocity, - Vector &n_sp) = 0; - MFEM_HOST_DEVICE virtual void ComputeSourceTransportProperties(const double *state, const double *Up, - const double *gradUp, const double *Efield, - double distance, double *globalTransport, - double *speciesTransport, double *diffusionVelocity, - double *n_sp) = 0; + virtual void ComputeSourceTransportProperties(const Vector& state, const Vector& Up, const DenseMatrix& gradUp, + const Vector& Efield, double distance, Vector& globalTransport, + DenseMatrix& speciesTransport, DenseMatrix& diffusionVelocity, + Vector& n_sp) = 0; + MFEM_HOST_DEVICE virtual void ComputeSourceTransportProperties(const double* state, const double* Up, + const double* gradUp, const double* Efield, + double distance, double* globalTransport, + double* speciesTransport, double* diffusionVelocity, + double* n_sp) = 0; /** @brief Evaluate viscosity and bulk viscosity * @@ -116,7 +116,7 @@ class TransportProperties { * @param primitive Pointer to primitive state vector * @param visc Pointer to viscosities (visc[0] = dynamic viscosity, visc[1] = bulk viscosity) */ - MFEM_HOST_DEVICE virtual void GetViscosities(const double *conserved, const double *primitive, double *visc) = 0; + MFEM_HOST_DEVICE virtual void GetViscosities(const double* conserved, const double* primitive, double* visc) = 0; /** @brief Evaluate viscosity and bulk viscosity * @@ -133,67 +133,67 @@ class TransportProperties { * @param distance Distance to the nearest no-slip wall * @param visc Pointer to viscosities (visc[0] = dynamic viscosity, visc[1] = bulk viscosity) */ - MFEM_HOST_DEVICE virtual void GetViscosities(const double *conserved, const double *primitive, const double *gradUp, - double radius, double distance, double *visc) = 0; + MFEM_HOST_DEVICE virtual void GetViscosities(const double* conserved, const double* primitive, const double* gradUp, + double radius, double distance, double* visc) = 0; // For mixture-averaged diffusion, correct for mass conservation. - void correctMassDiffusionFlux(const Vector &Y_sp, DenseMatrix &diffusionVelocity); - MFEM_HOST_DEVICE void correctMassDiffusionFlux(const double *Y_sp, double *diffusionVelocity); + void correctMassDiffusionFlux(const Vector& Y_sp, DenseMatrix& diffusionVelocity); + MFEM_HOST_DEVICE void correctMassDiffusionFlux(const double* Y_sp, double* diffusionVelocity); // compute electric conductivity for mixture-averaged diffusions. // NOTE: in unit of ELECTRONCHARGE * AVOGADRONUMBER. - double computeMixtureElectricConductivity(const Vector &mobility, const Vector &n_sp); - MFEM_HOST_DEVICE double computeMixtureElectricConductivity(const double *mobility, const double *n_sp); + double computeMixtureElectricConductivity(const Vector& mobility, const Vector& n_sp); + MFEM_HOST_DEVICE double computeMixtureElectricConductivity(const double* mobility, const double* n_sp); // These are only for mixture-averaged diffusivity models. - void addAmbipolarEfield(const Vector &mobility, const Vector &n_sp, DenseMatrix &diffusionVelocity); - MFEM_HOST_DEVICE void addAmbipolarEfield(const double *mobility, const double *n_sp, double *diffusionVelocity); - void addMixtureDrift(const Vector &mobility, const Vector &n_sp, const Vector &Efield, - DenseMatrix &diffusionVelocity); - MFEM_HOST_DEVICE void addMixtureDrift(const double *mobility, const double *n_sp, const double *Efield, - double *diffusionVelocity); - double linearAverage(const Vector &X_sp, const Vector &speciesTransport); - MFEM_HOST_DEVICE double linearAverage(const double *X_sp, const double *speciesTransport); + void addAmbipolarEfield(const Vector& mobility, const Vector& n_sp, DenseMatrix& diffusionVelocity); + MFEM_HOST_DEVICE void addAmbipolarEfield(const double* mobility, const double* n_sp, double* diffusionVelocity); + void addMixtureDrift(const Vector& mobility, const Vector& n_sp, const Vector& Efield, + DenseMatrix& diffusionVelocity); + MFEM_HOST_DEVICE void addMixtureDrift(const double* mobility, const double* n_sp, const double* Efield, + double* diffusionVelocity); + double linearAverage(const Vector& X_sp, const Vector& speciesTransport); + MFEM_HOST_DEVICE double linearAverage(const double* X_sp, const double* speciesTransport); // Curtiss-Hirschfelder approximation of diffusivity. - void CurtissHirschfelder(const Vector &X_sp, const Vector &Y_sp, const DenseMatrix &binaryDiff, Vector &avgDiff); - MFEM_HOST_DEVICE void CurtissHirschfelder(const double *X_sp, const double *Y_sp, const double *binaryDiff, - double *avgDiff); + void CurtissHirschfelder(const Vector& X_sp, const Vector& Y_sp, const DenseMatrix& binaryDiff, Vector& avgDiff); + MFEM_HOST_DEVICE void CurtissHirschfelder(const double* X_sp, const double* Y_sp, const double* binaryDiff, + double* avgDiff); }; /** Class for molecular transport (as opposed to turbulent transport) */ class MolecularTransport : public TransportProperties { public: - MFEM_HOST_DEVICE MolecularTransport(GasMixture *_mixture) : TransportProperties(_mixture) {} + MFEM_HOST_DEVICE MolecularTransport(GasMixture* _mixture) : TransportProperties(_mixture) {} MFEM_HOST_DEVICE virtual ~MolecularTransport() {} - MFEM_HOST_DEVICE virtual void ComputeFluxMolecularTransport(const double *state, const double *gradUp, - const double *Efield, double *transportBuffer, - double *diffusionVelocity) = 0; + MFEM_HOST_DEVICE virtual void ComputeFluxMolecularTransport(const double* state, const double* gradUp, + const double* Efield, double* transportBuffer, + double* diffusionVelocity) = 0; - void ComputeFluxTransportProperties(const Vector &state, const DenseMatrix &gradUp, const Vector &Efield, - double radius, double distance, Vector &transportBuffer, - DenseMatrix &diffusionVelocity) final { + void ComputeFluxTransportProperties(const Vector& state, const DenseMatrix& gradUp, const Vector& Efield, + double radius, double distance, Vector& transportBuffer, + DenseMatrix& diffusionVelocity) final { transportBuffer.SetSize(FluxTrns::NUM_FLUX_TRANS); diffusionVelocity.SetSize(numSpecies, nvel_); ComputeFluxTransportProperties(&state[0], gradUp.Read(), &Efield[0], radius, distance, &transportBuffer[0], diffusionVelocity.Write()); } - MFEM_HOST_DEVICE void ComputeFluxTransportProperties(const double *state, const double *gradUp, const double *Efield, - double radius, double distance, double *transportBuffer, - double *diffusionVelocity) final { + MFEM_HOST_DEVICE void ComputeFluxTransportProperties(const double* state, const double* gradUp, const double* Efield, + double radius, double distance, double* transportBuffer, + double* diffusionVelocity) final { ComputeFluxMolecularTransport(state, gradUp, Efield, transportBuffer, diffusionVelocity); } - MFEM_HOST_DEVICE virtual void ComputeSourceMolecularTransport(const double *state, const double *Up, - const double *gradUp, const double *Efield, - double *globalTransport, double *speciesTransport, - double *diffusionVelocity, double *n_sp) = 0; + MFEM_HOST_DEVICE virtual void ComputeSourceMolecularTransport(const double* state, const double* Up, + const double* gradUp, const double* Efield, + double* globalTransport, double* speciesTransport, + double* diffusionVelocity, double* n_sp) = 0; - void ComputeSourceTransportProperties(const Vector &state, const Vector &Up, const DenseMatrix &gradUp, - const Vector &Efield, double distance, Vector &globalTransport, - DenseMatrix &speciesTransport, DenseMatrix &diffusionVelocity, - Vector &n_sp) final { + void ComputeSourceTransportProperties(const Vector& state, const Vector& Up, const DenseMatrix& gradUp, + const Vector& Efield, double distance, Vector& globalTransport, + DenseMatrix& speciesTransport, DenseMatrix& diffusionVelocity, + Vector& n_sp) final { globalTransport.SetSize(SrcTrns::NUM_SRC_TRANS); speciesTransport.SetSize(numSpecies, SpeciesTrns::NUM_SPECIES_COEFFS); n_sp.SetSize(numSpecies); @@ -202,20 +202,20 @@ class MolecularTransport : public TransportProperties { speciesTransport.Write(), diffusionVelocity.Write(), &n_sp[0]); } - MFEM_HOST_DEVICE void ComputeSourceTransportProperties(const double *state, const double *Up, const double *gradUp, - const double *Efield, double distance, double *globalTransport, - double *speciesTransport, double *diffusionVelocity, - double *n_sp) final { + MFEM_HOST_DEVICE void ComputeSourceTransportProperties(const double* state, const double* Up, const double* gradUp, + const double* Efield, double distance, double* globalTransport, + double* speciesTransport, double* diffusionVelocity, + double* n_sp) final { ComputeSourceMolecularTransport(state, Up, gradUp, Efield, globalTransport, speciesTransport, diffusionVelocity, n_sp); } - MFEM_HOST_DEVICE void GetViscosities(const double *conserved, const double *primitive, double *visc) override { + MFEM_HOST_DEVICE void GetViscosities(const double* conserved, const double* primitive, double* visc) override { printf("MolecularTransport::GetViscosities is not implemented!\n"); } - MFEM_HOST_DEVICE void GetViscosities(const double *conserved, const double *primitive, const double *gradUp, - double radius, double distance, double *visc) final { + MFEM_HOST_DEVICE void GetViscosities(const double* conserved, const double* primitive, const double* gradUp, + double radius, double distance, double* visc) final { GetViscosities(conserved, primitive, visc); } }; @@ -243,26 +243,26 @@ class DryAirTransport : public MolecularTransport { double Sc; // Schmidt number public: - DryAirTransport(GasMixture *_mixture, RunConfiguration &_runfile); - MFEM_HOST_DEVICE DryAirTransport(GasMixture *_mixture, const double viscosity_multiplier, const double bulk_viscosity, + DryAirTransport(GasMixture* _mixture, RunConfiguration& _runfile); + MFEM_HOST_DEVICE DryAirTransport(GasMixture* _mixture, const double viscosity_multiplier, const double bulk_viscosity, const double C1 = 1.458e-6, const double S = 110.4, const double Pr = 0.71); MFEM_HOST_DEVICE virtual ~DryAirTransport() {} - MFEM_HOST_DEVICE void ComputeFluxMolecularTransport(const double *state, const double *gradUp, const double *Efield, - double *transportBuffer, double *diffusionVelocity) final; + MFEM_HOST_DEVICE void ComputeFluxMolecularTransport(const double* state, const double* gradUp, const double* Efield, + double* transportBuffer, double* diffusionVelocity) final; - MFEM_HOST_DEVICE void ComputeSourceMolecularTransport(const double *state, const double *Up, const double *gradUp, - const double *Efield, double *globalTransport, - double *speciesTransport, double *diffusionVelocity, - double *n_sp) final {} + MFEM_HOST_DEVICE void ComputeSourceMolecularTransport(const double* state, const double* Up, const double* gradUp, + const double* Efield, double* globalTransport, + double* speciesTransport, double* diffusionVelocity, + double* n_sp) final {} using MolecularTransport::GetViscosities; - MFEM_HOST_DEVICE void GetViscosities(const double *conserved, const double *primitive, double *visc) final; + MFEM_HOST_DEVICE void GetViscosities(const double* conserved, const double* primitive, double* visc) final; }; -MFEM_HOST_DEVICE inline void DryAirTransport::GetViscosities(const double *conserved, const double *primitive, - double *visc) { +MFEM_HOST_DEVICE inline void DryAirTransport::GetViscosities(const double* conserved, const double* primitive, + double* visc) { const double temp = primitive[1 + nvel_]; visc[0] = (C1_ * visc_mult * pow(temp, 1.5) / (temp + S0_)); visc[1] = bulk_visc_mult * visc[0]; @@ -285,25 +285,25 @@ class ConstantTransport : public MolecularTransport { const double qeOverkB_ = ELECTRONCHARGE / BOLTZMANNCONSTANT; public: - ConstantTransport(GasMixture *_mixture, RunConfiguration &_runfile); - MFEM_HOST_DEVICE ConstantTransport(GasMixture *_mixture, const constantTransportData &inputs); + ConstantTransport(GasMixture* _mixture, RunConfiguration& _runfile); + MFEM_HOST_DEVICE ConstantTransport(GasMixture* _mixture, const constantTransportData& inputs); MFEM_HOST_DEVICE virtual ~ConstantTransport() {} - MFEM_HOST_DEVICE void ComputeFluxMolecularTransport(const double *state, const double *gradUp, const double *Efield, - double *transportBuffer, double *diffusionVelocity) final; + MFEM_HOST_DEVICE void ComputeFluxMolecularTransport(const double* state, const double* gradUp, const double* Efield, + double* transportBuffer, double* diffusionVelocity) final; - MFEM_HOST_DEVICE void ComputeSourceMolecularTransport(const double *state, const double *Up, const double *gradUp, - const double *Efield, double *globalTransport, - double *speciesTransport, double *diffusionVelocity, - double *n_sp) final; + MFEM_HOST_DEVICE void ComputeSourceMolecularTransport(const double* state, const double* Up, const double* gradUp, + const double* Efield, double* globalTransport, + double* speciesTransport, double* diffusionVelocity, + double* n_sp) final; using MolecularTransport::GetViscosities; - MFEM_HOST_DEVICE void GetViscosities(const double *conserved, const double *primitive, double *visc) final; + MFEM_HOST_DEVICE void GetViscosities(const double* conserved, const double* primitive, double* visc) final; }; -MFEM_HOST_DEVICE inline void ConstantTransport::GetViscosities(const double *conserved, const double *primitive, - double *visc) { +MFEM_HOST_DEVICE inline void ConstantTransport::GetViscosities(const double* conserved, const double* primitive, + double* visc) { visc[0] = viscosity_; visc[1] = bulkViscosity_; } diff --git a/src/turb_model_base.cpp b/src/turb_model_base.cpp index f9d9b3a6..52f8103c 100644 --- a/src/turb_model_base.cpp +++ b/src/turb_model_base.cpp @@ -34,7 +34,7 @@ using namespace mfem; -ZeroTurbModel::ZeroTurbModel(ParMesh *pmesh, int sorder) : pmesh_(pmesh), sorder_(sorder) {} +ZeroTurbModel::ZeroTurbModel(ParMesh* pmesh, int sorder) : pmesh_(pmesh), sorder_(sorder) {} ZeroTurbModel::~ZeroTurbModel() { delete eddy_viscosity_; diff --git a/src/turb_model_base.hpp b/src/turb_model_base.hpp index dee1df35..19891067 100644 --- a/src/turb_model_base.hpp +++ b/src/turb_model_base.hpp @@ -47,7 +47,7 @@ struct spongeToTurbModel; * turbulence model to the flow. */ struct turbModelToFlow { - const mfem::ParGridFunction *eddy_viscosity = nullptr; + const mfem::ParGridFunction* eddy_viscosity = nullptr; }; /** @@ -55,7 +55,7 @@ struct turbModelToFlow { * turbulence model to the thermo chem model. */ struct turbModelToThermoChem { - const mfem::ParGridFunction *eddy_viscosity = nullptr; + const mfem::ParGridFunction* eddy_viscosity = nullptr; }; struct extDataToTurbModel; @@ -73,10 +73,10 @@ struct turbModelToExtData {}; */ class TurbModelBase { protected: - const flowToTurbModel *flow_interface_; - const thermoChemToTurbModel *thermoChem_interface_; - const extDataToTurbModel *extData_interface_; - const spongeToTurbModel *sponge_interface_; + const flowToTurbModel* flow_interface_; + const thermoChemToTurbModel* thermoChem_interface_; + const extDataToTurbModel* extData_interface_; + const spongeToTurbModel* sponge_interface_; public: /// Destructor @@ -97,9 +97,9 @@ class TurbModelBase { /** * @brief Hook to let derived classes register visualization fields with ParaViewDataCollection */ - virtual void initializeViz(mfem::ParaViewDataCollection &pvdc) {} + virtual void initializeViz(mfem::ParaViewDataCollection& pvdc) {} - virtual void initializeIO(IODataOrganizer &io) {} + virtual void initializeIO(IODataOrganizer& io) {} /** * @brief Initialize model operators @@ -127,10 +127,10 @@ class TurbModelBase { * Initialize fields that the turbulence model needs from the * visc mult. */ - void initializeFromSponge(spongeToTurbModel *sponge) { sponge_interface_ = sponge; } + void initializeFromSponge(spongeToTurbModel* sponge) { sponge_interface_ = sponge; } /// Get interface provided by flow model - const spongeToTurbModel *getSpongeInterface() const { return sponge_interface_; } + const spongeToTurbModel* getSpongeInterface() const { return sponge_interface_; } /** * @brief Initialize data from the flow class @@ -138,10 +138,10 @@ class TurbModelBase { * Initialize fields that the turbulence model needs from the * flow. */ - void initializeFromFlow(flowToTurbModel *flow) { flow_interface_ = flow; } + void initializeFromFlow(flowToTurbModel* flow) { flow_interface_ = flow; } /// Get interface provided by flow model - const flowToTurbModel *getFlowInterface() const { return flow_interface_; } + const flowToTurbModel* getFlowInterface() const { return flow_interface_; } /// Interface object, provides fields necessary for the flow turbModelToFlow toFlow_interface_; @@ -152,10 +152,10 @@ class TurbModelBase { * Initialize fields that the turbulence model needs from the * thermochem model. */ - void initializeFromThermoChem(thermoChemToTurbModel *thermoChem) { thermoChem_interface_ = thermoChem; } + void initializeFromThermoChem(thermoChemToTurbModel* thermoChem) { thermoChem_interface_ = thermoChem; } /// Get interface provided by thermoChem model - const thermoChemToTurbModel *getThermoChemInterface() const { return thermoChem_interface_; } + const thermoChemToTurbModel* getThermoChemInterface() const { return thermoChem_interface_; } /// Interface object, provides fields necessary for the turbModel turbModelToThermoChem toThermoChem_interface_; @@ -166,16 +166,16 @@ class TurbModelBase { * Initialize fields that the turbulence model needs from the * external data. */ - void initializeFromExtData(extDataToTurbModel *extData) { extData_interface_ = extData; } + void initializeFromExtData(extDataToTurbModel* extData) { extData_interface_ = extData; } /// Get interface provided by external data - const extDataToTurbModel *getExtDataInterface() const { return extData_interface_; } + const extDataToTurbModel* getExtDataInterface() const { return extData_interface_; } /// Interface object, provides fields necessary for the turbModel turbModelToExtData toExtData_interface_; - virtual mfem::ParGridFunction *getCurrentEddyViscosity() { return nullptr; } - virtual mfem::ParGridFunction *getGridScale() { return nullptr; } + virtual mfem::ParGridFunction* getCurrentEddyViscosity() { return nullptr; } + virtual mfem::ParGridFunction* getGridScale() { return nullptr; } }; /** @@ -184,13 +184,13 @@ class TurbModelBase { */ class ZeroTurbModel final : public TurbModelBase { protected: - mfem::ParMesh *pmesh_; + mfem::ParMesh* pmesh_; const int sorder_; - mfem::FiniteElementCollection *fec_ = nullptr; - mfem::ParFiniteElementSpace *fes_ = nullptr; + mfem::FiniteElementCollection* fec_ = nullptr; + mfem::ParFiniteElementSpace* fes_ = nullptr; - mfem::ParGridFunction *eddy_viscosity_ = nullptr; + mfem::ParGridFunction* eddy_viscosity_ = nullptr; public: /** @@ -202,7 +202,7 @@ class ZeroTurbModel final : public TurbModelBase { * @param sorder The polynomial order for scalar fields * @param nuT The (zero) value to use for the eddy viscosity */ - ZeroTurbModel(mfem::ParMesh *pmesh, int sorder); + ZeroTurbModel(mfem::ParMesh* pmesh, int sorder); /// Free the interface fields and support objects ~ZeroTurbModel() final; diff --git a/src/utils.cpp b/src/utils.cpp index 3d7bbb68..0f9ac6fa 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -69,7 +69,7 @@ bool slurm_job_almost_done_mpi(MPI_Comm comm, int threshold); bool slurm_job_almost_done_mpi(MPI_Comm comm, int threshold) { int rank; MPI_Comm_rank(comm, &rank); - char *SLURM_JOB_ID = getenv("SLURM_JOB_ID"); + char* SLURM_JOB_ID = getenv("SLURM_JOB_ID"); if (SLURM_JOB_ID == NULL) { printf("[ERROR]: SLURM_JOB_ID env variable not set. Unable to query how much time remaining\n"); return false; @@ -157,7 +157,7 @@ bool M2ulPhyS::Check_ExitEarly(int iter) { } // check if file exists -bool file_exists(const std::string &name) { return (access(name.c_str(), F_OK) != -1); } +bool file_exists(const std::string& name) { return (access(name.c_str(), F_OK) != -1); } // Look for existence of output.pvd files in vis output directory and // keep a sequentially numbered copy. Useful when doing restart, @@ -188,7 +188,7 @@ void M2ulPhyS::Cache_Paraview_Timesteps() { } // Run system command and capture output -std::string systemCmd(const char *cmd) { +std::string systemCmd(const char* cmd) { std::array buffer; std::string result; std::unique_ptr pipe(popen(cmd, "r"), pclose); @@ -201,12 +201,12 @@ std::string systemCmd(const char *cmd) { return result; } -void LocalProjectDiscCoefficient(GridFunction &gf, VectorCoefficient &coeff, Array &dof_attr) { +void LocalProjectDiscCoefficient(GridFunction& gf, VectorCoefficient& coeff, Array& dof_attr) { Array vdofs; Vector vals; gf.HostWrite(); - FiniteElementSpace *fes = gf.FESpace(); + FiniteElementSpace* fes = gf.FESpace(); // maximal element attribute for each dof dof_attr.SetSize(fes->GetVSize()); @@ -246,7 +246,7 @@ void LocalProjectDiscCoefficient(GridFunction &gf, VectorCoefficient &coeff, Arr } } -void GlobalProjectDiscCoefficient(ParGridFunction &gf, VectorCoefficient &coeff) { +void GlobalProjectDiscCoefficient(ParGridFunction& gf, VectorCoefficient& coeff) { // local maximal element attribute for each dof Array ldof_attr; @@ -257,9 +257,9 @@ void GlobalProjectDiscCoefficient(ParGridFunction &gf, VectorCoefficient &coeff) Array gdof_attr; ldof_attr.Copy(gdof_attr); - ParFiniteElementSpace *pfes = gf.ParFESpace(); + ParFiniteElementSpace* pfes = gf.ParFESpace(); - GroupCommunicator &gcomm = pfes->GroupComm(); + GroupCommunicator& gcomm = pfes->GroupComm(); gcomm.Reduce(gdof_attr, GroupCommunicator::Max); gcomm.Bcast(gdof_attr); @@ -275,11 +275,11 @@ void GlobalProjectDiscCoefficient(ParGridFunction &gf, VectorCoefficient &coeff) } // parallel averaging plus interpolation to determine final values - HypreParVector *tv = pfes->NewTrueDofVector(); + HypreParVector* tv = pfes->NewTrueDofVector(); gcomm.Reduce(gdof_attr, GroupCommunicator::Sum); gcomm.Bcast(gdof_attr); - FiniteElementSpace *fes = gf.FESpace(); + FiniteElementSpace* fes = gf.FESpace(); for (int i = 0; i < fes->GetVSize(); i++) { gf(i) /= gdof_attr[i]; } @@ -288,8 +288,8 @@ void GlobalProjectDiscCoefficient(ParGridFunction &gf, VectorCoefficient &coeff) delete tv; } -bool h5ReadTable(const std::string &fileName, const std::string &datasetName, mfem::DenseMatrix &output, - mfem::Array &shape) { +bool h5ReadTable(const std::string& fileName, const std::string& datasetName, mfem::DenseMatrix& output, + mfem::Array& shape) { bool success = false; hid_t file = -1; if (file_exists(fileName)) { @@ -330,8 +330,8 @@ bool h5ReadTable(const std::string &fileName, const std::string &datasetName, mf return success; } -bool h5ReadBcastMultiColumnTable(const std::string &fileName, const std::string &datasetName, MPI_Comm TPSCommWorld, - mfem::DenseMatrix &output, std::vector &tables) { +bool h5ReadBcastMultiColumnTable(const std::string& fileName, const std::string& datasetName, MPI_Comm TPSCommWorld, + mfem::DenseMatrix& output, std::vector& tables) { int myrank; MPI_Comm_rank(TPSCommWorld, &myrank); const bool rank0 = (myrank == 0); @@ -357,7 +357,7 @@ bool h5ReadBcastMultiColumnTable(const std::string &fileName, const std::string assert(ncol == (int)tables.size() + 1); if (!rank0) output.SetSize(nrow, ncol); - double *h_table = output.HostReadWrite(); + double* h_table = output.HostReadWrite(); MPI_Bcast(h_table, nrow * ncol, MPI_DOUBLE, 0, TPSCommWorld); for (size_t icol = 0; icol < tables.size(); icol++) { @@ -368,8 +368,8 @@ bool h5ReadBcastMultiColumnTable(const std::string &fileName, const std::string return success; } -void evaluateDistanceSerial(mfem::Mesh &mesh, const mfem::Array &wall_patches, const mfem::GridFunction &coords, - mfem::GridFunction &distance) { +void evaluateDistanceSerial(mfem::Mesh& mesh, const mfem::Array& wall_patches, const mfem::GridFunction& coords, + mfem::GridFunction& distance) { distance = -1.0; // Initialize with invalid data // Tolerance for solve @@ -422,7 +422,7 @@ void evaluateDistanceSerial(mfem::Mesh &mesh, const mfem::Array &wall_patch // the wall distance is updated. // Get information about the current face - FaceElementTransformations *Tr = mesh.GetBdrFaceTransformations(bel); + FaceElementTransformations* Tr = mesh.GetBdrFaceTransformations(bel); const Geometry::Type gt = Tr->GetGeometryType(); const int rdim = Tr->GetDimension(); // dim of reference space (should be dim-1) assert(rdim == dim - 1); @@ -513,71 +513,71 @@ void evaluateDistanceSerial(mfem::Mesh &mesh, const mfem::Array &wall_patch } // end loop over points in GridFunction for distance } -void multConstScalar(double A, Vector B, Vector *C) { +void multConstScalar(double A, Vector B, Vector* C) { { - double *dataB = B.HostReadWrite(); - double *dataC = C->HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* dataC = C->HostReadWrite(); MFEM_FORALL(i, B.Size(), { dataC[i] = A * dataB[i]; }); } } -void multConstScalarInv(double A, Vector B, Vector *C) { +void multConstScalarInv(double A, Vector B, Vector* C) { { - double *dataB = B.HostReadWrite(); - double *dataC = C->HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* dataC = C->HostReadWrite(); MFEM_FORALL(i, B.Size(), { dataC[i] = A / dataB[i]; }); } } -void multConstVector(double A, Vector B, Vector *C) { +void multConstVector(double A, Vector B, Vector* C) { { - double *dataB = B.HostReadWrite(); - double *dataC = C->HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* dataC = C->HostReadWrite(); MFEM_FORALL(i, B.Size(), { dataC[i] = A * dataB[i]; }); } } -void multConstScalarIP(double A, Vector *C) { +void multConstScalarIP(double A, Vector* C) { { - double *dataC = C->HostReadWrite(); + double* dataC = C->HostReadWrite(); MFEM_FORALL(i, C->Size(), { dataC[i] = A * dataC[i]; }); } } -void multConstScalarInvIP(double A, Vector *C) { +void multConstScalarInvIP(double A, Vector* C) { { - double *dataC = C->HostReadWrite(); + double* dataC = C->HostReadWrite(); MFEM_FORALL(i, C->Size(), { dataC[i] = A / dataC[i]; }); } } // not necessary -void multConstVectorIP(double A, Vector *C) { +void multConstVectorIP(double A, Vector* C) { { - double *dataC = C->HostReadWrite(); + double* dataC = C->HostReadWrite(); MFEM_FORALL(i, C->Size(), { dataC[i] = A * dataC[i]; }); } } -void multScalarScalar(Vector A, Vector B, Vector *C) { - double *dataA = A.HostReadWrite(); - double *dataB = B.HostReadWrite(); - double *dataC = C->HostReadWrite(); +void multScalarScalar(Vector A, Vector B, Vector* C) { + double* dataA = A.HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* dataC = C->HostReadWrite(); MFEM_FORALL(i, A.Size(), { dataC[i] = dataA[i] * dataB[i]; }); } -void multScalarScalarInv(Vector A, Vector B, Vector *C) { - double *dataA = A.HostReadWrite(); - double *dataB = B.HostReadWrite(); - double *dataC = C->HostReadWrite(); +void multScalarScalarInv(Vector A, Vector B, Vector* C) { + double* dataA = A.HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* dataC = C->HostReadWrite(); MFEM_FORALL(i, A.Size(), { dataC[i] = dataA[i] / dataB[i]; }); } -void multScalarVector(Vector A, Vector B, Vector *C, int dim) { +void multScalarVector(Vector A, Vector B, Vector* C, int dim) { int Ndof = A.Size(); - double *dataA = A.HostReadWrite(); - double *dataB = B.HostReadWrite(); - double *dataC = C->HostReadWrite(); + double* dataA = A.HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* dataC = C->HostReadWrite(); for (int eq = 0; eq < dim; eq++) { for (int i = 0; i < Ndof; i++) { dataC[i + eq * Ndof] = dataA[i] * dataB[i + eq * Ndof]; @@ -585,11 +585,11 @@ void multScalarVector(Vector A, Vector B, Vector *C, int dim) { } } -void multScalarInvVector(Vector A, Vector B, Vector *C, int dim) { +void multScalarInvVector(Vector A, Vector B, Vector* C, int dim) { int Ndof = A.Size(); - double *dataA = A.HostReadWrite(); - double *dataB = B.HostReadWrite(); - double *dataC = C->HostReadWrite(); + double* dataA = A.HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* dataC = C->HostReadWrite(); for (int eq = 0; eq < dim; eq++) { for (int i = 0; i < Ndof; i++) { dataC[i + eq * Ndof] = (1.0 / dataA[i]) * dataB[i + eq * Ndof]; @@ -597,10 +597,10 @@ void multScalarInvVector(Vector A, Vector B, Vector *C, int dim) { } } -void multScalarInvVectorIP(Vector A, Vector *C, int dim) { +void multScalarInvVectorIP(Vector A, Vector* C, int dim) { int Ndof = A.Size(); - double *dataA = A.HostReadWrite(); - double *dataC = C->HostReadWrite(); + double* dataA = A.HostReadWrite(); + double* dataC = C->HostReadWrite(); for (int eq = 0; eq < dim; eq++) { for (int i = 0; i < Ndof; i++) { dataC[i + eq * Ndof] = (1.0 / dataA[i]) * dataC[i + eq * Ndof]; @@ -608,12 +608,12 @@ void multScalarInvVectorIP(Vector A, Vector *C, int dim) { } } -void multVectorVector(Vector A, Vector B, Vector *C1, Vector *C2, Vector *C3, int dim) { +void multVectorVector(Vector A, Vector B, Vector* C1, Vector* C2, Vector* C3, int dim) { { int Ndof = A.Size() / dim; - double *dataA = A.HostReadWrite(); - double *dataB = B.HostReadWrite(); - double *dataC = C1->HostReadWrite(); + double* dataA = A.HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* dataC = C1->HostReadWrite(); for (int eq = 0; eq < dim; eq++) { for (int i = 0; i < Ndof; i++) { dataC[i + eq * Ndof] = dataA[i + 0 * Ndof] * dataB[i + eq * Ndof]; @@ -623,9 +623,9 @@ void multVectorVector(Vector A, Vector B, Vector *C1, Vector *C2, Vector *C3, in { int Ndof = A.Size() / dim; - double *dataA = A.HostReadWrite(); - double *dataB = B.HostReadWrite(); - double *dataC = C2->HostReadWrite(); + double* dataA = A.HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* dataC = C2->HostReadWrite(); for (int eq = 0; eq < dim; eq++) { for (int i = 0; i < Ndof; i++) { dataC[i + eq * Ndof] = dataA[i + 1 * Ndof] * dataB[i + eq * Ndof]; @@ -635,9 +635,9 @@ void multVectorVector(Vector A, Vector B, Vector *C1, Vector *C2, Vector *C3, in { int Ndof = A.Size() / dim; - double *dataA = A.HostReadWrite(); - double *dataB = B.HostReadWrite(); - double *dataC = C3->HostReadWrite(); + double* dataA = A.HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* dataC = C3->HostReadWrite(); for (int eq = 0; eq < dim; eq++) { for (int i = 0; i < Ndof; i++) { dataC[i + eq * Ndof] = dataA[i + 2 * Ndof] * dataB[i + eq * Ndof]; @@ -646,11 +646,11 @@ void multVectorVector(Vector A, Vector B, Vector *C1, Vector *C2, Vector *C3, in } } -void dotVector(Vector A, Vector B, Vector *C, int dim) { +void dotVector(Vector A, Vector B, Vector* C, int dim) { int Ndof = A.Size() / dim; - double *dataA = A.HostReadWrite(); - double *dataB = B.HostReadWrite(); - double *data = C->HostReadWrite(); + double* dataA = A.HostReadWrite(); + double* dataB = B.HostReadWrite(); + double* data = C->HostReadWrite(); for (int i = 0; i < Ndof; i++) { data[i] = 0.0; } @@ -661,22 +661,22 @@ void dotVector(Vector A, Vector B, Vector *C, int dim) { } } -void multScalarScalarIP(Vector A, Vector *C) { - double *dataA = A.HostReadWrite(); - double *dataB = C->HostReadWrite(); +void multScalarScalarIP(Vector A, Vector* C) { + double* dataA = A.HostReadWrite(); + double* dataB = C->HostReadWrite(); MFEM_FORALL(i, A.Size(), { dataB[i] = dataA[i] * dataB[i]; }); } -void multScalarInvScalarIP(Vector A, Vector *C) { - double *dataA = A.HostReadWrite(); - double *dataB = C->HostReadWrite(); +void multScalarInvScalarIP(Vector A, Vector* C) { + double* dataA = A.HostReadWrite(); + double* dataB = C->HostReadWrite(); MFEM_FORALL(i, A.Size(), { dataB[i] = 1.0 / dataA[i] * dataB[i]; }); } -void multScalarVectorIP(Vector A, Vector *C, int dim) { +void multScalarVectorIP(Vector A, Vector* C, int dim) { int Ndof = A.Size(); - double *dataA = A.HostReadWrite(); - double *dataB = C->HostReadWrite(); + double* dataA = A.HostReadWrite(); + double* dataB = C->HostReadWrite(); for (int eq = 0; eq < dim; eq++) { for (int i = 0; i < Ndof; i++) { dataB[i + eq * Ndof] = dataA[i] * dataB[i + eq * Ndof]; @@ -684,22 +684,22 @@ void multScalarVectorIP(Vector A, Vector *C, int dim) { } } -void setScalarFromVector(Vector A, int ind, Vector *C) { +void setScalarFromVector(Vector A, int ind, Vector* C) { int Ndof = C->Size(); - const double *dataA = A.Read(); - double *data = C->Write(); + const double* dataA = A.Read(); + double* data = C->Write(); MFEM_FORALL(i, Ndof, { data[i] = dataA[i + ind * Ndof]; }); } -void setVectorFromScalar(Vector A, int ind, Vector *C) { +void setVectorFromScalar(Vector A, int ind, Vector* C) { int Ndof = A.Size(); - const double *dataA = A.Read(); - double *data = C->Write(); + const double* dataA = A.Read(); + double* data = C->Write(); MFEM_FORALL(i, Ndof, { data[i + ind * Ndof] = dataA[i]; }); } -void ComputeCurl3D(const ParGridFunction &u, ParGridFunction &cu) { - const FiniteElementSpace *fes = u.FESpace(); +void ComputeCurl3D(const ParGridFunction& u, ParGridFunction& cu) { + const FiniteElementSpace* fes = u.FESpace(); // AccumulateAndCountZones. Array zones_per_vdof; @@ -728,15 +728,15 @@ void ComputeCurl3D(const ParGridFunction &u, ParGridFunction &cu) { fes->GetElementVDofs(e, vdofs); u.GetSubVector(vdofs, loc_data); vals.SetSize(vdofs.Size()); - ElementTransformation *tr = fes->GetElementTransformation(e); - const FiniteElement *el = fes->GetFE(e); + ElementTransformation* tr = fes->GetElementTransformation(e); + const FiniteElement* el = fes->GetFE(e); elndofs = el->GetDof(); int dim = el->GetDim(); dshape.SetSize(elndofs, dim); for (int dof = 0; dof < elndofs; ++dof) { // Project. - const IntegrationPoint &ip = el->GetNodes().IntPoint(dof); + const IntegrationPoint& ip = el->GetNodes().IntPoint(dof); tr->SetIntPoint(&ip); // Eval and GetVectorGradientHat. @@ -745,7 +745,7 @@ void ComputeCurl3D(const ParGridFunction &u, ParGridFunction &cu) { DenseMatrix loc_data_mat(loc_data.GetData(), elndofs, vdim); MultAtB(loc_data_mat, dshape, grad_hat); - const DenseMatrix &Jinv = tr->InverseJacobian(); + const DenseMatrix& Jinv = tr->InverseJacobian(); grad.SetSize(grad_hat.Height(), Jinv.Width()); Mult(grad_hat, Jinv, grad); @@ -770,7 +770,7 @@ void ComputeCurl3D(const ParGridFunction &u, ParGridFunction &cu) { // Communication // Count the zones globally. - GroupCommunicator &gcomm = u.ParFESpace()->GroupComm(); + GroupCommunicator& gcomm = u.ParFESpace()->GroupComm(); gcomm.Reduce(zones_per_vdof, GroupCommunicator::Sum); gcomm.Bcast(zones_per_vdof); @@ -787,15 +787,15 @@ void ComputeCurl3D(const ParGridFunction &u, ParGridFunction &cu) { } } -void vectorGrad3D(ParGridFunction &uSub, ParGridFunction &u, ParGridFunction &gu, ParGridFunction &gv, - ParGridFunction &gw) { +void vectorGrad3D(ParGridFunction& uSub, ParGridFunction& u, ParGridFunction& gu, ParGridFunction& gv, + ParGridFunction& gw) { // FiniteElementSpace *sfes = uSub.FESpace(); int dim = 3; int nSize = uSub.Size(); { - double *dataSub = uSub.HostReadWrite(); - double *data = u.HostReadWrite(); + double* dataSub = uSub.HostReadWrite(); + double* data = u.HostReadWrite(); for (int i = 0; i < nSize; i++) { dataSub[i] = data[i + 0 * nSize]; } @@ -803,8 +803,8 @@ void vectorGrad3D(ParGridFunction &uSub, ParGridFunction &u, ParGridFunction &gu scalarGrad3D(uSub, gu); { - double *dataSub = uSub.HostReadWrite(); - double *data = u.HostReadWrite(); + double* dataSub = uSub.HostReadWrite(); + double* data = u.HostReadWrite(); for (int i = 0; i < nSize; i++) { dataSub[i] = data[i + 1 * nSize]; } @@ -812,8 +812,8 @@ void vectorGrad3D(ParGridFunction &uSub, ParGridFunction &u, ParGridFunction &gu scalarGrad3D(uSub, gv); if (dim == 3) { - double *dataSub = uSub.HostReadWrite(); - double *data = u.HostReadWrite(); + double* dataSub = uSub.HostReadWrite(); + double* data = u.HostReadWrite(); for (int i = 0; i < nSize; i++) { dataSub[i] = data[i + 2 * nSize]; } @@ -821,9 +821,9 @@ void vectorGrad3D(ParGridFunction &uSub, ParGridFunction &u, ParGridFunction &gu } } -void scalarGrad3D(ParGridFunction &u, ParGridFunction &gu) { - FiniteElementSpace *fes = u.FESpace(); - GroupCommunicator &gcomm = u.ParFESpace()->GroupComm(); +void scalarGrad3D(ParGridFunction& u, ParGridFunction& gu) { + FiniteElementSpace* fes = u.FESpace(); + GroupCommunicator& gcomm = u.ParFESpace()->GroupComm(); int dim = 3; // spatial dimension int vdim = fes->GetVDim(); // vector dimension (or u) @@ -851,8 +851,8 @@ void scalarGrad3D(ParGridFunction &u, ParGridFunction &gu) { vals1.SetSize(vdofs.Size()); vals2.SetSize(vdofs.Size()); vals3.SetSize(vdofs.Size()); - ElementTransformation *tr = fes->GetElementTransformation(e); - const FiniteElement *el = fes->GetFE(e); + ElementTransformation* tr = fes->GetElementTransformation(e); + const FiniteElement* el = fes->GetFE(e); elndofs = el->GetDof(); int dim = el->GetDim(); dshape.SetSize(elndofs, dim); @@ -860,7 +860,7 @@ void scalarGrad3D(ParGridFunction &u, ParGridFunction &gu) { // element dof for (int dof = 0; dof < elndofs; ++dof) { // Project. - const IntegrationPoint &ip = el->GetNodes().IntPoint(dof); + const IntegrationPoint& ip = el->GetNodes().IntPoint(dof); tr->SetIntPoint(&ip); // Eval and GetVectorGradientHat. @@ -870,7 +870,7 @@ void scalarGrad3D(ParGridFunction &u, ParGridFunction &gu) { DenseMatrix loc_data_mat(loc_data.GetData(), elndofs, vdim); MultAtB(loc_data_mat, dshape, grad_hat); - const DenseMatrix &Jinv = tr->InverseJacobian(); + const DenseMatrix& Jinv = tr->InverseJacobian(); grad.SetSize(grad_hat.Height(), Jinv.Width()); Mult(grad_hat, Jinv, grad); @@ -906,7 +906,7 @@ void scalarGrad3D(ParGridFunction &u, ParGridFunction &gu) { gcomm.Bcast(zones_per_vdof); // Accumulate for all vdofs. - GroupCommunicator &gcomm_g = gu.ParFESpace()->GroupComm(); + GroupCommunicator& gcomm_g = gu.ParFESpace()->GroupComm(); gcomm_g.Reduce(gu.GetData(), GroupCommunicator::Sum); gcomm_g.Bcast(gu.GetData()); @@ -919,8 +919,8 @@ void scalarGrad3D(ParGridFunction &u, ParGridFunction &gu) { } } -void ComputeCurl2D(const ParGridFunction &u, ParGridFunction &cu, bool assume_scalar) { - const FiniteElementSpace *fes = u.FESpace(); +void ComputeCurl2D(const ParGridFunction& u, ParGridFunction& cu, bool assume_scalar) { + const FiniteElementSpace* fes = u.FESpace(); // AccumulateAndCountZones. Array zones_per_vdof; @@ -949,15 +949,15 @@ void ComputeCurl2D(const ParGridFunction &u, ParGridFunction &cu, bool assume_sc fes->GetElementVDofs(e, vdofs); u.GetSubVector(vdofs, loc_data); vals.SetSize(vdofs.Size()); - ElementTransformation *tr = fes->GetElementTransformation(e); - const FiniteElement *el = fes->GetFE(e); + ElementTransformation* tr = fes->GetElementTransformation(e); + const FiniteElement* el = fes->GetFE(e); elndofs = el->GetDof(); int dim = el->GetDim(); dshape.SetSize(elndofs, dim); for (int dof = 0; dof < elndofs; ++dof) { // Project. - const IntegrationPoint &ip = el->GetNodes().IntPoint(dof); + const IntegrationPoint& ip = el->GetNodes().IntPoint(dof); tr->SetIntPoint(&ip); // Eval and GetVectorGradientHat. @@ -966,7 +966,7 @@ void ComputeCurl2D(const ParGridFunction &u, ParGridFunction &cu, bool assume_sc DenseMatrix loc_data_mat(loc_data.GetData(), elndofs, vdim); MultAtB(loc_data_mat, dshape, grad_hat); - const DenseMatrix &Jinv = tr->InverseJacobian(); + const DenseMatrix& Jinv = tr->InverseJacobian(); grad.SetSize(grad_hat.Height(), Jinv.Width()); Mult(grad_hat, Jinv, grad); @@ -996,7 +996,7 @@ void ComputeCurl2D(const ParGridFunction &u, ParGridFunction &cu, bool assume_sc // Communication. // Count the zones globally. - GroupCommunicator &gcomm = u.ParFESpace()->GroupComm(); + GroupCommunicator& gcomm = u.ParFESpace()->GroupComm(); gcomm.Reduce(zones_per_vdof, GroupCommunicator::Sum); gcomm.Bcast(zones_per_vdof); @@ -1013,9 +1013,9 @@ void ComputeCurl2D(const ParGridFunction &u, ParGridFunction &cu, bool assume_sc } } -void ComputeCurlAxi(const ParGridFunction &u, ParGridFunction &cu, bool assume_scalar) { - const FiniteElementSpace *fes = u.FESpace(); - const FiniteElementSpace *cfes = cu.FESpace(); +void ComputeCurlAxi(const ParGridFunction& u, ParGridFunction& cu, bool assume_scalar) { + const FiniteElementSpace* fes = u.FESpace(); + const FiniteElementSpace* cfes = cu.FESpace(); // AccumulateAndCountZones. Array zones_per_vdof; @@ -1048,15 +1048,15 @@ void ComputeCurlAxi(const ParGridFunction &u, ParGridFunction &cu, bool assume_s u.GetSubVector(vdofs, loc_data); vals.SetSize(cvdofs.Size()); - ElementTransformation *tr = fes->GetElementTransformation(e); - const FiniteElement *el = fes->GetFE(e); + ElementTransformation* tr = fes->GetElementTransformation(e); + const FiniteElement* el = fes->GetFE(e); elndofs = el->GetDof(); int dim = el->GetDim(); dshape.SetSize(elndofs, dim); for (int dof = 0; dof < elndofs; ++dof) { // Project. - const IntegrationPoint &ip = el->GetNodes().IntPoint(dof); + const IntegrationPoint& ip = el->GetNodes().IntPoint(dof); tr->SetIntPoint(&ip); tr->Transform(ip, spatial_location); @@ -1068,7 +1068,7 @@ void ComputeCurlAxi(const ParGridFunction &u, ParGridFunction &cu, bool assume_s DenseMatrix loc_data_mat(loc_data.GetData(), elndofs, vdim); MultAtB(loc_data_mat, dshape, grad_hat); - const DenseMatrix &Jinv = tr->InverseJacobian(); + const DenseMatrix& Jinv = tr->InverseJacobian(); grad.SetSize(grad_hat.Height(), Jinv.Width()); Mult(grad_hat, Jinv, grad); @@ -1104,7 +1104,7 @@ void ComputeCurlAxi(const ParGridFunction &u, ParGridFunction &cu, bool assume_s // Communication. // Count the zones globally. - GroupCommunicator &gcomm = u.ParFESpace()->GroupComm(); + GroupCommunicator& gcomm = u.ParFESpace()->GroupComm(); gcomm.Reduce(zones_per_vdof, GroupCommunicator::Sum); gcomm.Bcast(zones_per_vdof); @@ -1121,7 +1121,7 @@ void ComputeCurlAxi(const ParGridFunction &u, ParGridFunction &cu, bool assume_s } } -void scalarGrad3DV(FiniteElementSpace *fes, FiniteElementSpace *vfes, Vector u, Vector *gu) { +void scalarGrad3DV(FiniteElementSpace* fes, FiniteElementSpace* vfes, Vector u, Vector* gu) { ParGridFunction R0_gf; R0_gf.SetSpace(fes); @@ -1133,7 +1133,7 @@ void scalarGrad3DV(FiniteElementSpace *fes, FiniteElementSpace *vfes, Vector u, R1_gf.GetTrueDofs(*gu); } -void streamwiseTensor(const Vector &vel, DenseMatrix &swMgbl) { +void streamwiseTensor(const Vector& vel, DenseMatrix& swMgbl) { int dim = vel.Size(); swMgbl.SetSize(dim, dim); @@ -1157,11 +1157,11 @@ void streamwiseTensor(const Vector &vel, DenseMatrix &swMgbl) { double csupgFactor(double Reh, double Reh_factor, double Reh_offset) { return Reh_factor * (tanh(Reh) + Reh_offset); } -void EliminateRHS(Operator &A, ConstrainedOperator &constrainedA, const Array &ess_tdof_list, Vector &x, Vector &b, - Vector &X, Vector &B, int copy_interior) { - const Operator *Po = A.GetOutputProlongation(); - const Operator *Pi = A.GetProlongation(); - const Operator *Ri = A.GetRestriction(); +void EliminateRHS(Operator& A, ConstrainedOperator& constrainedA, const Array& ess_tdof_list, Vector& x, Vector& b, + Vector& X, Vector& B, int copy_interior) { + const Operator* Po = A.GetOutputProlongation(); + const Operator* Pi = A.GetProlongation(); + const Operator* Ri = A.GetRestriction(); A.InitTVectors(Po, Ri, Pi, x, b, X, B); if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); @@ -1169,7 +1169,7 @@ void EliminateRHS(Operator &A, ConstrainedOperator &constrainedA, const Array(global_size); } -bool copyFile(const char *SRC, const char *DEST) { +bool copyFile(const char* SRC, const char* DEST) { std::ifstream src(SRC, std::ios::binary); std::ofstream dest(DEST, std::ios::binary); dest << src.rdbuf(); return src && dest; } -void makeContinuous(ParGridFunction &u) { - FiniteElementSpace *fes = u.FESpace(); +void makeContinuous(ParGridFunction& u) { + FiniteElementSpace* fes = u.FESpace(); ParGridFunction au; au.SetSpace(fes); @@ -1208,7 +1208,7 @@ void makeContinuous(ParGridFunction &u) { fes->GetElementVDofs(e, vdofs); u.GetSubVector(vdofs, loc_data); vals.SetSize(vdofs.Size()); - const FiniteElement *el = fes->GetFE(e); + const FiniteElement* el = fes->GetFE(e); elndofs = el->GetDof(); for (int dof = 0; dof < elndofs; ++dof) { vals(dof) = loc_data(dof); @@ -1225,7 +1225,7 @@ void makeContinuous(ParGridFunction &u) { // Communication // Count the zones globally. - GroupCommunicator &gcomm = u.ParFESpace()->GroupComm(); + GroupCommunicator& gcomm = u.ParFESpace()->GroupComm(); gcomm.Reduce(zones_per_vdof, GroupCommunicator::Sum); gcomm.Bcast(zones_per_vdof); @@ -1246,7 +1246,7 @@ void makeContinuous(ParGridFunction &u) { } void readTable(MPI_Comm TPSCommWorld, std::string filename, bool xLogScale, bool fLogScale, int order, - std::list &tableHost, TableInput &result) { + std::list& tableHost, TableInput& result) { int myrank; MPI_Comm_rank(TPSCommWorld, &myrank); const bool rank0 = (myrank == 0); @@ -1269,7 +1269,7 @@ void readTable(MPI_Comm TPSCommWorld, std::string filename, bool xLogScale, bool success = (suc_int != 0); if (!success) exit(ERROR); - int *d_dims = dims.GetData(); + int* d_dims = dims.GetData(); MPI_Bcast(&Ndata, 1, MPI_INT, 0, TPSCommWorld); MPI_Bcast(d_dims, 2, MPI_INT, 0, TPSCommWorld); assert(dims[0] > 0); @@ -1277,7 +1277,7 @@ void readTable(MPI_Comm TPSCommWorld, std::string filename, bool xLogScale, bool // all not 0 ranks have not had matrix size set as in h5ReadTable if (!rank0) tableHost.back().SetSize(dims[0], dims[1]); - double *d_table = tableHost.back().HostReadWrite(); + double* d_table = tableHost.back().HostReadWrite(); MPI_Bcast(d_table, dims[0] * dims[1], MPI_DOUBLE, 0, TPSCommWorld); result.Ndata = Ndata; @@ -1288,19 +1288,19 @@ void readTable(MPI_Comm TPSCommWorld, std::string filename, bool xLogScale, bool } namespace mfem { -GradientVectorGridFunctionCoefficient::GradientVectorGridFunctionCoefficient(const GridFunction *gf) +GradientVectorGridFunctionCoefficient::GradientVectorGridFunctionCoefficient(const GridFunction* gf) : MatrixCoefficient((gf) ? gf->VectorDim() : 0) { GridFunc = gf; } -void GradientVectorGridFunctionCoefficient::SetGridFunction(const GridFunction *gf) { +void GradientVectorGridFunctionCoefficient::SetGridFunction(const GridFunction* gf) { GridFunc = gf; const int dim = (gf) ? gf->VectorDim() : 0; height = width = dim; } -void GradientVectorGridFunctionCoefficient::Eval(DenseMatrix &G, ElementTransformation &T, const IntegrationPoint &ip) { - Mesh *gf_mesh = GridFunc->FESpace()->GetMesh(); +void GradientVectorGridFunctionCoefficient::Eval(DenseMatrix& G, ElementTransformation& T, const IntegrationPoint& ip) { + Mesh* gf_mesh = GridFunc->FESpace()->GetMesh(); if (T.mesh->GetNE() == gf_mesh->GetNE()) { GridFunc->GetVectorGradient(T, G); } else { @@ -1312,23 +1312,23 @@ void GradientVectorGridFunctionCoefficient::Eval(DenseMatrix &G, ElementTransfor #if MFEM_VERSION >= 40700 // mfem 4.7 and later - const Mesh &fine_mesh = *T.mesh; + const Mesh& fine_mesh = *T.mesh; #else // older versions - Mesh &fine_mesh = *T.mesh; + Mesh& fine_mesh = *T.mesh; #endif // Get the element transformation of the coarse element containing the // fine element. int fine_element = T.ElementNo; - const CoarseFineTransformations &cf = fine_mesh.GetRefinementTransforms(); + const CoarseFineTransformations& cf = fine_mesh.GetRefinementTransforms(); int coarse_element = cf.embeddings[fine_element].parent; - ElementTransformation *coarse_T = gf_mesh->GetElementTransformation(coarse_element); + ElementTransformation* coarse_T = gf_mesh->GetElementTransformation(coarse_element); // Transform the integration point from fine element coordinates to coarse // element coordinates. Geometry::Type geom = T.GetGeometryType(); IntegrationPointTransformation fine_to_coarse; - IsoparametricTransformation &emb_tr = fine_to_coarse.Transf; + IsoparametricTransformation& emb_tr = fine_to_coarse.Transf; emb_tr.SetIdentityTransformation(geom); emb_tr.SetPointMat(cf.point_matrices[geom](cf.embeddings[fine_element].matrix)); fine_to_coarse.Transform(ip, coarse_ip); @@ -1338,7 +1338,7 @@ void GradientVectorGridFunctionCoefficient::Eval(DenseMatrix &G, ElementTransfor } } -VectorMagnitudeCoefficient::VectorMagnitudeCoefficient(VectorCoefficient &A) : a(&A), va(A.GetVDim()) {} +VectorMagnitudeCoefficient::VectorMagnitudeCoefficient(VectorCoefficient& A) : a(&A), va(A.GetVDim()) {} void VectorMagnitudeCoefficient::SetTime(double t) { if (a) { @@ -1347,7 +1347,7 @@ void VectorMagnitudeCoefficient::SetTime(double t) { this->Coefficient::SetTime(t); } -double VectorMagnitudeCoefficient::Eval(ElementTransformation &T, const IntegrationPoint &ip) { +double VectorMagnitudeCoefficient::Eval(ElementTransformation& T, const IntegrationPoint& ip) { a->Eval(va, T, ip); return std::max(std::sqrt(va * va), 1.0e-18); } @@ -1357,7 +1357,7 @@ void TransformedMatrixVectorCoefficient::SetTime(double t) { this->MatrixCoefficient::SetTime(t); } -void TransformedMatrixVectorCoefficient::Eval(DenseMatrix &G, ElementTransformation &T, const IntegrationPoint &ip) { +void TransformedMatrixVectorCoefficient::Eval(DenseMatrix& G, ElementTransformation& T, const IntegrationPoint& ip) { Vector buf; buf.SetSize(Q1->GetVDim()); Q1->Eval(buf, T, ip); @@ -1374,7 +1374,7 @@ void ExtTransformedCoefficient::SetTime(double t) { this->Coefficient::SetTime(t); } -double ExtTransformedCoefficient::Eval(ElementTransformation &T, const IntegrationPoint &ip) { +double ExtTransformedCoefficient::Eval(ElementTransformation& T, const IntegrationPoint& ip) { if (Q2) { return Transform2(Q1->Eval(T, ip, GetTime()), Q2->Eval(T, ip, GetTime())); } else { diff --git a/src/utils.hpp b/src/utils.hpp index a8e05c35..b8f84d8c 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -55,8 +55,8 @@ enum ExitCodes { NORMAL = 0, ERROR = 1, JOB_RESTART = 10, EARLY_EXIT = 11 }; // Misc. utilities -bool file_exists(const std::string &name); -std::string systemCmd(const char *cmd); +bool file_exists(const std::string& name); +std::string systemCmd(const char* cmd); // HDF5 convenience utilities inline hid_t h5_getType(int) { return (H5T_NATIVE_INT); } @@ -77,7 +77,7 @@ void h5_save_attribute(hid_t dest, std::string attribute, T value) { } template -void h5_read_attribute(hid_t source, std::string attribute, T &value) { +void h5_read_attribute(hid_t source, std::string attribute, T& value) { herr_t status; hid_t attr; hid_t attrType = h5_getType(value); @@ -91,8 +91,8 @@ void h5_read_attribute(hid_t source, std::string attribute, T &value) { // A simple HDF5 routine to read two-dimensional array into DenseMatrix. // Return result as boolean. -bool h5ReadTable(const std::string &fileName, const std::string &datasetName, mfem::DenseMatrix &output, - mfem::Array &shape); +bool h5ReadTable(const std::string& fileName, const std::string& datasetName, mfem::DenseMatrix& output, + mfem::Array& shape); /** Read multi-column table * @@ -101,11 +101,11 @@ bool h5ReadTable(const std::string &fileName, const std::string &datasetName, mf * are broadcast to all ranks. The length of the input std::vector of * TableInput must match the number of columsn read. */ -bool h5ReadBcastMultiColumnTable(const std::string &fileName, const std::string &datasetName, MPI_Comm TPSCommWorld, - mfem::DenseMatrix &output, std::vector &tables); +bool h5ReadBcastMultiColumnTable(const std::string& fileName, const std::string& datasetName, MPI_Comm TPSCommWorld, + mfem::DenseMatrix& output, std::vector& tables); void readTable(MPI_Comm TPSCommWorld, std::string filename, bool xLogScale, bool fLogScale, int order, - std::list &tableHost, TableInput &result); + std::list& tableHost, TableInput& result); // MFEM extensions @@ -120,7 +120,7 @@ void readTable(MPI_Comm TPSCommWorld, std::string filename, bool xLogScale, bool * mfem::GridFunction::ProjectDiscCoefficient but has fixes s.t. it * will work with Nedelec elements. */ -void LocalProjectDiscCoefficient(mfem::GridFunction &gf, mfem::VectorCoefficient &coeff, mfem::Array &dof_attr); +void LocalProjectDiscCoefficient(mfem::GridFunction& gf, mfem::VectorCoefficient& coeff, mfem::Array& dof_attr); /** Project discontinous function onto FE space * @@ -132,7 +132,7 @@ void LocalProjectDiscCoefficient(mfem::GridFunction &gf, mfem::VectorCoefficient * mfem::ParGridFunction::ProjectDiscCoefficient but calls * LocalProjectDiscCoefficient. */ -void GlobalProjectDiscCoefficient(mfem::ParGridFunction &gf, mfem::VectorCoefficient &coeff); +void GlobalProjectDiscCoefficient(mfem::ParGridFunction& gf, mfem::VectorCoefficient& coeff); /** @brief Evaluate the distance function * @@ -149,62 +149,62 @@ void GlobalProjectDiscCoefficient(mfem::ParGridFunction &gf, mfem::VectorCoeffic * This function is not guarenteed to work for nonlinear elements. * See comments in source about why. */ -void evaluateDistanceSerial(mfem::Mesh &mesh, const mfem::Array &wall_patches, const mfem::GridFunction &coords, - mfem::GridFunction &distance); - -void multConstScalar(double A, Vector B, Vector *C); -void multConstScalarInv(double A, Vector B, Vector *C); -void multConstVector(double A, Vector B, Vector *C); -void multConstScalarIP(double A, Vector *C); -void multConstScalarInvIP(double A, Vector *C); -void multConstVectorIP(double A, Vector *C); -void multScalarScalar(Vector A, Vector B, Vector *C); -void multScalarScalarInv(Vector A, Vector B, Vector *C); -void multScalarVector(Vector A, Vector B, Vector *C, int dim = 3); -void multScalarInvVector(Vector A, Vector B, Vector *C, int dim = 3); -void multScalarInvVectorIP(Vector A, Vector *C, int dim = 3); -void multVectorVector(Vector A, Vector B, Vector *C1, Vector *C2, Vector *C3, int dim = 3); -void dotVector(Vector A, Vector B, Vector *C, int dim = 3); -void multScalarScalarIP(Vector A, Vector *C); -void multScalarInvScalarIP(Vector A, Vector *C); -void multScalarVectorIP(Vector A, Vector *C, int dim = 3); -void setScalarFromVector(Vector A, int ind, Vector *C); -void setVectorFromScalar(Vector A, int ind, Vector *C); +void evaluateDistanceSerial(mfem::Mesh& mesh, const mfem::Array& wall_patches, const mfem::GridFunction& coords, + mfem::GridFunction& distance); + +void multConstScalar(double A, Vector B, Vector* C); +void multConstScalarInv(double A, Vector B, Vector* C); +void multConstVector(double A, Vector B, Vector* C); +void multConstScalarIP(double A, Vector* C); +void multConstScalarInvIP(double A, Vector* C); +void multConstVectorIP(double A, Vector* C); +void multScalarScalar(Vector A, Vector B, Vector* C); +void multScalarScalarInv(Vector A, Vector B, Vector* C); +void multScalarVector(Vector A, Vector B, Vector* C, int dim = 3); +void multScalarInvVector(Vector A, Vector B, Vector* C, int dim = 3); +void multScalarInvVectorIP(Vector A, Vector* C, int dim = 3); +void multVectorVector(Vector A, Vector B, Vector* C1, Vector* C2, Vector* C3, int dim = 3); +void dotVector(Vector A, Vector B, Vector* C, int dim = 3); +void multScalarScalarIP(Vector A, Vector* C); +void multScalarInvScalarIP(Vector A, Vector* C); +void multScalarVectorIP(Vector A, Vector* C, int dim = 3); +void setScalarFromVector(Vector A, int ind, Vector* C); +void setVectorFromScalar(Vector A, int ind, Vector* C); /// Compute \f$\nabla \times \nabla \times u\f$ for \f$u \in (H^1)^2\f$. -void ComputeCurl2D(const ParGridFunction &u, ParGridFunction &cu, bool assume_scalar = false); +void ComputeCurl2D(const ParGridFunction& u, ParGridFunction& cu, bool assume_scalar = false); -void ComputeCurlAxi(const ParGridFunction &u, ParGridFunction &cu, bool assume_scalar = false); +void ComputeCurlAxi(const ParGridFunction& u, ParGridFunction& cu, bool assume_scalar = false); /// Compute \f$\nabla \times \nabla \times u\f$ for \f$u \in (H^1)^3\f$. -void ComputeCurl3D(const ParGridFunction &u, ParGridFunction &cu); +void ComputeCurl3D(const ParGridFunction& u, ParGridFunction& cu); -void vectorGrad3D(ParGridFunction &uSub, ParGridFunction &u, ParGridFunction &gu, ParGridFunction &gv, - ParGridFunction &gw); -void scalarGrad3D(ParGridFunction &u, ParGridFunction &gu); +void vectorGrad3D(ParGridFunction& uSub, ParGridFunction& u, ParGridFunction& gu, ParGridFunction& gv, + ParGridFunction& gw); +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); -void makeContinuous(ParGridFunction &u); +void scalarGrad3DV(FiniteElementSpace* fes, FiniteElementSpace* vfes, Vector u, Vector* gu); +void makeContinuous(ParGridFunction& u); -bool copyFile(const char *SRC, const char *DEST); +bool copyFile(const char* SRC, const char* DEST); /// upwind diffusion support: evaluate u * u^T / ||u||^2 -void streamwiseTensor(const Vector &vel, DenseMatrix &swMgbl); +void streamwiseTensor(const Vector& vel, DenseMatrix& swMgbl); /// upwind diffusion support: evaluate supg constant double csupgFactor(double Reh, double Reh_factor, double Reh_offset); /// Eliminate essential BCs in an Operator and apply to RHS. /// rename this to something sensible "ApplyEssentialBC" or something -void EliminateRHS(Operator &A, ConstrainedOperator &constrainedA, const Array &ess_tdof_list, Vector &x, Vector &b, - Vector &X, Vector &B, int copy_interior = 0); +void EliminateRHS(Operator& A, ConstrainedOperator& constrainedA, const Array& ess_tdof_list, Vector& x, Vector& b, + Vector& X, Vector& B, int copy_interior = 0); /// Remove mean from a Vector. /** * Modify the Vector @a v by subtracting its mean using * \f$v = v - \frac{\sum_i^N v_i}{N} \f$ */ -void Orthogonalize(Vector &v, MPI_Comm comm); +void Orthogonalize(Vector& v, MPI_Comm comm); // Adding to the mfem namespace namespace mfem { @@ -212,21 +212,21 @@ namespace mfem { /// Matrix coefficient defined as the Gradient of a Vector GridFunction class GradientVectorGridFunctionCoefficient : public MatrixCoefficient { protected: - const GridFunction *GridFunc; + const GridFunction* GridFunc; public: /** @brief Construct the coefficient with a scalar grid function @a gf. The grid function is not owned by the coefficient. */ - GradientVectorGridFunctionCoefficient(const GridFunction *gf); + GradientVectorGridFunctionCoefficient(const GridFunction* gf); /// Set the scalar grid function. - void SetGridFunction(const GridFunction *gf); + void SetGridFunction(const GridFunction* gf); /// Get the scalar grid function. - const GridFunction *GetGridFunction() const { return GridFunc; } + const GridFunction* GetGridFunction() const { return GridFunc; } /// Evaluate the gradient vector coefficient at @a ip. - virtual void Eval(DenseMatrix &G, ElementTransformation &T, const IntegrationPoint &ip); + virtual void Eval(DenseMatrix& G, ElementTransformation& T, const IntegrationPoint& ip); virtual ~GradientVectorGridFunctionCoefficient() {} }; @@ -234,41 +234,41 @@ class GradientVectorGridFunctionCoefficient : public MatrixCoefficient { /// Scalar coefficient defined as the magnitude of a vector coefficient class VectorMagnitudeCoefficient : public Coefficient { private: - VectorCoefficient *a; + VectorCoefficient* a; mutable Vector va; public: /// Construct with the vector coefficient. Result is \sqrt{(\f$ A \cdot a \f$}. - VectorMagnitudeCoefficient(VectorCoefficient &A); + VectorMagnitudeCoefficient(VectorCoefficient& A); /// Set the time for internally stored coefficients void SetTime(double t); /// Reset the vector - void SetACoef(VectorCoefficient &A) { a = &A; } + void SetACoef(VectorCoefficient& A) { a = &A; } /// Return the vector coefficient - VectorCoefficient *GetACoef() const { return a; } + VectorCoefficient* GetACoef() const { return a; } /// Evaluate the coefficient at @a ip. - virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); + virtual double Eval(ElementTransformation& T, const IntegrationPoint& ip); }; /// Matrix coefficient computed from a function F(v(x)) of a dim-sized vector coefficient, v(x) class TransformedMatrixVectorCoefficient : public MatrixCoefficient { protected: - VectorCoefficient *Q1; - std::function Function; + VectorCoefficient* Q1; + std::function Function; public: - TransformedMatrixVectorCoefficient(VectorCoefficient *vc, std::function F) + TransformedMatrixVectorCoefficient(VectorCoefficient* vc, std::function F) : MatrixCoefficient(vc->GetVDim()), Q1(vc), Function(std::move(F)) {} /// Set the time for internally stored coefficients void SetTime(double t); // using MatrixCoefficient::Eval; - virtual void Eval(DenseMatrix &G, ElementTransformation &T, const IntegrationPoint &ip); + virtual void Eval(DenseMatrix& G, ElementTransformation& T, const IntegrationPoint& ip); virtual ~TransformedMatrixVectorCoefficient() {} }; @@ -277,22 +277,22 @@ class TransformedMatrixVectorCoefficient : public MatrixCoefficient { /// easier to implement wrapped functions with fixed arguments class ExtTransformedCoefficient : public Coefficient { protected: - Coefficient *Q1; - Coefficient *Q2; + Coefficient* Q1; + Coefficient* Q2; std::function Transform1; std::function Transform2; public: /// Define a time-independent coefficient from a std function /** \param F time-independent std::function */ - ExtTransformedCoefficient(Coefficient *q, std::function F) : Q1(q), Transform1(std::move(F)) { + ExtTransformedCoefficient(Coefficient* q, std::function F) : Q1(q), Transform1(std::move(F)) { Q2 = 0; Transform2 = 0; } /// Define a time-dependent coefficient from a std function /** \param TDF time-dependent function */ - ExtTransformedCoefficient(Coefficient *q1, Coefficient *q2, std::function F) + ExtTransformedCoefficient(Coefficient* q1, Coefficient* q2, std::function F) : Q1(q1), Q2(q2), Transform2(std::move(F)) { Transform1 = 0; } @@ -301,7 +301,7 @@ class ExtTransformedCoefficient : public Coefficient { void SetTime(double t); /// Evaluate the coefficient at @a ip. - virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip); + virtual double Eval(ElementTransformation& T, const IntegrationPoint& ip); virtual ~ExtTransformedCoefficient() {} }; diff --git a/src/wallBC.cpp b/src/wallBC.cpp index d51e7a1d..3d30f031 100644 --- a/src/wallBC.cpp +++ b/src/wallBC.cpp @@ -34,10 +34,10 @@ #include "riemann_solver.hpp" -WallBC::WallBC(RiemannSolverTPS *_rsolver, GasMixture *_mixture, GasMixture *d_mixture, Equations _eqSystem, - Fluxes *_fluxClass, ParFiniteElementSpace *_vfes, IntegrationRules *_intRules, double &_dt, +WallBC::WallBC(RiemannSolverTPS* _rsolver, GasMixture* _mixture, GasMixture* d_mixture, Equations _eqSystem, + Fluxes* _fluxClass, ParFiniteElementSpace* _vfes, IntegrationRules* _intRules, double& _dt, const int _dim, const int _num_equation, int _patchNumber, WallType _bcType, const WallData _inputData, - const boundaryFaceIntegrationData &boundary_face_data, const int &_maxIntPoints, bool axisym, + const boundaryFaceIntegrationData& boundary_face_data, const int& _maxIntPoints, bool axisym, bool useBCinGrad) : BoundaryCondition(_rsolver, _mixture, _eqSystem, _vfes, _intRules, _dt, _dim, _num_equation, _patchNumber, 1, axisym), // so far walls do not require ref. length. Left at 1 @@ -202,8 +202,8 @@ void WallBC::buildWallElemsArray() { wallElems.ReadWrite(); } -void WallBC::computeBdrFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - double time, double distance, Vector &bdrFlux) { +void WallBC::computeBdrFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + double time, double distance, Vector& bdrFlux) { switch (wallType_) { /* case INV: @@ -238,7 +238,7 @@ void WallBC::computeBdrFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradSt } } -void WallBC::computeBdrPrimitiveStateForGradient(const Vector &primIn, Vector &primBC) const { +void WallBC::computeBdrPrimitiveStateForGradient(const Vector& primIn, Vector& primBC) const { primBC = primIn; switch (wallType_) { @@ -265,17 +265,17 @@ void WallBC::computeBdrPrimitiveStateForGradient(const Vector &primIn, Vector &p } } -void WallBC::integrationBC(Vector &y, const Vector &x, const elementIndexingData &elem_index_data, ParGridFunction *Up, - ParGridFunction *gradUp, const boundaryFaceIntegrationData &boundary_face_data, - const int &maxIntPoints, const int &maxDofs) { +void WallBC::integrationBC(Vector& y, const Vector& x, const elementIndexingData& elem_index_data, ParGridFunction* Up, + ParGridFunction* gradUp, const boundaryFaceIntegrationData& boundary_face_data, + const int& maxIntPoints, const int& maxDofs) { interpWalls_gpu(x, elem_index_data, Up, gradUp, boundary_face_data, maxDofs); integrateWalls_gpu(y, // output x, elem_index_data, boundary_face_data, maxDofs); } -void WallBC::computeINVwallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - double distance, Vector &bdrFlux) { +void WallBC::computeINVwallFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + double distance, Vector& bdrFlux) { Vector vel(nvel_); for (int d = 0; d < nvel_; d++) vel[d] = stateIn[1 + d] / stateIn[0]; @@ -323,8 +323,8 @@ void WallBC::computeINVwallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gr Inviscid slip boundary condition. Finds interior velocity in wall-coordinates, flips normal component (mirror state), transforms back to global, send to riemann */ -void WallBC::computeSlipWallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - Vector &bdrFlux) { +void WallBC::computeSlipWallFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + Vector& bdrFlux) { Vector prim(num_equation_); mixture->GetPrimitivesFromConservatives(stateIn, prim); @@ -427,8 +427,8 @@ void WallBC::computeSlipWallFlux(Vector &normal, Vector &stateIn, DenseMatrix &g rsolver->Eval(stateIn, state2, normal, bdrFlux); } -void WallBC::computeAdiabaticWallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, - double delta, Vector &bdrFlux) { +void WallBC::computeAdiabaticWallFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, + double delta, Vector& bdrFlux) { Vector wallState(num_equation_); mixture->computeStagnationState(stateIn, wallState); @@ -468,8 +468,8 @@ void WallBC::computeAdiabaticWallFlux(Vector &normal, Vector &stateIn, DenseMatr } } -void WallBC::computeIsothermalWallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, - double delta, Vector &bdrFlux) { +void WallBC::computeIsothermalWallFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, + double delta, Vector& bdrFlux) { Vector wallState(num_equation_); wallState = stateIn; @@ -509,8 +509,8 @@ void WallBC::computeIsothermalWallFlux(Vector &normal, Vector &stateIn, DenseMat } } -void WallBC::computeGeneralWallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, - double delta, Vector &bdrFlux) { +void WallBC::computeGeneralWallFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, + double delta, Vector& bdrFlux) { Vector wallState(num_equation_); mixture->modifyStateFromPrimitive(stateIn, bcState_, wallState); @@ -542,20 +542,20 @@ void WallBC::computeGeneralWallFlux(Vector &normal, Vector &stateIn, DenseMatrix } } -void WallBC::integrateWalls_gpu(Vector &y, const Vector &x, const elementIndexingData &elem_index_data, - const boundaryFaceIntegrationData &boundary_face_data, const int &maxDofs) { +void WallBC::integrateWalls_gpu(Vector& y, const Vector& x, const elementIndexingData& elem_index_data, + const boundaryFaceIntegrationData& boundary_face_data, const int& maxDofs) { #ifdef _GPU_ - double *d_y = y.ReadWrite(); + double* d_y = y.ReadWrite(); // const double *d_U = x.Read(); - const int *d_elem_dofs_list = elem_index_data.dofs_list.Read(); - const int *d_elem_dof_off = elem_index_data.dof_offset.Read(); - const int *d_elem_dof_num = elem_index_data.dof_number.Read(); - const double *d_face_shape = boundary_face_data.shape.Read(); - const double *d_weight = boundary_face_data.quad_weight.Read(); - const int *d_face_el = boundary_face_data.el.Read(); - const int *d_face_num_quad = boundary_face_data.num_quad.Read(); - const int *d_wallElems = wallElems.Read(); - const int *d_listElems = listElems.Read(); + const int* d_elem_dofs_list = elem_index_data.dofs_list.Read(); + const int* d_elem_dof_off = elem_index_data.dof_offset.Read(); + const int* d_elem_dof_num = elem_index_data.dof_number.Read(); + const double* d_face_shape = boundary_face_data.shape.Read(); + const double* d_weight = boundary_face_data.quad_weight.Read(); + const int* d_face_el = boundary_face_data.el.Read(); + const int* d_face_num_quad = boundary_face_data.num_quad.Read(); + const int* d_wallElems = wallElems.Read(); + const int* d_listElems = listElems.Read(); const int totDofs = x.Size() / num_equation_; // const int numBdrElem = listElems.Size(); @@ -563,7 +563,7 @@ void WallBC::integrateWalls_gpu(Vector &y, const Vector &x, const elementIndexin const int num_equation = num_equation_; const int maxIntPoints = maxIntPoints_; - const double *d_flux = face_flux_.Read(); + const double* d_flux = face_flux_.Read(); // clang-format on // MFEM_FORALL(el_wall, wallElems.Size() / 7, { @@ -631,25 +631,25 @@ void WallBC::integrateWalls_gpu(Vector &y, const Vector &x, const elementIndexin #endif } -void WallBC::interpWalls_gpu(const mfem::Vector &x, const elementIndexingData &elem_index_data, - mfem::ParGridFunction *Up, mfem::ParGridFunction *gradUp, - const boundaryFaceIntegrationData &boundary_face_data, const int &maxDofs) { +void WallBC::interpWalls_gpu(const mfem::Vector& x, const elementIndexingData& elem_index_data, + mfem::ParGridFunction* Up, mfem::ParGridFunction* gradUp, + const boundaryFaceIntegrationData& boundary_face_data, const int& maxDofs) { #ifdef _GPU_ - double *d_flux = face_flux_.Write(); - - const double *d_U = x.Read(); - const double *d_gradUp = gradUp->Read(); - const int *d_elem_dofs_list = elem_index_data.dofs_list.Read(); - const int *d_elem_dof_off = elem_index_data.dof_offset.Read(); - const int *d_elem_dof_num = elem_index_data.dof_number.Read(); - const double *d_face_shape = boundary_face_data.shape.Read(); - const double *d_normal = boundary_face_data.normal.Read(); - const double *d_xyz = boundary_face_data.xyz.Read(); - const int *d_face_num_quad = boundary_face_data.num_quad.Read(); - const int *d_face_el = boundary_face_data.el.Read(); - const int *d_wallElems = wallElems.Read(); - const int *d_listElems = listElems.Read(); - const double *d_dist = boundary_face_data.dist.Read(); + double* d_flux = face_flux_.Write(); + + const double* d_U = x.Read(); + const double* d_gradUp = gradUp->Read(); + const int* d_elem_dofs_list = elem_index_data.dofs_list.Read(); + const int* d_elem_dof_off = elem_index_data.dof_offset.Read(); + const int* d_elem_dof_num = elem_index_data.dof_number.Read(); + const double* d_face_shape = boundary_face_data.shape.Read(); + const double* d_normal = boundary_face_data.normal.Read(); + const double* d_xyz = boundary_face_data.xyz.Read(); + const int* d_face_num_quad = boundary_face_data.num_quad.Read(); + const int* d_face_el = boundary_face_data.el.Read(); + const int* d_wallElems = wallElems.Read(); + const int* d_listElems = listElems.Read(); + const double* d_dist = boundary_face_data.dist.Read(); auto d_delta = boundary_face_data.delta_el1.Read(); @@ -667,9 +667,9 @@ void WallBC::interpWalls_gpu(const mfem::Vector &x, const elementIndexingData &e const bool computeSheath = (wallData_.elecThermalCond == SHTH); - const RiemannSolverTPS *d_rsolver = rsolver; - GasMixture *d_mix = d_mixture_; - Fluxes *d_fluxclass = fluxClass; + const RiemannSolverTPS* d_rsolver = rsolver; + GasMixture* d_mix = d_mixture_; + Fluxes* d_fluxclass = fluxClass; const bool useBCinGrad = useBCinGrad_; diff --git a/src/wallBC.hpp b/src/wallBC.hpp index dd4e0c18..68970319 100644 --- a/src/wallBC.hpp +++ b/src/wallBC.hpp @@ -49,8 +49,8 @@ class WallBC : public BoundaryCondition { const bool useBCinGrad_; - GasMixture *d_mixture_; // only used in the device. - Fluxes *fluxClass; + GasMixture* d_mixture_; // only used in the device. + Fluxes* fluxClass; // TODO(kevin): eventually replace this with wallPrim. double wallTemp_; @@ -59,54 +59,54 @@ class WallBC : public BoundaryCondition { BoundaryViscousFluxData bcFlux_; BoundaryPrimitiveData bcState_; - const boundaryFaceIntegrationData &boundary_face_data_; - const int &maxIntPoints_; + const boundaryFaceIntegrationData& boundary_face_data_; + const int& maxIntPoints_; Array wallElems; void buildWallElemsArray(); - void computeINVwallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - double distance, Vector &bdrFlux); - void computeSlipWallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - Vector &bdrFlux); - void computeAdiabaticWallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - Vector &bdrFlux); - void computeIsothermalWallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - Vector &bdrFlux); - void computeGeneralWallFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - Vector &bdrFlux); + void computeINVwallFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + double distance, Vector& bdrFlux); + void computeSlipWallFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + Vector& bdrFlux); + void computeAdiabaticWallFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + Vector& bdrFlux); + void computeIsothermalWallFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + Vector& bdrFlux); + void computeGeneralWallFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + Vector& bdrFlux); public: - WallBC(RiemannSolverTPS *rsolver_, GasMixture *_mixture, GasMixture *d_mixture, Equations _eqSystem, - Fluxes *_fluxClass, ParFiniteElementSpace *_vfes, IntegrationRules *_intRules, double &_dt, const int _dim, + WallBC(RiemannSolverTPS* rsolver_, GasMixture* _mixture, GasMixture* d_mixture, Equations _eqSystem, + Fluxes* _fluxClass, ParFiniteElementSpace* _vfes, IntegrationRules* _intRules, double& _dt, const int _dim, const int _num_equation, int _patchNumber, WallType _bcType, const WallData _inputData, - const boundaryFaceIntegrationData &boundary_face_data, const int &maxIntPoints, bool axisym, + const boundaryFaceIntegrationData& boundary_face_data, const int& maxIntPoints, bool axisym, bool useBCinGrad = false); ~WallBC(); WallType getType() { return wallType_; } - void computeBdrFlux(Vector &normal, Vector &stateIn, DenseMatrix &gradState, Vector transip, double delta, - double time, double distance, Vector &bdrFlux) override; - void computeBdrPrimitiveStateForGradient(const Vector &primIn, Vector &primBC) const override; + void computeBdrFlux(Vector& normal, Vector& stateIn, DenseMatrix& gradState, Vector transip, double delta, + double time, double distance, Vector& bdrFlux) override; + void computeBdrPrimitiveStateForGradient(const Vector& primIn, Vector& primBC) const override; void initBCs() override; - void updateMean(IntegrationRules *intRules, ParGridFunction *Up) override {} + void updateMean(IntegrationRules* intRules, ParGridFunction* Up) override {} // functions for BC integration on GPU - void integrationBC(Vector &y, // output - const Vector &x, const elementIndexingData &elem_index_data, ParGridFunction *Up, - ParGridFunction *gradUp, const boundaryFaceIntegrationData &boundary_face_data, - const int &maxIntPoints, const int &maxDofs) override; + void integrationBC(Vector& y, // output + const Vector& x, const elementIndexingData& elem_index_data, ParGridFunction* Up, + ParGridFunction* gradUp, const boundaryFaceIntegrationData& boundary_face_data, + const int& maxIntPoints, const int& maxDofs) override; - void integrateWalls_gpu(Vector &y, // output - const Vector &x, const elementIndexingData &elem_index_data, - const boundaryFaceIntegrationData &boundary_face_data, const int &maxDofs); + void integrateWalls_gpu(Vector& y, // output + const Vector& x, const elementIndexingData& elem_index_data, + const boundaryFaceIntegrationData& boundary_face_data, const int& maxDofs); - void interpWalls_gpu(const Vector &x, const elementIndexingData &elem_index_data, ParGridFunction *Up, - ParGridFunction *gradUp, const boundaryFaceIntegrationData &boundary_face_data, - const int &maxDofs); + void interpWalls_gpu(const Vector& x, const elementIndexingData& elem_index_data, ParGridFunction* Up, + ParGridFunction* gradUp, const boundaryFaceIntegrationData& boundary_face_data, + const int& maxDofs); double getWallTemp() const { assert(wallType_ == VISC_ISOTH); @@ -114,8 +114,8 @@ class WallBC : public BoundaryCondition { } #ifdef _GPU_ - static MFEM_HOST_DEVICE void computeInvWallState(const double *u1, double *u2, const double *nor, const int &dim, - const int &num_equation, const int &thrd, const int &maxThreads) { + static MFEM_HOST_DEVICE void computeInvWallState(const double* u1, double* u2, const double* nor, const int& dim, + const int& num_equation, const int& thrd, const int& maxThreads) { MFEM_SHARED double momNormal, norm; MFEM_SHARED double unitNor[3]; @@ -143,8 +143,8 @@ class WallBC : public BoundaryCondition { } } - static MFEM_HOST_DEVICE void computeInvWallState_gpu_serial(const double *u1, double *u2, const double *nor, - const int &dim, const int &num_equation) { + static MFEM_HOST_DEVICE void computeInvWallState_gpu_serial(const double* u1, double* u2, const double* nor, + const int& dim, const int& num_equation) { double momNormal, norm; double unitNor[3]; @@ -164,11 +164,11 @@ class WallBC : public BoundaryCondition { } } - static MFEM_HOST_DEVICE void computeIsothermalState(const double *u1, double *u2, const double *nor, - const double &wallTemp, const double &gamma, const double &Rg, - const int &dim, const int &num_equation, - const WorkingFluid &fluid, const int &thrd, - const int &maxThreads) { + static MFEM_HOST_DEVICE void computeIsothermalState(const double* u1, double* u2, const double* nor, + const double& wallTemp, const double& gamma, const double& Rg, + const int& dim, const int& num_equation, + const WorkingFluid& fluid, const int& thrd, + const int& maxThreads) { if (thrd < num_equation) u2[thrd] = u1[thrd]; MFEM_SYNC_THREAD; @@ -177,10 +177,10 @@ class WallBC : public BoundaryCondition { } } - static MFEM_HOST_DEVICE void computeIsothermalState_gpu_serial(const double *u1, double *u2, const double *nor, - const double &wallTemp, const double &gamma, - const double &Rg, const int &dim, - const int &num_equation, const WorkingFluid &fluid) { + static MFEM_HOST_DEVICE void computeIsothermalState_gpu_serial(const double* u1, double* u2, const double* nor, + const double& wallTemp, const double& gamma, + const double& Rg, const int& dim, + const int& num_equation, const WorkingFluid& fluid) { for (int eq = 0; eq < num_equation; eq++) { u2[eq] = u1[eq]; } diff --git a/src/zetaModel.cpp b/src/zetaModel.cpp index 1b52dfe8..73578aa0 100644 --- a/src/zetaModel.cpp +++ b/src/zetaModel.cpp @@ -49,13 +49,13 @@ using namespace mfem; using namespace mfem::common; -static double radius(const Vector &pos) { return pos[0]; } +static double radius(const Vector& pos) { return pos[0]; } static FunctionCoefficient radius_coeff(radius); double smoothMin(double val1, double val2); double smoothMax(double val1, double val2); -ZetaModel::ZetaModel(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalSchemeCoefficients &time_coeff, - TPS::Tps *tps, ParGridFunction *gridScale) +ZetaModel::ZetaModel(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalSchemeCoefficients& time_coeff, + TPS::Tps* tps, ParGridFunction* gridScale) : tpsP_(tps), loMach_opts_(loMach_opts), pmesh_(pmesh), time_coeff_(time_coeff) { rank_ = pmesh_->GetMyRank(); rank0_ = (pmesh_->GetMyRank() == 0); @@ -94,7 +94,7 @@ ZetaModel::ZetaModel(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalS tpsP_->getInput("ransModel/streamwise-stabilization", sw_stab_, false); tpsP_->getInput("ransModel/Reh_factor", Reh_factor_, 1.0); tpsP_->getInput("ransModel/Reh_offset", Reh_offset_, 0.0); - + // solver options tpsP_->getInput("ransModel/hsolve-maxIters", max_iter_, 2000); tpsP_->getInput("ransModel/fsolve-maxIters", f_max_iter_, 4000); @@ -107,7 +107,6 @@ ZetaModel::ZetaModel(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalS } ZetaModel::~ZetaModel() { - delete As_form_; delete Ms_form_; delete MsRho_form_; @@ -148,7 +147,7 @@ ZetaModel::~ZetaModel() { delete tke_coeff_; delete nu_coeff_; delete gradTKE_coeff_; - // delete nu_delta_coeff_; + // delete nu_delta_coeff_; // delete two_nu_delta_coeff_; // NOTE: seg fault originates from deleting coeffs used for BCs, which is done automatically in @@ -205,7 +204,6 @@ ZetaModel::~ZetaModel() { delete sfes_; delete vfec_; delete vfes_; - } void ZetaModel::initializeSelf() { @@ -217,7 +215,7 @@ void ZetaModel::initializeSelf() { // scalar sfec_ = new H1_FECollection(order_); - //sfec_ = new H1_FECollection(forder_); + // sfec_ = new H1_FECollection(forder_); sfes_ = new ParFiniteElementSpace(pmesh_, sfec_); // f-rate @@ -226,7 +224,7 @@ void ZetaModel::initializeSelf() { // vector vfec_ = new H1_FECollection(order_, dim_); - //vfec_ = new H1_FECollection(forder_, dim_); + // vfec_ = new H1_FECollection(forder_, dim_); vfes_ = new ParFiniteElementSpace(pmesh_, vfec_, dim_); // Check if fully periodic mesh @@ -288,7 +286,7 @@ void ZetaModel::initializeSelf() { filter_gf_.SetSpace(ffes_); filter_.SetSize(ffes_truevsize); filter_gf_ = 0.0; - filter_ = 0.0; + filter_ = 0.0; tke_next_gf_.SetSpace(sfes_); tke_next_.SetSize(sfes_truevsize); @@ -368,7 +366,7 @@ void ZetaModel::initializeSelf() { tls2_.SetSize(sfes_truevsize); tls2_gf_ = 1.0; tls2_gf_.GetTrueDofs(tls2_); - + tts_gf_.SetSpace(sfes_); tts_.SetSize(sfes_truevsize); tts_gf_ = 1.0; @@ -484,7 +482,7 @@ void ZetaModel::initializeSelf() { if (axisym_) { radius_gf_.ProjectCoefficient(radius_coeff); radius_gf_.GetTrueDofs(radius_v_); - // fradius_gf_.ProjectGridFunction(radius_gf_); + // fradius_gf_.ProjectGridFunction(radius_gf_); } //----------------------------------------------------- @@ -636,19 +634,18 @@ void ZetaModel::initializeSelf() { } void ZetaModel::initializeOperators() { - dt_ = time_coeff_.dt; Array empty; // GLL integration rule (Numerical Integration) // const IntegrationRule &ir_lump = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ - 1); - const IntegrationRule &ir_i = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ + 1); - const IntegrationRule &ir_nli = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 4 * order_); - const IntegrationRule &ir_di = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * order_ - 1); + const IntegrationRule& ir_i = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * order_ + 1); + const IntegrationRule& ir_nli = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 4 * order_); + const IntegrationRule& ir_di = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * order_ - 1); - const IntegrationRule &ir_if = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * forder_ + 1); - const IntegrationRule &ir_dif = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * forder_ - 1); + const IntegrationRule& ir_if = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 2 * forder_ + 1); + const IntegrationRule& ir_dif = gll_rules_.Get(sfes_->GetFE(0)->GetGeomType(), 3 * forder_ - 1); // coefficients for operators zero_coeff_ = new ConstantCoefficient(0.0); @@ -694,7 +691,7 @@ void ZetaModel::initializeOperators() { tdr_diff_total_coeff_ = new ProductCoefficient(*mult_coeff_, *tdr_diff_sum_coeff_); zeta_diff_total_coeff_ = new ProductCoefficient(*mult_coeff_, *zeta_diff_sum_coeff_); // unity_diff_total_coeff_ = new ProductCoefficient(*unity_coeff_, *unity_diff_coeff_); - + // unsteady- and destruction-related rhoDt_gf_ = *(thermoChem_interface_->density); rhoDt_gf_ /= dt_; @@ -733,13 +730,11 @@ void ZetaModel::initializeOperators() { // need separate coeffs for f-space (all of em) // rad_f_diag_coeff_ = new ProductCoefficient(fradius_coeff, *f_diag_coeff_); rad_f_diag_coeff_ = new ProductCoefficient(radius_coeff, *f_diag_coeff_); - } // artifical diffusion coefficients if (sw_stab_) { - - gscale_coeff_ = new GridFunctionCoefficient(gridScale_gf_); + gscale_coeff_ = new GridFunctionCoefficient(gridScale_gf_); umag_coeff_ = new VectorMagnitudeCoefficient(*vel_coeff_); visc_coeff_ = new GridFunctionCoefficient(*mu_coeff_); @@ -768,10 +763,10 @@ void ZetaModel::initializeOperators() { supg_coeff_ = new ScalarMatrixProductCoefficient(*upwind_coeff_, *swdiff_coeff_); } - + // operators As_form_ = new ParBilinearForm(sfes_); - ConvectionIntegrator *as_blfi; + ConvectionIntegrator* as_blfi; if (axisym_) { as_blfi = new ConvectionIntegrator(*rad_rhou_coeff_); } else { @@ -789,7 +784,7 @@ void ZetaModel::initializeOperators() { // mass matrix Ms_form_ = new ParBilinearForm(sfes_); - MassIntegrator *ms_blfi; + MassIntegrator* ms_blfi; if (axisym_) { ms_blfi = new MassIntegrator(radius_coeff); } else { @@ -807,7 +802,7 @@ void ZetaModel::initializeOperators() { // mass matrix with rho MsRho_form_ = new ParBilinearForm(sfes_); - MassIntegrator *msrho_blfi; + MassIntegrator* msrho_blfi; if (axisym_) { msrho_blfi = new MassIntegrator(*rad_rho_coeff_); } else { @@ -824,7 +819,7 @@ void ZetaModel::initializeOperators() { MsRho_form_->Assemble(); MsRho_form_->FormSystemMatrix(empty, MsRho_); Mf_form_ = new ParBilinearForm(sfes_); - MassIntegrator *mf_blfi; + MassIntegrator* mf_blfi; if (axisym_) { mf_blfi = new MassIntegrator(radius_coeff); } else { @@ -870,8 +865,8 @@ void ZetaModel::initializeOperators() { // auto *hmk_blfi = new MassIntegrator(*tke_diag_coeff_); // auto *hmk_blfi = new MassIntegrator(*rhoDt_coeff_); // auto *hdk_blfi = new DiffusionIntegrator(*tke_diff_total_coeff_); - MassIntegrator *hmk_blfi; - DiffusionIntegrator *hdk_blfi; + MassIntegrator* hmk_blfi; + DiffusionIntegrator* hdk_blfi; if (axisym_) { hmk_blfi = new MassIntegrator(*rad_tke_diag_coeff_); hdk_blfi = new DiffusionIntegrator(*rad_tke_diff_total_coeff_); @@ -886,12 +881,12 @@ void ZetaModel::initializeOperators() { Hk_form_->AddDomainIntegrator(hmk_blfi); Hk_form_->AddDomainIntegrator(hdk_blfi); if (sw_stab_) { - auto *sdk_blfi = new DiffusionIntegrator(*supg_coeff_); + auto* sdk_blfi = new DiffusionIntegrator(*supg_coeff_); if (numerical_integ_) { sdk_blfi->SetIntRule(&ir_di); } Hk_form_->AddDomainIntegrator(sdk_blfi); - } + } Hk_form_->Assemble(); Hk_form_->FormSystemMatrix(tke_ess_tdof_, Hk_); @@ -899,8 +894,8 @@ void ZetaModel::initializeOperators() { // auto *hme_blfi = new MassIntegrator(*tdr_diag_coeff_); // auto *hme_blfi = new MassIntegrator(*rhoDt_coeff_); // auto *hde_blfi = new DiffusionIntegrator(*tdr_diff_total_coeff_); - MassIntegrator *hme_blfi; - DiffusionIntegrator *hde_blfi; + MassIntegrator* hme_blfi; + DiffusionIntegrator* hde_blfi; if (axisym_) { hme_blfi = new MassIntegrator(*rad_tdr_diag_coeff_); hde_blfi = new DiffusionIntegrator(*rad_tdr_diff_total_coeff_); @@ -916,12 +911,12 @@ void ZetaModel::initializeOperators() { He_form_->AddDomainIntegrator(hme_blfi); He_form_->AddDomainIntegrator(hde_blfi); if (sw_stab_) { - auto *sde_blfi = new DiffusionIntegrator(*supg_coeff_); + auto* sde_blfi = new DiffusionIntegrator(*supg_coeff_); if (numerical_integ_) { sde_blfi->SetIntRule(&ir_di); } He_form_->AddDomainIntegrator(sde_blfi); - } + } He_form_->Assemble(); He_form_->FormSystemMatrix(tdr_ess_tdof_, He_); @@ -929,8 +924,8 @@ void ZetaModel::initializeOperators() { // auto *hmv_blfi = new MassIntegrator(*v2_diag_coeff_); // auto *hmv_blfi = new MassIntegrator(*rhoDt_coeff_); // auto *hdv_blfi = new DiffusionIntegrator(*tke_diff_total_coeff_); // NOTE: not an error - MassIntegrator *hmv_blfi; - DiffusionIntegrator *hdv_blfi; + MassIntegrator* hmv_blfi; + DiffusionIntegrator* hdv_blfi; if (axisym_) { hmv_blfi = new MassIntegrator(*rad_v2_diag_coeff_); hdv_blfi = new DiffusionIntegrator(*rad_tke_diff_total_coeff_); @@ -945,12 +940,12 @@ void ZetaModel::initializeOperators() { Hv_form_->AddDomainIntegrator(hmv_blfi); Hv_form_->AddDomainIntegrator(hdv_blfi); if (sw_stab_) { - auto *sdv_blfi = new DiffusionIntegrator(*supg_coeff_); + auto* sdv_blfi = new DiffusionIntegrator(*supg_coeff_); if (numerical_integ_) { sdv_blfi->SetIntRule(&ir_di); } Hv_form_->AddDomainIntegrator(sdv_blfi); - } + } Hv_form_->Assemble(); Hv_form_->FormSystemMatrix(v2_ess_tdof_, Hv_); @@ -961,8 +956,8 @@ void ZetaModel::initializeOperators() { // div(L^2 df) - f =... // auto *hmf_blfi = new MassIntegrator(*unity_coeff_); // auto *hdf_blfi = new DiffusionIntegrator(*tls2_coeff_); - MassIntegrator *hmf_blfi; - DiffusionIntegrator *hdf_blfi; + MassIntegrator* hmf_blfi; + DiffusionIntegrator* hdf_blfi; if (axisym_) { hmf_blfi = new MassIntegrator(*rad_f_diag_coeff_); hdf_blfi = new DiffusionIntegrator(*rad_unity_coeff_); @@ -982,8 +977,8 @@ void ZetaModel::initializeOperators() { Hz_form_ = new ParBilinearForm(sfes_); // auto *hmz_blfi = new MassIntegrator(*zeta_diag_coeff_); // auto *hdz_blfi = new DiffusionIntegrator(*zeta_diff_total_coeff_); - MassIntegrator *hmz_blfi; - DiffusionIntegrator *hdz_blfi; + MassIntegrator* hmz_blfi; + DiffusionIntegrator* hdz_blfi; if (axisym_) { hmz_blfi = new MassIntegrator(*rad_zeta_diag_coeff_); hdz_blfi = new DiffusionIntegrator(*rad_zeta_diff_total_coeff_); @@ -1012,7 +1007,7 @@ void ZetaModel::initializeOperators() { */ Lk_form_ = new ParBilinearForm(sfes_); // auto *lkd_blfi = new DiffusionIntegrator(*scalar_diff_coeff_); - DiffusionIntegrator *lkd_blfi; + DiffusionIntegrator* lkd_blfi; if (axisym_) { lkd_blfi = new DiffusionIntegrator(*rad_scalar_diff_coeff_); } else { @@ -1030,7 +1025,7 @@ void ZetaModel::initializeOperators() { Lk_bdry_ = new ParLinearForm(sfes_); // auto *lk_bdry_lfi = new BoundaryNormalLFIntegrator(*nu_gradTKE_coeff_, 2, -1); - BoundaryNormalLFIntegrator *lk_bdry_lfi; + BoundaryNormalLFIntegrator* lk_bdry_lfi; if (axisym_) { lk_bdry_lfi = new BoundaryNormalLFIntegrator(*rad_nu_gradTKE_coeff_, 2, -1); } else { @@ -1048,7 +1043,7 @@ void ZetaModel::initializeOperators() { MsInvPC_ = new OperatorJacobiSmoother(diag_pa, empty); } else { MsInvPC_ = new HypreSmoother(*Ms_.As()); - dynamic_cast(MsInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(MsInvPC_)->SetType(HypreSmoother::Jacobi, 1); } MsInv_ = new CGSolver(sfes_->GetComm()); MsInv_->iterative_mode = false; @@ -1064,7 +1059,7 @@ void ZetaModel::initializeOperators() { MsRhoInvPC_ = new OperatorJacobiSmoother(diag_pa, empty); } else { MsRhoInvPC_ = new HypreSmoother(*MsRho_.As()); - dynamic_cast(MsRhoInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(MsRhoInvPC_)->SetType(HypreSmoother::Jacobi, 1); } MsRhoInv_ = new CGSolver(sfes_->GetComm()); MsRhoInv_->iterative_mode = false; @@ -1075,7 +1070,7 @@ void ZetaModel::initializeOperators() { MsRhoInv_->SetMaxIter(max_iter_); HkInvPC_ = new HypreSmoother(*Hk_.As()); - dynamic_cast(HkInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(HkInvPC_)->SetType(HypreSmoother::Jacobi, 1); HkInv_ = new CGSolver(sfes_->GetComm()); HkInv_->iterative_mode = true; HkInv_->SetOperator(*Hk_); @@ -1085,7 +1080,7 @@ void ZetaModel::initializeOperators() { HkInv_->SetMaxIter(max_iter_); HeInvPC_ = new HypreSmoother(*He_.As()); - dynamic_cast(HeInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(HeInvPC_)->SetType(HypreSmoother::Jacobi, 1); HeInv_ = new CGSolver(sfes_->GetComm()); HeInv_->iterative_mode = true; HeInv_->SetOperator(*He_); @@ -1095,7 +1090,7 @@ void ZetaModel::initializeOperators() { HeInv_->SetMaxIter(max_iter_); HvInvPC_ = new HypreSmoother(*Hv_.As()); - dynamic_cast(HvInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(HvInvPC_)->SetType(HypreSmoother::Jacobi, 1); HvInv_ = new CGSolver(sfes_->GetComm()); HvInv_->iterative_mode = true; HvInv_->SetOperator(*Hv_); @@ -1105,7 +1100,7 @@ void ZetaModel::initializeOperators() { HvInv_->SetMaxIter(max_iter_); HfInvPC_ = new HypreSmoother(*Hf_.As()); - dynamic_cast(HfInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(HfInvPC_)->SetType(HypreSmoother::Jacobi, 1); HfInv_ = new CGSolver(sfes_->GetComm()); // HfInv_ = new GMRESSolver(sfes_->GetComm()); HfInv_->iterative_mode = true; @@ -1116,7 +1111,7 @@ void ZetaModel::initializeOperators() { HfInv_->SetMaxIter(f_max_iter_); HzInvPC_ = new HypreSmoother(*Hz_.As()); - dynamic_cast(HzInvPC_)->SetType(HypreSmoother::Jacobi, 1); + dynamic_cast(HzInvPC_)->SetType(HypreSmoother::Jacobi, 1); HzInv_ = new CGSolver(sfes_->GetComm()); HzInv_->iterative_mode = true; HzInv_->SetOperator(*Hz_); @@ -1128,7 +1123,7 @@ void ZetaModel::initializeOperators() { if (rank0_) std::cout << "zeta-f operators set" << endl; } -void ZetaModel::initializeIO(IODataOrganizer &io) { +void ZetaModel::initializeIO(IODataOrganizer& io) { io.registerIOFamily("tke", "/tke", &tke_gf_, true, true, sfec_); io.registerIOVar("/tke", "tke", 0); io.registerIOFamily("tdr", "/tdr", &tdr_gf_, true, true, sfec_); @@ -1144,7 +1139,7 @@ void ZetaModel::initializeIO(IODataOrganizer &io) { io.registerIOVar("/muT", "muT", 0); } -void ZetaModel::initializeViz(ParaViewDataCollection &pvdc) { +void ZetaModel::initializeViz(ParaViewDataCollection& pvdc) { pvdc.RegisterField("Pk", &prod_gf_); pvdc.RegisterField("TTS", &tts_gf_); pvdc.RegisterField("TLS", &tls_gf_); @@ -1206,16 +1201,16 @@ void ZetaModel::step() { (sponge_interface_->diff_multiplier)->GetTrueDofs(mult_); // Set current time for Dirichlet boundary conditions. - for (auto &tke_dbc : tke_dbcs_) { + for (auto& tke_dbc : tke_dbcs_) { tke_dbc.coeff->SetTime(time_ + dt_); } - for (auto &tdr_dbc : tdr_dbcs_) { + for (auto& tdr_dbc : tdr_dbcs_) { tdr_dbc.coeff->SetTime(time_ + dt_); } - for (auto &fRate_dbc : fRate_dbcs_) { + for (auto& fRate_dbc : fRate_dbcs_) { fRate_dbc.coeff->SetTime(time_ + dt_); } - for (auto &zeta_dbc : zeta_dbcs_) { + for (auto& zeta_dbc : zeta_dbcs_) { zeta_dbc.coeff->SetTime(time_ + dt_); } @@ -1252,20 +1247,19 @@ void ZetaModel::step() { } void ZetaModel::updateMuT() { - // Cmu*rho portion eddyVisc_.Set(Cmu_, rho_); - + { double twoThirds = 2.0 / 3.0; - const double *dv2 = v2_next_.HostRead(); - const double *dk = tke_next_.HostRead(); - const double *dTTS = tts_.HostRead(); - const double *dTTS_strain = tts_strain_.HostRead(); - double *muT = eddyVisc_.HostReadWrite(); - - //for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dv2[i], twoThirds * dk[i]); - for (int i = 0; i < SdofInt_; i++) muT[i] *= smoothMin(dv2[i], twoThirds * dk[i]); + const double* dv2 = v2_next_.HostRead(); + const double* dk = tke_next_.HostRead(); + const double* dTTS = tts_.HostRead(); + const double* dTTS_strain = tts_strain_.HostRead(); + double* muT = eddyVisc_.HostReadWrite(); + + // for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dv2[i], twoThirds * dk[i]); + for (int i = 0; i < SdofInt_; i++) muT[i] *= smoothMin(dv2[i], twoThirds * dk[i]); // to prevent kinks // for (int i = 0; i < SdofInt_; i++) { // wgt = std::tanh(tanh_half_ * dv2[i]/(twoThirds*dk[i])); @@ -1273,7 +1267,7 @@ void ZetaModel::updateMuT() { // muT[i] *= ((1.0-wgt)*dv2[i] + wgt*twoThirds*dk[i]); //} - //for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dTTS[i], dTTS_strain[i]); + // for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dTTS[i], dTTS_strain[i]); for (int i = 0; i < SdofInt_; i++) muT[i] *= smoothMin(dTTS[i], dTTS_strain[i]); // to prevent kinks // for (int i = 0; i < SdofInt_; i++) { @@ -1282,7 +1276,7 @@ void ZetaModel::updateMuT() { // muT[i] *= ((1.0-wgt)*dTTS[i] + wgt*dTTS_strain[i]); //} - //for (int i = 0; i < SdofInt_; i++) muT[i] = std::max(muT[i], mut_min_); + // for (int i = 0; i < SdofInt_; i++) muT[i] = std::max(muT[i], mut_min_); for (int i = 0; i < SdofInt_; i++) muT[i] = smoothMax(muT[i], mut_min_); } eddyVisc_gf_.SetFromTrueDofs(eddyVisc_); @@ -1293,13 +1287,13 @@ void ZetaModel::updateMuT() { } void ZetaModel::computeStrain() { - const double *dGradU = gradU_.HostRead(); - const double *dGradV = gradV_.HostRead(); - const double *dGradW = gradW_.HostRead(); - const double *dGradS = gradS_.HostRead(); - double *Sij = strain_.HostReadWrite(); - double *dSmag = sMag_.HostReadWrite(); - double *dRad = radius_v_.HostReadWrite(); + const double* dGradU = gradU_.HostRead(); + const double* dGradV = gradV_.HostRead(); + const double* dGradW = gradW_.HostRead(); + const double* dGradS = gradS_.HostRead(); + double* Sij = strain_.HostReadWrite(); + double* dSmag = sMag_.HostReadWrite(); + double* dRad = radius_v_.HostReadWrite(); double Smin = 1.0e-14; for (int i = 0; i < SdofInt_; i++) { @@ -1369,21 +1363,20 @@ void ZetaModel::computeStrain() { } void ZetaModel::updateTTS() { - const double *dTKE = tke_next_.HostRead(); - const double *dTDR = tdr_next_.HostRead(); - const double *dv2 = v2_next_.HostRead(); + const double* dTKE = tke_next_.HostRead(); + const double* dTDR = tdr_next_.HostRead(); + const double* dv2 = v2_next_.HostRead(); // const double *dZeta = zeta_next_.HostRead(); - const double *dSmag = sMag_.HostRead(); - const double *dMu = mu_.HostRead(); - const double *dRho = rho_.HostRead(); - double *dTTS = tts_.HostReadWrite(); - double *dTTS_strain = tts_strain_.HostReadWrite(); - double *dTTS_kol = tts_kol_.HostReadWrite(); + const double* dSmag = sMag_.HostRead(); + const double* dMu = mu_.HostRead(); + const double* dRho = rho_.HostRead(); + double* dTTS = tts_.HostReadWrite(); + double* dTTS_strain = tts_strain_.HostReadWrite(); + double* dTTS_kol = tts_kol_.HostReadWrite(); double Ctime; Ctime = 0.6 / (std::sqrt(6.0) * Cmu_); for (int i = 0; i < SdofInt_; i++) { - double T1, T2, T3; T1 = dTKE[i] / std::max(dTDR[i], tdr_min_); T2 = Ctime * dTKE[i] / (dSmag[i] * std::max(dv2[i], v2_min_)); @@ -1403,39 +1396,39 @@ void ZetaModel::updateTTS() { // dTTS[i] = std::max(T1, T3); // to prevent kinks - //double wgt = 1.0; - //wgt = std::tanh(tanh_half_ * (T1/T3) * (T1/T3) ); - //dTTS[i] = wgt * T1 + (1.0 - wgt) * T3; - dTTS[i] = smoothMax(T1,T3); + // double wgt = 1.0; + // wgt = std::tanh(tanh_half_ * (T1/T3) * (T1/T3) ); + // dTTS[i] = wgt * T1 + (1.0 - wgt) * T3; + dTTS[i] = smoothMax(T1, T3); // including stag-limit T in nuT only // dTTS[i] = std::min(T1, T2); - //dTTS[i] = std::max(dTTS[i], tts_min_); - //dTTS[i] = std::min(dTTS[i], tts_max_); + // dTTS[i] = std::max(dTTS[i], tts_min_); + // dTTS[i] = std::min(dTTS[i], tts_max_); dTTS[i] = smoothMax(dTTS[i], tts_min_); dTTS[i] = smoothMin(dTTS[i], tts_max_); - + dTTS_kol[i] = T3; dTTS_strain[i] = T2; - //dTTS_strain[i] = std::max(dTTS_strain[i], tts_min_); - //dTTS_strain[i] = std::min(dTTS_strain[i], tts_max_); + // dTTS_strain[i] = std::max(dTTS_strain[i], tts_min_); + // dTTS_strain[i] = std::min(dTTS_strain[i], tts_max_); dTTS_strain[i] = smoothMax(dTTS_strain[i], tts_min_); - dTTS_strain[i] = smoothMin(dTTS_strain[i], tts_max_); + dTTS_strain[i] = smoothMin(dTTS_strain[i], tts_max_); } tts_gf_.SetFromTrueDofs(tts_); } void ZetaModel::updateTLS() { - const double *dTKE = tke_next_.HostRead(); - const double *dTDR = tdr_next_.HostRead(); + const double* dTKE = tke_next_.HostRead(); + const double* dTDR = tdr_next_.HostRead(); // const double *dv2 = v2_next_.HostRead(); // const double *dZeta = zeta_next_.HostRead(); // const double *dSmag = sMag_.HostRead(); - const double *dMu = mu_.HostRead(); - const double *dRho = rho_.HostRead(); - double *dTLS = tls_.HostReadWrite(); + const double* dMu = mu_.HostRead(); + const double* dRho = rho_.HostRead(); + double* dTLS = tls_.HostReadWrite(); double wgt = 1.0; // double Clength; @@ -1460,25 +1453,24 @@ void ZetaModel::updateTLS() { // to prevent kinks // wgt = std::tanh(tanh_half_ * dTLS[i]/L3); - //wgt = std::tanh(tanh_half_ * (L1/L3) * (L1/L3)); - //dTLS[i] = Cl_ * (wgt * L1 + (1.0 - wgt) * L3); - dTLS[i] = Cl_ * smoothMax(L1,L3); + // wgt = std::tanh(tanh_half_ * (L1/L3) * (L1/L3)); + // dTLS[i] = Cl_ * (wgt * L1 + (1.0 - wgt) * L3); + dTLS[i] = Cl_ * smoothMax(L1, L3); - //dTLS[i] = std::max(dTLS[i], tls_min_); + // dTLS[i] = std::max(dTLS[i], tls_min_); dTLS[i] = smoothMax(dTLS[i], tls_min_); // dTLS[i] = std::min(dTLS[i], tls_max_); - //wgt = std::tanh(tanh_half_ * dTLS[i] / tls_max_); - //dTLS[i] = (1.0 - wgt) * dTLS[i] + wgt * tls_max_; + // wgt = std::tanh(tanh_half_ * dTLS[i] / tls_max_); + // dTLS[i] = (1.0 - wgt) * dTLS[i] + wgt * tls_max_; dTLS[i] = smoothMin(dTLS[i], tls_max_); } tls_gf_.SetFromTrueDofs(tls_); - tmpR0_.Set(1.0, tls_); tmpR0_ *= tls_; res_gf_.SetFromTrueDofs(tmpR0_); filter_gf_.ProjectGridFunction(res_gf_); - tls2_gf_.ProjectGridFunction(filter_gf_); + tls2_gf_.ProjectGridFunction(filter_gf_); tls2_gf_.GetTrueDofs(tls2_); } @@ -1490,16 +1482,16 @@ void ZetaModel::updateMsRho() { } void ZetaModel::updateProd() { - const double *dGradU = gradU_.HostRead(); - const double *dGradV = gradV_.HostRead(); - const double *dGradW = gradW_.HostRead(); - const double *dGradS = gradS_.HostRead(); - const double *Sij = strain_.HostReadWrite(); - const double *dTKE = tke_.HostRead(); - const double *dmuT = eddyVisc_.HostRead(); - const double *dRho = rho_.HostRead(); - const double *dRad = radius_v_.HostRead(); - double *Pk = prod_.HostReadWrite(); + const double* dGradU = gradU_.HostRead(); + const double* dGradV = gradV_.HostRead(); + const double* dGradW = gradW_.HostRead(); + const double* dGradS = gradS_.HostRead(); + const double* Sij = strain_.HostReadWrite(); + const double* dTKE = tke_.HostRead(); + const double* dmuT = eddyVisc_.HostRead(); + const double* dRho = rho_.HostRead(); + const double* dRad = radius_v_.HostRead(); + double* Pk = prod_.HostReadWrite(); double twoThirds = 2.0 / 3.0; for (int i = 0; i < SdofInt_; i++) { @@ -1529,7 +1521,7 @@ void ZetaModel::updateProd() { tau(2, 2) = 2.0 * Sij[i + 2 * SdofInt_]; tau(0, 1) = 2.0 * Sij[i + 3 * SdofInt_]; tau(0, 2) = 2.0 * Sij[i + 4 * SdofInt_]; - tau(1, 2) = 2.0 * Sij[i + 5 * SdofInt_]; + tau(1, 2) = 2.0 * Sij[i + 5 * SdofInt_]; tau(1, 0) = 2.0 * Sij[i + 3 * SdofInt_]; tau(2, 0) = 2.0 * Sij[i + 4 * SdofInt_]; tau(2, 1) = 2.0 * Sij[i + 5 * SdofInt_]; @@ -1643,8 +1635,8 @@ void ZetaModel::updateZeta() { zeta_next_.Set(1.0, v2_next_); { // const double twoThirds = 2.0 / 3.0; - const double *dk = tke_next_.HostRead(); - double *dz = zeta_next_.HostReadWrite(); + const double* dk = tke_next_.HostRead(); + double* dz = zeta_next_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { dz[i] /= std::max(dk[i], tke_min_); // leave larger so D_v2 can grow @@ -1783,7 +1775,7 @@ void ZetaModel::tkeStep() { } // Prepare for the solve - for (auto &tke_dbc : tke_dbcs_) { + for (auto& tke_dbc : tke_dbcs_) { tke_next_gf_.ProjectBdrCoefficient(*tke_dbc.coeff, tke_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(res_, res_gf_); @@ -1800,7 +1792,7 @@ void ZetaModel::tkeStep() { // hard-clip { - double *dTKE = tke_next_.HostReadWrite(); + double* dTKE = tke_next_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { dTKE[i] = std::max(dTKE[i], 0.0); } @@ -1834,8 +1826,8 @@ void ZetaModel::tdrStep() { ceps1_min = 1.4 * (1.0 + 0.05 * std::sqrt(1.5)); // const double *dk = tke_next_.HostRead(); // const double *dv2 = v2_next_.HostRead(); - const double *dz = zeta_next_.HostRead(); - double *data = tmpR0_.HostReadWrite(); + const double* dz = zeta_next_.HostRead(); + double* data = tmpR0_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { // zeta model // double ceps1 = 1.4 * (1.0 + 0.012 / dz[i]); @@ -1891,7 +1883,7 @@ void ZetaModel::tdrStep() { } // project new tdr bc onto gf which transfers actual ess bc's to solver - for (auto &tdr_dbc : tdr_dbcs_) { + for (auto& tdr_dbc : tdr_dbcs_) { // tdr_next_gf_.ProjectBdrCoefficient(*tdr_dbc.coeff, tdr_dbc.attr); tdr_next_gf_.ProjectBdrCoefficient(*tdr_wall_eval_coeff_, tdr_dbc.attr); } @@ -1908,7 +1900,7 @@ void ZetaModel::tdrStep() { tdr_next_gf_.GetTrueDofs(tdr_next_); // hard-clip - double *dTDR = tdr_next_.HostReadWrite(); + double* dTDR = tdr_next_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { dTDR[i] = std::max(dTDR[i], 0.0); } @@ -1956,7 +1948,7 @@ void ZetaModel::zetaStep() { } // Prepare for the solve - for (auto &zeta_dbc : zeta_dbcs_) { + for (auto& zeta_dbc : zeta_dbcs_) { zeta_next_gf_.ProjectBdrCoefficient(*zeta_dbc.coeff, zeta_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(res_, res_gf_); @@ -1972,7 +1964,7 @@ void ZetaModel::zetaStep() { zeta_next_gf_.GetTrueDofs(zeta_next_); // hard-clip - double *dZ = zeta_next_.HostReadWrite(); + double* dZ = zeta_next_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { dZ[i] = std::max(dZ[i], zeta_min_); dZ[i] = std::min(dZ[i], 2.0 / 3.0); @@ -2000,10 +1992,10 @@ void ZetaModel::v2Step() { res_gf_.ProjectGridFunction(fRate_gf_); res_gf_.GetTrueDofs(tmpR0a_); { - const double *df = tmpR0a_.HostRead(); + const double* df = tmpR0a_.HostRead(); // const double *dtkol = tts_kol_.HostRead(); - const double *dTTS = tts_.HostReadWrite(); - double *data = tmpR0_.HostReadWrite(); + const double* dTTS = tts_.HostReadWrite(); + double* data = tmpR0_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { // data[i] *= std::min(df[i], 12.0/dtkol[i]); // data[i] *= df[i]; @@ -2037,7 +2029,7 @@ void ZetaModel::v2Step() { } // Prepare for the solve - for (auto &v2_dbc : v2_dbcs_) { + for (auto& v2_dbc : v2_dbcs_) { v2_next_gf_.ProjectBdrCoefficient(*v2_dbc.coeff, v2_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(res_, res_gf_); @@ -2055,7 +2047,7 @@ void ZetaModel::v2Step() { // hard-clip { // const double *dtke = tke_next_.HostReadWrite(); - double *dv2 = v2_next_.HostReadWrite(); + double* dv2 = v2_next_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { dv2[i] = std::max(dv2[i], 0.0); // clip when used in certain areas, allow to be above 2/3k for destruction in v2 @@ -2095,8 +2087,8 @@ void ZetaModel::fStep() { tmpR0b_.Set(C2_, prod_); tmpR0b_ /= rho_; { - const double *dk = tke_next_.HostRead(); - double *data = tmpR0b_.HostReadWrite(); + const double* dk = tke_next_.HostRead(); + double* data = tmpR0b_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { data[i] /= std::max(dk[i], tke_min_); } @@ -2105,9 +2097,9 @@ void ZetaModel::fStep() { // v2/k { double twoThirds = 2.0 / 3.0; - const double *dv2 = v2_next_.HostRead(); - const double *dk = tke_next_.HostRead(); - double *data = tmpR0a_.HostReadWrite(); + const double* dv2 = v2_next_.HostRead(); + const double* dk = tke_next_.HostRead(); + double* data = tmpR0a_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { data[i] = std::min(dv2[i], twoThirds * dk[i]); } @@ -2180,10 +2172,10 @@ void ZetaModel::fStep() { // filter f-source res_gf_.SetFromTrueDofs(tmpR0a_); filter_gf_.ProjectGridFunction(res_gf_); - res_gf_.ProjectGridFunction(filter_gf_); + res_gf_.ProjectGridFunction(filter_gf_); res_gf_.GetTrueDofs(tmpR0_); - resf_gf_.ProjectGridFunction(res_gf_); - resf_gf_.GetTrueDofs(ftmpR0_); + resf_gf_.ProjectGridFunction(res_gf_); + resf_gf_.GetTrueDofs(ftmpR0_); Mf_->AddMult(ftmpR0_, resf_, -1.0); resf_gf_.SetFromTrueDofs(resf_); @@ -2203,7 +2195,7 @@ void ZetaModel::fStep() { } // Prepare for the solve - for (auto &fRate_dbc : fRate_dbcs_) { + for (auto& fRate_dbc : fRate_dbcs_) { fRate_gf_.ProjectBdrCoefficient(*fRate_dbc.coeff, fRate_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(resf_, resf_gf_); @@ -2220,14 +2212,13 @@ void ZetaModel::fStep() { // hard-clip { - double *df = fRate_.HostReadWrite(); + double* df = fRate_.HostReadWrite(); for (int i = 0; i < sfes_->GetTrueVSize(); i++) { if (df[i] != df[i]) std::cout << " f is actually NaN!" << endl; - df[i] = std::max(df[i], 0.0); - } + df[i] = std::max(df[i], 0.0); + } } fRate_gf_.SetFromTrueDofs(fRate_); - } /// TODO: pull in tensor gridscale and calc Mnn^T for wall-normal spacing @@ -2272,7 +2263,7 @@ void ZetaModel::computeTDRwall() { } /// Add a Dirichlet boundary condition to scalar fields -void ZetaModel::AddTKEDirichletBC(const double &tke, Array &attr) { +void ZetaModel::AddTKEDirichletBC(const double& tke, Array& attr) { tke_dbcs_.emplace_back(attr, new ConstantCoefficient(tke)); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2282,7 +2273,7 @@ void ZetaModel::AddTKEDirichletBC(const double &tke, Array &attr) { } } -void ZetaModel::AddTKEDirichletBC(Coefficient *coeff, Array &attr) { +void ZetaModel::AddTKEDirichletBC(Coefficient* coeff, Array& attr) { tke_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2292,11 +2283,11 @@ void ZetaModel::AddTKEDirichletBC(Coefficient *coeff, Array &attr) { } } -void ZetaModel::AddTKEDirichletBC(ScalarFuncT *f, Array &attr) { +void ZetaModel::AddTKEDirichletBC(ScalarFuncT* f, Array& attr) { AddTKEDirichletBC(new FunctionCoefficient(f), attr); } -void ZetaModel::AddV2DirichletBC(const double &v2, Array &attr) { +void ZetaModel::AddV2DirichletBC(const double& v2, Array& attr) { v2_dbcs_.emplace_back(attr, new ConstantCoefficient(v2)); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2306,7 +2297,7 @@ void ZetaModel::AddV2DirichletBC(const double &v2, Array &attr) { } } -void ZetaModel::AddV2DirichletBC(Coefficient *coeff, Array &attr) { +void ZetaModel::AddV2DirichletBC(Coefficient* coeff, Array& attr) { v2_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2316,7 +2307,7 @@ void ZetaModel::AddV2DirichletBC(Coefficient *coeff, Array &attr) { } } -void ZetaModel::AddTDRDirichletBC(const double &tdr, Array &attr) { +void ZetaModel::AddTDRDirichletBC(const double& tdr, Array& attr) { tdr_dbcs_.emplace_back(attr, new ConstantCoefficient(tdr)); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2326,7 +2317,7 @@ void ZetaModel::AddTDRDirichletBC(const double &tdr, Array &attr) { } } -void ZetaModel::AddTDRDirichletBC(Coefficient *coeff, Array &attr) { +void ZetaModel::AddTDRDirichletBC(Coefficient* coeff, Array& attr) { tdr_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2336,7 +2327,7 @@ void ZetaModel::AddTDRDirichletBC(Coefficient *coeff, Array &attr) { } } -void ZetaModel::AddZETADirichletBC(const double &zeta, Array &attr) { +void ZetaModel::AddZETADirichletBC(const double& zeta, Array& attr) { zeta_dbcs_.emplace_back(attr, new ConstantCoefficient(zeta)); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2346,7 +2337,7 @@ void ZetaModel::AddZETADirichletBC(const double &zeta, Array &attr) { } } -void ZetaModel::AddZETADirichletBC(Coefficient *coeff, Array &attr) { +void ZetaModel::AddZETADirichletBC(Coefficient* coeff, Array& attr) { zeta_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2356,7 +2347,7 @@ void ZetaModel::AddZETADirichletBC(Coefficient *coeff, Array &attr) { } } -void ZetaModel::AddFRATEDirichletBC(const double &fRate, Array &attr) { +void ZetaModel::AddFRATEDirichletBC(const double& fRate, Array& attr) { fRate_dbcs_.emplace_back(attr, new ConstantCoefficient(fRate)); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2366,7 +2357,7 @@ void ZetaModel::AddFRATEDirichletBC(const double &fRate, Array &attr) { } } -void ZetaModel::AddFRATEDirichletBC(Coefficient *coeff, Array &attr) { +void ZetaModel::AddFRATEDirichletBC(Coefficient* coeff, Array& attr) { fRate_dbcs_.emplace_back(attr, coeff); for (int i = 0; i < attr.Size(); ++i) { if (attr[i] == 1) { @@ -2380,7 +2371,7 @@ void ZetaModel::AddFRATEDirichletBC(Coefficient *coeff, Array &attr) { double smoothMin(double val1, double val2) { double C = 4.0; double val; - val = -1.0/C * std::log(std::exp(-C*val1) + std::exp(-C*val2)); + val = -1.0 / C * std::log(std::exp(-C * val1) + std::exp(-C * val2)); return val; } @@ -2388,6 +2379,6 @@ double smoothMin(double val1, double val2) { double smoothMax(double val1, double val2) { double C = 4.0; double val; - val = 1.0/C * std::log(std::exp(C*val1) + std::exp(C*val2)); + val = 1.0 / C * std::log(std::exp(C * val1) + std::exp(C * val2)); return val; } diff --git a/src/zetaModel.hpp b/src/zetaModel.hpp index 58a371bf..161f0033 100644 --- a/src/zetaModel.hpp +++ b/src/zetaModel.hpp @@ -56,8 +56,8 @@ class Tps; #include "tps_mfem_wrap.hpp" #include "turb_model_base.hpp" -using VecFuncT = void(const Vector &x, double t, Vector &u); -using ScalarFuncT = double(const Vector &x, double t); +using VecFuncT = void(const Vector& x, double t, Vector& u); +using ScalarFuncT = double(const Vector& x, double t); class LoMachSolver; class LoMachOptions; @@ -68,14 +68,14 @@ class ZetaModel : public TurbModelBase { friend class LoMachSolver; private: - TPS::Tps *tpsP_; - LoMachOptions *loMach_opts_ = nullptr; + TPS::Tps* tpsP_; + LoMachOptions* loMach_opts_ = nullptr; // Mesh and discretization scheme info - ParMesh *pmesh_ = nullptr; + ParMesh* pmesh_ = nullptr; int order_; IntegrationRules gll_rules_; - const temporalSchemeCoefficients &time_coeff_; + const temporalSchemeCoefficients& time_coeff_; double dt_; double time_; int nvel_, dim_; @@ -125,38 +125,38 @@ class ZetaModel : public TurbModelBase { // streamwise stabilization bool sw_stab_ = false; /**< Enable/disable supg stabilization. */ - double Reh_factor_, Reh_offset_; /**< supg stabilization parameters */ - + double Reh_factor_, Reh_offset_; /**< supg stabilization parameters */ + // just keep these saved for ease int numWalls_, numInlets_, numOutlets_; // Scalar \f$H^1\f$ finite element collection. - FiniteElementCollection *sfec_ = nullptr; + FiniteElementCollection* sfec_ = nullptr; // Scalar \f$H^1\f$ finite element space. - ParFiniteElementSpace *sfes_ = nullptr; + ParFiniteElementSpace* sfes_ = nullptr; /// Velocity \f$H^1\f$ finite element collection. - FiniteElementCollection *vfec_ = nullptr; + FiniteElementCollection* vfec_ = nullptr; /// Velocity \f$(H^1)^d\f$ finite element space. - ParFiniteElementSpace *vfes_ = nullptr; + ParFiniteElementSpace* vfes_ = nullptr; - FiniteElementCollection *ffec_ = nullptr; - ParFiniteElementSpace *ffes_ = nullptr; + FiniteElementCollection* ffec_ = nullptr; + ParFiniteElementSpace* ffes_ = nullptr; /// velocity - ParGridFunction *vel_gf_ = nullptr; + ParGridFunction* vel_gf_ = nullptr; Vector vel_; /// swirl - ParGridFunction *swirl_gf_ = nullptr; + ParGridFunction* swirl_gf_ = nullptr; Vector swirl_; /// velocity gradients - ParGridFunction *gradU_gf_ = nullptr; - ParGridFunction *gradV_gf_ = nullptr; - ParGridFunction *gradW_gf_ = nullptr; + ParGridFunction* gradU_gf_ = nullptr; + ParGridFunction* gradV_gf_ = nullptr; + ParGridFunction* gradW_gf_ = nullptr; Vector gradU_; Vector gradV_; Vector gradW_; @@ -175,7 +175,7 @@ class ZetaModel : public TurbModelBase { Vector mult_; /// grid information - ParGridFunction *gridScale_gf_ = nullptr; + ParGridFunction* gridScale_gf_ = nullptr; /// eddy viscosity ParGridFunction eddyVisc_gf_; @@ -199,7 +199,7 @@ class ZetaModel : public TurbModelBase { Vector tdr_nm1_, tdr_nm2_; Vector Ntdr_, Ntdr_nm1_, Ntdr_nm2_; ParGridFunction tdr_wall_gf_; - GridFunctionCoefficient *tdr_bc_ = nullptr; + GridFunctionCoefficient* tdr_bc_ = nullptr; /// ratio of wall normal stress component to k ParGridFunction zeta_gf_; @@ -262,7 +262,7 @@ class ZetaModel : public TurbModelBase { ParGridFunction filter_gf_; Vector filter_; - + ParGridFunction vfres_gf_; // ParGridFunction diag_gf_; @@ -276,111 +276,111 @@ class ZetaModel : public TurbModelBase { Vector radius_v_; /// coefficient fields for operators - GridFunctionCoefficient *delta_coeff_ = nullptr; - GradientGridFunctionCoefficient *gradTKE_coeff_ = nullptr; - ScalarVectorProductCoefficient *nu_gradTKE_coeff_ = nullptr; - GridFunctionCoefficient *mu_coeff_ = nullptr; - RatioCoefficient *nu_coeff_ = nullptr; - RatioCoefficient *nu_delta_coeff_ = nullptr; - ProductCoefficient *two_nu_delta_coeff_ = nullptr; - ProductCoefficient *two_nuNeg_delta_coeff_ = nullptr; - GradientGridFunctionCoefficient *gradZeta_coeff_ = nullptr; + GridFunctionCoefficient* delta_coeff_ = nullptr; + GradientGridFunctionCoefficient* gradTKE_coeff_ = nullptr; + ScalarVectorProductCoefficient* nu_gradTKE_coeff_ = nullptr; + GridFunctionCoefficient* mu_coeff_ = nullptr; + RatioCoefficient* nu_coeff_ = nullptr; + RatioCoefficient* nu_delta_coeff_ = nullptr; + ProductCoefficient* two_nu_delta_coeff_ = nullptr; + ProductCoefficient* two_nuNeg_delta_coeff_ = nullptr; + GradientGridFunctionCoefficient* gradZeta_coeff_ = nullptr; // ScalarVectorProductCoefficient *tdr_wall_coeff_ = nullptr; // DivergenceGridFunctionCoefficient *tdr_wall_coeff_ = nullptr; - GridFunctionCoefficient *tdr_wall_coeff_ = nullptr; - ScalarVectorProductCoefficient *fRate_wall_coeff_ = nullptr; - ScalarVectorProductCoefficient *wall_coeff_ = nullptr; - GridFunctionCoefficient *tdr_wall_eval_coeff_ = nullptr; - - GridFunctionCoefficient *swirl_coeff_ = nullptr; - ProductCoefficient *rad_rho_coeff_ = nullptr; - ScalarVectorProductCoefficient *rad_rhou_coeff_ = nullptr; - ProductCoefficient *rad_tke_diag_coeff_ = nullptr; - ProductCoefficient *rad_tke_diff_total_coeff_ = nullptr; - ProductCoefficient *rad_tdr_diag_coeff_ = nullptr; - ProductCoefficient *rad_tdr_diff_total_coeff_ = nullptr; - ProductCoefficient *rad_v2_diag_coeff_ = nullptr; - ProductCoefficient *rad_f_diag_coeff_ = nullptr; - ProductCoefficient *rad_unity_coeff_ = nullptr; - ProductCoefficient *rad_zeta_diag_coeff_ = nullptr; - ProductCoefficient *rad_zeta_diff_total_coeff_ = nullptr; - ProductCoefficient *rad_scalar_diff_coeff_ = nullptr; - ScalarVectorProductCoefficient *rad_nu_gradTKE_coeff_ = nullptr; - - GridFunctionCoefficient *tts_coeff_ = nullptr; - GridFunctionCoefficient *tls2_coeff_ = nullptr; - GridFunctionCoefficient *prod_coeff_ = nullptr; - GridFunctionCoefficient *tke_coeff_ = nullptr; - GridFunctionCoefficient *tdr_coeff_ = nullptr; - GridFunctionCoefficient *rho_coeff_ = nullptr; - VectorGridFunctionCoefficient *vel_coeff_ = nullptr; - ScalarVectorProductCoefficient *rhou_coeff_ = nullptr; - GridFunctionCoefficient *scalar_diff_coeff_ = nullptr; - GridFunctionCoefficient *mut_coeff_ = nullptr; - GridFunctionCoefficient *mult_coeff_ = nullptr; - SumCoefficient *tke_diff_sum_coeff_ = nullptr; - SumCoefficient *tdr_diff_sum_coeff_ = nullptr; - SumCoefficient *zeta_diff_sum_coeff_ = nullptr; - ProductCoefficient *tke_diff_total_coeff_ = nullptr; - ProductCoefficient *tdr_diff_total_coeff_ = nullptr; - ProductCoefficient *zeta_diff_total_coeff_ = nullptr; - ConstantCoefficient *unity_diff_coeff_ = nullptr; + GridFunctionCoefficient* tdr_wall_coeff_ = nullptr; + ScalarVectorProductCoefficient* fRate_wall_coeff_ = nullptr; + ScalarVectorProductCoefficient* wall_coeff_ = nullptr; + GridFunctionCoefficient* tdr_wall_eval_coeff_ = nullptr; + + GridFunctionCoefficient* swirl_coeff_ = nullptr; + ProductCoefficient* rad_rho_coeff_ = nullptr; + ScalarVectorProductCoefficient* rad_rhou_coeff_ = nullptr; + ProductCoefficient* rad_tke_diag_coeff_ = nullptr; + ProductCoefficient* rad_tke_diff_total_coeff_ = nullptr; + ProductCoefficient* rad_tdr_diag_coeff_ = nullptr; + ProductCoefficient* rad_tdr_diff_total_coeff_ = nullptr; + ProductCoefficient* rad_v2_diag_coeff_ = nullptr; + ProductCoefficient* rad_f_diag_coeff_ = nullptr; + ProductCoefficient* rad_unity_coeff_ = nullptr; + ProductCoefficient* rad_zeta_diag_coeff_ = nullptr; + ProductCoefficient* rad_zeta_diff_total_coeff_ = nullptr; + ProductCoefficient* rad_scalar_diff_coeff_ = nullptr; + ScalarVectorProductCoefficient* rad_nu_gradTKE_coeff_ = nullptr; + + GridFunctionCoefficient* tts_coeff_ = nullptr; + GridFunctionCoefficient* tls2_coeff_ = nullptr; + GridFunctionCoefficient* prod_coeff_ = nullptr; + GridFunctionCoefficient* tke_coeff_ = nullptr; + GridFunctionCoefficient* tdr_coeff_ = nullptr; + GridFunctionCoefficient* rho_coeff_ = nullptr; + VectorGridFunctionCoefficient* vel_coeff_ = nullptr; + ScalarVectorProductCoefficient* rhou_coeff_ = nullptr; + GridFunctionCoefficient* scalar_diff_coeff_ = nullptr; + GridFunctionCoefficient* mut_coeff_ = nullptr; + GridFunctionCoefficient* mult_coeff_ = nullptr; + SumCoefficient* tke_diff_sum_coeff_ = nullptr; + SumCoefficient* tdr_diff_sum_coeff_ = nullptr; + SumCoefficient* zeta_diff_sum_coeff_ = nullptr; + ProductCoefficient* tke_diff_total_coeff_ = nullptr; + ProductCoefficient* tdr_diff_total_coeff_ = nullptr; + ProductCoefficient* zeta_diff_total_coeff_ = nullptr; + ConstantCoefficient* unity_diff_coeff_ = nullptr; // ProductCoefficient *unity_diff_total_coeff_ = nullptr; - ConstantCoefficient *unity_coeff_ = nullptr; - ConstantCoefficient *zero_coeff_ = nullptr; - ConstantCoefficient *posTwo_coeff_ = nullptr; - ConstantCoefficient *negTwo_coeff_ = nullptr; - - GridFunctionCoefficient *rhoDt_coeff_ = nullptr; - RatioCoefficient *rhoTTS_coeff_ = nullptr; - ConstantCoefficient *Ce2_coeff_ = nullptr; - ProductCoefficient *Ce2rhoTTS_coeff_ = nullptr; - RatioCoefficient *Pk_coeff_ = nullptr; - RatioCoefficient *ek_coeff_ = nullptr; - ProductCoefficient *ek_rho_coeff_ = nullptr; - SumCoefficient *tke_diag_coeff_ = nullptr; - SumCoefficient *tdr_diag_coeff_ = nullptr; - SumCoefficient *zeta_diag_coeff_ = nullptr; - SumCoefficient *v2_diag_coeff_ = nullptr; - RatioCoefficient *f_diag_coeff_ = nullptr; - SumCoefficient *f_diag_total_coeff_ = nullptr; - - ProductCoefficient *diff_total_coeff_ = nullptr; - SumCoefficient *diag_coeff_ = nullptr; - - GridFunctionCoefficient *tke_field_ = nullptr; - GridFunctionCoefficient *v2_field_ = nullptr; + ConstantCoefficient* unity_coeff_ = nullptr; + ConstantCoefficient* zero_coeff_ = nullptr; + ConstantCoefficient* posTwo_coeff_ = nullptr; + ConstantCoefficient* negTwo_coeff_ = nullptr; + + GridFunctionCoefficient* rhoDt_coeff_ = nullptr; + RatioCoefficient* rhoTTS_coeff_ = nullptr; + ConstantCoefficient* Ce2_coeff_ = nullptr; + ProductCoefficient* Ce2rhoTTS_coeff_ = nullptr; + RatioCoefficient* Pk_coeff_ = nullptr; + RatioCoefficient* ek_coeff_ = nullptr; + ProductCoefficient* ek_rho_coeff_ = nullptr; + SumCoefficient* tke_diag_coeff_ = nullptr; + SumCoefficient* tdr_diag_coeff_ = nullptr; + SumCoefficient* zeta_diag_coeff_ = nullptr; + SumCoefficient* v2_diag_coeff_ = nullptr; + RatioCoefficient* f_diag_coeff_ = nullptr; + SumCoefficient* f_diag_total_coeff_ = nullptr; + + ProductCoefficient* diff_total_coeff_ = nullptr; + SumCoefficient* diag_coeff_ = nullptr; + + GridFunctionCoefficient* tke_field_ = nullptr; + GridFunctionCoefficient* v2_field_ = nullptr; // streamwise stabilization - VectorMagnitudeCoefficient *umag_coeff_ = nullptr; - GridFunctionCoefficient *gscale_coeff_ = nullptr; - ProductCoefficient *gscale2_coeff_ = nullptr; - GridFunctionCoefficient *visc_coeff_ = nullptr; - PowerCoefficient *visc_inv_coeff_ = nullptr; - ProductCoefficient *reh1_coeff_ = nullptr; - ProductCoefficient *reh2_coeff_ = nullptr; - ProductCoefficient *Reh_coeff_ = nullptr; - ExtTransformedCoefficient *csupg_coeff_ = nullptr; - ProductCoefficient *uw1_coeff_ = nullptr; - ProductCoefficient *uw2_coeff_ = nullptr; - ProductCoefficient *upwind_coeff_ = nullptr; - TransformedMatrixVectorCoefficient *swdiff_coeff_ = nullptr; - ScalarMatrixProductCoefficient *supg_coeff_ = nullptr; - + VectorMagnitudeCoefficient* umag_coeff_ = nullptr; + GridFunctionCoefficient* gscale_coeff_ = nullptr; + ProductCoefficient* gscale2_coeff_ = nullptr; + GridFunctionCoefficient* visc_coeff_ = nullptr; + PowerCoefficient* visc_inv_coeff_ = nullptr; + ProductCoefficient* reh1_coeff_ = nullptr; + ProductCoefficient* reh2_coeff_ = nullptr; + ProductCoefficient* Reh_coeff_ = nullptr; + ExtTransformedCoefficient* csupg_coeff_ = nullptr; + ProductCoefficient* uw1_coeff_ = nullptr; + ProductCoefficient* uw2_coeff_ = nullptr; + ProductCoefficient* upwind_coeff_ = nullptr; + TransformedMatrixVectorCoefficient* swdiff_coeff_ = nullptr; + ScalarMatrixProductCoefficient* supg_coeff_ = nullptr; + /// operators and solvers - ParBilinearForm *As_form_ = nullptr; - ParBilinearForm *Ms_form_ = nullptr; - ParBilinearForm *MsRho_form_ = nullptr; - ParBilinearForm *Mf_form_ = nullptr; - ParBilinearForm *Hk_form_ = nullptr; - ParBilinearForm *He_form_ = nullptr; - ParBilinearForm *Hv_form_ = nullptr; - ParBilinearForm *Hf_form_ = nullptr; - ParBilinearForm *Hz_form_ = nullptr; - ParBilinearForm *Lk_form_ = nullptr; - ParBilinearForm *Lf_form_ = nullptr; - ParLinearForm *Lk_bdry_ = nullptr; - ParLinearForm *He_bdry_ = nullptr; + ParBilinearForm* As_form_ = nullptr; + ParBilinearForm* Ms_form_ = nullptr; + ParBilinearForm* MsRho_form_ = nullptr; + ParBilinearForm* Mf_form_ = nullptr; + ParBilinearForm* Hk_form_ = nullptr; + ParBilinearForm* He_form_ = nullptr; + ParBilinearForm* Hv_form_ = nullptr; + ParBilinearForm* Hf_form_ = nullptr; + ParBilinearForm* Hz_form_ = nullptr; + ParBilinearForm* Lk_form_ = nullptr; + ParBilinearForm* Lf_form_ = nullptr; + ParLinearForm* Lk_bdry_ = nullptr; + ParLinearForm* He_bdry_ = nullptr; OperatorHandle As_; OperatorHandle Ms_; @@ -394,21 +394,21 @@ class ZetaModel : public TurbModelBase { OperatorHandle Lk_; OperatorHandle Lf_; - mfem::Solver *MsInvPC_ = nullptr; - mfem::CGSolver *MsInv_ = nullptr; - mfem::Solver *MsRhoInvPC_ = nullptr; - mfem::CGSolver *MsRhoInv_ = nullptr; - mfem::Solver *HkInvPC_ = nullptr; - mfem::Solver *HeInvPC_ = nullptr; - mfem::Solver *HvInvPC_ = nullptr; - mfem::Solver *HfInvPC_ = nullptr; - mfem::Solver *HzInvPC_ = nullptr; - mfem::CGSolver *HkInv_ = nullptr; - mfem::CGSolver *HeInv_ = nullptr; - mfem::CGSolver *HvInv_ = nullptr; - mfem::CGSolver *HfInv_ = nullptr; + mfem::Solver* MsInvPC_ = nullptr; + mfem::CGSolver* MsInv_ = nullptr; + mfem::Solver* MsRhoInvPC_ = nullptr; + mfem::CGSolver* MsRhoInv_ = nullptr; + mfem::Solver* HkInvPC_ = nullptr; + mfem::Solver* HeInvPC_ = nullptr; + mfem::Solver* HvInvPC_ = nullptr; + mfem::Solver* HfInvPC_ = nullptr; + mfem::Solver* HzInvPC_ = nullptr; + mfem::CGSolver* HkInv_ = nullptr; + mfem::CGSolver* HeInv_ = nullptr; + mfem::CGSolver* HvInv_ = nullptr; + mfem::CGSolver* HfInv_ = nullptr; // mfem::GMRESSolver *HfInv_ = nullptr; - mfem::CGSolver *HzInv_ = nullptr; + mfem::CGSolver* HzInv_ = nullptr; // Boundary condition info Array tke_ess_attr_; @@ -421,8 +421,8 @@ class ZetaModel : public TurbModelBase { Array zeta_ess_tdof_; Array v2_ess_tdof_; Array fRate_ess_tdof_; - Array *ess_attr_ = nullptr; - Array *ess_tdof_ = nullptr; + Array* ess_attr_ = nullptr; + Array* ess_tdof_ = nullptr; std::vector> tke_dbcs_; std::vector> tdr_dbcs_; @@ -431,8 +431,8 @@ class ZetaModel : public TurbModelBase { std::vector> fRate_dbcs_; public: - ZetaModel(mfem::ParMesh *pmesh, LoMachOptions *loMach_opts, temporalSchemeCoefficients &time_coeff, TPS::Tps *tps, - ParGridFunction *gridScale); + ZetaModel(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalSchemeCoefficients& time_coeff, TPS::Tps* tps, + ParGridFunction* gridScale); virtual ~ZetaModel(); // Functions overriden from base class @@ -441,8 +441,8 @@ class ZetaModel : public TurbModelBase { void updateBC(int current_step); void step() final; void setup() final; - void initializeIO(IODataOrganizer &io) final; - void initializeViz(ParaViewDataCollection &pvdc) final; + void initializeIO(IODataOrganizer& io) final; + void initializeViz(ParaViewDataCollection& pvdc) final; void tkeStep(); void tdrStep(); void zetaStep(); @@ -462,27 +462,27 @@ class ZetaModel : public TurbModelBase { void computeTDRwall(); /// Return a pointer to the current temperature ParGridFunction. - ParGridFunction *getCurrentEddyViscosity() { return &eddyVisc_gf_; } + ParGridFunction* getCurrentEddyViscosity() { return &eddyVisc_gf_; } /// Add a Dirichlet boundary condition to the temperature and Qt field. - void AddTKEDirichletBC(const double &tke, Array &attr); - void AddTKEDirichletBC(Coefficient *coeff, Array &attr); - void AddTKEDirichletBC(ScalarFuncT *f, Array &attr); + void AddTKEDirichletBC(const double& tke, Array& attr); + void AddTKEDirichletBC(Coefficient* coeff, Array& attr); + void AddTKEDirichletBC(ScalarFuncT* f, Array& attr); - void AddV2DirichletBC(const double &tke, Array &attr); - void AddV2DirichletBC(Coefficient *coeff, Array &attr); - void AddV2DirichletBC(ScalarFuncT *f, Array &attr); + void AddV2DirichletBC(const double& tke, Array& attr); + void AddV2DirichletBC(Coefficient* coeff, Array& attr); + void AddV2DirichletBC(ScalarFuncT* f, Array& attr); - void AddTDRDirichletBC(const double &tdr, Array &attr); - void AddTDRDirichletBC(Coefficient *coeff, Array &attr); - void AddTDRDirichletBC(ScalarFuncT *f, Array &attr); + void AddTDRDirichletBC(const double& tdr, Array& attr); + void AddTDRDirichletBC(Coefficient* coeff, Array& attr); + void AddTDRDirichletBC(ScalarFuncT* f, Array& attr); - void AddZETADirichletBC(const double &zeta, Array &attr); - void AddZETADirichletBC(Coefficient *coeff, Array &attr); - void AddZETADirichletBC(ScalarFuncT *f, Array &attr); + void AddZETADirichletBC(const double& zeta, Array& attr); + void AddZETADirichletBC(Coefficient* coeff, Array& attr); + void AddZETADirichletBC(ScalarFuncT* f, Array& attr); - void AddFRATEDirichletBC(const double &fRate, Array &attr); - void AddFRATEDirichletBC(Coefficient *coeff, Array &attr); - void AddFRATEDirichletBC(ScalarFuncT *f, Array &attr); + void AddFRATEDirichletBC(const double& fRate, Array& attr); + void AddFRATEDirichletBC(Coefficient* coeff, Array& attr); + void AddFRATEDirichletBC(ScalarFuncT* f, Array& attr); }; #endif // ZETAMODEL_HPP_ From 7ef10b005b8ee9a309479aafbab926e0766e4aa8 Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Sun, 21 Jun 2026 13:00:05 -0700 Subject: [PATCH 06/12] style --- src/quasimagnetostatic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quasimagnetostatic.cpp b/src/quasimagnetostatic.cpp index ecfb45ce..01516c61 100644 --- a/src/quasimagnetostatic.cpp +++ b/src/quasimagnetostatic.cpp @@ -705,12 +705,12 @@ double QuasiMagnetostaticSolver3D::elementJouleHeating(const FiniteElement& el, // need to modify here so that joule heating is only IN torch // this is a problem-specific hack (HACK) double rCyl = 0.028; - double x, y, z, dist; + double x, z, dist; double wgt = 1.0; Vector coords(Tr.GetSpaceDim()); Tr.Transform(ip, coords); x = coords[0]; - y = coords[1]; + // unused, but if we need it later... y = coords[1]; dist = x * x; if (dim_ == Tr.GetSpaceDim()) { z = coords[2]; From eb37a4e64a82a259182a72df434e51dad65ccd4d Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Sun, 21 Jun 2026 13:25:51 -0700 Subject: [PATCH 07/12] style --- src/zetaModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zetaModel.cpp b/src/zetaModel.cpp index 73578aa0..c980ddea 100644 --- a/src/zetaModel.cpp +++ b/src/zetaModel.cpp @@ -1430,7 +1430,7 @@ void ZetaModel::updateTLS() { const double* dRho = rho_.HostRead(); double* dTLS = tls_.HostReadWrite(); - double wgt = 1.0; + // double wgt = 1.0; // double Clength; // Clength = 1.0 / (std::sqrt(6.0) * Cmu_); for (int i = 0; i < SdofInt_; i++) { From d6fb13b572ba75ea9028a6cf16f57951f29292da Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Sun, 21 Jun 2026 13:33:49 -0700 Subject: [PATCH 08/12] style --- src/reactingFlow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/reactingFlow.cpp b/src/reactingFlow.cpp index 7085533a..a7d7b329 100644 --- a/src/reactingFlow.cpp +++ b/src/reactingFlow.cpp @@ -2407,7 +2407,7 @@ void ReactingFlow::temperatureStep() { { double* djh = jh_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { - double x, y, z, dist; + double x, z, dist; double wgt; x = coordsDof(0 * sDofInt_ + i); // y = coordsDof(1 * sDofInt_ + i); @@ -3557,7 +3557,7 @@ void ReactingFlow::computeQtTO() { { double* djh = jh_.HostReadWrite(); for (int i = 0; i < sDofInt_; i++) { - double x, y, z, dist; + double x, z, dist; double wgt; x = coordsDof(0 * sDofInt_ + i); // y = coordsDof(1 * sDofInt_ + i); From f20d741fea0109b961e3c93d9b505e78c8c471b3 Mon Sep 17 00:00:00 2001 From: Garo Levon Bedonian Date: Tue, 23 Jun 2026 01:18:41 -0700 Subject: [PATCH 09/12] adjusted turbulent pipe test for zetaModel changes --- src/zetaModel.cpp | 4 ++++ test/inputs/lomach.pipe.zf.ini | 10 ++++++---- .../REF0_restart_output-pipe-zeta-f.sol.h5 | Bin 165656 -> 165656 bytes .../REFSOL_restart_output-pipe-zeta-f.sol.h5 | Bin 165656 -> 165656 bytes 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/zetaModel.cpp b/src/zetaModel.cpp index c980ddea..ff4a20ad 100644 --- a/src/zetaModel.cpp +++ b/src/zetaModel.cpp @@ -2372,6 +2372,9 @@ double smoothMin(double val1, double val2) { double C = 4.0; double val; val = -1.0 / C * std::log(std::exp(-C * val1) + std::exp(-C * val2)); + // if (val > 1e10) { + // std::cout << "min " << val1 << " " << std::exp(val1) << " " << val2 << " " << std::exp(val2) << " " << val << std::endl; + // } return val; } @@ -2380,5 +2383,6 @@ double smoothMax(double val1, double val2) { double C = 4.0; double val; val = 1.0 / C * std::log(std::exp(C * val1) + std::exp(C * val2)); + // std::cout << "max " << val1 << " " << val2 << " " << val << std::endl; return val; } diff --git a/test/inputs/lomach.pipe.zf.ini b/test/inputs/lomach.pipe.zf.ini index bb5c3ec7..6815f469 100644 --- a/test/inputs/lomach.pipe.zf.ini +++ b/test/inputs/lomach.pipe.zf.ini @@ -8,6 +8,7 @@ ref_levels = 0 order = 1 #order = 3 maxIters = 20200 +#maxIters = 20000 #outputFreq = 1000 outputFreq = 200 timingFreq = 10 @@ -23,12 +24,12 @@ turb-model = zeta-f tke-min = 1.0e-7 tdr-min = 1.0e-9 v2-min = 1.0e-7 -#tts-max = 1.0e2 -tts-max = 1.0e4 +#tts-max = 1.0e4 +tts-max = 1.0e2 tls-max = 1.0e2 #tls-max = 1.0e0 -#tls-min = 1.0e-4 -#tts-min = 1.0e-4 +tls-min = 1.0e-4 +tts-min = 1.0e-4 #mut-min = 1.0e-7 destruction = 1.0 zeta-f-file = inlet_turb_k_v2_2.csv @@ -58,6 +59,7 @@ streamwise-stabilization = false [io] outdirBase = output-pipe-zeta-f enableRestart = True +#enableRestart = False #restartMode = singleFileRead restartMode = variableP diff --git a/test/ref_solns/pipe.zeta-f/REF0_restart_output-pipe-zeta-f.sol.h5 b/test/ref_solns/pipe.zeta-f/REF0_restart_output-pipe-zeta-f.sol.h5 index 5c5b01e368986d894850ad790853abe025df21d7..2ec6e5620e6210819530824fe21073b542760491 100644 GIT binary patch literal 165656 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 S^`AI4Ld^28tUt-MCjJKlQALRW literal 165656 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±XHJkHUkniPo;rSX@Y6ds(oJ=u|)R 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

=|MVhp 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 H8HN7`WKmqq diff --git a/test/ref_solns/pipe.zeta-f/REFSOL_restart_output-pipe-zeta-f.sol.h5 b/test/ref_solns/pipe.zeta-f/REFSOL_restart_output-pipe-zeta-f.sol.h5 index 8ca460f36d4a201307836ba50656272a1a919c52..b6a1043b32d99668ac9b5b094aa3c70b5d749c7e 100644 GIT binary patch literal 165656 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 #jsc%{GTwN&KkZcJG_6 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Ν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

qhiv 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 LXkYI;Sw;U33sOV{ From e017d245a98267a746f6c71dc75d5af0a8081dc8 Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Fri, 26 Jun 2026 13:19:41 -0700 Subject: [PATCH 10/12] version seems to work with higher-order v2f and give decent results. smoothing function turned out to be wonky in very small limits. starting to implement robust f-solver --- src/gaussianInterpExtData.cpp | 27 ++- src/loMach.cpp | 10 +- src/lte_thermo_chem.cpp | 76 ++++++- src/lte_thermo_chem.hpp | 15 ++ src/reactingFlow.cpp | 4 +- src/zetaModel.cpp | 381 +++++++++++++++++++++++++--------- src/zetaModel.hpp | 14 +- 7 files changed, 411 insertions(+), 116 deletions(-) diff --git a/src/gaussianInterpExtData.cpp b/src/gaussianInterpExtData.cpp index f0d91fcf..56748361 100644 --- a/src/gaussianInterpExtData.cpp +++ b/src/gaussianInterpExtData.cpp @@ -977,7 +977,7 @@ void GaussianInterpExtData::setInletTurbScalars() { double buffer = std::stod(substr); entry++; - // using the current format, SHOULD CHANGE + // using the current format if (entry == 1) { tke_pr[nLines].x = buffer; } else if (entry == 2) { @@ -1039,10 +1039,14 @@ void GaussianInterpExtData::setInletTurbScalars() { if (tke_pr[j].tke < 0.0 && tke_pr[j].v2 < 0.0) { continue; } - - dist = sqrt((xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x) + (xp[1] - tke_pr[j].y) * (xp[1] - tke_pr[j].y) + - (xp[2] - tke_pr[j].z) * (xp[2] - tke_pr[j].z)); + + dist = (xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x) + (xp[1] - tke_pr[j].y) * (xp[1] - tke_pr[j].y); + if (dim_ == 3) { + dist += (xp[2] - tke_pr[j].z) * (xp[2] - tke_pr[j].z); + } + dist = std::sqrt(dist); distMin = std::min(distMin, dist); + } // find second closest data pt @@ -1053,11 +1057,15 @@ void GaussianInterpExtData::setInletTurbScalars() { continue; } - dist = sqrt((xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x) + (xp[1] - tke_pr[j].y) * (xp[1] - tke_pr[j].y) + - (xp[2] - tke_pr[j].z) * (xp[2] - tke_pr[j].z)); + dist = (xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x) + (xp[1] - tke_pr[j].y) * (xp[1] - tke_pr[j].y); + if (dim_ == 3) { + dist += (xp[2] - tke_pr[j].z) * (xp[2] - tke_pr[j].z); + } + dist = std::sqrt(dist); if (dist > distMin) { distMinSecond = std::min(distMinSecond, dist); } + } // radius for Gaussian interpolation @@ -1069,9 +1077,10 @@ void GaussianInterpExtData::setInletTurbScalars() { continue; } - dist = sqrt((xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x) + (xp[1] - tke_pr[j].y) * (xp[1] - tke_pr[j].y) + - (xp[2] - tke_pr[j].z) * (xp[2] - tke_pr[j].z)); - + // dist = sqrt((xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x) + (xp[1] - tke_pr[j].y) * (xp[1] - tke_pr[j].y) + + // (xp[2] - tke_pr[j].z) * (xp[2] - tke_pr[j].z)); + dist = sqrt((xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x)); + // gaussian interpolation if (dist <= 1.5 * radius) { wt = exp(-(dist * dist) / (radius * radius)); diff --git a/src/loMach.cpp b/src/loMach.cpp index a782a2b9..cfb76ae1 100644 --- a/src/loMach.cpp +++ b/src/loMach.cpp @@ -417,21 +417,25 @@ void LoMachSolver::solveStep() { if (loMach_opts_.ts_opts_.integrator_type_ == LoMachTemporalOptions::CURL_CURL) { SetTimeIntegrationCoefficients(iter - iter_start_); extData_->step(); + // if (rank0_ == true) std::cout << "external data complete" << endl; sw_thermChem_.Start(); thermo_->step(); - sw_thermChem_.Stop(); + // if (rank0_ == true) std::cout << "thermoChem complete" << endl; + sw_flow_.Start(); if (!disable_flow_) { flow_->step(); } - sw_flow_.Stop(); + // if (rank0_ == true) std::cout << "flow complete" << endl; + sw_turb_.Start(); turbModel_->step(); - sw_turb_.Stop(); + // if (rank0_ == true) std::cout << "turbulence model complete" << endl; + } else { if (rank0_) std::cout << "Time integration not updated." << endl; exit(1); diff --git a/src/lte_thermo_chem.cpp b/src/lte_thermo_chem.cpp index bde5a725..8d1522c8 100644 --- a/src/lte_thermo_chem.cpp +++ b/src/lte_thermo_chem.cpp @@ -81,6 +81,8 @@ LteThermoChem::LteThermoChem(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, t tps->getInput("loMach/axisymmetric", axisym_, false); + dim_ = pmesh->Dimension(); + // Initialize thermo TableInput (data read below) std::vector thermo_tables(5); for (size_t i = 0; i < thermo_tables.size(); i++) { @@ -171,6 +173,9 @@ LteThermoChem::LteThermoChem(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, t tps->getInput("loMach/ltethermo/turb-Prandtl", Prt_, 0.9); invPrt_ = 1.0 / Prt_; + tps->getInput("loMach/ltethermo/Prandtl", Pr_, 0.5); + invPr_ = 1.0 / Pr_; + tps->getInput("loMach/ltethermo/clip-temperature", Tclip_, false); tps->getInput("loMach/ltethermo/min-temperature", Tmin_, 0.0); tps->getInput("loMach/ltethermo/max-temperature", Tmax_, 100000.0); @@ -206,7 +211,7 @@ LteThermoChem::~LteThermoChem() { delete rad_rho_Cp_coeff_; delete rad_rho_coeff_; - delete sfes_filter_; + delete sfes_filter_; delete sfec_filter_; delete HtInv_; delete HtInvPC_; @@ -249,6 +254,8 @@ LteThermoChem::~LteThermoChem() { // allocated in initializeSelf delete sfes_; delete sfec_; + delete vfes_; + delete vfec_; } void LteThermoChem::initializeSelf() { @@ -260,6 +267,11 @@ void LteThermoChem::initializeSelf() { sfec_ = new H1_FECollection(order_); sfes_ = new ParFiniteElementSpace(pmesh_, sfec_); + vfec_ = new H1_FECollection(order_, dim_); + vfes_ = new ParFiniteElementSpace(pmesh_, vfec_, dim_); + + sDofInt_ = sfes_->GetTrueVSize(); + // Check if fully periodic mesh if (!(pmesh_->bdr_attributes.Size() == 0)) { temp_ess_attr_.SetSize(pmesh_->bdr_attributes.Max()); @@ -599,7 +611,7 @@ void LteThermoChem::initializeOperators() { mut_coeff_ = new GridFunctionCoefficient(turbModel_interface_->eddy_viscosity); kapt_coeff_ = new ProductCoefficient(*Cp_coeff_, *mut_coeff_); - thermal_diff_sum_coeff_ = new SumCoefficient(*kapt_coeff_, *thermal_diff_coeff_, invPrt_, 1.0); + thermal_diff_sum_coeff_ = new SumCoefficient(*kapt_coeff_, *thermal_diff_coeff_, invPrt_, invPr_); mult_coeff_ = new GridFunctionCoefficient(sponge_interface_->diff_multiplier); thermal_diff_total_coeff_ = new ProductCoefficient(*mult_coeff_, *thermal_diff_sum_coeff_); @@ -1141,6 +1153,31 @@ void LteThermoChem::step() { jh_form_->Update(); jh_form_->Assemble(); jh_form_->ParallelAssemble(jh_); + + // this bit is to prevent joule heating bleed -> make more elegant and then move to separate routine + ParGridFunction coordsDof(vfes_); + pmesh_->GetNodes(coordsDof); + double rCyl = 0.029; + { + double* djh = jh_.HostReadWrite(); + for (int i = 0; i < sDofInt_; i++) { + double x, z, dist; + double wgt; + x = coordsDof(0 * sDofInt_ + i); + // y = coordsDof(1 * sDofInt_ + i); + dist = x * x; + if (dim_ == 3) { + z = coordsDof(2 * sDofInt_ + i); + // z = z - spark_center_[2]; + dist += z * z; + } + dist = std::sqrt(dist); + wgt = 1.0; + if (dist > rCyl) wgt = 0.0; + djh[i] *= wgt; + } + } + resT_ += jh_; // Update Helmholtz operator to account for changing dt, rho, and kappa @@ -1174,10 +1211,18 @@ void LteThermoChem::step() { // solve helmholtz eq for temp HtInv_->Mult(Bt2, Xt2); - assert(HtInv_->GetConverged()); Ht_form_->RecoverFEMSolution(Xt2, resT_gf_, Tn_next_gf_); Tn_next_gf_.GetTrueDofs(Tn_next_); + + // assert(HtInv_->GetConverged()); + if (!(HtInv_->GetConverged())) { + if (rank0_) { + mfem::out << "Warning, temperature not converging!"; + } + Tn_next_.Set(1.0,Tn_); + Tn_next_gf_.SetFromTrueDofs(Tn_next_); + } // explicit filter if (filter_temperature_) { @@ -1458,6 +1503,31 @@ void LteThermoChem::computeQt() { jh_form_->Update(); jh_form_->Assemble(); jh_form_->ParallelAssemble(jh_); + + // this bit is to prevent joule heating bleed -> make more elegant and then move to separate routine + ParGridFunction coordsDof(vfes_); + pmesh_->GetNodes(coordsDof); + double rCyl = 0.029; + { + double* djh = jh_.HostReadWrite(); + for (int i = 0; i < sDofInt_; i++) { + double x, z, dist; + double wgt; + x = coordsDof(0 * sDofInt_ + i); + // y = coordsDof(1 * sDofInt_ + i); + dist = x * x; + if (dim_ == 3) { + z = coordsDof(2 * sDofInt_ + i); + // z = z - spark_center_[2]; + dist += z * z; + } + dist = std::sqrt(dist); + wgt = 1.0; + if (dist > rCyl) wgt = 0.0; + djh[i] *= wgt; + } + } + tmpR0_ -= jh_; sfes_->GetRestrictionMatrix()->MultTranspose(tmpR0_, resT_gf_); diff --git a/src/lte_thermo_chem.hpp b/src/lte_thermo_chem.hpp index e5cfc1ce..1573af0c 100644 --- a/src/lte_thermo_chem.hpp +++ b/src/lte_thermo_chem.hpp @@ -101,6 +101,15 @@ class LteThermoChem final : public ThermoChemModelBase { int max_iter_; /**< Maximum number of linear solver iterations */ double rtol_ = 1e-12; /**< Linear solver relative tolerance */ + int dim_; + int sDofInt_; + + // flow spark + bool spark_ = false; + double spark_radius_; + double spark_peak_; + Vector spark_center_; + // Boundary condition info Array temp_ess_attr_; /**< List of patches with Dirichlet BC on temperature */ Array Qt_ess_attr_; /**< List of patches with Dirichlet BC on Q (thermal divergence) */ @@ -129,6 +138,9 @@ class LteThermoChem final : public ThermoChemModelBase { double Prt_; double invPrt_; + double Pr_; + double invPr_; + bool Tclip_ = false; double Tmin_ = 0.0; double Tmax_ = 100000.0; @@ -141,6 +153,9 @@ class LteThermoChem final : public ThermoChemModelBase { // Scalar \f$H^1\f$ finite element space. ParFiniteElementSpace* sfes_ = nullptr; + FiniteElementCollection* vfec_ = nullptr; + ParFiniteElementSpace* vfes_ = nullptr; + // Fields ParGridFunction Tnm1_gf_, Tnm2_gf_; ParGridFunction Tn_gf_, Tn_next_gf_, Text_gf_, resT_gf_; diff --git a/src/reactingFlow.cpp b/src/reactingFlow.cpp index a7d7b329..f5de78a0 100644 --- a/src/reactingFlow.cpp +++ b/src/reactingFlow.cpp @@ -2414,7 +2414,7 @@ void ReactingFlow::temperatureStep() { dist = x * x; if (dim_ == 3) { z = coordsDof(2 * sDofInt_ + i); - z = z - spark_center_[2]; + // z = z - spark_center_[2]; dist += z * z; } dist = std::sqrt(dist); @@ -3564,7 +3564,7 @@ void ReactingFlow::computeQtTO() { dist = x * x; if (dim_ == 3) { z = coordsDof(2 * sDofInt_ + i); - z = z - spark_center_[2]; + // z = z - spark_center_[2]; dist += z * z; } dist = std::sqrt(dist); diff --git a/src/zetaModel.cpp b/src/zetaModel.cpp index c980ddea..ced34ea2 100644 --- a/src/zetaModel.cpp +++ b/src/zetaModel.cpp @@ -53,6 +53,7 @@ static double radius(const Vector& pos) { return pos[0]; } static FunctionCoefficient radius_coeff(radius); double smoothMin(double val1, double val2); double smoothMax(double val1, double val2); +double smoothMinTwo(double val1, double val2); ZetaModel::ZetaModel(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalSchemeCoefficients& time_coeff, TPS::Tps* tps, ParGridFunction* gridScale) @@ -81,7 +82,7 @@ ZetaModel::ZetaModel(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalS tpsP_->getInput("ransModel/tls-min", tls_min_, 1.0e-12); tpsP_->getInput("ransModel/tts-max", tts_max_, 100.0); tpsP_->getInput("ransModel/tls-max", tls_max_, 100.0); - tpsP_->getInput("ransModel/mut-min", mut_min_, 1.0e-12); + tpsP_->getInput("ransModel/mut-min", mut_min_, 1.0e-8); tpsP_->getInput("ransModel/prod-min", pk_min_, 1.0e-14); tpsP_->getInput("ransModel/destruction", des_wgt_, 1.0); tpsP_->getInput("ransModel/production", prod_wgt_, 1.0); @@ -89,6 +90,8 @@ ZetaModel::ZetaModel(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalS tpsP_->getInput("ransModel/f-order", forder_, order_); tpsP_->getInput("ransModel/zfp-max", zfp_max_, 1.0e12); tpsP_->getInput("ransModel/v2-production-rate-coeff-limit", v2Prod_fLimiter_coeff_, 1.0e6); + tpsP_->getInput("ransModel/inlet-scale", inlet_scale_, 1.0); + tpsP_->getInput("ransModel/mutMax-scale", mutMax_scale_, 1.0e5); // streamwise stabilization (add full, no real disadvantage like in momentum) tpsP_->getInput("ransModel/streamwise-stabilization", sw_stab_, false); @@ -254,7 +257,7 @@ void ZetaModel::initializeSelf() { eddyVisc_gf_.SetSpace(sfes_); eddyVisc_.SetSize(sfes_truevsize); - eddyVisc_gf_ = 1.0e-2; + eddyVisc_gf_ = mut_min_; eddyVisc_gf_.GetTrueDofs(eddyVisc_); tke_gf_.SetSpace(sfes_); @@ -379,6 +382,11 @@ void ZetaModel::initializeSelf() { prod_gf_ = 1.0e-8; prod_gf_.GetTrueDofs(prod_); + prod_plus_tkeDiff_gf_.SetSpace(sfes_); + prod_plus_tkeDiff_.SetSize(sfes_truevsize); + prod_plus_tkeDiff_gf_ = 1.0e-8; + prod_plus_tkeDiff_gf_.GetTrueDofs(prod_plus_tkeDiff_); + prod_next_gf_.SetSpace(sfes_); prod_next_.SetSize(sfes_truevsize); prod_nm1_.SetSize(sfes_truevsize); @@ -513,9 +521,10 @@ void ZetaModel::initializeSelf() { tpsP_->getRequiredInput((basepath + "/tke").c_str(), tke_value); AddTKEDirichletBC(tke_value, inlet_attr); AddV2DirichletBC(2.0 / 3.0 * tke_value, inlet_attr); + } else if (type == "interpolate") { if (rank0_) { - std::cout << "Zeta Model: Setting interpolated Dirichlet TKE on patch = " << patch << std::endl; + std::cout << "Zeta Model: Setting interpolated Dirichlet TKE on patch = " << patch << " with scaling: " << inlet_scale_ << std::endl; } // Array inlet_attr(pmesh_->bdr_attributes.Max()); // inlet_attr = 0; @@ -530,8 +539,17 @@ void ZetaModel::initializeSelf() { tke_field_ = new GridFunctionCoefficient(extData_interface_->TKEdata); v2_field_ = new GridFunctionCoefficient(extData_interface_->V2data); - AddTKEDirichletBC(tke_field_, inlet_attr); - AddV2DirichletBC(v2_field_, inlet_attr); + scaling_coeff_ = new ConstantCoefficient(inlet_scale_); + tke_scaled_field_ = new ProductCoefficient(*scaling_coeff_, *tke_field_); + v2_scaled_field_ = new ProductCoefficient(*scaling_coeff_, *v2_field_); + + AddTKEDirichletBC(tke_scaled_field_, inlet_attr); + AddV2DirichletBC(v2_scaled_field_, inlet_attr); + + // this is an approximation that neglects tansport terms (assumes steady and equilibrium which is not correct) + tdr_field_ = new GridFunctionCoefficient(&prod_plus_tkeDiff_gf_); + AddTDRDirichletBC(tdr_field_, inlet_attr); + } else if (type == "fully-developed-pipe") { Array inlet_attr(pmesh_->bdr_attributes.Max()); inlet_attr = 0; @@ -604,13 +622,9 @@ void ZetaModel::initializeSelf() { // ConstantCoefficient *tdr_wall_coeff = new ConstantCoefficient(); // tdr_wall_coeff->constant = 0.0; // AddTDRDirichletBC(0.0, attr_wall); - AddTDRDirichletBC(tdr_wall_coeff_, attr_wall); - // DivergenceGridFunctionCoefficient *tdr_wall_coeff = new - // DivergenceGridFunctionCoefficient(*nu_gradTKE_coeff_); - // AddTDRDirichletBC(tdr_wall_coeff, attr_wall); - // tdr_bc_ = new GridFunctionCoefficient(&tdr_wall_gf_); - // AddTDRDirichletBC(tdr_bc_, attr_wall); + // tdr wall-bc from tke diffusion term + AddTDRDirichletBC(tdr_wall_coeff_, attr_wall); // ConstantCoefficient *zeta_wall_coeff = new ConstantCoefficient(); // zeta_wall_coeff->constant = 0.0; @@ -709,6 +723,8 @@ void ZetaModel::initializeOperators() { v2_diag_coeff_ = new SumCoefficient(*rhoDt_coeff_, *rhoTTS_coeff_, 1.0, 6.0 * des_wgt_); // v2_diag_coeff_ = new SumCoefficient(*rhoDt_coeff_, *ek_rho_coeff_, 1.0, 6.0*des_wgt_); + //if laplacian-f coeff is pos, it is NEG on the rhs due to ibp and then diag f MUST be also be pos! + // further, entire rhs is neg f_diag_coeff_ = new RatioCoefficient(1.0, *tls2_coeff_); f_diag_total_coeff_ = new SumCoefficient(*f_diag_coeff_, *zero_coeff_); @@ -1176,6 +1192,8 @@ void ZetaModel::setup() { // initial mu_t /* + extrapolateState(); + extrapolateRHS(); computeStrain(); updateTTS(); updateMuT(); @@ -1223,24 +1241,30 @@ void ZetaModel::step() { updateProd(); updateMsRho(); extrapolateRHS(); + // if (rank0_) {std::cout << "v2-f preliminaries complete" << endl;} // TKE step tkeStep(); + // if (rank0_) {std::cout << "v2-f tke complete" << endl;} // TDR step tdrStep(); + // if (rank0_) {std::cout << "v2-f tdr complete" << endl;} // f-Rate fStep(); + // if (rank0_) {std::cout << "v2-f f complete" << endl;} // zeta or v2 step // zetaStep(); v2Step(); updateZeta(); + // if (rank0_) {std::cout << "v2-f v2 complete" << endl;} // final calc of eddy visc at {n+1} updateTTS(); updateMuT(); + // if (rank0_) {std::cout << "v2-f updates complete" << endl;} // rotate storage updateTimestepHistory(); @@ -1256,9 +1280,10 @@ void ZetaModel::updateMuT() { const double* dk = tke_next_.HostRead(); const double* dTTS = tts_.HostRead(); const double* dTTS_strain = tts_strain_.HostRead(); + const double* dMu = mu_.HostRead(); double* muT = eddyVisc_.HostReadWrite(); - // for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dv2[i], twoThirds * dk[i]); + //for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dv2[i], twoThirds * dk[i]); for (int i = 0; i < SdofInt_; i++) muT[i] *= smoothMin(dv2[i], twoThirds * dk[i]); // to prevent kinks // for (int i = 0; i < SdofInt_; i++) { @@ -1267,7 +1292,7 @@ void ZetaModel::updateMuT() { // muT[i] *= ((1.0-wgt)*dv2[i] + wgt*twoThirds*dk[i]); //} - // for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dTTS[i], dTTS_strain[i]); + //for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dTTS[i], dTTS_strain[i]); for (int i = 0; i < SdofInt_; i++) muT[i] *= smoothMin(dTTS[i], dTTS_strain[i]); // to prevent kinks // for (int i = 0; i < SdofInt_; i++) { @@ -1277,12 +1302,15 @@ void ZetaModel::updateMuT() { //} // for (int i = 0; i < SdofInt_; i++) muT[i] = std::max(muT[i], mut_min_); - for (int i = 0; i < SdofInt_; i++) muT[i] = smoothMax(muT[i], mut_min_); + //??? for (int i = 0; i < SdofInt_; i++) muT[i] = smoothMax(muT[i], mut_min_); + + //??? for (int i = 0; i < SdofInt_; i++) muT[i] = smoothMin(muT[i], mutMax_scale_ * dMu[i]); + } eddyVisc_gf_.SetFromTrueDofs(eddyVisc_); - resf_gf_.ProjectGridFunction(eddyVisc_gf_); - eddyVisc_gf_.ProjectGridFunction(resf_gf_); + filter_gf_.ProjectGridFunction(eddyVisc_gf_); + eddyVisc_gf_.ProjectGridFunction(filter_gf_); eddyVisc_gf_.GetTrueDofs(eddyVisc_); } @@ -1615,6 +1643,15 @@ void ZetaModel::extrapolateState() { } void ZetaModel::extrapolateRHS() { + prod_next_.Set(1.0,prod_); + tts_next_.Set(1.0,tts_); + tls2_next_.Set(1.0,tls2_); + + prod_next_gf_.SetFromTrueDofs(prod_next_); + tts_next_gf_.SetFromTrueDofs(tts_next_); + tls2_next_gf_.SetFromTrueDofs(tls2_next_); + + /* prod_next_.Set(time_coeff_.ab1, prod_); prod_next_.Add(time_coeff_.ab2, prod_nm1_); prod_next_.Add(time_coeff_.ab3, prod_nm2_); @@ -1629,6 +1666,8 @@ void ZetaModel::extrapolateRHS() { tls2_next_.Add(time_coeff_.ab2, tls2_nm1_); tls2_next_.Add(time_coeff_.ab3, tls2_nm2_); tls2_next_gf_.SetFromTrueDofs(tls2_next_); + */ + } void ZetaModel::updateZeta() { @@ -1858,17 +1897,17 @@ void ZetaModel::tdrStep() { diag_coeff_ = tdr_diag_coeff_; diff_total_coeff_ = tdr_diff_total_coeff_; - // boundary condition - Array empty; - Lk_form_->Update(); - Lk_form_->Assemble(); + // boundary condition -> moved to after tke solve + //Array empty; + //Lk_form_->Update(); + //Lk_form_->Assemble(); // Lk_form_->FormSystemMatrix(tke_ess_tdof_, Lk_); - Lk_form_->FormSystemMatrix(empty, Lk_); - Lk_->Mult(tke_next_, tmpR0_); - MsRhoInv_->Mult(tmpR0_, tmpR0a_); - tmpR0a_ *= -1.0; - tdr_wall_gf_.SetFromTrueDofs(tmpR0a_); - + //Lk_form_->FormSystemMatrix(empty, Lk_); + //Lk_->Mult(tke_next_, tmpR0_); + //MsRhoInv_->Mult(tmpR0_, tmpR0a_); + //tmpR0a_ *= -1.0; + //tdr_wall_gf_.SetFromTrueDofs(tmpR0a_); + He_form_->Update(); He_form_->Assemble(); He_form_->FormSystemMatrix(tdr_ess_tdof_, He_); @@ -1884,8 +1923,8 @@ void ZetaModel::tdrStep() { // project new tdr bc onto gf which transfers actual ess bc's to solver for (auto& tdr_dbc : tdr_dbcs_) { - // tdr_next_gf_.ProjectBdrCoefficient(*tdr_dbc.coeff, tdr_dbc.attr); - tdr_next_gf_.ProjectBdrCoefficient(*tdr_wall_eval_coeff_, tdr_dbc.attr); + tdr_next_gf_.ProjectBdrCoefficient(*tdr_dbc.coeff, tdr_dbc.attr); + // tdr_next_gf_.ProjectBdrCoefficient(*tdr_wall_eval_coeff_, tdr_dbc.attr); } sfes_->GetRestrictionMatrix()->MultTranspose(res_, res_gf_); @@ -1988,7 +2027,9 @@ void ZetaModel::v2Step() { // production tmpR0_.Set(1.0, tke_next_); - // tmpR0_ *= fRate_; + tmpR0_ *= fRate_; + + /* res_gf_.ProjectGridFunction(fRate_gf_); res_gf_.GetTrueDofs(tmpR0a_); { @@ -2004,6 +2045,7 @@ void ZetaModel::v2Step() { data[i] *= std::min(df[i], v2Prod_fLimiter_coeff_ / dTTS[i]); } } + */ MsRho_->AddMult(tmpR0_, res_, +1.0); // destruction => 1/2 included in lhs @@ -2039,20 +2081,30 @@ void ZetaModel::v2Step() { // solve helmholtz eq for temp HvInv_->Mult(Bt2, Xt2); - assert(HvInv_->GetConverged()); + // assert(HvInv_->GetConverged()); Hv_form_->RecoverFEMSolution(Xt2, res_gf_, v2_next_gf_); v2_next_gf_.GetTrueDofs(v2_next_); + if ( !(HvInv_->GetConverged()) ) { + if(rank0_) { + std::cout << "Warnign: v2 not converged" << endl; + v2_next_.Set(1.0,v2_); + v2_next_gf_.SetFromTrueDofs(v2_next_); + } + } + // hard-clip { - // const double *dtke = tke_next_.HostReadWrite(); + const double *dtke = tke_next_.HostReadWrite(); double* dv2 = v2_next_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { dv2[i] = std::max(dv2[i], 0.0); + // clip when used in certain areas, allow to be above 2/3k for destruction in v2 // dv2[i] = std::min(dv2[i], 2.0/3.0 * dtke[i]); - if (dv2[i] != dv2[i]) std::cout << " v2 is actually NaN!" << endl; + + // if (dv2[i] != dv2[i]) std::cout << " v2 is actually NaN!" << endl; } } v2_next_gf_.SetFromTrueDofs(v2_next_); @@ -2063,20 +2115,6 @@ void ZetaModel::fStep() { res_ = 0.0; resf_ = 0.0; - // assemble source - /* - tmpR0b_.Set(C2_, prod_); - tmpR0b_ /= rho_; - tmpR0b_ /= tdr_; - tmpR0b_ += (C1_ - 1.0); - - tmpR0a_.Set(1.0, zeta_); - tmpR0a_ -= 2.0 / 3.0; - tmpR0a_ *= tmpR0b_; - tmpR0a_ /= tts_; - tmpR0a_ /= tls2_; - */ - // code-friendly form // rhs: 1/T * [(C1-6)*v2/k - 2/3*(C1-1)] - C2*Pk/(rho*k) double Ctmp1, Ctmp2; @@ -2090,7 +2128,7 @@ void ZetaModel::fStep() { const double* dk = tke_next_.HostRead(); double* data = tmpR0b_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { - data[i] /= std::max(dk[i], tke_min_); + data[i] /= smoothMax(dk[i], tke_min_); } } @@ -2101,74 +2139,143 @@ void ZetaModel::fStep() { const double* dk = tke_next_.HostRead(); double* data = tmpR0a_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { - data[i] = std::min(dv2[i], twoThirds * dk[i]); + data[i] = smoothMin(dv2[i], twoThirds * dk[i]); } for (int i = 0; i < SdofInt_; i++) { - data[i] /= std::max(dk[i], tke_min_); - } - // clip again? - // for (int i = 0; i < SdofInt_; i++) { - // data[i] = std::min(data[i], zfp_max_); - // } + data[i] /= smoothMax(dk[i], tke_min_); + } } // intercept f res for viz - vfres_gf_.SetFromTrueDofs(tmpR0a_); + // vfres_gf_.SetFromTrueDofs(tmpR0a_); + // these terms are in L^2*nabla{f} - f = ... form tmpR0a_ *= Ctmp2; tmpR0a_ -= Ctmp1; tmpR0a_ /= tts_; tmpR0a_ -= tmpR0b_; - // limiter-term - /* + // neg to account for neg on rhs from ibp + // NO, this is done in Mf_ line below... tmpR0a_.Neg(); + + // if not including L2 in laplacian term (but do have 1/L2 on the diaf term) + tmpR0a_ /= tls2_; + + // filter f-source + res_gf_.SetFromTrueDofs(tmpR0a_); + filter_gf_.ProjectGridFunction(res_gf_); + res_gf_.ProjectGridFunction(filter_gf_); + res_gf_.GetTrueDofs(tmpR0_); + resf_gf_.ProjectGridFunction(res_gf_); + resf_gf_.GetTrueDofs(ftmpR0_); + + // with diag in Hf pos and nabla neg (due to ibp), rhs needs a negative + Mf_->AddMult(ftmpR0_, resf_, -1.0); + resf_gf_.SetFromTrueDofs(resf_); + + // Update Helmholtz operator + Hf_form_->Update(); + Hf_form_->Assemble(); + Hf_form_->FormSystemMatrix(fRate_ess_tdof_, Hf_); + + HfInv_->SetOperator(*Hf_); + if (partial_assembly_) { + delete HfInvPC_; + Vector diag_pa(sfes_->GetTrueVSize()); + Hf_form_->AssembleDiagonal(diag_pa); + HfInvPC_ = new OperatorJacobiSmoother(diag_pa, fRate_ess_tdof_); + HfInv_->SetPreconditioner(*HfInvPC_); + } + + // Prepare for the solve + for (auto& fRate_dbc : fRate_dbcs_) { + fRate_gf_.ProjectBdrCoefficient(*fRate_dbc.coeff, fRate_dbc.attr); + } + sfes_->GetRestrictionMatrix()->MultTranspose(resf_, resf_gf_); + + Vector Xt2, Bt2; + Hf_form_->FormLinearSystem(fRate_ess_tdof_, fRate_gf_, resf_gf_, Hf_, Xt2, Bt2, 1); + + // solve helmholtz eq for temp + HfInv_->Mult(Bt2, Xt2); + assert(HfInv_->GetConverged()); + + Hf_form_->RecoverFEMSolution(Xt2, resf_gf_, fRate_gf_); + fRate_gf_.GetTrueDofs(fRate_); + + // hard-clip { - double twoThirds = 2.0/3.0; - double tmp; - const double *dz = zeta_next_.HostRead(); - double *data = tmpR0c_.HostReadWrite(); - for (int i = 0; i < SdofInt_; i++) { - tmp = dz[i] - twoThirds; - tmp = std::max(tmp, 0.0); - tmp *= (C1_ - 1.0); - data[i] = tmp; + double* df = fRate_.HostReadWrite(); + for (int i = 0; i < sfes_->GetTrueVSize(); i++) { + if (df[i] != df[i]) std::cout << " f is actually NaN!" << endl; + df[i] = std::max(df[i], 0.0); } } - tmpR0c_ /= tts_; - tmpR0a_ += tmpR0c_; + fRate_gf_.SetFromTrueDofs(fRate_); +} + + +// Based on code-friendly version but shifts the f-shift to production +// and treats the destruction implicitly. Has the advantage of maintaining +// correct destruction behavior with zeta and increasing diagonal dominance +// to reduce corner singularity sensitivity +void ZetaModel::fStepRobustified() { + // Build the right-hand-side + res_ = 0.0; + resf_ = 0.0; + + // code-friendly form + // rhs: 1/T * [(C1-6)*v2/k - 2/3*(C1-1)] - C2*Pk/(rho*k) + // lhs: L^2*nabla{f} - f + + // robustified form + // Df = -(C1-1)(zeta-2/3) (note sign change so Df is (+) with zeta limited to 2/3) + // Pf = C2*Pk/k + 5*e/k + // f - L^2*nabla{f} = + // (I+Df-L^2*nabla){f} = Pf + + double Ctmp1, Ctmp2; + Ctmp1 = 2.0 / 3.0 * (C1_ - 1.0); + Ctmp2 = (C1_ - 6.0); + + // C2*Pk/(rho*k) + tmpR0b_.Set(C2_, prod_); + tmpR0b_ /= rho_; { - double *data = tmpR0a_.HostReadWrite(); + const double* dk = tke_next_.HostRead(); + double* data = tmpR0b_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { - data[i] = std::min(data[i], 0.0); + data[i] /= smoothMax(dk[i], tke_min_); } } - */ - // HACK limit - /* + // v2/k { - double twoThirds = 2.0/3.0; - double Pv2_max; - const double *dP = prod_.HostRead(); - const double *de = tdr_.HostRead(); - const double *dv2 = v2_.HostRead(); - const double *dk = tke_.HostRead(); - const double *drho = rho_.HostRead(); - double *data = tmpR0a_.HostReadWrite(); + double twoThirds = 2.0 / 3.0; + const double* dv2 = v2_next_.HostRead(); + const double* dk = tke_next_.HostRead(); + double* data = tmpR0a_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { - Pv2_max = twoThirds * (dP[i]/drho[i] - de[i]); - // Pv2_max += 6.0 * (dv2[i]/std::max(dk[i], tke_min_)) * de[i]; - Pv2_max += 6.0 * twoThirds * de[i]; - data[i] = - Pv2_max; + data[i] = smoothMin(dv2[i], twoThirds * dk[i]); } + for (int i = 0; i < SdofInt_; i++) { + data[i] /= smoothMax(dk[i], tke_min_); + } } - */ + // intercept f res for viz + // vfres_gf_.SetFromTrueDofs(tmpR0a_); - // minus is to (-) on operator - // Ms_->AddMult(tmpR0a_, res_, -1.0); + // these terms are in L^2*nabla{f} - f = ... form + tmpR0a_ *= Ctmp2; + tmpR0a_ -= Ctmp1; + tmpR0a_ /= tts_; + tmpR0a_ -= tmpR0b_; - // if not including L2 in laplacian term + // neg to account for neg on rhs from ibp + // NO, this is done in Mf_ line below... tmpR0a_.Neg(); + + // if not including L2 in laplacian term (but do have 1/L2 on the diaf term) tmpR0a_ /= tls2_; - + // filter f-source res_gf_.SetFromTrueDofs(tmpR0a_); filter_gf_.ProjectGridFunction(res_gf_); @@ -2177,9 +2284,10 @@ void ZetaModel::fStep() { resf_gf_.ProjectGridFunction(res_gf_); resf_gf_.GetTrueDofs(ftmpR0_); + // with diag in Hf pos and nabla neg (due to ibp), rhs needs a negative Mf_->AddMult(ftmpR0_, resf_, -1.0); resf_gf_.SetFromTrueDofs(resf_); - + // Update Helmholtz operator Hf_form_->Update(); Hf_form_->Assemble(); @@ -2221,6 +2329,7 @@ void ZetaModel::fStep() { fRate_gf_.SetFromTrueDofs(fRate_); } + /// TODO: pull in tensor gridscale and calc Mnn^T for wall-normal spacing void ZetaModel::updateBC(int step) { /* @@ -2246,6 +2355,7 @@ void ZetaModel::updateBC(int step) { } void ZetaModel::computeTDRwall() { + tmpR0_ = 0.0; Lk_bdry_->Update(); Lk_bdry_->Assemble(); @@ -2259,7 +2369,15 @@ void ZetaModel::computeTDRwall() { Lk_->AddMult(tke_next_, tmpR0_); MsInv_->Mult(tmpR0_, tke_lapl_); - tke_lapl_gf_.SetFromTrueDofs(tmpR0_); + tke_lapl_.Neg(); + tke_lapl_gf_.SetFromTrueDofs(tke_lapl_); + + // update for and tdr inlets (add advection of tke later) + prod_plus_tkeDiff_.Set(1.0,prod_next_); + prod_plus_tkeDiff_ /= rho_; + prod_plus_tkeDiff_.Add(1.0,tke_lapl_); + prod_plus_tkeDiff_gf_.SetFromTrueDofs(prod_plus_tkeDiff_); + } /// Add a Dirichlet boundary condition to scalar fields @@ -2369,16 +2487,85 @@ void ZetaModel::AddFRATEDirichletBC(Coefficient* coeff, Array& attr) { // Smoothed-min (C-infinity) function which does not over-shoot double smoothMin(double val1, double val2) { - double C = 4.0; - double val; - val = -1.0 / C * std::log(std::exp(-C * val1) + std::exp(-C * val2)); + //double C = 4.0; + double k = 0.001; + double tanh_half = 0.54930615; + double val, arg, wt; + + // val = -1.0 / C * std::log(std::exp(-C * val1) + std::exp(-C * val2)); + + if (isnan(val1) | isinf(val1)) { + std::cout << "smin: BAD val1" << endl; + } + if (isnan(val2) | isinf(val2)) { + std::cout << "smin: BAD val2" << endl; + } + + //arg = val1 / val2; + //arg = std::pow(arg,C); + //wt = std::tanh(tanh_half * arg); + //val = (1.0-wt) * val1 + wt * val2; + + //val = 0.5 * (val1 + val2 - std::sqrt((val1-val2)*(val1-val2) + k)); + + val = std::min(val1,val2); + return val; } // Smoothed-max (C-infinity) function which does not under-shoot double smoothMax(double val1, double val2) { double C = 4.0; - double val; - val = 1.0 / C * std::log(std::exp(C * val1) + std::exp(C * val2)); + double k = 0.001; + double tanh_half = 0.54930615; + double val, arg, wt; + + //val = 1.0 / C * std::log(std::exp(C * val1) + std::exp(C * val2)); + + if (isnan(val1) | isinf(val1)) { + std::cout << "smax: BAD val1" << endl; + } + if (isnan(val2) | isinf(val2)) { + std::cout << "smax: BAD val2" << endl; + } + + //arg = val1 / val2; + //arg = std::pow(arg,C); + //wt = std::tanh(tanh_half * arg); + //val = wt * val1 + (1.0 - wt) * val2; + + //val = 0.5 * (val1 + val2 + std::sqrt((val1-val2)*(val1-val2) + k)); + + val = std::max(val1,val2); + return val; } + +// Smoothed-min (C-infinity) function which does not over-shoot +double smoothMinTwo(double val1, double val2) { + double C = 20.0; + double k = 0.001; + double tanh_half = 0.54930615; + double val, arg, wt; + + val = -1.0 / C * std::log(std::exp(-C * val1) + std::exp(-C * val2)); + + if (isnan(val1) | isinf(val1)) { + std::cout << "smin: BAD val1" << endl; + } + if (isnan(val2) | isinf(val2)) { + std::cout << "smin: BAD val2" << endl; + } + + //arg = val1 / val2; + //arg = std::pow(arg,C); + //wt = std::tanh(tanh_half * arg); + //val = (1.0-wt) * val1 + wt * val2; + + //val = 0.5 * (val1 + val2 - std::sqrt((val1-val2)*(val1-val2) + k)); + + //val = std::min(val1,val2); + + return val; +} + diff --git a/src/zetaModel.hpp b/src/zetaModel.hpp index 161f0033..63bdaf94 100644 --- a/src/zetaModel.hpp +++ b/src/zetaModel.hpp @@ -122,7 +122,8 @@ class ZetaModel : public TurbModelBase { double prod_wgt_; double zfp_max_; double v2Prod_fLimiter_coeff_; - + double mutMax_scale_; + // streamwise stabilization bool sw_stab_ = false; /**< Enable/disable supg stabilization. */ double Reh_factor_, Reh_offset_; /**< supg stabilization parameters */ @@ -238,6 +239,9 @@ class ZetaModel : public TurbModelBase { ParGridFunction prod_next_gf_; Vector prod_, prod_next_, prod_nm1_, prod_nm2_; + ParGridFunction prod_plus_tkeDiff_gf_; + Vector prod_plus_tkeDiff_; + /// model coefficients double Cmu_ = 0.22; double sigmaK_ = 1.0; @@ -253,6 +257,7 @@ class ZetaModel : public TurbModelBase { double Cl_ = 0.23; double Cn_ = 70.0; double Ce1_; // function of local zeta + double inlet_scale_; ParGridFunction res_gf_; Vector res_; @@ -350,7 +355,11 @@ class ZetaModel : public TurbModelBase { GridFunctionCoefficient* tke_field_ = nullptr; GridFunctionCoefficient* v2_field_ = nullptr; - + GridFunctionCoefficient* tdr_field_ = nullptr; + ProductCoefficient* tke_scaled_field_ = nullptr; + ProductCoefficient* v2_scaled_field_ = nullptr; + ConstantCoefficient* scaling_coeff_ = nullptr; + // streamwise stabilization VectorMagnitudeCoefficient* umag_coeff_ = nullptr; GridFunctionCoefficient* gscale_coeff_ = nullptr; @@ -448,6 +457,7 @@ class ZetaModel : public TurbModelBase { void zetaStep(); void v2Step(); void fStep(); + void fStepRobustified(); void convection(string scalar); void updateTimestepHistory(); void updateZeta(); From e57008bf65ec120988839071240c8f2b34d32b3e Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Wed, 1 Jul 2026 11:18:43 -0700 Subject: [PATCH 11/12] adding robust form of f to allow higher-order v2f runs. fix to inlet interpolation for 2d-axisym inlets --- src/gaussianInterpExtData.cpp | 18 +- src/loMach.cpp | 12 +- src/lte_thermo_chem.cpp | 24 +-- src/lte_thermo_chem.hpp | 8 +- src/zetaModel.cpp | 343 +++++++++++++++++++--------------- src/zetaModel.hpp | 25 ++- 6 files changed, 245 insertions(+), 185 deletions(-) diff --git a/src/gaussianInterpExtData.cpp b/src/gaussianInterpExtData.cpp index 56748361..a3b8568c 100644 --- a/src/gaussianInterpExtData.cpp +++ b/src/gaussianInterpExtData.cpp @@ -1039,14 +1039,13 @@ void GaussianInterpExtData::setInletTurbScalars() { if (tke_pr[j].tke < 0.0 && tke_pr[j].v2 < 0.0) { continue; } - + dist = (xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x) + (xp[1] - tke_pr[j].y) * (xp[1] - tke_pr[j].y); - if (dim_ == 3) { - dist += (xp[2] - tke_pr[j].z) * (xp[2] - tke_pr[j].z); + if (dim_ == 3) { + dist += (xp[2] - tke_pr[j].z) * (xp[2] - tke_pr[j].z); } - dist = std::sqrt(dist); + dist = std::sqrt(dist); distMin = std::min(distMin, dist); - } // find second closest data pt @@ -1058,14 +1057,13 @@ void GaussianInterpExtData::setInletTurbScalars() { } dist = (xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x) + (xp[1] - tke_pr[j].y) * (xp[1] - tke_pr[j].y); - if (dim_ == 3) { + if (dim_ == 3) { dist += (xp[2] - tke_pr[j].z) * (xp[2] - tke_pr[j].z); - } - dist = std::sqrt(dist); + } + dist = std::sqrt(dist); if (dist > distMin) { distMinSecond = std::min(distMinSecond, dist); } - } // radius for Gaussian interpolation @@ -1080,7 +1078,7 @@ void GaussianInterpExtData::setInletTurbScalars() { // dist = sqrt((xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x) + (xp[1] - tke_pr[j].y) * (xp[1] - tke_pr[j].y) + // (xp[2] - tke_pr[j].z) * (xp[2] - tke_pr[j].z)); dist = sqrt((xp[0] - tke_pr[j].x) * (xp[0] - tke_pr[j].x)); - + // gaussian interpolation if (dist <= 1.5 * radius) { wt = exp(-(dist * dist) / (radius * radius)); diff --git a/src/loMach.cpp b/src/loMach.cpp index cfb76ae1..d2a0f225 100644 --- a/src/loMach.cpp +++ b/src/loMach.cpp @@ -422,20 +422,20 @@ void LoMachSolver::solveStep() { sw_thermChem_.Start(); thermo_->step(); sw_thermChem_.Stop(); - // if (rank0_ == true) std::cout << "thermoChem complete" << endl; - + // if (rank0_ == true) std::cout << "thermoChem complete" << endl; + sw_flow_.Start(); if (!disable_flow_) { flow_->step(); } sw_flow_.Stop(); - // if (rank0_ == true) std::cout << "flow complete" << endl; - + // if (rank0_ == true) std::cout << "flow complete" << endl; + sw_turb_.Start(); turbModel_->step(); sw_turb_.Stop(); - // if (rank0_ == true) std::cout << "turbulence model complete" << endl; - + // if (rank0_ == true) std::cout << "turbulence model complete" << endl; + } else { if (rank0_) std::cout << "Time integration not updated." << endl; exit(1); diff --git a/src/lte_thermo_chem.cpp b/src/lte_thermo_chem.cpp index 8d1522c8..bc215e7b 100644 --- a/src/lte_thermo_chem.cpp +++ b/src/lte_thermo_chem.cpp @@ -175,7 +175,7 @@ LteThermoChem::LteThermoChem(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, t tps->getInput("loMach/ltethermo/Prandtl", Pr_, 0.5); invPr_ = 1.0 / Pr_; - + tps->getInput("loMach/ltethermo/clip-temperature", Tclip_, false); tps->getInput("loMach/ltethermo/min-temperature", Tmin_, 0.0); tps->getInput("loMach/ltethermo/max-temperature", Tmax_, 100000.0); @@ -211,7 +211,7 @@ LteThermoChem::~LteThermoChem() { delete rad_rho_Cp_coeff_; delete rad_rho_coeff_; - delete sfes_filter_; + delete sfes_filter_; delete sfec_filter_; delete HtInv_; delete HtInvPC_; @@ -255,7 +255,7 @@ LteThermoChem::~LteThermoChem() { delete sfes_; delete sfec_; delete vfes_; - delete vfec_; + delete vfec_; } void LteThermoChem::initializeSelf() { @@ -271,7 +271,7 @@ void LteThermoChem::initializeSelf() { vfes_ = new ParFiniteElementSpace(pmesh_, vfec_, dim_); sDofInt_ = sfes_->GetTrueVSize(); - + // Check if fully periodic mesh if (!(pmesh_->bdr_attributes.Size() == 0)) { temp_ess_attr_.SetSize(pmesh_->bdr_attributes.Max()); @@ -1177,7 +1177,7 @@ void LteThermoChem::step() { djh[i] *= wgt; } } - + resT_ += jh_; // Update Helmholtz operator to account for changing dt, rho, and kappa @@ -1214,14 +1214,14 @@ void LteThermoChem::step() { Ht_form_->RecoverFEMSolution(Xt2, resT_gf_, Tn_next_gf_); Tn_next_gf_.GetTrueDofs(Tn_next_); - + // assert(HtInv_->GetConverged()); if (!(HtInv_->GetConverged())) { - if (rank0_) { - mfem::out << "Warning, temperature not converging!"; - } - Tn_next_.Set(1.0,Tn_); - Tn_next_gf_.SetFromTrueDofs(Tn_next_); + if (rank0_) { + mfem::out << "Warning, temperature not converging!"; + } + Tn_next_.Set(1.0, Tn_); + Tn_next_gf_.SetFromTrueDofs(Tn_next_); } // explicit filter @@ -1527,7 +1527,7 @@ void LteThermoChem::computeQt() { djh[i] *= wgt; } } - + tmpR0_ -= jh_; sfes_->GetRestrictionMatrix()->MultTranspose(tmpR0_, resT_gf_); diff --git a/src/lte_thermo_chem.hpp b/src/lte_thermo_chem.hpp index 1573af0c..85f9a42d 100644 --- a/src/lte_thermo_chem.hpp +++ b/src/lte_thermo_chem.hpp @@ -108,8 +108,8 @@ class LteThermoChem final : public ThermoChemModelBase { bool spark_ = false; double spark_radius_; double spark_peak_; - Vector spark_center_; - + Vector spark_center_; + // Boundary condition info Array temp_ess_attr_; /**< List of patches with Dirichlet BC on temperature */ Array Qt_ess_attr_; /**< List of patches with Dirichlet BC on Q (thermal divergence) */ @@ -140,7 +140,7 @@ class LteThermoChem final : public ThermoChemModelBase { double Pr_; double invPr_; - + bool Tclip_ = false; double Tmin_ = 0.0; double Tmax_ = 100000.0; @@ -155,7 +155,7 @@ class LteThermoChem final : public ThermoChemModelBase { FiniteElementCollection* vfec_ = nullptr; ParFiniteElementSpace* vfes_ = nullptr; - + // Fields ParGridFunction Tnm1_gf_, Tnm2_gf_; ParGridFunction Tn_gf_, Tn_next_gf_, Text_gf_, resT_gf_; diff --git a/src/zetaModel.cpp b/src/zetaModel.cpp index ced34ea2..fcca1716 100644 --- a/src/zetaModel.cpp +++ b/src/zetaModel.cpp @@ -85,13 +85,17 @@ ZetaModel::ZetaModel(mfem::ParMesh* pmesh, LoMachOptions* loMach_opts, temporalS tpsP_->getInput("ransModel/mut-min", mut_min_, 1.0e-8); tpsP_->getInput("ransModel/prod-min", pk_min_, 1.0e-14); tpsP_->getInput("ransModel/destruction", des_wgt_, 1.0); - tpsP_->getInput("ransModel/production", prod_wgt_, 1.0); + // not implemented... tpsP_->getInput("ransModel/production", prod_wgt_, 0.0); tpsP_->getInput("ransModel/tls-coeff", Cl_, 0.23); tpsP_->getInput("ransModel/f-order", forder_, order_); tpsP_->getInput("ransModel/zfp-max", zfp_max_, 1.0e12); tpsP_->getInput("ransModel/v2-production-rate-coeff-limit", v2Prod_fLimiter_coeff_, 1.0e6); tpsP_->getInput("ransModel/inlet-scale", inlet_scale_, 1.0); tpsP_->getInput("ransModel/mutMax-scale", mutMax_scale_, 1.0e5); + tpsP_->getInput("ransModel/robust-f", robust_, false); + if (rank0_ && robust_) { + std::cout << " Using experimental robustified-f formulation!" << endl; + } // streamwise stabilization (add full, no real disadvantage like in momentum) tpsP_->getInput("ransModel/streamwise-stabilization", sw_stab_, false); @@ -291,6 +295,9 @@ void ZetaModel::initializeSelf() { filter_gf_ = 0.0; filter_ = 0.0; + Df_gf_.SetSpace(sfes_); + Df_gf_ = 0.0; + tke_next_gf_.SetSpace(sfes_); tke_next_.SetSize(sfes_truevsize); tke_next_gf_ = tke_gf_; @@ -386,7 +393,7 @@ void ZetaModel::initializeSelf() { prod_plus_tkeDiff_.SetSize(sfes_truevsize); prod_plus_tkeDiff_gf_ = 1.0e-8; prod_plus_tkeDiff_gf_.GetTrueDofs(prod_plus_tkeDiff_); - + prod_next_gf_.SetSpace(sfes_); prod_next_.SetSize(sfes_truevsize); prod_nm1_.SetSize(sfes_truevsize); @@ -521,10 +528,11 @@ void ZetaModel::initializeSelf() { tpsP_->getRequiredInput((basepath + "/tke").c_str(), tke_value); AddTKEDirichletBC(tke_value, inlet_attr); AddV2DirichletBC(2.0 / 3.0 * tke_value, inlet_attr); - + } else if (type == "interpolate") { if (rank0_) { - std::cout << "Zeta Model: Setting interpolated Dirichlet TKE on patch = " << patch << " with scaling: " << inlet_scale_ << std::endl; + std::cout << "Zeta Model: Setting interpolated Dirichlet TKE on patch = " << patch + << " with scaling: " << inlet_scale_ << std::endl; } // Array inlet_attr(pmesh_->bdr_attributes.Max()); // inlet_attr = 0; @@ -542,14 +550,14 @@ void ZetaModel::initializeSelf() { scaling_coeff_ = new ConstantCoefficient(inlet_scale_); tke_scaled_field_ = new ProductCoefficient(*scaling_coeff_, *tke_field_); v2_scaled_field_ = new ProductCoefficient(*scaling_coeff_, *v2_field_); - + AddTKEDirichletBC(tke_scaled_field_, inlet_attr); AddV2DirichletBC(v2_scaled_field_, inlet_attr); // this is an approximation that neglects tansport terms (assumes steady and equilibrium which is not correct) tdr_field_ = new GridFunctionCoefficient(&prod_plus_tkeDiff_gf_); - AddTDRDirichletBC(tdr_field_, inlet_attr); - + AddTDRDirichletBC(tdr_field_, inlet_attr); + } else if (type == "fully-developed-pipe") { Array inlet_attr(pmesh_->bdr_attributes.Max()); inlet_attr = 0; @@ -623,7 +631,7 @@ void ZetaModel::initializeSelf() { // tdr_wall_coeff->constant = 0.0; // AddTDRDirichletBC(0.0, attr_wall); - // tdr wall-bc from tke diffusion term + // tdr wall-bc from tke diffusion term AddTDRDirichletBC(tdr_wall_coeff_, attr_wall); // ConstantCoefficient *zeta_wall_coeff = new ConstantCoefficient(); @@ -664,6 +672,7 @@ void ZetaModel::initializeOperators() { // coefficients for operators zero_coeff_ = new ConstantCoefficient(0.0); unity_coeff_ = new ConstantCoefficient(1.0); + // negOne_coeff_ = new ConstantCoefficient(-1.0); posTwo_coeff_ = new ConstantCoefficient(2.0); negTwo_coeff_ = new ConstantCoefficient(-2.0); delta_coeff_ = new GridFunctionCoefficient(gridScale_gf_); @@ -723,10 +732,17 @@ void ZetaModel::initializeOperators() { v2_diag_coeff_ = new SumCoefficient(*rhoDt_coeff_, *rhoTTS_coeff_, 1.0, 6.0 * des_wgt_); // v2_diag_coeff_ = new SumCoefficient(*rhoDt_coeff_, *ek_rho_coeff_, 1.0, 6.0*des_wgt_); - //if laplacian-f coeff is pos, it is NEG on the rhs due to ibp and then diag f MUST be also be pos! - // further, entire rhs is neg - f_diag_coeff_ = new RatioCoefficient(1.0, *tls2_coeff_); - f_diag_total_coeff_ = new SumCoefficient(*f_diag_coeff_, *zero_coeff_); + // if laplacian-f coeff is pos, it is NEG on the rhs due to ibp and then diag f MUST be also be pos! + // further, entire rhs is neg + // f_diag_coeff_ = new RatioCoefficient(1.0, *tls2_coeff_); + if (robust_) { + f_destruction_coeff_ = new GridFunctionCoefficient(&Df_gf_); + // f_diag_total_coeff_ = new SumCoefficient(*f_diag_coeff_, f_destruction_coeff_); + f_diag_total_coeff_ = new SumCoefficient(*unity_coeff_, *f_destruction_coeff_); + } else { + // f_diag_total_coeff_ = new SumCoefficient(*f_diag_coeff_, *zero_coeff_); + f_diag_total_coeff_ = new SumCoefficient(*unity_coeff_, *zero_coeff_); + } if (axisym_) { swirl_coeff_ = new GridFunctionCoefficient(flow_interface_->swirl); @@ -745,7 +761,9 @@ void ZetaModel::initializeOperators() { // need separate coeffs for f-space (all of em) // rad_f_diag_coeff_ = new ProductCoefficient(fradius_coeff, *f_diag_coeff_); - rad_f_diag_coeff_ = new ProductCoefficient(radius_coeff, *f_diag_coeff_); + // rad_f_diag_coeff_ = new ProductCoefficient(radius_coeff, *f_diag_coeff_); + rad_f_diag_coeff_ = new ProductCoefficient(radius_coeff, *f_diag_total_coeff_); + rad_tls2_coeff_ = new ProductCoefficient(radius_coeff, *tls2_coeff_); } // artifical diffusion coefficients @@ -974,12 +992,20 @@ void ZetaModel::initializeOperators() { // auto *hdf_blfi = new DiffusionIntegrator(*tls2_coeff_); MassIntegrator* hmf_blfi; DiffusionIntegrator* hdf_blfi; + // if f-diag is positive, lapl term is (-) on lhs and no additional neg + // is added to lapl term to correct for ibp sign if (axisym_) { + // hmf_blfi = new MassIntegrator(*rad_f_diag_coeff_); + // hdf_blfi = new DiffusionIntegrator(*rad_unity_coeff_); + // hmf_blfi = new MassIntegrator(*rad_unity_coeff_); hmf_blfi = new MassIntegrator(*rad_f_diag_coeff_); - hdf_blfi = new DiffusionIntegrator(*rad_unity_coeff_); + hdf_blfi = new DiffusionIntegrator(*rad_tls2_coeff_); } else { - hmf_blfi = new MassIntegrator(*f_diag_coeff_); - hdf_blfi = new DiffusionIntegrator(*unity_coeff_); + // hmf_blfi = new MassIntegrator(*f_diag_coeff_); + // hdf_blfi = new DiffusionIntegrator(*unity_coeff_); + // hmf_blfi = new MassIntegrator(*unity_coeff_); + hmf_blfi = new MassIntegrator(*f_diag_total_coeff_); + hdf_blfi = new DiffusionIntegrator(*tls2_coeff_); } if (numerical_integ_) { hmf_blfi->SetIntRule(&ir_dif); @@ -1193,7 +1219,7 @@ void ZetaModel::setup() { // initial mu_t /* extrapolateState(); - extrapolateRHS(); + extrapolateRHS(); computeStrain(); updateTTS(); updateMuT(); @@ -1245,26 +1271,30 @@ void ZetaModel::step() { // TKE step tkeStep(); - // if (rank0_) {std::cout << "v2-f tke complete" << endl;} + // if (rank0_) {std::cout << "v2-f tke complete" << endl;} // TDR step tdrStep(); - // if (rank0_) {std::cout << "v2-f tdr complete" << endl;} + // if (rank0_) {std::cout << "v2-f tdr complete" << endl;} // f-Rate - fStep(); - // if (rank0_) {std::cout << "v2-f f complete" << endl;} + if (robust_) { + fStepRobustified(); + } else { + fStep(); + } + // if (rank0_) {std::cout << "v2-f f complete" << endl;} // zeta or v2 step // zetaStep(); v2Step(); updateZeta(); - // if (rank0_) {std::cout << "v2-f v2 complete" << endl;} + // if (rank0_) {std::cout << "v2-f v2 complete" << endl;} // final calc of eddy visc at {n+1} updateTTS(); updateMuT(); - // if (rank0_) {std::cout << "v2-f updates complete" << endl;} + // if (rank0_) {std::cout << "v2-f updates complete" << endl;} // rotate storage updateTimestepHistory(); @@ -1280,10 +1310,10 @@ void ZetaModel::updateMuT() { const double* dk = tke_next_.HostRead(); const double* dTTS = tts_.HostRead(); const double* dTTS_strain = tts_strain_.HostRead(); - const double* dMu = mu_.HostRead(); + const double* dMu = mu_.HostRead(); double* muT = eddyVisc_.HostReadWrite(); - //for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dv2[i], twoThirds * dk[i]); + // for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dv2[i], twoThirds * dk[i]); for (int i = 0; i < SdofInt_; i++) muT[i] *= smoothMin(dv2[i], twoThirds * dk[i]); // to prevent kinks // for (int i = 0; i < SdofInt_; i++) { @@ -1292,7 +1322,7 @@ void ZetaModel::updateMuT() { // muT[i] *= ((1.0-wgt)*dv2[i] + wgt*twoThirds*dk[i]); //} - //for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dTTS[i], dTTS_strain[i]); + // for (int i = 0; i < SdofInt_; i++) muT[i] *= std::min(dTTS[i], dTTS_strain[i]); for (int i = 0; i < SdofInt_; i++) muT[i] *= smoothMin(dTTS[i], dTTS_strain[i]); // to prevent kinks // for (int i = 0; i < SdofInt_; i++) { @@ -1305,7 +1335,6 @@ void ZetaModel::updateMuT() { //??? for (int i = 0; i < SdofInt_; i++) muT[i] = smoothMax(muT[i], mut_min_); //??? for (int i = 0; i < SdofInt_; i++) muT[i] = smoothMin(muT[i], mutMax_scale_ * dMu[i]); - } eddyVisc_gf_.SetFromTrueDofs(eddyVisc_); @@ -1643,13 +1672,13 @@ void ZetaModel::extrapolateState() { } void ZetaModel::extrapolateRHS() { - prod_next_.Set(1.0,prod_); - tts_next_.Set(1.0,tts_); - tls2_next_.Set(1.0,tls2_); + prod_next_.Set(1.0, prod_); + tts_next_.Set(1.0, tts_); + tls2_next_.Set(1.0, tls2_); prod_next_gf_.SetFromTrueDofs(prod_next_); tts_next_gf_.SetFromTrueDofs(tts_next_); - tls2_next_gf_.SetFromTrueDofs(tls2_next_); + tls2_next_gf_.SetFromTrueDofs(tls2_next_); /* prod_next_.Set(time_coeff_.ab1, prod_); @@ -1667,7 +1696,6 @@ void ZetaModel::extrapolateRHS() { tls2_next_.Add(time_coeff_.ab3, tls2_nm2_); tls2_next_gf_.SetFromTrueDofs(tls2_next_); */ - } void ZetaModel::updateZeta() { @@ -1793,7 +1821,7 @@ void ZetaModel::tkeStep() { // production Ms_->AddMult(prod_next_, res_, +1.0); - // destruction => 1/2 included in lhs + // explicit destruction tmpR0_.Set((1.0 - des_wgt_), tdr_next_); MsRho_->AddMult(tmpR0_, res_, -1.0); @@ -1886,7 +1914,7 @@ void ZetaModel::tdrStep() { } Ms_->AddMult(tmpR0_, res_, +1.0); - // destruction => 1/2 included in lhs + // explicit destruction tmpR0_.Set((1.0 - des_wgt_) * Ce2_, tdr_next_); tmpR0_ /= tts_next_; MsRho_->AddMult(tmpR0_, res_, -1.0); @@ -1898,16 +1926,16 @@ void ZetaModel::tdrStep() { diff_total_coeff_ = tdr_diff_total_coeff_; // boundary condition -> moved to after tke solve - //Array empty; - //Lk_form_->Update(); - //Lk_form_->Assemble(); + // Array empty; + // Lk_form_->Update(); + // Lk_form_->Assemble(); // Lk_form_->FormSystemMatrix(tke_ess_tdof_, Lk_); - //Lk_form_->FormSystemMatrix(empty, Lk_); - //Lk_->Mult(tke_next_, tmpR0_); - //MsRhoInv_->Mult(tmpR0_, tmpR0a_); - //tmpR0a_ *= -1.0; - //tdr_wall_gf_.SetFromTrueDofs(tmpR0a_); - + // Lk_form_->FormSystemMatrix(empty, Lk_); + // Lk_->Mult(tke_next_, tmpR0_); + // MsRhoInv_->Mult(tmpR0_, tmpR0a_); + // tmpR0a_ *= -1.0; + // tdr_wall_gf_.SetFromTrueDofs(tmpR0a_); + He_form_->Update(); He_form_->Assemble(); He_form_->FormSystemMatrix(tdr_ess_tdof_, He_); @@ -2029,6 +2057,12 @@ void ZetaModel::v2Step() { tmpR0_.Set(1.0, tke_next_); tmpR0_ *= fRate_; + // filter production + res_gf_.SetFromTrueDofs(tmpR0_); + filter_gf_.ProjectGridFunction(res_gf_); + res_gf_.ProjectGridFunction(filter_gf_); + res_gf_.GetTrueDofs(tmpR0_); + /* res_gf_.ProjectGridFunction(fRate_gf_); res_gf_.GetTrueDofs(tmpR0a_); @@ -2048,9 +2082,13 @@ void ZetaModel::v2Step() { */ MsRho_->AddMult(tmpR0_, res_, +1.0); - // destruction => 1/2 included in lhs + // explicit part of destruction tmpR0_.Set(6.0 * (1.0 - des_wgt_), tdr_next_); tmpR0_ *= zeta_; + res_gf_.SetFromTrueDofs(tmpR0_); + filter_gf_.ProjectGridFunction(res_gf_); + res_gf_.ProjectGridFunction(filter_gf_); + res_gf_.GetTrueDofs(tmpR0_); MsRho_->AddMult(tmpR0_, res_, -1.0); // Update Helmholtz operator to account for changing dt, rho, and kappa @@ -2086,25 +2124,25 @@ void ZetaModel::v2Step() { Hv_form_->RecoverFEMSolution(Xt2, res_gf_, v2_next_gf_); v2_next_gf_.GetTrueDofs(v2_next_); - if ( !(HvInv_->GetConverged()) ) { - if(rank0_) { + if (!(HvInv_->GetConverged())) { + if (rank0_) { std::cout << "Warnign: v2 not converged" << endl; - v2_next_.Set(1.0,v2_); - v2_next_gf_.SetFromTrueDofs(v2_next_); + v2_next_.Set(1.0, v2_); + v2_next_gf_.SetFromTrueDofs(v2_next_); } } // hard-clip { - const double *dtke = tke_next_.HostReadWrite(); + const double* dtke = tke_next_.HostReadWrite(); double* dv2 = v2_next_.HostReadWrite(); for (int i = 0; i < SdofInt_; i++) { dv2[i] = std::max(dv2[i], 0.0); - + // clip when used in certain areas, allow to be above 2/3k for destruction in v2 // dv2[i] = std::min(dv2[i], 2.0/3.0 * dtke[i]); - - // if (dv2[i] != dv2[i]) std::cout << " v2 is actually NaN!" << endl; + + // if (dv2[i] != dv2[i]) std::cout << " v2 is actually NaN!" << endl; } } v2_next_gf_.SetFromTrueDofs(v2_next_); @@ -2143,7 +2181,7 @@ void ZetaModel::fStep() { } for (int i = 0; i < SdofInt_; i++) { data[i] /= smoothMax(dk[i], tke_min_); - } + } } // intercept f res for viz // vfres_gf_.SetFromTrueDofs(tmpR0a_); @@ -2156,10 +2194,10 @@ void ZetaModel::fStep() { // neg to account for neg on rhs from ibp // NO, this is done in Mf_ line below... tmpR0a_.Neg(); - + // if not including L2 in laplacian term (but do have 1/L2 on the diaf term) - tmpR0a_ /= tls2_; - + // tmpR0a_ /= tls2_; + // filter f-source res_gf_.SetFromTrueDofs(tmpR0a_); filter_gf_.ProjectGridFunction(res_gf_); @@ -2168,10 +2206,10 @@ void ZetaModel::fStep() { resf_gf_.ProjectGridFunction(res_gf_); resf_gf_.GetTrueDofs(ftmpR0_); - // with diag in Hf pos and nabla neg (due to ibp), rhs needs a negative + // with diag in Hf pos and nabla neg (due to ibp), rhs needs a negative Mf_->AddMult(ftmpR0_, resf_, -1.0); resf_gf_.SetFromTrueDofs(resf_); - + // Update Helmholtz operator Hf_form_->Update(); Hf_form_->Assemble(); @@ -2213,7 +2251,6 @@ void ZetaModel::fStep() { fRate_gf_.SetFromTrueDofs(fRate_); } - // Based on code-friendly version but shifts the f-shift to production // and treats the destruction implicitly. Has the advantage of maintaining // correct destruction behavior with zeta and increasing diagonal dominance @@ -2223,19 +2260,34 @@ void ZetaModel::fStepRobustified() { res_ = 0.0; resf_ = 0.0; - // code-friendly form + // update implicit destruction + tmpR0_ = 0.0; + { + double* data = tmpR0_.HostReadWrite(); + double* dz = zeta_.HostReadWrite(); + double zetaCap; + double twoThree = 2.0 / 3.0; + double cd = C1_ * C3_; + double pd = C1_ - C4_; + for (int i = 0; i < sfes_->GetTrueVSize(); i++) { + zetaCap = std::min(dz[i], twoThree); + data[i] = cd * std::pow(zetaCap, pd); + } + } + res_gf_.SetFromTrueDofs(tmpR0_); + filter_gf_.ProjectGridFunction(res_gf_); + res_gf_.ProjectGridFunction(filter_gf_); + res_gf_.GetTrueDofs(tmpR0_); + Df_gf_.SetFromTrueDofs(tmpR0_); + + // "code-friendly" form // rhs: 1/T * [(C1-6)*v2/k - 2/3*(C1-1)] - C2*Pk/(rho*k) // lhs: L^2*nabla{f} - f - // robustified form - // Df = -(C1-1)(zeta-2/3) (note sign change so Df is (+) with zeta limited to 2/3) - // Pf = C2*Pk/k + 5*e/k - // f - L^2*nabla{f} = - // (I+Df-L^2*nabla){f} = Pf - - double Ctmp1, Ctmp2; - Ctmp1 = 2.0 / 3.0 * (C1_ - 1.0); - Ctmp2 = (C1_ - 6.0); + // "robustified" form + // rhs = -C1*5*zeta^(2-C4)/T + C2*Pk/k + 1/T(6*zeta + (C1-1)*2/3) + // lhs = (I+Df-L^2*nabla){f} + // Df = C1*C3*zeta^(1-C4) // C2*Pk/(rho*k) tmpR0b_.Set(C2_, prod_); @@ -2248,46 +2300,45 @@ void ZetaModel::fStepRobustified() { } } - // v2/k + // explicit part of destruction { - double twoThirds = 2.0 / 3.0; - const double* dv2 = v2_next_.HostRead(); - const double* dk = tke_next_.HostRead(); - double* data = tmpR0a_.HostReadWrite(); + const double* dz = zeta_.HostRead(); + const double* dT = tts_.HostRead(); + double* data = tmpR0b_.HostReadWrite(); + double zetaCap; + double twoThree = 2.0 / 3.0; + double cd = -C1_ * C3_ * 5.0; + double pd = 2.0 - C4_; for (int i = 0; i < SdofInt_; i++) { - data[i] = smoothMin(dv2[i], twoThirds * dk[i]); + zetaCap = std::min(dz[i], twoThree); + data[i] += cd * std::pow(zetaCap, pd) / dT[i]; } - for (int i = 0; i < SdofInt_; i++) { - data[i] /= smoothMax(dk[i], tke_min_); - } } - // intercept f res for viz - // vfres_gf_.SetFromTrueDofs(tmpR0a_); - // these terms are in L^2*nabla{f} - f = ... form - tmpR0a_ *= Ctmp2; - tmpR0a_ -= Ctmp1; - tmpR0a_ /= tts_; - tmpR0a_ -= tmpR0b_; + // shift and part of of Pf + { + const double* dz = zeta_.HostRead(); + const double* dT = tts_.HostRead(); + double* data = tmpR0b_.HostReadWrite(); + double zetaCap; + double twoThree = 2.0 / 3.0; + double cd = (C1_ - 1.0) * twoThree; + for (int i = 0; i < SdofInt_; i++) { + zetaCap = std::min(dz[i], twoThree); + data[i] += (6.0 * zetaCap + cd) / dT[i]; + } + } - // neg to account for neg on rhs from ibp - // NO, this is done in Mf_ line below... tmpR0a_.Neg(); - - // if not including L2 in laplacian term (but do have 1/L2 on the diaf term) - tmpR0a_ /= tls2_; - // filter f-source - res_gf_.SetFromTrueDofs(tmpR0a_); + res_gf_.SetFromTrueDofs(tmpR0b_); filter_gf_.ProjectGridFunction(res_gf_); res_gf_.ProjectGridFunction(filter_gf_); res_gf_.GetTrueDofs(tmpR0_); - resf_gf_.ProjectGridFunction(res_gf_); - resf_gf_.GetTrueDofs(ftmpR0_); - // with diag in Hf pos and nabla neg (due to ibp), rhs needs a negative - Mf_->AddMult(ftmpR0_, resf_, -1.0); + resf_ = 0.0; + Mf_->AddMult(tmpR0_, resf_, 1.0); resf_gf_.SetFromTrueDofs(resf_); - + // Update Helmholtz operator Hf_form_->Update(); Hf_form_->Assemble(); @@ -2329,7 +2380,6 @@ void ZetaModel::fStepRobustified() { fRate_gf_.SetFromTrueDofs(fRate_); } - /// TODO: pull in tensor gridscale and calc Mnn^T for wall-normal spacing void ZetaModel::updateBC(int step) { /* @@ -2355,7 +2405,6 @@ void ZetaModel::updateBC(int step) { } void ZetaModel::computeTDRwall() { - tmpR0_ = 0.0; Lk_bdry_->Update(); Lk_bdry_->Assemble(); @@ -2373,11 +2422,10 @@ void ZetaModel::computeTDRwall() { tke_lapl_gf_.SetFromTrueDofs(tke_lapl_); // update for and tdr inlets (add advection of tke later) - prod_plus_tkeDiff_.Set(1.0,prod_next_); + prod_plus_tkeDiff_.Set(1.0, prod_next_); prod_plus_tkeDiff_ /= rho_; - prod_plus_tkeDiff_.Add(1.0,tke_lapl_); + prod_plus_tkeDiff_.Add(1.0, tke_lapl_); prod_plus_tkeDiff_gf_.SetFromTrueDofs(prod_plus_tkeDiff_); - } /// Add a Dirichlet boundary condition to scalar fields @@ -2486,58 +2534,62 @@ void ZetaModel::AddFRATEDirichletBC(Coefficient* coeff, Array& attr) { } // Smoothed-min (C-infinity) function which does not over-shoot +// switched back to basic min for now as smoothed functions +// were causing issues with small numbers double smoothMin(double val1, double val2) { - //double C = 4.0; + // double C = 4.0; double k = 0.001; - double tanh_half = 0.54930615; + double tanh_half = 0.54930615; double val, arg, wt; - + // val = -1.0 / C * std::log(std::exp(-C * val1) + std::exp(-C * val2)); if (isnan(val1) | isinf(val1)) { - std::cout << "smin: BAD val1" << endl; + std::cout << "smin: BAD val1" << endl; + } + if (isnan(val2) | isinf(val2)) { + std::cout << "smin: BAD val2" << endl; } - if (isnan(val2) | isinf(val2)) { - std::cout << "smin: BAD val2" << endl; - } - - //arg = val1 / val2; - //arg = std::pow(arg,C); - //wt = std::tanh(tanh_half * arg); - //val = (1.0-wt) * val1 + wt * val2; - //val = 0.5 * (val1 + val2 - std::sqrt((val1-val2)*(val1-val2) + k)); + // arg = val1 / val2; + // arg = std::pow(arg,C); + // wt = std::tanh(tanh_half * arg); + // val = (1.0-wt) * val1 + wt * val2; + + // val = 0.5 * (val1 + val2 - std::sqrt((val1-val2)*(val1-val2) + k)); + + val = std::min(val1, val2); - val = std::min(val1,val2); - return val; } // Smoothed-max (C-infinity) function which does not under-shoot +// switched back to basic max for now as smoothed functions +// were causing issues with small numbers double smoothMax(double val1, double val2) { double C = 4.0; - double k = 0.001; + double k = 0.001; double tanh_half = 0.54930615; double val, arg, wt; - - //val = 1.0 / C * std::log(std::exp(C * val1) + std::exp(C * val2)); + + // val = 1.0 / C * std::log(std::exp(C * val1) + std::exp(C * val2)); if (isnan(val1) | isinf(val1)) { - std::cout << "smax: BAD val1" << endl; + std::cout << "smax: BAD val1" << endl; } - if (isnan(val2) | isinf(val2)) { - std::cout << "smax: BAD val2" << endl; + if (isnan(val2) | isinf(val2)) { + std::cout << "smax: BAD val2" << endl; } - - //arg = val1 / val2; - //arg = std::pow(arg,C); - //wt = std::tanh(tanh_half * arg); - //val = wt * val1 + (1.0 - wt) * val2; - //val = 0.5 * (val1 + val2 + std::sqrt((val1-val2)*(val1-val2) + k)); + // arg = val1 / val2; + // arg = std::pow(arg,C); + // wt = std::tanh(tanh_half * arg); + // val = wt * val1 + (1.0 - wt) * val2; + + // val = 0.5 * (val1 + val2 + std::sqrt((val1-val2)*(val1-val2) + k)); + + val = std::max(val1, val2); - val = std::max(val1,val2); - return val; } @@ -2545,27 +2597,26 @@ double smoothMax(double val1, double val2) { double smoothMinTwo(double val1, double val2) { double C = 20.0; double k = 0.001; - double tanh_half = 0.54930615; + double tanh_half = 0.54930615; double val, arg, wt; - + val = -1.0 / C * std::log(std::exp(-C * val1) + std::exp(-C * val2)); if (isnan(val1) | isinf(val1)) { - std::cout << "smin: BAD val1" << endl; + std::cout << "smin: BAD val1" << endl; + } + if (isnan(val2) | isinf(val2)) { + std::cout << "smin: BAD val2" << endl; } - if (isnan(val2) | isinf(val2)) { - std::cout << "smin: BAD val2" << endl; - } - - //arg = val1 / val2; - //arg = std::pow(arg,C); - //wt = std::tanh(tanh_half * arg); - //val = (1.0-wt) * val1 + wt * val2; - //val = 0.5 * (val1 + val2 - std::sqrt((val1-val2)*(val1-val2) + k)); + // arg = val1 / val2; + // arg = std::pow(arg,C); + // wt = std::tanh(tanh_half * arg); + // val = (1.0-wt) * val1 + wt * val2; + + // val = 0.5 * (val1 + val2 - std::sqrt((val1-val2)*(val1-val2) + k)); + + // val = std::min(val1,val2); - //val = std::min(val1,val2); - return val; } - diff --git a/src/zetaModel.hpp b/src/zetaModel.hpp index 63bdaf94..9f0c5537 100644 --- a/src/zetaModel.hpp +++ b/src/zetaModel.hpp @@ -103,6 +103,9 @@ class ZetaModel : public TurbModelBase { bool numerical_integ_ = false; // bool numerical_integ_ = true; + // alternative f-formulation + bool robust_ = false; + // Linear-solver-related options int pl_solve_ = 0; int max_iter_; // = 2000; @@ -123,7 +126,7 @@ class ZetaModel : public TurbModelBase { double zfp_max_; double v2Prod_fLimiter_coeff_; double mutMax_scale_; - + // streamwise stabilization bool sw_stab_ = false; /**< Enable/disable supg stabilization. */ double Reh_factor_, Reh_offset_; /**< supg stabilization parameters */ @@ -241,7 +244,10 @@ class ZetaModel : public TurbModelBase { ParGridFunction prod_plus_tkeDiff_gf_; Vector prod_plus_tkeDiff_; - + + // implicit part of destruction for f + ParGridFunction Df_gf_; + /// model coefficients double Cmu_ = 0.22; double sigmaK_ = 1.0; @@ -256,8 +262,10 @@ class ZetaModel : public TurbModelBase { // double Cn_ = 85.0; double Cl_ = 0.23; double Cn_ = 70.0; - double Ce1_; // function of local zeta - double inlet_scale_; + double Ce1_; // function of local zeta + double C3_ = 0.075; // tune + double C4_ = 1.28; // tune + double inlet_scale_; ParGridFunction res_gf_; Vector res_; @@ -311,6 +319,7 @@ class ZetaModel : public TurbModelBase { ProductCoefficient* rad_zeta_diff_total_coeff_ = nullptr; ProductCoefficient* rad_scalar_diff_coeff_ = nullptr; ScalarVectorProductCoefficient* rad_nu_gradTKE_coeff_ = nullptr; + ProductCoefficient* rad_tls2_coeff_ = nullptr; GridFunctionCoefficient* tts_coeff_ = nullptr; GridFunctionCoefficient* tls2_coeff_ = nullptr; @@ -355,11 +364,11 @@ class ZetaModel : public TurbModelBase { GridFunctionCoefficient* tke_field_ = nullptr; GridFunctionCoefficient* v2_field_ = nullptr; - GridFunctionCoefficient* tdr_field_ = nullptr; + GridFunctionCoefficient* tdr_field_ = nullptr; ProductCoefficient* tke_scaled_field_ = nullptr; ProductCoefficient* v2_scaled_field_ = nullptr; ConstantCoefficient* scaling_coeff_ = nullptr; - + // streamwise stabilization VectorMagnitudeCoefficient* umag_coeff_ = nullptr; GridFunctionCoefficient* gscale_coeff_ = nullptr; @@ -376,6 +385,8 @@ class ZetaModel : public TurbModelBase { TransformedMatrixVectorCoefficient* swdiff_coeff_ = nullptr; ScalarMatrixProductCoefficient* supg_coeff_ = nullptr; + GridFunctionCoefficient* f_destruction_coeff_ = nullptr; + /// operators and solvers ParBilinearForm* As_form_ = nullptr; ParBilinearForm* Ms_form_ = nullptr; @@ -457,7 +468,7 @@ class ZetaModel : public TurbModelBase { void zetaStep(); void v2Step(); void fStep(); - void fStepRobustified(); + void fStepRobustified(); void convection(string scalar); void updateTimestepHistory(); void updateZeta(); From 204e9bb628d8984ffefe15e9fc401925ed3fa34c Mon Sep 17 00:00:00 2001 From: Sigfried Haering Date: Wed, 1 Jul 2026 11:24:39 -0700 Subject: [PATCH 12/12] fix to joule heating scaling to prevent heating outside of torch --- src/quasimagnetostatic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quasimagnetostatic.cpp b/src/quasimagnetostatic.cpp index 01516c61..27da1009 100644 --- a/src/quasimagnetostatic.cpp +++ b/src/quasimagnetostatic.cpp @@ -699,7 +699,7 @@ double QuasiMagnetostaticSolver3D::elementJouleHeating(const FiniteElement& el, double qpcontrib = soln[0]; const double wt = ip.weight * Tr.Weight(); - elem_jh += qpcontrib * wt; + // elem_jh += qpcontrib * wt; // HERE // need to modify here so that joule heating is only IN torch @@ -718,7 +718,7 @@ double QuasiMagnetostaticSolver3D::elementJouleHeating(const FiniteElement& el, } dist = std::sqrt(dist); if (dist > rCyl) wgt = 0.0; - elem_jh *= wgt; + elem_jh += qpcontrib * wt * wgt; } return elem_jh;