Skip to content
Snippets Groups Projects
Select Git revision
  • a143de698384b1aa89457bba0ccc0722de419ecd
  • develop default protected
  • feature/variational-hydro
  • origin/stage/bouguettaia
  • feature/gmsh-reader
  • feature/reconstruction
  • save_clemence
  • feature/kinetic-schemes
  • feature/local-dt-fsi
  • feature/composite-scheme-sources
  • feature/composite-scheme-other-fluxes
  • feature/serraille
  • feature/composite-scheme
  • hyperplastic
  • feature/polynomials
  • feature/gks
  • feature/implicit-solver-o2
  • feature/coupling_module
  • feature/implicit-solver
  • feature/merge-local-dt-fsi
  • master protected
  • v0.5.0 protected
  • v0.4.1 protected
  • v0.4.0 protected
  • v0.3.0 protected
  • v0.2.0 protected
  • v0.1.0 protected
  • Kidder
  • v0.0.4 protected
  • v0.0.3 protected
  • v0.0.2 protected
  • v0 protected
  • v0.0.1 protected
33 results

FluxingAdvectionSolver.cpp

Blame
  • FluxingAdvectionSolver.cpp 15.67 KiB
    #include <scheme/FluxingAdvectionSolver.hpp>
    
    #include <language/utils/EvaluateAtPoints.hpp>
    #include <mesh/Connectivity.hpp>
    #include <mesh/IMesh.hpp>
    #include <mesh/Mesh.hpp>
    #include <mesh/MeshData.hpp>
    #include <mesh/MeshDataManager.hpp>
    #include <mesh/MeshFaceBoundary.hpp>
    #include <mesh/SubItemValuePerItem.hpp>
    #include <scheme/DiscreteFunctionP0.hpp>
    #include <scheme/DiscreteFunctionUtils.hpp>
    #include <scheme/IDiscreteFunctionDescriptor.hpp>
    template <size_t Dimension>
    class FluxingAdvectionSolver
    {
     private:
      using Rd = TinyVector<Dimension>;
    
      using MeshType     = Mesh<Connectivity<Dimension>>;
      using MeshDataType = MeshData<Dimension>;
    
      const std::shared_ptr<const MeshType> m_old_mesh;
      const std::shared_ptr<const MeshType> m_new_mesh;
    
     public:
      // CellValue<double>
      // compute_PFnp1(const DiscreteFunctionP0<Dimension, const double> F, const double& dt, const double& dx)
      // {
      //   CellValue<double> PFnp1{m_mesh.connectivity()};
    
      //   DiscreteFunctionP0<Dimension, double> deltaF  = compute_delta2Fn(F);
      //   DiscreteFunctionP0<Dimension, double> deltaF0 = compute_delta2Fn(m_Fn);
    
      //   for (CellId cell_id = 0; cell_id < m_mesh.numberOfCells(); ++cell_id) {
      //     PFnp1[cell_id] = m_Fn[cell_id][0] + m_Fn[cell_id][1] -
      //                      (0.5 * dt / dx) * m_lambda * (deltaF[cell_id][0] - deltaF[cell_id][1]) -
      //                      (0.5 * dt / dx) * m_lambda * (deltaF0[cell_id][0] - deltaF0[cell_id][1]);
      //   }
      //   return PFnp1;
      // }
    
      // DiscreteFunctionP0<Dimension, double>
      // apply(const double& dt, const double& eps)
      // {
      //   const DiscreteFunctionP0<Dimension, const double>& F0 = m_Fn;
      //   DiscreteFunctionP0<Dimension, double> Fnp1            = copy(F0);
      //   DiscreteFunctionP0<Dimension, double> deltaFn         = compute_delta2Fn(F0);
    
      //   for (size_t p = 0; p < 2; ++p) {
      //     CellId first_cell_id = 0;
      //     const double dx      = m_dx_table[first_cell_id];
    
      //     DiscreteFunctionP0<Dimension, double> deltaFnp1 = compute_delta2Fn(Fnp1);
    
      //     const CellValue<const double> PFnp1  = compute_PFnp1(Fnp1, dt, dx);
      //     const CellValue<const double> APFnp1 = getA(PFnp1);
      //     const CellArray<const double> MPFnp1 = compute_M(PFnp1, APFnp1);
      //     const CellValue<const double> PFn    = compute_PFn(F0);
      //     const CellValue<const double> APFn   = getA(PFn);
      //     const CellArray<const double> MPFn   = compute_M(PFn, APFn);
    
      //     for (CellId cell_id = 0; cell_id < m_mesh.numberOfCells(); ++cell_id) {
      //       Fnp1[cell_id][0] = 1. / (1 + 0.5 * dt / eps) *
      //                          ((0.5 * dt / eps) * MPFnp1[cell_id][0] + F0[cell_id][0] -
      //                           (0.5 * dt / dx) * m_lambda * (deltaFnp1[cell_id][0] + deltaFn[cell_id][0]) +
      //                           (0.5 * dt / eps) * (MPFn[cell_id][0] - F0[cell_id][0]));
      //       Fnp1[cell_id][1] = 1. / (1 + 0.5 * dt / eps) *
      //                          ((0.5 * dt / eps) * MPFnp1[cell_id][1] + F0[cell_id][1] +
      //                           (0.5 * dt / dx) * m_lambda * (deltaFnp1[cell_id][1] + deltaFn[cell_id][1]) +
      //                           (0.5 * dt / eps) * (MPFn[cell_id][1] - F0[cell_id][1]));
      //     }
      //   }
    
      //   return Fnp1;
      // }
    
      FaceValue<double> computeFluxVolume() const;
    
      FluxingAdvectionSolver(const std::shared_ptr<const MeshType> old_mesh, const std::shared_ptr<const MeshType> new_mesh)
        : m_old_mesh{old_mesh}, m_new_mesh{new_mesh}
      {}
    
      ~FluxingAdvectionSolver() = default;
    };
    
    template <>
    FaceValue<double>
    FluxingAdvectionSolver<1>::computeFluxVolume() const
    {
      throw NotImplementedError("Viens");
    }
    
    template <>
    FaceValue<double>
    FluxingAdvectionSolver<2>::computeFluxVolume() const
    {
      if (m_new_mesh->shared_connectivity() != m_old_mesh->shared_connectivity()) {
        throw NormalError("Old and new meshes must share the same connectivity");
      }
      // std::cout << " CARRE "
      // << "\n";
      // MeshDataType& old_mesh_data    = MeshDataManager::instance().getMeshData(*m_old_mesh);
      // MeshDataType& new_mesh_data    = MeshDataManager::instance().getMeshData(*m_new_mesh);
      const auto face_to_node_matrix = m_old_mesh->connectivity().faceToNodeMatrix();
      FaceValue<double> flux_volume(m_new_mesh->connectivity());
      parallel_for(
        m_new_mesh->numberOfFaces(), PUGS_LAMBDA(FaceId face_id) {
          const auto face_to_node = face_to_node_matrix[face_id];
          const Rd x0             = m_old_mesh->xr()[face_to_node[0]];
          const Rd x1             = m_old_mesh->xr()[face_to_node[1]];
          const Rd x2             = m_new_mesh->xr()[face_to_node[1]];
          const Rd x3             = m_new_mesh->xr()[face_to_node[0]];
          TinyMatrix<2> M(x2[0] - x0[0], x3[0] - x1[0], x2[1] - x0[1], x3[1] - x1[1]);
          flux_volume[face_id] = 0.5 * det(M);
          // std::cout << " x1 " << x1 << " x0 " << x0 << " x3 " << x3 << " x2 " << x2 << " flux volume "
          //           << flux_volume[face_id] << "\n";
        });
      return flux_volume;
    }
    
    template <>
    FaceValue<double>
    FluxingAdvectionSolver<3>::computeFluxVolume() const
    {
      throw NotImplementedError("ViensViensViens");
    }
    
    template <typename MeshType, typename DataType>
    auto
    calculateRemapCycles(const std::shared_ptr<const MeshType>& old_mesh,
                         [[maybe_unused]] const FaceValue<DataType>& fluxing_volumes)
    {
      constexpr size_t Dimension                               = MeshType::Dimension;
      const FaceValuePerCell<const bool> cell_face_is_reversed = old_mesh->connectivity().cellFaceIsReversed();
      const auto cell_to_face_matrix                           = old_mesh->connectivity().cellToFaceMatrix();
      const CellValue<double> total_negative_flux(old_mesh->connectivity());
      total_negative_flux.fill(0);
      parallel_for(
        old_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) {
          const auto& cell_to_face = cell_to_face_matrix[cell_id];
          for (size_t i_face = 0; i_face < cell_to_face.size(); ++i_face) {
            FaceId face_id = cell_to_face[i_face];
            double flux    = fluxing_volumes[face_id];
            if (!cell_face_is_reversed(cell_id, i_face)) {
              flux = -flux;
            }
            if (flux < 0) {
              total_negative_flux[cell_id] += flux;
            }
          }
          // std::cout << " cell_id " << cell_id << " total_negative_flux " << total_negative_flux[cell_id] << "\n";
        });
      MeshData<Dimension>& mesh_data   = MeshDataManager::instance().getMeshData(*old_mesh);
      const CellValue<const double> Vj = mesh_data.Vj();
      const CellValue<size_t> ratio(old_mesh->connectivity());
      parallel_for(
        old_mesh->numberOfCells(),
        PUGS_LAMBDA(CellId cell_id) { ratio[cell_id] = std::ceil(abs(total_negative_flux[cell_id]) / Vj[cell_id]); });
      size_t number_of_cycle = max(ratio);
      std::cout << " number_of_cycle " << number_of_cycle << "\n";
      return number_of_cycle;
    }
    
    template <typename MeshType, typename DataType>
    auto
    remapUsingFluxing(const std::shared_ptr<const MeshType>& old_mesh,
                      const std::shared_ptr<const MeshType>& new_mesh,
                      const FaceValue<double>& fluxing_volumes,
                      const size_t num,
                      const DiscreteFunctionP0<MeshType::Dimension, const DataType>& old_q)
    {
      constexpr size_t Dimension = MeshType::Dimension;
      //  const Connectivity<Dimension>& connectivity = new_mesh->connectivity();
      const FaceValuePerCell<const bool> cell_face_is_reversed = new_mesh->connectivity().cellFaceIsReversed();
      DiscreteFunctionP0<Dimension, DataType> new_q(new_mesh, copy(old_q.cellValues()));
      DiscreteFunctionP0<Dimension, DataType> previous_q(new_mesh, copy(old_q.cellValues()));
      const auto cell_to_face_matrix      = new_mesh->connectivity().cellToFaceMatrix();
      const auto face_to_cell_matrix      = new_mesh->connectivity().faceToCellMatrix();
      MeshData<Dimension>& old_mesh_data  = MeshDataManager::instance().getMeshData(*old_mesh);
      const CellValue<const double> oldVj = old_mesh_data.Vj();
      const CellValue<double> Vjstep(new_mesh->connectivity());
      parallel_for(
        new_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) {
          Vjstep[cell_id] = oldVj[cell_id];
          new_q[cell_id] *= oldVj[cell_id];
        });
      for (size_t jstep = 0; jstep < num; ++jstep) {
        // std::cout << " step " << jstep << "\n";
        parallel_for(
          new_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) {
            const auto& cell_to_face = cell_to_face_matrix[cell_id];
            for (size_t i_face = 0; i_face < cell_to_face.size(); ++i_face) {
              FaceId face_id = cell_to_face[i_face];
              double flux    = fluxing_volumes[face_id];
              if (!cell_face_is_reversed(cell_id, i_face)) {
                flux = -flux;
              }
              const auto& face_to_cell = face_to_cell_matrix[face_id];
              if (face_to_cell.size() == 1) {
                continue;
              }
              CellId other_cell_id = face_to_cell[0];
              if (other_cell_id == cell_id) {
                other_cell_id = face_to_cell[1];
              }
              DataType fluxed_q = previous_q[cell_id];
              if (flux > 0) {
                fluxed_q = previous_q[other_cell_id];
              }
              Vjstep[cell_id] += flux / num;
              fluxed_q *= flux / num;
              new_q[cell_id] += fluxed_q;
            }
            // std::cout << " old q " << old_q[cell_id] << " new q " << new_q[cell_id] << "\n";
          });
        parallel_for(
          new_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) {
            previous_q[cell_id] = 1 / Vjstep[cell_id] * new_q[cell_id];
            //     std::cout << " old q " << old_q[cell_id] << " new q " << previous_q[cell_id] << "\n";
            //     std::cout << " old vj " << oldVj[cell_id] << " new Vj " << Vjstep[cell_id] << "\n";
          });
      }
    
      MeshData<Dimension>& new_mesh_data  = MeshDataManager::instance().getMeshData(*new_mesh);
      const CellValue<const double> newVj = new_mesh_data.Vj();
      parallel_for(
        new_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { new_q[cell_id] = 1 / newVj[cell_id] * new_q[cell_id]; });
      // for (CellId cell_id = 0; cell_id < new_mesh->numberOfCells(); ++cell_id) {
      //   if (abs(newVj[cell_id] - Vjstep[cell_id]) > 1e-15) {
      //     std::cout << " cell " << cell_id << " newVj " << newVj[cell_id] << " Vjstep " << Vjstep[cell_id] << " diff "
      //               << abs(newVj[cell_id] - Vjstep[cell_id]) << "\n";
      //   }
      // }
      return new_q;
    }
    
    template <typename MeshType, typename DataType>
    auto
    remapUsingFluxing([[maybe_unused]] const std::shared_ptr<const MeshType>& old_mesh,
                      const std::shared_ptr<const MeshType>& new_mesh,
                      [[maybe_unused]] const FaceValue<double>& fluxing_volumes,
                      [[maybe_unused]] const size_t num,
                      const DiscreteFunctionP0Vector<MeshType::Dimension, const DataType>& old_q)
    {
      constexpr size_t Dimension = MeshType::Dimension;
      //  const Connectivity<Dimension>& connectivity = new_mesh->connectivity();
    
      DiscreteFunctionP0Vector<Dimension, DataType> new_q(new_mesh, copy(old_q.cellArrays()));
    
      throw NotImplementedError("DiscreteFunctionP0Vector");
    
      return new_q;
    }
    
    std::vector<std::shared_ptr<const DiscreteFunctionVariant>>
    FluxingAdvectionSolverHandler(const std::shared_ptr<const IMesh> new_mesh,
                                  const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& remapped_variables)
    {
      const std::shared_ptr<const IMesh> old_mesh = getCommonMesh(remapped_variables);
    
      if (not checkDiscretizationType({remapped_variables}, DiscreteFunctionType::P0)) {
        throw NormalError("acoustic solver expects P0 functions");
      }
    
      switch (old_mesh->dimension()) {
      case 1: {
        constexpr size_t Dimension = 1;
        using MeshType             = Mesh<Connectivity<Dimension>>;
    
        const std::shared_ptr<const MeshType> old_mesh0 = std::dynamic_pointer_cast<const MeshType>(old_mesh);
    
        const std::shared_ptr<const MeshType> new_mesh0 = std::dynamic_pointer_cast<const MeshType>(new_mesh);
    
        FluxingAdvectionSolver<Dimension> solver(old_mesh0, new_mesh0);
    
        FaceValue<double> fluxing_volumes(new_mesh0->connectivity());
        fluxing_volumes.fill(0);
    
        std::vector<std::shared_ptr<const DiscreteFunctionVariant>> new_variables;
    
        // for (auto&& variable_v : remapped_variables) {
        //   std::visit(
        //     [&](auto&& variable) {
        //       using DiscreteFunctionT = std::decay_t<decltype(variable)>;
        //       if constexpr (std::is_same_v<MeshType, typename DiscreteFunctionT::MeshType>) {
        //         remapUsingFluxing(new_mesh0, fluxing_volumes, variable);
        //       }
        //     },
        //     variable_v->discreteFunction());
        // }
    
        return remapped_variables;   // std::make_shared<std::vector<std::shared_ptr<const
                                     // DiscreteFunctionVariant>>>(new_variables);
      }
      case 2: {
        constexpr size_t Dimension = 2;
    
        using MeshType = Mesh<Connectivity<Dimension>>;
    
        const std::shared_ptr<const MeshType> old_mesh0 = std::dynamic_pointer_cast<const MeshType>(old_mesh);
    
        const std::shared_ptr<const MeshType> new_mesh0 = std::dynamic_pointer_cast<const MeshType>(new_mesh);
    
        FluxingAdvectionSolver<Dimension> solver(old_mesh0, new_mesh0);
    
        FaceValue<double> fluxing_volumes(new_mesh0->connectivity());
        fluxing_volumes.fill(0);
    
        std::vector<std::shared_ptr<const DiscreteFunctionVariant>> new_variables;
    
        // for (auto&& variable_v : remapped_variables) {
        //   std::visit(
        //     [&](auto&& variable) {
        //       using DiscreteFunctionT = std::decay_t<decltype(variable)>;
        //       if constexpr (std::is_same_v<MeshType, typename DiscreteFunctionT::MeshType>) {
        //         remapUsingFluxing(new_mesh0, fluxing_volumes, variable);
        //       }
        //     },
        //     variable_v->discreteFunction());
        // }
    
        return remapped_variables;   // std::make_shared<std::vector<std::shared_ptr<const
    
        // throw NotImplementedError("Fluxing advection solver not implemented in dimension 2");
      }
      case 3: {
        throw NotImplementedError("Fluxing advection solver not implemented in dimension 3");
      }
      default: {
        throw UnexpectedError("Invalid mesh dimension");
      }
      }
    }
    
    std::shared_ptr<const DiscreteFunctionVariant>
    FluxingAdvectionSolverHandler(const std::shared_ptr<const IMesh> new_mesh,
                                  const std::shared_ptr<const DiscreteFunctionVariant>& remapped_variable)
    {
      const std::shared_ptr<const IMesh> old_mesh = getCommonMesh({remapped_variable});
    
      if (not checkDiscretizationType({remapped_variable}, DiscreteFunctionType::P0)) {
        throw NormalError("acoustic solver expects P0 functions");
      }
    
      switch (old_mesh->dimension()) {
      case 1: {
        throw NormalError("Not yet implemented in 1d");
      }
      case 2: {
        constexpr size_t Dimension = 2;
        using MeshType             = Mesh<Connectivity<Dimension>>;
    
        const std::shared_ptr<const MeshType> old_mesh0 = std::dynamic_pointer_cast<const MeshType>(old_mesh);
    
        const std::shared_ptr<const MeshType> new_mesh0 = std::dynamic_pointer_cast<const MeshType>(new_mesh);
    
        FluxingAdvectionSolver<Dimension> solver(old_mesh0, new_mesh0);
    
        FaceValue<double> fluxing_volumes = solver.computeFluxVolume();
        size_t number_of_cycles           = calculateRemapCycles(old_mesh0, fluxing_volumes);
    
        DiscreteFunctionVariant new_variable = std::visit(
          [&](auto&& variable) -> DiscreteFunctionVariant {
            using DiscreteFunctionT = std::decay_t<decltype(variable)>;
            if constexpr (std::is_same_v<MeshType, typename DiscreteFunctionT::MeshType>) {
              return remapUsingFluxing(old_mesh0, new_mesh0, fluxing_volumes, number_of_cycles, variable);
            } else {
              throw UnexpectedError("incompatible mesh types");
            }
          },
          remapped_variable->discreteFunction());
    
        return std::make_shared<DiscreteFunctionVariant>(new_variable);
      }
      case 3: {
        throw NotImplementedError("Fluxing advection solver not implemented in dimension 3");
      }
      default: {
        throw UnexpectedError("Invalid mesh dimension");
      }
      }
    }