From f4218dce4355a2470e89851ab79906a6a8f2e60c Mon Sep 17 00:00:00 2001 From: Axelle <axelle.drouard@orange.fr> Date: Tue, 3 Dec 2024 09:35:33 +0100 Subject: [PATCH] Set up second order in space --- src/language/modules/SchemeModule.cpp | 39 + src/scheme/CMakeLists.txt | 1 + src/scheme/EulerKineticSolverMultiDOrder2.cpp | 1239 +++++++++++++++++ src/scheme/EulerKineticSolverMultiDOrder2.hpp | 25 + 4 files changed, 1304 insertions(+) create mode 100644 src/scheme/EulerKineticSolverMultiDOrder2.cpp create mode 100644 src/scheme/EulerKineticSolverMultiDOrder2.hpp diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index ef3e5dbc9..e1729dace 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -44,6 +44,7 @@ #include <scheme/EulerKineticSolverMoodFD.hpp> #include <scheme/EulerKineticSolverMoodFV.hpp> #include <scheme/EulerKineticSolverMultiD.hpp> +#include <scheme/EulerKineticSolverMultiDOrder2.hpp> #include <scheme/EulerKineticSolverOneFluxMood.hpp> #include <scheme/EulerKineticSolverThirdOrderFD.hpp> #include <scheme/EulerKineticSolverThirdOrderFV.hpp> @@ -1041,6 +1042,44 @@ SchemeModule::SchemeModule() )); + this->_addBuiltinFunction("euler_kinetic_MultiD_Order2", + std::function( + + [](const double& dt, const double& gamma, const std::vector<TinyVector<2>>& lambda_vector, + const double& eps, const size_t& SpaceOrder, const size_t& TimeOrder, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_u, + const std::shared_ptr<const DiscreteFunctionVariant>& F_E, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list) -> std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + return eulerKineticSolverMultiDOrder2(dt, gamma, lambda_vector, eps, SpaceOrder, + TimeOrder, F_rho, F_rho_u, F_E, + bc_descriptor_list); + } + + )); + + this->_addBuiltinFunction("euler_kinetic_MultiD_Order2", + std::function( + + [](const double& dt, const double& gamma, const std::vector<TinyVector<3>>& lambda_vector, + const double& eps, const size_t& SpaceOrder, const size_t& TimeOrder, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_u, + const std::shared_ptr<const DiscreteFunctionVariant>& F_E, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list) -> std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + return eulerKineticSolverMultiDOrder2(dt, gamma, lambda_vector, eps, SpaceOrder, + TimeOrder, F_rho, F_rho_u, F_E, + bc_descriptor_list); + } + + )); + this->_addBuiltinFunction("euler_kinetic_first_order_FV", std::function( diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt index e243b5249..ee7b44b7d 100644 --- a/src/scheme/CMakeLists.txt +++ b/src/scheme/CMakeLists.txt @@ -22,6 +22,7 @@ add_library( EulerKineticSolverMoodFD.cpp EulerKineticSolverMoodFV.cpp EulerKineticSolverMultiD.cpp + EulerKineticSolverMultiDOrder2.cpp EulerKineticSolverThirdOrderMoodFV.cpp EulerKineticSolverThirdOrderMoodFD.cpp EulerKineticSolverThirdOrderFV.cpp diff --git a/src/scheme/EulerKineticSolverMultiDOrder2.cpp b/src/scheme/EulerKineticSolverMultiDOrder2.cpp new file mode 100644 index 000000000..8fade4f03 --- /dev/null +++ b/src/scheme/EulerKineticSolverMultiDOrder2.cpp @@ -0,0 +1,1239 @@ +#include <scheme/EulerKineticSolverMultiDOrder2.hpp> + +#include <language/utils/EvaluateAtPoints.hpp> +#include <language/utils/InterpolateItemArray.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshFaceBoundary.hpp> +#include <mesh/MeshFlatFaceBoundary.hpp> +#include <mesh/MeshFlatNodeBoundary.hpp> +#include <mesh/MeshNodeBoundary.hpp> +#include <mesh/MeshVariant.hpp> +#include <scheme/DiscreteFunctionDPkVariant.hpp> +#include <scheme/DiscreteFunctionDPkVector.hpp> +#include <scheme/DiscreteFunctionDescriptorP0Vector.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IDiscreteFunctionDescriptor.hpp> +#include <scheme/InflowListBoundaryConditionDescriptor.hpp> +#include <scheme/OutflowBoundaryConditionDescriptor.hpp> +#include <scheme/PolynomialReconstruction.hpp> +#include <scheme/PolynomialReconstructionDescriptor.hpp> +#include <scheme/SymmetryBoundaryConditionDescriptor.hpp> +#include <scheme/WallBoundaryConditionDescriptor.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/LineTransformation.hpp> +#include <tuple> + +template <MeshConcept MeshType> +class EulerKineticSolverMultiDOrder2 +{ + private: + constexpr static size_t Dimension = MeshType::Dimension; + using Rd = TinyVector<Dimension>; + + class SymmetryBoundaryCondition; + class WallBoundaryCondition; + class InflowListBoundaryCondition; + class OutflowBoundaryCondition; + + using BoundaryCondition = std:: + variant<SymmetryBoundaryCondition, WallBoundaryCondition, InflowListBoundaryCondition, OutflowBoundaryCondition>; + using BoundaryConditionList = std::vector<BoundaryCondition>; + + const double m_dt; + const double m_eps; + const std::vector<TinyVector<Dimension>>& m_lambda_vector; + const size_t m_SpaceOrder; + const size_t m_TimeOrder; + const CellArray<const double> m_Fn_rho; + const CellArray<const TinyVector<Dimension>> m_Fn_rho_u; + const CellArray<const double> m_Fn_rho_E; + const double m_gamma; + const std::shared_ptr<const MeshType> p_mesh; + const MeshType& m_mesh; + const CellValue<const double> m_Vj = MeshDataManager::instance().getMeshData(m_mesh).Vj(); + + const FaceValue<const TinyVector<Dimension>> nl = MeshDataManager::instance().getMeshData(m_mesh).nl(); + + CellValue<const double> m_inv_Vj; + const CellValue<const TinyVector<Dimension>> m_xj = MeshDataManager::instance().getMeshData(m_mesh).xj(); + const NodeValue<const TinyVector<Dimension>> m_xr = m_mesh.xr(); + const FaceValue<const TinyVector<Dimension>> m_xl = MeshDataManager::instance().getMeshData(m_mesh).xl(); + + 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()), + getMeshFlatFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::wall: { + bc_list.emplace_back(WallBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFaceBoundary(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()); + } + auto node_boundary = getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + Array<size_t> is_boundary_cell{p_mesh->numberOfCells()}; + + is_boundary_cell.fill(0); + + auto node_to_cell_matrix = m_mesh.connectivity().nodeToCellMatrix(); + + auto node_list = node_boundary.nodeList(); + for (size_t i_node = 0; i_node < node_list.size(); ++i_node) { + auto cell_list = node_to_cell_matrix[node_list[i_node]]; + for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) { + const CellId cell_id = cell_list[i_cell]; + is_boundary_cell[cell_id] = 1; + } + } + + size_t nb_boundary_cells = sum(is_boundary_cell); + + Array<CellId> cell_list{nb_boundary_cells}; + + size_t index = 0; + for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) { + if (is_boundary_cell[cell_id]) { + cell_list[index++] = cell_id; + } + } + auto xj = MeshDataManager::instance().getMeshData(m_mesh).xj(); + + Table<const double> cell_array_list = + InterpolateItemArray<double(Rd)>::template interpolate<ItemType::cell>(inflow_list_bc_descriptor + .functionSymbolIdList(), + xj, cell_list); + bc_list.emplace_back(InflowListBoundaryCondition(cell_array_list, cell_list)); + break; + } + case IBoundaryConditionDescriptor::Type::outflow: { + bc_list.emplace_back(OutflowBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()), + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + 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; + } + + public: + CellArray<TinyVector<MeshType::Dimension>> + getA(const DiscreteFunctionP0<const double>& rho, + const DiscreteFunctionP0<const double>& rho_u1, + const DiscreteFunctionP0<const double>& rho_u2, + const DiscreteFunctionP0<const double>& rho_E) const + { + // const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); + + CellArray<TinyVector<Dimension>> vec_A{m_mesh.connectivity(), 4}; + + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + double rho_e = rho_E[cell_id] - 0.5 * (1. / rho[cell_id]) * + (rho_u1[cell_id] * rho_u1[cell_id] + rho_u2[cell_id] * rho_u2[cell_id]); + double p = (m_gamma - 1) * rho_e; + + vec_A[cell_id][0][0] = rho_u1[cell_id]; + vec_A[cell_id][1][0] = rho_u1[cell_id] * rho_u1[cell_id] / rho[cell_id] + p; + vec_A[cell_id][2][0] = rho_u1[cell_id] * rho_u2[cell_id] / rho[cell_id]; + vec_A[cell_id][3][0] = (rho_E[cell_id] + p) * rho_u1[cell_id] / rho[cell_id]; + + vec_A[cell_id][0][1] = rho_u2[cell_id]; + vec_A[cell_id][1][1] = rho_u1[cell_id] * rho_u2[cell_id] / rho[cell_id]; + vec_A[cell_id][2][1] = rho_u2[cell_id] * rho_u2[cell_id] / rho[cell_id] + p; + vec_A[cell_id][3][1] = (rho_E[cell_id] + p) * rho_u2[cell_id] / rho[cell_id]; + }); + return vec_A; + } + + const CellValue<const TinyVector<Dimension>> + getA_rho(const CellValue<const TinyVector<Dimension>>& rho_u) const + { + return rho_u; + } + + const CellValue<const TinyMatrix<Dimension>> + getA_rho_u(const CellValue<const double>& rho, + const CellValue<const TinyVector<Dimension>>& rho_u, + const CellValue<const double>& rho_E) const + { + CellValue<TinyMatrix<Dimension>> vec_A{m_mesh.connectivity()}; + const TinyMatrix<Dimension> I = identity; + CellValue<double> rho_e{m_mesh.connectivity()}; + CellValue<double> p{m_mesh.connectivity()}; + + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + rho_e[cell_id] = rho_E[cell_id] - 0.5 * (1. / rho[cell_id]) * dot(rho_u[cell_id], rho_u[cell_id]); + p[cell_id] = (m_gamma - 1) * rho_e[cell_id]; + + vec_A[cell_id] = 1. / rho[cell_id] * tensorProduct(rho_u[cell_id], rho_u[cell_id]) + p[cell_id] * I; + }); + + return vec_A; + } + + const CellValue<const TinyVector<Dimension>> + getA_rho_E(const CellValue<const double>& rho, + const CellValue<const TinyVector<Dimension>>& rho_u, + const CellValue<const double>& rho_E) const + { + CellValue<TinyVector<Dimension>> vec_A{m_mesh.connectivity()}; + + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + double rho_e = rho_E[cell_id] - 0.5 * (1. / rho[cell_id]) * dot(rho_u[cell_id], rho_u[cell_id]); + double p = (m_gamma - 1) * rho_e; + + vec_A[cell_id] = (rho_E[cell_id] + p) / rho[cell_id] * rho_u[cell_id]; + }); + + return vec_A; + } + + const CellArray<const double> + compute_scalar_M(const CellValue<const double>& u, const CellValue<const TinyVector<Dimension>>& A_u) + { + const size_t nb_waves = m_lambda_vector.size(); + CellArray<double> M{p_mesh->connectivity(), nb_waves}; + TinyVector<Dimension> inv_S = zero; + for (size_t d = 0; d < MeshType::Dimension; ++d) { + for (size_t i = 0; i < nb_waves; ++i) { + inv_S[d] += m_lambda_vector[i][d] * m_lambda_vector[i][d]; + } + inv_S[d] = 1. / inv_S[d]; + } + + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + for (size_t i = 0; i < nb_waves; ++i) { + M[cell_id][i] = (1. / nb_waves) * u[cell_id]; + + for (size_t d = 0; d < Dimension; ++d) { + M[cell_id][i] += inv_S[d] * m_lambda_vector[i][d] * A_u[cell_id][d]; + } + } + }); + + return M; + } + + const CellArray<const TinyVector<Dimension>> + compute_vector_M(const CellValue<const TinyVector<Dimension>>& u, const CellValue<const TinyMatrix<Dimension>>& A_u) + { + const size_t nb_waves = m_lambda_vector.size(); + CellArray<TinyVector<Dimension>> M{p_mesh->connectivity(), nb_waves}; + TinyVector<MeshType::Dimension> inv_S = zero; + for (size_t d = 0; d < MeshType::Dimension; ++d) { + for (size_t i = 0; i < nb_waves; ++i) { + inv_S[d] += m_lambda_vector[i][d] * m_lambda_vector[i][d]; + } + inv_S[d] = 1. / inv_S[d]; + } + + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + M[cell_id][i_wave] = 1. / nb_waves * u[cell_id]; + for (size_t d1 = 0; d1 < Dimension; ++d1) { + for (size_t d2 = 0; d2 < Dimension; ++d2) { + M[cell_id][i_wave][d1] += inv_S[d2] * m_lambda_vector[i_wave][d2] * A_u[cell_id](d2, d1); + } + } + } + }); + return M; + } + + template <typename T> + const CellValue<const T> + compute_PFnp1(const CellArray<const T>& Fn, const CellArray<const T>& deltaLFn) + + { + CellValue<T> PFnp1{p_mesh->connectivity()}; + + if constexpr (is_tiny_vector_v<T>) { + PFnp1.fill(zero); + } else { + PFnp1.fill(0.); + } + + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double inv_Vj = m_inv_Vj[cell_id]; + const double dt_over_Vj = m_dt * inv_Vj; + + for (size_t i_wave = 0; i_wave < m_lambda_vector.size(); ++i_wave) { + PFnp1[cell_id] += Fn[cell_id][i_wave] - dt_over_Vj * deltaLFn[cell_id][i_wave]; + } + }); + + return PFnp1; + } + + template <typename T> + const CellValue<const T> + compute_PFn(const CellArray<const T>& F) + { + const size_t nb_waves = m_lambda_vector.size(); + CellValue<T> PFn{p_mesh->connectivity()}; + if constexpr (is_tiny_vector_v<T>) { + PFn.fill(zero); + } else { + PFn.fill(0.); + } + + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + for (size_t i = 0; i < nb_waves; ++i) { + PFn[cell_id] += F[cell_id][i]; + } + }); + return PFn; + } + + template <typename T> + NodeArray<T> + compute_Flux1(CellArray<T>& Fn) + { + if constexpr (Dimension > 1) { + const NodeValuePerCell<const TinyVector<Dimension>> njr = MeshDataManager::instance().getMeshData(m_mesh).njr(); + const size_t nb_waves = m_lambda_vector.size(); + NodeArray<T> Fr(m_mesh.connectivity(), nb_waves); + const auto& node_local_numbers_in_their_cells = p_mesh->connectivity().nodeLocalNumbersInTheirCells(); + const auto& node_to_cell_matrix = p_mesh->connectivity().nodeToCellMatrix(); + + if constexpr (is_tiny_vector_v<T>) { + Fr.fill(zero); + } else { + Fr.fill(0.); + } + + parallel_for( + p_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { + const auto& node_local_number_in_its_cell = node_local_numbers_in_their_cells.itemArray(node_id); + const auto& node_to_cell = node_to_cell_matrix[node_id]; + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + double sum_li_njr = 0; + + for (size_t i_cell = 0; i_cell < node_to_cell.size(); ++i_cell) { + const CellId cell_id = node_to_cell[i_cell]; + const unsigned int i_node = node_local_number_in_its_cell[i_cell]; + + double li_njr = dot(m_lambda_vector[i_wave], njr(cell_id, i_node)); + if (li_njr > 0) { + Fr[node_id][i_wave] += Fn[cell_id][i_wave] * li_njr; + sum_li_njr += li_njr; + } + } + if (sum_li_njr != 0) { + Fr[node_id][i_wave] /= sum_li_njr; + } + } + }); + + return Fr; + } else { + throw NormalError("Glace not defined in 1d"); + } + } + + template <typename T> + FaceArrayPerNode<T> + compute_Flux1_eucchlyd(CellArray<T> Fn) + { + if constexpr (Dimension > 1) { + const NodeValuePerFace<const TinyVector<Dimension>> nlr = MeshDataManager::instance().getMeshData(m_mesh).nlr(); + const size_t nb_waves = m_lambda_vector.size(); + FaceArrayPerNode<T> Flr(m_mesh.connectivity(), nb_waves); + const auto& node_local_numbers_in_their_faces = p_mesh->connectivity().nodeLocalNumbersInTheirFaces(); + const auto& face_local_numbers_in_their_cells = p_mesh->connectivity().faceLocalNumbersInTheirCells(); + const auto& node_to_face_matrix = p_mesh->connectivity().nodeToFaceMatrix(); + const auto& face_to_cell_matrix = p_mesh->connectivity().faceToCellMatrix(); + const auto& face_cell_is_reversed = p_mesh->connectivity().cellFaceIsReversed(); + + if constexpr (is_tiny_vector_v<T>) { + Flr.fill(zero); + } else { + Flr.fill(0.); + } + + parallel_for( + p_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { + const auto& node_local_number_in_its_face = node_local_numbers_in_their_faces.itemArray(node_id); + const auto& node_to_face = node_to_face_matrix[node_id]; + + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + for (size_t i_face = 0; i_face < node_to_face.size(); ++i_face) { + const FaceId face_id = node_to_face[i_face]; + const auto& face_local_number_in_its_cell = face_local_numbers_in_their_cells.itemArray(face_id); + const auto& face_to_cell = face_to_cell_matrix[face_id]; + const size_t i_node_face = node_local_number_in_its_face[i_face]; + + double sum = 0; + + for (size_t i_cell = 0; i_cell < face_to_cell.size(); ++i_cell) { + const CellId cell_id = face_to_cell[i_cell]; + const size_t i_face_cell = face_local_number_in_its_cell[i_cell]; + + TinyVector<Dimension> n_face = nlr(face_id, i_node_face); + const double sign = face_cell_is_reversed(cell_id, i_face_cell) ? -1 : 1; + + double li_nlr = sign * dot(m_lambda_vector[i_wave], n_face); + + if (li_nlr > 0) { + Flr[node_id][i_face][i_wave] += Fn[cell_id][i_wave] * li_nlr; + sum += li_nlr; + } + } + if (sum != 0) { + Flr[node_id][i_face][i_wave] /= sum; + } + } + } + }); + + return Flr; + } else { + throw NormalError("Eucclhyd not defined in 1d"); + } + } + + template <typename T> + FaceArray<T> + compute_Flux1_face(const DiscreteFunctionDPkVector<Dimension, const T> DPk_Fn) + { + const size_t nb_waves = m_lambda_vector.size(); + FaceArray<T> Fl(m_mesh.connectivity(), nb_waves); + const auto& face_local_numbers_in_their_cells = p_mesh->connectivity().faceLocalNumbersInTheirCells(); + const auto& face_to_cell_matrix = p_mesh->connectivity().faceToCellMatrix(); + const auto& face_cell_is_reversed = p_mesh->connectivity().cellFaceIsReversed(); + + if constexpr (is_tiny_vector_v<T>) { + Fl.fill(zero); + } else { + Fl.fill(0.); + } + + parallel_for( + p_mesh->numberOfFaces(), PUGS_LAMBDA(FaceId face_id) { + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + const auto& face_local_number_in_its_cell = face_local_numbers_in_their_cells.itemArray(face_id); + const auto& face_to_cell = face_to_cell_matrix[face_id]; + + for (size_t i_cell = 0; i_cell < face_to_cell.size(); ++i_cell) { + const CellId cell_id = face_to_cell[i_cell]; + const size_t i_face_cell = face_local_number_in_its_cell[i_cell]; + + TinyVector<Dimension> n_face = nl[face_id]; + const double sign = face_cell_is_reversed(cell_id, i_face_cell) ? -1 : 1; + + double li_nl = sign * dot(m_lambda_vector[i_wave], n_face); + + if (li_nl > 0) { + Fl[face_id][i_wave] += DPk_Fn(cell_id, i_wave)(m_xl[face_id]); + } + } + } + }); + + return Fl; + } + + void + apply_bc(FaceArray<double> Fl_rho, + FaceArray<TinyVector<Dimension>> Fl_rho_u, + FaceArray<double> Fl_rho_E, + const CellValue<const double> rho, + const CellValue<const TinyVector<Dimension>> rho_u, + const CellValue<const double> rho_E, + const CellArray<const double> Fn_rho, + const CellArray<const TinyVector<Dimension>> Fn_rho_u, + const CellArray<const double> Fn_rho_E, + const BoundaryConditionList& bc_list) + { + const size_t nb_waves = m_lambda_vector.size(); + const auto& face_local_numbers_in_their_cells = p_mesh->connectivity().faceLocalNumbersInTheirCells(); + const auto& face_to_cell_matrix = p_mesh->connectivity().faceToCellMatrix(); + const auto& face_cell_is_reversed = p_mesh->connectivity().cellFaceIsReversed(); + + TinyVector<MeshType::Dimension> inv_S = zero; + for (size_t d = 0; d < MeshType::Dimension; ++d) { + for (size_t i = 0; i < nb_waves; ++i) { + inv_S[d] += m_lambda_vector[i][d] * m_lambda_vector[i][d]; + } + inv_S[d] = 1. / inv_S[d]; + } + + for (auto&& bc_v : bc_list) { + std::visit( + [=, this](auto&& bc) { + using BCType = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<BCType, SymmetryBoundaryCondition>) { + auto face_list = bc.faceList(); + auto n = bc.outgoingNormal(); + auto nxn = tensorProduct(n, n); + TinyMatrix<Dimension> I = identity; + auto txt = I - nxn; + + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + const auto& face_local_number_in_its_cell = face_local_numbers_in_their_cells.itemArray(face_id); + const auto& face_to_cell = face_to_cell_matrix[face_id]; + + for (size_t i_cell = 0; i_cell < face_to_cell.size(); ++i_cell) { + const CellId cell_id = face_to_cell[i_cell]; + const size_t i_face_cell = face_local_number_in_its_cell[i_cell]; + + TinyVector<Dimension> n_face = nl[face_id]; + const double sign = face_cell_is_reversed(cell_id, i_face_cell) ? -1 : 1; + + double li_nl = sign * dot(m_lambda_vector[i_wave], n_face); + if (li_nl < 0) { + double rhoj_prime = rho[cell_id]; + TinyVector<Dimension> rho_uj = rho_u[cell_id]; + TinyVector<Dimension> rho_uj_prime = txt * rho_uj - nxn * rho_uj; + double rho_Ej_prime = rho_E[cell_id]; + + double rho_e = rho_E[cell_id] - 0.5 * (1. / rho[cell_id]) * dot(rho_u[cell_id], rho_u[cell_id]); + double p = (m_gamma - 1) * rho_e; + + TinyVector<Dimension> A_rho_prime = rho_uj_prime; + TinyMatrix<Dimension> A_rho_u_prime = + 1. / rhoj_prime * tensorProduct(rho_uj_prime, rho_uj_prime) + p * I; + TinyVector<Dimension> A_rho_E_prime = (rho_Ej_prime + p) / rhoj_prime * rho_uj_prime; + + double Fn_rho_prime = rhoj_prime / nb_waves; + TinyVector<Dimension> Fn_rho_u_prime = 1. / nb_waves * rho_uj_prime; + double Fn_rho_E_prime = rho_Ej_prime / nb_waves; + + for (size_t d1 = 0; d1 < Dimension; ++d1) { + Fn_rho_prime += inv_S[d1] * m_lambda_vector[i_wave][d1] * A_rho_prime[d1]; + for (size_t d2 = 0; d2 < Dimension; ++d2) { + Fn_rho_u_prime[d1] += inv_S[d2] * m_lambda_vector[i_wave][d2] * A_rho_u_prime(d2, d1); + } + Fn_rho_E_prime += inv_S[d1] * m_lambda_vector[i_wave][d1] * A_rho_E_prime[d1]; + } + + Fl_rho[face_id][i_wave] += Fn_rho_prime; + Fl_rho_u[face_id][i_wave] += Fn_rho_u_prime; + Fl_rho_E[face_id][i_wave] += Fn_rho_E_prime; + } + } + } + } + } else if constexpr (std::is_same_v<BCType, WallBoundaryCondition>) { + auto face_list = bc.faceList(); + + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + const auto& face_local_number_in_its_cell = face_local_numbers_in_their_cells.itemArray(face_id); + const auto& face_to_cell = face_to_cell_matrix[face_id]; + + for (size_t i_cell = 0; i_cell < face_to_cell.size(); ++i_cell) { + const CellId cell_id = face_to_cell[i_cell]; + const size_t i_face_cell = face_local_number_in_its_cell[i_cell]; + const double sign = face_cell_is_reversed(cell_id, i_face_cell) ? -1 : 1; + + auto n = sign * nl[face_id]; + auto nxn = tensorProduct(n, n); + TinyMatrix<Dimension> I = identity; + auto txt = I - nxn; + + double li_nl = dot(m_lambda_vector[i_wave], n); + if (li_nl < 0) { + double rhoj_prime = rho[cell_id]; + TinyVector<Dimension> rho_uj = rho_u[cell_id]; + TinyVector<Dimension> rho_uj_prime = txt * rho_uj - nxn * rho_uj; + double rho_Ej_prime = rho_E[cell_id]; + + double rho_e = rho_E[cell_id] - 0.5 * (1. / rho[cell_id]) * dot(rho_u[cell_id], rho_u[cell_id]); + double p = (m_gamma - 1) * rho_e; + + TinyVector<Dimension> A_rho_prime = rho_uj_prime; + TinyMatrix<Dimension> A_rho_u_prime = + 1. / rhoj_prime * tensorProduct(rho_uj_prime, rho_uj_prime) + p * I; + TinyVector<Dimension> A_rho_E_prime = (rho_Ej_prime + p) / rhoj_prime * rho_uj_prime; + + double Fn_rho_prime = rhoj_prime / nb_waves; + TinyVector<Dimension> Fn_rho_u_prime = 1. / nb_waves * rho_uj_prime; + double Fn_rho_E_prime = rho_Ej_prime / nb_waves; + + for (size_t d1 = 0; d1 < Dimension; ++d1) { + Fn_rho_prime += inv_S[d1] * m_lambda_vector[i_wave][d1] * A_rho_prime[d1]; + for (size_t d2 = 0; d2 < Dimension; ++d2) { + Fn_rho_u_prime[d1] += inv_S[d2] * m_lambda_vector[i_wave][d2] * A_rho_u_prime(d2, d1); + } + Fn_rho_E_prime += inv_S[d1] * m_lambda_vector[i_wave][d1] * A_rho_E_prime[d1]; + } + + Fl_rho[face_id][i_wave] += Fn_rho_prime; + Fl_rho_u[face_id][i_wave] += Fn_rho_u_prime; + Fl_rho_E[face_id][i_wave] += Fn_rho_E_prime; + } + } + } + } + } else if constexpr (std::is_same_v<BCType, OutflowBoundaryCondition>) { + auto face_list = bc.faceList(); + + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + const auto& face_local_number_in_its_cell = face_local_numbers_in_their_cells.itemArray(face_id); + const auto& face_to_cell = face_to_cell_matrix[face_id]; + + for (size_t i_cell = 0; i_cell < face_to_cell.size(); ++i_cell) { + const CellId cell_id = face_to_cell[i_cell]; + const size_t i_face_cell = face_local_number_in_its_cell[i_cell]; + const double sign = face_cell_is_reversed(cell_id, i_face_cell) ? -1 : 1; + + auto n = sign * nl[face_id]; + + double li_nl = dot(m_lambda_vector[i_wave], n); + if (li_nl < 0) { + Fl_rho[face_id][i_wave] += Fn_rho[cell_id][i_wave]; + Fl_rho_u[face_id][i_wave] += Fn_rho_u[cell_id][i_wave]; + Fl_rho_E[face_id][i_wave] += Fn_rho_E[cell_id][i_wave]; + } + } + } + } + } + }, + bc_v); + } + } + + DiscreteFunctionP0Vector<double> + compute_deltaLFn(NodeArray<double> Fr) + { + if constexpr (Dimension > 1) { + const NodeValuePerCell<const TinyVector<Dimension>> Cjr = MeshDataManager::instance().getMeshData(m_mesh).Cjr(); + const size_t nb_waves = m_lambda_vector.size(); + DiscreteFunctionP0Vector<double> deltaLFn(p_mesh, nb_waves); + + const auto& cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix(); + + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const auto& cell_to_node = cell_to_node_matrix[cell_id]; + + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + deltaLFn[cell_id][i_wave] = 0; + for (size_t i_node = 0; i_node < cell_to_node.size(); ++i_node) { + const NodeId node_id = cell_to_node[i_node]; + + double li_Cjr = dot(m_lambda_vector[i_wave], Cjr(cell_id, i_node)); + deltaLFn[cell_id][i_wave] += Fr[node_id][i_wave] * li_Cjr; + } + } + }); + return deltaLFn; + } else { + throw NormalError("Glace not defined in 1d"); + } + } + + DiscreteFunctionP0Vector<double> + compute_deltaLFn_eucclhyd(FaceArrayPerNode<double> Fr) + { + if constexpr (Dimension > 1) { + const size_t nb_waves = m_lambda_vector.size(); + DiscreteFunctionP0Vector<double> deltaLFn(p_mesh, nb_waves); + + const NodeValuePerFace<const TinyVector<Dimension>> Nlr = MeshDataManager::instance().getMeshData(m_mesh).Nlr(); + + const auto& cell_to_face_matrix = p_mesh->connectivity().cellToFaceMatrix(); + const auto& face_to_node_matrix = p_mesh->connectivity().faceToNodeMatrix(); + const auto& node_to_face_matrix = p_mesh->connectivity().nodeToFaceMatrix(); + const auto& face_cell_is_reversed = p_mesh->connectivity().cellFaceIsReversed(); + + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const auto& cell_to_face = cell_to_face_matrix[cell_id]; + + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + deltaLFn[cell_id][i_wave] = 0; + + for (size_t i_face_cell = 0; i_face_cell < cell_to_face.size(); ++i_face_cell) { + const FaceId face_id = cell_to_face[i_face_cell]; + const auto& face_to_node = face_to_node_matrix[face_id]; + + for (size_t i_node_face = 0; i_node_face < face_to_node.size(); ++i_node_face) { + const NodeId node_id = face_to_node[i_node_face]; + const auto& node_to_face = node_to_face_matrix[node_id]; + + auto local_face_number_in_node = [&](FaceId face_number) { + for (size_t i_face = 0; i_face < node_to_face.size(); ++i_face) { + if (face_number == node_to_face[i_face]) { + return i_face; + } + } + return std::numeric_limits<size_t>::max(); + }; + + const size_t i_face_node = local_face_number_in_node(face_id); + + const double sign = face_cell_is_reversed(cell_id, i_face_cell) ? -1 : 1; + + const double li_Nlr = sign * dot(m_lambda_vector[i_wave], Nlr(face_id, i_node_face)); + + deltaLFn[cell_id][i_wave] += Fr[node_id][i_face_node][i_wave] * li_Nlr; + } + } + } + }); + return deltaLFn; + } else { + throw NormalError("Eucclhyd not defined in 1d"); + } + } + + template <typename T> + CellArray<T> + compute_deltaLFn_face(FaceArray<T> Fl) + { + if constexpr (Dimension > 1) { + const FaceValue<const TinyVector<Dimension>> Nl = MeshDataManager::instance().getMeshData(m_mesh).Nl(); + const size_t nb_waves = m_lambda_vector.size(); + CellArray<T> deltaLFn(p_mesh->connectivity(), nb_waves); + + const auto& cell_to_face_matrix = p_mesh->connectivity().cellToFaceMatrix(); + const auto& face_cell_is_reversed = p_mesh->connectivity().cellFaceIsReversed(); + + if constexpr (is_tiny_vector_v<T>) { + deltaLFn.fill(zero); + } else { + deltaLFn.fill(0.); + } + + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const auto& cell_to_face = cell_to_face_matrix[cell_id]; + + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + for (size_t i_face_cell = 0; i_face_cell < cell_to_face.size(); ++i_face_cell) { + const FaceId face_id = cell_to_face[i_face_cell]; + + const double sign = face_cell_is_reversed(cell_id, i_face_cell) ? -1 : 1; + + const double li_Nl = sign * dot(m_lambda_vector[i_wave], Nl[face_id]); + + deltaLFn[cell_id][i_wave] += li_Nl * Fl[face_id][i_wave]; + } + } + }); + return deltaLFn; + } else { + throw NormalError("Nl in meaningless in 1d"); + } + } + + CellValue<bool> + getInflowBoundaryCells(const BoundaryConditionList& bc_list) + { + CellValue<bool> is_boundary_cell{p_mesh->connectivity()}; + + is_boundary_cell.fill(false); + + for (auto&& bc_v : bc_list) { + std::visit( + [=](auto&& bc) { + using BCType = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<BCType, InflowListBoundaryCondition>) { + auto cell_list = bc.cellList(); + for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) { + const CellId cell_id = cell_list[i_cell]; + is_boundary_cell[cell_id] = true; + } + } + }, + bc_v); + } + + return is_boundary_cell; + } + + std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply(const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) + { + BoundaryConditionList bc_list = this->_getBCList(m_mesh, bc_descriptor_list); + + const size_t nb_waves = m_lambda_vector.size(); + + CellValue<bool> is_inflow_boundary_cell = getInflowBoundaryCells(bc_list); + + const CellValue<double> rho_ex{p_mesh->connectivity()}; + const CellValue<TinyVector<Dimension>> rho_u_ex{p_mesh->connectivity()}; + const CellValue<double> rho_E_ex{p_mesh->connectivity()}; + + rho_ex.fill(1); // !! A modifier en ne parcourant que les bords + rho_u_ex.fill(zero); + rho_E_ex.fill(0); + + for (auto&& bc_v : bc_list) { + std::visit( + [=](auto&& bc) { + using BCType = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<BCType, InflowListBoundaryCondition>) { + auto cell_list = bc.cellList(); + auto cell_array_list = bc.cellArrayList(); + for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) { + const CellId cell_id = cell_list[i_cell]; + rho_ex[cell_id] = cell_array_list[i_cell][0]; + rho_u_ex[cell_id][0] = cell_array_list[i_cell][1]; + rho_u_ex[cell_id][1] = cell_array_list[i_cell][2]; + rho_E_ex[cell_id] = cell_array_list[i_cell][3]; + } + } + }, + bc_v); + } + + const CellValue<const TinyVector<Dimension>> A_rho_ex = getA_rho(rho_u_ex); + const CellValue<const TinyMatrix<Dimension>> A_rho_u_ex = getA_rho_u(rho_ex, rho_u_ex, rho_E_ex); + const CellValue<const TinyVector<Dimension>> A_rho_E_ex = getA_rho_E(rho_ex, rho_u_ex, rho_E_ex); + + const CellArray<const double> Fn_rho_ex = compute_scalar_M(rho_ex, A_rho_ex); + const CellArray<const TinyVector<Dimension>> Fn_rho_u_ex = compute_vector_M(rho_u_ex, A_rho_u_ex); + const CellArray<const double> Fn_rho_E_ex = compute_scalar_M(rho_E_ex, A_rho_E_ex); + + const CellArray<const double> Fn_rho = copy(m_Fn_rho); + const CellArray<const TinyVector<Dimension>> Fn_rho_u = copy(m_Fn_rho_u); + const CellArray<const double> Fn_rho_E = copy(m_Fn_rho_E); + + DiscreteFunctionP0Vector<double> Fnp1_rho(p_mesh, nb_waves); + DiscreteFunctionP0Vector<TinyVector<Dimension>> Fnp1_rho_u(p_mesh, nb_waves); + DiscreteFunctionP0Vector<double> Fnp1_rho_E(p_mesh, nb_waves); + + // Compute first order F + + const CellValue<const double> rho = compute_PFn<double>(Fn_rho); + const CellValue<const TinyVector<Dimension>> rho_u = compute_PFn<TinyVector<Dimension>>(Fn_rho_u); + const CellValue<const double> rho_E = compute_PFn<double>(Fn_rho_E); + + std::vector<std::shared_ptr<const IBoundaryDescriptor>> symmetry_boundary_descriptor_list; + // Reconstruction uniquement à l'intérieur donc pas utile + // for (auto&& bc_descriptor : bc_descriptor_list) { + // if (bc_descriptor->type() == IBoundaryConditionDescriptor::Type::symmetry) { + // symmetry_boundary_descriptor_list.push_back(bc_descriptor->boundaryDescriptor_shared()); + // } + // } + + PolynomialReconstructionDescriptor reconstruction_descriptor(IntegrationMethodType::cell_center, 1, + symmetry_boundary_descriptor_list); + + auto reconstruction = + PolynomialReconstruction{reconstruction_descriptor}.build(DiscreteFunctionP0Vector(p_mesh, Fn_rho), + DiscreteFunctionP0Vector(p_mesh, Fn_rho_u), + DiscreteFunctionP0Vector(p_mesh, Fn_rho_E)); + auto DPk_Fn_rho = reconstruction[0]->template get<DiscreteFunctionDPkVector<Dimension, const double>>(); + auto DPk_Fn_rho_u = + reconstruction[1]->template get<DiscreteFunctionDPkVector<Dimension, const TinyVector<Dimension>>>(); + auto DPk_Fn_rho_E = reconstruction[2]->template get<DiscreteFunctionDPkVector<Dimension, const double>>(); + + FaceArray<double> Fl_rho = compute_Flux1_face<double>(DPk_Fn_rho); + FaceArray<TinyVector<Dimension>> Fl_rho_u = compute_Flux1_face<TinyVector<Dimension>>(DPk_Fn_rho_u); + FaceArray<double> Fl_rho_E = compute_Flux1_face<double>(DPk_Fn_rho_E); + + apply_bc(Fl_rho, Fl_rho_u, Fl_rho_E, rho, rho_u, rho_E, Fn_rho, Fn_rho_u, Fn_rho_E, bc_list); + + synchronize(Fl_rho); + synchronize(Fl_rho_u); + synchronize(Fl_rho_E); + + const CellArray<const double> deltaLFn_rho = compute_deltaLFn_face<double>(Fl_rho); + const CellArray<const TinyVector<Dimension>> deltaLFn_rho_u = + compute_deltaLFn_face<TinyVector<Dimension>>(Fl_rho_u); + const CellArray<const double> deltaLFn_rho_E = compute_deltaLFn_face<double>(Fl_rho_E); + + const CellValue<const TinyVector<Dimension>> A_rho = getA_rho(rho_u); + const CellValue<const TinyMatrix<Dimension>> A_rho_u = getA_rho_u(rho, rho_u, rho_E); + const CellValue<const TinyVector<Dimension>> A_rho_E = getA_rho_E(rho, rho_u, rho_E); + + const CellArray<const double> M_rho = compute_scalar_M(rho, A_rho); + const CellArray<const TinyVector<Dimension>> M_rho_u = compute_vector_M(rho_u, A_rho_u); + const CellArray<const double> M_rho_E = compute_scalar_M(rho_E, A_rho_E); + + const CellValue<const double> rho_np1 = compute_PFnp1<double>(Fn_rho, deltaLFn_rho); + const CellValue<const TinyVector<Dimension>> rho_u_np1 = + compute_PFnp1<TinyVector<Dimension>>(Fn_rho_u, deltaLFn_rho_u); + const CellValue<const double> rho_E_np1 = compute_PFnp1<double>(Fn_rho_E, deltaLFn_rho_E); + + const CellValue<const TinyVector<Dimension>> A_rho_np1 = getA_rho(rho_u_np1); + const CellValue<const TinyMatrix<Dimension>> A_rho_u_np1 = getA_rho_u(rho_np1, rho_u_np1, rho_E_np1); + const CellValue<const TinyVector<Dimension>> A_rho_E_np1 = getA_rho_E(rho_np1, rho_u_np1, rho_E_np1); + + const CellArray<const double> M_rho_np1 = compute_scalar_M(rho_np1, A_rho_np1); + const CellArray<const TinyVector<Dimension>> M_rho_u_np1 = compute_vector_M(rho_u_np1, A_rho_u_np1); + const CellArray<const double> M_rho_E_np1 = compute_scalar_M(rho_E_np1, A_rho_E_np1); + + parallel_for( + p_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (not is_inflow_boundary_cell[cell_id]) { + const double c1 = 1. / (m_eps + m_dt); + const double c2 = m_eps * m_dt * m_inv_Vj[cell_id]; + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + Fnp1_rho[cell_id][i_wave] = c1 * (m_eps * Fn_rho[cell_id][i_wave] - c2 * deltaLFn_rho[cell_id][i_wave] + + m_dt * M_rho_np1[cell_id][i_wave]); + Fnp1_rho_u[cell_id][i_wave] = + c1 * (m_eps * Fn_rho_u[cell_id][i_wave] - c2 * deltaLFn_rho_u[cell_id][i_wave] + + m_dt * M_rho_u_np1[cell_id][i_wave]); + Fnp1_rho_E[cell_id][i_wave] = + c1 * (m_eps * Fn_rho_E[cell_id][i_wave] - c2 * deltaLFn_rho_E[cell_id][i_wave] + + m_dt * M_rho_E_np1[cell_id][i_wave]); + } + } else { + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + Fnp1_rho[cell_id][i_wave] = Fn_rho_ex[cell_id][i_wave]; + Fnp1_rho_u[cell_id][i_wave] = Fn_rho_u_ex[cell_id][i_wave]; + Fnp1_rho_E[cell_id][i_wave] = Fn_rho_E_ex[cell_id][i_wave]; + } + } + }); + + return std::make_tuple(std::make_shared<DiscreteFunctionVariant>(Fnp1_rho), + std::make_shared<DiscreteFunctionVariant>(Fnp1_rho_u), + std::make_shared<DiscreteFunctionVariant>(Fnp1_rho_E)); + } + + EulerKineticSolverMultiDOrder2(std::shared_ptr<const MeshType> mesh, + const double& dt, + const double& eps, + const double& gamma, + const std::vector<TinyVector<MeshType::Dimension>>& lambda_vector, + const size_t& SpaceOrder, + const size_t& TimeOrder, + const CellArray<const double>& Fn_rho, + const CellArray<const TinyVector<MeshType::Dimension>>& Fn_rho_u, + const CellArray<const double>& Fn_rho_E) + : m_dt{dt}, + m_eps{eps}, + m_lambda_vector{lambda_vector}, + m_SpaceOrder{SpaceOrder}, + m_TimeOrder{TimeOrder}, + m_Fn_rho{Fn_rho}, + m_Fn_rho_u{Fn_rho_u}, + m_Fn_rho_E{Fn_rho_E}, + m_gamma{gamma}, + p_mesh{mesh}, + m_mesh{*mesh} + { + if ((lambda_vector.size() != Fn_rho[CellId(0)].size()) or (lambda_vector.size() != Fn_rho_u[CellId(0)].size()) or + (lambda_vector.size() != Fn_rho_u[CellId(0)].size()) or + ((lambda_vector.size() != Fn_rho_E[CellId(0)].size()))) { + throw NormalError("Incompatible dimensions of lambda vector and Fn"); + } + + m_inv_Vj = [&] { + CellValue<double> inv_Vj{m_mesh.connectivity()}; + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { inv_Vj[cell_id] = 1. / m_Vj[cell_id]; }); + return inv_Vj; + }(); + } + + ~EulerKineticSolverMultiDOrder2() = default; +}; + +template <MeshConcept MeshType> +class EulerKineticSolverMultiDOrder2<MeshType>::SymmetryBoundaryCondition +{ + public: + static constexpr const size_t Dimension = MeshType::Dimension; + + 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(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_flat_node_boundary.nodeList(); + } + + size_t + numberOfFaces() const + { + return m_mesh_flat_face_boundary.faceList().size(); + } + + 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 <MeshConcept MeshType> +class EulerKineticSolverMultiDOrder2<MeshType>::WallBoundaryCondition +{ + public: + static constexpr const size_t Dimension = MeshType::Dimension; + + 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(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + size_t + numberOfFaces() const + { + return m_mesh_face_boundary.faceList().size(); + } + + 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) + { + ; + } + + ~WallBoundaryCondition() = default; +}; + +template <MeshConcept MeshType> +class EulerKineticSolverMultiDOrder2<MeshType>::InflowListBoundaryCondition +{ + public: + static constexpr const size_t Dimension = MeshType::Dimension; + + using Rd = TinyVector<Dimension, double>; + + private: + const Table<const double> m_cell_array_list; + const Array<const CellId> m_cell_list; + + public: + size_t + numberOfCells() const + { + return m_cell_list.size(); + } + + const Array<const CellId>& + cellList() const + { + return m_cell_list; + } + + const Table<const double>& + cellArrayList() const + { + return m_cell_array_list; + } + + InflowListBoundaryCondition(const Table<const double>& cell_array_list, const Array<const CellId> cell_list) + : m_cell_array_list(cell_array_list), m_cell_list(cell_list) + { + ; + } + + ~InflowListBoundaryCondition() = default; +}; + +template <MeshConcept MeshType> +class EulerKineticSolverMultiDOrder2<MeshType>::OutflowBoundaryCondition +{ + public: + static constexpr const size_t Dimension = MeshType::Dimension; + + 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(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + size_t + numberOfFaces() const + { + return m_mesh_face_boundary.faceList().size(); + } + + 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) + { + ; + } + + ~OutflowBoundaryCondition() = default; +}; + +template <size_t Dimension> +std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +eulerKineticSolverMultiDOrder2( + const double& dt, + const double& gamma, + const std::vector<TinyVector<Dimension>>& lambda_vector, + const double& eps, + const size_t& SpaceOrder, + const size_t& TimeOrder, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_u, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_E, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) +{ + const std::shared_ptr<const MeshVariant> mesh_v = getCommonMesh({F_rho, F_rho_u, F_rho_E}); + if (mesh_v.use_count() == 0) { + throw NormalError("F_rho, F_rho_u1, F_rho_u2 and F_rho_E have to be defined on the same mesh"); + } + if (SpaceOrder > 1 or TimeOrder > 1) { + throw NotImplementedError("Euler kinetic solver in Multi D not implemented at order > 1"); + } + + return std::visit( + [&](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)>; + if constexpr (is_polygonal_mesh_v<MeshType> and (MeshType::Dimension == Dimension)) { + auto Fn_rho = F_rho->get<DiscreteFunctionP0Vector<const double>>(); + auto Fn_rho_u = F_rho_u->get<DiscreteFunctionP0Vector<const TinyVector<MeshType::Dimension>>>(); + auto Fn_rho_E = F_rho_E->get<DiscreteFunctionP0Vector<const double>>(); + + EulerKineticSolverMultiDOrder2 solver(p_mesh, dt, eps, gamma, lambda_vector, SpaceOrder, TimeOrder, + Fn_rho.cellArrays(), Fn_rho_u.cellArrays(), Fn_rho_E.cellArrays()); + + return solver.apply(bc_descriptor_list); + } else { + throw NotImplementedError("Invalid mesh type for Multi D Euler Kinetic solver"); + } + }, + mesh_v->variant()); +} + +template std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +eulerKineticSolverMultiDOrder2( + const double& dt, + const double& gamma, + const std::vector<TinyVector<2>>& lambda_vector, + const double& eps, + const size_t& SpaceOrder, + const size_t& TimeOrder, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_u, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_E, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list); + +template std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +eulerKineticSolverMultiDOrder2( + const double& dt, + const double& gamma, + const std::vector<TinyVector<3>>& lambda_vector, + const double& eps, + const size_t& SpaceOrder, + const size_t& TimeOrder, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_u, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_E, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list); diff --git a/src/scheme/EulerKineticSolverMultiDOrder2.hpp b/src/scheme/EulerKineticSolverMultiDOrder2.hpp new file mode 100644 index 000000000..c533e9d12 --- /dev/null +++ b/src/scheme/EulerKineticSolverMultiDOrder2.hpp @@ -0,0 +1,25 @@ +#ifndef EULER_KINETIC_SOLVER_MULTID_ORDER2_HPP +#define EULER_KINETIC_SOLVER_MULTID_ORDER2_HPP + +#include <language/utils/FunctionSymbolId.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> + +class IBoundaryConditionDescriptor; + +template <size_t Dimension> +std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +eulerKineticSolverMultiDOrder2( + const double& dt, + const double& gamma, + const std::vector<TinyVector<Dimension>>& lambda_vector, + const double& eps, + const size_t& SpaceOrder, + const size_t& TimeOrder, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_u, + const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_E, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list); + +#endif // EULER_KINETIC_SOLVER_MULTID_ORDER2_HPP -- GitLab