LCOV - code coverage report
Current view: top level - src/FieldLayout - SubFieldLayout.hpp (source / functions) Coverage Total Hit
Test: final_report.info Lines: 90.9 % 22 20
Test Date: 2025-08-21 12:17:48 Functions: 100.0 % 18 18

            Line data    Source code
       1              : //
       2              : // Class SubFieldLayout
       3              : // SubFieldLayout provides a layout for a sub-region of a larger field.
       4              : // It ensures that the sub-region is partitioned in the same way as the original FieldLayout,
       5              : // maintaining consistent parallel decomposition and neighbor relationships within the sub-region.
       6              : //
       7              : #include "Ippl.h"
       8              : 
       9              : #include <cstdlib>
      10              : #include <limits>
      11              : 
      12              : #include "Utility/IpplException.h"
      13              : #include "Utility/IpplTimings.h"
      14              : #include "Utility/PAssert.h"
      15              : 
      16              : #include "FieldLayout/SubFieldLayout.h"
      17              : 
      18              : namespace ippl {
      19              : 
      20              :     /**
      21              :      * @copydoc SubFieldLayout::SubFieldLayout(const mpi::Communicator&)
      22              :      * 
      23              :      * Creates a SubFieldLayout without specifying domains. The layout must be initialized
      24              :      * later using the initialize() methods. This constructor is useful when you need to
      25              :      * defer the layout configuration until more information is available.
      26              :      */
      27              :     template <unsigned Dim>
      28          216 :     SubFieldLayout<Dim>::SubFieldLayout(const mpi::Communicator& communicator)
      29          216 :         : FieldLayout<Dim>(communicator) {}
      30              : 
      31              :     /**
      32              :      * @copydoc SubFieldLayout::SubFieldLayout(mpi::Communicator, const NDIndex<Dim>&, const NDIndex<Dim>&, std::array<bool, Dim>, bool)
      33              :      * 
      34              :      * Implementation details:
      35              :      * Initializes both the full domain decomposition and the sub-domain layout. The sub-domain
      36              :      * must be contained within the full domain. All MPI ranks must have non-empty local domains
      37              :      * after intersection with the sub-domain, otherwise an exception will be thrown.
      38              :      * 
      39              :      * This constructor sets up the parallel decomposition based on the full domain, then
      40              :      * restricts the full domain to the specified sub-region while maintaining the same
      41              :      * partitioning structure.
      42              :      */
      43              :     template <unsigned Dim>
      44          552 :     SubFieldLayout<Dim>::SubFieldLayout(mpi::Communicator communicator, const NDIndex<Dim>& domain,
      45              :                                   const NDIndex<Dim>& subDomain, std::array<bool, Dim> isParallel, bool isAllPeriodic)
      46          552 :         : FieldLayout<Dim>(communicator) {
      47          552 :         initialize(domain, subDomain, isParallel, isAllPeriodic);
      48          552 :     }
      49              : 
      50              :     /**
      51              :      * @copydoc SubFieldLayout::SubFieldLayout(mpi::Communicator, const NDIndex<Dim>&, std::array<bool, Dim>, bool)
      52              :      * 
      53              :      * Implementation details:
      54              :      * Creates a SubFieldLayout where the sub-domain is the same as the full domain, making it
      55              :      * functionally equivalent to a regular FieldLayout.
      56              :      */
      57              :     template <unsigned Dim>
      58              :     SubFieldLayout<Dim>::SubFieldLayout(mpi::Communicator communicator, const NDIndex<Dim>& domain, 
      59              :                                   std::array<bool, Dim> isParallel, bool isAllPeriodic)
      60              :         : FieldLayout<Dim>(communicator) {
      61              :         initialize(domain, isParallel, isAllPeriodic);
      62              :     }
      63              : 
      64              :     /**
      65              :      * @copydoc SubFieldLayout::initialize(const NDIndex<Dim>&, const NDIndex<Dim>&, std::array<bool, Dim>, bool)
      66              :      * 
      67              :      * Implementation details:
      68              :      * This method first partitions the full domain for parallel processing,
      69              :      * then restricts each rank's local domain to the specified sub-domain.
      70              :      * 
      71              :      * The sub-domain must be contained within the full domain, and all MPI ranks must have 
      72              :      * non-empty local domains after intersection with the sub-domain, otherwise an exception
      73              :      * will be thrown.
      74              :      */
      75              :     template <unsigned Dim>
      76          552 :     void SubFieldLayout<Dim>::initialize(const NDIndex<Dim>& domain, const NDIndex<Dim>& subDomain, std::array<bool, Dim> isParallel,
      77              :                                       bool isAllPeriodic) {
      78              : 
      79              :         // Ensure the sub-domain is contained within the main domain
      80          552 :         PAssert(domain.contains(subDomain));
      81              : 
      82              :         // Call the base class initialize method to set up the main domain and parallel decomposition
      83          552 :         FieldLayout<Dim>::initialize(domain, isParallel, isAllPeriodic);
      84              : 
      85          552 :         unsigned int nRanks = this->comm.size();
      86              : 
      87          552 :         originDomain_m = domain;
      88              : 
      89          552 :         this->gDomain_m = subDomain;
      90              :         
      91              :         // Check if all ranks have a valid local domain that intersects with the sub-domain
      92         1104 :         if (this->hLocalDomains_m(this->comm.rank()).intersect(subDomain).empty()) {
      93            0 :             throw std::runtime_error("SubFieldLayout:initialize: given subdomain is not valid, rank"
      94            0 :                 + std::to_string(this->comm.rank()) + " has an empty local domain, choose a sub-domain that has content on all ranks");
      95              :         }
      96              : 
      97              :         // If the local domain is not contained in the sub-domain, change it to the intersection of the local domain and the sub-domain
      98              :         // This ensures that the sub-field layout is consistent with the original layout
      99         1656 :         for (unsigned int rank = 0; rank < nRanks; ++rank) {
     100         2208 :             if (!this->gDomain_m.contains(this->hLocalDomains_m(rank))) {
     101         3036 :                 this->hLocalDomains_m(rank) = this->hLocalDomains_m(rank).intersect(this->gDomain_m);
     102              :             }
     103              :         }
     104              : 
     105          552 :         this->findNeighbors();
     106              : 
     107          552 :         Kokkos::deep_copy(this->dLocalDomains_m, this->hLocalDomains_m);
     108              : 
     109          552 :         this->calcWidths();
     110          552 :     }
     111              : 
     112              :     /**
     113              :      * @copydoc SubFieldLayout::initialize(const NDIndex<Dim>&, std::array<bool, Dim>, bool)
     114              :      * 
     115              :      * Implementation details:
     116              :      * This method initializes the layout to use the entire domain as both the full domain
     117              :      * and the sub-domain, making it equivalent to a regular FieldLayout.
     118              :      */
     119              :     template <unsigned Dim>
     120              :     void SubFieldLayout<Dim>::initialize(const NDIndex<Dim>& domain, std::array<bool, Dim> isParallel, 
     121              :                                          bool isAllPeriodic) {
     122              :         // Call the base class initialize method to set up the main domain and parallel decomposition
     123              :         FieldLayout<Dim>::initialize(domain, isParallel, isAllPeriodic);
     124              : 
     125              :         originDomain_m = domain;
     126              :     }
     127              : 
     128              : }  // namespace ippl
        

Generated by: LCOV version 2.0-1