diff --git a/src/language/modules/KineticSchemeModule.cpp b/src/language/modules/KineticSchemeModule.cpp index de1b5fd06d92c94ffa1b892c00b6a593bd45d36c..8a1f13b1e2c4d1b0afd2392a62b1687fc1ba4053 100644 --- a/src/language/modules/KineticSchemeModule.cpp +++ b/src/language/modules/KineticSchemeModule.cpp @@ -12,6 +12,7 @@ #include <scheme/EulerKineticSolverLagrangeMultiD.hpp> #include <scheme/EulerKineticSolverLagrangeMultiDLocal.hpp> #include <scheme/EulerKineticSolverLagrangeMultiDLocalOrder2.hpp> +#include <scheme/EulerKineticSolverLagrangeMultiDLocalOrder2Periodic.hpp> #include <scheme/EulerKineticSolverMeanFluxMood.hpp> #include <scheme/EulerKineticSolverMoodFD.hpp> #include <scheme/EulerKineticSolverMoodFV.hpp> @@ -904,6 +905,27 @@ KineticSchemeModule::KineticSchemeModule() )); + this->_addBuiltinFunction("euler_kinetic_lagrange_multiD_local_order2_periodic", + std::function( + + [](const double& dt, const size_t& L, const size_t& M, const size_t& k, + const double& gamma, const double& eps, const size_t& space_order, + const size_t& time_order, 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>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list) -> std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + return eulerKineticSolverLagrangeMultiDLocalOrder2(dt, L, M, k, gamma, eps, space_order, + time_order, rho, u, E, p, + bc_descriptor_list); + } + + )); + this->_addBuiltinFunction("euler_kinetic_acoustic_lagrange_FV", std::function( diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt index cea3033cd68b47769e56f7c97529aabe3b1fa471..c43dcecd3845c31d8d6ae757f22d819acdda3442 100644 --- a/src/scheme/CMakeLists.txt +++ b/src/scheme/CMakeLists.txt @@ -20,6 +20,7 @@ add_library( EulerKineticSolverLagrangeMultiD.cpp EulerKineticSolverLagrangeMultiDLocal.cpp EulerKineticSolverLagrangeMultiDLocalOrder2.cpp + EulerKineticSolverLagrangeMultiDLocalOrder2Periodic.cpp EulerKineticSolverMeanFluxMood.cpp EulerKineticSolverOneFluxMood.cpp EulerKineticSolverMoodFD.cpp diff --git a/src/scheme/EulerKineticSolverLagrangeMultiDLocalOrder2Periodic.cpp b/src/scheme/EulerKineticSolverLagrangeMultiDLocalOrder2Periodic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46682295729de63aa20b00505e66ad9737e28a25 --- /dev/null +++ b/src/scheme/EulerKineticSolverLagrangeMultiDLocalOrder2Periodic.cpp @@ -0,0 +1,666 @@ +#include <scheme/EulerKineticSolverLagrangeMultiDLocalOrder2.hpp> + +#include <language/utils/EvaluateAtPoints.hpp> +#include <language/utils/InterpolateItemArray.hpp> +#include <language/utils/InterpolateItemValue.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshVariant.hpp> +#include <mesh/StencilManager.hpp> +#include <scheme/DiscreteFunctionDPkVariant.hpp> +#include <scheme/DiscreteFunctionDPkVector.hpp> +#include <scheme/DiscreteFunctionDescriptorP0Vector.hpp> +#include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/IDiscreteFunctionDescriptor.hpp> +#include <scheme/PolynomialReconstruction.hpp> +#include <scheme/PolynomialReconstructionDescriptor.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/LineTransformation.hpp> +#include <tuple> + +template <MeshConcept MeshType> +class EulerKineticSolverLagrangeMultiDLocalOrder2Periodic +{ + private: + constexpr static size_t Dimension = MeshType::Dimension; + using Rd = TinyVector<Dimension>; + + const double m_dt; + const size_t m_L; + const size_t m_M; + const size_t m_k; + const double m_gamma; + const size_t m_spaceOrder; + const size_t m_timeOrder; + const CellValue<const double> m_rho; + const CellValue<const TinyVector<Dimension>> m_u; + const CellValue<const double> m_E; + const CellValue<const double> m_p; + const std::shared_ptr<const MeshType> p_mesh; + const MeshType& m_mesh; + const CellValue<const double> m_Vj = MeshDataManager::instance().getMeshData(m_mesh).Vj(); + CellValue<const double> m_inv_Mj; + CellValue<const double> m_inv_Vj; + CellValue<const double> m_Mj; + const CellValue<const TinyVector<Dimension>> m_xj = MeshDataManager::instance().getMeshData(m_mesh).xj(); + const NodeValue<const TinyVector<Dimension>> m_xr = m_mesh.xr(); + + public: + NodeArray<double> + compute_Flux_Fp(const DiscreteFunctionDPk<Dimension, const double> DPk_p, + const DiscreteFunctionDPk<Dimension, const TinyVector<Dimension>> DPk_u, + const NodeArray<const TinyVector<Dimension>>& lambda_vector) + { + const NodeValuePerCell<const TinyVector<Dimension>> njr = MeshDataManager::instance().getMeshData(m_mesh).njr(); + const size_t nb_waves = m_k; + NodeArray<double> 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(); + + 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]; + + TinyVector<Dimension> inv_S = zero; + for (size_t d = 0; d < Dimension; ++d) { + for (size_t i = 0; i < nb_waves; ++i) { + inv_S[d] += lambda_vector[node_id][i][d] * lambda_vector[node_id][i][d]; + } + inv_S[d] = 1. / inv_S[d]; + } + double lambda_r = std::sqrt(dot(lambda_vector[node_id][m_L], lambda_vector[node_id][m_L])); + + 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(lambda_vector[node_id][i_wave], njr(cell_id, i_node)); + if (li_njr > 1e-14) { + double Fj = (1. / nb_waves) * DPk_p[cell_id](m_xr[node_id]); + + for (size_t d = 0; d < Dimension; ++d) { + Fj += inv_S[d] * lambda_vector[node_id][i_wave][d] * + (lambda_r * lambda_r * DPk_u[cell_id](m_xr[node_id])[d]); + } + + Fr[node_id][i_wave] += li_njr * Fj; + sum_li_njr += li_njr; + } + } + if (sum_li_njr != 0) { + Fr[node_id][i_wave] = 1. / sum_li_njr * Fr[node_id][i_wave]; + } + } + }); + + return Fr; + } + + NodeArray<TinyVector<Dimension>> + compute_Flux_Fu(const DiscreteFunctionDPk<Dimension, const double> DPk_p, + const DiscreteFunctionDPk<Dimension, const TinyVector<Dimension>> DPk_u, + const NodeArray<const TinyVector<Dimension>>& lambda_vector) + { + const NodeValuePerCell<const TinyVector<Dimension>> njr = MeshDataManager::instance().getMeshData(m_mesh).njr(); + const size_t nb_waves = m_k; + NodeArray<TinyVector<Dimension>> 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(); + + Fr.fill(zero); + + 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) { + TinyVector<Dimension> inv_S = zero; + for (size_t d = 0; d < Dimension; ++d) { + for (size_t i = 0; i < nb_waves; ++i) { + inv_S[d] += lambda_vector[node_id][i][d] * lambda_vector[node_id][i][d]; + } + inv_S[d] = 1. / inv_S[d]; + } + + 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(lambda_vector[node_id][i_wave], njr(cell_id, i_node)); + if (li_njr > 1e-14) { + TinyVector<Dimension> Fj = (1. / nb_waves) * DPk_u[cell_id](m_xr[node_id]); + + for (size_t d = 0; d < Dimension; ++d) { + Fj[d] += 1. / Dimension * inv_S[d] * lambda_vector[node_id][i_wave][d] * DPk_p[cell_id](m_xr[node_id]); + } + + Fr[node_id][i_wave] += li_njr * Fj; + sum_li_njr += li_njr; + } + } + if (sum_li_njr != 0) { + Fr[node_id][i_wave] = 1. / sum_li_njr * Fr[node_id][i_wave]; + } + } + }); + + return Fr; + } + + const NodeValue<TinyVector<Dimension>> + compute_velocity_flux(NodeArray<double>& F, const NodeArray<const TinyVector<Dimension>>& lambda_vector) + { + NodeValue<TinyVector<Dimension>> u{p_mesh->connectivity()}; + const size_t nb_waves = m_k; + u.fill(zero); + + parallel_for( + m_mesh.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { + const double inv_lambda_squared = 1. / dot(lambda_vector[node_id][m_L], lambda_vector[node_id][m_L]); + + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + u[node_id] += F[node_id][i_wave] * lambda_vector[node_id][i_wave]; + } + u[node_id] = inv_lambda_squared * u[node_id]; + }); + return u; + } + + const NodeValue<TinyVector<Dimension>> + compute_pressure_flux(NodeArray<TinyVector<Dimension>>& F, + const NodeArray<const TinyVector<Dimension>>& lambda_vector) + { + NodeValue<TinyVector<Dimension>> p{p_mesh->connectivity()}; + const size_t nb_waves = m_k; + p.fill(zero); + + parallel_for( + m_mesh.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { + for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) { + for (size_t dim = 0; dim < Dimension; ++dim) { + p[node_id][dim] += dot(F[node_id][i_wave], lambda_vector[node_id][i_wave]); + } + } + }); + return p; + } + + const CellValue<const double> + compute_delta_velocity(const NodeValue<const TinyVector<Dimension>>& ur) + { + const NodeValuePerCell<const TinyVector<Dimension>> Cjr = MeshDataManager::instance().getMeshData(m_mesh).Cjr(); + CellValue<double> delta{p_mesh->connectivity()}; + + const auto& cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix(); + + delta.fill(0.); + + 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_node = 0; i_node < cell_to_node.size(); ++i_node) { + const NodeId node_id = cell_to_node[i_node]; + delta[cell_id] += dot(Cjr(cell_id, i_node), ur[node_id]); + } + }); + return delta; + } + + const CellValue<const TinyVector<Dimension>> + compute_delta_pressure(const NodeValue<const TinyVector<Dimension>>& pr) + { + const NodeValuePerCell<const TinyVector<Dimension>> Cjr = MeshDataManager::instance().getMeshData(m_mesh).Cjr(); + CellValue<TinyVector<Dimension>> delta{p_mesh->connectivity()}; + + const auto& cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix(); + + delta.fill(zero); + + 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_node = 0; i_node < cell_to_node.size(); ++i_node) { + for (size_t dim = 0; dim < Dimension; ++dim) { + const NodeId node_id = cell_to_node[i_node]; + delta[cell_id][dim] += Cjr(cell_id, i_node)[dim] * pr[node_id][dim]; + } + } + }); + return delta; + } + + const CellValue<const double> + compute_delta_pu(const NodeValue<const TinyVector<Dimension>>& ur, const NodeValue<const TinyVector<Dimension>>& pr) + { + const NodeValuePerCell<const TinyVector<Dimension>> Cjr = MeshDataManager::instance().getMeshData(m_mesh).Cjr(); + CellValue<double> delta{p_mesh->connectivity()}; + + const auto& cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix(); + delta.fill(0.); + + 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_node = 0; i_node < cell_to_node.size(); ++i_node) { + const NodeId node_id = cell_to_node[i_node]; + TinyVector<Dimension> Fjr = zero; + for (size_t dim = 0; dim < Dimension; ++dim) { + Fjr[dim] = Cjr(cell_id, i_node)[dim] * pr[node_id][dim]; + } + delta[cell_id] += dot(Fjr, ur[node_id]); + } + }); + return delta; + } + + const CellValue<const double> + build_lambda_j(const CellValue<double>& rho, const CellValue<double>& p) + { + CellValue<double> lambda_j{p_mesh->connectivity()}; + CellValue<double> cj{m_mesh.connectivity()}; + + if constexpr (Dimension == 1) { + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + cj[cell_id] = std::sqrt(m_gamma * p[cell_id] / rho[cell_id]); + lambda_j[cell_id] = std::sqrt((3. * (m_k - 1.)) / (m_k + 1.)) * std::abs(rho[cell_id] * cj[cell_id]); + }); + } else if constexpr (Dimension == 2) { + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + cj[cell_id] = std::sqrt(m_gamma * p[cell_id] / rho[cell_id]); + lambda_j[cell_id] = + (12. * m_L * m_L) / ((m_L + 1.) * (2. * m_L + 1.)) * 2. * std::abs(rho[cell_id] * cj[cell_id]); + }); + } else if constexpr (Dimension == 3) { + if (m_k != 6) { + throw NotImplementedError("3D Lagrangian scheme not implemented for other than 6 waves model"); + } + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + cj[cell_id] = std::sqrt(m_gamma * p[cell_id] / rho[cell_id]); + lambda_j[cell_id] = 3. * std::abs(rho[cell_id] * cj[cell_id]); + }); + } + return lambda_j; + } + + const NodeArray<const TinyVector<Dimension>> + build_nodal_wavespeeds(const CellValue<const double>& lambda_j) + { + const auto& node_to_cell_matrix = m_mesh.connectivity().nodeToCellMatrix(); + NodeArray<TinyVector<Dimension>> lambda_vector(p_mesh->connectivity(), m_k); + const double pi = std::acos(-1); + + parallel_for( + m_mesh.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { + const auto& node_to_cell = node_to_cell_matrix[node_id]; + + double lambda_r = 0.; + for (size_t i_cell = 0; i_cell < node_to_cell.size(); ++i_cell) { + const CellId cell_id = node_to_cell[i_cell]; + + lambda_r = std::max(lambda_r, lambda_j[cell_id]); + + // std::cout << "node_id = " << node_id << ", lambda_r = " << lambda_r << "\n"; + } + + if constexpr (Dimension == 1) { + for (size_t i_wave = 0; i_wave < m_k; ++i_wave) { + lambda_vector[node_id][i_wave][0] = lambda_r * (1 - 2. * i_wave / (m_k - 1)); + } + } else if constexpr (Dimension == 2) { + for (size_t l = 1; l < m_L + 1; ++l) { + for (size_t m = 1; m < 4 * m_M + 1; ++m) { + size_t i_wave = (l - 1) * 4 * m_M + m - 1; + double ll = l; + lambda_vector[node_id][i_wave] = + TinyVector<Dimension>{(ll / m_L) * lambda_r * std::cos((m * pi) / (2 * m_M)), // + 0.2 * pi), + (ll / m_L) * lambda_r * std::sin((m * pi) / (2 * m_M))}; // + 0.2 * pi)}; + } + } + } else if constexpr (Dimension == 3) { + if (m_k != 6) { + throw NotImplementedError("3D Lagrangian scheme not implemented for other than 6 waves model"); + } + lambda_vector[node_id][0] = TinyVector<Dimension>{lambda_r, 0., 0.}; + lambda_vector[node_id][1] = TinyVector<Dimension>{-lambda_r, 0., 0.}; + lambda_vector[node_id][2] = TinyVector<Dimension>{0., lambda_r, 0.}; + lambda_vector[node_id][3] = TinyVector<Dimension>{0., -lambda_r, 0.}; + lambda_vector[node_id][4] = TinyVector<Dimension>{0., 0., lambda_r}; + lambda_vector[node_id][5] = TinyVector<Dimension>{0., 0., -lambda_r}; + } + }); + return lambda_vector; + } + + void + scalar_limiter(const CellValue<const double>& u, DiscreteFunctionDPk<Dimension, double>& DPk_uh) const + { + StencilDescriptor stencil_descriptor{1, StencilDescriptor::ConnectionType::by_nodes}; + auto stencil = StencilManager::instance().getCellToCellStencilArray(m_mesh.connectivity(), stencil_descriptor); + + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double uj = u[cell_id]; + + double u_min = uj; + double u_max = uj; + + const auto cell_stencil = stencil[cell_id]; + for (size_t i_cell = 0; i_cell < cell_stencil.size(); ++i_cell) { + u_min = std::min(u_min, u[cell_stencil[i_cell]]); + u_max = std::max(u_max, u[cell_stencil[i_cell]]); + } + + const double eps = 1E-14; + double coef = 1; + double lambda = 1.; + + for (size_t i_cell = 0; i_cell < cell_stencil.size(); ++i_cell) { + const CellId cell_i_id = cell_stencil[i_cell]; + const double u_bar_i = DPk_uh[cell_id](m_xj[cell_i_id]); + const double Delta = (u_bar_i - uj); + + if (Delta > eps) { + coef = std::min(1., (u_max - uj) / Delta); + } else if (Delta < -eps) { + coef = std::min(1., (u_min - uj) / Delta); + } + lambda = std::min(lambda, coef); + } + + auto coefficients = DPk_uh.coefficients(cell_id); + coefficients[0] = (1 - lambda) * u[cell_id] + lambda * coefficients[0]; + for (size_t i = 1; i < coefficients.size(); ++i) { + coefficients[i] *= lambda; + } + }); + } + + void + vector_limiter(const CellValue<const TinyVector<Dimension>>& u, + DiscreteFunctionDPk<Dimension, TinyVector<Dimension>>& DPk_uh) const + { + StencilDescriptor stencil_descriptor{1, StencilDescriptor::ConnectionType::by_nodes}; + auto stencil = StencilManager::instance().getCellToCellStencilArray(m_mesh.connectivity(), stencil_descriptor); + + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension> uj = u[cell_id]; + + TinyVector<Dimension> u_min = uj; + TinyVector<Dimension> u_max = uj; + + const auto cell_stencil = stencil[cell_id]; + for (size_t i_cell = 0; i_cell < cell_stencil.size(); ++i_cell) { + for (size_t dim = 0; dim < Dimension; ++dim) { + u_min[dim] = std::min(u_min[dim], u[cell_stencil[i_cell]][dim]); + u_max[dim] = std::max(u_max[dim], u[cell_stencil[i_cell]][dim]); + } + } + + const double eps = 1E-14; + TinyVector<Dimension> coef; + double lambda = 1.; + + for (size_t i_cell = 0; i_cell < cell_stencil.size(); ++i_cell) { + const CellId cell_i_id = cell_stencil[i_cell]; + const TinyVector<Dimension> u_bar_i = DPk_uh[cell_id](m_xj[cell_i_id]); + TinyVector<Dimension> Delta; + + for (size_t dim = 0; dim < Dimension; ++dim) { + Delta[dim] = (u_bar_i[dim] - uj[dim]); + coef[dim] = 1.; + if (Delta[dim] > eps) { + coef[dim] = std::min(1., (u_max[dim] - uj[dim]) / Delta[dim]); + } else if (Delta[dim] < -eps) { + coef[dim] = std::min(1., (u_min[dim] - uj[dim]) / Delta[dim]); + } + lambda = std::min(lambda, coef[dim]); + } + } + auto coefficients = DPk_uh.coefficients(cell_id); + + coefficients[0] = (1 - lambda) * u[cell_id] + lambda * coefficients[0]; + for (size_t i = 1; i < coefficients.size(); ++i) { + coefficients[i] *= lambda; + } + }); + } + + std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply() + { + const bool limitation = true; + + const CellValue<double> rho = copy(m_rho); + const CellValue<TinyVector<Dimension>> u = copy(m_u); + const CellValue<double> p = copy(m_p); + const CellValue<double> E = copy(m_E); + + CellValue<TinyVector<Dimension>> u_np1 = copy(u); + CellValue<double> p_np1 = copy(p); + CellValue<double> E_np1 = copy(E); + + const CellValue<const double> lambda_j = build_lambda_j(rho, p); + const NodeArray<const TinyVector<Dimension>> lambda_vector = build_nodal_wavespeeds(lambda_j); + + PolynomialReconstructionDescriptor reconstruction_descriptor(IntegrationMethodType::cell_center, 1); + + auto reconstruction = PolynomialReconstruction{reconstruction_descriptor}.build(DiscreteFunctionP0(p_mesh, p), + DiscreteFunctionP0(p_mesh, u)); + + auto DPk_p = reconstruction[0]->template get<DiscreteFunctionDPk<Dimension, const double>>(); + auto DPk_u = reconstruction[1]->template get<DiscreteFunctionDPk<Dimension, const TinyVector<Dimension>>>(); + + DiscreteFunctionDPk<Dimension, double> p_lim = copy(DPk_p); + DiscreteFunctionDPk<Dimension, TinyVector<Dimension>> u_lim = copy(DPk_u); + + if (limitation) { + scalar_limiter(p, p_lim); + vector_limiter(u, u_lim); + + synchronize(p_lim.cellArrays()); + synchronize(u_lim.cellArrays()); + } + + NodeArray<double> Fr_p = compute_Flux_Fp(p_lim, u_lim, lambda_vector); + NodeArray<TinyVector<Dimension>> Fr_u = compute_Flux_Fu(p_lim, u_lim, lambda_vector); + + const NodeValue<TinyVector<Dimension>> ur = compute_velocity_flux(Fr_p, lambda_vector); + const NodeValue<TinyVector<Dimension>> pr = compute_pressure_flux(Fr_u, lambda_vector); + + const CellValue<const double> delta_u = compute_delta_velocity(ur); + const CellValue<const TinyVector<Dimension>> delta_p = compute_delta_pressure(pr); + const CellValue<const double> delta_pu = compute_delta_pu(ur, pr); + + CellValue<double> pj_star{m_mesh.connectivity()}; + CellValue<TinyVector<Dimension>> uj_star = copy(m_u); + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double dt_over_Mj = m_dt * m_inv_Mj[cell_id]; + double tauj_star = 1. / m_rho[cell_id] + dt_over_Mj * delta_u[cell_id]; + pj_star[cell_id] = m_p[cell_id] / std::pow(m_rho[cell_id] * tauj_star, m_gamma); + uj_star[cell_id] += dt_over_Mj * delta_p[cell_id]; + }); + + auto reconstruction_star = + PolynomialReconstruction{reconstruction_descriptor}.build(DiscreteFunctionP0(p_mesh, pj_star), + DiscreteFunctionP0(p_mesh, uj_star)); + + auto DPk_p_star = reconstruction_star[0]->template get<DiscreteFunctionDPk<Dimension, const double>>(); + auto DPk_u_star = + reconstruction_star[1]->template get<DiscreteFunctionDPk<Dimension, const TinyVector<Dimension>>>(); + + DiscreteFunctionDPk<Dimension, double> p_star_lim = copy(DPk_p_star); + DiscreteFunctionDPk<Dimension, TinyVector<Dimension>> u_star_lim = copy(DPk_u_star); + + if (limitation) { + scalar_limiter(pj_star, p_star_lim); + vector_limiter(uj_star, u_star_lim); + + synchronize(p_star_lim.cellArrays()); + synchronize(u_star_lim.cellArrays()); + } + + NodeArray<double> Fr_p_star = compute_Flux_Fp(p_star_lim, u_star_lim, lambda_vector); + NodeArray<TinyVector<Dimension>> Fr_u_star = compute_Flux_Fu(p_star_lim, u_star_lim, lambda_vector); + + const NodeValue<TinyVector<Dimension>> ur_star = compute_velocity_flux(Fr_p_star, lambda_vector); + const NodeValue<TinyVector<Dimension>> pr_star = compute_pressure_flux(Fr_u_star, lambda_vector); + + const CellValue<const double> delta_u_star = compute_delta_velocity(ur_star); + const CellValue<const TinyVector<Dimension>> delta_p_star = compute_delta_pressure(pr_star); + const CellValue<const double> delta_pu_star = compute_delta_pu(ur_star, pr_star); + + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double dt_over_Mj = m_dt * m_inv_Mj[cell_id]; + u_np1[cell_id] -= 0.5 * dt_over_Mj * (delta_p[cell_id] + delta_p_star[cell_id]); + E_np1[cell_id] -= 0.5 * dt_over_Mj * (delta_pu[cell_id] + delta_pu_star[cell_id]); + }); + + NodeValue<TinyVector<Dimension>> new_xr = copy(m_mesh.xr()); + parallel_for( + m_mesh.numberOfNodes(), + PUGS_LAMBDA(NodeId node_id) { new_xr[node_id] += 0.5 * m_dt * (ur[node_id] + ur_star[node_id]); }); + + std::shared_ptr<const MeshType> new_mesh = std::make_shared<MeshType>(m_mesh.shared_connectivity(), new_xr); + + CellValue<const double> new_Vj = MeshDataManager::instance().getMeshData(*new_mesh).Vj(); + CellValue<double> rho_np1{p_mesh->connectivity()}; + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { rho_np1[cell_id] = m_Mj[cell_id] / new_Vj[cell_id]; }); + + return std::make_tuple(std::make_shared<MeshVariant>(new_mesh), + std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionP0<const double>(new_mesh, rho_np1)), + std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionP0<const TinyVector<Dimension>>(new_mesh, u_np1)), + std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionP0<const double>(new_mesh, E_np1))); + } + + EulerKineticSolverLagrangeMultiDLocalOrder2Periodic(std::shared_ptr<const MeshType> mesh, + const double& dt, + const size_t& L, + const size_t& M, + const size_t& k, + const double& gamma, + const size_t& space_order, + const size_t& time_order, + const CellValue<const double>& rho, + const CellValue<const TinyVector<MeshType::Dimension>>& u, + const CellValue<const double>& E, + const CellValue<const double>& p) + : m_dt{dt}, + m_L{L}, + m_M{M}, + m_k{k}, + m_gamma{gamma}, + m_spaceOrder{space_order}, + m_timeOrder{time_order}, + m_rho{rho}, + m_u{u}, + m_E{E}, + m_p{p}, + p_mesh{mesh}, + m_mesh{*mesh} + { + m_Mj = [&] { + CellValue<double> Mj{m_mesh.connectivity()}; + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { Mj[cell_id] = m_rho[cell_id] * m_Vj[cell_id]; }); + return Mj; + }(); + + m_inv_Mj = [&] { + CellValue<double> inv_Mj{m_mesh.connectivity()}; + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { inv_Mj[cell_id] = 1. / m_Mj[cell_id]; }); + return inv_Mj; + }(); + + 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; + }(); + } + + ~EulerKineticSolverLagrangeMultiDLocalOrder2Periodic() = default; +}; + +std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +eulerKineticSolverLagrangeMultiDLocalOrder2Periodic(const double& dt, + const size_t& L, + const size_t& M, + const size_t& k, + const double& gamma, + const double& eps, + const size_t& space_order, + const size_t& time_order, + const std::shared_ptr<const DiscreteFunctionVariant>& rho_n, + const std::shared_ptr<const DiscreteFunctionVariant>& u_n, + const std::shared_ptr<const DiscreteFunctionVariant>& E_n, + const std::shared_ptr<const DiscreteFunctionVariant>& p_n) +{ + const std::shared_ptr<const MeshVariant> mesh_v = getCommonMesh({rho_n, u_n, E_n, p_n}); + if (mesh_v.use_count() == 0) { + throw NormalError("rho_n, u_n, E_n and p_n have to be defined on the same mesh"); + } + if (space_order > 1 or time_order > 1) { + throw NotImplementedError("Euler kinetic solver in Multi D not implemented at order > 1"); + } + double eps_bis = eps; // A retirer !! + eps_bis += eps_bis; // A retirer !! + return std::visit( + [&](auto&& p_mesh) + -> std::tuple<std::shared_ptr<const MeshVariant>, 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 (MeshType::Dimension != 1) { + throw NotImplementedError("periodic bc are only implemented in 1d"); + } else { + if constexpr (is_polygonal_mesh_v<MeshType>) { + auto rho = rho_n->get<DiscreteFunctionP0<const double>>(); + auto u = u_n->get<DiscreteFunctionP0<const TinyVector<MeshType::Dimension>>>(); + auto E = E_n->get<DiscreteFunctionP0<const double>>(); + auto p = p_n->get<DiscreteFunctionP0<const double>>(); + + EulerKineticSolverLagrangeMultiDLocalOrder2Periodic solver(p_mesh, dt, L, M, k, gamma, space_order, + time_order, rho.cellValues(), u.cellValues(), + E.cellValues(), p.cellValues()); + + return solver.apply(); + } else { + throw NotImplementedError("Invalid mesh type for multi-D Lagrangian Kinetic solver"); + } + } + }, + mesh_v->variant()); +} diff --git a/src/scheme/EulerKineticSolverLagrangeMultiDLocalOrder2Periodic.hpp b/src/scheme/EulerKineticSolverLagrangeMultiDLocalOrder2Periodic.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ef7bb2f0dc4562e9c0738117c17a2d6deb591afe --- /dev/null +++ b/src/scheme/EulerKineticSolverLagrangeMultiDLocalOrder2Periodic.hpp @@ -0,0 +1,28 @@ +#ifndef EULER_KINETIC_SOLVER_LAGRANGE_MULTI_D_LOCAL_ORDER_2PERIODIC_HPP +#define EULER_KINETIC_SOLVER_LAGRANGE_MULTI_D_LOCAL_ORDER_2PERIODIC_HPP + +#include <language/utils/FunctionSymbolId.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> + +class IBoundaryConditionDescriptor; + +std::tuple<std::shared_ptr<const MeshVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> +eulerKineticSolverLagrangeMultiDLocalOrder2Periodic( + const double& dt, + const size_t& L, + const size_t& M, + const size_t& k, + const double& gamma, + const double& eps, + const size_t& space_order, + const size_t& time_order, + 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>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list); + +#endif // EULER_KINETIC_SOLVER_LAGRANGE_MULTI_D_LOCAL_ORDER_2PERIODIC_HPP