From 063dc78a1de1527b56044ee135e0b90acb0bba2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com> Date: Sat, 20 May 2023 10:03:51 +0200 Subject: [PATCH] Add boundary condition support for fluxing advection Allowed bc tyes are - inflow - outflow - symmetry Inflow is not yet implemented for variables of type P0Vector --- src/language/modules/SchemeModule.cpp | 17 +- src/scheme/FluxingAdvectionSolver.cpp | 358 +++++++++++++++++++++++--- src/scheme/FluxingAdvectionSolver.hpp | 5 + 3 files changed, 343 insertions(+), 37 deletions(-) diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index 32628a2eb..813bde93a 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -677,16 +677,17 @@ SchemeModule::SchemeModule() } )); - this->_addBuiltinFunction("fluxing_advection", - std::function( - [](const std::shared_ptr<const IMesh> new_mesh, - const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& remapped_variables) - -> std::vector<std::shared_ptr<const DiscreteFunctionVariant>> { - return advectByFluxing(new_mesh, remapped_variables); - } + this->_addBuiltinFunction("fluxing_advection", std::function( - )); + [](const std::shared_ptr<const IMesh> new_mesh, + const std::vector<std::shared_ptr<const VariableBCDescriptor>>& + remapped_quantity_with_bc) + -> std::vector<std::shared_ptr<const DiscreteFunctionVariant>> { + return advectByFluxing(new_mesh, remapped_quantity_with_bc); + } + + )); MathFunctionRegisterForVh{*this}; } diff --git a/src/scheme/FluxingAdvectionSolver.cpp b/src/scheme/FluxingAdvectionSolver.cpp index 57f0d4842..97aad4bb8 100644 --- a/src/scheme/FluxingAdvectionSolver.cpp +++ b/src/scheme/FluxingAdvectionSolver.cpp @@ -1,6 +1,7 @@ #include <scheme/FluxingAdvectionSolver.hpp> #include <language/utils/EvaluateAtPoints.hpp> +#include <language/utils/InterpolateItemValue.hpp> #include <mesh/Connectivity.hpp> #include <mesh/IMesh.hpp> #include <mesh/ItemArrayUtils.hpp> @@ -9,10 +10,18 @@ #include <mesh/MeshData.hpp> #include <mesh/MeshDataManager.hpp> #include <mesh/MeshFaceBoundary.hpp> +#include <mesh/MeshFlatFaceBoundary.hpp> +#include <mesh/MeshNodeBoundary.hpp> #include <mesh/SubItemValuePerItem.hpp> #include <scheme/DiscreteFunctionP0.hpp> #include <scheme/DiscreteFunctionUtils.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> +#include <scheme/InflowBoundaryConditionDescriptor.hpp> +#include <scheme/OutflowBoundaryConditionDescriptor.hpp> +#include <scheme/SymmetryBoundaryConditionDescriptor.hpp> + +#include <variant> +#include <vector> template <size_t Dimension> class FluxingAdvectionSolver @@ -36,7 +45,25 @@ class FluxingAdvectionSolver CellArray<double>>; + template <typename DataType> + class InflowValueBoundaryCondition; + class InflowArrayBoundaryCondition; + class OutflowBoundaryCondition; + class SymmetryBoundaryCondition; + + using BoundaryConditionVariant = std::variant<InflowValueBoundaryCondition<double>, // + InflowValueBoundaryCondition<TinyVector<1>>, + InflowValueBoundaryCondition<TinyVector<2>>, + InflowValueBoundaryCondition<TinyVector<3>>, + InflowValueBoundaryCondition<TinyMatrix<1>>, + InflowValueBoundaryCondition<TinyMatrix<2>>, + InflowValueBoundaryCondition<TinyMatrix<3>>, + InflowArrayBoundaryCondition, + OutflowBoundaryCondition, + SymmetryBoundaryCondition>; + std::vector<RemapVariant> m_remapped_list; + std::vector<std::vector<BoundaryConditionVariant>> m_boundary_condition_list; FaceValue<const CellId> m_donnor_cell; FaceValue<const double> m_cycle_fluxing_volume; @@ -55,21 +82,98 @@ class FluxingAdvectionSolver m_remapped_list.emplace_back(copy(old_q.cellValues())); } - template <typename DataType> void - _storeValues(const DiscreteFunctionP0Vector<Dimension, const DataType>& old_q) + _storeValues(const DiscreteFunctionP0Vector<Dimension, const double>& old_q) { m_remapped_list.emplace_back(copy(old_q.cellArrays())); } + template <typename DataType> + void + _storeValueBCList(const size_t i_quantity, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_list) + { + const Mesh<Connectivity<Dimension>>& mesh = *m_old_mesh; + + for (auto& i_bc : bc_list) { + switch (i_bc->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + m_boundary_condition_list[i_quantity].emplace_back( + SymmetryBoundaryCondition(getMeshFlatFaceBoundary(mesh, i_bc->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::outflow: { + m_boundary_condition_list[i_quantity].emplace_back( + OutflowBoundaryCondition(getMeshFaceBoundary(mesh, i_bc->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::inflow: { + const InflowBoundaryConditionDescriptor& inflow_bc_descriptor = + dynamic_cast<const InflowBoundaryConditionDescriptor&>(*i_bc); + + MeshFaceBoundary<Dimension> mesh_face_boundary = + getMeshFaceBoundary(mesh, inflow_bc_descriptor.boundaryDescriptor()); + + FaceValue<const Rd> xl = MeshDataManager::instance().getMeshData(*m_old_mesh).xl(); + Array<const DataType> value_list = + InterpolateItemValue<DataType(Rd)>::template interpolate<ItemType::face>(inflow_bc_descriptor + .functionSymbolId(), + xl, mesh_face_boundary.faceList()); + + m_boundary_condition_list[i_quantity].emplace_back( + InflowValueBoundaryCondition<DataType>{mesh_face_boundary, value_list}); + break; + } + default: { + std::ostringstream os; + os << "invalid boundary condition for advection: " << *i_bc; + throw NotImplementedError("inflow boundary condition"); + } + } + } + } + + void + _storeArrayBCList(const size_t i_quantity, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_list) + { + const Mesh<Connectivity<Dimension>>& mesh = *m_old_mesh; + + for (auto& i_bc : bc_list) { + switch (i_bc->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + m_boundary_condition_list[i_quantity].emplace_back( + SymmetryBoundaryCondition(getMeshFlatFaceBoundary(mesh, i_bc->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::outflow: { + m_boundary_condition_list[i_quantity].emplace_back( + OutflowBoundaryCondition(getMeshFaceBoundary(mesh, i_bc->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::inflow: { + throw NotImplementedError("inflow boundary condition"); + break; + } + default: { + std::ostringstream os; + os << "invalid boundary condition for advection: " << *i_bc; + throw NotImplementedError("inflow boundary condition"); + } + } + } + } + template <typename CellDataType> - void _remapOne(const CellValue<const double>& step_Vj, CellDataType& old_q); + void _remapOne(const CellValue<const double>& step_Vj, + const std::vector<BoundaryConditionVariant>& q_bc_list, + CellDataType& old_q); void _remapAllQuantities(); public: std::vector<std::shared_ptr<const DiscreteFunctionVariant>> // - remap(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& quantities); + remap(const std::vector<std::shared_ptr<const VariableBCDescriptor>>& quantity_list_with_bc); FluxingAdvectionSolver(const std::shared_ptr<const IMesh> i_old_mesh, const std::shared_ptr<const IMesh> i_new_mesh) : m_old_mesh{std::dynamic_pointer_cast<const MeshType>(i_old_mesh)}, @@ -102,16 +206,16 @@ FluxingAdvectionSolver<Dimension>::_computeDonorCells(FaceValue<const double> al FaceValue<CellId> donnor_cell{m_old_mesh->connectivity()}; parallel_for( m_new_mesh->numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) { - const auto& face_to_cell = face_to_cell_matrix[face_id]; - if (face_to_cell.size() == 1) { - donnor_cell[face_id] = face_to_cell[0]; + const auto& face_to_cell = face_to_cell_matrix[face_id]; + const size_t i_face_in_cell = face_local_number_in_their_cells[face_id][0]; + const CellId cell_id = face_to_cell[0]; + if (cell_face_is_reversed[cell_id][i_face_in_cell] xor (algebraic_fluxing_volumes[face_id] <= 0)) { + donnor_cell[face_id] = cell_id; } else { - const CellId cell_id = face_to_cell[0]; - const size_t i_face_in_cell = face_local_number_in_their_cells[face_id][0]; - if (cell_face_is_reversed[cell_id][i_face_in_cell] xor (algebraic_fluxing_volumes[face_id] <= 0)) { - donnor_cell[face_id] = cell_id; - } else { + if (face_to_cell.size() == 2) { donnor_cell[face_id] = face_to_cell[1]; + } else { + donnor_cell[face_id] = std::numeric_limits<CellId::base_type>::max(); } } }); @@ -128,14 +232,20 @@ FluxingAdvectionSolver<1>::_computeDonorCells(FaceValue<const double> algebraic_ const auto face_to_cell_matrix = m_new_mesh->connectivity().faceToCellMatrix(); const auto cell_to_face_matrix = m_new_mesh->connectivity().cellToFaceMatrix(); + const auto face_local_number_in_their_cells = m_new_mesh->connectivity().faceLocalNumbersInTheirCells(); + FaceValue<CellId> donnor_cell{m_old_mesh->connectivity()}; parallel_for( m_new_mesh->numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) { const auto& face_to_cell = face_to_cell_matrix[face_id]; + const CellId cell_id = face_to_cell[0]; if (face_to_cell.size() == 1) { - donnor_cell[face_id] = face_to_cell[0]; + if ((algebraic_fluxing_volumes[face_id] <= 0) xor (cell_to_face_matrix[cell_id][1] == face_id)) { + donnor_cell[face_id] = std::numeric_limits<CellId::base_type>::max(); + } else { + donnor_cell[face_id] = cell_id; + } } else { - const CellId cell_id = face_to_cell[0]; if ((algebraic_fluxing_volumes[face_id] <= 0) xor (cell_to_face_matrix[cell_id][0] == face_id)) { donnor_cell[face_id] = cell_id; } else { @@ -299,8 +409,9 @@ FluxingAdvectionSolver<Dimension>::_computeCycleNumber(FaceValue<double> fluxing CellValue<size_t> ratio(m_old_mesh->connectivity()); parallel_for( - m_old_mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { ratio[cell_id] = std::ceil(total_negative_flux[cell_id] / Vj[cell_id]); }); + m_old_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + ratio[cell_id] = (1. / 0.6) * std::ceil(total_negative_flux[cell_id] / Vj[cell_id]); + }); synchronize(ratio); size_t number_of_cycles = max(ratio); @@ -329,8 +440,12 @@ FluxingAdvectionSolver<Dimension>::_computeGeometricalData() template <size_t Dimension> template <typename CellDataType> void -FluxingAdvectionSolver<Dimension>::_remapOne(const CellValue<const double>& step_Vj, CellDataType& old_q) +FluxingAdvectionSolver<Dimension>::_remapOne(const CellValue<const double>& step_Vj, + const std::vector<BoundaryConditionVariant>& q_bc_list, + CellDataType& old_q) { + using DataType = std::decay_t<typename CellDataType::data_type>; + static_assert(is_item_value_v<CellDataType> or is_item_array_v<CellDataType>, "invalid data type"); const auto cell_to_face_matrix = m_new_mesh->connectivity().cellToFaceMatrix(); @@ -353,6 +468,7 @@ FluxingAdvectionSolver<Dimension>::_remapOne(const CellValue<const double>& step }); } + // First we deal with inner faces parallel_for( m_new_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { const auto& cell_to_face = cell_to_face_matrix[cell_id]; @@ -384,6 +500,97 @@ FluxingAdvectionSolver<Dimension>::_remapOne(const CellValue<const double>& step } }); + // Now we deal with boundary faces + for (const auto& bc_descriptor : q_bc_list) { + std::visit( + [&](auto&& bc) { + using TypeOfBC = std::decay_t<decltype(bc)>; + + if constexpr (std::is_same_v<TypeOfBC, SymmetryBoundaryCondition>) { + 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]; + const double fluxing_volume = m_cycle_fluxing_volume[face_id]; + const CellId face_cell_id = face_to_cell_matrix[face_id][0]; + if (fluxing_volume > 1E-12 * step_Vj[face_cell_id]) { + std::ostringstream error_msg; + error_msg << "invalid symmetry for face " << face_id + << " (number=" << m_old_mesh->connectivity().faceNumber()[face_id] << ")\n" + << "face has non zero fluxing volume " << fluxing_volume + << " (cell volume = " << step_Vj[face_cell_id] << ")\n"; + throw NormalError(error_msg.str()); + } + } + } else if constexpr (std::is_same_v<TypeOfBC, 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]; + const CellId cell_id = m_donnor_cell[face_id]; + const double fluxing_volume = m_cycle_fluxing_volume[face_id]; + if (cell_id != std::numeric_limits<CellId::base_type>::max()) { + if constexpr (is_item_array_v<CellDataType>) { + for (size_t i = 0; i < new_q[cell_id].size(); ++i) { + new_q[cell_id][i] -= fluxing_volume * old_q[cell_id][i]; + } + } else { + new_q[cell_id] -= fluxing_volume * old_q[cell_id]; + } + } else { + const CellId face_cell_id = face_to_cell_matrix[face_id][0]; + if (fluxing_volume > 1E-12 * step_Vj[face_cell_id]) { + std::ostringstream error_msg; + error_msg << "invalid outflow for face " << face_id + << " (number=" << m_old_mesh->connectivity().faceNumber()[face_id] << ")" + << "face has inflow fluxing volume " << fluxing_volume + << " (cell volume = " << step_Vj[face_cell_id] << ")\n"; + throw NormalError(error_msg.str()); + } + } + } + } else if constexpr (std::is_same_v<TypeOfBC, InflowValueBoundaryCondition<DataType>>) { + if constexpr (is_item_value_v<CellDataType>) { + auto face_list = bc.faceList(); + 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 CellId cell_id = m_donnor_cell[face_id]; + const double fluxing_volume = m_cycle_fluxing_volume[face_id]; + if (cell_id == std::numeric_limits<CellId::base_type>::max()) { + if constexpr (is_item_value_v<CellDataType>) { + Assert(face_to_cell_matrix[face_id].size() == 1, "boundary face must be connected to a single cell"); + const CellId face_cell_id = face_to_cell_matrix[face_id][0]; + new_q[face_cell_id] += fluxing_volume * value_list[i_face]; + } else { + throw UnexpectedError("invalid boundary condition for fluxing advection"); + } + } else { + const CellId face_cell_id = face_to_cell_matrix[face_id][0]; + if (fluxing_volume > 1E-12 * step_Vj[face_cell_id]) { + std::ostringstream error_msg; + error_msg << "invalid inflow for face " << face_id + << " (number=" << m_old_mesh->connectivity().faceNumber()[face_id] << ")" + << "face has outflow fluxing volume " << fluxing_volume + << " (cell volume = " << step_Vj[face_cell_id] << ")\n"; + throw NormalError(error_msg.str()); + } + } + } + } else { + throw UnexpectedError("invalid boundary condition for fluxing advection"); + } + } else if constexpr (std::is_same_v<TypeOfBC, InflowArrayBoundaryCondition>) { + if constexpr (is_item_array_v<CellDataType>) { + throw NotImplementedError("advect array"); + } else { + throw UnexpectedError("invalid boundary condition for fluxing advection"); + } + } else { + throw UnexpectedError("invalid boundary condition for fluxing advection"); + } + }, + bc_descriptor); + } + synchronize(new_q); old_q = new_q; } @@ -399,10 +606,12 @@ FluxingAdvectionSolver<Dimension>::_remapAllQuantities() const CellValue<const double> old_Vj = old_mesh_data.Vj(); const CellValue<double> step_Vj = copy(old_Vj); - for (size_t jstep = 0; jstep < m_number_of_cycles; ++jstep) { - for (auto& remapped_q : m_remapped_list) { - std::visit([&](auto&& old_q) { this->_remapOne(step_Vj, old_q); }, remapped_q); + for (size_t i = 0; i < m_remapped_list.size(); ++i) { + Assert(m_remapped_list.size() == m_boundary_condition_list.size()); + auto& remapped_q = m_remapped_list[i]; + auto& q_bc_list = m_boundary_condition_list[i]; + std::visit([&](auto&& old_q) { this->_remapOne(step_Vj, q_bc_list, old_q); }, remapped_q); } parallel_for( @@ -452,26 +661,32 @@ FluxingAdvectionSolver<Dimension>::_remapAllQuantities() template <size_t Dimension> std::vector<std::shared_ptr<const DiscreteFunctionVariant>> FluxingAdvectionSolver<Dimension>::remap( - const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& quantity_list) + const std::vector<std::shared_ptr<const VariableBCDescriptor>>& quantity_list_with_bc) { - for (auto&& variable_v : quantity_list) { + m_boundary_condition_list.resize(quantity_list_with_bc.size()); + for (size_t i = 0; i < quantity_list_with_bc.size(); ++i) { + const auto& quantity_v_with_bc = quantity_list_with_bc[i]; + const auto& quantity_v = quantity_v_with_bc->discreteFunctionVariant(); + const auto& bc_list = quantity_v_with_bc->bcDescriptorList(); std::visit( [&](auto&& variable) { using DiscreteFunctionT = std::decay_t<decltype(variable)>; if constexpr (std::is_same_v<MeshType, typename DiscreteFunctionT::MeshType>) { this->_storeValues(variable); + using DataType = std::decay_t<typename DiscreteFunctionT::data_type>; + this->_storeValueBCList<DataType>(i, bc_list); } else { throw UnexpectedError("incompatible mesh types"); } }, - variable_v->discreteFunction()); + quantity_v->discreteFunction()); } this->_remapAllQuantities(); std::vector<std::shared_ptr<const DiscreteFunctionVariant>> new_variables; - for (size_t i = 0; i < quantity_list.size(); ++i) { + for (size_t i = 0; i < quantity_list_with_bc.size(); ++i) { std::visit( [&](auto&& variable) { using DiscreteFunctionT = std::decay_t<decltype(variable)>; @@ -491,16 +706,101 @@ FluxingAdvectionSolver<Dimension>::remap( throw UnexpectedError("incompatible mesh types"); } }, - quantity_list[i]->discreteFunction()); + quantity_list_with_bc[i]->discreteFunctionVariant()->discreteFunction()); } return new_variables; } +template <size_t Dimension> +template <typename DataType> +class FluxingAdvectionSolver<Dimension>::InflowValueBoundaryCondition +{ + private: + const MeshFaceBoundary<Dimension> m_mesh_face_boundary; + + Array<const DataType> m_value_list; + + public: + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + const Array<const DataType>& + valueList() const + { + return m_value_list; + } + + InflowValueBoundaryCondition(const MeshFaceBoundary<Dimension>& mesh_face_boundary, Array<const DataType> value_list) + : m_mesh_face_boundary(mesh_face_boundary), m_value_list(value_list) + { + ; + } + + ~InflowValueBoundaryCondition() = default; +}; + +template <size_t Dimension> +class FluxingAdvectionSolver<Dimension>::InflowArrayBoundaryCondition +{ +}; + +template <size_t Dimension> +class FluxingAdvectionSolver<Dimension>::OutflowBoundaryCondition +{ + private: + const MeshFaceBoundary<Dimension> m_mesh_face_boundary; + + public: + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + OutflowBoundaryCondition(const MeshFaceBoundary<Dimension>& mesh_face_boundary) + : m_mesh_face_boundary(mesh_face_boundary) + { + ; + } + + ~OutflowBoundaryCondition() = default; +}; + +template <size_t Dimension> +class FluxingAdvectionSolver<Dimension>::SymmetryBoundaryCondition +{ + private: + const MeshFlatFaceBoundary<Dimension> m_mesh_flat_face_boundary; + + public: + const Array<const FaceId>& + faceList() const + { + return m_mesh_flat_face_boundary.faceList(); + } + + SymmetryBoundaryCondition(const MeshFlatFaceBoundary<Dimension>& mesh_flat_face_boundary) + : m_mesh_flat_face_boundary(mesh_flat_face_boundary) + { + ; + } + + ~SymmetryBoundaryCondition() = default; +}; + std::vector<std::shared_ptr<const DiscreteFunctionVariant>> advectByFluxing(const std::shared_ptr<const IMesh> i_new_mesh, - const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& remapped_variables) + const std::vector<std::shared_ptr<const VariableBCDescriptor>>& remapped_variables_with_bc) { + std::vector<std::shared_ptr<const DiscreteFunctionVariant>> remapped_variables; + for (auto i_remapped_var_with_bc : remapped_variables_with_bc) { + remapped_variables.push_back(i_remapped_var_with_bc->discreteFunctionVariant()); + } + if (not hasSameMesh(remapped_variables)) { throw NormalError("remapped quantities are not defined on the same mesh"); } @@ -509,13 +809,13 @@ advectByFluxing(const std::shared_ptr<const IMesh> i_new_mesh, switch (i_old_mesh->dimension()) { case 1: { - return FluxingAdvectionSolver<1>{i_old_mesh, i_new_mesh}.remap(remapped_variables); + return FluxingAdvectionSolver<1>{i_old_mesh, i_new_mesh}.remap(remapped_variables_with_bc); } case 2: { - return FluxingAdvectionSolver<2>{i_old_mesh, i_new_mesh}.remap(remapped_variables); + return FluxingAdvectionSolver<2>{i_old_mesh, i_new_mesh}.remap(remapped_variables_with_bc); } case 3: { - return FluxingAdvectionSolver<3>{i_old_mesh, i_new_mesh}.remap(remapped_variables); + return FluxingAdvectionSolver<3>{i_old_mesh, i_new_mesh}.remap(remapped_variables_with_bc); } default: { throw UnexpectedError("Invalid mesh dimension"); diff --git a/src/scheme/FluxingAdvectionSolver.hpp b/src/scheme/FluxingAdvectionSolver.hpp index 05dce5055..2cbb653cb 100644 --- a/src/scheme/FluxingAdvectionSolver.hpp +++ b/src/scheme/FluxingAdvectionSolver.hpp @@ -3,6 +3,7 @@ #include <language/utils/FunctionSymbolId.hpp> #include <scheme/DiscreteFunctionVariant.hpp> +#include <scheme/VariableBCDescriptor.hpp> #include <vector> @@ -10,4 +11,8 @@ std::vector<std::shared_ptr<const DiscreteFunctionVariant>> advectByFluxing( const std::shared_ptr<const IMesh> new_mesh, const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& remapped_variables); +std::vector<std::shared_ptr<const DiscreteFunctionVariant>> advectByFluxing( + const std::shared_ptr<const IMesh> new_mesh, + const std::vector<std::shared_ptr<const VariableBCDescriptor>>& remapped_variables_with_bc); + #endif // FLUXING_ADVECION_SOLVER_HPP -- GitLab