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 : #ifndef IPPL_SUB_FIELD_LAYOUT_H
8 : #define IPPL_SUB_FIELD_LAYOUT_H
9 :
10 : #include <array>
11 : #include <iostream>
12 : #include <map>
13 : #include <vector>
14 :
15 : #include "Types/ViewTypes.h"
16 :
17 : #include "Communicate/Communicator.h"
18 : #include "FieldLayout/FieldLayout.h"
19 :
20 : namespace ippl {
21 :
22 : /**
23 : * @class SubFieldLayout
24 : * @brief SubFieldLayout provides a layout for a sub-region of a larger field
25 : *
26 : * SubFieldLayout extends FieldLayout to handle sub-regions of a larger computational domain.
27 : * It ensures that the sub-region is partitioned in the same way as the original FieldLayout,
28 : * maintaining consistent parallel decomposition and neighbor relationships within the sub-region.
29 : *
30 : * @par Important Constraint:
31 : * SubFieldLayout only allows for sub-layouts that do NOT leave local domains empty.
32 : * All MPI ranks must have at least some portion of the sub-domain assigned to them.
33 : * If a sub-domain would result in empty local domains for some ranks, an exception
34 : * will be thrown during initialization.
35 : *
36 : * @tparam Dim Number of spatial dimensions
37 : */
38 : template <unsigned Dim>
39 : class SubFieldLayout : public FieldLayout<Dim> {
40 : public:
41 : using NDIndex_t = NDIndex<Dim>;
42 : using view_type = typename detail::ViewType<NDIndex_t, 1>::view_type;
43 : using host_mirror_type = typename view_type::host_mirror_type;
44 :
45 : /**
46 : * @brief Default constructor, which should only be used if you are going to
47 : * call 'initialize' soon after (before using in any context)
48 : *
49 : * @param communicator MPI communicator to use (defaults to MPI_COMM_WORLD)
50 : */
51 : SubFieldLayout(const mpi::Communicator& = MPI_COMM_WORLD);
52 :
53 : /**
54 : * @brief Constructor that creates a SubFieldLayout for a sub-region of a larger domain
55 : *
56 : * @param communicator MPI communicator to use
57 : * @param domain The full domain that defines the partitioning
58 : * @param subDomain The sub-region within the full domain, which is partitioned in the same way as the fullomain
59 : * @param decomp Array specifying which dimensions should be parallel
60 : * @param isAllPeriodic Whether all dimensions have periodic boundary conditions
61 : */
62 : SubFieldLayout(mpi::Communicator, const NDIndex<Dim>& domain, const NDIndex<Dim>& subDomain, std::array<bool, Dim> decomp,
63 : bool isAllPeriodic = false);
64 :
65 : /**
66 : * @brief Constructor for full-domain layout.
67 : *
68 : * @param communicator MPI communicator to use
69 : * @param domain The full domain that defines the partitioning and is used as the sub-domain simultaneously
70 : * @param decomp Array specifying which dimensions should be parallel
71 : * @param isAllPeriodic Whether all dimensions have periodic boundary conditions
72 : */
73 : SubFieldLayout(mpi::Communicator, const NDIndex<Dim>& domain, std::array<bool, Dim> decomp,
74 : bool isAllPeriodic = false);
75 :
76 : /**
77 : * @brief Destructor: Everything deletes itself automatically
78 : */
79 768 : virtual ~SubFieldLayout() = default;
80 :
81 : /**
82 : * @brief Initializes a SubFieldLayout with the sub-domain partitioned in the same way
83 : * as the original FieldLayout partitiones the full domain
84 : *
85 : * @param domain The full domain to be partitioned
86 : * @param subDomain The sub-region within the full domain
87 : * @param decomp Array specifying which dimensions should be parallel
88 : * @param isAllPeriodic Whether all dimensions have periodic boundary conditions
89 : */
90 : void initialize(const NDIndex<Dim>& domain, const NDIndex<Dim>& subDomain, std::array<bool, Dim> decomp,
91 : bool isAllPeriodic = false);
92 :
93 : /**
94 : * @brief Initializes a SubFieldLayout using the domain as both the full domain and sub-domain
95 : *
96 : * @param domain The domain to be partitioned
97 : * @param decomp Array specifying which dimensions should be parallel
98 : * @param isAllPeriodic Whether all dimensions have periodic boundary conditions
99 : */
100 : void initialize(const NDIndex<Dim>& domain, std::array<bool, Dim> decomp,
101 : bool isAllPeriodic = false);
102 :
103 : /**
104 : * @brief Return the original domain before sub-region extraction
105 : *
106 : * @return Reference to the original full domain
107 : */
108 : const NDIndex<Dim>& getOriginDomain() const { return originDomain_m; }
109 :
110 : /**
111 : * @brief Compare SubFieldLayouts to see if they represent the same domain
112 : *
113 : * @tparam Dim2 Dimension of the other SubFieldLayout
114 : * @param x The other SubFieldLayout to compare with
115 : * @return true if both the current domain, origin domain and local domains match
116 : */
117 : template <unsigned Dim2>
118 : bool operator==(const SubFieldLayout<Dim2>& x) const {
119 : // Ensure the dimensions match
120 : if (Dim2 != Dim) {
121 : return false;
122 : }
123 :
124 : // Check if the original and global domains match
125 : if (originDomain_m != x.getOriginDomain() || this->gDomain_m != x.getDomain()) {
126 : return false;
127 : }
128 :
129 : // Ensure the local domains match
130 : for (unsigned int rank = 0; rank < this->comm.size(); ++rank) {
131 : if (this->hLocalDomains_m(rank) != x.getLocalNDIndex(rank)) {
132 : return false;
133 : }
134 : }
135 :
136 : // If all checks passed, the SubFieldLayouts matche
137 : return true;
138 : }
139 :
140 : /**
141 : * @brief Compare SubFieldLayout to a FieldLayout to see if they represent the same domain
142 : *
143 : * @tparam Dim2 Dimension of the FieldLayout
144 : * @param x The FieldLayout to compare with
145 : * @return true if the SubFieldLayout's domain equals its original domain and matches the FieldLayout's domain and local domains
146 : */
147 : template <unsigned Dim2>
148 : bool operator==(const FieldLayout<Dim2>& x) const {
149 : // Ensure the dimensions match
150 : if (Dim2 != Dim) {
151 : return false;
152 : }
153 :
154 : // Check if the global domain matches the original domain and the FieldLayout's domain
155 : if (this->gDomain_m != originDomain_m || this->gDomain_m != x.getDomain()) {
156 : return false;
157 : }
158 :
159 : // Ensure the local domains match
160 : for (unsigned int rank = 0; rank < this->comm.size(); ++rank) {
161 : if (this->hLocalDomains_m(rank) != x.getLocalNDIndex(rank)) {
162 : return false;
163 : }
164 : }
165 :
166 : // If all checks passed, the SubFieldLayout matches the FieldLayout
167 : return true;
168 : }
169 :
170 : private:
171 : /**
172 : * @brief Original global domain in which the sub-field is defined
173 : *
174 : * This stores the full domain before any sub-region extraction,
175 : * allowing comparison with regular FieldLayouts.
176 : */
177 : NDIndex_t originDomain_m;
178 : };
179 : } // namespace ippl
180 :
181 : #include "FieldLayout/SubFieldLayout.hpp"
182 :
183 : #endif
|