From 9d36f3d7a505600173747999e0bd2ffd11d7a1f7 Mon Sep 17 00:00:00 2001 From: acrovato <a.crovato@uliege.be> Date: Fri, 20 Dec 2024 15:43:58 +0100 Subject: [PATCH] Add provisions for second order upwind formulation --- dart/src/wFluid.cpp | 1 + dart/src/wFluid.h | 2 + dart/src/wNewton.cpp | 24 +++++- dart/src/wPotentialResidual.cpp | 145 ++++++++++++++++++++++++++++++-- dart/src/wPotentialResidual.h | 8 +- dart/validation/onera.py | 2 + 6 files changed, 172 insertions(+), 10 deletions(-) diff --git a/dart/src/wFluid.cpp b/dart/src/wFluid.cpp index f150924..07b018e 100644 --- a/dart/src/wFluid.cpp +++ b/dart/src/wFluid.cpp @@ -98,6 +98,7 @@ void Fluid::createMap() } // Pair an element and its adjacent elements adjMap[i] = std::pair<Element *, std::vector<Element *>>(e, vAdjE); + adjMap2[e] = i; i++; } } diff --git a/dart/src/wFluid.h b/dart/src/wFluid.h index 600c35d..f8c594e 100644 --- a/dart/src/wFluid.h +++ b/dart/src/wFluid.h @@ -29,6 +29,7 @@ namespace dart /** * @brief Group of elements representing the fluid * @authors Adrien Crovato + * @todo replace adjMap by adjMap2 */ class DART_API Fluid : public tbox::Group { @@ -44,6 +45,7 @@ public: F0PsPhiInf *phiInf; ///< freestream potential std::vector<std::pair<tbox::Element *, std::vector<tbox::Element *>>> adjMap; ///< map of adjacent elements + std::map<tbox::Element *, size_t> adjMap2; ///< map of adjacent elements #endif Fluid(std::shared_ptr<tbox::MshData> _msh, int no, double mInf, int dim, double alpha, double beta); diff --git a/dart/src/wNewton.cpp b/dart/src/wNewton.cpp index f4b932f..30672cf 100644 --- a/dart/src/wNewton.cpp +++ b/dart/src/wNewton.cpp @@ -293,9 +293,11 @@ void Newton::buildJac(Eigen::SparseMatrix<double, Eigen::RowMajor> &J) Element *e = p.first; // Upwind element Element *eU = p.second[0]; + // Upwind-upwind element + Element *eUU = fluid->adjMap[fluid->adjMap2.at(eU)].second[0]; // Build elementary matrices - Eigen::MatrixXd Ae1, Ae2; - std::tie(Ae1, Ae2) = PotentialResidual::buildGradientFlow(*e, *eU, phi, *fluid, muCv, mCOv); + Eigen::MatrixXd Ae1, Ae2, Ae3; + std::tie(Ae1, Ae2, Ae3) = PotentialResidual::buildGradientFlow(*e, *eU, *eUU, phi, *fluid, muCv, mCOv); // Assembly (subsonic) std::deque<Eigen::Triplet<double>> &locT = cmbT.local(); @@ -323,6 +325,20 @@ void Newton::buildJac(Eigen::SparseMatrix<double, Eigen::RowMajor> &J) locT.push_back(Eigen::Triplet<double>(rows[nodi->row], nodj->row, Ae2(ii, jj))); } } + // Second order supersonic + double ratio = (e->computeGradient(phi, 0)(0) - eU->computeGradient(phi, 0)(0)) / (eU->computeGradient(phi, 0)(0) - eUU->computeGradient(phi, 0)(0)); + if (ratio >= 0.) + { + for (size_t ii = 0; ii < e->nodes.size(); ++ii) + { + Node *nodi = e->nodes[ii]; + for (size_t jj = 0; jj < eUU->nodes.size(); ++jj) + { + Node *nodj = eUU->nodes[jj]; + locT.push_back(Eigen::Triplet<double>(rows[nodi->row], nodj->row, Ae3(ii, jj))); + } + } + } } }); tms["0-Jbase"].stop(); @@ -430,8 +446,10 @@ void Newton::buildRes(Eigen::Map<Eigen::VectorXd> &R) Element *e = p.first; // Upwind element Element *eU = p.second[0]; + // Upwind-upwind element + Element *eUU = fluid->adjMap[fluid->adjMap2.at(eU)].second[0]; // Build elementary vector - Eigen::VectorXd be = PotentialResidual::build(*e, *eU, phi, *fluid, muCv, mCOv); + Eigen::VectorXd be = PotentialResidual::build(*e, *eU, *eUU, phi, *fluid, muCv, mCOv); // Assembly (subsonic) tbb::spin_mutex::scoped_lock lock(mutex); for (size_t ii = 0; ii < e->nodes.size(); ++ii) diff --git a/dart/src/wPotentialResidual.cpp b/dart/src/wPotentialResidual.cpp index 0a684f1..6ee3654 100644 --- a/dart/src/wPotentialResidual.cpp +++ b/dart/src/wPotentialResidual.cpp @@ -52,7 +52,7 @@ Eigen::MatrixXd PotentialResidual::buildFixed(Element const &e, std::vector<doub * * b = \int ( (1-mu)*rho + mu*rhoU ) * grad_phi * grad_psi dV */ -Eigen::VectorXd PotentialResidual::build(Element const &e, Element const &eU, std::vector<double> const &phi, Fluid const &fluid, double muC, double mCO) +Eigen::VectorXd PotentialResidual::build(Element const &e, Element const &eU, Element const &eUU, std::vector<double> const &phi, Fluid const &fluid, double muC, double mCO) { // Get pre-computed values Cache &cache = e.getVCache(); @@ -76,6 +76,63 @@ Eigen::VectorXd PotentialResidual::build(Element const &e, Element const &eU, st // contribution of upwind element for (size_t k = 0; k < gauss.getN(); ++k) b += mu * rhoU * (e.getJinv(k) * cache.getDsf(k)).transpose() * e.computeGradient(phi, k) * gauss.getW(k) * e.getDetJ(k); + + // second order upwind + double rhoUU = fluid.rho->eval(eUU, phi, 0); + double ratio = (e.computeGradient(phi, 0)(0) - eU.computeGradient(phi, 0)(0)) / (eU.computeGradient(phi, 0)(0) - eUU.computeGradient(phi, 0)(0)); + if (ratio >= 0.) + { + double alpha = 1.0; + if (ratio >= 1.00) + alpha = 1.00; + else if (ratio >= 0.95) + alpha = 0.95; + else if (ratio >= 0.90) + alpha = 0.90; + else if (ratio >= 0.85) + alpha = 0.85; + else if (ratio >= 0.80) + alpha = 0.80; + else if (ratio >= 0.75) + alpha = 0.75; + else if (ratio >= 0.70) + alpha = 0.70; + else if (ratio >= 0.65) + alpha = 0.65; + else if (ratio >= 0.60) + alpha = 0.60; + else if (ratio >= 0.55) + alpha = 0.55; + else if (ratio >= 0.50) + alpha = 0.50; + else if (ratio >= 0.45) + alpha = 0.45; + else if (ratio >= 0.40) + alpha = 0.40; + else if (ratio >= 0.35) + alpha = 0.35; + else if (ratio >= 0.30) + alpha = 0.30; + else if (ratio >= 0.25) + alpha = 0.25; + else if (ratio >= 0.20) + alpha = 0.20; + else if (ratio >= 0.15) + alpha = 0.15; + else if (ratio >= 0.10) + alpha = 0.10; + else if (ratio >= 0.05) + alpha = 0.05; + else + alpha = 0.025; + //alpha = (alpha < 0.5) ? alpha*2 : 1.0; + + for (size_t k = 0; k < gauss.getN(); ++k) + { + b += alpha * mu * rhoU * (e.getJinv(k) * cache.getDsf(k)).transpose() * e.computeGradient(phi, k) * gauss.getW(k) * e.getDetJ(k); + b -= alpha * mu * rhoUU * (e.getJinv(k) * cache.getDsf(k)).transpose() * e.computeGradient(phi, k) * gauss.getW(k) * e.getDetJ(k); + } + } } return b; } @@ -89,7 +146,7 @@ Eigen::VectorXd PotentialResidual::build(Element const &e, Element const &eU, st * + \int ( (1-mu)*rho + mu*rhoU ) * dgrad_phi * grad_psi dV * + \int (rhoU - rho)*dmu * grad_phi * grad_psi dV */ -std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientFlow(tbox::Element const &e, tbox::Element const &eU, std::vector<double> const &phi, Fluid const &fluid, double muC, double mCO) +std::tuple<Eigen::MatrixXd, Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientFlow(Element const &e, Element const &eU, Element const &eUU, std::vector<double> const &phi, Fluid const &fluid, double muC, double mCO) { // Get pre-computed values Cache &cache = e.getVCache(); @@ -111,7 +168,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientFlo } // Supersonic contribution - Eigen::MatrixXd A2; + Eigen::MatrixXd A2, A3; double machC = fluid.mach->eval(e, phi, 0); double machU = fluid.mach->eval(eU, phi, 0); double mach = (machC < machU) ? machU : machC; @@ -128,7 +185,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientFlo // upwinding A1 *= 1 - mu; - A2 = Eigen::MatrixXd::Zero(e.nodes.size(), e.nodes.size()); + A2 = Eigen::MatrixXd::Zero(e.nodes.size(), eU.nodes.size()); for (size_t k = 0; k < gauss.getN(); ++k) { // Gauss point and determinant @@ -147,8 +204,86 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> PotentialResidual::buildGradientFlo else A2 += dmu * (rhoU - fluid.rho->eval(e, phi, k)) * fluid.mach->evalGrad(eU, phi, k) * dSf.transpose() * dPhi * dPhiU.transpose() * dSfU * wdj; } + + // second order upwind + double rhoUU = fluid.rho->eval(eUU, phi, 0); + double ratio = (e.computeGradient(phi, 0)(0) - eU.computeGradient(phi, 0)(0)) / (eU.computeGradient(phi, 0)(0) - eUU.computeGradient(phi, 0)(0)); + if (ratio >= 0.) + { + double alpha = 1.0; + if (ratio >= 1.0) + alpha = 1.00; + else if (ratio >= 0.95) + alpha = 0.95; + else if (ratio >= 0.90) + alpha = 0.90; + else if (ratio >= 0.85) + alpha = 0.85; + else if (ratio >= 0.80) + alpha = 0.80; + else if (ratio >= 0.75) + alpha = 0.75; + else if (ratio >= 0.70) + alpha = 0.70; + else if (ratio >= 0.65) + alpha = 0.65; + else if (ratio >= 0.60) + alpha = 0.60; + else if (ratio >= 0.55) + alpha = 0.55; + else if (ratio >= 0.50) + alpha = 0.50; + else if (ratio >= 0.45) + alpha = 0.45; + else if (ratio >= 0.40) + alpha = 0.40; + else if (ratio >= 0.35) + alpha = 0.35; + else if (ratio >= 0.30) + alpha = 0.30; + else if (ratio >= 0.25) + alpha = 0.25; + else if (ratio >= 0.20) + alpha = 0.20; + else if (ratio >= 0.15) + alpha = 0.15; + else if (ratio >= 0.10) + alpha = 0.10; + else if (ratio >= 0.05) + alpha = 0.05; + else + alpha = 0.025; + //alpha = (alpha < 0.5) ? alpha*2 : 1.0; + + double dRhoUU = fluid.rho->evalGrad(eUU, phi, 0); + Eigen::VectorXd dPhiUU = eUU.computeGradient(phi, 0); + Eigen::MatrixXd const &dSfUU = eUU.getJinv(0) * eUU.getVCache().getDsf(0); + + A3 = Eigen::MatrixXd::Zero(e.nodes.size(), eUU.nodes.size()); + for (size_t k = 0; k < gauss.getN(); ++k) + { + // Gauss point and determinant + double wdj = gauss.getW(k) * e.getDetJ(k); + // Shape functions and solution gradient + Eigen::MatrixXd const &dSf = e.getJinv(k) * cache.getDsf(k); + Eigen::VectorXd dPhi = e.computeGradient(phi, k); + + // (mu * rhoU - mu * rhUU) * grad_phi * grad_psi + A1 += alpha * mu * rhoU * dSf.transpose() * dSf * wdj; + A1 -= alpha * mu * rhoUU * dSf.transpose() * dSf * wdj; + // mu * drhoU * grad_phi * grad_psi + A2 += alpha * mu * dRhoU * dSf.transpose() * dPhi * dPhiU.transpose() * dSfU * wdj; + // mu * drhoUU * grad_phi * grad_psi + A3 -= alpha * mu * dRhoUU * dSf.transpose() * dPhi * dPhiUU.transpose() * dSfUU * wdj; + // dmu(U) * (rhoU-rhoUU) * grad_phi * grad_psi + if (machC >= machU) + A1 += alpha * dmu * (rhoU - rhoUU) * fluid.mach->evalGrad(e, phi, k) * dSf.transpose() * dPhi * dPhi.transpose() * dSf * wdj; + else + A2 += alpha * dmu * (rhoU - rhoUU) * fluid.mach->evalGrad(eU, phi, k) * dSf.transpose() * dPhi * dPhiU.transpose() * dSfU * wdj; + } + } } - return std::make_tuple(A1, A2); + return std::make_tuple(A1, A2, A3); } /** diff --git a/dart/src/wPotentialResidual.h b/dart/src/wPotentialResidual.h index 5007fe1..e5b07cf 100644 --- a/dart/src/wPotentialResidual.h +++ b/dart/src/wPotentialResidual.h @@ -29,6 +29,10 @@ namespace dart * @brief Formulation of nonlinear potential equation residuals * @todo mu as F0ElMu? * @todo split stabilization terms from subsonic terms? + * @todo check that dR = J + * @todo fix SOU oscillations (improve limiter, without limiter, use divU/c (Ducross), use FOU then SOU?) + * @todo use aprox. Newton (do not use Ae3)? + * @todo clean second order upwind formulation */ class DART_API PotentialResidual { @@ -36,8 +40,8 @@ public: // Picard static Eigen::MatrixXd buildFixed(tbox::Element const &e, std::vector<double> const &phi, Fluid const &fluid); // Newton - static Eigen::VectorXd build(tbox::Element const &e, tbox::Element const &eU, std::vector<double> const &phi, Fluid const &fluid, double muC, double mCO); - static std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> buildGradientFlow(tbox::Element const &e, tbox::Element const &eU, std::vector<double> const &phi, Fluid const &fluid, double muC, double mCO); + static Eigen::VectorXd build(tbox::Element const &e, tbox::Element const &eU, tbox::Element const &eUU, std::vector<double> const &phi, Fluid const &fluid, double muC, double mCO); + static std::tuple<Eigen::MatrixXd, Eigen::MatrixXd, Eigen::MatrixXd> buildGradientFlow(tbox::Element const &e, tbox::Element const &eU, tbox::Element const &eUU, std::vector<double> const &phi, Fluid const &fluid, double muC, double mCO); // Adjoint static std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> buildGradientMesh(tbox::Element const &e, tbox::Element const &eU, std::vector<double> const &phi, Fluid const &fluid, int nDim, double muC, double mCO); }; diff --git a/dart/validation/onera.py b/dart/validation/onera.py index cc1c3d3..8b65b86 100644 --- a/dart/validation/onera.py +++ b/dart/validation/onera.py @@ -84,6 +84,8 @@ def main(): floU.write_slices(msh.name,[0.01, 0.239, 0.526, 0.777, 0.957, 1.076, 1.136, 1.184], 5) data = np.loadtxt(f'{msh.name}_slice_2.dat', delimiter=',', skiprows=2) floD.plot(data[:,0], data[:,-1], {'xlabel': 'x/c', 'ylabel': 'Cp', 'title': 'Pressure distribution at MAC', 'invert': True}) + data = np.loadtxt(f'{msh.name}_slice_3.dat', delimiter=',', skiprows=2) + floD.plot(data[:,0], data[:,-1], {'xlabel': 'x/c', 'ylabel': 'Cp', 'title': 'Pressure distribution at MAC', 'invert': True}) tms['post'].stop() # display timers -- GitLab