diff --git a/src/language/modules/CompositeSchemeOtherFluxesModule.cpp b/src/language/modules/CompositeSchemeOtherFluxesModule.cpp index b464c9b9ace5415e7d0ea95ee912f08312288d37..dfc28723a184a4dff1343239e3d6f8962c94bc27 100644 --- a/src/language/modules/CompositeSchemeOtherFluxesModule.cpp +++ b/src/language/modules/CompositeSchemeOtherFluxesModule.cpp @@ -17,8 +17,49 @@ #include <scheme/RusanovEulerianCompositeSolver_v2.hpp> #include <scheme/RusanovEulerianCompositeSolver_v2_o2.hpp> #include <scheme/RusanovEulerianCompositeSolver_v2_order_n.hpp> +#include <scheme/HybridRoeRusanovViscousFormEulerianCompositeSolver_v2.hpp> +#include <scheme/HybridRusanovRoeViscousFormEulerianCompositeSolver_v2.hpp> -CompositeSchemeOtherFluxesModule::CompositeSchemeOtherFluxesModule() {} +CompositeSchemeOtherFluxesModule::CompositeSchemeOtherFluxesModule() { + + this->_addBuiltinFunction("hybrid_roe_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 size_t& degree, + 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 hybridRoeRusanovViscousFormEulerianCompositeSolver_v2(rho, u, E, gamma, c, p, // degree, + bc_descriptor_list, dt); + } + + )); + + this->_addBuiltinFunction("hybrid_rusanov_roe_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 size_t& degree, + 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 hybridRusanovRoeViscousFormEulerianCompositeSolver_v2(rho, u, E, gamma, c, p, // degree, + bc_descriptor_list, dt); + } + + )); +} void CompositeSchemeOtherFluxesModule::registerOperators() const diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt index 009bb3bf1699600c6e520ec20ebf8092fddab94e..c3d8d605084ae1f85eea97cd5c5041d753289c5b 100644 --- a/src/scheme/CMakeLists.txt +++ b/src/scheme/CMakeLists.txt @@ -32,6 +32,8 @@ add_library( RusanovEulerianCompositeSolver_v2_o2.cpp RusanovEulerianCompositeSolver_v2_order_n.cpp RoeViscousFormEulerianCompositeSolver_v2_o2.cpp + HybridRoeRusanovViscousFormEulerianCompositeSolver_v2.cpp + HybridRusanovRoeViscousFormEulerianCompositeSolver_v2.cpp ) target_link_libraries( diff --git a/src/scheme/HybridRoeRusanovViscousFormEulerianCompositeSolver_v2.cpp b/src/scheme/HybridRoeRusanovViscousFormEulerianCompositeSolver_v2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92f258ff2d2abee68a2778efd094ea780f334d6b --- /dev/null +++ b/src/scheme/HybridRoeRusanovViscousFormEulerianCompositeSolver_v2.cpp @@ -0,0 +1,2499 @@ +#include <scheme/HybridRoeRusanovViscousFormEulerianCompositeSolver_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 <mesh/SubItemValuePerItemUtils.hpp> +#include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/InflowListBoundaryConditionDescriptor.hpp> + +#include <variant> + +template <MeshConcept MeshTypeT> +class HybridRoeRusanovViscousFormEulerianCompositeSolver_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>; + + using Rpxd = TinyMatrix<Dimension + 2, Dimension>; + + class SymmetryBoundaryCondition; + class InflowListBoundaryCondition; + class OutflowBoundaryCondition; + class WallBoundaryCondition; + class NeumannflatBoundaryCondition; + + using BoundaryCondition = std::variant<SymmetryBoundaryCondition, + InflowListBoundaryCondition, + OutflowBoundaryCondition, + NeumannflatBoundaryCondition, + WallBoundaryCondition>; + + 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::wall: { + if constexpr (Dimension == 2) { + bc_list.emplace_back(WallBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + } else { + static_assert(Dimension == 3); + bc_list.emplace_back(WallBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshEdgeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + } + break; + } + 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: { + if constexpr (Dimension == 2) { + bc_list.emplace_back( + OutflowBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + } else { + static_assert(Dimension == 3); + bc_list.emplace_back( + OutflowBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshEdgeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + } + break; + // 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 Hybrid Roe/Rusanov v2 Eulerian Composite solver"; + throw NormalError(error_msg.str()); + } + } + + return bc_list; + } + + public: + void + _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>) { + std::cout << " Traitement Outflow \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(); + + const auto xj = mesh.xj(); + const auto xr = mesh.xr(); + const auto xf = mesh.xl(); + const auto xe = mesh.xe(); + + 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] += vectorSym[dim]; + + 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]; + } + } + + // throw NormalError("Not implemented"); + } + */ + } + }, + boundary_condition); + } + } + + void + _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] = stateFace[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); + } + } + + void + _applyNeumannflatBoundaryCondition(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<NeumannflatBoundaryCondition, T>) { + // MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + std::cout << " Traitement WALL \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]; + + vectorSym -= dot(vectorSym, normal) * normal; + + 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] = stateFace[face_cell_id][face_local_number_in_cell][1 + dim]; + + vectorSym -= dot(vectorSym, normal) * normal; + + 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]; + + vectorSym -= dot(vectorSym, normal) * normal; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateEdge[edge_cell_id][edge_local_number_in_cell][dim + 1] = vectorSym[dim]; + } + } + } + } + }, + boundary_condition); + } + } + + void + _applyWallBoundaryCondition(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<WallBoundaryCondition, T>) { + MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + std::cout << " Traitement WALL local (non flat) \n"; + // const Rd& normal = bc.outgoingNormal(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_to_face_matrix = mesh.connectivity().nodeToFaceMatrix(); + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + const auto& node_local_numbers_in_their_faces = mesh.connectivity().nodeLocalNumbersInTheirFaces(); + 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 Cjr = mesh_data.Cjr(); + const auto Cjf = mesh_data.Cjf(); + + for (size_t i_node = 0; i_node < node_list.size(); ++i_node) { + const NodeId node_id = node_list[i_node]; + + const auto& node_face_list = node_to_face_matrix[node_id]; + // Assert(face_cell_list.size() == 1); + // const auto& node_local_number_in_its_faces = node_local_numbers_in_their_faces.itemArray(node_id); + + // on va chercher les normale d'une face issue du noeud de CL et contenue dans le faceList + Rd normal(zero); + int nbnormal = 0; + + for (size_t i_face = 0; i_face < node_face_list.size(); ++i_face) { + FaceId node_face_id = node_face_list[i_face]; + + for (size_t i_facebc = 0; i_facebc < face_list.size(); ++i_facebc) { + const FaceId facebc_id = face_list[i_facebc]; + if (node_face_id == facebc_id) { + const auto& face_cell_list = face_to_cell_matrix[facebc_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(facebc_id, 0); + + // Normal locale approchée + Rd normalloc = Cjf(face_cell_id, face_local_number_in_cell); + normalloc *= 1. / l2Norm(normalloc); + normal += normalloc; + ++nbnormal; + + break; + } + } + } + + if (nbnormal == 0) + continue; + normal *= 1. / nbnormal; + + normal *= 1. / l2Norm(normal); + 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]; + + vectorSym -= dot(vectorSym, normal) * normal; + + 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); + + // Normal locale approchée + Rd normal(Cjf(face_cell_id, face_local_number_in_cell)); + normal *= 1. / l2Norm(normal); + + Rd vectorSym(zero); + for (size_t dim = 0; dim < Dimension; ++dim) + vectorSym[dim] = stateFace[face_cell_id][face_local_number_in_cell][1 + dim]; + + vectorSym -= dot(vectorSym, normal) * normal; + + 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_to_face_matrix = mesh.connectivity().edgeToFaceMatrix(); + + const auto& edge_local_numbers_in_their_faces = mesh.connectivity().edgeLocalNumbersInTheirFaces(); + + 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_face_list = edge_to_face_matrix[edge_id]; + + // on va chercher les normale d'une face issue du edge de CL et contenue dans le faceList + Rd normal(zero); + int nbnormal = 0; + for (size_t i_face = 0; i_face < edge_face_list.size(); ++i_face) { + FaceId edge_face_id = edge_face_list[i_face]; + + for (size_t i_facebc = 0; i_facebc < face_list.size(); ++i_facebc) { + const FaceId facebc_id = face_list[i_facebc]; + if (edge_face_id == facebc_id) { + const auto& face_cell_list = face_to_cell_matrix[facebc_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(facebc_id, 0); + + // Normal locale approchée + Rd normalloc = Cjf(face_cell_id, face_local_number_in_cell); + normalloc *= 1. / l2Norm(normalloc); + normal += normalloc; + ++nbnormal; + break; + } + } + } + + if (nbnormal == 0) + continue; + normal *= 1. / nbnormal; + + normal *= 1. / l2Norm(normal); + + 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); + + 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]; + + vectorSym -= dot(vectorSym, normal) * normal; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateEdge[edge_cell_id][edge_local_number_in_cell][dim + 1] = vectorSym[dim]; + } + } + } + } + }, + boundary_condition); + } + } + + void + _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); + } + } + + public: + inline double + pression(const double rho, const double epsilon, const double gam) const + { + return (gam - 1) * rho * epsilon; + } + + inline Rpxd + Flux(const double& rho, const Rd& U, const double& E, const double gam) const + { + // const R2 flux_rho = rhoU; + // const R22 flux_rhoU = R22(rhoU.x1() * rhoU.x1() / rho + P, rhoU.x1() * rhoU.x2() / rho, rhoU.x2() * rhoU.x1() + // rho,rhoU.x2() * rhoU.x2() / rho + P); + // const R2 flux_rhoE = ((rhoE + P) / rho) * rhoU; + /* 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; + + */ + const Rd& rhoU = rho * U; + const Rdxd rhoUTensU = tensorProduct(rhoU, U); + const double p = pression(rho, E - .5 * dot(U, U), gam); + + Rdxd pid(identity); + pid *= p; + const Rdxd rhoUTensUPlusPid = rhoUTensU + pid; + const double rhoEPlusP = rho * E + p; + + const Rd& rhoEPlusPtimesU = rhoEPlusP * U; + + Rpxd Fluxx; // En ligne ci dessous + + Fluxx[0] = rhoU; + for (size_t dim = 0; dim < Dimension; ++dim) + // for (size_t dim2 = 0; dim2 < Dimension; ++dim2) + Fluxx[1 + dim] = rhoUTensUPlusPid[dim]; + // Fluxx[1 + dim][dim2] = rhoUTensUPlusPid[dim][dim2]; + Fluxx[1 + Dimension] = rhoEPlusPtimesU; + return Fluxx; + } + + struct JacobianInformations + { + Rpxp Jacobian; + Rpxp LeftEigenVectors; + Rpxp RightEigenVectors; + Rp EigenValues; + Rpxp AbsJacobian; + double maxabsVpNormal; + // bool changingSign; + double MaxErrorProd; + + public: + JacobianInformations(const Rpxp& Jacobiand, + const Rpxp& LeftEigenVectorsd, + const Rpxp& RightEigenVectorsd, + const Rp& EigenValuesd, + const Rpxp& AbsJacobiand, + const double maxabsVpNormald, + const double MaxErrorProdd) + : Jacobian(Jacobiand), + LeftEigenVectors(LeftEigenVectorsd), + RightEigenVectors(RightEigenVectorsd), + EigenValues(EigenValuesd), + AbsJacobian(AbsJacobiand), + maxabsVpNormal(maxabsVpNormald), + MaxErrorProd(MaxErrorProdd) + {} + ~JacobianInformations() {} + }; + + Rp + EvaluateEigenValuesNormal( // const double rhod, // rhoJ, uJ, EJ, gammaJ, cJ, pJ, normal + const Rd& Ud, + // const double Ed, + // const double gammad, + const double cd, + // const double pd, + const Rd& normal) const + { + Rp Eigen; + const double uscaln = dot(Ud, normal); + + Eigen[0] = uscaln - cd; + for (size_t dim = 0; dim < Dimension; ++dim) + Eigen[dim] = uscaln; + Eigen[1 + Dimension] = uscaln + cd; + + return Eigen; + } + + struct RoeAverageStateStructData + { + double rho; + Rd U; + double E; + double H; + double gamma; + double p; + double c; + RoeAverageStateStructData(const double rhod, + const Rd Ud, + const double Ed, + const double Hd, + const double gammad, + const double pd, + const double cd) + : rho(rhod), U(Ud), E(Ed), H(Hd), gamma(gammad), p(pd), c(cd) + {} + }; + + RoeAverageStateStructData + RoeAverageState(const double& rhoG, + const Rd& UG, + const double& EG, + const double& gammaG, + const double& pG, + const double& rhoD, + const Rd& UD, + const double& ED, + const double gammaD, + const double pD) const + + { + double gamma = .5 * (gammaG + gammaD); // ou ponderation racine roG et roD + double RacineRoG = sqrt(rhoG); + double RacineRoD = sqrt(rhoD); + double rho_mean = RacineRoG * RacineRoD; + Rd U_mean = 1. / (RacineRoG + RacineRoD) * (RacineRoG * UG + RacineRoD * UD); + double unorm2 = dot(U_mean, U_mean); + double NrjCin = .5 * unorm2; + const double TotEnthalpyG = (EG + pG / rhoG); + const double TotEnthalpyD = (ED + pD / rhoD); + + double H_mean = (RacineRoG * TotEnthalpyG + RacineRoD * TotEnthalpyD) / (RacineRoG + RacineRoD); + + double E_mean = H_mean / gamma + ((gamma - 1) / (gamma)) * (NrjCin); + + double P_mean = rho_mean * (H_mean - E_mean); + + double c2 = gamma * P_mean / rho_mean; // cspeed*cspeed; + // assert(fabs((gamma - 1) * rho_mean * (E_mean - .5 * (u_mean, u_mean)) - P_mean) < 1e-13); // equilibre GP + double c_mean = sqrt(c2); // cspeed_meandof/Area; + + return RoeAverageStateStructData(rho_mean, U_mean, E_mean, H_mean, gamma, P_mean, c_mean); + } + + bool + EvaluateChangingSignVpAlongNormal( // const double rhoJ, + const Rd& uJ, + // const double EJ, + // const double gammaJ, + const double cJ, + // const double pJ, + + // const double rhoK, + const Rd& uK, + // const double EK, + // const double gammaK, + const double cK, + // const double pK, + const Rd& normal) const + { + const Rp& EigenJ = EvaluateEigenValuesNormal( // rhoJ, + uJ, // EJ, gammaJ, + cJ, // pJ, + normal); + + const Rp& EigenK = EvaluateEigenValuesNormal( // rhoK, + uK, // EK, gammaK, + cK, // pK, + normal); + + if (EigenJ[0] * EigenK[0] < -1e-12) // <=0) //< -1e-12) + return true; + for (size_t dim = 1; dim < Dimension + 1; ++dim) // vp multiplicite d + if (EigenJ[dim] * EigenK[dim] < -1e-12) // <=0) //< -1e-12) + return true; + if (EigenJ[1 + Dimension] * EigenK[1 + Dimension] < -1e-12) // <=0) //< -1e-12) + return true; + + return false; + } + + JacobianInformations + JacobianFluxAlongUnitNormal(const RoeAverageStateStructData& RoeState, + /* + const double rhoJ, + const Rd& uJ, + const double EJ, + const double gammaJ, + const double cJ, + const double pJ, + + const double rhoK, + const Rd& uK, + const double EK, + const double gammaK, + const double cK, + const double pK, +*/ + const Rd& normal, + const bool check = false) const + { + Assert((l2Norm(normal) - 1) < 1e-12); + + // const double& rho = RoeState.rho; + const Rd& u_mean = RoeState.U; + const double H_mean = RoeState.H; + const double& cspeed = RoeState.c; + const double& gamma = RoeState.gamma; + const double& uscaln = dot(u_mean, normal); + const double& u2 = dot(u_mean, u_mean); + // const R NrjCin=.5*unorm2; + + const double c2 = cspeed * cspeed; + const double gm1 = gamma - 1; + const double K = c2 + gm1 * (dot(u_mean, u_mean) - H_mean); + + // Le jacobien est lineaire par rapport a la normale + // Ref : PAr ex. le papier de D. Chauvheid sur la tension de surface + Rpxp Jacobian; + + Rdxd CentralT = identity; + CentralT *= uscaln; + CentralT += tensorProduct(u_mean, normal) - gm1 * tensorProduct(normal, u_mean); + + Jacobian(0, 0) = 0.; + for (size_t dim = 0; dim < Dimension; ++dim) { + Jacobian(0, dim + 1) = normal[dim]; + } + Jacobian(0, Dimension + 1) = 0; + + for (size_t dim = 0; dim < Dimension; ++dim) { + Jacobian(dim + 1, 0) = K * normal[dim] - uscaln * u_mean[dim]; + for (size_t dim2 = 0; dim2 < Dimension; ++dim2) + Jacobian(dim + 1, dim2 + 1) = CentralT(dim, dim2); + Jacobian(dim + 1, Dimension + 1) = gm1 * normal[dim]; + } + + Jacobian(Dimension + 1, 0) = (K - H_mean) * uscaln; + for (size_t dim = 0; dim < Dimension; ++dim) + Jacobian(Dimension + 1, dim + 1) = (H_mean * normal[dim] - gm1 * uscaln * u_mean[dim]); + Jacobian(Dimension + 1, Dimension + 1) = gamma * uscaln; + + // Valeur propres.. + Rp EigenValues; + + EigenValues[0] = uscaln - cspeed; + for (size_t dim = 0; dim < Dimension; ++dim) // vp multiplicite d + EigenValues[1 + dim] = uscaln; + EigenValues[1 + Dimension] = uscaln + cspeed; + + const double maxabsVpNormal = std::max(fabs(EigenValues[0]), fabs(EigenValues[1 + Dimension])); + + // Vecteur propres a droite et gauche + + // hyper plan ortho à la normale + std::vector<Rd> ortho(Dimension - 1); + if constexpr (Dimension == 2) { + ortho[0] = Rd{normal[1], -normal[0]}; // aussi de norme 1 + } else { + const double a = normal[0]; + const double b = normal[1]; + const double c = normal[2]; + + if ((a == b) and (b == c)) { + static double invsqrt2 = 1. / sqrt(2.); + static double invsqrt6 = 1. / sqrt(6.); + + ortho[0] = Rd{invsqrt2, -invsqrt2, 0}; + ortho[1] = Rd{invsqrt6, invsqrt6, -2 * invsqrt6}; // au signe pres + + } else { + ortho[0] = Rd{b - c, -(a - c), a - b}; + ortho[0] *= 1. / l2Norm(ortho[0]); + ortho[1] = Rd{a * (b + c) - b * b - c * c, b * (a + c) - a * a - c * c, c * (a + b) - a * a - b * b}; + ortho[1] *= 1. / l2Norm(ortho[1]); // au signe pres + } + } + + Rpxp RightTligne; + RightTligne(0, 0) = 1; + for (size_t dim = 1; dim < Dimension + 1; ++dim) + RightTligne(0, dim) = u_mean[dim - 1] - cspeed * normal[dim - 1]; + RightTligne(0, Dimension + 1) = H_mean - uscaln * cspeed; + + RightTligne(1, 0) = 1; + for (size_t dim = 1; dim < Dimension + 1; ++dim) + RightTligne(1, dim) = u_mean[dim - 1]; + RightTligne(1, Dimension + 1) = H_mean - c2 / gm1; + + for (size_t dim = 1; dim < Dimension; ++dim) { + RightTligne(dim + 1, 0) = 0.; + for (size_t dim2 = 1; dim2 < Dimension + 1; ++dim2) { + RightTligne(dim + 1, dim2) = ortho[dim - 1][dim2 - 1]; + } + RightTligne(dim + 1, Dimension + 1) = dot(u_mean, ortho[dim - 1]); + } + + RightTligne(Dimension + 1, 0) = 1; + for (size_t dim = 1; dim < Dimension + 1; ++dim) { + RightTligne(Dimension + 1, dim) = u_mean[dim - 1] + cspeed * normal[dim - 1]; + } + RightTligne(Dimension + 1, Dimension + 1) = H_mean + uscaln * cspeed; + + Rpxp Right = transpose(RightTligne); + + const double invc2 = 1. / c2; + + Rpxp Left; //(zero); + Left(0, 0) = .5 * invc2 * (K + uscaln * cspeed); + for (size_t dim = 1; dim < Dimension + 1; ++dim) + Left(0, dim) = .5 * invc2 * (-gm1 * u_mean[dim - 1] - cspeed * normal[dim - 1]); + Left(0, Dimension + 1) = .5 * invc2 * gm1; + + Left(1, 0) = gm1 * invc2 * (H_mean - u2); + for (size_t dim = 1; dim < Dimension + 1; ++dim) + Left(1, dim) = gm1 * invc2 * u_mean[dim - 1]; + Left(1, 1 + Dimension) = -gm1 * invc2; + + for (size_t dim = 1; dim < Dimension; ++dim) { + Left(1 + dim, 0) = -dot(u_mean, ortho[dim - 1]); + for (size_t dim2 = 0; dim2 < Dimension; ++dim2) + Left(1 + dim, dim2 + 1) = ortho[dim - 1][dim2]; + Left(1 + dim, 1 + Dimension) = 0; + } + + Left(1 + Dimension, 0) = .5 * invc2 * (K - uscaln * cspeed); + for (size_t dim = 1; dim < Dimension + 1; ++dim) + Left(1 + Dimension, dim) = .5 * invc2 * (-gm1 * u_mean[dim - 1] + cspeed * normal[dim - 1]); + Left(1 + Dimension, Dimension + 1) = .5 * invc2 * gm1; + + // check + // Rpxp prod = Right * Left; + // std::cout << prod << "\n"; + + Rpxp EigenMatAbs(identity); + for (size_t dim = 0; dim < Dimension + 2; ++dim) { + EigenMatAbs(dim, dim) *= fabs(EigenValues[dim]); + } + Rpxp ProdLefAbs = Right * EigenMatAbs; + Rpxp AbsJacobian = ProdLefAbs * Left; + double maxErr = 0; + + if (check) { + Rpxp EigenAbs(identity); + for (size_t dim = 0; dim < Dimension + 2; ++dim) { + EigenAbs(dim, dim) *= EigenValues[dim]; + } + Rpxp ProdLeft = Right * EigenAbs; + Rpxp JacobianR = ProdLeft * Left; + + // Rpxp id = identity; + maxErr = 0; + // double maxErrLeftRightId = 0; + for (size_t i = 0; i < Dimension + 2; ++i) + for (size_t j = 0; j < Dimension + 2; ++j) { + maxErr = std::max(maxErr, fabs(Jacobian(i, j) - JacobianR(i, j))); + // maxErrLeftRightId = std::max(maxErrLeftRightId, fabs(id(i, j) - prod(i, j))); + } + // std::clog << " maxErr " << maxErr << " maxErrUnit " << maxErrLeftRightId; + // throw NormalError("STOP"); + } + + return JacobianInformations(Jacobian, Left, Right, EigenValues, AbsJacobian, maxabsVpNormal, maxErr); + } + + 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 size_t& degree, + 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); + _applyNeumannflatBoundaryCondition(bc_list, *p_mesh, StateAtNode, StateAtEdge, StateAtFace); + _applyWallBoundaryCondition(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); + NodeValue<double> MaxErrNode{p_mesh->connectivity()}; + MaxErrNode.fill(0); + FaceValue<double> MaxErrFace{p_mesh->connectivity()}; + MaxErrFace.fill(0); + EdgeValue<double> MaxErrEdge{p_mesh->connectivity()}; + MaxErrEdge.fill(0); + + NodeValue<int> nbChangingSignNode{p_mesh->connectivity()}; + nbChangingSignNode.fill(0); + 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(); + } + }); + synchronize(Gjr); + + 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); + double maxGjrAbs = 0; + 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]; + maxGjrAbs = std::max(maxGjrAbs, l2Norm(Gjr[K][R])); + } + // MaxErrorConservationNode = std::max(MaxErrorConservationNode, l2Norm(SumGjr)); + MaxErrorConservationNode[l] = l2Norm(SumGjr) / maxGjrAbs; + } + }); + std::cout << " Max Error Node " << max(MaxErrorConservationNode) << " Max Error RoeMatrice " << max(MaxErrNode) + << " nb Chg Sign " << sum(nbChangingSignNode) << "\n"; + } + // + FaceValue<int> nbChangingSignFace{p_mesh->connectivity()}; + nbChangingSignFace.fill(0); + 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); + /* + // Moyenne de 2 etats + 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; + */ + // La moyenne de Roe entre les etats jk + RoeAverageStateStructData RoeS( + RoeAverageState(rho_n[j], u_n[j], E_n[j], gamma, p_n[j], rho_n[K], u_n[K], E_n[K], gamma, p_n[K])); + // Viscosity j k + const double nrmCkf = l2Norm(Ckf_loc); + const Rd& normal = 1. / nrmCkf * Ckf_loc; + const JacobianInformations& JacInfoK = JacobianFluxAlongUnitNormal(RoeS, normal); + const double nrmCjf = l2Norm(Cjf_loc); + const Rd& normalJ = 1. / nrmCjf * Cjf_loc; + const JacobianInformations& JacInfoJ = JacobianFluxAlongUnitNormal(RoeS, normalJ); + + // Matrice de Viscosite : Valeur Abs de la jacobienne en l'etat de Roe + Rpxp ViscosityMatrixJK = .5 * (nrmCjf * JacInfoJ.AbsJacobian + nrmCkf * JacInfoK.AbsJacobian); + + // Test Rajout Viscosité type Rusanov v2 si chgt signe vp .. + + bool anySignChgJ = EvaluateChangingSignVpAlongNormal( // rho_n[j], + u_n[j], // E_n[j], gamma, + c_n[j], // p_n[j], rho_n[K], + u_n[K], + // E_n[K], gamma, + c_n[K], // p_n[K], + normalJ); + bool anySignChgK = EvaluateChangingSignVpAlongNormal( // rho_n[j], + u_n[j], // E_n[j], gamma, + c_n[j], // p_n[j], rho_n[K], + u_n[K], + // E_n[K], gamma, + c_n[K], // p_n[K], + normal); + + bool anySignDif = false; + if (anySignChgJ or anySignChgK) + anySignDif = false; // false; // true; + + if (anySignDif) { + Rpxp AddedViscosity(identity); + AddedViscosity *= std::max(JacInfoJ.maxabsVpNormal * nrmCjf, JacInfoK.maxabsVpNormal * nrmCkf); + ViscosityMatrixJK += AddedViscosity; + nbChangingSignFace[face] = 1; + } + + MaxErrFace[face] = std::max(MaxErrFace[face], JacInfoK.MaxErrorProd); + + 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(); + } + }); + synchronize(Gjf); + + 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); + double maxGjrAbs = 0; + 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]; + maxGjrAbs = std::max(maxGjrAbs, l2Norm(Gjf[K][R])); + } + MaxErrorConservationFace[l] = l2Norm(SumGjf) / maxGjrAbs; + // MaxErrorConservationFace = std::max(MaxErrorConservationFace, l2Norm(SumGjf)); + } + }); + std::cout << " Max Error Face " << max(MaxErrorConservationFace) << " Max Error RoeMatrice " << max(MaxErrFace) + << " nb Chg Sign " << sum(nbChangingSignFace) << "\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(); + + EdgeValue<int> nbChangingSignEdge(p_mesh->connectivity()); + nbChangingSignEdge.fill(0); + + 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); + /* + // Moyenne de 2 etats + 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; + */ + // La moyenne de Roe entre les etats jk + RoeAverageStateStructData RoeS( + RoeAverageState(rho_n[j], u_n[j], E_n[j], gamma, p_n[j], rho_n[K], u_n[K], E_n[K], gamma, p_n[K])); + // Viscosity j k + const double nrmCke = l2Norm(Cke_loc); + const Rd& normal = 1. / nrmCke * Cke_loc; + const JacobianInformations& JacInfoK = JacobianFluxAlongUnitNormal(RoeS, normal); + + const double nrmCje = l2Norm(Cje_loc); + const Rd& normalJ = 1. / nrmCje * Cje_loc; + const JacobianInformations& JacInfoJ = JacobianFluxAlongUnitNormal(RoeS, normalJ); + + // Matrice de Viscosite : Valeur Abs de la jacobienne en l'etat de Roe + Rpxp ViscosityMatrixJK = .5 * (nrmCje * JacInfoJ.AbsJacobian + nrmCke * JacInfoK.AbsJacobian); + + // Test Rajout Viscosité type Rusanov v2 si chgt signe vp .. + + bool anySignChgJ = EvaluateChangingSignVpAlongNormal( // rho_n[j], + u_n[j], // E_n[j], gamma, + c_n[j], // p_n[j], rho_n[K], + u_n[K], + // E_n[K], gamma, + c_n[K], // p_n[K], + normalJ); + bool anySignChgK = EvaluateChangingSignVpAlongNormal( // rho_n[j], + u_n[j], // E_n[j], gamma, + c_n[j], // p_n[j], rho_n[K], + u_n[K], + // E_n[K], gamma, + c_n[K], // p_n[K], + normal); + + bool anySignDif = false; + if (anySignChgJ or anySignChgK) + anySignDif = false; // false; // true; + + if (anySignDif) { + Rpxp AddedViscosity(identity); + AddedViscosity *= std::max(JacInfoJ.maxabsVpNormal * nrmCje, JacInfoK.maxabsVpNormal * nrmCke); + ViscosityMatrixJK += AddedViscosity; + nbChangingSignEdge[edge] = 1; + } + + MaxErrEdge[edge] = std::max(MaxErrEdge[edge], JacInfoK.MaxErrorProd); + + 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(); + } + }); + synchronize(Gje); + + 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); + double maxGjrAbs = 0; + 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]; + maxGjrAbs = std::max(maxGjrAbs, l2Norm(Gje[K][R])); + } + // MaxErrorConservationEdge = std::max(MaxErrorConservationEdge, l2Norm(SumGje)); + MaxErrorConservationEdge[l] = l2Norm(SumGje) / maxGjrAbs; + } + }); + std::cout << " Max Error Edge " << max(MaxErrorConservationEdge) << " Max Error RoeMatrice " << max(MaxErrEdge) + << " nb Chg Sign " << sum(nbChangingSignEdge) << "\n"; + } + } // dim 3 + + // Pour les assemblages + double theta = 2. / 3.; //.5; + double eta = 1. / 6.; //.2; + if constexpr (Dimension == 2) { + eta = 0; + // theta = 1; // pour schema aux aretes + // theta=0; //pour schema aux noeuds + } + + // 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)); + } + + HybridRoeRusanovViscousFormEulerianCompositeSolver_v2() = default; + ~HybridRoeRusanovViscousFormEulerianCompositeSolver_v2() = default; +}; + +template <MeshConcept MeshType> +class HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<MeshType>::WallBoundaryCondition +{ +}; + +template <> +class HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<Mesh<2>>::WallBoundaryCondition +{ + using Rd = TinyVector<Dimension, double>; + + private: + const MeshNodeBoundary m_mesh_node_boundary; + const MeshFaceBoundary m_mesh_face_boundary; + // const MeshFlatNodeBoundary<MeshType> m_mesh_flat_node_boundary; + // const MeshFlatFaceBoundary<MeshType> m_mesh_flat_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(); + } + + WallBoundaryCondition(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 HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<Mesh<3>>::WallBoundaryCondition +{ + 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(); + } + + WallBoundaryCondition(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 HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<MeshType>::NeumannflatBoundaryCondition +{ +}; +template <> +class HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<Mesh<2>>::NeumannflatBoundaryCondition +{ + 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(); + } + + NeumannflatBoundaryCondition(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) + { + ; + } + + ~NeumannflatBoundaryCondition() = default; +}; + +template <> +class HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<Mesh<3>>::NeumannflatBoundaryCondition +{ + 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(); + } + + NeumannflatBoundaryCondition(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) + { + ; + } + + ~NeumannflatBoundaryCondition() = default; +}; + +template <MeshConcept MeshType> +class HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<MeshType>::SymmetryBoundaryCondition +{ +}; + +template <> +class HybridRoeRusanovViscousFormEulerianCompositeSolver_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 HybridRoeRusanovViscousFormEulerianCompositeSolver_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 HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<MeshType>::InflowListBoundaryCondition +{ +}; + +template <> +class HybridRoeRusanovViscousFormEulerianCompositeSolver_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 HybridRoeRusanovViscousFormEulerianCompositeSolver_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 HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<MeshType>::OutflowBoundaryCondition +{ +}; + +template <> +class HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<Mesh<2>>::OutflowBoundaryCondition +{ + 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(); + } + + OutflowBoundaryCondition(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 HybridRoeRusanovViscousFormEulerianCompositeSolver_v2<Mesh<3>>::OutflowBoundaryCondition +{ + 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(); + } + + OutflowBoundaryCondition(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) + { + ; + } +}; + +std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +hybridRoeRusanovViscousFormEulerianCompositeSolver_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 size_t& degree, + 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("RoeViscousFormEulerianCompositeSolver v2 is not available in 1D"); + } else { + if constexpr (is_polygonal_mesh_v<MeshType>) { + return HybridRoeRusanovViscousFormEulerianCompositeSolver_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>>(), // degree, + bc_descriptor_list, dt, check); + } else { + throw NormalError("RoeViscousFormEulerianCompositeSolver v2 is only defined on polygonal meshes"); + } + } + }, + mesh_v->variant()); +} diff --git a/src/scheme/HybridRoeRusanovViscousFormEulerianCompositeSolver_v2.hpp b/src/scheme/HybridRoeRusanovViscousFormEulerianCompositeSolver_v2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5d4e2a939b35a52613fed2b8891c42f702df05a4 --- /dev/null +++ b/src/scheme/HybridRoeRusanovViscousFormEulerianCompositeSolver_v2.hpp @@ -0,0 +1,30 @@ +#ifndef HYBRID_ROE_RUSANOV_VISCOUS_FORM_EULERIAN_COMPOSITE_SOLVER_V2_HPP +#define HYBRID_ROE_RUSANOV_VISCOUS_FORM_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>> +hybridRoeRusanovViscousFormEulerianCompositeSolver_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 size_t& degree, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const double& dt, + const bool check = false); + +#endif // HYBRID_ROE_RUSANOV_VISCOUS_FORM_EULERIAN_COMPOSITE_SOLVER_V2_HPP diff --git a/src/scheme/HybridRusanovRoeViscousFormEulerianCompositeSolver_v2.cpp b/src/scheme/HybridRusanovRoeViscousFormEulerianCompositeSolver_v2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a01ea6cc4ccdf44183ba16f11700fc9ca24c21b --- /dev/null +++ b/src/scheme/HybridRusanovRoeViscousFormEulerianCompositeSolver_v2.cpp @@ -0,0 +1,2451 @@ +#include <scheme/HybridRusanovRoeViscousFormEulerianCompositeSolver_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 <mesh/SubItemValuePerItemUtils.hpp> +#include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/InflowListBoundaryConditionDescriptor.hpp> +#include <variant> + +template <MeshConcept MeshTypeT> +class HybridRusanovRoeViscousFormEulerianCompositeSolver_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>; + + using Rpxd = TinyMatrix<Dimension + 2, Dimension>; + + class SymmetryBoundaryCondition; + class InflowListBoundaryCondition; + class OutflowBoundaryCondition; + class WallBoundaryCondition; + class NeumannflatBoundaryCondition; + + using BoundaryCondition = std::variant<SymmetryBoundaryCondition, + InflowListBoundaryCondition, + OutflowBoundaryCondition, + NeumannflatBoundaryCondition, + WallBoundaryCondition>; + + 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::wall: { + if constexpr (Dimension == 2) { + bc_list.emplace_back(WallBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + } else { + static_assert(Dimension == 3); + bc_list.emplace_back(WallBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshEdgeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + } + break; + } + 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: { + if constexpr (Dimension == 2) { + bc_list.emplace_back( + OutflowBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + } else { + static_assert(Dimension == 3); + bc_list.emplace_back( + OutflowBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshEdgeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + } + break; + // 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 + _applyWallBoundaryCondition(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<WallBoundaryCondition, T>) { + MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + std::cout << " Traitement WALL local (non flat) \n"; + // const Rd& normal = bc.outgoingNormal(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_to_face_matrix = mesh.connectivity().nodeToFaceMatrix(); + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + const auto& node_local_numbers_in_their_faces = mesh.connectivity().nodeLocalNumbersInTheirFaces(); + 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 Cjr = mesh_data.Cjr(); + const auto Cjf = mesh_data.Cjf(); + + for (size_t i_node = 0; i_node < node_list.size(); ++i_node) { + const NodeId node_id = node_list[i_node]; + + const auto& node_face_list = node_to_face_matrix[node_id]; + // Assert(face_cell_list.size() == 1); + // const auto& node_local_number_in_its_faces = node_local_numbers_in_their_faces.itemArray(node_id); + + // on va chercher les normale d'une face issue du noeud de CL et contenue dans le faceList + Rd normal(zero); + int nbnormal = 0; + for (size_t i_face = 0; i_face < node_face_list.size(); ++i_face) { + FaceId node_face_id = node_face_list[i_face]; + + for (size_t i_facebc = 0; i_facebc < face_list.size(); ++i_facebc) { + const FaceId facebc_id = face_list[i_facebc]; + if (node_face_id == facebc_id) { + const auto& face_cell_list = face_to_cell_matrix[facebc_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(facebc_id, 0); + + // Normal locale approchée + Rd normalloc = Cjf(face_cell_id, face_local_number_in_cell); + normalloc *= 1. / l2Norm(normalloc); + normal += normalloc; + ++nbnormal; + break; + } + } + } + if (nbnormal == 0) + continue; + normal *= 1. / nbnormal; + + normal *= 1. / l2Norm(normal); + 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]; + + vectorSym -= dot(vectorSym, normal) * normal; + + 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 + 1] = 0; + } + } + + 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); + + // Normal locale approchée + Rd normal(Cjf(face_cell_id, face_local_number_in_cell)); + normal *= 1. / l2Norm(normal); + + Rd vectorSym(zero); + for (size_t dim = 0; dim < Dimension; ++dim) + vectorSym[dim] = stateFace[face_cell_id][face_local_number_in_cell][1 + dim]; + + vectorSym -= dot(vectorSym, normal) * normal; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateFace[face_cell_id][face_local_number_in_cell][dim + 1] = vectorSym[dim]; + // stateFace[face_cell_id][face_local_number_in_cell][dim + 1] = 0; + } + + 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_to_face_matrix = mesh.connectivity().edgeToFaceMatrix(); + + const auto& edge_local_numbers_in_their_faces = mesh.connectivity().edgeLocalNumbersInTheirFaces(); + + 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_face_list = edge_to_face_matrix[edge_id]; + + // on va chercher les normale d'une face issue du edge de CL et contenue dans le faceList + Rd normal(zero); + int nbnormal = 0; + for (size_t i_face = 0; i_face < edge_face_list.size(); ++i_face) { + FaceId edge_face_id = edge_face_list[i_face]; + + for (size_t i_facebc = 0; i_facebc < face_list.size(); ++i_facebc) { + const FaceId facebc_id = face_list[i_facebc]; + if (edge_face_id == facebc_id) { + const auto& face_cell_list = face_to_cell_matrix[facebc_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(facebc_id, 0); + + // Normal locale approchée + Rd normalloc = Cjf(face_cell_id, face_local_number_in_cell); + normalloc *= 1. / l2Norm(normalloc); + normal += normalloc; + ++nbnormal; + break; + } + } + } + + if (nbnormal == 0) + continue; + normal *= 1. / nbnormal; + + normal *= 1. / l2Norm(normal); + + 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); + + 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]; + + vectorSym -= dot(vectorSym, normal) * normal; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateEdge[edge_cell_id][edge_local_number_in_cell][dim + 1] = vectorSym[dim]; + // stateEdge[edge_cell_id][edge_local_number_in_cell][dim + 1] = 0; + } + } + } + } + }, + boundary_condition); + } + } + + void + _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>) { + std::cout << " Traitement Outflow \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(); + + const auto xj = mesh.xj(); + const auto xr = mesh.xr(); + const auto xf = mesh.xl(); + const auto xe = mesh.xe(); + + 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] += vectorSym[dim]; + + 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]; + } + } + + // throw NormalError("Not implemented"); + } + */ + } + }, + boundary_condition); + } + } + + void + _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] = stateFace[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); + } + } + + void + _applyNeumannflatBoundaryCondition(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<NeumannflatBoundaryCondition, T>) { + // MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + std::cout << " Traitement WALL \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]; + + vectorSym -= dot(vectorSym, normal) * normal; + + 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] = stateFace[face_cell_id][face_local_number_in_cell][1 + dim]; + + vectorSym -= dot(vectorSym, normal) * normal; + + 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]; + + vectorSym -= dot(vectorSym, normal) * normal; + + for (size_t dim = 0; dim < Dimension; ++dim) + stateEdge[edge_cell_id][edge_local_number_in_cell][dim + 1] = vectorSym[dim]; + } + } + } + } + }, + boundary_condition); + } + } + + void + _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); + } + } + + public: + inline double + pression(const double rho, const double epsilon, const double gam) const + { + return (gam - 1) * rho * epsilon; + } + + inline Rpxd + Flux(const double& rho, const Rd& U, const double& E, const double gam) const + { + // const R2 flux_rho = rhoU; + // const R22 flux_rhoU = R22(rhoU.x1() * rhoU.x1() / rho + P, rhoU.x1() * rhoU.x2() / rho, rhoU.x2() * rhoU.x1() + // rho,rhoU.x2() * rhoU.x2() / rho + P); + // const R2 flux_rhoE = ((rhoE + P) / rho) * rhoU; + /* 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; + + */ + const Rd& rhoU = rho * U; + const Rdxd rhoUTensU = tensorProduct(rhoU, U); + const double p = pression(rho, E - .5 * dot(U, U), gam); + + Rdxd pid(identity); + pid *= p; + const Rdxd rhoUTensUPlusPid = rhoUTensU + pid; + const double rhoEPlusP = rho * E + p; + + const Rd& rhoEPlusPtimesU = rhoEPlusP * U; + + Rpxd Fluxx; // En ligne ci dessous + + Fluxx[0] = rhoU; + for (size_t dim = 0; dim < Dimension; ++dim) + // for (size_t dim2 = 0; dim2 < Dimension; ++dim2) + Fluxx[1 + dim] = rhoUTensUPlusPid[dim]; + // Fluxx[1 + dim][dim2] = rhoUTensUPlusPid[dim][dim2]; + Fluxx[1 + Dimension] = rhoEPlusPtimesU; + return Fluxx; + } + + struct JacobianInformations + { + Rpxp Jacobian; + Rpxp LeftEigenVectors; + Rpxp RightEigenVectors; + Rp EigenValues; + Rpxp AbsJacobian; + double maxabsVpNormal; + // bool changingSign; + double MaxErrorProd; + + public: + JacobianInformations(const Rpxp& Jacobiand, + const Rpxp& LeftEigenVectorsd, + const Rpxp& RightEigenVectorsd, + const Rp& EigenValuesd, + const Rpxp& AbsJacobiand, + const double maxabsVpNormald, + const double MaxErrorProdd) + : Jacobian(Jacobiand), + LeftEigenVectors(LeftEigenVectorsd), + RightEigenVectors(RightEigenVectorsd), + EigenValues(EigenValuesd), + AbsJacobian(AbsJacobiand), + maxabsVpNormal(maxabsVpNormald), + MaxErrorProd(MaxErrorProdd) + {} + ~JacobianInformations() {} + }; + + Rp + EvaluateEigenValuesNormal( // const double rhod, // rhoJ, uJ, EJ, gammaJ, cJ, pJ, normal + const Rd& Ud, + // const double Ed, + // const double gammad, + const double cd, + // const double pd, + const Rd& normal) const + { + Rp Eigen; + const double uscaln = dot(Ud, normal); + + Eigen[0] = uscaln - cd; + for (size_t dim = 0; dim < Dimension; ++dim) + Eigen[dim] = uscaln; + Eigen[1 + Dimension] = uscaln + cd; + + return Eigen; + } + + struct RoeAverageStateStructData + { + double rho; + Rd U; + double E; + double H; + double gamma; + double p; + double c; + RoeAverageStateStructData(const double rhod, + const Rd Ud, + const double Ed, + const double Hd, + const double gammad, + const double pd, + const double cd) + : rho(rhod), U(Ud), E(Ed), H(Hd), gamma(gammad), p(pd), c(cd) + {} + }; + + RoeAverageStateStructData + RoeAverageState(const double& rhoG, + const Rd& UG, + const double& EG, + const double& gammaG, + const double& pG, + const double& rhoD, + const Rd& UD, + const double& ED, + const double gammaD, + const double pD) const + + { + double gamma = .5 * (gammaG + gammaD); // ou ponderation racine roG et roD + double RacineRoG = sqrt(rhoG); + double RacineRoD = sqrt(rhoD); + double rho_mean = RacineRoG * RacineRoD; + Rd U_mean = 1. / (RacineRoG + RacineRoD) * (RacineRoG * UG + RacineRoD * UD); + double unorm2 = dot(U_mean, U_mean); + double NrjCin = .5 * unorm2; + const double TotEnthalpyG = (EG + pG / rhoG); + const double TotEnthalpyD = (ED + pD / rhoD); + + double H_mean = (RacineRoG * TotEnthalpyG + RacineRoD * TotEnthalpyD) / (RacineRoG + RacineRoD); + + double E_mean = H_mean / gamma + ((gamma - 1) / (gamma)) * (NrjCin); + + double P_mean = rho_mean * (H_mean - E_mean); + + double c2 = gamma * P_mean / rho_mean; // cspeed*cspeed; + // assert(fabs((gamma - 1) * rho_mean * (E_mean - .5 * (u_mean, u_mean)) - P_mean) < 1e-13); // equilibre GP + double c_mean = sqrt(c2); // cspeed_meandof/Area; + + return RoeAverageStateStructData(rho_mean, U_mean, E_mean, H_mean, gamma, P_mean, c_mean); + } + + bool + EvaluateChangingSignVpAlongNormal( // const double rhoJ, + const Rd& uJ, + // const double EJ, + // const double gammaJ, + const double cJ, + // const double pJ, + + // const double rhoK, + const Rd& uK, + // const double EK, + // const double gammaK, + const double cK, + // const double pK, + const Rd& normal) const + { + const Rp& EigenJ = EvaluateEigenValuesNormal( // rhoJ, + uJ, // EJ, gammaJ, + cJ, // pJ, + normal); + + const Rp& EigenK = EvaluateEigenValuesNormal( // rhoK, + uK, // EK, gammaK, + cK, // pK, + normal); + + if (EigenJ[0] * EigenK[0] < -1e-12) // <=0) //< -1e-12) + return true; + for (size_t dim = 1; dim < Dimension + 1; ++dim) // vp multiplicite d + if (EigenJ[dim] * EigenK[dim] < -1e-12) // <=0) //< -1e-12) + return true; + if (EigenJ[1 + Dimension] * EigenK[1 + Dimension] < -1e-12) // <=0) //< -1e-12) + return true; + + return false; + } + + JacobianInformations + JacobianFluxAlongUnitNormal(const RoeAverageStateStructData& RoeState, + /* + const double rhoJ, + const Rd& uJ, + const double EJ, + const double gammaJ, + const double cJ, + const double pJ, + + const double rhoK, + const Rd& uK, + const double EK, + const double gammaK, + const double cK, + const double pK, +*/ + const Rd& normal, + const bool check = false) const + { + Assert((l2Norm(normal) - 1) < 1e-12); + + // const double& rho = RoeState.rho; + const Rd& u_mean = RoeState.U; + const double H_mean = RoeState.H; + const double& cspeed = RoeState.c; + const double& gamma = RoeState.gamma; + const double& uscaln = dot(u_mean, normal); + const double& u2 = dot(u_mean, u_mean); + // const R NrjCin=.5*unorm2; + + const double c2 = cspeed * cspeed; + const double gm1 = gamma - 1; + const double K = c2 + gm1 * (dot(u_mean, u_mean) - H_mean); + + // Le jacobien est lineaire par rapport a la normale + // Ref : PAr ex. le papier de D. Chauvheid sur la tension de surface + Rpxp Jacobian; + + Rdxd CentralT = identity; + CentralT *= uscaln; + CentralT += tensorProduct(u_mean, normal) - gm1 * tensorProduct(normal, u_mean); + + Jacobian(0, 0) = 0.; + for (size_t dim = 0; dim < Dimension; ++dim) { + Jacobian(0, dim + 1) = normal[dim]; + } + Jacobian(0, Dimension + 1) = 0; + + for (size_t dim = 0; dim < Dimension; ++dim) { + Jacobian(dim + 1, 0) = K * normal[dim] - uscaln * u_mean[dim]; + for (size_t dim2 = 0; dim2 < Dimension; ++dim2) + Jacobian(dim + 1, dim2 + 1) = CentralT(dim, dim2); + Jacobian(dim + 1, Dimension + 1) = gm1 * normal[dim]; + } + + Jacobian(Dimension + 1, 0) = (K - H_mean) * uscaln; + for (size_t dim = 0; dim < Dimension; ++dim) + Jacobian(Dimension + 1, dim + 1) = (H_mean * normal[dim] - gm1 * uscaln * u_mean[dim]); + Jacobian(Dimension + 1, Dimension + 1) = gamma * uscaln; + + // Valeur propres.. + Rp EigenValues; + + EigenValues[0] = uscaln - cspeed; + for (size_t dim = 0; dim < Dimension; ++dim) // vp multiplicite d + EigenValues[1 + dim] = uscaln; + EigenValues[1 + Dimension] = uscaln + cspeed; + + const double maxabsVpNormal = std::max(fabs(EigenValues[0]), fabs(EigenValues[1 + Dimension])); + + // Vecteur propres a droite et gauche + + // hyper plan ortho à la normale + std::vector<Rd> ortho(Dimension - 1); + if constexpr (Dimension == 2) { + ortho[0] = Rd{normal[1], -normal[0]}; // aussi de norme 1 + } else { + const double a = normal[0]; + const double b = normal[1]; + const double c = normal[2]; + + if ((a == b) and (b == c)) { + static double invsqrt2 = 1. / sqrt(2.); + static double invsqrt6 = 1. / sqrt(6.); + + ortho[0] = Rd{invsqrt2, -invsqrt2, 0}; + ortho[1] = Rd{invsqrt6, invsqrt6, -2 * invsqrt6}; // au signe pres + + } else { + ortho[0] = Rd{b - c, -(a - c), a - b}; + ortho[0] *= 1. / l2Norm(ortho[0]); + ortho[1] = Rd{a * (b + c) - b * b - c * c, b * (a + c) - a * a - c * c, c * (a + b) - a * a - b * b}; + ortho[1] *= 1. / l2Norm(ortho[1]); // au signe pres + } + } + + Rpxp RightTligne; + RightTligne(0, 0) = 1; + for (size_t dim = 1; dim < Dimension + 1; ++dim) + RightTligne(0, dim) = u_mean[dim - 1] - cspeed * normal[dim - 1]; + RightTligne(0, Dimension + 1) = H_mean - uscaln * cspeed; + + RightTligne(1, 0) = 1; + for (size_t dim = 1; dim < Dimension + 1; ++dim) + RightTligne(1, dim) = u_mean[dim - 1]; + RightTligne(1, Dimension + 1) = H_mean - c2 / gm1; + + for (size_t dim = 1; dim < Dimension; ++dim) { + RightTligne(dim + 1, 0) = 0.; + for (size_t dim2 = 1; dim2 < Dimension + 1; ++dim2) { + RightTligne(dim + 1, dim2) = ortho[dim - 1][dim2 - 1]; + } + RightTligne(dim + 1, Dimension + 1) = dot(u_mean, ortho[dim - 1]); + } + + RightTligne(Dimension + 1, 0) = 1; + for (size_t dim = 1; dim < Dimension + 1; ++dim) { + RightTligne(Dimension + 1, dim) = u_mean[dim - 1] + cspeed * normal[dim - 1]; + } + RightTligne(Dimension + 1, Dimension + 1) = H_mean + uscaln * cspeed; + + Rpxp Right = transpose(RightTligne); + + const double invc2 = 1. / c2; + + Rpxp Left; //(zero); + Left(0, 0) = .5 * invc2 * (K + uscaln * cspeed); + for (size_t dim = 1; dim < Dimension + 1; ++dim) + Left(0, dim) = .5 * invc2 * (-gm1 * u_mean[dim - 1] - cspeed * normal[dim - 1]); + Left(0, Dimension + 1) = .5 * invc2 * gm1; + + Left(1, 0) = gm1 * invc2 * (H_mean - u2); + for (size_t dim = 1; dim < Dimension + 1; ++dim) + Left(1, dim) = gm1 * invc2 * u_mean[dim - 1]; + Left(1, 1 + Dimension) = -gm1 * invc2; + + for (size_t dim = 1; dim < Dimension; ++dim) { + Left(1 + dim, 0) = -dot(u_mean, ortho[dim - 1]); + for (size_t dim2 = 0; dim2 < Dimension; ++dim2) + Left(1 + dim, dim2 + 1) = ortho[dim - 1][dim2]; + Left(1 + dim, 1 + Dimension) = 0; + } + + Left(1 + Dimension, 0) = .5 * invc2 * (K - uscaln * cspeed); + for (size_t dim = 1; dim < Dimension + 1; ++dim) + Left(1 + Dimension, dim) = .5 * invc2 * (-gm1 * u_mean[dim - 1] + cspeed * normal[dim - 1]); + Left(1 + Dimension, Dimension + 1) = .5 * invc2 * gm1; + + // check + // Rpxp prod = Right * Left; + // std::cout << prod << "\n"; + + Rpxp EigenMatAbs(identity); + for (size_t dim = 0; dim < Dimension + 2; ++dim) { + EigenMatAbs(dim, dim) *= fabs(EigenValues[dim]); + } + Rpxp ProdLefAbs = Right * EigenMatAbs; + Rpxp AbsJacobian = ProdLefAbs * Left; + double maxErr = 0; + + if (check) { + Rpxp EigenAbs(identity); + for (size_t dim = 0; dim < Dimension + 2; ++dim) { + EigenAbs(dim, dim) *= EigenValues[dim]; + } + Rpxp ProdLeft = Right * EigenAbs; + Rpxp JacobianR = ProdLeft * Left; + + // Rpxp id = identity; + maxErr = 0; + // double maxErrLeftRightId = 0; + for (size_t i = 0; i < Dimension + 2; ++i) + for (size_t j = 0; j < Dimension + 2; ++j) { + maxErr = std::max(maxErr, fabs(Jacobian(i, j) - JacobianR(i, j))); + // maxErrLeftRightId = std::max(maxErrLeftRightId, fabs(id(i, j) - prod(i, j))); + } + // std::clog << " maxErr " << maxErr << " maxErrUnit " << maxErrLeftRightId; + // throw NormalError("STOP"); + } + + return JacobianInformations(Jacobian, Left, Right, EigenValues, AbsJacobian, maxabsVpNormal, maxErr); + } + + 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 size_t degree, + 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()}; + // + // Remplir ici les reconstructions d'ordre élevé + + // + 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(); + + // const auto xr = p_mesh->xr(); + // auto xl = MeshDataManager::instance().getMeshData(*p_mesh).xl(); + // auto xe = MeshDataManager::instance().getMeshData(*p_mesh).xe(); + + 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); + _applyNeumannflatBoundaryCondition(bc_list, *p_mesh, StateAtNode, StateAtEdge, StateAtFace); + _applyWallBoundaryCondition(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()}; + + 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); + NodeValue<double> MaxErrNode{p_mesh->connectivity()}; + MaxErrNode.fill(0); + FaceValue<double> MaxErrFace{p_mesh->connectivity()}; + MaxErrFace.fill(0); + EdgeValue<double> MaxErrEdge{p_mesh->connectivity()}; + MaxErrEdge.fill(0); + + NodeValue<int> nbChangingSignNode{p_mesh->connectivity()}; + nbChangingSignNode.fill(0); + 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); + + /* + // Moyenne de 2 etats + 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; + */ + + // La moyenne de Roe entre les etats jk + RoeAverageStateStructData RoeS( + RoeAverageState(rho_n[j], u_n[j], E_n[j], gamma, p_n[j], rho_n[K], u_n[K], E_n[K], gamma, p_n[K])); + // Viscosity j k + const double nrmCkr = l2Norm(Ckr_loc); + const Rd& normal = 1. / nrmCkr * Ckr_loc; + const JacobianInformations& JacInfoK = JacobianFluxAlongUnitNormal(RoeS, normal); + + const double nrmCjr = l2Norm(Cjr_loc); + const Rd& normalJ = 1. / nrmCjr * Cjr_loc; + const JacobianInformations& JacInfoJ = JacobianFluxAlongUnitNormal(RoeS, normalJ); + + // Matrice de Viscosite : Valeur Abs de la jacobienne en l'etat de Roe + Rpxp ViscosityMatrixJK = .5 * (nrmCjr * JacInfoJ.AbsJacobian + nrmCkr * JacInfoK.AbsJacobian); + + // Test Rajout Viscosité type Rusanov v2 si chgt signe vp .. + + bool anySignChgJ = EvaluateChangingSignVpAlongNormal( // rho_n[j], + u_n[j], // E_n[j], gamma, + c_n[j], // p_n[j], rho_n[K], + u_n[K], + // E_n[K], gamma, + c_n[K], // p_n[K], + normalJ); + bool anySignChgK = EvaluateChangingSignVpAlongNormal( // rho_n[j], + u_n[j], // E_n[j], gamma, + c_n[j], // p_n[j], rho_n[K], + u_n[K], + // E_n[K], gamma, + c_n[K], // p_n[K], + normal); + + bool anySignDif = false; + if (anySignChgJ or anySignChgK) + anySignDif = false; // false; // true; + + if (anySignDif) { + Rpxp AddedViscosity(identity); + AddedViscosity *= std::max(JacInfoJ.maxabsVpNormal * nrmCjr, JacInfoK.maxabsVpNormal * nrmCkr); + ViscosityMatrixJK += AddedViscosity; + nbChangingSignNode[node] = 1; + } + + MaxErrNode[node] = std::max(MaxErrNode[node], JacInfoK.MaxErrorProd); + + 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(); + } + }); + + synchronize(Gjr); + 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); + double maxGjrAbs = 0; + 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]; + maxGjrAbs = std::max(maxGjrAbs, l2Norm(Gjr[K][R])); + } + // MaxErrorConservationNode = std::max(MaxErrorConservationNode, l2Norm(SumGjr)); + MaxErrorConservationNode[l] = l2Norm(SumGjr) / maxGjrAbs; + } + }); + 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(); + } + }); + synchronize(Gjf); + + 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); + double maxGjrAbs = 0; + 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]; + maxGjrAbs = std::max(maxGjrAbs, l2Norm(Gjf[K][R])); + } + MaxErrorConservationFace[l] = l2Norm(SumGjf) / maxGjrAbs; + // 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(); + } + }); + synchronize(Gje); + + 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); + double maxGjrAbs = 0; + 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]; + maxGjrAbs = std::max(maxGjrAbs, l2Norm(Gje[K][R])); + } + // MaxErrorConservationEdge = std::max(MaxErrorConservationEdge, l2Norm(SumGje)); + MaxErrorConservationEdge[l] = l2Norm(SumGje) / maxGjrAbs; + } + }); + std::cout << " Max Error Edge " << max(MaxErrorConservationEdge) << "\n"; + } + } // dim 3 + + // Pour les assemblages + double theta = 2. / 3.; //.5; + double eta = 1. / 6.; //.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)); + } + + HybridRusanovRoeViscousFormEulerianCompositeSolver_v2() = default; + ~HybridRusanovRoeViscousFormEulerianCompositeSolver_v2() = default; +}; + +template <MeshConcept MeshType> +class HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<MeshType>::WallBoundaryCondition +{ +}; + +template <> +class HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<Mesh<2>>::WallBoundaryCondition +{ + using Rd = TinyVector<Dimension, double>; + + private: + const MeshNodeBoundary m_mesh_node_boundary; + const MeshFaceBoundary m_mesh_face_boundary; + // const MeshFlatNodeBoundary<MeshType> m_mesh_flat_node_boundary; + // const MeshFlatFaceBoundary<MeshType> m_mesh_flat_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(); + } + + WallBoundaryCondition(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 HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<Mesh<3>>::WallBoundaryCondition +{ + 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(); + } + + WallBoundaryCondition(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 HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<MeshType>::NeumannflatBoundaryCondition +{ +}; +template <> +class HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<Mesh<2>>::NeumannflatBoundaryCondition +{ + 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(); + } + + NeumannflatBoundaryCondition(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) + { + ; + } + + ~NeumannflatBoundaryCondition() = default; +}; + +template <> +class HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<Mesh<3>>::NeumannflatBoundaryCondition +{ + 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(); + } + + NeumannflatBoundaryCondition(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) + { + ; + } + + ~NeumannflatBoundaryCondition() = default; +}; + +template <MeshConcept MeshType> +class HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<MeshType>::SymmetryBoundaryCondition +{ +}; + +template <> +class HybridRusanovRoeViscousFormEulerianCompositeSolver_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 HybridRusanovRoeViscousFormEulerianCompositeSolver_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 HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<MeshType>::InflowListBoundaryCondition +{ +}; + +template <> +class HybridRusanovRoeViscousFormEulerianCompositeSolver_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 HybridRusanovRoeViscousFormEulerianCompositeSolver_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 HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<MeshType>::OutflowBoundaryCondition +{ +}; + +template <> +class HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<Mesh<2>>::OutflowBoundaryCondition +{ + 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(); + } + + OutflowBoundaryCondition(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 HybridRusanovRoeViscousFormEulerianCompositeSolver_v2<Mesh<3>>::OutflowBoundaryCondition +{ + 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(); + } + + OutflowBoundaryCondition(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) + { + ; + } +}; + +std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +hybridRusanovRoeViscousFormEulerianCompositeSolver_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 size_t& degree, + 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 HybridRusanovRoeViscousFormEulerianCompositeSolver_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()); +} diff --git a/src/scheme/HybridRusanovRoeViscousFormEulerianCompositeSolver_v2.hpp b/src/scheme/HybridRusanovRoeViscousFormEulerianCompositeSolver_v2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f6a56e75c29200dea4175c8e280a6394d79cc72d --- /dev/null +++ b/src/scheme/HybridRusanovRoeViscousFormEulerianCompositeSolver_v2.hpp @@ -0,0 +1,30 @@ +#ifndef HYBRID_RUSANOV_ROE_VISCOUS_FORM_EULERIAN_COMPOSITE_SOLVER_V2_HPP +#define HYBRID_RUSANOV_ROE_VISCOUS_FORM_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>> +hybridRusanovRoeViscousFormEulerianCompositeSolver_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 size_t& degree, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const double& dt, + const bool check = false); + +#endif // HYBRID_RUSANOV_ROE_VISCOUS_FORM_EULERIAN_COMPOSITE_SOLVER_V2_HPP diff --git a/src/scheme/RoeViscousFormEulerianCompositeSolver_v2.cpp b/src/scheme/RoeViscousFormEulerianCompositeSolver_v2.cpp index 8752bbecf4d17c54183babdde52addb24bc7e362..5089597fb9896a16812c9108ad913827fb4e0cd3 100644 --- a/src/scheme/RoeViscousFormEulerianCompositeSolver_v2.cpp +++ b/src/scheme/RoeViscousFormEulerianCompositeSolver_v2.cpp @@ -1507,7 +1507,7 @@ class RoeViscousFormEulerianCompositeSolver_v2 bool anySignDif = false; if (anySignChgJ or anySignChgK) - anySignDif = true; // false; // true; + anySignDif = false; // false; // true; if (anySignDif) { Rpxp AddedViscosity(identity); @@ -1630,7 +1630,7 @@ class RoeViscousFormEulerianCompositeSolver_v2 bool anySignDif = false; if (anySignChgJ or anySignChgK) - anySignDif = true; // false; // true; + anySignDif = false; // false; // true; if (anySignDif) { Rpxp AddedViscosity(identity); @@ -1763,7 +1763,7 @@ class RoeViscousFormEulerianCompositeSolver_v2 bool anySignDif = false; if (anySignChgJ or anySignChgK) - anySignDif = true; // false; // true; + anySignDif = false; // false; // true; if (anySignDif) { Rpxp AddedViscosity(identity); @@ -1822,8 +1822,8 @@ class RoeViscousFormEulerianCompositeSolver_v2 } // dim 3 // Pour les assemblages - double theta = 2. / 3.; //.5; - double eta = 1. / 6.; //.2; + double theta = 2/3; //.5 ou 2/3 + double eta = 1. / 6.; //.2; 1. / 6. if constexpr (Dimension == 2) { eta = 0; // theta = 1; // pour schema aux aretes diff --git a/src/scheme/RusanovEulerianCompositeSolver_v2.cpp b/src/scheme/RusanovEulerianCompositeSolver_v2.cpp index a68b66b90edaf331b23a3d16218d013856f9c1f2..b2cabf70c1053d7acb3efcdeec0a4260db8a4971 100644 --- a/src/scheme/RusanovEulerianCompositeSolver_v2.cpp +++ b/src/scheme/RusanovEulerianCompositeSolver_v2.cpp @@ -1301,8 +1301,8 @@ class RusanovEulerianCompositeSolver_v2 } // dim 3 // Pour les assemblages - double theta = 2. / 3.; //.5; - double eta = 1. / 6.; //.2; + double theta = 2. / 3.; //.5; 2. / 3. + double eta = 1. / 6.; //.2; 1. / 6. if constexpr (Dimension == 2) { eta = 0; }