From 1c63552656cf03543e8b1ad1f09a3c38ac1268aa Mon Sep 17 00:00:00 2001
From: Axelle <axelle.drouard@orange.fr>
Date: Thu, 14 Nov 2024 16:08:59 +0100
Subject: [PATCH] Symmetry boundary conditions

---
 src/scheme/EulerKineticSolver2D.cpp | 218 ++++++++++++++++++++++++++--
 1 file changed, 204 insertions(+), 14 deletions(-)

diff --git a/src/scheme/EulerKineticSolver2D.cpp b/src/scheme/EulerKineticSolver2D.cpp
index d7df345b4..470663f98 100644
--- a/src/scheme/EulerKineticSolver2D.cpp
+++ b/src/scheme/EulerKineticSolver2D.cpp
@@ -4,6 +4,7 @@
 #include <language/utils/InterpolateItemArray.hpp>
 #include <mesh/Connectivity.hpp>
 #include <mesh/Mesh.hpp>
+#include <mesh/MeshFlatFaceBoundary.hpp>
 #include <mesh/MeshFlatNodeBoundary.hpp>
 #include <mesh/MeshNodeBoundary.hpp>
 #include <mesh/MeshVariant.hpp>
@@ -228,6 +229,8 @@ class EulerKineticSolver2D
   const NodeValuePerCell<const TinyVector<Dimension>> njr = MeshDataManager::instance().getMeshData(m_mesh).njr();
   const NodeValuePerFace<const TinyVector<Dimension>> Nlr = MeshDataManager::instance().getMeshData(m_mesh).Nlr();
   const NodeValuePerFace<const TinyVector<Dimension>> nlr = MeshDataManager::instance().getMeshData(m_mesh).nlr();
+  const FaceValue<const TinyVector<Dimension>> nl         = MeshDataManager::instance().getMeshData(m_mesh).nl();
+  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();
@@ -245,7 +248,8 @@ class EulerKineticSolver2D
       switch (bc_descriptor->type()) {
       case IBoundaryConditionDescriptor::Type::symmetry: {
         bc_list.emplace_back(
-          SymmetryBoundaryCondition(getMeshFlatNodeBoundary(mesh, bc_descriptor->boundaryDescriptor())));
+          SymmetryBoundaryCondition(getMeshFlatNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()),
+                                    getMeshFlatFaceBoundary(mesh, bc_descriptor->boundaryDescriptor())));
         break;
       }
       case IBoundaryConditionDescriptor::Type::inflow_list: {
@@ -469,9 +473,6 @@ class EulerKineticSolver2D
               if (li_nlr > 0) {
                 Fr[node_id][i_face][i_wave] += Fn[cell_id][i_wave] * li_nlr;
                 sum += li_nlr;
-                // std::cout << "i_wave = " << i_wave << ", node_id = " << node_id << ", face_id = " << face_id << ",
-                // cell_id = " << cell_id << ", lambda = " << m_lambda_vector[i_wave] << ", nlr = " << n_face << ", njr
-                // = " << n_node << "\n";
               }
             }
             if (sum != 0) {
@@ -484,6 +485,139 @@ class EulerKineticSolver2D
     return Fr;
   }
 
