diff --git a/.gitignore b/.gitignore index cb98282bfb904d03ac706cc8740ee1ad922c8851..066e7213900207034976978af9c91ee0dca2317d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ *.o *.a *~ -build/ +build*/ CMakeFiles/ CMakeCache.txt .\#* diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index f60cedd06cbea496f19ca991c47dba984fa0611e..43b6e5c3ddf1844d2d3390215c03ca92e8c9e5cd 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -18,8 +18,8 @@ #include <mesh/MeshRandomizer.hpp> #include <mesh/MeshSmoother.hpp> #include <mesh/MeshTraits.hpp> -#include <scheme/AcousticSolver.hpp> #include <scheme/AcousticCompositeSolver.hpp> +#include <scheme/AcousticSolver.hpp> #include <scheme/AxisBoundaryConditionDescriptor.hpp> #include <scheme/DirichletBoundaryConditionDescriptor.hpp> #include <scheme/DiscreteFunctionDescriptorP0.hpp> @@ -40,8 +40,10 @@ #include <scheme/IBoundaryConditionDescriptor.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> #include <scheme/InflowBoundaryConditionDescriptor.hpp> +#include <scheme/InflowListBoundaryConditionDescriptor.hpp> #include <scheme/NeumannBoundaryConditionDescriptor.hpp> #include <scheme/OutflowBoundaryConditionDescriptor.hpp> +#include <scheme/RusanovEulerianCompositeSolver.hpp> #include <scheme/SymmetryBoundaryConditionDescriptor.hpp> #include <scheme/VariableBCDescriptor.hpp> #include <utils/Socket.hpp> @@ -394,6 +396,18 @@ SchemeModule::SchemeModule() )); + this->_addBuiltinFunction("inflow_list", + std::function( + + [](std::shared_ptr<const IBoundaryDescriptor> boundary, + const std::vector<FunctionSymbolId>& function_id_list) + -> std::shared_ptr<const IBoundaryConditionDescriptor> { + return std::make_shared<InflowListBoundaryConditionDescriptor>(boundary, + function_id_list); + } + + )); + this->_addBuiltinFunction("outflow", std::function( [](std::shared_ptr<const IBoundaryDescriptor> boundary) @@ -420,29 +434,29 @@ SchemeModule::SchemeModule() } )); - - this->_addBuiltinFunction("composite_glace_fluxes", std::function( - [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, - const std::shared_ptr<const DiscreteFunctionVariant>& u, - 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) - -> std::tuple<std::shared_ptr<const ItemValueVariant>, - std::shared_ptr<const SubItemValuePerItemVariant>, - std::shared_ptr<const ItemValueVariant>, - std::shared_ptr<const SubItemValuePerItemVariant>, - std::shared_ptr<const ItemValueVariant>, - std::shared_ptr<const SubItemValuePerItemVariant> - > { - return AcousticCompositeSolverHandler{getCommonMesh({rho, c, u, p})} - .solver() - .compute_fluxes(AcousticCompositeSolverHandler::SolverType::GlaceComposite, rho, c, u, - p, bc_descriptor_list); - } + this->_addBuiltinFunction("composite_glace_fluxes", + std::function( - )); + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + 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) + -> std::tuple<std::shared_ptr<const ItemValueVariant>, + std::shared_ptr<const SubItemValuePerItemVariant>, + std::shared_ptr<const ItemValueVariant>, + std::shared_ptr<const SubItemValuePerItemVariant>, + std::shared_ptr<const ItemValueVariant>, + std::shared_ptr<const SubItemValuePerItemVariant>> { + return AcousticCompositeSolverHandler{getCommonMesh({rho, c, u, p})} + .solver() + .compute_fluxes(AcousticCompositeSolverHandler::SolverType::GlaceComposite, rho, c, u, + p, bc_descriptor_list); + } + + )); this->_addBuiltinFunction("glace_solver", std::function( @@ -466,8 +480,7 @@ SchemeModule::SchemeModule() )); - - this->_addBuiltinFunction("composite_glace_solver", + this->_addBuiltinFunction("composite_glace_solver", std::function( [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, @@ -483,14 +496,30 @@ SchemeModule::SchemeModule() std::shared_ptr<const DiscreteFunctionVariant>> { return AcousticCompositeSolverHandler{getCommonMesh({rho, u, E, c, p})} .solver() - .apply(AcousticCompositeSolverHandler::SolverType::GlaceComposite, dt, rho, u, E, c, p, - bc_descriptor_list); + .apply(AcousticCompositeSolverHandler::SolverType::GlaceComposite, dt, rho, u, E, c, + p, bc_descriptor_list); } )); + this->_addBuiltinFunction("rusanov_eulerian_composite_solver_version1", + std::function( + + [](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>& 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, c, p, bc_descriptor_list, dt); + } + + )); - this->_addBuiltinFunction("eucclhyd_fluxes", std::function( @@ -510,7 +539,7 @@ SchemeModule::SchemeModule() )); - this->_addBuiltinFunction("composite_eucclhyd_fluxes", + this->_addBuiltinFunction("composite_eucclhyd_fluxes", std::function( [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, @@ -520,22 +549,19 @@ SchemeModule::SchemeModule() const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) -> std::tuple<std::shared_ptr<const ItemValueVariant>, - std::shared_ptr<const SubItemValuePerItemVariant>, - std::shared_ptr<const ItemValueVariant>, - std::shared_ptr<const SubItemValuePerItemVariant>, - std::shared_ptr<const ItemValueVariant>, - std::shared_ptr<const SubItemValuePerItemVariant> - > { + std::shared_ptr<const SubItemValuePerItemVariant>, + std::shared_ptr<const ItemValueVariant>, + std::shared_ptr<const SubItemValuePerItemVariant>, + std::shared_ptr<const ItemValueVariant>, + std::shared_ptr<const SubItemValuePerItemVariant>> { return AcousticCompositeSolverHandler{getCommonMesh({rho, c, u, p})} .solver() - .compute_fluxes(AcousticCompositeSolverHandler::SolverType::EucclhydComposite, rho, c, u, p, - bc_descriptor_list); + .compute_fluxes(AcousticCompositeSolverHandler::SolverType::EucclhydComposite, rho, c, + u, p, bc_descriptor_list); } )); - - this->_addBuiltinFunction("eucclhyd_solver", std::function( @@ -574,13 +600,12 @@ SchemeModule::SchemeModule() std::shared_ptr<const DiscreteFunctionVariant>> { return AcousticCompositeSolverHandler{getCommonMesh({rho, u, E, c, p})} .solver() - .apply(AcousticCompositeSolverHandler::SolverType::EucclhydComposite, dt, rho, u, E, c, p, - bc_descriptor_list); + .apply(AcousticCompositeSolverHandler::SolverType::EucclhydComposite, dt, rho, u, E, + c, p, bc_descriptor_list); } )); - this->_addBuiltinFunction("apply_acoustic_fluxes", std::function( @@ -599,7 +624,7 @@ SchemeModule::SchemeModule() } )); - this->_addBuiltinFunction("apply_acoustic_composite_fluxes", + this->_addBuiltinFunction("apply_acoustic_composite_fluxes", std::function( [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, // @@ -607,17 +632,17 @@ SchemeModule::SchemeModule() const std::shared_ptr<const DiscreteFunctionVariant>& E, // const std::shared_ptr<const ItemValueVariant>& ur, // const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr, // - const std::shared_ptr<const ItemValueVariant>& ue, // + const std::shared_ptr<const ItemValueVariant>& ue, // const std::shared_ptr<const SubItemValuePerItemVariant>& Fje, // - const std::shared_ptr<const ItemValueVariant>& uf, // - const std::shared_ptr<const SubItemValuePerItemVariant>& Fjf, // + const std::shared_ptr<const ItemValueVariant>& uf, // + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjf, // const double& dt) -> std::tuple<std::shared_ptr<const MeshVariant>, std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> { return AcousticCompositeSolverHandler{getCommonMesh({rho, u, E})} // - .solver() - .apply_fluxes(dt, rho, u, E, ur, Fjr, ue, Fje, uf, Fjf); + .solver() + .apply_fluxes(dt, rho, u, E, ur, Fjr, ue, Fje, uf, Fjf); } )); diff --git a/src/mesh/MeshData.hpp b/src/mesh/MeshData.hpp index 38f8e7f29697c476dca64f0a8006f447aef1e24c..a23d778a6a41df49f06af3c00fa95272c79852d7 100644 --- a/src/mesh/MeshData.hpp +++ b/src/mesh/MeshData.hpp @@ -31,27 +31,27 @@ class MeshData<Mesh<Dimension>> const MeshType& m_mesh; NodeValuePerFace<const Rd> m_Nlr; NodeValuePerFace<const Rd> m_nlr; - + NodeValuePerCell<const Rd> m_Cjr; EdgeValuePerCell<const Rd> m_Cje; FaceValuePerCell<const Rd> m_Cjf; - + NodeValuePerCell<const double> m_ljr; NodeValuePerCell<const Rd> m_njr; EdgeValuePerCell<const double> m_lje; EdgeValuePerCell<const Rd> m_nje; FaceValuePerCell<const double> m_ljf; FaceValuePerCell<const Rd> m_njf; - + FaceValue<const Rd> m_xl; CellValue<const Rd> m_cell_centroid; CellValue<const Rd> m_cell_iso_barycenter; CellValue<const double> m_Vj; - + CellValue<const double> m_sum_r_ljr; CellValue<const double> m_sum_e_lje; CellValue<const double> m_sum_f_ljf; - + FaceValue<const Rd> m_Nl; FaceValue<const Rd> m_nl; FaceValue<const double> m_ll; @@ -143,8 +143,7 @@ class MeshData<Mesh<Dimension>> m_nlr = nlr; } } - - + PUGS_INLINE void _computeFaceIsobarycenter() @@ -505,8 +504,6 @@ class MeshData<Mesh<Dimension>> } } - - PUGS_INLINE void _computeCjf() @@ -528,9 +525,9 @@ class MeshData<Mesh<Dimension>> 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(); + 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]}; + Cjf(j, R) = Rd{xrp_xr[1], -xrp_xr[0]}; } }); m_Cjf = Cjf; @@ -545,16 +542,15 @@ class MeshData<Mesh<Dimension>> parallel_for( m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { - - const auto& cell_faces = cell_to_face_matrix[j]; + const auto& cell_faces = cell_to_face_matrix[j]; for (size_t l = 0; l < cell_faces.size(); ++l) { - const FaceId& F = cell_faces[l]; + const FaceId& F = cell_faces[l]; - if (cell_face_is_reversed(j,l)) - Cjf(j,l)=-Nl[F]; - else - Cjf(j,l)=Nl[F]; + if (cell_face_is_reversed(j, l)) + Cjf(j, l) = -Nl[F]; + else + Cjf(j, l) = Nl[F]; } }); @@ -562,15 +558,14 @@ class MeshData<Mesh<Dimension>> } } - - PUGS_INLINE + PUGS_INLINE void - _compute_ljf() + _compute_ljf() { auto Cjf = this->Cjf(); - + if constexpr (Dimension == 1) { - FaceValuePerCell<double> ljf(m_mesh.connectivity()); + FaceValuePerCell<double> ljf(m_mesh.connectivity()); parallel_for( ljf.numberOfValues(), PUGS_LAMBDA(size_t jf) { ljf[jf] = 1; }); m_ljf = ljf; @@ -583,8 +578,7 @@ class MeshData<Mesh<Dimension>> } } - - PUGS_INLINE + PUGS_INLINE void _compute_njf() { @@ -602,7 +596,6 @@ class MeshData<Mesh<Dimension>> } } - PUGS_INLINE void _computeCje() @@ -624,17 +617,17 @@ class MeshData<Mesh<Dimension>> 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(); + 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]}; + Cje(j, R) = Rd{xrp_xr[1], -xrp_xr[0]}; } }); m_Cje = Cje; } else if (Dimension == 3) { auto Nlr = this->Nlr(); - const auto& face_to_node_matrix = m_mesh.connectivity().faceToNodeMatrix(); - //const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); + const auto& face_to_node_matrix = m_mesh.connectivity().faceToNodeMatrix(); + // const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); const auto& cell_to_face_matrix = m_mesh.connectivity().cellToFaceMatrix(); const auto& cell_to_edge_matrix = m_mesh.connectivity().cellToEdgeMatrix(); const auto& edge_to_face_matrix = m_mesh.connectivity().edgeToFaceMatrix(); @@ -646,63 +639,61 @@ class MeshData<Mesh<Dimension>> parallel_for( m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { - const auto& cell_faces = cell_to_face_matrix[j]; - const auto& cell_edges = cell_to_edge_matrix[j]; - + const auto& cell_faces = cell_to_face_matrix[j]; + const auto& cell_edges = cell_to_edge_matrix[j]; + for (size_t i_edge = 0; i_edge < cell_edges.size(); ++i_edge) { - const EdgeId edge_id = cell_edges[i_edge]; - auto edges_faces = edge_to_face_matrix[edge_id]; - auto edges_nodes = edge_to_node_matrix[edge_id]; - - const NodeId& node0_id= edges_nodes[0]; - const NodeId& node1_id= edges_nodes[1]; - - int nbFacEdge=0; - - // On ne garde que si les 2 faces qui sont dans la maille - //bool findTwoFaces=false; - for (size_t i_face = 0; i_face < edges_faces.size(); ++i_face) { - const FaceId face_id = edges_faces[i_face]; - - for (size_t i_face_cell = 0; i_face_cell < cell_faces.size(); ++i_face_cell) { - const FaceId face_id_cell = cell_faces[i_face_cell]; - - if (face_id_cell==face_id) { - - double sign = (cell_face_is_reversed(j, i_face_cell)) ? -1 : 1; - - const auto& face_nodes = face_to_node_matrix[face_id_cell]; - - for (size_t rl = 0; rl < face_nodes.size(); ++rl) { - if (node0_id==face_nodes[rl] or node1_id==face_nodes[rl]) - Cje(j,i_edge)+=.5*sign*Nlr(face_id_cell,rl); - } - //findTwoFaces=true; - ++nbFacEdge; - break; - } - } - } - - if (nbFacEdge!=2) - { - throw NormalError("Probleme finding edge mesh ") ; - } - } + const EdgeId edge_id = cell_edges[i_edge]; + auto edges_faces = edge_to_face_matrix[edge_id]; + auto edges_nodes = edge_to_node_matrix[edge_id]; + + const NodeId& node0_id = edges_nodes[0]; + const NodeId& node1_id = edges_nodes[1]; + + int nbFacEdge = 0; + + // On ne garde que si les 2 faces qui sont dans la maille + // bool findTwoFaces=false; + for (size_t i_face = 0; i_face < edges_faces.size(); ++i_face) { + const FaceId face_id = edges_faces[i_face]; + + for (size_t i_face_cell = 0; i_face_cell < cell_faces.size(); ++i_face_cell) { + const FaceId face_id_cell = cell_faces[i_face_cell]; + + if (face_id_cell == face_id) { + double sign = (cell_face_is_reversed(j, i_face_cell)) ? -1 : 1; + + const auto& face_nodes = face_to_node_matrix[face_id_cell]; + + for (size_t rl = 0; rl < face_nodes.size(); ++rl) { + if (node0_id == face_nodes[rl] or node1_id == face_nodes[rl]) + Cje(j, i_edge) += .5 * sign * Nlr(face_id_cell, rl); + } + // findTwoFaces=true; + ++nbFacEdge; + break; + } + } + } + + if (nbFacEdge != 2) { + throw NormalError("Probleme finding edge mesh "); + } + } }); - + m_Cje = Cje; } - } + } - PUGS_INLINE + PUGS_INLINE void - _compute_lje() + _compute_lje() { auto Cje = this->Cje(); - + if constexpr (Dimension == 1) { - EdgeValuePerCell<double> lje(m_mesh.connectivity()); + EdgeValuePerCell<double> lje(m_mesh.connectivity()); parallel_for( lje.numberOfValues(), PUGS_LAMBDA(size_t je) { lje[je] = 1; }); m_lje = lje; @@ -715,8 +706,7 @@ class MeshData<Mesh<Dimension>> } } - - PUGS_INLINE + PUGS_INLINE void _compute_nje() { @@ -734,9 +724,6 @@ class MeshData<Mesh<Dimension>> } } - - - PUGS_INLINE void _computeSumOverRljr() @@ -764,7 +751,7 @@ class MeshData<Mesh<Dimension>> m_sum_r_ljr = sum_r_ljr; } - + PUGS_INLINE void _computeSumOverElje() @@ -821,8 +808,6 @@ class MeshData<Mesh<Dimension>> m_sum_f_ljf = sum_f_ljf; } - - void _checkCellVolume() { @@ -930,7 +915,6 @@ class MeshData<Mesh<Dimension>> return m_njr; } - PUGS_INLINE EdgeValuePerCell<const Rd> Cje() @@ -991,8 +975,6 @@ class MeshData<Mesh<Dimension>> return m_njf; } - - PUGS_INLINE FaceValue<const Rd> xl() @@ -1053,7 +1035,7 @@ class MeshData<Mesh<Dimension>> } return m_sum_r_ljr; } - + PUGS_INLINE CellValue<const double> sumOverELje() @@ -1063,7 +1045,7 @@ class MeshData<Mesh<Dimension>> } return m_sum_e_lje; } - + PUGS_INLINE CellValue<const double> sumOverFLjf() @@ -1074,7 +1056,6 @@ class MeshData<Mesh<Dimension>> return m_sum_f_ljf; } - private: // MeshData **must** be constructed through MeshDataManager friend class MeshDataManager; diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt index 8cdd43f9e51e3b36c0c93e4d4cbfcbdfd9325f71..e285dbde1250fae2ebe063291db6bba6cc8bc2ec 100644 --- a/src/scheme/CMakeLists.txt +++ b/src/scheme/CMakeLists.txt @@ -11,6 +11,7 @@ add_library( DiscreteFunctionVectorIntegrator.cpp DiscreteFunctionVectorInterpoler.cpp FluxingAdvectionSolver.cpp + RusanovEulerianCompositeSolver.cpp ) target_link_libraries( diff --git a/src/scheme/IBoundaryConditionDescriptor.hpp b/src/scheme/IBoundaryConditionDescriptor.hpp index 1350aa4dba4f7f6739b7de6689c10554ceec6971..e1169aed79c785ffe7c768ee4762b50e122dabb2 100644 --- a/src/scheme/IBoundaryConditionDescriptor.hpp +++ b/src/scheme/IBoundaryConditionDescriptor.hpp @@ -17,6 +17,7 @@ class IBoundaryConditionDescriptor fixed, free, inflow, + inflow_list, neumann, outflow, symmetry diff --git a/src/scheme/InflowListBoundaryConditionDescriptor.hpp b/src/scheme/InflowListBoundaryConditionDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3effc4315d886930708de629713f28a3010f6365 --- /dev/null +++ b/src/scheme/InflowListBoundaryConditionDescriptor.hpp @@ -0,0 +1,55 @@ +#ifndef INFLOW_LIST_BOUNDARY_CONDITION_DESCRIPTOR_HPP +#define INFLOW_LIST_BOUNDARY_CONDITION_DESCRIPTOR_HPP + +#include <language/utils/FunctionSymbolId.hpp> +#include <mesh/IBoundaryDescriptor.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> + +#include <memory> + +class InflowListBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +{ + private: + std::ostream& + _write(std::ostream& os) const final + { + os << "inflow_list(" << ',' << *m_boundary_descriptor << ")"; + return os; + } + + std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; + const std::vector<FunctionSymbolId> m_function_symbol_id_list; + + public: + const std::vector<FunctionSymbolId>& + functionSymbolIdList() const + { + return m_function_symbol_id_list; + } + + const IBoundaryDescriptor& + boundaryDescriptor() const final + { + return *m_boundary_descriptor; + } + + Type + type() const final + { + return Type::inflow_list; + } + + InflowListBoundaryConditionDescriptor(std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor, + const std::vector<FunctionSymbolId>& function_symbol_id_list) + : m_boundary_descriptor(boundary_descriptor), m_function_symbol_id_list{function_symbol_id_list} + { + ; + } + + InflowListBoundaryConditionDescriptor(const InflowListBoundaryConditionDescriptor&) = delete; + InflowListBoundaryConditionDescriptor(InflowListBoundaryConditionDescriptor&&) = delete; + + ~InflowListBoundaryConditionDescriptor() = default; +}; + +#endif // INFLOW_LIST_BOUNDARY_CONDITION_DESCRIPTOR_HPP diff --git a/src/scheme/RusanovEulerianCompositeSolver.cpp b/src/scheme/RusanovEulerianCompositeSolver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..633c324cd3bc0bcd1f0b2e9482e78dec5aed1c96 --- /dev/null +++ b/src/scheme/RusanovEulerianCompositeSolver.cpp @@ -0,0 +1,499 @@ +#include <scheme/RusanovEulerianCompositeSolver.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 +{ + private: + using MeshType = MeshTypeT; + + static constexpr size_t Dimension = MeshType::Dimension; + + using Rdxd = TinyMatrix<Dimension>; + using Rd = TinyVector<Dimension>; + + class SymmetryBoundaryCondition; + class InflowListBoundaryCondition; + class OutflowBoundaryCondition; + + using BoundaryCondition = + std::variant<SymmetryBoundaryCondition, InflowListBoundaryCondition, OutflowBoundaryCondition>; + + 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 Eulerian Composite solver"; + throw NormalError(error_msg.str()); + } + } + + return bc_list; + } + + public: + 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 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 + { + 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); + + return std::make_tuple(std::make_shared<const DiscreteFunctionVariant>(rho), + std::make_shared<const DiscreteFunctionVariant>(u), + std::make_shared<const DiscreteFunctionVariant>(E)); + } + + RusanovEulerianCompositeSolver() = default; + ~RusanovEulerianCompositeSolver() = default; +}; + +template <MeshConcept MeshType> +class RusanovEulerianCompositeSolver<MeshType>::SymmetryBoundaryCondition +{ +}; + +template <> +class RusanovEulerianCompositeSolver<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<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<MeshType>::InflowListBoundaryCondition +{ +}; + +template <> +class RusanovEulerianCompositeSolver<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<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<MeshType>::OutflowBoundaryCondition +{ +}; + +std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +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 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) +{ + 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 is not available in 1D"); + } else { + if constexpr (is_polygonal_mesh_v<MeshType>) { + return RusanovEulerianCompositeSolver<MeshType>{}.solve(p_mesh, + rho_v->get<DiscreteFunctionP0<const double>>(), + u_v->get<DiscreteFunctionP0<const Rd>>(), + E_v->get<DiscreteFunctionP0<const double>>(), + c_v->get<DiscreteFunctionP0<const double>>(), + p_v->get<DiscreteFunctionP0<const double>>(), + bc_descriptor_list, dt); + } else { + throw NormalError("RusanovEulerianCompositeSolver is only defined on polygonal meshes"); + } + } + }, + mesh_v->variant()); +} diff --git a/src/scheme/RusanovEulerianCompositeSolver.hpp b/src/scheme/RusanovEulerianCompositeSolver.hpp new file mode 100644 index 0000000000000000000000000000000000000000..69dfb6be8c4b762dad42414feebb20d2eec0b337 --- /dev/null +++ b/src/scheme/RusanovEulerianCompositeSolver.hpp @@ -0,0 +1,23 @@ +#ifndef RUSANOV_EULERIAN_COMPOSITE_SOLVER_HPP +#define RUSANOV_EULERIAN_COMPOSITE_SOLVER_HPP + +#include <mesh/MeshVariant.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> + +#include <memory> +#include <vector> + +std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +rusanovEulerianCompositeSolver( + 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>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const double& dt); + +#endif // RUSANOV_EULERIAN_COMPOSITE_SOLVER_HPP diff --git a/tests/test_TestVolumes3D.cpp b/tests/test_TestVolumes3D.cpp index 2bf95290526dbd3e6816f4cee2dd53a6640cb6bc..7006dc7ebeb2a17ba25615e57304af00b9b8c0df 100644 --- a/tests/test_TestVolumes3D.cpp +++ b/tests/test_TestVolumes3D.cpp @@ -1,8 +1,8 @@ #include <catch2/catch_approx.hpp> #include <catch2/catch_test_macros.hpp> -#include <mesh/ItemArrayUtils.hpp> #include <mesh/DualMeshManager.hpp> +#include <mesh/ItemArrayUtils.hpp> #include <mesh/ItemValue.hpp> #include <mesh/ItemValueUtils.hpp> #include <mesh/Mesh.hpp> @@ -16,278 +16,263 @@ TEST_CASE("TestVolumes3D", "[scheme]") { SECTION("3D") - { - using R3 = TinyVector<3>; - - auto hybrid_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); - /* - auto f = [](const R3& X) -> double { - const double x = X[0]; - const double y = X[1]; - const double z = X[2]; - return x * x + 2 * x * y + 3 * y * y + 2 * z * z - z + 1; - }; - */ - std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list; - mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); - mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh))); - - for (const auto& mesh_info : mesh_list) { - auto mesh_name = mesh_info.first; - auto mesh = mesh_info.second->get<Mesh<3>>(); - std::clog << " name " << mesh_name << "\n"; - auto& mesh_data = MeshDataManager::instance().getMeshData(*mesh); - - auto Cjr = mesh_data.Cjr(); - auto Cje = mesh_data.Cje(); - auto Cjf = mesh_data.Cjf(); - - auto xr = mesh->xr(); - auto Vj = mesh_data.Vj(); - - auto xl = mesh_data.xl(); // Les centres des faces - auto xe = mesh_data.xe(); // Les centres des aretes - auto Nl = mesh_data.Nl(); // Normale aux faces .. au "centre" des faces - auto nl = mesh_data.nl(); // Normale unite aux faces .. au "centre" des faces - - NodeValuePerFace<const R3> Nlr=mesh_data.Nlr(); - - auto cell_to_node_connectivity = mesh->connectivity().cellToNodeMatrix(); - auto cell_to_face_connectivity = mesh->connectivity().cellToFaceMatrix(); - - const auto& cell_face_is_reversed = mesh->connectivity().cellFaceIsReversed(); - - auto cell_to_edge_connectivity = mesh->connectivity().cellToEdgeMatrix(); - auto edge_to_node_connectivity = mesh->connectivity().edgeToNodeMatrix(); - auto edge_to_face_connectivity = mesh->connectivity().edgeToFaceMatrix(); - auto face_to_node_connectivity = mesh->connectivity().faceToNodeMatrix(); - - FaceValuePerCell<R3> face_normal_per_cell(mesh->connectivity()); - face_normal_per_cell.fill(zero); - EdgeValuePerCell<R3> edge_normal_per_cell(mesh->connectivity()); - edge_normal_per_cell.fill(zero); - CellValue<double> tabErrVolCjr(mesh->connectivity()); - CellValue<double> tabErrVolCjf(mesh->connectivity()); - CellValue<double> tabErrVolCje(mesh->connectivity()); - tabErrVolCjr.fill(0.); - tabErrVolCjf.fill(0.); - tabErrVolCje.fill(0.); - - CellValue<double> tabErrStokesCjr(mesh->connectivity()); - CellValue<double> tabErrStokesCjf(mesh->connectivity()); - CellValue<double> tabErrStokesCje(mesh->connectivity()); - tabErrStokesCjr.fill(0.); - tabErrStokesCjf.fill(0.); - tabErrStokesCje.fill(0.); - - NodeValue<double> tabErrConservation_r_Cjr(mesh->connectivity()); - FaceValue<double> tabErrConservation_f_Cjf(mesh->connectivity()); - EdgeValue<double> tabErrConservation_e_Cje(mesh->connectivity()); - tabErrConservation_r_Cjr.fill(0.); - tabErrConservation_f_Cjf.fill(0.); - tabErrConservation_e_Cje.fill(0.); - - parallel_for(mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - - // ******************************** - // Travail sur les nodes - // ******************************** - - auto cell_nodes = cell_to_node_connectivity[cell_id]; - double SumCjrXr=0; - R3 SumCjr=R3{0,0,0}; - for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { - const NodeId node_id = cell_nodes[i_node]; - SumCjrXr+=dot(Cjr(cell_id,i_node),xr[node_id]); - SumCjr+=Cjr(cell_id,i_node); - } - SumCjrXr/=3.; - tabErrVolCjr[cell_id]=fabs(Vj[cell_id]-SumCjrXr); - tabErrStokesCjr[cell_id]=l2Norm(SumCjr); - - // ******************************** - // Travail sur les faces - // ******************************** - - auto cell_faces = cell_to_face_connectivity[cell_id]; - const auto& face_is_reversed = cell_face_is_reversed.itemArray(cell_id); - - double SumCjrXf=0; - R3 SumCjf=R3{0,0,0}; - double SumCjrXf_mesh=0; - R3 SumCjf_mesh=R3{0,0,0}; - for (size_t i_face = 0; i_face < cell_faces.size(); ++i_face) { - const FaceId face_id = cell_faces[i_face]; - SumCjrXf_mesh+=dot(Cjf(cell_id,i_face),xl[face_id]); - SumCjf_mesh+=Cjf(cell_id,i_face); - - if (face_is_reversed[i_face]) - { - face_normal_per_cell[cell_id][i_face]=-Nl[face_id]; - SumCjrXf-=dot(Nl[face_id],xl[face_id]); - SumCjf-=Nl[face_id]; - } - else - { - face_normal_per_cell[cell_id][i_face]=Nl[face_id]; - SumCjrXf+=dot(Nl[face_id],xl[face_id]); - SumCjf+=Nl[face_id]; - } - } - SumCjrXf/=3.; - SumCjrXf_mesh/=3.; - tabErrVolCjf[cell_id]=fabs(Vj[cell_id]-SumCjrXf); - tabErrStokesCjf[cell_id]=l2Norm(SumCjf); - - // ******************************** - // Travail sur les edges - // ******************************** - //auto cell_faces = cell_to_face_connectivity[cell_id]; - //const auto& face_is_reversed = cell_face_is_reversed.itemArray(cell_id); - //const auto& cell_face_is_reversed = mesh->connectivity().cellFaceIsReversed(); - - auto cell_edges = cell_to_edge_connectivity[cell_id]; - double SumCjrXe=0; - R3 SumCje=zero; - double SumCjrXe_mesh=0; - R3 SumCje_mesh=zero; - - for (size_t i_edge = 0; i_edge < cell_edges.size(); ++i_edge) { - const EdgeId edge_id = cell_edges[i_edge]; - - SumCjrXe_mesh+=dot(Cje(cell_id,i_edge),xe[edge_id]); - SumCje_mesh+=Cje(cell_id,i_edge); - - auto edges_faces = edge_to_face_connectivity[edge_id]; - //auto cell_faces = cell_to_face_connectivity[edge_id]; - auto edges_nodes = edge_to_node_connectivity[edge_id]; - - const NodeId& node0_id= edges_nodes[0]; - const NodeId& node1_id= edges_nodes[1]; - - int nbFacEdge=0; - // On ne garde que si les 2 faces qui sont dans la maille - for (size_t i_face = 0; i_face < edges_faces.size(); ++i_face) { - const FaceId face_id = edges_faces[i_face]; - - for (size_t i_face_cell = 0; i_face_cell < cell_faces.size(); ++i_face_cell) { - const FaceId face_id_cell = cell_faces[i_face_cell]; - - // La face autour de l arete appartient à la maille courante : On peut faire le calcul avec la face - if (face_id_cell==face_id) - { - - double sign = (cell_face_is_reversed(cell_id, i_face_cell)) ? -1 : 1; - - const auto& face_nodes = face_to_node_connectivity[face_id_cell]; - - for (size_t rl = 0; rl < face_nodes.size(); ++rl) { - if (node0_id==face_nodes[rl] or node1_id==face_nodes[rl]) - edge_normal_per_cell(cell_id,i_edge)+=.5*sign*Nlr(face_id_cell,rl); - } - - ++nbFacEdge; - break; - } - } - } - - if (nbFacEdge!=2) - { - exit(1); - } - - R3 Cje_l=edge_normal_per_cell[cell_id][i_edge]; - //R3 Cje_l=Cje(cell_id,i_edge);//edge_normal_per_cell[cell_id][i_edge]; - - SumCjrXe+=dot(Cje_l,xe[edge_id]); - SumCje+=Cje_l; - } - SumCjrXe/=3.; - SumCjrXe_mesh/=3.; - - tabErrVolCje[cell_id]=fabs(Vj[cell_id]-SumCjrXe); - tabErrStokesCje[cell_id]=l2Norm(SumCje); - - }); - - auto node_to_cell_connectivity = mesh->connectivity().nodeToCellMatrix(); - auto face_to_cell_connectivity = mesh->connectivity().faceToCellMatrix(); - auto edge_to_cell_connectivity = mesh->connectivity().edgeToCellMatrix(); - - auto is_boundary_node = mesh->connectivity().isBoundaryNode(); - auto is_boundary_face = mesh->connectivity().isBoundaryFace(); - auto is_boundary_edge = mesh->connectivity().isBoundaryEdge(); - - parallel_for(mesh->numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) - { - R3 SumCjr=R3{0,0,0}; - if (not is_boundary_node[node_id]) - { - - for (size_t i_node = 0; i_node < node_to_cell_connectivity[node_id].size(); ++i_node) { - const CellId cell_id= node_to_cell_connectivity[node_id][i_node]; - - - for (size_t i_node_cell = 0; i_node_cell < cell_to_node_connectivity[cell_id].size(); ++i_node_cell) { - const NodeId node_cell_id = cell_to_node_connectivity[cell_id][i_node_cell]; - if (node_id==node_cell_id) - { - SumCjr+=Cjr(cell_id,i_node_cell); - break; - } - } - } - } - tabErrConservation_r_Cjr[node_id]=l2Norm(SumCjr); - }); - - parallel_for(mesh->numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) { - R3 SumCjf=zero; - if (not is_boundary_face[face_id]) - { - for (size_t i_face = 0; i_face < face_to_cell_connectivity[face_id].size(); ++i_face) { - const CellId cell_id= face_to_cell_connectivity[face_id][i_face]; - - for (size_t i_face_cell = 0; i_face_cell < cell_to_face_connectivity[cell_id].size(); ++i_face_cell) { - const FaceId face_cell_id = cell_to_face_connectivity[cell_id][i_face_cell]; - if (face_id==face_cell_id) - { - SumCjf+=face_normal_per_cell[cell_id][i_face_cell]; - break; - } - } - } - } - tabErrConservation_f_Cjf[face_id]=l2Norm(SumCjf)+1e-13;//R3(1e-13,1e-56,1e-34}; - }); - - parallel_for(mesh->numberOfEdges(), PUGS_LAMBDA(const EdgeId edge_id) { - R3 SumCje=zero; - - if (not is_boundary_edge[edge_id]) - { - for (size_t i_edge = 0; i_edge < edge_to_cell_connectivity[edge_id].size(); ++i_edge) { - const CellId cell_id= edge_to_cell_connectivity[edge_id][i_edge]; - - for (size_t i_edge_cell = 0; i_edge_cell < cell_to_edge_connectivity[cell_id].size(); ++i_edge_cell) { - const EdgeId edge_cell_id = cell_to_edge_connectivity[cell_id][i_edge_cell]; - if (edge_id==edge_cell_id) - { - SumCje+=edge_normal_per_cell[cell_id][i_edge_cell]; - //SumCje+=Cje(cell_id,i_edge_cell);//edge_normal_per_cell[cell_id][i_edge_cell]; - break; - } - } - } - } - tabErrConservation_e_Cje[edge_id]=l2Norm(SumCje); - }); - //std::clog << " Max Cje et tab " << max(dif_edge_normal_per_cell) << "\n" ; - std::clog << " Max Error (Stokes/Vol/Cons) Cjr " << max(tabErrStokesCjr) << "/" << max(tabErrVolCjr) << "/" << max(tabErrConservation_r_Cjr) << " Max Error (Stokes/Vol/Cons) Cjf " << max(tabErrStokesCjf) << "/" << max(tabErrVolCjf) << "/" << max(tabErrConservation_f_Cjf) << " Max Error (Stokes/Vol/Cons) Cje "<< max(tabErrStokesCje) << "/" << max(tabErrVolCje) << "/"<< max(tabErrConservation_e_Cje) << "\n"; - - //1.00868e-16/1.73472e-18/2.399e-17 Max Error (Stokes/Vol/Cons) Cjf 9.10193e-17/1.82146e-17/2.22507e-308 Max Error (Stokes/Vol/Cons) Cje - - } + { + using R3 = TinyVector<3>; + + auto hybrid_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); + /* + auto f = [](const R3& X) -> double { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return x * x + 2 * x * y + 3 * y * y + 2 * z * z - z + 1; + }; + */ + std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list; + mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); + mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh))); + + for (const auto& mesh_info : mesh_list) { + auto mesh_name = mesh_info.first; + auto mesh = mesh_info.second->get<Mesh<3>>(); + + auto& mesh_data = MeshDataManager::instance().getMeshData(*mesh); + + auto Cjr = mesh_data.Cjr(); + auto Cje = mesh_data.Cje(); + auto Cjf = mesh_data.Cjf(); + + auto xr = mesh->xr(); + auto Vj = mesh_data.Vj(); + + auto xl = mesh_data.xl(); // Les centres des faces + auto xe = mesh_data.xe(); // Les centres des aretes + auto Nl = mesh_data.Nl(); // Normale aux faces .. au "centre" des faces + auto nl = mesh_data.nl(); // Normale unite aux faces .. au "centre" des faces + + NodeValuePerFace<const R3> Nlr = mesh_data.Nlr(); + + auto cell_to_node_connectivity = mesh->connectivity().cellToNodeMatrix(); + auto cell_to_face_connectivity = mesh->connectivity().cellToFaceMatrix(); + + const auto& cell_face_is_reversed = mesh->connectivity().cellFaceIsReversed(); + + auto cell_to_edge_connectivity = mesh->connectivity().cellToEdgeMatrix(); + auto edge_to_node_connectivity = mesh->connectivity().edgeToNodeMatrix(); + auto edge_to_face_connectivity = mesh->connectivity().edgeToFaceMatrix(); + auto face_to_node_connectivity = mesh->connectivity().faceToNodeMatrix(); + + FaceValuePerCell<R3> face_normal_per_cell(mesh->connectivity()); + face_normal_per_cell.fill(zero); + EdgeValuePerCell<R3> edge_normal_per_cell(mesh->connectivity()); + edge_normal_per_cell.fill(zero); + CellValue<double> tabErrVolCjr(mesh->connectivity()); + CellValue<double> tabErrVolCjf(mesh->connectivity()); + CellValue<double> tabErrVolCje(mesh->connectivity()); + tabErrVolCjr.fill(0.); + tabErrVolCjf.fill(0.); + tabErrVolCje.fill(0.); + + CellValue<double> tabErrStokesCjr(mesh->connectivity()); + CellValue<double> tabErrStokesCjf(mesh->connectivity()); + CellValue<double> tabErrStokesCje(mesh->connectivity()); + tabErrStokesCjr.fill(0.); + tabErrStokesCjf.fill(0.); + tabErrStokesCje.fill(0.); + + NodeValue<double> tabErrConservation_r_Cjr(mesh->connectivity()); + FaceValue<double> tabErrConservation_f_Cjf(mesh->connectivity()); + EdgeValue<double> tabErrConservation_e_Cje(mesh->connectivity()); + tabErrConservation_r_Cjr.fill(0.); + tabErrConservation_f_Cjf.fill(0.); + tabErrConservation_e_Cje.fill(0.); + + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + // ******************************** + // Travail sur les nodes + // ******************************** + + auto cell_nodes = cell_to_node_connectivity[cell_id]; + double SumCjrXr = 0; + R3 SumCjr = R3{0, 0, 0}; + for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { + const NodeId node_id = cell_nodes[i_node]; + SumCjrXr += dot(Cjr(cell_id, i_node), xr[node_id]); + SumCjr += Cjr(cell_id, i_node); + } + SumCjrXr /= 3.; + tabErrVolCjr[cell_id] = fabs(Vj[cell_id] - SumCjrXr); + tabErrStokesCjr[cell_id] = l2Norm(SumCjr); + + // ******************************** + // Travail sur les faces + // ******************************** + + auto cell_faces = cell_to_face_connectivity[cell_id]; + const auto& face_is_reversed = cell_face_is_reversed.itemArray(cell_id); + + double SumCjrXf = 0; + R3 SumCjf = R3{0, 0, 0}; + double SumCjrXf_mesh = 0; + R3 SumCjf_mesh = R3{0, 0, 0}; + for (size_t i_face = 0; i_face < cell_faces.size(); ++i_face) { + const FaceId face_id = cell_faces[i_face]; + SumCjrXf_mesh += dot(Cjf(cell_id, i_face), xl[face_id]); + SumCjf_mesh += Cjf(cell_id, i_face); + + if (face_is_reversed[i_face]) { + face_normal_per_cell[cell_id][i_face] = -Nl[face_id]; + SumCjrXf -= dot(Nl[face_id], xl[face_id]); + SumCjf -= Nl[face_id]; + } else { + face_normal_per_cell[cell_id][i_face] = Nl[face_id]; + SumCjrXf += dot(Nl[face_id], xl[face_id]); + SumCjf += Nl[face_id]; + } + } + SumCjrXf /= 3.; + SumCjrXf_mesh /= 3.; + tabErrVolCjf[cell_id] = fabs(Vj[cell_id] - SumCjrXf); + tabErrStokesCjf[cell_id] = l2Norm(SumCjf); + + // ******************************** + // Travail sur les edges + // ******************************** + // auto cell_faces = cell_to_face_connectivity[cell_id]; + // const auto& face_is_reversed = cell_face_is_reversed.itemArray(cell_id); + // const auto& cell_face_is_reversed = mesh->connectivity().cellFaceIsReversed(); + + auto cell_edges = cell_to_edge_connectivity[cell_id]; + double SumCjrXe = 0; + R3 SumCje = zero; + double SumCjrXe_mesh = 0; + R3 SumCje_mesh = zero; + + for (size_t i_edge = 0; i_edge < cell_edges.size(); ++i_edge) { + const EdgeId edge_id = cell_edges[i_edge]; + + SumCjrXe_mesh += dot(Cje(cell_id, i_edge), xe[edge_id]); + SumCje_mesh += Cje(cell_id, i_edge); + + auto edges_faces = edge_to_face_connectivity[edge_id]; + // auto cell_faces = cell_to_face_connectivity[edge_id]; + auto edges_nodes = edge_to_node_connectivity[edge_id]; + + const NodeId& node0_id = edges_nodes[0]; + const NodeId& node1_id = edges_nodes[1]; + + int nbFacEdge = 0; + // On ne garde que si les 2 faces qui sont dans la maille + for (size_t i_face = 0; i_face < edges_faces.size(); ++i_face) { + const FaceId face_id = edges_faces[i_face]; + + for (size_t i_face_cell = 0; i_face_cell < cell_faces.size(); ++i_face_cell) { + const FaceId face_id_cell = cell_faces[i_face_cell]; + + // La face autour de l arete appartient à la maille courante : On peut faire le calcul avec la face + if (face_id_cell == face_id) { + double sign = (cell_face_is_reversed(cell_id, i_face_cell)) ? -1 : 1; + + const auto& face_nodes = face_to_node_connectivity[face_id_cell]; + + for (size_t rl = 0; rl < face_nodes.size(); ++rl) { + if (node0_id == face_nodes[rl] or node1_id == face_nodes[rl]) + edge_normal_per_cell(cell_id, i_edge) += .5 * sign * Nlr(face_id_cell, rl); + } + + ++nbFacEdge; + break; + } + } + } + + if (nbFacEdge != 2) { + throw UnexpectedError("invaid number of edges"); + } + + R3 Cje_l = edge_normal_per_cell[cell_id][i_edge]; + // R3 Cje_l=Cje(cell_id,i_edge);//edge_normal_per_cell[cell_id][i_edge]; + + SumCjrXe += dot(Cje_l, xe[edge_id]); + SumCje += Cje_l; + } + SumCjrXe /= 3.; + SumCjrXe_mesh /= 3.; + + tabErrVolCje[cell_id] = fabs(Vj[cell_id] - SumCjrXe); + tabErrStokesCje[cell_id] = l2Norm(SumCje); + }); + + std::clog << " Max Error Vol et Stokes " << max(tabErrVolCje) << " / " << max(tabErrStokesCje); + auto node_to_cell_connectivity = mesh->connectivity().nodeToCellMatrix(); + auto face_to_cell_connectivity = mesh->connectivity().faceToCellMatrix(); + auto edge_to_cell_connectivity = mesh->connectivity().edgeToCellMatrix(); + + auto is_boundary_node = mesh->connectivity().isBoundaryNode(); + auto is_boundary_face = mesh->connectivity().isBoundaryFace(); + auto is_boundary_edge = mesh->connectivity().isBoundaryEdge(); + + parallel_for( + mesh->numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { + R3 SumCjr = R3{0, 0, 0}; + if (not is_boundary_node[node_id]) { + for (size_t i_node = 0; i_node < node_to_cell_connectivity[node_id].size(); ++i_node) { + const CellId cell_id = node_to_cell_connectivity[node_id][i_node]; + + for (size_t i_node_cell = 0; i_node_cell < cell_to_node_connectivity[cell_id].size(); ++i_node_cell) { + const NodeId node_cell_id = cell_to_node_connectivity[cell_id][i_node_cell]; + if (node_id == node_cell_id) { + SumCjr += Cjr(cell_id, i_node_cell); + break; + } + } + } + } + tabErrConservation_r_Cjr[node_id] = l2Norm(SumCjr); + }); + + parallel_for( + mesh->numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) { + R3 SumCjf = zero; + if (not is_boundary_face[face_id]) { + for (size_t i_face = 0; i_face < face_to_cell_connectivity[face_id].size(); ++i_face) { + const CellId cell_id = face_to_cell_connectivity[face_id][i_face]; + + for (size_t i_face_cell = 0; i_face_cell < cell_to_face_connectivity[cell_id].size(); ++i_face_cell) { + const FaceId face_cell_id = cell_to_face_connectivity[cell_id][i_face_cell]; + if (face_id == face_cell_id) { + SumCjf += face_normal_per_cell[cell_id][i_face_cell]; + break; + } + } + } + } + tabErrConservation_f_Cjf[face_id] = l2Norm(SumCjf); + }); + + parallel_for( + mesh->numberOfEdges(), PUGS_LAMBDA(const EdgeId edge_id) { + R3 SumCje = zero; + + if (not is_boundary_edge[edge_id]) { + for (size_t i_edge = 0; i_edge < edge_to_cell_connectivity[edge_id].size(); ++i_edge) { + const CellId cell_id = edge_to_cell_connectivity[edge_id][i_edge]; + + for (size_t i_edge_cell = 0; i_edge_cell < cell_to_edge_connectivity[cell_id].size(); ++i_edge_cell) { + const EdgeId edge_cell_id = cell_to_edge_connectivity[cell_id][i_edge_cell]; + if (edge_id == edge_cell_id) { + SumCje += edge_normal_per_cell[cell_id][i_edge_cell]; + // SumCje+=Cje(cell_id,i_edge_cell);//edge_normal_per_cell[cell_id][i_edge_cell]; + break; + } + } + } + } + tabErrConservation_e_Cje[edge_id] = l2Norm(SumCje); + }); + + REQUIRE(sum(tabErrConservation_e_Cje) == Catch::Approx(0).margin(1E-13)); } + } }