From 3d5fe299e7b08ab2bebf0fff5e51b4e7a10fce92 Mon Sep 17 00:00:00 2001 From: HOCH PHILIPPE <philippe.hoch@gmail.com> Date: Sun, 11 Aug 2024 19:48:01 +0200 Subject: [PATCH] mise a jour Rusanov v1 et rajout Rusanov v2 correction Cjf en 2d (vu pour certains maillages) --- src/language/modules/SchemeModule.cpp | 48 +- src/mesh/MeshData.hpp | 61 +- src/scheme/CMakeLists.txt | 2 + src/scheme/RusanovEulerianCompositeSolver.cpp | 724 +++++++-- src/scheme/RusanovEulerianCompositeSolver.hpp | 6 +- .../RusanovEulerianCompositeSolverTools.cpp | 89 ++ .../RusanovEulerianCompositeSolverTools.hpp | 24 + .../RusanovEulerianCompositeSolver_v2.cpp | 1397 +++++++++++++++++ .../RusanovEulerianCompositeSolver_v2.hpp | 29 + 9 files changed, 2227 insertions(+), 153 deletions(-) create mode 100644 src/scheme/RusanovEulerianCompositeSolverTools.cpp create mode 100644 src/scheme/RusanovEulerianCompositeSolverTools.hpp create mode 100644 src/scheme/RusanovEulerianCompositeSolver_v2.cpp create mode 100644 src/scheme/RusanovEulerianCompositeSolver_v2.hpp diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index 3960f2667..a37461b77 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -44,6 +44,7 @@ #include <scheme/NeumannBoundaryConditionDescriptor.hpp> #include <scheme/OutflowBoundaryConditionDescriptor.hpp> #include <scheme/RusanovEulerianCompositeSolver.hpp> +#include <scheme/RusanovEulerianCompositeSolver_v2.hpp> #include <scheme/SymmetryBoundaryConditionDescriptor.hpp> #include <scheme/VariableBCDescriptor.hpp> #include <utils/Socket.hpp> @@ -507,7 +508,7 @@ SchemeModule::SchemeModule() [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, const std::shared_ptr<const DiscreteFunctionVariant>& u, - const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& E, const double& gamma, const std::shared_ptr<const DiscreteFunctionVariant>& c, const std::shared_ptr<const DiscreteFunctionVariant>& p, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& @@ -515,7 +516,7 @@ SchemeModule::SchemeModule() const double& dt) -> std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> { - return rusanovEulerianCompositeSolver(rho, u, E, c, p, bc_descriptor_list, dt); + return rusanovEulerianCompositeSolver(rho, u, E, gamma, c, p, bc_descriptor_list, dt); } )); @@ -525,7 +526,43 @@ SchemeModule::SchemeModule() [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, const std::shared_ptr<const DiscreteFunctionVariant>& u, - const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& E, const double& gamma, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list, + const double& dt) -> std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + return rusanovEulerianCompositeSolver(rho, u, E, gamma, c, p, bc_descriptor_list, dt, + true); + } + + )); + + this->_addBuiltinFunction("rusanov_eulerian_composite_solver_version2", + std::function( + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, const double& gamma, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list, + const double& dt) -> std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + return rusanovEulerianCompositeSolver_v2(rho, u, E, gamma, c, p, bc_descriptor_list, + dt); + } + + )); + + this->_addBuiltinFunction("rusanov_eulerian_composite_solver_version2_with_checks", + std::function( + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, const double& gamma, const std::shared_ptr<const DiscreteFunctionVariant>& c, const std::shared_ptr<const DiscreteFunctionVariant>& p, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& @@ -533,7 +570,8 @@ SchemeModule::SchemeModule() const double& dt) -> std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> { - return rusanovEulerianCompositeSolver(rho, u, E, c, p, bc_descriptor_list, dt, true); + return rusanovEulerianCompositeSolver_v2(rho, u, E, gamma, c, p, bc_descriptor_list, dt, + true); } )); @@ -797,7 +835,7 @@ SchemeModule::SchemeModule() [](const std::shared_ptr<const DiscreteFunctionVariant>& u, const std::shared_ptr<const DiscreteFunctionVariant>& c) -> double { - return compute_dt(u, c); + return toolsCompositeSolver::compute_dt(u, c); })); this->_addBuiltinFunction("cell_volume", diff --git a/src/mesh/MeshData.hpp b/src/mesh/MeshData.hpp index a23d778a6..8016f370b 100644 --- a/src/mesh/MeshData.hpp +++ b/src/mesh/MeshData.hpp @@ -516,22 +516,7 @@ class MeshData<Mesh<Dimension>> Cjf(j, 1) = Rd{1}; }); m_Cjf = Cjf; - } else if constexpr (Dimension == 2) { - const NodeValue<const Rd>& xr = m_mesh.xr(); - const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); - - FaceValuePerCell<Rd> Cjf(m_mesh.connectivity()); - parallel_for( - m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { - const auto& cell_nodes = cell_to_node_matrix[j]; - for (size_t R = 0; R < cell_nodes.size(); ++R) { - int Rp = (R + 1) % cell_nodes.size(); - const Rd& xrp_xr = (xr[cell_nodes[Rp]] - xr[cell_nodes[R]]); - Cjf(j, R) = Rd{xrp_xr[1], -xrp_xr[0]}; - } - }); - m_Cjf = Cjf; - } else if (Dimension == 3) { + } else if (Dimension >= 2) { auto Nl = this->Nl(); const auto& cell_to_face_matrix = m_mesh.connectivity().cellToFaceMatrix(); @@ -609,20 +594,54 @@ class MeshData<Mesh<Dimension>> }); m_Cje = Cje; } else if constexpr (Dimension == 2) { + // EdgeValuePerCell<Rd> Cje(m_mesh.connectivity()); + // Cje = this->Cjf(); + // auto Cjf = this->Cjf(); + // m_xl = FaceValue<const Rd>{m_mesh.connectivity(), m_mesh.xr().arrayView()}; + m_Cje = EdgeValuePerCell<const Rd>{m_mesh.connectivity(), this->Cjf().arrayView()}; + /* const NodeValue<const Rd>& xr = m_mesh.xr(); + const auto& cell_to_edge_matrix = m_mesh.connectivity().cellToEdgeMatrix(); + const auto& edge_to_node_matrix = m_mesh.connectivity().edgeToNodeMatrix(); const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); + // const auto& cell_edge_is_reversed = m_mesh.connectivity().cellEgdeIsReversed(); + EdgeValuePerCell<Rd> Cje(m_mesh.connectivity()); parallel_for( m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { - const auto& cell_nodes = cell_to_node_matrix[j]; - for (size_t R = 0; R < cell_nodes.size(); ++R) { - int Rp = (R + 1) % cell_nodes.size(); - const Rd& xrp_xr = (xr[cell_nodes[Rp]] - xr[cell_nodes[R]]); - Cje(j, R) = Rd{xrp_xr[1], -xrp_xr[0]}; + const auto& cell_edge = cell_to_edge_matrix[j]; + const auto& cell_node = cell_to_node_matrix[j]; + assert(cell_edge.size() == cell_node.size()); + // size_t node_locl = 0; + for (size_t R = 0; R < cell_edge.size(); ++R) { + { + const EdgeId& edge_id = cell_edge[R]; + const auto& edges_nodes = edge_to_node_matrix[edge_id]; + + const NodeId& node0_id = edges_nodes[0]; + const NodeId& node1_id = edges_nodes[1]; + assert((node0_id == cell_node[R]) or (node0_id == cell_node[R])); + assert((node0_id == cell_node[(R + 1) % cell_node.size()]) or + (node0_id == cell_node[(R + 1) % cell_node.size()])); + + bool reversed = true; + if ((node0_id == cell_node[R]) and (node1_id == cell_node[(R + 1) % cell_node.size()])) + reversed = false; + + const Rd& xrp_xr = (xr[node1_id] - xr[node0_id]); + + if (reversed) + Cje(j, R) = -Rd{xrp_xr[1], -xrp_xr[0]}; + else + Cje(j, R) = Rd{xrp_xr[1], -xrp_xr[0]}; + + // node_locl++; + } } }); m_Cje = Cje; + */ } else if (Dimension == 3) { auto Nlr = this->Nlr(); diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt index 260582273..884906ec3 100644 --- a/src/scheme/CMakeLists.txt +++ b/src/scheme/CMakeLists.txt @@ -21,7 +21,9 @@ add_library( DiscreteFunctionVectorIntegrator.cpp DiscreteFunctionVectorInterpoler.cpp FluxingAdvectionSolver.cpp + RusanovEulerianCompositeSolverTools.cpp RusanovEulerianCompositeSolver.cpp + RusanovEulerianCompositeSolver_v2.cpp ) target_link_libraries( diff --git a/src/scheme/RusanovEulerianCompositeSolver.cpp b/src/scheme/RusanovEulerianCompositeSolver.cpp index e2c9f5af5..953ab6ec6 100644 --- a/src/scheme/RusanovEulerianCompositeSolver.cpp +++ b/src/scheme/RusanovEulerianCompositeSolver.cpp @@ -17,94 +17,6 @@ #include <variant> -template <class Rd> -double -EvaluateMaxEigenValueTimesNormalLengthInGivenDirection( // const double& rho_mean, - const Rd& U_mean, - // const double& E_mean, - const double& c_mean, - const Rd& normal) // const -{ - const double norme_normal = l2Norm(normal); - Rd unit_normal = normal; - unit_normal *= 1. / norme_normal; - const double uscaln = dot(U_mean, unit_normal); - - return std::max(std::fabs(uscaln - c_mean) * norme_normal, std::fabs(uscaln + c_mean) * norme_normal); -} - -double -compute_dt(const std::shared_ptr<const DiscreteFunctionVariant>& u_v, - const std::shared_ptr<const DiscreteFunctionVariant>& c_v) -{ - const auto& c = c_v->get<DiscreteFunctionP0<const double>>(); - - return std::visit( - [&](auto&& p_mesh) -> double { - const auto& mesh = *p_mesh; - - using MeshType = mesh_type_t<decltype(p_mesh)>; - static constexpr size_t Dimension = MeshType::Dimension; - using Rd = TinyVector<Dimension>; - - const auto& u = u_v->get<DiscreteFunctionP0<const Rd>>(); - - if constexpr (is_polygonal_mesh_v<MeshType>) { - const auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); - // const auto Sj = MeshDataManager::instance().getMeshData(mesh).sumOverRLjr(); - - const NodeValuePerCell<const Rd> Cjr = MeshDataManager::instance().getMeshData(mesh).Cjr(); - const NodeValuePerCell<const Rd> njr = MeshDataManager::instance().getMeshData(mesh).njr(); - - const FaceValuePerCell<const Rd> Cjf = MeshDataManager::instance().getMeshData(mesh).Cjf(); - const FaceValuePerCell<const Rd> njf = MeshDataManager::instance().getMeshData(mesh).njf(); - - const EdgeValuePerCell<const Rd> Cje = MeshDataManager::instance().getMeshData(mesh).Cje(); - const EdgeValuePerCell<const Rd> nje = MeshDataManager::instance().getMeshData(mesh).nje(); - - const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); - const auto& cell_to_edge_matrix = mesh.connectivity().cellToEdgeMatrix(); - const auto& cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); - - CellValue<double> local_dt{mesh.connectivity()}; - - parallel_for( - p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { - const auto& cell_to_node = cell_to_node_matrix[j]; - const auto& cell_to_edge = cell_to_edge_matrix[j]; - const auto& cell_to_face = cell_to_face_matrix[j]; - - double maxm(0); - for (size_t l = 0; l < cell_to_node.size(); ++l) { - const Rd normalCjr = Cjr(j, l); - // maxm = std::max(maxm, EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u, c, normalCjr)); - maxm += EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u[j], c[j], normalCjr); - } - for (size_t l = 0; l < cell_to_face.size(); ++l) { - const Rd normalCjf = Cjf(j, l); - // maxm = std::max(maxm, EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u, c, normalCjr)); - maxm += EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u[j], c[j], normalCjf); - } - - if constexpr (MeshType::Dimension == 3) { - for (size_t l = 0; l < cell_to_edge.size(); ++l) { - const Rd normalCje = Cje(j, l); - // maxm = std::max(maxm, EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u, c, normalCjr)); - maxm += EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u[j], c[j], normalCje); - } - } - - local_dt[j] = Vj[j] / maxm; //(Sj[j] * c[j]); - }); - - return min(local_dt); - } else { - throw NormalError("unexpected mesh type"); - } - }, - c.meshVariant()->variant()); -} - template <MeshConcept MeshTypeT> class RusanovEulerianCompositeSolver { @@ -122,9 +34,10 @@ class RusanovEulerianCompositeSolver class SymmetryBoundaryCondition; class InflowListBoundaryCondition; class OutflowBoundaryCondition; + class NeumannBoundaryCondition; - using BoundaryCondition = - std::variant<SymmetryBoundaryCondition, InflowListBoundaryCondition, OutflowBoundaryCondition>; + using BoundaryCondition = std:: + variant<SymmetryBoundaryCondition, InflowListBoundaryCondition, OutflowBoundaryCondition, NeumannBoundaryCondition>; using BoundaryConditionList = std::vector<BoundaryCondition>; @@ -226,6 +139,31 @@ class RusanovEulerianCompositeSolver return bc_list; } + public: + void _applyInflowBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const; + + void _applyOutflowBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const; + + void _applyWallBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const; + + void _applySymmetricBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const; + public: double EvaluateMaxEigenValueInGivenUnitDirection(const double& rho_mean, @@ -242,6 +180,12 @@ class RusanovEulerianCompositeSolver return std::max(std::fabs(uscaln - c_mean), std::fabs(uscaln + c_mean)); } + inline double + pression(const double rho, const double epsilon, const double gam) const + { + return (gam - 1) * rho * epsilon; + } + std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> @@ -249,6 +193,7 @@ class RusanovEulerianCompositeSolver const DiscreteFunctionP0<const double>& rho_n, const DiscreteFunctionP0<const Rd>& u_n, const DiscreteFunctionP0<const double>& E_n, + const double& gamma, const DiscreteFunctionP0<const double>& c_n, const DiscreteFunctionP0<const double>& p_n, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, @@ -280,6 +225,24 @@ class RusanovEulerianCompositeSolver }); // CellValue<Rp> State{p_mesh->connectivity()}; + NodeValuePerCell<Rp> StateAtNode{p_mesh->connectivity()}; + StateAtNode.fill(zero); + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { StateAtNode[j].fill(State[j]); }); + EdgeValuePerCell<Rp> StateAtEdge{p_mesh->connectivity()}; + StateAtEdge.fill(zero); + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { StateAtEdge[j].fill(State[j]); }); + FaceValuePerCell<Rp> StateAtFace{p_mesh->connectivity()}; + StateAtFace.fill(zero); + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { StateAtFace[j].fill(State[j]); }); + + // Conditions aux limites des etats conservatifs + + _applyInflowBoundaryCondition(bc_list, *p_mesh, StateAtNode, StateAtEdge, StateAtFace); + //_applyOutflowBoundaryCondition(bc_list, *p_mesh, StateAtNode, StateAtEdge, StateAtFace); + _applySymmetricBoundaryCondition(bc_list, *p_mesh, StateAtNode, StateAtEdge, StateAtFace); // // Construction du flux .. ok pour l'ordre 1 @@ -301,6 +264,174 @@ class RusanovEulerianCompositeSolver auto Flux_qtmvt = rhoUtensUPlusPid; // rhoUtensU + Pid; auto Flux_totnrj = (rhoE + p_n) * u; + // Flux avec prise en compte des states at Node/Edge/Face + + NodeValuePerCell<Rd> Flux_rhoAtCellNode{p_mesh->connectivity()}; + EdgeValuePerCell<Rd> Flux_rhoAtCellEdge{p_mesh->connectivity()}; + FaceValuePerCell<Rd> Flux_rhoAtCellFace{p_mesh->connectivity()}; + /* + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_to_node = cell_to_node_matrix[j]; + + for (size_t l = 0; l < cell_to_node.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_rhoAtCellNode[j][l][dim] = StateAtNode[j][l][0] * StateAtNode[j][l][dim]; + } + + const auto& cell_to_face = cell_to_face_matrix[j]; + + for (size_t l = 0; l < cell_to_face.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_rhoAtCellFace[j][l][dim] = StateAtFace[j][l][0] * StateAtFace[j][l][dim]; + } + + const auto& cell_to_edge = cell_to_edge_matrix[j]; + + for (size_t l = 0; l < cell_to_edge.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_rhoAtCellEdge[j][l][dim] = StateAtEdge[j][l][0] * StateAtEdge[j][l][dim]; + } + }); +*/ + NodeValuePerCell<Rdxd> Flux_qtmvtAtCellNode{p_mesh->connectivity()}; // = rhoUtensUPlusPid; // rhoUtensU + Pid; + EdgeValuePerCell<Rdxd> Flux_qtmvtAtCellEdge{p_mesh->connectivity()}; // = rhoUtensUPlusPid; // rhoUtensU + Pid; + FaceValuePerCell<Rdxd> Flux_qtmvtAtCellFace{p_mesh->connectivity()}; // = rhoUtensUPlusPid; // rhoUtensU + Pid; + /* + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_to_node = cell_to_node_matrix[j]; + + for (size_t l = 0; l < cell_to_node.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_qtmvtAtCellNode[j][l][dim] = StateAtNode[j][l][0] * StateAtNode[j][l][dim]; + } + + const auto& cell_to_face = cell_to_face_matrix[j]; + + for (size_t l = 0; l < cell_to_face.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_qtmvtAtCellFace[j][l][dim] = StateAtFace[j][l][0] * StateAtFace[j][l][dim]; + } + + const auto& cell_to_edge = cell_to_edge_matrix[j]; + + for (size_t l = 0; l < cell_to_edge.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_qtmvtAtCellEdge[j][l][dim] = StateAtEdge[j][l][0] * StateAtEdge[j][l][dim]; + } + }); +*/ + // parallel_for( + // p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + // Flux_qtmvtAtCellNode[j] = Flux_qtmvtAtCellEdge[j] = Flux_qtmvtAtCellFace[j] = Flux_qtmvt[j]; + // }); + + NodeValuePerCell<Rd> Flux_totnrjAtCellNode{p_mesh->connectivity()}; + EdgeValuePerCell<Rd> Flux_totnrjAtCellEdge{p_mesh->connectivity()}; + FaceValuePerCell<Rd> Flux_totnrjAtCellFace{p_mesh->connectivity()}; + + const auto& cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix(); + const auto& cell_to_edge_matrix = p_mesh->connectivity().cellToEdgeMatrix(); + const auto& cell_to_face_matrix = p_mesh->connectivity().cellToFaceMatrix(); + + Flux_rhoAtCellEdge.fill(zero); + Flux_totnrjAtCellEdge.fill(zero); + Flux_qtmvtAtCellEdge.fill(zero); + + // Les flux aux nodes/edge/faces + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_to_node = cell_to_node_matrix[j]; + + for (size_t l = 0; l < cell_to_node.size(); ++l) { + // Etats conservatifs aux noeuds + const double rhonode = StateAtNode[j][l][0]; + Rd Unode; + for (size_t dim = 0; dim < Dimension; ++dim) + Unode[dim] = StateAtNode[j][l][dim + 1] / rhonode; + const double rhoEnode = StateAtNode[j][l][Dimension + 1]; + // + const double Enode = rhoEnode / rhonode; + const double epsilonnode = Enode - .5 * dot(Unode, Unode); + const Rd rhoUnode = rhonode * Unode; + const Rdxd rhoUtensUnode = tensorProduct(rhoUnode, Unode); + + const double Pressionnode = pression(rhonode, epsilonnode, gamma); + + const double rhoEnodePlusP = rhoEnode + Pressionnode; + + Rdxd rhoUtensUPlusPidnode(identity); + rhoUtensUPlusPidnode *= Pressionnode; + rhoUtensUPlusPidnode += rhoUtensUnode; + + Flux_rhoAtCellNode[j][l] = rhoUnode; + Flux_qtmvtAtCellNode[j][l] = rhoUtensUPlusPidnode; + Flux_totnrjAtCellNode[j][l] = rhoEnodePlusP * Unode; + } + + const auto& cell_to_face = cell_to_face_matrix[j]; + + for (size_t l = 0; l < cell_to_face.size(); ++l) { + const double rhoface = StateAtFace[j][l][0]; + Rd Uface; + for (size_t dim = 0; dim < Dimension; ++dim) + Uface[dim] = StateAtFace[j][l][dim + 1] / rhoface; + const double rhoEface = StateAtFace[j][l][Dimension + 1]; + // + const double Eface = rhoEface / rhoface; + const double epsilonface = Eface - .5 * dot(Uface, Uface); + const Rd rhoUface = rhoface * Uface; + const Rdxd rhoUtensUface = tensorProduct(rhoUface, Uface); + + const double Pressionface = pression(rhoface, epsilonface, gamma); + + const double rhoEfacePlusP = rhoEface + Pressionface; + + Rdxd rhoUtensUPlusPidface(identity); + rhoUtensUPlusPidface *= Pressionface; + rhoUtensUPlusPidface += rhoUtensUface; + + Flux_rhoAtCellFace[j][l] = rhoUface; + Flux_qtmvtAtCellFace[j][l] = rhoUtensUPlusPidface; + Flux_totnrjAtCellFace[j][l] = rhoEfacePlusP * Uface; + } + + if constexpr (Dimension == 3) { + const auto& cell_to_edge = cell_to_edge_matrix[j]; + + for (size_t l = 0; l < cell_to_edge.size(); ++l) { + const double rhoedge = StateAtEdge[j][l][0]; + Rd Uedge; + for (size_t dim = 0; dim < Dimension; ++dim) + Uedge[dim] = StateAtEdge[j][l][dim + 1] / rhoedge; + const double rhoEedge = StateAtEdge[j][l][Dimension + 1]; + // + const double Eedge = rhoEedge / rhoedge; + const double epsilonedge = Eedge - .5 * dot(Uedge, Uedge); + const Rd rhoUedge = rhoedge * Uedge; + const Rdxd rhoUtensUedge = tensorProduct(rhoUedge, Uedge); + + const double Pressionedge = pression(rhoedge, epsilonedge, gamma); + + const double rhoEedgePlusP = rhoEedge + Pressionedge; + + Rdxd rhoUtensUPlusPidedge(identity); + rhoUtensUPlusPidedge *= Pressionedge; + rhoUtensUPlusPidedge += rhoUtensUedge; + + Flux_rhoAtCellEdge[j][l] = rhoUedge; + Flux_qtmvtAtCellEdge[j][l] = rhoUtensUPlusPidedge; + Flux_totnrjAtCellEdge[j][l] = rhoEedgePlusP * Uedge; + } + } + }); + + // parallel_for( + // p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + // Flux_totnrjAtCellNode[j] = Flux_totnrjAtCellEdge[j] = Flux_totnrjAtCellFace[j] = Flux_totnrj[j]; + // }); + MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(*p_mesh); auto volumes_cell = mesh_data.Vj(); @@ -351,10 +482,11 @@ class RusanovEulerianCompositeSolver const unsigned int R = node_local_number_in_its_cells[j]; const Rd& Cjr_loc = Cjr(J, R); - maxabsVpNormCjr = std::max(maxabsVpNormCjr, - EvaluateMaxEigenValueTimesNormalLengthInGivenDirection( // rhoNode, - uNode, // ENode, - cNode, Cjr_loc)); + maxabsVpNormCjr = + std::max(maxabsVpNormCjr, + toolsCompositeSolver::EvaluateMaxEigenValueTimesNormalLengthInGivenDirection( // rhoNode, + uNode, // ENode, + cNode, Cjr_loc)); } ViscosityNodeMatrix[l] *= maxabsVpNormCjr; }); @@ -392,17 +524,18 @@ class RusanovEulerianCompositeSolver const Rd& Cjf_loc = Cjf(J, R); - maxabsVpNormCjf = std::max(maxabsVpNormCjf, - EvaluateMaxEigenValueTimesNormalLengthInGivenDirection( // rhoEdge, - uFace, // EEdge, - cFace, Cjf_loc)); + maxabsVpNormCjf = + std::max(maxabsVpNormCjf, + toolsCompositeSolver::EvaluateMaxEigenValueTimesNormalLengthInGivenDirection( // rhoEdge, + uFace, // EEdge, + cFace, Cjf_loc)); } ViscosityFaceMatrix[l] *= maxabsVpNormCjf; }); // Computation of Viscosity Matrices at nodes and edges are done - // We may compute Gjr, Gje + // We may compute Gjr, Gjf NodeValuePerCell<Rp> Gjr{p_mesh->connectivity()}; Gjr.fill(zero); @@ -411,16 +544,14 @@ class RusanovEulerianCompositeSolver FaceValuePerCell<Rp> Gjf{p_mesh->connectivity()}; Gjf.fill(zero); - const auto& cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix(); - const auto& cell_to_edge_matrix = p_mesh->connectivity().cellToEdgeMatrix(); - const auto& cell_to_face_matrix = p_mesh->connectivity().cellToFaceMatrix(); - parallel_for( p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { const auto& cell_to_node = cell_to_node_matrix[j]; for (size_t l = 0; l < cell_to_node.size(); ++l) { - const NodeId& node = cell_to_node[l]; + const NodeId& node = cell_to_node[l]; + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(node); + const auto& node_to_cell = node_to_cell_matrix[node]; const Rd& Cjr_loc = Cjr(j, l); @@ -428,17 +559,18 @@ class RusanovEulerianCompositeSolver for (size_t k = 0; k < node_to_cell.size(); ++k) { const CellId K = node_to_cell[k]; + const size_t R = node_local_number_in_its_cells[k]; - const Rd& u_Cjr = Flux_qtmvt[K] * Cjr_loc; + const Rd& u_Cjr = Flux_qtmvtAtCellNode[K][R] * Cjr_loc; // Flux_qtmvt[K] * Cjr_loc; // const Rp& - statediff += State[j] - State[K]; + statediff += StateAtNode[j][l] - StateAtNode[K][R]; // State[j] - State[K]; // const Rp& diff = ViscosityNodeMatrix[node] * statediff; - Gjr[j][l][0] += dot(Flux_rho[K], Cjr_loc); + Gjr[j][l][0] += dot(Flux_rhoAtCellNode[K][R], Cjr_loc); // dot(Flux_rho[K], Cjr_loc); for (size_t d = 0; d < Dimension; ++d) Gjr[j][l][1 + d] += u_Cjr[d]; - Gjr[j][l][1 + Dimension] += dot(Flux_totnrj[K], Cjr_loc); + Gjr[j][l][1 + Dimension] += dot(Flux_totnrjAtCellNode[K][R], Cjr_loc); // dot(Flux_totnrj[K], Cjr_loc); // Gjr[j][l] += diff; } @@ -479,25 +611,28 @@ class RusanovEulerianCompositeSolver const auto& cell_to_face = cell_to_face_matrix[j]; for (size_t l = 0; l < cell_to_face.size(); ++l) { - const FaceId& face = cell_to_face[l]; + const FaceId& face = cell_to_face[l]; + const auto& face_local_number_in_its_cells = face_local_numbers_in_their_cells.itemArray(face); + const auto& face_to_cell = face_to_cell_matrix[face]; const Rd& Cjf_loc = Cjf(j, l); Rp statediff(zero); for (size_t k = 0; k < face_to_cell.size(); ++k) { - const CellId K = face_to_cell[k]; + const CellId K = face_to_cell[k]; + const unsigned int R = face_local_number_in_its_cells[k]; - const Rd& u_Cjf = Flux_qtmvt[K] * Cjf_loc; + const Rd& u_Cjf = Flux_qtmvtAtCellFace[K][R] * Cjf_loc; // Flux_qtmvt[K] * Cjf_loc; // const Rp& - statediff += State[j] - State[K]; + statediff += StateAtFace[j][l] - StateAtFace[K][R]; // State[j] - State[K]; // const Rp& diff = ViscosityFaceMatrix[face] * statediff; - Gjf[j][l][0] += dot(Flux_rho[K], Cjf_loc); + Gjf[j][l][0] += dot(Flux_rhoAtCellFace[K][R], Cjf_loc); // dot(Flux_rho[K], Cjf_loc); for (size_t d = 0; d < Dimension; ++d) Gjf[j][l][1 + d] += u_Cjf[d]; - Gjf[j][l][1 + Dimension] += dot(Flux_totnrj[K], Cjf_loc); + Gjf[j][l][1 + Dimension] += dot(Flux_totnrjAtCellFace[K][R], Cjf_loc); // dot(Flux_totnrj[K], Cjf_loc); // Gjf[j][l] += diff; } @@ -513,6 +648,9 @@ class RusanovEulerianCompositeSolver FaceValue<double> MaxErrorConservationFace(p_mesh->connectivity()); MaxErrorConservationFace.fill(0.); + // const auto& mesh_data = MeshDataManager::instance().getMeshData(*p_mesh); + auto xl = mesh_data.xl(); + auto Nl = mesh_data.Nl(); parallel_for( p_mesh->numberOfFaces(), PUGS_LAMBDA(FaceId l) { @@ -526,11 +664,21 @@ class RusanovEulerianCompositeSolver const unsigned int R = face_local_number_in_its_cells[k]; SumGjf += Gjf[K][R]; } + /* + std::cout << " maxErr face " << xl[l] << " err " << l2Norm(SumGjf) << " size face cell" + << face_to_cell.size() << " Cell " << face_to_cell[0] << " / " << face_to_cell[1] << " Cjf0 " + << Cjf(face_to_cell[0], 0) << " / Cjf1 " << Cjf(face_to_cell[1], 1) << "\n"; + + if (l2Norm(SumGjf) > 1e-3) + throw UnexpectedError("Pb consevvation face loc"); + */ MaxErrorConservationFace[l] = l2Norm(SumGjf); // MaxErrorConservationFace = std::max(MaxErrorConservationFace, l2Norm(SumGjf)); } }); std::cout << " Max Error Face " << max(MaxErrorConservationFace) << "\n"; + if (max(MaxErrorConservationFace) > 1e-3) + throw UnexpectedError("Pb conservation Face"); } if constexpr (Dimension == 3) { @@ -573,10 +721,11 @@ class RusanovEulerianCompositeSolver const Rd& Cje_loc = Cje(J, R); - maxabsVpNormCje = std::max(maxabsVpNormCje, - EvaluateMaxEigenValueTimesNormalLengthInGivenDirection( // rhoEdge, - uEdge, // EEdge, - cEdge, Cje_loc)); + maxabsVpNormCje = + std::max(maxabsVpNormCje, + toolsCompositeSolver::EvaluateMaxEigenValueTimesNormalLengthInGivenDirection( // rhoEdge, + uEdge, // EEdge, + cEdge, Cje_loc)); } ViscosityEdgeMatrix[l] *= maxabsVpNormCje; }); @@ -587,7 +736,9 @@ class RusanovEulerianCompositeSolver const auto& cell_to_edge = cell_to_edge_matrix[j]; for (size_t l = 0; l < cell_to_edge.size(); ++l) { - const EdgeId& edge = cell_to_edge[l]; + const EdgeId& edge = cell_to_edge[l]; + const auto& edge_local_number_in_its_cells = edge_local_numbers_in_their_cells.itemArray(edge); + const auto& edge_to_cell = edge_to_cell_matrix[edge]; const Rd& Cje_loc = Cje(j, l); @@ -595,17 +746,18 @@ class RusanovEulerianCompositeSolver for (size_t k = 0; k < edge_to_cell.size(); ++k) { const CellId K = edge_to_cell[k]; + const size_t R = edge_local_number_in_its_cells[k]; - const Rd& u_Cje = Flux_qtmvt[K] * Cje_loc; + const Rd& u_Cje = Flux_qtmvtAtCellEdge[K][R] * Cje_loc; // Flux_qtmvt[K] * Cje_loc; // const Rp& - statediff += State[j] - State[K]; + statediff += StateAtEdge[j][l] - StateAtEdge[K][R]; // State[j] - State[K]; // const Rp& diff = ViscosityEdgeMatrix[edge] * statediff; - Gje[j][l][0] += dot(Flux_rho[K], Cje_loc); + Gje[j][l][0] += dot(Flux_rhoAtCellEdge[K][R], Cje_loc); // dot(Flux_rho[K], Cje_loc); for (size_t d = 0; d < Dimension; ++d) Gje[j][l][1 + d] += u_Cje[d]; - Gje[j][l][1 + Dimension] += dot(Flux_totnrj[K], Cje_loc); + Gje[j][l][1 + Dimension] += dot(Flux_totnrjAtCellEdge[K][R], Cje_loc); // dot(Flux_totnrj[K], Cje_loc); // Gje[j][l] += diff; } @@ -700,8 +852,108 @@ class RusanovEulerianCompositeSolver }; template <MeshConcept MeshType> -class RusanovEulerianCompositeSolver<MeshType>::SymmetryBoundaryCondition +class RusanovEulerianCompositeSolver<MeshType>::NeumannBoundaryCondition +{ +}; + +template <> +class RusanovEulerianCompositeSolver<Mesh<2>>::NeumannBoundaryCondition +{ + using Rd = TinyVector<Dimension, double>; + + private: + const MeshNodeBoundary m_mesh_node_boundary; + const MeshFaceBoundary m_mesh_face_boundary; + + public: + size_t + numberOfNodes() const + { + return m_mesh_node_boundary.nodeList().size(); + } + + size_t + numberOfFaces() const + { + return m_mesh_face_boundary.faceList().size(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + NeumannBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary, const MeshFaceBoundary& mesh_face_boundary) + : m_mesh_node_boundary(mesh_node_boundary), m_mesh_face_boundary(mesh_face_boundary) + { + ; + } +}; + +template <> +class RusanovEulerianCompositeSolver<Mesh<3>>::NeumannBoundaryCondition { + using Rd = TinyVector<Dimension, double>; + + private: + const MeshNodeBoundary m_mesh_node_boundary; + const MeshEdgeBoundary m_mesh_edge_boundary; + const MeshFaceBoundary m_mesh_face_boundary; + + public: + size_t + numberOfNodes() const + { + return m_mesh_node_boundary.nodeList().size(); + } + size_t + numberOfEdges() const + { + return m_mesh_edge_boundary.edgeList().size(); + } + + size_t + numberOfFaces() const + { + return m_mesh_face_boundary.faceList().size(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const EdgeId>& + edgeList() const + { + return m_mesh_edge_boundary.edgeList(); + } + + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + NeumannBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary, + const MeshEdgeBoundary& mesh_edge_boundary, + const MeshFaceBoundary& mesh_face_boundary) + : m_mesh_node_boundary(mesh_node_boundary), + + m_mesh_edge_boundary(mesh_edge_boundary), + + m_mesh_face_boundary(mesh_face_boundary) + { + ; + } }; template <> @@ -991,6 +1243,7 @@ rusanovEulerianCompositeSolver( const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, const std::shared_ptr<const DiscreteFunctionVariant>& u_v, const std::shared_ptr<const DiscreteFunctionVariant>& E_v, + const double& gamma, const std::shared_ptr<const DiscreteFunctionVariant>& c_v, const std::shared_ptr<const DiscreteFunctionVariant>& p_v, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, @@ -1021,7 +1274,7 @@ rusanovEulerianCompositeSolver( return RusanovEulerianCompositeSolver<MeshType>{}.solve(p_mesh, rho_v->get<DiscreteFunctionP0<const double>>(), u_v->get<DiscreteFunctionP0<const Rd>>(), - E_v->get<DiscreteFunctionP0<const double>>(), + E_v->get<DiscreteFunctionP0<const double>>(), gamma, c_v->get<DiscreteFunctionP0<const double>>(), p_v->get<DiscreteFunctionP0<const double>>(), bc_descriptor_list, dt, check); @@ -1032,3 +1285,224 @@ rusanovEulerianCompositeSolver( }, mesh_v->variant()); } + +template <MeshConcept MeshType> +void +RusanovEulerianCompositeSolver<MeshType>::_applyOutflowBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<OutflowBoundaryCondition, T>) { + throw NormalError("Not implemented"); + } + }, + boundary_condition); + } +} + +template <MeshConcept MeshType> +void +RusanovEulerianCompositeSolver<MeshType>::_applySymmetricBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<SymmetryBoundaryCondition, T>) { + // MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + std::cout << " Traitement SYMMETRY \n"; + const Rd& normal = bc.outgoingNormal(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + const auto& face_local_numbers_in_their_cells = mesh.connectivity().faceLocalNumbersInTheirCells(); + // const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed(); + + const auto& face_list = bc.faceList(); + const auto& node_list = bc.nodeList(); + + for (size_t i_node = 0; i_node < node_list.size(); ++i_node) { + const NodeId node_id = node_list[i_node]; + + const auto& node_cell_list = node_to_cell_matrix[node_id]; + // Assert(face_cell_list.size() == 1); + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(node_id); + + for (size_t i_cell = 0; i_cell < node_cell_list.size(); ++i_cell) { + CellId node_cell_id = node_cell_list[i_cell]; + size_t node_local_number_in_cell = node_local_number_in_its_cells[i_cell]; + + Rd vectorSym(zero); + for (size_t dim = 0; dim < Dimension; ++dim) + vectorSym[dim] = stateNode[node_cell_id][node_local_number_in_cell][1 + dim]; + + Rdxd MatriceProj(identity); + MatriceProj -= tensorProduct(normal, normal); + vectorSym = MatriceProj * vectorSym; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateNode[node_cell_id][node_local_number_in_cell][dim + 1] = vectorSym[dim]; + // stateNode[node_cell_id][node_local_number_in_cell][dim] = 0; // node_array_list[i_node][dim]; + } + } + + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + + const auto& face_cell_list = face_to_cell_matrix[face_id]; + Assert(face_cell_list.size() == 1); + + CellId face_cell_id = face_cell_list[0]; + size_t face_local_number_in_cell = face_local_numbers_in_their_cells(face_id, 0); + + Rd vectorSym(zero); + for (size_t dim = 0; dim < Dimension; ++dim) + vectorSym[dim] = stateEdge[face_cell_id][face_local_number_in_cell][1 + dim]; + + Rdxd MatriceProj(identity); + MatriceProj -= tensorProduct(normal, normal); + vectorSym = MatriceProj * vectorSym; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateFace[face_cell_id][face_local_number_in_cell][dim + 1] = vectorSym[dim]; + } + + if constexpr (Dimension == 3) { + const auto& edge_to_cell_matrix = mesh.connectivity().edgeToCellMatrix(); + + const auto& edge_local_numbers_in_their_cells = mesh.connectivity().edgeLocalNumbersInTheirCells(); + + const auto& edge_list = bc.edgeList(); + + for (size_t i_edge = 0; i_edge < edge_list.size(); ++i_edge) { + const EdgeId edge_id = edge_list[i_edge]; + + const auto& edge_cell_list = edge_to_cell_matrix[edge_id]; + // Assert(face_cell_list.size() == 1); + const auto& edge_local_number_in_its_cells = edge_local_numbers_in_their_cells.itemArray(edge_id); + + for (size_t i_cell = 0; i_cell < edge_cell_list.size(); ++i_cell) { + CellId edge_cell_id = edge_cell_list[i_cell]; + size_t edge_local_number_in_cell = edge_local_number_in_its_cells[i_cell]; + + Rd vectorSym(zero); + for (size_t dim = 0; dim < Dimension; ++dim) + vectorSym[dim] = stateEdge[edge_cell_id][edge_local_number_in_cell][1 + dim]; + + Rdxd MatriceProj(identity); + MatriceProj -= tensorProduct(normal, normal); + vectorSym = MatriceProj * vectorSym; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateEdge[edge_cell_id][edge_local_number_in_cell][dim + 1] = vectorSym[dim]; + } + } + } + } + }, + boundary_condition); + } +} + +template <MeshConcept MeshType> +void +RusanovEulerianCompositeSolver<MeshType>::_applyInflowBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<InflowListBoundaryCondition, T>) { + // MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + std::cout << " Traitement INFLOW \n"; + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + const auto& face_local_numbers_in_their_cells = mesh.connectivity().faceLocalNumbersInTheirCells(); + // const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed(); + + const auto& face_list = bc.faceList(); + const auto& node_list = bc.nodeList(); + + const auto& face_array_list = bc.faceArrayList(); + const auto& node_array_list = bc.nodeArrayList(); + + for (size_t i_node = 0; i_node < node_list.size(); ++i_node) { + const NodeId node_id = node_list[i_node]; + + const auto& node_cell_list = node_to_cell_matrix[node_id]; + // Assert(face_cell_list.size() == 1); + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(node_id); + + for (size_t i_cell = 0; i_cell < node_cell_list.size(); ++i_cell) { + CellId node_cell_id = node_cell_list[i_cell]; + size_t node_local_number_in_cell = node_local_number_in_its_cells[i_cell]; + + for (size_t dim = 0; dim < Dimension + 2; ++dim) + stateNode[node_cell_id][node_local_number_in_cell][dim] = node_array_list[i_node][dim]; + } + } + + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + + const auto& face_cell_list = face_to_cell_matrix[face_id]; + Assert(face_cell_list.size() == 1); + + CellId face_cell_id = face_cell_list[0]; + size_t face_local_number_in_cell = face_local_numbers_in_their_cells(face_id, 0); + + for (size_t dim = 0; dim < Dimension + 2; ++dim) + stateFace[face_cell_id][face_local_number_in_cell][dim] = face_array_list[i_face][dim]; + } + + if constexpr (Dimension == 3) { + const auto& edge_to_cell_matrix = mesh.connectivity().edgeToCellMatrix(); + + const auto& edge_local_numbers_in_their_cells = mesh.connectivity().edgeLocalNumbersInTheirCells(); + // const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed(); + + const auto& edge_list = bc.edgeList(); + + const auto& edge_array_list = bc.edgeArrayList(); + + for (size_t i_edge = 0; i_edge < edge_list.size(); ++i_edge) { + const EdgeId edge_id = edge_list[i_edge]; + + const auto& edge_cell_list = edge_to_cell_matrix[edge_id]; + const auto& edge_local_number_in_its_cells = edge_local_numbers_in_their_cells.itemArray(edge_id); + + // Assert(face_cell_list.size() == 1); + + for (size_t i_cell = 0; i_cell < edge_cell_list.size(); ++i_cell) { + CellId edge_cell_id = edge_cell_list[i_cell]; + size_t edge_local_number_in_cell = edge_local_number_in_its_cells[i_cell]; + + for (size_t dim = 0; dim < Dimension + 2; ++dim) + stateEdge[edge_cell_id][edge_local_number_in_cell][dim] = edge_array_list[i_edge][dim]; + } + } + } + } + }, + boundary_condition); + } +} diff --git a/src/scheme/RusanovEulerianCompositeSolver.hpp b/src/scheme/RusanovEulerianCompositeSolver.hpp index 357adf245..593b6f763 100644 --- a/src/scheme/RusanovEulerianCompositeSolver.hpp +++ b/src/scheme/RusanovEulerianCompositeSolver.hpp @@ -4,12 +4,13 @@ #include <mesh/MeshVariant.hpp> #include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/RusanovEulerianCompositeSolverTools.hpp> #include <memory> #include <vector> -double compute_dt(const std::shared_ptr<const DiscreteFunctionVariant>& u_v, - const std::shared_ptr<const DiscreteFunctionVariant>& c_v); +// double compute_dt(const std::shared_ptr<const DiscreteFunctionVariant>& u_v, +// const std::shared_ptr<const DiscreteFunctionVariant>& c_v); std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>, @@ -18,6 +19,7 @@ rusanovEulerianCompositeSolver( const std::shared_ptr<const DiscreteFunctionVariant>& rho, const std::shared_ptr<const DiscreteFunctionVariant>& u, const std::shared_ptr<const DiscreteFunctionVariant>& E, + const double& gamma, const std::shared_ptr<const DiscreteFunctionVariant>& c, const std::shared_ptr<const DiscreteFunctionVariant>& p, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, diff --git a/src/scheme/RusanovEulerianCompositeSolverTools.cpp b/src/scheme/RusanovEulerianCompositeSolverTools.cpp new file mode 100644 index 000000000..d4055d7e9 --- /dev/null +++ b/src/scheme/RusanovEulerianCompositeSolverTools.cpp @@ -0,0 +1,89 @@ +#include <scheme/RusanovEulerianCompositeSolverTools.hpp> + +template <class Rd> +double +toolsCompositeSolver::EvaluateMaxEigenValueTimesNormalLengthInGivenDirection( // const double& rho_mean, + const Rd& U_mean, + // const double& E_mean, + const double& c_mean, + const Rd& normal) // const +{ + const double norme_normal = l2Norm(normal); + Rd unit_normal = normal; + unit_normal *= 1. / norme_normal; + const double uscaln = dot(U_mean, unit_normal); + + return std::max(std::fabs(uscaln - c_mean) * norme_normal, std::fabs(uscaln + c_mean) * norme_normal); +} + +double +toolsCompositeSolver::compute_dt(const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& c_v) +{ + const auto& c = c_v->get<DiscreteFunctionP0<const double>>(); + + return std::visit( + [&](auto&& p_mesh) -> double { + const auto& mesh = *p_mesh; + + using MeshType = mesh_type_t<decltype(p_mesh)>; + static constexpr size_t Dimension = MeshType::Dimension; + using Rd = TinyVector<Dimension>; + + const auto& u = u_v->get<DiscreteFunctionP0<const Rd>>(); + + if constexpr (is_polygonal_mesh_v<MeshType>) { + const auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); + // const auto Sj = MeshDataManager::instance().getMeshData(mesh).sumOverRLjr(); + + const NodeValuePerCell<const Rd> Cjr = MeshDataManager::instance().getMeshData(mesh).Cjr(); + const NodeValuePerCell<const Rd> njr = MeshDataManager::instance().getMeshData(mesh).njr(); + + const FaceValuePerCell<const Rd> Cjf = MeshDataManager::instance().getMeshData(mesh).Cjf(); + const FaceValuePerCell<const Rd> njf = MeshDataManager::instance().getMeshData(mesh).njf(); + + const EdgeValuePerCell<const Rd> Cje = MeshDataManager::instance().getMeshData(mesh).Cje(); + const EdgeValuePerCell<const Rd> nje = MeshDataManager::instance().getMeshData(mesh).nje(); + + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_edge_matrix = mesh.connectivity().cellToEdgeMatrix(); + const auto& cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); + + CellValue<double> local_dt{mesh.connectivity()}; + + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_to_node = cell_to_node_matrix[j]; + const auto& cell_to_edge = cell_to_edge_matrix[j]; + const auto& cell_to_face = cell_to_face_matrix[j]; + + double maxm(0); + for (size_t l = 0; l < cell_to_node.size(); ++l) { + const Rd normalCjr = Cjr(j, l); + // maxm = std::max(maxm, EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u, c, normalCjr)); + maxm += EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u[j], c[j], normalCjr); + } + for (size_t l = 0; l < cell_to_face.size(); ++l) { + const Rd normalCjf = Cjf(j, l); + // maxm = std::max(maxm, EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u, c, normalCjr)); + maxm += EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u[j], c[j], normalCjf); + } + + if constexpr (MeshType::Dimension == 3) { + for (size_t l = 0; l < cell_to_edge.size(); ++l) { + const Rd normalCje = Cje(j, l); + // maxm = std::max(maxm, EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u, c, normalCjr)); + maxm += EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(u[j], c[j], normalCje); + } + } + + local_dt[j] = Vj[j] / maxm; //(Sj[j] * c[j]); + }); + + return min(local_dt); + } else { + throw NormalError("unexpected mesh type"); + } + }, + c.meshVariant()->variant()); +} diff --git a/src/scheme/RusanovEulerianCompositeSolverTools.hpp b/src/scheme/RusanovEulerianCompositeSolverTools.hpp new file mode 100644 index 000000000..cc2a4477c --- /dev/null +++ b/src/scheme/RusanovEulerianCompositeSolverTools.hpp @@ -0,0 +1,24 @@ +#ifndef RUSANOV_EULERIAN_COMPOSITE_SOLVER_TOOLS_HPP +#define RUSANOV_EULERIAN_COMPOSITE_SOLVER_TOOLS_HPP + +#include <mesh/MeshVariant.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> + +#include <memory> +#include <vector> + +namespace toolsCompositeSolver +{ +template <class Rd> +double EvaluateMaxEigenValueTimesNormalLengthInGivenDirection( // const double& rho_mean, + const Rd& U_mean, + // const double& E_mean, + const double& c_mean, + const Rd& normal); + +double compute_dt(const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& c_v); + +} // namespace toolsCompositeSolver +#endif diff --git a/src/scheme/RusanovEulerianCompositeSolver_v2.cpp b/src/scheme/RusanovEulerianCompositeSolver_v2.cpp new file mode 100644 index 000000000..3bfe9a877 --- /dev/null +++ b/src/scheme/RusanovEulerianCompositeSolver_v2.cpp @@ -0,0 +1,1397 @@ +#include <scheme/RusanovEulerianCompositeSolver_v2.hpp> + +#include <language/utils/InterpolateItemArray.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshData.hpp> +#include <mesh/MeshDataManager.hpp> +#include <mesh/MeshEdgeBoundary.hpp> +#include <mesh/MeshFaceBoundary.hpp> +#include <mesh/MeshFlatEdgeBoundary.hpp> +#include <mesh/MeshFlatFaceBoundary.hpp> +#include <mesh/MeshFlatNodeBoundary.hpp> +#include <mesh/MeshNodeBoundary.hpp> +#include <mesh/MeshTraits.hpp> +#include <mesh/MeshVariant.hpp> +#include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/InflowListBoundaryConditionDescriptor.hpp> + +#include <variant> + +template <MeshConcept MeshTypeT> +class RusanovEulerianCompositeSolver_v2 +{ + private: + using MeshType = MeshTypeT; + + static constexpr size_t Dimension = MeshType::Dimension; + + using Rdxd = TinyMatrix<Dimension>; + using Rd = TinyVector<Dimension>; + + using Rpxp = TinyMatrix<Dimension + 2>; + using Rp = TinyVector<Dimension + 2>; + + class SymmetryBoundaryCondition; + class InflowListBoundaryCondition; + class OutflowBoundaryCondition; + class NeumannBoundaryCondition; + + using BoundaryCondition = std:: + variant<SymmetryBoundaryCondition, InflowListBoundaryCondition, OutflowBoundaryCondition, NeumannBoundaryCondition>; + + using BoundaryConditionList = std::vector<BoundaryCondition>; + + BoundaryConditionList + _getBCList(const MeshType& mesh, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + BoundaryConditionList bc_list; + + for (const auto& bc_descriptor : bc_descriptor_list) { + bool is_valid_boundary_condition = true; + + switch (bc_descriptor->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + if constexpr (Dimension == 2) { + bc_list.emplace_back( + SymmetryBoundaryCondition(getMeshFlatNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFlatFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + } else { + static_assert(Dimension == 3); + bc_list.emplace_back( + SymmetryBoundaryCondition(getMeshFlatNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFlatEdgeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFlatFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + } + break; + } + case IBoundaryConditionDescriptor::Type::inflow_list: { + const InflowListBoundaryConditionDescriptor& inflow_list_bc_descriptor = + dynamic_cast<const InflowListBoundaryConditionDescriptor&>(*bc_descriptor); + if (inflow_list_bc_descriptor.functionSymbolIdList().size() != 2 + Dimension) { + std::ostringstream error_msg; + error_msg << "invalid number of functions for inflow boundary " + << inflow_list_bc_descriptor.boundaryDescriptor() << ", found " + << inflow_list_bc_descriptor.functionSymbolIdList().size() << ", expecting " << 2 + Dimension; + throw NormalError(error_msg.str()); + } + + if constexpr (Dimension == 2) { + auto node_boundary = getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()); + Table<const double> node_values = + InterpolateItemArray<double(Rd)>::template interpolate<ItemType::node>(inflow_list_bc_descriptor + .functionSymbolIdList(), + mesh.xr(), node_boundary.nodeList()); + + auto xl = MeshDataManager::instance().getMeshData(mesh).xl(); + + auto face_boundary = getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()); + Table<const double> face_values = + InterpolateItemArray<double(Rd)>::template interpolate<ItemType::face>(inflow_list_bc_descriptor + .functionSymbolIdList(), + xl, face_boundary.faceList()); + + bc_list.emplace_back(InflowListBoundaryCondition(node_boundary, face_boundary, node_values, face_values)); + } else { + static_assert(Dimension == 3); + auto node_boundary = getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()); + Table<const double> node_values = + InterpolateItemArray<double(Rd)>::template interpolate<ItemType::node>(inflow_list_bc_descriptor + .functionSymbolIdList(), + mesh.xr(), node_boundary.nodeList()); + + auto xe = MeshDataManager::instance().getMeshData(mesh).xe(); + + auto edge_boundary = getMeshEdgeBoundary(mesh, bc_descriptor->boundaryDescriptor()); + Table<const double> edge_values = + InterpolateItemArray<double(Rd)>::template interpolate<ItemType::edge>(inflow_list_bc_descriptor + .functionSymbolIdList(), + xe, edge_boundary.edgeList()); + + auto xl = MeshDataManager::instance().getMeshData(mesh).xl(); + + auto face_boundary = getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()); + Table<const double> face_values = + InterpolateItemArray<double(Rd)>::template interpolate<ItemType::face>(inflow_list_bc_descriptor + .functionSymbolIdList(), + xl, face_boundary.faceList()); + + bc_list.emplace_back(InflowListBoundaryCondition(node_boundary, edge_boundary, face_boundary, node_values, + edge_values, face_values)); + } + break; + } + case IBoundaryConditionDescriptor::Type::outflow: { + std::cout << "outflow not implemented yet\n"; + break; + } + default: { + is_valid_boundary_condition = false; + } + } + if (not is_valid_boundary_condition) { + std::ostringstream error_msg; + error_msg << *bc_descriptor << " is an invalid boundary condition for Rusanov v2 Eulerian Composite solver"; + throw NormalError(error_msg.str()); + } + } + + return bc_list; + } + + public: + void _applyInflowBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const; + + void _applyOutflowBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const; + + void _applySymmetricBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const; + + public: + double + EvaluateMaxEigenValueInGivenUnitDirection(const double& rho_mean, + const Rd& U_mean, + const double& E_mean, + const double& c_mean, + const Rd& normal) const + { + const double norme_normal = l2norm(normal); + Rd unit_normal = normal; + unit_normal *= 1. / norme_normal; + const double uscaln = dot(U_mean, unit_normal); + + return std::max(std::fabs(uscaln - c_mean), std::fabs(uscaln + c_mean)); + } + + inline double + pression(const double rho, const double epsilon, const double gam) const + { + return (gam - 1) * rho * epsilon; + } + + std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + solve(const std::shared_ptr<const MeshType>& p_mesh, + const DiscreteFunctionP0<const double>& rho_n, + const DiscreteFunctionP0<const Rd>& u_n, + const DiscreteFunctionP0<const double>& E_n, + const double& gamma, + const DiscreteFunctionP0<const double>& c_n, + const DiscreteFunctionP0<const double>& p_n, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const double& dt, + const bool checkLocalConservation) const + { + auto rho = copy(rho_n); + auto u = copy(u_n); + auto E = copy(E_n); + // auto c = copy(c_n); + // auto p = copy(p_n); + + auto bc_list = this->_getBCList(*p_mesh, bc_descriptor_list); + + auto rhoE = rho * E; + auto rhoU = rho * u; + + // Construction du vecteur des variables conservatives + // + // Ci dessous juste ordre 1 + // + CellValue<Rp> State{p_mesh->connectivity()}; + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + State[j][0] = rho[j]; + for (size_t d = 0; d < Dimension; ++d) + State[j][1 + d] = rhoU[j][d]; + State[j][1 + Dimension] = rhoE[j]; + }); + + // CellValue<Rp> State{p_mesh->connectivity()}; + NodeValuePerCell<Rp> StateAtNode{p_mesh->connectivity()}; + StateAtNode.fill(zero); + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { StateAtNode[j].fill(State[j]); }); + EdgeValuePerCell<Rp> StateAtEdge{p_mesh->connectivity()}; + StateAtEdge.fill(zero); + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { StateAtEdge[j].fill(State[j]); }); + FaceValuePerCell<Rp> StateAtFace{p_mesh->connectivity()}; + StateAtFace.fill(zero); + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { StateAtFace[j].fill(State[j]); }); + + // Conditions aux limites des etats conservatifs + + _applyInflowBoundaryCondition(bc_list, *p_mesh, StateAtNode, StateAtEdge, StateAtFace); + //_applyOutflowBoundaryCondition(bc_list, *p_mesh, StateAtNode, StateAtEdge, StateAtFace); + _applySymmetricBoundaryCondition(bc_list, *p_mesh, StateAtNode, StateAtEdge, StateAtFace); + + // + // Construction du flux .. ok pour l'ordre 1 + // + CellValue<Rdxd> rhoUtensU{p_mesh->connectivity()}; + CellValue<Rdxd> Pid(p_mesh->connectivity()); + Pid.fill(identity); + CellValue<Rdxd> rhoUtensUPlusPid{p_mesh->connectivity()}; + rhoUtensUPlusPid.fill(zero); + + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + rhoUtensU[j] = tensorProduct(rhoU[j], u[j]); + Pid[j] *= p_n[j]; + rhoUtensUPlusPid[j] = rhoUtensU[j] + Pid[j]; + }); + + auto Flux_rho = rhoU; + auto Flux_qtmvt = rhoUtensUPlusPid; // rhoUtensU + Pid; + auto Flux_totnrj = (rhoE + p_n) * u; + + // Flux avec prise en compte des states at Node/Edge/Face + + NodeValuePerCell<Rd> Flux_rhoAtCellNode{p_mesh->connectivity()}; + EdgeValuePerCell<Rd> Flux_rhoAtCellEdge{p_mesh->connectivity()}; + FaceValuePerCell<Rd> Flux_rhoAtCellFace{p_mesh->connectivity()}; + /* + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_to_node = cell_to_node_matrix[j]; + + for (size_t l = 0; l < cell_to_node.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_rhoAtCellNode[j][l][dim] = StateAtNode[j][l][0] * StateAtNode[j][l][dim]; + } + + const auto& cell_to_face = cell_to_face_matrix[j]; + + for (size_t l = 0; l < cell_to_face.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_rhoAtCellFace[j][l][dim] = StateAtFace[j][l][0] * StateAtFace[j][l][dim]; + } + + const auto& cell_to_edge = cell_to_edge_matrix[j]; + + for (size_t l = 0; l < cell_to_edge.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_rhoAtCellEdge[j][l][dim] = StateAtEdge[j][l][0] * StateAtEdge[j][l][dim]; + } + }); +*/ + NodeValuePerCell<Rdxd> Flux_qtmvtAtCellNode{p_mesh->connectivity()}; // = rhoUtensUPlusPid; // rhoUtensU + Pid; + EdgeValuePerCell<Rdxd> Flux_qtmvtAtCellEdge{p_mesh->connectivity()}; // = rhoUtensUPlusPid; // rhoUtensU + Pid; + FaceValuePerCell<Rdxd> Flux_qtmvtAtCellFace{p_mesh->connectivity()}; // = rhoUtensUPlusPid; // rhoUtensU + Pid; + /* + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_to_node = cell_to_node_matrix[j]; + + for (size_t l = 0; l < cell_to_node.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_qtmvtAtCellNode[j][l][dim] = StateAtNode[j][l][0] * StateAtNode[j][l][dim]; + } + + const auto& cell_to_face = cell_to_face_matrix[j]; + + for (size_t l = 0; l < cell_to_face.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_qtmvtAtCellFace[j][l][dim] = StateAtFace[j][l][0] * StateAtFace[j][l][dim]; + } + + const auto& cell_to_edge = cell_to_edge_matrix[j]; + + for (size_t l = 0; l < cell_to_edge.size(); ++l) { + for (size_t dim = 0; dim < Dimension; ++dim) + Flux_qtmvtAtCellEdge[j][l][dim] = StateAtEdge[j][l][0] * StateAtEdge[j][l][dim]; + } + }); +*/ + // parallel_for( + // p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + // Flux_qtmvtAtCellNode[j] = Flux_qtmvtAtCellEdge[j] = Flux_qtmvtAtCellFace[j] = Flux_qtmvt[j]; + // }); + + NodeValuePerCell<Rd> Flux_totnrjAtCellNode{p_mesh->connectivity()}; + EdgeValuePerCell<Rd> Flux_totnrjAtCellEdge{p_mesh->connectivity()}; + FaceValuePerCell<Rd> Flux_totnrjAtCellFace{p_mesh->connectivity()}; + + const auto& cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix(); + const auto& cell_to_edge_matrix = p_mesh->connectivity().cellToEdgeMatrix(); + const auto& cell_to_face_matrix = p_mesh->connectivity().cellToFaceMatrix(); + + Flux_rhoAtCellEdge.fill(zero); + Flux_totnrjAtCellEdge.fill(zero); + Flux_qtmvtAtCellEdge.fill(zero); + + // Les flux aux nodes/edge/faces + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_to_node = cell_to_node_matrix[j]; + + for (size_t l = 0; l < cell_to_node.size(); ++l) { + // Etats conservatifs aux noeuds + const double rhonode = StateAtNode[j][l][0]; + Rd Unode; + for (size_t dim = 0; dim < Dimension; ++dim) + Unode[dim] = StateAtNode[j][l][dim + 1] / rhonode; + const double rhoEnode = StateAtNode[j][l][Dimension + 1]; + // + const double Enode = rhoEnode / rhonode; + const double epsilonnode = Enode - .5 * dot(Unode, Unode); + const Rd rhoUnode = rhonode * Unode; + const Rdxd rhoUtensUnode = tensorProduct(rhoUnode, Unode); + + const double Pressionnode = pression(rhonode, epsilonnode, gamma); + + const double rhoEnodePlusP = rhoEnode + Pressionnode; + + Rdxd rhoUtensUPlusPidnode(identity); + rhoUtensUPlusPidnode *= Pressionnode; + rhoUtensUPlusPidnode += rhoUtensUnode; + + Flux_rhoAtCellNode[j][l] = rhoUnode; + Flux_qtmvtAtCellNode[j][l] = rhoUtensUPlusPidnode; + Flux_totnrjAtCellNode[j][l] = rhoEnodePlusP * Unode; + } + + const auto& cell_to_face = cell_to_face_matrix[j]; + + for (size_t l = 0; l < cell_to_face.size(); ++l) { + const double rhoface = StateAtFace[j][l][0]; + Rd Uface; + for (size_t dim = 0; dim < Dimension; ++dim) + Uface[dim] = StateAtFace[j][l][dim + 1] / rhoface; + const double rhoEface = StateAtFace[j][l][Dimension + 1]; + // + const double Eface = rhoEface / rhoface; + const double epsilonface = Eface - .5 * dot(Uface, Uface); + const Rd rhoUface = rhoface * Uface; + const Rdxd rhoUtensUface = tensorProduct(rhoUface, Uface); + + const double Pressionface = pression(rhoface, epsilonface, gamma); + + const double rhoEfacePlusP = rhoEface + Pressionface; + + Rdxd rhoUtensUPlusPidface(identity); + rhoUtensUPlusPidface *= Pressionface; + rhoUtensUPlusPidface += rhoUtensUface; + + Flux_rhoAtCellFace[j][l] = rhoUface; + Flux_qtmvtAtCellFace[j][l] = rhoUtensUPlusPidface; + Flux_totnrjAtCellFace[j][l] = rhoEfacePlusP * Uface; + } + + if constexpr (Dimension == 3) { + const auto& cell_to_edge = cell_to_edge_matrix[j]; + + for (size_t l = 0; l < cell_to_edge.size(); ++l) { + const double rhoedge = StateAtEdge[j][l][0]; + Rd Uedge; + for (size_t dim = 0; dim < Dimension; ++dim) + Uedge[dim] = StateAtEdge[j][l][dim + 1] / rhoedge; + const double rhoEedge = StateAtEdge[j][l][Dimension + 1]; + // + const double Eedge = rhoEedge / rhoedge; + const double epsilonedge = Eedge - .5 * dot(Uedge, Uedge); + const Rd rhoUedge = rhoedge * Uedge; + const Rdxd rhoUtensUedge = tensorProduct(rhoUedge, Uedge); + + const double Pressionedge = pression(rhoedge, epsilonedge, gamma); + + const double rhoEedgePlusP = rhoEedge + Pressionedge; + + Rdxd rhoUtensUPlusPidedge(identity); + rhoUtensUPlusPidedge *= Pressionedge; + rhoUtensUPlusPidedge += rhoUtensUedge; + + Flux_rhoAtCellEdge[j][l] = rhoUedge; + Flux_qtmvtAtCellEdge[j][l] = rhoUtensUPlusPidedge; + Flux_totnrjAtCellEdge[j][l] = rhoEedgePlusP * Uedge; + } + } + }); + + // parallel_for( + // p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + // Flux_totnrjAtCellNode[j] = Flux_totnrjAtCellEdge[j] = Flux_totnrjAtCellFace[j] = Flux_totnrj[j]; + // }); + + MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(*p_mesh); + + auto volumes_cell = mesh_data.Vj(); + + // Calcul des matrices de viscosité aux node/edge/face + + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + const NodeValuePerCell<const Rd> njr = mesh_data.njr(); + + const FaceValuePerCell<const Rd> Cjf = mesh_data.Cjf(); + const FaceValuePerCell<const Rd> njf = mesh_data.njf(); + + const auto& node_to_cell_matrix = p_mesh->connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = p_mesh->connectivity().nodeLocalNumbersInTheirCells(); + + const auto& face_to_cell_matrix = p_mesh->connectivity().faceToCellMatrix(); + const auto& face_local_numbers_in_their_cells = p_mesh->connectivity().faceLocalNumbersInTheirCells(); + + // We compute Gjr, Gjf + + NodeValuePerCell<Rp> Gjr{p_mesh->connectivity()}; + Gjr.fill(zero); + EdgeValuePerCell<Rp> Gje{p_mesh->connectivity()}; + Gje.fill(zero); + FaceValuePerCell<Rp> Gjf{p_mesh->connectivity()}; + Gjf.fill(zero); + + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_to_node = cell_to_node_matrix[j]; + + for (size_t l = 0; l < cell_to_node.size(); ++l) { + const NodeId& node = cell_to_node[l]; + const auto& node_to_cell = node_to_cell_matrix[node]; + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(node); + + const Rd& Cjr_loc = Cjr(j, l); + + for (size_t k = 0; k < node_to_cell.size(); ++k) { + const CellId K = node_to_cell[k]; + const size_t R = node_local_number_in_its_cells[k]; + const Rd& Ckr_loc = Cjr(K, R); + + // Une moyenne entre les etats jk + + Rd uNode = .5 * (u_n[j] + u_n[K]); + double cNode = .5 * (c_n[j] + c_n[K]); + + // Viscosity j k + Rpxp ViscosityMatrixJK(identity); + const double MaxmaxabsVpNormjk = + std::max(toolsCompositeSolver::EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(uNode, cNode, + Cjr_loc), + toolsCompositeSolver::EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(uNode, cNode, + Ckr_loc)); + + ViscosityMatrixJK *= MaxmaxabsVpNormjk; + const Rd& u_Cjr = Flux_qtmvtAtCellNode[K][R] * Cjr_loc; // Flux_qtmvt[K] * Cjr_loc; + + const Rp& statediff = StateAtNode[j][l] - StateAtNode[K][R]; // State[j] - State[K]; + const Rp& diff = ViscosityMatrixJK * statediff; + + Gjr[j][l][0] += dot(Flux_rhoAtCellNode[K][R], Cjr_loc); // dot(Flux_rho[K], Cjr_loc); + for (size_t d = 0; d < Dimension; ++d) + Gjr[j][l][1 + d] += u_Cjr[d]; + Gjr[j][l][1 + Dimension] += dot(Flux_totnrjAtCellNode[K][R], Cjr_loc); // dot(Flux_totnrj[K], Cjr_loc); + + Gjr[j][l] += diff; + } + + Gjr[j][l] *= 1. / node_to_cell.size(); + } + }); + + if (checkLocalConservation) { + auto is_boundary_node = p_mesh->connectivity().isBoundaryNode(); + + NodeValue<double> MaxErrorConservationNode(p_mesh->connectivity()); + MaxErrorConservationNode.fill(0.); + // double MaxErrorConservationNode = 0; + parallel_for( + p_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId l) { + const auto& node_to_cell = node_to_cell_matrix[l]; + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(l); + + if (not is_boundary_node[l]) { + Rp SumGjr(zero); + for (size_t k = 0; k < node_to_cell.size(); ++k) { + const CellId K = node_to_cell[k]; + const unsigned int R = node_local_number_in_its_cells[k]; + SumGjr += Gjr[K][R]; + } + // MaxErrorConservationNode = std::max(MaxErrorConservationNode, l2Norm(SumGjr)); + MaxErrorConservationNode[l] = l2Norm(SumGjr); + } + }); + std::cout << " Max Error Node " << max(MaxErrorConservationNode) << "\n"; + } + // + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + // Edge + const auto& cell_to_face = cell_to_face_matrix[j]; + + for (size_t l = 0; l < cell_to_face.size(); ++l) { + const FaceId& face = cell_to_face[l]; + const auto& face_to_cell = face_to_cell_matrix[face]; + const auto& face_local_number_in_its_cells = face_local_numbers_in_their_cells.itemArray(face); + + const Rd& Cjf_loc = Cjf(j, l); + + for (size_t k = 0; k < face_to_cell.size(); ++k) { + const CellId K = face_to_cell[k]; + const unsigned int R = face_local_number_in_its_cells[k]; + const Rd& Ckf_loc = Cjf(K, R); + // Une moyenne entre les etats jk + + Rd uFace = .5 * (u_n[j] + u_n[K]); + double cFace = .5 * (c_n[j] + c_n[K]); + + // Viscosity j k + Rpxp ViscosityMatrixJK(identity); + const double MaxmaxabsVpNormjk = + std::max(toolsCompositeSolver::EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(uFace, cFace, + Cjf_loc), + toolsCompositeSolver::EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(uFace, cFace, + Ckf_loc)); + + ViscosityMatrixJK *= MaxmaxabsVpNormjk; + + const Rd& u_Cjf = Flux_qtmvtAtCellFace[K][R] * Cjf_loc; // Flux_qtmvt[K] * Cjf_loc; + + const Rp& statediff = StateAtFace[j][l] - StateAtFace[K][R]; // State[j] - State[K]; + const Rp& diff = ViscosityMatrixJK * statediff; + + Gjf[j][l][0] += dot(Flux_rhoAtCellFace[K][R], Cjf_loc); // dot(Flux_rho[K], Cjf_loc); + for (size_t d = 0; d < Dimension; ++d) + Gjf[j][l][1 + d] += u_Cjf[d]; + Gjf[j][l][1 + Dimension] += dot(Flux_totnrjAtCellFace[K][R], Cjf_loc); // dot(Flux_totnrj[K], Cjf_loc); + + Gjf[j][l] += diff; + } + + Gjf[j][l] *= 1. / face_to_cell.size(); + } + }); + + if (checkLocalConservation) { + auto is_boundary_face = p_mesh->connectivity().isBoundaryFace(); + + FaceValue<double> MaxErrorConservationFace(p_mesh->connectivity()); + MaxErrorConservationFace.fill(0.); + + parallel_for( + p_mesh->numberOfFaces(), PUGS_LAMBDA(FaceId l) { + const auto& face_to_cell = face_to_cell_matrix[l]; + const auto& face_local_number_in_its_cells = face_local_numbers_in_their_cells.itemArray(l); + + if (not is_boundary_face[l]) { + Rp SumGjf(zero); + for (size_t k = 0; k < face_to_cell.size(); ++k) { + const CellId K = face_to_cell[k]; + const unsigned int R = face_local_number_in_its_cells[k]; + SumGjf += Gjf[K][R]; + } + MaxErrorConservationFace[l] = l2Norm(SumGjf); + // MaxErrorConservationFace = std::max(MaxErrorConservationFace, l2Norm(SumGjf)); + } + }); + std::cout << " Max Error Face " << max(MaxErrorConservationFace) << "\n"; + } + + if constexpr (Dimension == 3) { + const auto& edge_to_cell_matrix = p_mesh->connectivity().edgeToCellMatrix(); + const auto& edge_local_numbers_in_their_cells = p_mesh->connectivity().edgeLocalNumbersInTheirCells(); + + const EdgeValuePerCell<const Rd> Cje = mesh_data.Cje(); + const EdgeValuePerCell<const Rd> nje = mesh_data.nje(); + + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + // Edge + const auto& cell_to_edge = cell_to_edge_matrix[j]; + + for (size_t l = 0; l < cell_to_edge.size(); ++l) { + const EdgeId& edge = cell_to_edge[l]; + const auto& edge_to_cell = edge_to_cell_matrix[edge]; + const auto& edge_local_number_in_its_cells = edge_local_numbers_in_their_cells.itemArray(edge); + + const Rd& Cje_loc = Cje(j, l); + + for (size_t k = 0; k < edge_to_cell.size(); ++k) { + const CellId K = edge_to_cell[k]; + const size_t R = edge_local_number_in_its_cells[k]; + + const Rd& Cke_loc = Cje(K, R); + + // Une moyenne entre les etats jk + + Rd uEdge = .5 * (u_n[j] + u_n[K]); + double cEdge = .5 * (c_n[j] + c_n[K]); + + // Viscosity j k + Rpxp ViscosityMatrixJK(identity); + const double MaxmaxabsVpNormjk = + std::max(toolsCompositeSolver::EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(uEdge, cEdge, + Cje_loc), + toolsCompositeSolver::EvaluateMaxEigenValueTimesNormalLengthInGivenDirection(uEdge, cEdge, + Cke_loc)); + + ViscosityMatrixJK *= MaxmaxabsVpNormjk; + + const Rd& u_Cje = Flux_qtmvtAtCellEdge[K][R] * Cje_loc; // Flux_qtmvt[K] * Cje_loc; + + const Rp& statediff = StateAtEdge[j][l] - StateAtEdge[K][R]; // State[j] - State[K]; + const Rp& diff = ViscosityMatrixJK * statediff; + + Gje[j][l][0] += dot(Flux_rhoAtCellEdge[K][R], Cje_loc); // dot(Flux_rho[K], Cje_loc); + for (size_t d = 0; d < Dimension; ++d) + Gje[j][l][1 + d] += u_Cje[d]; + Gje[j][l][1 + Dimension] += dot(Flux_totnrjAtCellEdge[K][R], Cje_loc); // dot(Flux_totnrj[K], Cje_loc); + + Gje[j][l] += diff; + } + + Gje[j][l] *= 1. / edge_to_cell.size(); + } + }); + + if (checkLocalConservation) { + auto is_boundary_edge = p_mesh->connectivity().isBoundaryEdge(); + + EdgeValue<double> MaxErrorConservationEdge(p_mesh->connectivity()); + MaxErrorConservationEdge.fill(0.); + // double MaxErrorConservationEdge = 0; + parallel_for( + p_mesh->numberOfEdges(), PUGS_LAMBDA(EdgeId l) { + const auto& edge_to_cell = edge_to_cell_matrix[l]; + const auto& edge_local_number_in_its_cells = edge_local_numbers_in_their_cells.itemArray(l); + + if (not is_boundary_edge[l]) { + Rp SumGje(zero); + for (size_t k = 0; k < edge_to_cell.size(); ++k) { + const CellId K = edge_to_cell[k]; + const unsigned int R = edge_local_number_in_its_cells[k]; + SumGje += Gje[K][R]; + } + // MaxErrorConservationEdge = std::max(MaxErrorConservationEdge, l2norm(SumGje)); + MaxErrorConservationEdge[l] = l2Norm(SumGje); + } + }); + std::cout << " Max Error Edge " << max(MaxErrorConservationEdge) << "\n"; + } + } // dim 3 + + // Pour les assemblages + double theta = .5; + double eta = .2; + if constexpr (Dimension == 2) { + eta = 0; + } else { + theta = 1. / 3.; + eta = 1. / 3.; + + // theta = .5; + // eta = 0; + } + // + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_to_node = cell_to_node_matrix[j]; + + Rp SumFluxesNode(zero); + + for (size_t l = 0; l < cell_to_node.size(); ++l) { + SumFluxesNode += Gjr[j][l]; + } + // SumFluxesNode *= (1 - theta); + + const auto& cell_to_edge = cell_to_edge_matrix[j]; + Rp SumFluxesEdge(zero); + + for (size_t l = 0; l < cell_to_edge.size(); ++l) { + SumFluxesEdge += Gje[j][l]; + } + + const auto& cell_to_face = cell_to_face_matrix[j]; + Rp SumFluxesFace(zero); + + for (size_t l = 0; l < cell_to_face.size(); ++l) { + SumFluxesFace += Gjf[j][l]; + } + // SumFluxesEdge *= (theta); + + const Rp SumFluxes = (1 - theta - eta) * SumFluxesNode + eta * SumFluxesEdge + theta * SumFluxesFace; + + State[j] -= dt / volumes_cell[j] * SumFluxes; + + rho[j] = State[j][0]; + for (size_t d = 0; d < Dimension; ++d) + u[j][d] = State[j][1 + d] / rho[j]; + E[j] = State[j][1 + Dimension] / rho[j]; + }); + + return std::make_tuple(std::make_shared<const DiscreteFunctionVariant>(rho), + std::make_shared<const DiscreteFunctionVariant>(u), + std::make_shared<const DiscreteFunctionVariant>(E)); + } + + RusanovEulerianCompositeSolver_v2() = default; + ~RusanovEulerianCompositeSolver_v2() = default; +}; + +template <MeshConcept MeshType> +class RusanovEulerianCompositeSolver_v2<MeshType>::NeumannBoundaryCondition +{ +}; + +template <> +class RusanovEulerianCompositeSolver_v2<Mesh<2>>::NeumannBoundaryCondition +{ + using Rd = TinyVector<Dimension, double>; + + private: + const MeshNodeBoundary m_mesh_node_boundary; + const MeshFaceBoundary m_mesh_face_boundary; + + public: + size_t + numberOfNodes() const + { + return m_mesh_node_boundary.nodeList().size(); + } + + size_t + numberOfFaces() const + { + return m_mesh_face_boundary.faceList().size(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + NeumannBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary, const MeshFaceBoundary& mesh_face_boundary) + : m_mesh_node_boundary(mesh_node_boundary), m_mesh_face_boundary(mesh_face_boundary) + { + ; + } +}; + +template <> +class RusanovEulerianCompositeSolver_v2<Mesh<3>>::NeumannBoundaryCondition +{ + using Rd = TinyVector<Dimension, double>; + + private: + const MeshNodeBoundary m_mesh_node_boundary; + const MeshEdgeBoundary m_mesh_edge_boundary; + const MeshFaceBoundary m_mesh_face_boundary; + + public: + size_t + numberOfNodes() const + { + return m_mesh_node_boundary.nodeList().size(); + } + size_t + numberOfEdges() const + { + return m_mesh_edge_boundary.edgeList().size(); + } + + size_t + numberOfFaces() const + { + return m_mesh_face_boundary.faceList().size(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const EdgeId>& + edgeList() const + { + return m_mesh_edge_boundary.edgeList(); + } + + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + NeumannBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary, + const MeshEdgeBoundary& mesh_edge_boundary, + const MeshFaceBoundary& mesh_face_boundary) + : m_mesh_node_boundary(mesh_node_boundary), + + m_mesh_edge_boundary(mesh_edge_boundary), + + m_mesh_face_boundary(mesh_face_boundary) + { + ; + } +}; + +template <MeshConcept MeshType> +class RusanovEulerianCompositeSolver_v2<MeshType>::SymmetryBoundaryCondition +{ +}; + +template <> +class RusanovEulerianCompositeSolver_v2<Mesh<2>>::SymmetryBoundaryCondition +{ + public: + using Rd = TinyVector<Dimension, double>; + + private: + const MeshFlatNodeBoundary<MeshType> m_mesh_flat_node_boundary; + const MeshFlatFaceBoundary<MeshType> m_mesh_flat_face_boundary; + + public: + const Rd& + outgoingNormal() const + { + return m_mesh_flat_node_boundary.outgoingNormal(); + } + + size_t + numberOfNodes() const + { + return m_mesh_flat_node_boundary.nodeList().size(); + } + + size_t + numberOfFaces() const + { + return m_mesh_flat_face_boundary.faceList().size(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_flat_node_boundary.nodeList(); + } + + const Array<const FaceId>& + faceList() const + { + return m_mesh_flat_face_boundary.faceList(); + } + + SymmetryBoundaryCondition(const MeshFlatNodeBoundary<MeshType>& mesh_flat_node_boundary, + const MeshFlatFaceBoundary<MeshType>& mesh_flat_face_boundary) + : m_mesh_flat_node_boundary(mesh_flat_node_boundary), m_mesh_flat_face_boundary(mesh_flat_face_boundary) + { + ; + } + + ~SymmetryBoundaryCondition() = default; +}; + +template <> +class RusanovEulerianCompositeSolver_v2<Mesh<3>>::SymmetryBoundaryCondition +{ + public: + using Rd = TinyVector<Dimension, double>; + + private: + const MeshFlatNodeBoundary<MeshType> m_mesh_flat_node_boundary; + const MeshFlatEdgeBoundary<MeshType> m_mesh_flat_edge_boundary; + const MeshFlatFaceBoundary<MeshType> m_mesh_flat_face_boundary; + + public: + const Rd& + outgoingNormal() const + { + return m_mesh_flat_node_boundary.outgoingNormal(); + } + + size_t + numberOfNodes() const + { + return m_mesh_flat_node_boundary.nodeList().size(); + } + + size_t + numberOfEdges() const + { + return m_mesh_flat_edge_boundary.edgeList().size(); + } + + size_t + numberOfFaces() const + { + return m_mesh_flat_face_boundary.faceList().size(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_flat_node_boundary.nodeList(); + } + + const Array<const EdgeId>& + edgeList() const + { + return m_mesh_flat_edge_boundary.edgeList(); + } + + const Array<const FaceId>& + faceList() const + { + return m_mesh_flat_face_boundary.faceList(); + } + + SymmetryBoundaryCondition(const MeshFlatNodeBoundary<MeshType>& mesh_flat_node_boundary, + const MeshFlatEdgeBoundary<MeshType>& mesh_flat_edge_boundary, + const MeshFlatFaceBoundary<MeshType>& mesh_flat_face_boundary) + : m_mesh_flat_node_boundary(mesh_flat_node_boundary), + m_mesh_flat_edge_boundary(mesh_flat_edge_boundary), + m_mesh_flat_face_boundary(mesh_flat_face_boundary) + { + ; + } + + ~SymmetryBoundaryCondition() = default; +}; + +template <MeshConcept MeshType> +class RusanovEulerianCompositeSolver_v2<MeshType>::InflowListBoundaryCondition +{ +}; + +template <> +class RusanovEulerianCompositeSolver_v2<Mesh<2>>::InflowListBoundaryCondition +{ + public: + using Rd = TinyVector<Dimension, double>; + + private: + const MeshNodeBoundary m_mesh_node_boundary; + const MeshFaceBoundary m_mesh_face_boundary; + const Table<const double> m_node_array_list; + const Table<const double> m_face_array_list; + + public: + size_t + numberOfNodes() const + { + return m_mesh_node_boundary.nodeList().size(); + } + + size_t + numberOfFaces() const + { + return m_mesh_face_boundary.faceList().size(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + const Table<const double>& + nodeArrayList() const + { + return m_node_array_list; + } + + const Table<const double>& + faceArrayList() const + { + return m_face_array_list; + } + + InflowListBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary, + const MeshFaceBoundary& mesh_face_boundary, + const Table<const double>& node_array_list, + const Table<const double>& face_array_list) + : m_mesh_node_boundary(mesh_node_boundary), + m_mesh_face_boundary(mesh_face_boundary), + m_node_array_list(node_array_list), + m_face_array_list(face_array_list) + { + ; + } + + ~InflowListBoundaryCondition() = default; +}; + +template <> +class RusanovEulerianCompositeSolver_v2<Mesh<3>>::InflowListBoundaryCondition +{ + public: + using Rd = TinyVector<Dimension, double>; + + private: + const MeshNodeBoundary m_mesh_node_boundary; + const MeshEdgeBoundary m_mesh_edge_boundary; + const MeshFaceBoundary m_mesh_face_boundary; + const Table<const double> m_node_array_list; + const Table<const double> m_edge_array_list; + const Table<const double> m_face_array_list; + + public: + size_t + numberOfNodes() const + { + return m_mesh_node_boundary.nodeList().size(); + } + + size_t + numberOfEdges() const + { + return m_mesh_edge_boundary.edgeList().size(); + } + + size_t + numberOfFaces() const + { + return m_mesh_face_boundary.faceList().size(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const EdgeId>& + edgeList() const + { + return m_mesh_edge_boundary.edgeList(); + } + + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + const Table<const double>& + nodeArrayList() const + { + return m_node_array_list; + } + + const Table<const double>& + edgeArrayList() const + { + return m_edge_array_list; + } + + const Table<const double>& + faceArrayList() const + { + return m_face_array_list; + } + + InflowListBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary, + const MeshEdgeBoundary& mesh_edge_boundary, + const MeshFaceBoundary& mesh_face_boundary, + const Table<const double>& node_array_list, + const Table<const double>& edge_array_list, + const Table<const double>& face_array_list) + : m_mesh_node_boundary(mesh_node_boundary), + m_mesh_edge_boundary(mesh_edge_boundary), + m_mesh_face_boundary(mesh_face_boundary), + m_node_array_list(node_array_list), + m_edge_array_list(edge_array_list), + m_face_array_list(face_array_list) + { + ; + } + + ~InflowListBoundaryCondition() = default; +}; + +template <MeshConcept MeshType> +class RusanovEulerianCompositeSolver_v2<MeshType>::OutflowBoundaryCondition +{ +}; + +std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +rusanovEulerianCompositeSolver_v2( + const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& E_v, + const double& gamma, + const std::shared_ptr<const DiscreteFunctionVariant>& c_v, + const std::shared_ptr<const DiscreteFunctionVariant>& p_v, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const double& dt, + const bool check) +{ + std::shared_ptr mesh_v = getCommonMesh({rho_v, u_v, E_v, c_v, p_v}); + if (not mesh_v) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + if (not checkDiscretizationType({rho_v, u_v, E_v}, DiscreteFunctionType::P0)) { + throw NormalError("acoustic solver expects P0 functions"); + } + + return std::visit( + PUGS_LAMBDA(auto&& p_mesh) + ->std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + using MeshType = mesh_type_t<decltype(p_mesh)>; + static constexpr size_t Dimension = MeshType::Dimension; + using Rd = TinyVector<Dimension>; + + if constexpr (Dimension == 1) { + throw NormalError("RusanovEulerianCompositeSolver v2 is not available in 1D"); + } else { + if constexpr (is_polygonal_mesh_v<MeshType>) { + return RusanovEulerianCompositeSolver_v2<MeshType>{} + .solve(p_mesh, rho_v->get<DiscreteFunctionP0<const double>>(), u_v->get<DiscreteFunctionP0<const Rd>>(), + E_v->get<DiscreteFunctionP0<const double>>(), gamma, c_v->get<DiscreteFunctionP0<const double>>(), + p_v->get<DiscreteFunctionP0<const double>>(), bc_descriptor_list, dt, check); + } else { + throw NormalError("RusanovEulerianCompositeSolver v2 is only defined on polygonal meshes"); + } + } + }, + mesh_v->variant()); +} + +template <MeshConcept MeshType> +void +RusanovEulerianCompositeSolver_v2<MeshType>::_applyOutflowBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<OutflowBoundaryCondition, T>) { + throw NormalError("Not implemented"); + } + }, + boundary_condition); + } +} + +template <MeshConcept MeshType> +void +RusanovEulerianCompositeSolver_v2<MeshType>::_applySymmetricBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<SymmetryBoundaryCondition, T>) { + // MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + std::cout << " Traitement SYMMETRY \n"; + const Rd& normal = bc.outgoingNormal(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + const auto& face_local_numbers_in_their_cells = mesh.connectivity().faceLocalNumbersInTheirCells(); + // const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed(); + + const auto& face_list = bc.faceList(); + const auto& node_list = bc.nodeList(); + + for (size_t i_node = 0; i_node < node_list.size(); ++i_node) { + const NodeId node_id = node_list[i_node]; + + const auto& node_cell_list = node_to_cell_matrix[node_id]; + // Assert(face_cell_list.size() == 1); + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(node_id); + + for (size_t i_cell = 0; i_cell < node_cell_list.size(); ++i_cell) { + CellId node_cell_id = node_cell_list[i_cell]; + size_t node_local_number_in_cell = node_local_number_in_its_cells[i_cell]; + + Rd vectorSym(zero); + for (size_t dim = 0; dim < Dimension; ++dim) + vectorSym[dim] = stateNode[node_cell_id][node_local_number_in_cell][1 + dim]; + + Rdxd MatriceProj(identity); + MatriceProj -= tensorProduct(normal, normal); + vectorSym = MatriceProj * vectorSym; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateNode[node_cell_id][node_local_number_in_cell][dim + 1] = vectorSym[dim]; + // stateNode[node_cell_id][node_local_number_in_cell][dim] = 0; // node_array_list[i_node][dim]; + } + } + + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + + const auto& face_cell_list = face_to_cell_matrix[face_id]; + Assert(face_cell_list.size() == 1); + + CellId face_cell_id = face_cell_list[0]; + size_t face_local_number_in_cell = face_local_numbers_in_their_cells(face_id, 0); + + Rd vectorSym(zero); + for (size_t dim = 0; dim < Dimension; ++dim) + vectorSym[dim] = stateEdge[face_cell_id][face_local_number_in_cell][1 + dim]; + + Rdxd MatriceProj(identity); + MatriceProj -= tensorProduct(normal, normal); + vectorSym = MatriceProj * vectorSym; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateFace[face_cell_id][face_local_number_in_cell][dim + 1] = vectorSym[dim]; + } + + if constexpr (Dimension == 3) { + const auto& edge_to_cell_matrix = mesh.connectivity().edgeToCellMatrix(); + + const auto& edge_local_numbers_in_their_cells = mesh.connectivity().edgeLocalNumbersInTheirCells(); + + const auto& edge_list = bc.edgeList(); + + for (size_t i_edge = 0; i_edge < edge_list.size(); ++i_edge) { + const EdgeId edge_id = edge_list[i_edge]; + + const auto& edge_cell_list = edge_to_cell_matrix[edge_id]; + // Assert(face_cell_list.size() == 1); + const auto& edge_local_number_in_its_cells = edge_local_numbers_in_their_cells.itemArray(edge_id); + + for (size_t i_cell = 0; i_cell < edge_cell_list.size(); ++i_cell) { + CellId edge_cell_id = edge_cell_list[i_cell]; + size_t edge_local_number_in_cell = edge_local_number_in_its_cells[i_cell]; + + Rd vectorSym(zero); + for (size_t dim = 0; dim < Dimension; ++dim) + vectorSym[dim] = stateEdge[edge_cell_id][edge_local_number_in_cell][1 + dim]; + + Rdxd MatriceProj(identity); + MatriceProj -= tensorProduct(normal, normal); + vectorSym = MatriceProj * vectorSym; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateEdge[edge_cell_id][edge_local_number_in_cell][dim + 1] = vectorSym[dim]; + } + } + } + } + }, + boundary_condition); + } +} + +template <MeshConcept MeshType> +void +RusanovEulerianCompositeSolver_v2<MeshType>::_applyInflowBoundaryCondition(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValuePerCell<Rp>& stateNode, + EdgeValuePerCell<Rp>& stateEdge, + FaceValuePerCell<Rp>& stateFace) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<InflowListBoundaryCondition, T>) { + // MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + std::cout << " Traitement INFLOW \n"; + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + const auto& face_local_numbers_in_their_cells = mesh.connectivity().faceLocalNumbersInTheirCells(); + // const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed(); + + const auto& face_list = bc.faceList(); + const auto& node_list = bc.nodeList(); + + const auto& face_array_list = bc.faceArrayList(); + const auto& node_array_list = bc.nodeArrayList(); + + for (size_t i_node = 0; i_node < node_list.size(); ++i_node) { + const NodeId node_id = node_list[i_node]; + + const auto& node_cell_list = node_to_cell_matrix[node_id]; + // Assert(face_cell_list.size() == 1); + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(node_id); + + for (size_t i_cell = 0; i_cell < node_cell_list.size(); ++i_cell) { + CellId node_cell_id = node_cell_list[i_cell]; + size_t node_local_number_in_cell = node_local_number_in_its_cells[i_cell]; + + for (size_t dim = 0; dim < Dimension + 2; ++dim) + stateNode[node_cell_id][node_local_number_in_cell][dim] = node_array_list[i_node][dim]; + } + } + + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + + const auto& face_cell_list = face_to_cell_matrix[face_id]; + Assert(face_cell_list.size() == 1); + + CellId face_cell_id = face_cell_list[0]; + size_t face_local_number_in_cell = face_local_numbers_in_their_cells(face_id, 0); + + for (size_t dim = 0; dim < Dimension + 2; ++dim) + stateFace[face_cell_id][face_local_number_in_cell][dim] = face_array_list[i_face][dim]; + } + + if constexpr (Dimension == 3) { + const auto& edge_to_cell_matrix = mesh.connectivity().edgeToCellMatrix(); + + const auto& edge_local_numbers_in_their_cells = mesh.connectivity().edgeLocalNumbersInTheirCells(); + // const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed(); + + const auto& edge_list = bc.edgeList(); + + const auto& edge_array_list = bc.edgeArrayList(); + + for (size_t i_edge = 0; i_edge < edge_list.size(); ++i_edge) { + const EdgeId edge_id = edge_list[i_edge]; + + const auto& edge_cell_list = edge_to_cell_matrix[edge_id]; + // Assert(face_cell_list.size() == 1); + const auto& edge_local_number_in_its_cells = edge_local_numbers_in_their_cells.itemArray(edge_id); + + for (size_t i_cell = 0; i_cell < edge_cell_list.size(); ++i_cell) { + CellId edge_cell_id = edge_cell_list[i_cell]; + size_t edge_local_number_in_cell = edge_local_number_in_its_cells[i_cell]; + + for (size_t dim = 0; dim < Dimension + 2; ++dim) + stateEdge[edge_cell_id][edge_local_number_in_cell][dim] = edge_array_list[i_edge][dim]; + } + } + } + } + }, + boundary_condition); + } +} diff --git a/src/scheme/RusanovEulerianCompositeSolver_v2.hpp b/src/scheme/RusanovEulerianCompositeSolver_v2.hpp new file mode 100644 index 000000000..749c09a18 --- /dev/null +++ b/src/scheme/RusanovEulerianCompositeSolver_v2.hpp @@ -0,0 +1,29 @@ +#ifndef RUSANOV_EULERIAN_COMPOSITE_SOLVER_V2_HPP +#define RUSANOV_EULERIAN_COMPOSITE_SOLVER_V2_HPP + +#include <mesh/MeshVariant.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/RusanovEulerianCompositeSolverTools.hpp> + +#include <memory> +#include <vector> + +// double compute_dt(const std::shared_ptr<const DiscreteFunctionVariant>& u_v, +// const std::shared_ptr<const DiscreteFunctionVariant>& c_v); + +std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +rusanovEulerianCompositeSolver_v2( + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const double& gamma, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const double& dt, + const bool check = false); + +#endif // RUSANOV_EULERIAN_COMPOSITE_SOLVER_V2_HPP -- GitLab