LCOV - code coverage report
Current view: top level - issm-precice - coupler.cpp (source / functions) Hit Total Coverage
Test: issm-precice-test-coverage.info Lines: 69 82 84.1 %
Date: 2025-07-12 23:40:24 Functions: 15 18 83.3 %

          Line data    Source code
       1             : // SPDX-FileCopyrightText: 2024 Daniel Abele <daniel.abele@dlr.de>
       2             : //
       3             : // SPDX-License-Identifier: BSD-3-Clause
       4             : 
       5             : #include "issm-precice/coupler.hpp"
       6             : #include "issm-precice/compiler.hpp"
       7             : #include "issm-precice/logging.hpp"
       8             : #include "issm-precice/ranges.hpp"
       9             : #include <cassert>
      10             : #include <map>
      11             : #include <ranges>
      12             : #include <string>
      13             : #include <vector>
      14             : 
      15             : namespace stdr = std::ranges;
      16             : namespace stdv = std::views;
      17             : 
      18             : namespace ipc
      19             : {
      20           8 : ICoupler::~ICoupler()
      21             : {
      22           8 : }
      23             : 
      24           4 : PreciceCoupler::PreciceCoupler(
      25             :     const std::vector<VariableDefinition>& variables,
      26             :     const std::string& config_file,
      27             :     const std::string& solver_name,
      28             :     const std::string& mesh_name,
      29           4 :     MPI_Comm comm)
      30           4 :     : m_initialized_mesh(false)
      31           4 :     , m_initialized_data(false)
      32           4 :     , m_finalized(false)
      33           4 :     , m_vertex_ids()
      34           4 :     , m_precice(
      35             :           solver_name,
      36             :           config_file,
      37           4 :           [comm]
      38             :           {
      39             :               int r;
      40           4 :               MPI_Comm_rank(comm, &r);
      41           4 :               return r;
      42             :           }(),
      43           4 :           [comm]
      44             :           {
      45             :               int sz;
      46           4 :               MPI_Comm_size(comm, &sz);
      47           4 :               return sz;
      48             :           }(),
      49             :           &comm)
      50           4 :     , m_mesh_name(mesh_name)
      51           4 :     , m_comm(comm)
      52             : {
      53             :     // check valid dimensions
      54           4 :     maybe_unused(variables);
      55           4 :     auto dimensions = m_precice.getMeshDimensions(m_mesh_name);
      56           4 :     if (dimensions < 2 || dimensions > 3)
      57             :     {
      58           0 :         throw std::domain_error("Unsupported number of dimensions.");
      59             :     }
      60           4 : }
      61             : 
      62           4 : PreciceCoupler::~PreciceCoupler()
      63             : {
      64           4 :     if (!m_finalized)
      65             :     {
      66           4 :         finalize();
      67             :     }
      68           4 : }
      69             : 
      70           4 : void PreciceCoupler::finalize()
      71             : {
      72           8 :     IPC_LOG_INFO_0(m_comm, "Finalizing preCICE coupler.");
      73           4 :     assert(!m_finalized);
      74           4 :     m_precice.finalize();
      75           4 :     m_finalized = true;
      76           4 : }
      77             : 
      78          12 : int PreciceCoupler::get_dimensions() const
      79             : {
      80          12 :     return m_precice.getMeshDimensions(m_mesh_name);
      81             : }
      82             : 
      83           4 : void PreciceCoupler::initialize_mesh()
      84             : {
      85             :     //nothing to do since precice 3
      86           4 :     m_initialized_mesh = true;
      87           4 : }
      88             : 
      89           4 : void PreciceCoupler::initialize_data()
      90             : {
      91           4 :     m_initialized_data = true;
      92           4 :     if (!m_precice.requiresInitialData())
      93             :     {
      94             :         // it's very unlikely that no data initialization is required, so we warn here.
      95             :         // also stops the exception thrown by precice when data initialization is enabled but requiresInitialData is
      96             :         // never called.
      97           0 :         IPC_LOG_WARN_0(m_comm, "No data initialization required. This is usually an error, did you forget to enable "
      98             :             "data initialization in your precice config? (<exchange ... initialize=\"1\">");
      99             :     }
     100           4 :     m_precice.initialize();
     101           4 : }
     102             : 
     103           4 : void PreciceCoupler::setup_coordinates(std::span<const double> coordinates)
     104             : {
     105           4 :     assert(coordinates.size() % get_dimensions() == 0);
     106             : 
     107           4 :     auto num_vertices = coordinates.size() / get_dimensions();
     108             : 
     109           4 :     m_vertex_ids.resize(num_vertices);
     110           4 :     m_precice.setMeshVertices(m_mesh_name, coordinates, m_vertex_ids);
     111           4 : }
     112             : 
     113           4 : void PreciceCoupler::setup_simplex_elements(std::span<const size_t> vertex_idxs)
     114             : {
     115           4 :     if (get_dimensions() == 2)
     116             :     {
     117             :         //triangles
     118           4 :         assert(vertex_idxs.size() % 3 == 0);
     119          16 :         for (auto i = size_t(0); i < vertex_idxs.size(); i += 3)
     120             :         {
     121          12 :             m_precice.setMeshTriangle(
     122          12 :                 m_mesh_name,
     123          12 :                 m_vertex_ids[vertex_idxs[i]],
     124          12 :                 m_vertex_ids[vertex_idxs[i + 1]],
     125          12 :                 m_vertex_ids[vertex_idxs[i + 2]]);
     126             :         }
     127             :     }
     128           0 :     else if (get_dimensions() == 3)
     129             :     {
     130             :         //tetrahedrons
     131           0 :         assert(vertex_idxs.size() % 4 == 0);
     132           0 :         for (auto i = size_t(0); i < vertex_idxs.size(); i += 4)
     133             :         {
     134           0 :             m_precice.setMeshTetrahedron(
     135           0 :                 m_mesh_name,
     136           0 :                 m_vertex_ids[vertex_idxs[i]],
     137           0 :                 m_vertex_ids[vertex_idxs[i + 1]],
     138           0 :                 m_vertex_ids[vertex_idxs[i + 2]],
     139           0 :                 m_vertex_ids[vertex_idxs[i + 3]]);
     140             :         }
     141             :     }
     142           4 : }
     143             : 
     144           0 : bool PreciceCoupler::is_coupling_ongoing() const
     145             : {
     146           0 :     return m_precice.isCouplingOngoing();
     147             : }
     148             : 
     149           4 : void PreciceCoupler::read_data(const std::string& data_name, double dt, std::span<double> data) const
     150             : {
     151           4 :     m_precice.readData(m_mesh_name, data_name, m_vertex_ids, dt, data);
     152           4 : }
     153             : 
     154           4 : void PreciceCoupler::write_data(const std::string& data_name, std::span<const double> data)
     155             : {
     156           4 :     m_precice.writeData(m_mesh_name, data_name, m_vertex_ids, data);
     157           4 : }
     158             : 
     159           6 : void PreciceCoupler::advance(double dt)
     160             : {
     161           6 :     IPC_LOG_INFO_0(m_comm, "Advance preCICE by {}", dt);
     162           6 :     m_precice.advance(dt);
     163           6 : }
     164             : 
     165           4 : double PreciceCoupler::get_time_step() const
     166             : {
     167           4 :     return m_precice.getMaxTimeStepSize();
     168             : }
     169             : 
     170             : } // namespace ipc

Generated by: LCOV version 1.14