From bb5e3cf4d09fc597e2194fbef6f41e8a52514f6c Mon Sep 17 00:00:00 2001 From: HOCH PHILIPPE <philippe.hoch@gmail.com> Date: Tue, 7 May 2024 16:38:16 +0200 Subject: [PATCH] versement Acoustic Solver et liens --- src/scheme/AcousticCompositeSolver.cpp | 1523 ++++++++++++++++++++++++ src/scheme/AcousticCompositeSolver.hpp | 99 ++ src/scheme/CMakeLists.txt | 1 + tests/test_TestVolumes3D.cpp | 293 +++++ 4 files changed, 1916 insertions(+) create mode 100644 src/scheme/AcousticCompositeSolver.cpp create mode 100644 src/scheme/AcousticCompositeSolver.hpp create mode 100644 tests/test_TestVolumes3D.cpp diff --git a/src/scheme/AcousticCompositeSolver.cpp b/src/scheme/AcousticCompositeSolver.cpp new file mode 100644 index 000000000..0c931ba8b --- /dev/null +++ b/src/scheme/AcousticCompositeSolver.cpp @@ -0,0 +1,1523 @@ +#include <scheme/AcousticCompositeSolver.hpp> + +#include <language/utils/InterpolateItemValue.hpp> +#include <mesh/ItemValueUtils.hpp> +#include <mesh/ItemValueVariant.hpp> +#include <mesh/MeshFaceBoundary.hpp> +#include <mesh/MeshFlatNodeBoundary.hpp> +#include <mesh/MeshNodeBoundary.hpp> +#include <mesh/MeshTraits.hpp> +#include <mesh/MeshVariant.hpp> +#include <mesh/SubItemValuePerItemVariant.hpp> +#include <scheme/DirichletBoundaryConditionDescriptor.hpp> +#include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/ExternalBoundaryConditionDescriptor.hpp> +#include <scheme/FixedBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IDiscreteFunctionDescriptor.hpp> +#include <scheme/SymmetryBoundaryConditionDescriptor.hpp> +#include <utils/Socket.hpp> + +#include <variant> +#include <vector> + +double +composite_acoustic_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c_v) +{ + const auto& c = c_v->get<DiscreteFunctionP0<const double>>(); + + return std::visit( + [&](auto&& p_mesh) -> double { + const auto& mesh = *p_mesh; + + using MeshType = decltype(mesh); + if constexpr (is_polygonal_mesh_v<MeshType>) { + const auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); + const auto Sj = MeshDataManager::instance().getMeshData(mesh).sumOverRLjr(); + + CellValue<double> local_dt{mesh.connectivity()}; + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { local_dt[j] = 2 * Vj[j] / (Sj[j] * c[j]); }); + + return min(local_dt); + } else { + throw NormalError("unexpected mesh type"); + } + }, + c.meshVariant()->variant()); +} + +template <MeshConcept MeshType> +class AcousticCompositeSolverHandler::AcousticCompositeSolver final : public AcousticCompositeSolverHandler::IAcousticCompositeSolver +{ + private: + static constexpr size_t Dimension = MeshType::Dimension; + + using Rdxd = TinyMatrix<Dimension>; + using Rd = TinyVector<Dimension>; + + using MeshDataType = MeshData<MeshType>; + + using DiscreteScalarFunction = DiscreteFunctionP0<const double>; + using DiscreteVectorFunction = DiscreteFunctionP0<const Rd>; + + class FixedBoundaryCondition; + class PressureBoundaryCondition; + class SymmetryBoundaryCondition; + class VelocityBoundaryCondition; + class ExternalFSIVelocityBoundaryCondition; + + using BoundaryCondition = std::variant<FixedBoundaryCondition, + PressureBoundaryCondition, + SymmetryBoundaryCondition, + VelocityBoundaryCondition, + ExternalFSIVelocityBoundaryCondition>; + + using BoundaryConditionList = std::vector<BoundaryCondition>; + + NodeValuePerCell<const Rdxd> + _computeGlaceAjr(const MeshType& mesh, const DiscreteScalarFunction& rhoc) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + const NodeValuePerCell<const Rd> njr = mesh_data.njr(); + + NodeValuePerCell<Rdxd> Ajr{mesh.connectivity()}; + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const size_t& nb_nodes = Ajr.numberOfSubValues(j); + const double& rhoc_j = rhoc[j]; + for (size_t r = 0; r < nb_nodes; ++r) { + Ajr(j, r) = tensorProduct(rhoc_j * Cjr(j, r), njr(j, r)); + } + }); + + return Ajr; + } + + EdgeValuePerCell<const Rdxd> + _computeGlaceAje(const MeshType& mesh, const DiscreteScalarFunction& rhoc) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const EdgeValuePerCell<const Rd> Cje = mesh_data.Cje(); + const EdgeValuePerCell<const Rd> nje = mesh_data.nje(); + + EdgeValuePerCell<Rdxd> Aje{mesh.connectivity()}; + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const size_t& nb_edges = Aje.numberOfSubValues(j); + const double& rhoc_j = rhoc[j]; + for (size_t e = 0; e < nb_edges; ++e) { + Aje(j, e) = tensorProduct(rhoc_j * Cje(j, e), nje(j, e)); + } + }); + + return Aje; + } + + FaceValuePerCell<const Rdxd> + _computeGlaceAjf(const MeshType& mesh, const DiscreteScalarFunction& rhoc) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const FaceValuePerCell<const Rd> Cjf = mesh_data.Cjf(); + const FaceValuePerCell<const Rd> njf = mesh_data.njf(); + + FaceValuePerCell<Rdxd> Ajf{mesh.connectivity()}; + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const size_t& nb_faces = Ajf.numberOfSubValues(j); + const double& rhoc_j = rhoc[j]; + for (size_t f = 0; f < nb_faces; ++f) { + Ajf(j, f) = tensorProduct(rhoc_j * Cjf(j, f), njf(j, f)); + } + }); + + return Ajf; + } + + + + NodeValuePerCell<const Rdxd> + _computeEucclhydAjr(const MeshType& mesh, const DiscreteScalarFunction& rhoc) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerFace<const Rd> Nlr = mesh_data.Nlr(); + const NodeValuePerFace<const Rd> nlr = mesh_data.nlr(); + + const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); + + NodeValuePerCell<Rdxd> Ajr{mesh.connectivity()}; + + parallel_for( + Ajr.numberOfValues(), PUGS_LAMBDA(size_t jr) { Ajr[jr] = zero; }); + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + const auto& cell_faces = cell_to_face_matrix[j]; + + const double& rho_c = rhoc[j]; + + for (size_t L = 0; L < cell_faces.size(); ++L) { + const FaceId& l = cell_faces[L]; + const auto& face_nodes = face_to_node_matrix[l]; + + auto local_node_number_in_cell = [&](NodeId node_number) { + for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { + if (node_number == cell_nodes[i_node]) { + return i_node; + } + } + return std::numeric_limits<size_t>::max(); + }; + + for (size_t rl = 0; rl < face_nodes.size(); ++rl) { + const size_t R = local_node_number_in_cell(face_nodes[rl]); + Ajr(j, R) += tensorProduct(rho_c * Nlr(l, rl), nlr(l, rl)); + } + } + }); + + return Ajr; + } + + EdgeValuePerCell<const Rdxd> + _computeEucclhydCompositeAje(const MeshType& mesh, const DiscreteScalarFunction& rhoc) const + { + /*MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const EdgeValuePerFace<const Rd> Nle = mesh_data.Nle(); + const EdgeValuePerFace<const Rd> nle = mesh_data.nle(); + + const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); +*/ + EdgeValuePerCell<Rdxd> Aje{mesh.connectivity()}; + + parallel_for( + Aje.numberOfValues(), PUGS_LAMBDA(size_t jr) { Aje[jr] = zero; }); + /* + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + const auto& cell_faces = cell_to_face_matrix[j]; + + const double& rho_c = rhoc[j]; + + for (size_t L = 0; L < cell_faces.size(); ++L) { + const FaceId& l = cell_faces[L]; + const auto& face_nodes = face_to_edge_matrix[l]; + + auto local_node_number_in_cell = [&](NodeId node_number) { + for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { + if (node_number == cell_nodes[i_node]) { + return i_node; + } + } + return std::numeric_limits<size_t>::max(); + }; + + for (size_t rl = 0; rl < face_nodes.size(); ++rl) { + const size_t R = local_node_number_in_cell(face_nodes[rl]); + Aje(j, R) += tensorProduct(rho_c * Nlr(l, rl), nlr(l, rl)); + } + } + }); + */ + return Aje; + } + + FaceValuePerCell<const Rdxd> + _computeEucclhydCompositeAjf(const MeshType& mesh, const DiscreteScalarFunction& rhoc) const + { + /*MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const FaceValue<const Rd> Nlf = mesh_data.Nlf(); + const FaceValue<const Rd> nlf = mesh_data.nlf(); + + const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); +*/ + FaceValuePerCell<Rdxd> Ajf{mesh.connectivity()}; + + parallel_for( + Ajf.numberOfValues(), PUGS_LAMBDA(size_t jr) { Ajf[jr] = zero; }); + /* + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + const auto& cell_faces = cell_to_face_matrix[j]; + + const double& rho_c = rhoc[j]; + + for (size_t L = 0; L < cell_faces.size(); ++L) { + const FaceId& l = cell_faces[L]; + const auto& face_nodes = face_to_edge_matrix[l]; + + auto local_node_number_in_cell = [&](NodeId node_number) { + for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { + if (node_number == cell_nodes[i_node]) { + return i_node; + } + } + return std::numeric_limits<size_t>::max(); + }; + + for (size_t rl = 0; rl < face_nodes.size(); ++rl) { + const size_t R = local_node_number_in_cell(face_nodes[rl]); + Aje(j, R) += tensorProduct(rho_c * Nlr(l, rl), nlr(l, rl)); + } + } + }); + */ + return Ajf; + } + + + + NodeValuePerCell<const Rdxd> + _computeAjr(const SolverType& solver_type, const MeshType& mesh, const DiscreteScalarFunction& rhoc) const + { + if constexpr (Dimension == 1) { + return _computeGlaceAjr(mesh, rhoc); + } else { + switch (solver_type) { + case SolverType::GlaceComposite: { + return _computeGlaceAjr(mesh, rhoc); + } + case SolverType::EucclhydComposite: { + return _computeEucclhydAjr(mesh, rhoc); + } + + default: { + throw UnexpectedError("invalid solver type"); + } + } + } + } + + EdgeValuePerCell<const Rdxd> + _computeAje(const SolverType& solver_type, const MeshType& mesh, const DiscreteScalarFunction& rhoc) const + { + if constexpr (Dimension == 1) { + throw UnexpectedError("invalid solver type pour arete 1D.."); + } else { + switch (solver_type) { + case SolverType::GlaceComposite: { + return _computeGlaceAje(mesh, rhoc); + } + case SolverType::EucclhydComposite: { + //return _computeEucclhydAje(mesh, rhoc); + } + default: { + throw UnexpectedError("invalid solver type"); + } + } + } + } + + FaceValuePerCell<const Rdxd> + _computeAjf(const SolverType& solver_type, const MeshType& mesh, const DiscreteScalarFunction& rhoc) const + { + if constexpr (Dimension == 1) { + throw UnexpectedError("invalid solver type pour face 1D.."); + } else { + switch (solver_type) { + case SolverType::GlaceComposite: { + return _computeGlaceAjf(mesh, rhoc); + } + case SolverType::EucclhydComposite: { + //return _computeEucclhydCompositeAjf(mesh, rhoc); + } + default: { + throw UnexpectedError("invalid solver type"); + } + } + } + } + + + NodeValue<Rdxd> + _computeAr(const MeshType& mesh, const NodeValuePerCell<const Rdxd>& Ajr) const + { + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + NodeValue<Rdxd> Ar{mesh.connectivity()}; + + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + Rdxd sum = zero; + const auto& node_to_cell = node_to_cell_matrix[r]; + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(r); + + for (size_t j = 0; j < node_to_cell.size(); ++j) { + const CellId J = node_to_cell[j]; + const unsigned int R = node_local_number_in_its_cells[j]; + sum += Ajr(J, R); + } + Ar[r] = sum; + }); + + return Ar; + } + + NodeValue<Rd> + _computeBr(const Mesh<Dimension>& mesh, + const NodeValuePerCell<const Rdxd>& Ajr, + const DiscreteVectorFunction& u, + const DiscreteScalarFunction& p) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerCell<const Rd>& Cjr = mesh_data.Cjr(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + NodeValue<Rd> b{mesh.connectivity()}; + + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + const auto& node_to_cell = node_to_cell_matrix[r]; + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(r); + + Rd br = zero; + for (size_t j = 0; j < node_to_cell.size(); ++j) { + const CellId J = node_to_cell[j]; + const unsigned int R = node_local_number_in_its_cells[j]; + br += Ajr(J, R) * u[J] + p[J] * Cjr(J, R); + } + + b[r] = br; + }); + + return b; + } + + BoundaryConditionList + _getBCList(const MeshType& mesh, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + BoundaryConditionList bc_list; + + for (const auto& bc_descriptor : bc_descriptor_list) { + bool is_valid_boundary_condition = true; + + switch (bc_descriptor->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + bc_list.emplace_back( + SymmetryBoundaryCondition(getMeshFlatNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::fixed: { + bc_list.emplace_back(FixedBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::external: { + if constexpr (Dimension == 1) { + const ExternalBoundaryConditionDescriptor& extern_bc_descriptor = + dynamic_cast<const ExternalBoundaryConditionDescriptor&>(*bc_descriptor); + bc_list.emplace_back( + ExternalFSIVelocityBoundaryCondition(mesh, getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + extern_bc_descriptor.socket())); + } else { + throw NotImplementedError("external FSI velocity not implemented for dimension > 1"); + } + break; + } + case IBoundaryConditionDescriptor::Type::dirichlet: { + const DirichletBoundaryConditionDescriptor& dirichlet_bc_descriptor = + dynamic_cast<const DirichletBoundaryConditionDescriptor&>(*bc_descriptor); + if (dirichlet_bc_descriptor.name() == "velocity") { + MeshNodeBoundary mesh_node_boundary = getMeshNodeBoundary(mesh, dirichlet_bc_descriptor.boundaryDescriptor()); + + Array<const Rd> value_list = + InterpolateItemValue<Rd(Rd)>::template interpolate<ItemType::node>(dirichlet_bc_descriptor.rhsSymbolId(), + mesh.xr(), + mesh_node_boundary.nodeList()); + + bc_list.emplace_back(VelocityBoundaryCondition{mesh_node_boundary, value_list}); + } else if (dirichlet_bc_descriptor.name() == "pressure") { + const FunctionSymbolId pressure_id = dirichlet_bc_descriptor.rhsSymbolId(); + + if constexpr (Dimension == 1) { + MeshNodeBoundary mesh_node_boundary = getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + Array<const double> node_values = + InterpolateItemValue<double(Rd)>::template interpolate<ItemType::node>(pressure_id, mesh.xr(), + mesh_node_boundary.nodeList()); + PressureBoundaryCondition p(mesh_node_boundary, node_values); + bc_list.emplace_back(p); + } else { + MeshFaceBoundary mesh_face_boundary = getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + Array<const double> face_values = + InterpolateItemValue<double(Rd)>::template interpolate<ItemType::face>(pressure_id, mesh_data.xl(), + mesh_face_boundary.faceList()); + bc_list.emplace_back(PressureBoundaryCondition{mesh_face_boundary, face_values}); + } + + } else { + is_valid_boundary_condition = false; + } + 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 acoustic solver"; + throw NormalError(error_msg.str()); + } + } + + return bc_list; + } + + void _applyPressureBC(const BoundaryConditionList& bc_list, const MeshType& mesh, NodeValue<Rd>& br) const; + void _applySymmetryBC(const BoundaryConditionList& bc_list, NodeValue<Rdxd>& Ar, NodeValue<Rd>& br) const; + void _applyVelocityBC(const BoundaryConditionList& bc_list, NodeValue<Rdxd>& Ar, NodeValue<Rd>& br) const; + void _applyExternalVelocityBC(const BoundaryConditionList& bc_list, + const DiscreteScalarFunction& p, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) const; + + void + _applyBoundaryConditions(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) const + { + this->_applyPressureBC(bc_list, mesh, br); + this->_applySymmetryBC(bc_list, Ar, br); + this->_applyVelocityBC(bc_list, Ar, br); + } + + NodeValue<const Rd> + _computeUr(const MeshType& mesh, const NodeValue<Rdxd>& Ar, const NodeValue<Rd>& br) const + { + NodeValue<Rd> u{mesh.connectivity()}; + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { u[r] = inverse(Ar[r]) * br[r]; }); + + return u; + } + + FaceValue<const Rd> + _computeUf(const MeshType& mesh, //const FaceValue<Rdxd>& Af, const FaceValue<Rd>& bf, + const NodeValue<Rd>& Ur, + const EdgeValue<Rd>& Ue, + const DiscreteScalarFunction& Z + ) const + { + FaceValue<Rd> u{mesh.connectivity()}; + parallel_for( + mesh.numberOfFaces(), PUGS_LAMBDA(FaceId f) { u[f] = zero;});//inverse(Ar[r]) * br[r]; }); + + return u; + } + + EdgeValue<const Rd> + _computeUe(const MeshType& mesh, + // const EdgeValue<Rdxd>& Ae, const EdgeValue<Rd>& be, + const NodeValue<Rd>& Ur, + const DiscreteScalarFunction& Z + ) const + { + EdgeValue<Rd> u{mesh.connectivity()}; + parallel_for( + mesh.numberOfEdges(), PUGS_LAMBDA(EdgeId e) { u[e] = zero; });//inverse(Ar[r]) * br[r]; }); + + return u; + } + + + NodeValuePerCell<Rd> + _computeFjr(const MeshType& mesh, + const NodeValuePerCell<const Rdxd>& Ajr, + const NodeValue<const Rd>& ur, + const DiscreteVectorFunction& u, + const DiscreteScalarFunction& p) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + + NodeValuePerCell<Rd> F{mesh.connectivity()}; + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + for (size_t r = 0; r < cell_nodes.size(); ++r) { + F(j, r) = Ajr(j, r) * (u[j] - ur[cell_nodes[r]]) + p[j] * Cjr(j, r); + } + }); + + return F; + } + + FaceValuePerCell<Rd> + _computeFjf(const MeshType& mesh, + const FaceValuePerCell<const Rdxd>& Ajf, + const FaceValue<const Rd>& uf, + const DiscreteVectorFunction& u, + const DiscreteScalarFunction& p) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const FaceValuePerCell<const Rd> Cjf = mesh_data.Cjf(); + + const auto& cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); + + FaceValuePerCell<Rd> F{mesh.connectivity()}; + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_faces = cell_to_face_matrix[j]; + + for (size_t f = 0; f < cell_faces.size(); ++f) { + F(j, f) = Ajf(j, f) * (u[j] - uf[cell_faces[f]]) + p[j] * Cjf(j, f); + } + }); + + return F; + } + + EdgeValuePerCell<Rd> + _computeFje(const MeshType& mesh, + const EdgeValuePerCell<const Rdxd>& Aje, + const EdgeValue<const Rd>& ue, + const DiscreteVectorFunction& u, + const DiscreteScalarFunction& p) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const EdgeValuePerCell<const Rd> Cje = mesh_data.Cje(); + + const auto& cell_to_edge_matrix = mesh.connectivity().cellToEdgeMatrix(); + + EdgeValuePerCell<Rd> F{mesh.connectivity()}; + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_edges = cell_to_edge_matrix[j]; + + for (size_t e = 0; e < cell_edges.size(); ++e) { + F(j, e) = Aje(j, e) * (u[j] - ue[cell_edges[e]]) + p[j] * Cje(j, e); + } + }); + + return F; + } + + + public: + + std::tuple<const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant>, + const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant>, + const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant> + > + compute_fluxes(const SolverType& solver_type, + const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, + const std::shared_ptr<const DiscreteFunctionVariant>& c_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& p_v, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + std::shared_ptr mesh_v = getCommonMesh({rho_v, c_v, u_v, p_v}); + if (not mesh_v) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + if (not checkDiscretizationType({rho_v, c_v, u_v, p_v}, DiscreteFunctionType::P0)) { + throw NormalError("acoustic solver expects P0 functions"); + } + const MeshType& mesh = *mesh_v->get<MeshType>(); + //if constexpr (Dimension ==1) + //{ + // throw NormalError("acoustic solver composite inutile dimension 1"); + //} + const DiscreteScalarFunction& rho = rho_v->get<DiscreteScalarFunction>(); + const DiscreteScalarFunction& c = c_v->get<DiscreteScalarFunction>(); + const DiscreteVectorFunction& u = u_v->get<DiscreteVectorFunction>(); + const DiscreteScalarFunction& p = p_v->get<DiscreteScalarFunction>(); + + NodeValuePerCell<const Rdxd> Ajr = this->_computeAjr(solver_type, mesh, rho * c); + EdgeValuePerCell<const Rdxd> Aje = this->_computeAje(solver_type, mesh, rho * c); + FaceValuePerCell<const Rdxd> Ajf = this->_computeAjf(solver_type, mesh, rho * c); + + NodeValue<Rdxd> Ar = this->_computeAr(mesh, Ajr); + NodeValue<Rd> br = this->_computeBr(mesh, Ajr, u, p); + + const BoundaryConditionList bc_list = this->_getBCList(mesh, bc_descriptor_list); + this->_applyBoundaryConditions(bc_list, mesh, Ar, br); + this->_applyExternalVelocityBC(bc_list, p, Ar, br); + + synchronize(Ar); + synchronize(br); + + NodeValue<const Rd> ur = this->_computeUr(mesh, Ar, br); + NodeValuePerCell<const Rd> Fjr = this->_computeFjr(mesh, Ajr, ur, u, p); + + auto edge_to_node_connectivity = mesh.connectivity().edgeToNodeMatrix(); + + EdgeValue<Rd> ue{mesh.connectivity()}; + ue.fill(zero); + + parallel_for(mesh.numberOfEdges(), PUGS_LAMBDA(const EdgeId edge_id) + { + const auto& edge_nodes = edge_to_node_connectivity[edge_id]; + const NodeId& node0_id= edge_nodes[0]; + const NodeId& node1_id= edge_nodes[1]; + ue[edge_id]=.5*(ur[node0_id]+ur[node1_id]); + }); + + //EdgeValue<const Rd> ue = this->_computeUe(mesh, ur, rho * c); + EdgeValuePerCell<const Rd> Fje = this->_computeFje(mesh, Aje, ue, u, p); + + auto face_to_node_connectivity = mesh.connectivity().faceToNodeMatrix(); + FaceValue<Rd> uf{mesh.connectivity()}; + uf.fill(zero); + + parallel_for(mesh.numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) + { + const auto& face_nodes = face_to_node_connectivity[face_id]; + Rd V=zero; + for (size_t i_node=0;i_node<face_nodes.size();++i_node) + { + const NodeId& node= face_nodes[i_node]; + + V+=ur[node]; + } + V*=1./face_nodes.size(); + uf[face_id]=V; + }); + + + //FaceValue<const Rd> uf = this->_computeUf(mesh, ur, ue, rho * c) ; + FaceValuePerCell<const Rd> Fjf = this->_computeFjf(mesh, Ajf, uf, u, p); + + return std::make_tuple(std::make_shared<const ItemValueVariant>(ur), + std::make_shared<const SubItemValuePerItemVariant>(Fjr), + + std::make_shared<const ItemValueVariant>(ue), + std::make_shared<const SubItemValuePerItemVariant>(Fje), + + std::make_shared<const ItemValueVariant>(uf), + std::make_shared<const SubItemValuePerItemVariant>(Fjf) + ); + } + + + + //2d + /* + std::tuple<const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant>, + const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant> + > + compute_fluxes(const SolverType& solver_type, + const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, + const std::shared_ptr<const DiscreteFunctionVariant>& c_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& p_v, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + std::shared_ptr mesh_v = getCommonMesh({rho_v, c_v, u_v, p_v}); + if (not mesh_v) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + if (not checkDiscretizationType({rho_v, c_v, u_v, p_v}, DiscreteFunctionType::P0)) { + throw NormalError("acoustic solver expects P0 functions"); + } + const MeshType& mesh = *mesh_v->get<MeshType>(); + //if constexpr (Dimension ==1) + //{ + // throw NormalError("acoustic solver composite inutile dimension 1"); + //} + const DiscreteScalarFunction& rho = rho_v->get<DiscreteScalarFunction>(); + const DiscreteScalarFunction& c = c_v->get<DiscreteScalarFunction>(); + const DiscreteVectorFunction& u = u_v->get<DiscreteVectorFunction>(); + const DiscreteScalarFunction& p = p_v->get<DiscreteScalarFunction>(); + + NodeValuePerCell<const Rdxd> Ajr = this->_computeAjr(solver_type, mesh, rho * c); + EdgeValuePerCell<const Rdxd> Aje = this->_computeAje(solver_type, mesh, rho * c); + FaceValuePerCell<const Rdxd> Ajf = this->_computeAjf(solver_type, mesh, rho * c); + + NodeValue<Rdxd> Ar = this->_computeAr(mesh, Ajr); + NodeValue<Rd> br = this->_computeBr(mesh, Ajr, u, p); + + const BoundaryConditionList bc_list = this->_getBCList(mesh, bc_descriptor_list); + this->_applyBoundaryConditions(bc_list, mesh, Ar, br); + this->_applyExternalVelocityBC(bc_list, p, Ar, br); + + synchronize(Ar); + synchronize(br); + + NodeValue<const Rd> ur = this->_computeUr(mesh, Ar, br); + NodeValuePerCell<const Rd> Fjr = this->_computeFjr(mesh, Ajr, ur, u, p); + + FaceValue<Rd> uf{mesh.connectivity()}; + uf.fill(zero); + + auto face_to_node_connectivity = mesh.connectivity().faceToNodeMatrix(); + + parallel_for(mesh.numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) + { + const auto& face_nodes = face_to_node_connectivity[face_id]; + Rd V=zero; + for (size_t i_node=0;i_node<face_nodes.size();++i_node) + { + const NodeId& node= face_nodes[i_node]; + + V+=ur[node]; + } + V*=1./face_nodes.size(); + uf[face_id]=V; + }); + + + //FaceValue<const Rd> uf = this->_computeUf(mesh, ur, ue, rho * c) ; + FaceValuePerCell<const Rd> Fjf = this->_computeFjf(mesh, Ajf, uf, u, p); + + return std::make_tuple(std::make_shared<const ItemValueVariant>(ur), + std::make_shared<const SubItemValuePerItemVariant>(Fjr), + + std::make_shared<const ItemValueVariant>(uf), + std::make_shared<const SubItemValuePerItemVariant>(Fjf) + ); + } + +*/ + + + + // 3d + std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const MeshType& mesh, + const DiscreteScalarFunction& rho, + const DiscreteVectorFunction& u, + const DiscreteScalarFunction& E, + const NodeValue<const Rd>& ur, + const NodeValuePerCell<const Rd>& Fjr, + const EdgeValue<const Rd>& ue, + const EdgeValuePerCell<const Rd>& Fje, + const FaceValue<const Rd>& uf, + const FaceValuePerCell<const Rd>& Fjf + ) const + { + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_edge_matrix = mesh.connectivity().cellToEdgeMatrix(); + const auto& cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); + + if ((mesh.shared_connectivity() != ur.connectivity_ptr()) or + (mesh.shared_connectivity() != Fjr.connectivity_ptr()) or + (mesh.shared_connectivity() != ue.connectivity_ptr()) or + (mesh.shared_connectivity() != Fje.connectivity_ptr()) or + (mesh.shared_connectivity() != uf.connectivity_ptr()) or + (mesh.shared_connectivity() != Fjf.connectivity_ptr()) + ) { + throw NormalError("fluxes are not defined on the same connectivity than the mesh"); + } + + NodeValue<Rd> new_xr = copy(mesh.xr()); + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { new_xr[r] += dt * ur[r]; }); + + std::shared_ptr<const MeshType> new_mesh = std::make_shared<MeshType>(mesh.shared_connectivity(), new_xr); + + CellValue<const double> Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); + + CellValue<double> new_rho = copy(rho.cellValues()); + CellValue<Rd> new_u = copy(u.cellValues()); + CellValue<double> new_E = copy(E.cellValues()); + + const double teta_e=1.; + const double teta_f=0.; + const double teta_r=1.0-teta_e-teta_f; + + double tetar=teta_r; + double tetaf=teta_e; + double tetae=0; + + if (Dimension==3) + { + tetaf=teta_f; + tetae=teta_e; + } + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + Rd momentum_fluxes = zero; + double energy_fluxes = 0; + for (size_t R = 0; R < cell_nodes.size(); ++R) { + const NodeId r = cell_nodes[R]; + momentum_fluxes +=tetar * Fjr(j, R); + energy_fluxes +=tetar * dot(Fjr(j, R), ur[r]); + } + + const auto& cell_edges = cell_to_edge_matrix[j]; + + for (size_t R = 0; R < cell_edges.size(); ++R) { + const EdgeId r = cell_edges[R]; + momentum_fluxes +=tetae * Fje(j, R); + energy_fluxes +=tetae * dot(Fje(j, R), ue[r]); + } + + const auto& cell_faces = cell_to_face_matrix[j]; + + for (size_t R = 0; R < cell_faces.size(); ++R) { + const FaceId r = cell_faces[R]; + momentum_fluxes += tetaf * Fjf(j, R); + energy_fluxes += tetaf * dot(Fjf(j, R), uf[r]); + } + + const double dt_over_Mj = dt / (rho[j] * Vj[j]); + new_u[j] -= dt_over_Mj * momentum_fluxes; + new_E[j] -= dt_over_Mj * energy_fluxes; + }); + + CellValue<const double> new_Vj = MeshDataManager::instance().getMeshData(*new_mesh).Vj(); + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { new_rho[j] *= Vj[j] / new_Vj[j]; }); + + return {std::make_shared<MeshVariant>(new_mesh), + std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_rho)), + std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh, new_u)), + std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_E))}; + } + + + // 2d .. + std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const MeshType& mesh, + const DiscreteScalarFunction& rho, + const DiscreteVectorFunction& u, + const DiscreteScalarFunction& E, + const NodeValue<const Rd>& ur, + const NodeValuePerCell<const Rd>& Fjr, + //const EdgeValue<const Rd>& ue, + //const EdgeValuePerCell<const Rd>& Fje, + const FaceValue<const Rd>& uf, + const FaceValuePerCell<const Rd>& Fjf + ) const + { + throw NormalError(" Cas apply flux composite 2D spec not finished"); + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + //const auto& cell_to_edge_matrix = mesh.connectivity().cellToEdgeMatrix(); + const auto& cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); + + if ((mesh.shared_connectivity() != ur.connectivity_ptr()) or + (mesh.shared_connectivity() != Fjr.connectivity_ptr()) or + //(mesh.shared_connectivity() != ue.connectivity_ptr()) or + //(mesh.shared_connectivity() != Fje.connectivity_ptr()) or + (mesh.shared_connectivity() != uf.connectivity_ptr()) or + (mesh.shared_connectivity() != Fjf.connectivity_ptr()) + ) { + throw NormalError("fluxes are not defined on the same connectivity than the mesh"); + } + + NodeValue<Rd> new_xr = copy(mesh.xr()); + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { new_xr[r] += dt * ur[r]; }); + + std::shared_ptr<const MeshType> new_mesh = std::make_shared<MeshType>(mesh.shared_connectivity(), new_xr); + + CellValue<const double> Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); + + CellValue<double> new_rho = copy(rho.cellValues()); + CellValue<Rd> new_u = copy(u.cellValues()); + CellValue<double> new_E = copy(E.cellValues()); + + const double teta_e=0.5; + const double teta_f=0.0; + const double teta_r=1.0-teta_e-teta_f; + + double tetar=teta_r; + double tetaf=teta_e; + double tetae=0; + + //if (Dimension==3) + //{ + // tetaf=teta_f; + // tetae=teta_e; + //} + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + Rd momentum_fluxes = zero; + double energy_fluxes = 0; + for (size_t R = 0; R < cell_nodes.size(); ++R) { + const NodeId r = cell_nodes[R]; + momentum_fluxes +=tetar * Fjr(j, R); + energy_fluxes +=tetar * dot(Fjr(j, R), ur[r]); + } + + // const auto& cell_edges = cell_to_edge_matrix[j]; + + // for (size_t R = 0; R < cell_edges.size(); ++R) { + // const EdgeId r = cell_edges[R]; + // momentum_fluxes +=tetae * Fje(j, R); + // energy_fluxes +=tetae * dot(Fje(j, R), ue[r]); + // } + + const auto& cell_faces = cell_to_face_matrix[j]; + + for (size_t R = 0; R < cell_faces.size(); ++R) { + const FaceId r = cell_faces[R]; + momentum_fluxes += tetaf * Fjf(j, R); + energy_fluxes += tetaf * dot(Fjf(j, R), uf[r]); + } + + const double dt_over_Mj = dt / (rho[j] * Vj[j]); + new_u[j] -= dt_over_Mj * momentum_fluxes; + new_E[j] -= dt_over_Mj * energy_fluxes; + }); + + CellValue<const double> new_Vj = MeshDataManager::instance().getMeshData(*new_mesh).Vj(); + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { new_rho[j] *= Vj[j] / new_Vj[j]; }); + + return {std::make_shared<MeshVariant>(new_mesh), + std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_rho)), + std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh, new_u)), + std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_E))}; + } + + + std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& E_v, + const std::shared_ptr<const ItemValueVariant>& ur, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr, + const std::shared_ptr<const ItemValueVariant>& ue, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fje, + const std::shared_ptr<const ItemValueVariant>& uf, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjf + ) const + { + std::shared_ptr mesh_v = getCommonMesh({rho_v, u_v, E_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 this->apply_fluxes(dt, // + *mesh_v->get<MeshType>(), // + rho_v->get<DiscreteScalarFunction>(), // + u_v->get<DiscreteVectorFunction>(), // + E_v->get<DiscreteScalarFunction>(), // + ur->get<NodeValue<const Rd>>(), // + Fjr->get<NodeValuePerCell<const Rd>>(), + ue->get<EdgeValue<const Rd>>(), // + Fje->get<EdgeValuePerCell<const Rd>>(), + uf->get<FaceValue<const Rd>>(), // + Fjf->get<FaceValuePerCell<const Rd>>() + ); + } + + + + // 2d + std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& E_v, + const std::shared_ptr<const ItemValueVariant>& ur, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr, + //const std::shared_ptr<const ItemValueVariant>& ue, + //const std::shared_ptr<const SubItemValuePerItemVariant>& Fje, + const std::shared_ptr<const ItemValueVariant>& uf, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjf + ) const + { + std::shared_ptr mesh_v = getCommonMesh({rho_v, u_v, E_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 this->apply_fluxes(dt, // + *mesh_v->get<MeshType>(), // + rho_v->get<DiscreteScalarFunction>(), // + u_v->get<DiscreteVectorFunction>(), // + E_v->get<DiscreteScalarFunction>(), // + ur->get<NodeValue<const Rd>>(), // + Fjr->get<NodeValuePerCell<const Rd>>(), + //ue->get<EdgeValue<const Rd>>(), // + //Fje->get<EdgeValuePerCell<const Rd>>(), + uf->get<FaceValue<const Rd>>(), // + Fjf->get<FaceValuePerCell<const Rd>>() + ); + } + + + + // 3d + std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply(const SolverType& solver_type, + const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + auto [ur, Fjr, ue, Fje, uf, Fjf] = compute_fluxes(solver_type, rho, c, u, p, bc_descriptor_list); + return apply_fluxes(dt, rho, u, E, ur, Fjr, ue, Fje, uf, Fjf); + } + + /* ci dessous marche pas .. faudrait passer template specialisation dim=2 + //2d + std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply(const SolverType& solver_type, + const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + auto [ur, Fjr, uf, Fjf] = compute_fluxes(solver_type, rho, c, u, p, bc_descriptor_list); + return apply_fluxes(dt, rho, u, E, ur, Fjr, uf, Fjf); + } + */ + + AcousticCompositeSolver() = default; + AcousticCompositeSolver(AcousticCompositeSolver&&) = default; + ~AcousticCompositeSolver() = default; +}; + +template <MeshConcept MeshType> +void +AcousticCompositeSolverHandler::AcousticCompositeSolver<MeshType>::_applyPressureBC(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValue<Rd>& br) 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<PressureBoundaryCondition, T>) { + MeshData<MeshType>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + if constexpr (Dimension == 1) { + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + const auto& node_list = bc.nodeList(); + const auto& value_list = bc.valueList(); + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + const NodeId node_id = node_list[i_node]; + const auto& node_cell_list = node_to_cell_matrix[node_id]; + Assert(node_cell_list.size() == 1); + + CellId node_cell_id = node_cell_list[0]; + size_t node_local_number_in_cell = node_local_numbers_in_their_cells(node_id, 0); + + br[node_id] -= value_list[i_node] * Cjr(node_cell_id, node_local_number_in_cell); + }); + } else { + const NodeValuePerFace<const Rd> Nlr = mesh_data.Nlr(); + + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + 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& value_list = bc.valueList(); + 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); + + const double sign = face_cell_is_reversed(face_cell_id, face_local_number_in_cell) ? -1 : 1; + + const auto& face_nodes = face_to_node_matrix[face_id]; + + for (size_t i_node = 0; i_node < face_nodes.size(); ++i_node) { + NodeId node_id = face_nodes[i_node]; + br[node_id] -= sign * value_list[i_face] * Nlr(face_id, i_node); + } + } + } + } + }, + boundary_condition); + } +} + +template <MeshConcept MeshType> +void +AcousticCompositeSolverHandler::AcousticCompositeSolver<MeshType>::_applySymmetryBC(const BoundaryConditionList& bc_list, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) 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>) { + const Rd& n = bc.outgoingNormal(); + + const Rdxd I = identity; + const Rdxd nxn = tensorProduct(n, n); + const Rdxd P = I - nxn; + + const Array<const NodeId>& node_list = bc.nodeList(); + parallel_for( + bc.numberOfNodes(), PUGS_LAMBDA(int r_number) { + const NodeId r = node_list[r_number]; + + Ar[r] = P * Ar[r] * P + nxn; + br[r] = P * br[r]; + }); + } + }, + boundary_condition); + } +} + +template <MeshConcept MeshType> +void +AcousticCompositeSolverHandler::AcousticCompositeSolver<MeshType>::_applyVelocityBC(const BoundaryConditionList& bc_list, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) 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<VelocityBoundaryCondition, T>) { + const auto& node_list = bc.nodeList(); + const auto& value_list = bc.valueList(); + + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + NodeId node_id = node_list[i_node]; + const auto& value = value_list[i_node]; + + Ar[node_id] = identity; + br[node_id] = value; + }); + } else if constexpr (std::is_same_v<FixedBoundaryCondition, T>) { + const auto& node_list = bc.nodeList(); + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + NodeId node_id = node_list[i_node]; + + Ar[node_id] = identity; + br[node_id] = zero; + }); + } + }, + boundary_condition); + } +} + +template <MeshConcept MeshType> +void +AcousticCompositeSolverHandler::AcousticCompositeSolver<MeshType>::_applyExternalVelocityBC(const BoundaryConditionList& bc_list, + const DiscreteScalarFunction& p, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) 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<ExternalFSIVelocityBoundaryCondition, T>) { + const auto& node_list = bc.nodeList(); + const auto& value_list = bc.valueList(p); + + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + NodeId node_id = node_list[i_node]; + const auto& value = value_list[i_node]; + + Ar[node_id] = identity; + br[node_id] = value; + }); + } + }, + boundary_condition); + } +} + +template <MeshConcept MeshType> +class AcousticCompositeSolverHandler::AcousticCompositeSolver<MeshType>::FixedBoundaryCondition +{ + private: + const MeshNodeBoundary m_mesh_node_boundary; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + FixedBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary) : m_mesh_node_boundary{mesh_node_boundary} {} + + ~FixedBoundaryCondition() = default; +}; + +template <MeshConcept MeshType> +class AcousticCompositeSolverHandler::AcousticCompositeSolver<MeshType>::PressureBoundaryCondition +{ + private: + const MeshFaceBoundary m_mesh_face_boundary; + const Array<const double> m_value_list; + + public: + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + const Array<const double>& + valueList() const + { + return m_value_list; + } + + PressureBoundaryCondition(const MeshFaceBoundary& mesh_face_boundary, const Array<const double>& value_list) + : m_mesh_face_boundary{mesh_face_boundary}, m_value_list{value_list} + {} + + ~PressureBoundaryCondition() = default; +}; + +template <> +class AcousticCompositeSolverHandler::AcousticCompositeSolver<Mesh<1>>::PressureBoundaryCondition +{ + private: + const MeshNodeBoundary m_mesh_node_boundary; + const Array<const double> m_value_list; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const double>& + valueList() const + { + return m_value_list; + } + + PressureBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary, const Array<const double>& value_list) + : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list} + {} + + ~PressureBoundaryCondition() = default; +}; + +template <MeshConcept MeshType> +class AcousticCompositeSolverHandler::AcousticCompositeSolver<MeshType>::ExternalFSIVelocityBoundaryCondition +{ + private: + const ItemToItemMatrix<ItemType::node, ItemType::cell> m_node_to_cell_matrix; + const MeshNodeBoundary m_mesh_node_boundary; + const Array<TinyVector<Dimension>> m_value_list; + const std::shared_ptr<const Socket> m_socket; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + Array<const TinyVector<Dimension>> + valueList(const DiscreteScalarFunction& p) const + { + if (parallel::size() > 1) { + throw NotImplementedError("Parallelism is not supported"); + } + if (m_value_list.size() != 1) { + throw NotImplementedError("Non connected boundaries are not supported"); + } + + const CellId cell_id = m_node_to_cell_matrix[m_mesh_node_boundary.nodeList()[0]][0]; + + write(*m_socket, p[cell_id]); + read(*m_socket, m_value_list[0]); + return m_value_list; + } + + ExternalFSIVelocityBoundaryCondition(const Mesh<Dimension>& mesh, + const MeshNodeBoundary& mesh_node_boundary, + const std::shared_ptr<const Socket>& socket) + : m_node_to_cell_matrix{mesh.connectivity().nodeToCellMatrix()}, + m_mesh_node_boundary{mesh_node_boundary}, + m_value_list(mesh_node_boundary.nodeList().size()), + m_socket{socket} + { + if constexpr (Dimension > 1) { + throw NotImplementedError("external FSI velocity bc in dimension > 1"); + } + } + + ~ExternalFSIVelocityBoundaryCondition() = default; +}; + +template <MeshConcept MeshType> +class AcousticCompositeSolverHandler::AcousticCompositeSolver<MeshType>::VelocityBoundaryCondition +{ + private: + const MeshNodeBoundary m_mesh_node_boundary; + + const Array<const TinyVector<Dimension>> m_value_list; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const TinyVector<Dimension>>& + valueList() const + { + return m_value_list; + } + + VelocityBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary, + const Array<const TinyVector<Dimension>>& value_list) + : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list} + {} + + ~VelocityBoundaryCondition() = default; +}; + +template <MeshConcept MeshType> +class AcousticCompositeSolverHandler::AcousticCompositeSolver<MeshType>::SymmetryBoundaryCondition +{ + public: + using Rd = TinyVector<Dimension, double>; + + private: + const MeshFlatNodeBoundary<MeshType> m_mesh_flat_node_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(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_flat_node_boundary.nodeList(); + } + + SymmetryBoundaryCondition(const MeshFlatNodeBoundary<MeshType>& mesh_flat_node_boundary) + : m_mesh_flat_node_boundary(mesh_flat_node_boundary) + { + ; + } + + ~SymmetryBoundaryCondition() = default; +}; + +AcousticCompositeSolverHandler::AcousticCompositeSolverHandler(const std::shared_ptr<const MeshVariant>& mesh_v) +{ + if (not mesh_v) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + std::visit( + [&](auto&& mesh) { + using MeshType = mesh_type_t<decltype(mesh)>; + if constexpr ((is_polygonal_mesh_v<MeshType>) and (MeshType::Dimension>1)) + { + m_acoustic_composite_solver = std::make_unique<AcousticCompositeSolver<MeshType>>(); + } else { + if (MeshType::Dimension==1) + throw NormalError("Use classical AcousticSolver instead of Composite in 1D"); + else + throw NormalError("unexpected mesh type"); + } + }, + mesh_v->variant()); +} diff --git a/src/scheme/AcousticCompositeSolver.hpp b/src/scheme/AcousticCompositeSolver.hpp new file mode 100644 index 000000000..46fc548e9 --- /dev/null +++ b/src/scheme/AcousticCompositeSolver.hpp @@ -0,0 +1,99 @@ +#ifndef ACOUSTIC_COMPOSITE_SOLVER_HPP +#define ACOUSTIC_COMPOSITE_SOLVER_HPP + +#include <mesh/MeshTraits.hpp> + +#include <memory> +#include <tuple> +#include <vector> + +class DiscreteFunctionVariant; +class IBoundaryConditionDescriptor; +class MeshVariant; +class ItemValueVariant; +class SubItemValuePerItemVariant; + +double composite_acoustic_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c); + +class AcousticCompositeSolverHandler +{ + public: + enum class SolverType + { + GlaceComposite, + EucclhydComposite + }; + + private: + struct IAcousticCompositeSolver + { + + virtual std::tuple<const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant>, + const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant>, + const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant> + > + + compute_fluxes( + const SolverType& solver_type, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const = 0; + + + virtual std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const ItemValueVariant>& ur, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr, + const std::shared_ptr<const ItemValueVariant>& ue, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fje, + const std::shared_ptr<const ItemValueVariant>& uf, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjf) const = 0; + + + virtual std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply(const SolverType& solver_type, + const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const = 0; + + IAcousticCompositeSolver() = default; + IAcousticCompositeSolver(IAcousticCompositeSolver&&) = default; + IAcousticCompositeSolver& operator=(IAcousticCompositeSolver&&) = default; + + virtual ~IAcousticCompositeSolver() = default; + }; + + template <MeshConcept MeshType> + class AcousticCompositeSolver; + + std::unique_ptr<IAcousticCompositeSolver> m_acoustic_composite_solver; + + public: + const IAcousticCompositeSolver& + solver() const + { + return *m_acoustic_composite_solver; + } + + AcousticCompositeSolverHandler(const std::shared_ptr<const MeshVariant>& mesh_v); +}; + +#endif // ACOUSTIC_COMPOSITE_SOLVER_HPP diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt index dadbe73bb..8cdd43f9e 100644 --- a/src/scheme/CMakeLists.txt +++ b/src/scheme/CMakeLists.txt @@ -3,6 +3,7 @@ add_library( PugsScheme AcousticSolver.cpp + AcousticCompositeSolver.cpp HyperelasticSolver.cpp DiscreteFunctionIntegrator.cpp DiscreteFunctionInterpoler.cpp diff --git a/tests/test_TestVolumes3D.cpp b/tests/test_TestVolumes3D.cpp new file mode 100644 index 000000000..2bf952905 --- /dev/null +++ b/tests/test_TestVolumes3D.cpp @@ -0,0 +1,293 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <mesh/ItemArrayUtils.hpp> +#include <mesh/DualMeshManager.hpp> +#include <mesh/ItemValue.hpp> +#include <mesh/ItemValueUtils.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshData.hpp> +#include <mesh/MeshDataManager.hpp> + +#include <MeshDataBaseForTests.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("TestVolumes3D", "[scheme]") +{ + SECTION("3D") + { + using R3 = TinyVector<3>; + + auto hybrid_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); + /* + auto f = [](const R3& X) -> double { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return x * x + 2 * x * y + 3 * y * y + 2 * z * z - z + 1; + }; + */ + std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list; + mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); + mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(hybrid_mesh))); + + for (const auto& mesh_info : mesh_list) { + auto mesh_name = mesh_info.first; + auto mesh = mesh_info.second->get<Mesh<3>>(); + std::clog << " name " << mesh_name << "\n"; + auto& mesh_data = MeshDataManager::instance().getMeshData(*mesh); + + auto Cjr = mesh_data.Cjr(); + auto Cje = mesh_data.Cje(); + auto Cjf = mesh_data.Cjf(); + + auto xr = mesh->xr(); + auto Vj = mesh_data.Vj(); + + auto xl = mesh_data.xl(); // Les centres des faces + auto xe = mesh_data.xe(); // Les centres des aretes + auto Nl = mesh_data.Nl(); // Normale aux faces .. au "centre" des faces + auto nl = mesh_data.nl(); // Normale unite aux faces .. au "centre" des faces + + NodeValuePerFace<const R3> Nlr=mesh_data.Nlr(); + + auto cell_to_node_connectivity = mesh->connectivity().cellToNodeMatrix(); + auto cell_to_face_connectivity = mesh->connectivity().cellToFaceMatrix(); + + const auto& cell_face_is_reversed = mesh->connectivity().cellFaceIsReversed(); + + auto cell_to_edge_connectivity = mesh->connectivity().cellToEdgeMatrix(); + auto edge_to_node_connectivity = mesh->connectivity().edgeToNodeMatrix(); + auto edge_to_face_connectivity = mesh->connectivity().edgeToFaceMatrix(); + auto face_to_node_connectivity = mesh->connectivity().faceToNodeMatrix(); + + FaceValuePerCell<R3> face_normal_per_cell(mesh->connectivity()); + face_normal_per_cell.fill(zero); + EdgeValuePerCell<R3> edge_normal_per_cell(mesh->connectivity()); + edge_normal_per_cell.fill(zero); + CellValue<double> tabErrVolCjr(mesh->connectivity()); + CellValue<double> tabErrVolCjf(mesh->connectivity()); + CellValue<double> tabErrVolCje(mesh->connectivity()); + tabErrVolCjr.fill(0.); + tabErrVolCjf.fill(0.); + tabErrVolCje.fill(0.); + + CellValue<double> tabErrStokesCjr(mesh->connectivity()); + CellValue<double> tabErrStokesCjf(mesh->connectivity()); + CellValue<double> tabErrStokesCje(mesh->connectivity()); + tabErrStokesCjr.fill(0.); + tabErrStokesCjf.fill(0.); + tabErrStokesCje.fill(0.); + + NodeValue<double> tabErrConservation_r_Cjr(mesh->connectivity()); + FaceValue<double> tabErrConservation_f_Cjf(mesh->connectivity()); + EdgeValue<double> tabErrConservation_e_Cje(mesh->connectivity()); + tabErrConservation_r_Cjr.fill(0.); + tabErrConservation_f_Cjf.fill(0.); + tabErrConservation_e_Cje.fill(0.); + + parallel_for(mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + + // ******************************** + // Travail sur les nodes + // ******************************** + + auto cell_nodes = cell_to_node_connectivity[cell_id]; + double SumCjrXr=0; + R3 SumCjr=R3{0,0,0}; + for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { + const NodeId node_id = cell_nodes[i_node]; + SumCjrXr+=dot(Cjr(cell_id,i_node),xr[node_id]); + SumCjr+=Cjr(cell_id,i_node); + } + SumCjrXr/=3.; + tabErrVolCjr[cell_id]=fabs(Vj[cell_id]-SumCjrXr); + tabErrStokesCjr[cell_id]=l2Norm(SumCjr); + + // ******************************** + // Travail sur les faces + // ******************************** + + auto cell_faces = cell_to_face_connectivity[cell_id]; + const auto& face_is_reversed = cell_face_is_reversed.itemArray(cell_id); + + double SumCjrXf=0; + R3 SumCjf=R3{0,0,0}; + double SumCjrXf_mesh=0; + R3 SumCjf_mesh=R3{0,0,0}; + for (size_t i_face = 0; i_face < cell_faces.size(); ++i_face) { + const FaceId face_id = cell_faces[i_face]; + SumCjrXf_mesh+=dot(Cjf(cell_id,i_face),xl[face_id]); + SumCjf_mesh+=Cjf(cell_id,i_face); + + if (face_is_reversed[i_face]) + { + face_normal_per_cell[cell_id][i_face]=-Nl[face_id]; + SumCjrXf-=dot(Nl[face_id],xl[face_id]); + SumCjf-=Nl[face_id]; + } + else + { + face_normal_per_cell[cell_id][i_face]=Nl[face_id]; + SumCjrXf+=dot(Nl[face_id],xl[face_id]); + SumCjf+=Nl[face_id]; + } + } + SumCjrXf/=3.; + SumCjrXf_mesh/=3.; + tabErrVolCjf[cell_id]=fabs(Vj[cell_id]-SumCjrXf); + tabErrStokesCjf[cell_id]=l2Norm(SumCjf); + + // ******************************** + // Travail sur les edges + // ******************************** + //auto cell_faces = cell_to_face_connectivity[cell_id]; + //const auto& face_is_reversed = cell_face_is_reversed.itemArray(cell_id); + //const auto& cell_face_is_reversed = mesh->connectivity().cellFaceIsReversed(); + + auto cell_edges = cell_to_edge_connectivity[cell_id]; + double SumCjrXe=0; + R3 SumCje=zero; + double SumCjrXe_mesh=0; + R3 SumCje_mesh=zero; + + for (size_t i_edge = 0; i_edge < cell_edges.size(); ++i_edge) { + const EdgeId edge_id = cell_edges[i_edge]; + + SumCjrXe_mesh+=dot(Cje(cell_id,i_edge),xe[edge_id]); + SumCje_mesh+=Cje(cell_id,i_edge); + + auto edges_faces = edge_to_face_connectivity[edge_id]; + //auto cell_faces = cell_to_face_connectivity[edge_id]; + auto edges_nodes = edge_to_node_connectivity[edge_id]; + + const NodeId& node0_id= edges_nodes[0]; + const NodeId& node1_id= edges_nodes[1]; + + int nbFacEdge=0; + // On ne garde que si les 2 faces qui sont dans la maille + for (size_t i_face = 0; i_face < edges_faces.size(); ++i_face) { + const FaceId face_id = edges_faces[i_face]; + + for (size_t i_face_cell = 0; i_face_cell < cell_faces.size(); ++i_face_cell) { + const FaceId face_id_cell = cell_faces[i_face_cell]; + + // La face autour de l arete appartient à la maille courante : On peut faire le calcul avec la face + if (face_id_cell==face_id) + { + + double sign = (cell_face_is_reversed(cell_id, i_face_cell)) ? -1 : 1; + + const auto& face_nodes = face_to_node_connectivity[face_id_cell]; + + for (size_t rl = 0; rl < face_nodes.size(); ++rl) { + if (node0_id==face_nodes[rl] or node1_id==face_nodes[rl]) + edge_normal_per_cell(cell_id,i_edge)+=.5*sign*Nlr(face_id_cell,rl); + } + + ++nbFacEdge; + break; + } + } + } + + if (nbFacEdge!=2) + { + exit(1); + } + + R3 Cje_l=edge_normal_per_cell[cell_id][i_edge]; + //R3 Cje_l=Cje(cell_id,i_edge);//edge_normal_per_cell[cell_id][i_edge]; + + SumCjrXe+=dot(Cje_l,xe[edge_id]); + SumCje+=Cje_l; + } + SumCjrXe/=3.; + SumCjrXe_mesh/=3.; + + tabErrVolCje[cell_id]=fabs(Vj[cell_id]-SumCjrXe); + tabErrStokesCje[cell_id]=l2Norm(SumCje); + + }); + + auto node_to_cell_connectivity = mesh->connectivity().nodeToCellMatrix(); + auto face_to_cell_connectivity = mesh->connectivity().faceToCellMatrix(); + auto edge_to_cell_connectivity = mesh->connectivity().edgeToCellMatrix(); + + auto is_boundary_node = mesh->connectivity().isBoundaryNode(); + auto is_boundary_face = mesh->connectivity().isBoundaryFace(); + auto is_boundary_edge = mesh->connectivity().isBoundaryEdge(); + + parallel_for(mesh->numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) + { + R3 SumCjr=R3{0,0,0}; + if (not is_boundary_node[node_id]) + { + + for (size_t i_node = 0; i_node < node_to_cell_connectivity[node_id].size(); ++i_node) { + const CellId cell_id= node_to_cell_connectivity[node_id][i_node]; + + + for (size_t i_node_cell = 0; i_node_cell < cell_to_node_connectivity[cell_id].size(); ++i_node_cell) { + const NodeId node_cell_id = cell_to_node_connectivity[cell_id][i_node_cell]; + if (node_id==node_cell_id) + { + SumCjr+=Cjr(cell_id,i_node_cell); + break; + } + } + } + } + tabErrConservation_r_Cjr[node_id]=l2Norm(SumCjr); + }); + + parallel_for(mesh->numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) { + R3 SumCjf=zero; + if (not is_boundary_face[face_id]) + { + for (size_t i_face = 0; i_face < face_to_cell_connectivity[face_id].size(); ++i_face) { + const CellId cell_id= face_to_cell_connectivity[face_id][i_face]; + + for (size_t i_face_cell = 0; i_face_cell < cell_to_face_connectivity[cell_id].size(); ++i_face_cell) { + const FaceId face_cell_id = cell_to_face_connectivity[cell_id][i_face_cell]; + if (face_id==face_cell_id) + { + SumCjf+=face_normal_per_cell[cell_id][i_face_cell]; + break; + } + } + } + } + tabErrConservation_f_Cjf[face_id]=l2Norm(SumCjf)+1e-13;//R3(1e-13,1e-56,1e-34}; + }); + + parallel_for(mesh->numberOfEdges(), PUGS_LAMBDA(const EdgeId edge_id) { + R3 SumCje=zero; + + if (not is_boundary_edge[edge_id]) + { + for (size_t i_edge = 0; i_edge < edge_to_cell_connectivity[edge_id].size(); ++i_edge) { + const CellId cell_id= edge_to_cell_connectivity[edge_id][i_edge]; + + for (size_t i_edge_cell = 0; i_edge_cell < cell_to_edge_connectivity[cell_id].size(); ++i_edge_cell) { + const EdgeId edge_cell_id = cell_to_edge_connectivity[cell_id][i_edge_cell]; + if (edge_id==edge_cell_id) + { + SumCje+=edge_normal_per_cell[cell_id][i_edge_cell]; + //SumCje+=Cje(cell_id,i_edge_cell);//edge_normal_per_cell[cell_id][i_edge_cell]; + break; + } + } + } + } + tabErrConservation_e_Cje[edge_id]=l2Norm(SumCje); + }); + //std::clog << " Max Cje et tab " << max(dif_edge_normal_per_cell) << "\n" ; + std::clog << " Max Error (Stokes/Vol/Cons) Cjr " << max(tabErrStokesCjr) << "/" << max(tabErrVolCjr) << "/" << max(tabErrConservation_r_Cjr) << " Max Error (Stokes/Vol/Cons) Cjf " << max(tabErrStokesCjf) << "/" << max(tabErrVolCjf) << "/" << max(tabErrConservation_f_Cjf) << " Max Error (Stokes/Vol/Cons) Cje "<< max(tabErrStokesCje) << "/" << max(tabErrVolCje) << "/"<< max(tabErrConservation_e_Cje) << "\n"; + + //1.00868e-16/1.73472e-18/2.399e-17 Max Error (Stokes/Vol/Cons) Cjf 9.10193e-17/1.82146e-17/2.22507e-308 Max Error (Stokes/Vol/Cons) Cje + + } + } +} -- GitLab