+  FaceArray<double>
+  compute_Flux1_face(const DiscreteFunctionP0Vector<const double> Fn)
+  {
+    const size_t nb_waves = m_lambda_vector.size();
+    FaceArray<double> 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();
+
+    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];
+
+          Fl[face_id][i_wave] = 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 = 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] += Fn[cell_id][i_wave];
+            }
+          }
+        }
+      });
+
+    return Fl;
+  }
+
+  void
+  apply_scalar_bc(FaceArray<double> Fl_rho,
+                  FaceArray<double> Fl_rho_u1,
+                  FaceArray<double> Fl_rho_u2,
+                  FaceArray<double> Fl_rho_E,
+                  const DiscreteFunctionP0<const double> rho,
+                  const DiscreteFunctionP0<const double> rho_u1,
+                  const DiscreteFunctionP0<const double> rho_u2,
+                  const DiscreteFunctionP0<const double> 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 i = 0; i < nb_waves; ++i) {
+      for (size_t d = 0; d < MeshType::Dimension; ++d) {
+        inv_S[d] += std::pow(m_lambda_vector[i][d], 2);
+      }
+    }
+    for (size_t d = 0; d < MeshType::Dimension; ++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_u1[cell_id], rho_u2[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]) *
+                                         (rho_u1[cell_id] * rho_u1[cell_id] + rho_u2[cell_id] * rho_u2[cell_id]);
+                    double p = (m_gamma - 1) * rho_e;
+
+                    TinyVector<Dimension> A_rho_prime = rho_uj_prime;
+                    TinyVector<Dimension> A_rho_u1_prime{rho_uj_prime[0] * rho_uj_prime[0] / rhoj_prime + p,
+                                                         rho_uj_prime[0] * rho_uj_prime[1] / rhoj_prime};
+                    TinyVector<Dimension> A_rho_u2_prime{rho_uj_prime[0] * rho_uj_prime[1] / rhoj_prime,
+                                                         rho_uj_prime[1] * rho_uj_prime[1] / rhoj_prime + p};
+                    TinyVector<Dimension> A_rho_E_prime = (rho_Ej_prime + p) / rhoj_prime * rho_uj_prime;
+
+                    double Fn_rho_prime = rhoj_prime / nb_waves +
+                                          inv_S[0] * m_lambda_vector[i_wave][0] * A_rho_prime[0] +
+                                          inv_S[1] * m_lambda_vector[i_wave][1] * A_rho_prime[1];
+                    double Fn_rho_u1_prime = rho_uj_prime[0] / nb_waves +
+                                             inv_S[0] * m_lambda_vector[i_wave][0] * A_rho_u1_prime[0] +
+                                             inv_S[1] * m_lambda_vector[i_wave][1] * A_rho_u1_prime[1];
+                    double Fn_rho_u2_prime = rho_uj_prime[1] / nb_waves +
+                                             inv_S[0] * m_lambda_vector[i_wave][0] * A_rho_u2_prime[0] +
+                                             inv_S[1] * m_lambda_vector[i_wave][1] * A_rho_u2_prime[1];
+                    double Fn_rho_E_prime = rho_Ej_prime / nb_waves +
+                                            inv_S[0] * m_lambda_vector[i_wave][0] * A_rho_E_prime[0] +
+                                            inv_S[1] * m_lambda_vector[i_wave][1] * A_rho_E_prime[1];
+
+                    Fl_rho[face_id][i_wave] += Fn_rho_prime;
+                    Fl_rho_u1[face_id][i_wave] += Fn_rho_u1_prime;
+                    Fl_rho_u2[face_id][i_wave] += Fn_rho_u2_prime;
+                    Fl_rho_E[face_id][i_wave] += Fn_rho_E_prime;
+                  }
+                }
+              }
+            }
+          }
+        },
+        bc_v);
+    }
+  }
+
   DiscreteFunctionP0Vector<double>
   compute_deltaLFn(NodeArray<double> Fr)
   {
@@ -558,6 +692,36 @@ class EulerKineticSolver2D
     return deltaLFn;
   }
 
