From 90701aa9381d5ed345c1524970e0b306b1b551cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Sun, 21 May 2023 22:23:52 +0200
Subject: [PATCH] Sets inflow boundary conditions for P0 vectors

---
 src/scheme/FluxingAdvectionSolver.cpp | 101 +++++++++++++++++++++-----
 1 file changed, 84 insertions(+), 17 deletions(-)

diff --git a/src/scheme/FluxingAdvectionSolver.cpp b/src/scheme/FluxingAdvectionSolver.cpp
index 97aad4bb8..264ecef04 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/InterpolateItemArray.hpp>
 #include <language/utils/InterpolateItemValue.hpp>
 #include <mesh/Connectivity.hpp>
 #include <mesh/IMesh.hpp>
@@ -125,9 +126,9 @@ class FluxingAdvectionSolver
         break;
       }
       default: {
-        std::ostringstream os;
-        os << "invalid boundary condition for advection: " << *i_bc;
-        throw NotImplementedError("inflow boundary condition");
+        std::ostringstream error_msg;
+        error_msg << "invalid boundary condition for advection: " << *i_bc;
+        throw NormalError(error_msg.str());
       }
       }
     }
@@ -152,13 +153,26 @@ class FluxingAdvectionSolver
         break;
       }
       case IBoundaryConditionDescriptor::Type::inflow: {
-        throw NotImplementedError("inflow boundary condition");
+        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();
+        Table<const double> array_list =
+          InterpolateItemArray<double(Rd)>::template interpolate<ItemType::face>({inflow_bc_descriptor
+                                                                                    .functionSymbolId()},
+                                                                                 xl, mesh_face_boundary.faceList());
+
+        m_boundary_condition_list[i_quantity].emplace_back(
+          InflowArrayBoundaryCondition{mesh_face_boundary, array_list});
         break;
       }
       default: {
-        std::ostringstream os;
-        os << "invalid boundary condition for advection: " << *i_bc;
-        throw NotImplementedError("inflow boundary condition");
+        std::ostringstream error_msg;
+        error_msg << "invalid boundary condition for advection: " << *i_bc;
+        throw NormalError(error_msg.str());
       }
       }
     }
@@ -556,13 +570,9 @@ FluxingAdvectionSolver<Dimension>::_remapOne(const CellValue<const double>& step
               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");
-                }
+                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 {
                 const CellId face_cell_id = face_to_cell_matrix[face_id][0];
                 if (fluxing_volume > 1E-12 * step_Vj[face_cell_id]) {
@@ -580,7 +590,33 @@ FluxingAdvectionSolver<Dimension>::_remapOne(const CellValue<const double>& step
           }
         } else if constexpr (std::is_same_v<TypeOfBC, InflowArrayBoundaryCondition>) {
           if constexpr (is_item_array_v<CellDataType>) {
-            throw NotImplementedError("advect array");
+            auto face_list  = bc.faceList();
+            auto array_list = bc.arrayList();
+            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()) {
+                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];
+                auto new_array            = new_q[face_cell_id];
+                const auto& bc_array      = array_list[i_face];
+
+                for (size_t i = 0; i < new_array.size(); ++i) {
+                  new_array[i] += fluxing_volume * bc_array[i];
+                }
+              } 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");
           }
@@ -673,8 +709,14 @@ FluxingAdvectionSolver<Dimension>::remap(
         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);
+          if constexpr (is_discrete_function_P0_v<DiscreteFunctionT>) {
+            using DataType = std::decay_t<typename DiscreteFunctionT::data_type>;
+            this->_storeValueBCList<DataType>(i, bc_list);
+          } else if constexpr (is_discrete_function_P0_vector_v<DiscreteFunctionT>) {
+            this->_storeArrayBCList(i, bc_list);
+          } else {
+            throw UnexpectedError("invalid discrete function type");
+          }
         } else {
           throw UnexpectedError("incompatible mesh types");
         }
@@ -746,6 +788,31 @@ class FluxingAdvectionSolver<Dimension>::InflowValueBoundaryCondition
 template <size_t Dimension>
 class FluxingAdvectionSolver<Dimension>::InflowArrayBoundaryCondition
 {
+ private:
+  const MeshFaceBoundary<Dimension> m_mesh_face_boundary;
+
+  Table<const double> m_array_list;
+
+ public:
+  const Array<const FaceId>&
+  faceList() const
+  {
+    return m_mesh_face_boundary.faceList();
+  }
+
+  const Table<const double>&
+  arrayList() const
+  {
+    return m_array_list;
+  }
+
+  InflowArrayBoundaryCondition(const MeshFaceBoundary<Dimension>& mesh_face_boundary, Table<const double> array_list)
+    : m_mesh_face_boundary(mesh_face_boundary), m_array_list(array_list)
+  {
+    ;
+  }
+
+  ~InflowArrayBoundaryCondition() = default;
 };
 
 template <size_t Dimension>
-- 
GitLab