+  DiscreteFunctionP0Vector<double>
+  compute_deltaLFn_face(FaceArray<double> Fl)
+  {
+    const size_t nb_waves = m_lambda_vector.size();
+    DiscreteFunctionP0Vector<double> deltaLFn(p_mesh, nb_waves);
+
+    const auto& cell_to_face_matrix   = p_mesh->connectivity().cellToFaceMatrix();
+    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 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] += Fl[face_id][i_wave] * li_Nl;
+          }
+        }
+      });
+    return deltaLFn;
+  }
+
   CellValue<bool>
   getBoundaryCells(const BoundaryConditionList& bc_list)
   {
@@ -668,20 +832,32 @@ class EulerKineticSolver2D
     // NodeArray<double> Fr_rho_u2 = compute_Flux1(Fn_rho_u2);
     // NodeArray<double> Fr_rho_E  = compute_Flux1(Fn_rho_E);
 
-    FaceArrayPerNode<double> Fr_rho    = compute_Flux1_eucchlyd(Fn_rho);
-    FaceArrayPerNode<double> Fr_rho_u1 = compute_Flux1_eucchlyd(Fn_rho_u1);
-    FaceArrayPerNode<double> Fr_rho_u2 = compute_Flux1_eucchlyd(Fn_rho_u2);
-    FaceArrayPerNode<double> Fr_rho_E  = compute_Flux1_eucchlyd(Fn_rho_E);
+    // FaceArrayPerNode<double> Fr_rho    = compute_Flux1_eucchlyd(Fn_rho);
+    // FaceArrayPerNode<double> Fr_rho_u1 = compute_Flux1_eucchlyd(Fn_rho_u1);
+    // FaceArrayPerNode<double> Fr_rho_u2 = compute_Flux1_eucchlyd(Fn_rho_u2);
+    // FaceArrayPerNode<double> Fr_rho_E  = compute_Flux1_eucchlyd(Fn_rho_E);
+
+    FaceArray<double> Fr_rho    = compute_Flux1_face(Fn_rho);
+    FaceArray<double> Fr_rho_u1 = compute_Flux1_face(Fn_rho_u1);
+    FaceArray<double> Fr_rho_u2 = compute_Flux1_face(Fn_rho_u2);
+    FaceArray<double> Fr_rho_E  = compute_Flux1_face(Fn_rho_E);
+
+    apply_scalar_bc(Fr_rho, Fr_rho_u1, Fr_rho_u2, Fr_rho_E, rho, rho_u1, rho_u2, rho_E, bc_list);
 
     // DiscreteFunctionP0Vector<double> deltaLFn_rho    = compute_deltaLFn(Fr_rho);
     // DiscreteFunctionP0Vector<double> deltaLFn_rho_u1 = compute_deltaLFn(Fr_rho_u1);
     // DiscreteFunctionP0Vector<double> deltaLFn_rho_u2 = compute_deltaLFn(Fr_rho_u2);
     // DiscreteFunctionP0Vector<double> deltaLFn_rho_E  = compute_deltaLFn(Fr_rho_E);
 
-    DiscreteFunctionP0Vector<double> deltaLFn_rho    = compute_deltaLFn_eucclhyd(Fr_rho);
-    DiscreteFunctionP0Vector<double> deltaLFn_rho_u1 = compute_deltaLFn_eucclhyd(Fr_rho_u1);
-    DiscreteFunctionP0Vector<double> deltaLFn_rho_u2 = compute_deltaLFn_eucclhyd(Fr_rho_u2);
-    DiscreteFunctionP0Vector<double> deltaLFn_rho_E  = compute_deltaLFn_eucclhyd(Fr_rho_E);
+    // DiscreteFunctionP0Vector<double> deltaLFn_rho    = compute_deltaLFn_eucclhyd(Fr_rho);
+    // DiscreteFunctionP0Vector<double> deltaLFn_rho_u1 = compute_deltaLFn_eucclhyd(Fr_rho_u1);
+    // DiscreteFunctionP0Vector<double> deltaLFn_rho_u2 = compute_deltaLFn_eucclhyd(Fr_rho_u2);
+    // DiscreteFunctionP0Vector<double> deltaLFn_rho_E  = compute_deltaLFn_eucclhyd(Fr_rho_E);
+
+    DiscreteFunctionP0Vector<double> deltaLFn_rho    = compute_deltaLFn_face(Fr_rho);
+    DiscreteFunctionP0Vector<double> deltaLFn_rho_u1 = compute_deltaLFn_face(Fr_rho_u1);
+    DiscreteFunctionP0Vector<double> deltaLFn_rho_u2 = compute_deltaLFn_face(Fr_rho_u2);
+    DiscreteFunctionP0Vector<double> deltaLFn_rho_E  = compute_deltaLFn_face(Fr_rho_E);
 
     const CellArray<const TinyVector<Dimension>> APFn = getA(rho, rho_u1, rho_u2, rho_E);
     const DiscreteFunctionP0<TinyVector<Dimension>> APFn_rho{p_mesh};
@@ -866,6 +1042,7 @@ class EulerKineticSolver2D<MeshType>::SymmetryBoundaryCondition
 
  private:
   const MeshFlatNodeBoundary<MeshType> m_mesh_flat_node_boundary;
+  const MeshFlatFaceBoundary<MeshType> m_mesh_flat_face_boundary;
 
  public:
   const Rd&
@@ -886,8 +1063,21 @@ class EulerKineticSolver2D<MeshType>::SymmetryBoundaryCondition
     return m_mesh_flat_node_boundary.nodeList();
   }
 
-  SymmetryBoundaryCondition(const MeshFlatNodeBoundary<MeshType>& mesh_flat_node_boundary)
-    : m_mesh_flat_node_boundary(mesh_flat_node_boundary)
+  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)
   {
     ;
   }
-- 
GitLab