Skip to content

Commit 54f8dba

Browse files
committed
WIP: Add communication in Z
The actual significant changes are quite small, but these have big knock-on effects in the tests. Main changes: - Z is still periodic, but this is now implemented using guard cells instead of modulus in `SpecificInd::zp/zm` - Adds a new `Mesh` method `sendZ` - `NZPE` is now a user-settable option - Domain decomposition is done in Z before the usual X-Y decomposition - The X/Y _boundary_ regions do not include the Z guards - These corners should be filled in by `Mesh::communicate` - Handle Z guards in `Gridfile` - Handle Z guards in FFTs for `LaplaceCyclic`, `LaplacePCR`, `LaplacePCR_THOMAS` - Pull out common classes for the FFT and DST transforms Other bug fixes: - `BoutMesh::GlobalZ` should start at the first interior point, not in the guards Changes to the tests: - `FakeMesh` now has 1 Z guard cell, which changes the size of the interior domain, and requires many of the `Field*` tests to be updated - `IndexOffsetTest` needs to skip the Z guards, just like X, Y - Derivative tests need extra point for interior + 2 * guards - The Petsc and Hypre Laplace unit tests require the Z guards to be communicated in order to fill in the global indices. This requires `FakeMesh` to actually implement `sendZ`. This just copies the relevant points into the Z guards - Also, we should not check the result in the Z guards - I've also pulled out a bunch of common machinery between these two tests - `BoutMeshTest` now needs to understand Z guards and Z processors This change also requires `boutdata.collect` to properly handle Z guards as well
1 parent 9d0ff3a commit 54f8dba

60 files changed

Lines changed: 2009 additions & 1990 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ set(BOUT_SOURCES
208208
./src/field/where.cxx
209209
./src/invert/fft_fftw.cxx
210210
./src/invert/lapack_routines.cxx
211+
./src/invert/laplace/common_transform.cxx
212+
./src/invert/laplace/common_transform.hxx
211213
./src/invert/laplace/impls/cyclic/cyclic_laplace.cxx
212214
./src/invert/laplace/impls/cyclic/cyclic_laplace.hxx
213215
./src/invert/laplace/impls/iterative_parallel_tri/iterative_parallel_tri.cxx

include/bout/fft.hxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ Array<BoutReal> irfft(const Array<dcomplex>& in, int length);
124124
void assertZSerial(const Mesh& mesh, std::string_view name);
125125
#else
126126
inline void assertZSerial([[maybe_unused]] const Mesh& mesh,
127-
[[maybe_unused]] std::string_view name) {}
127+
[[maybe_unused]] std::string_view name) {}
128128
#endif
129129
} // namespace fft
130130
} // namespace bout

include/bout/griddata.hxx

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,20 +129,38 @@ public:
129129
private:
130130
Options data;
131131
std::string filename;
132+
133+
// These next three quantities are already read in `BoutMesh`, but this way we
134+
// don't need the Mesh API to get them here
135+
136+
// Number of y-boundary guard cells saved in the grid file
132137
int grid_yguards{0};
133138
int ny_inner{0};
139+
// Number of z-boundary guard cells save in the grid file.
140+
// Always zero for older grid files
141+
int grid_zguards{0};
134142

135143
bool readgrid_3dvar_fft(Mesh* m, const std::string& name, int yread, int ydest,
136144
int ysize, int xread, int xdest, int xsize, Field3D& var);
137145

146+
// \param yread Start reading at global y-index
147+
// \param ydest Insert data starting from y=yd
148+
// \param ysize Length of data in Y
149+
// \param xread Start reading at global x-index
150+
// \param xdest Insert data starting from x=xd
151+
// \param xsize Length of data in X
152+
// \param zread Start reading at global z-index
153+
// \param zdest Insert data starting from z=zd
154+
// \param zsize Length of data in Z
138155
bool readgrid_3dvar_real(const std::string& name, int yread, int ydest, int ysize,
139-
int xread, int xdest, int xsize, Field3D& var);
156+
int xread, int xdest, int xsize, int zread, int zdest,
157+
int zsize, Field3D& var);
140158

141159
bool readgrid_perpvar_fft(Mesh* m, const std::string& name, int xread, int xdest,
142160
int xsize, FieldPerp& var);
143161

144162
bool readgrid_perpvar_real(const std::string& name, int xread, int xdest, int xsize,
145-
FieldPerp& var);
163+
int zread, int zdest, int zsize, FieldPerp& var);
146164

147165
// convenience template method to remove code duplication between Field2D,
148166
// Field3D and FieldPerp versions of get
@@ -151,13 +169,16 @@ private:
151169
CELL_LOC location);
152170
// utility method for Field2D to implement unshared parts of getField
153171
void readField(Mesh* m, const std::string& name, int ys, int yd, int ny_to_read, int xs,
154-
int xd, int nx_to_read, const std::vector<int>& size, Field2D& var);
172+
int xd, int nx_to_read, int zs, int zd, int nz_to_read,
173+
const std::vector<int>& size, Field2D& var);
155174
// utility method for Field3D to implement unshared parts of getField
156175
void readField(Mesh* m, const std::string& name, int ys, int yd, int ny_to_read, int xs,
157-
int xd, int nx_to_read, const std::vector<int>& size, Field3D& var);
176+
int xd, int nx_to_read, int zs, int zd, int nz_to_read,
177+
const std::vector<int>& size, Field3D& var);
158178
// utility method for FieldPerp to implement unshared parts of getField
159179
void readField(Mesh* m, const std::string& name, int ys, int yd, int ny_to_read, int xs,
160-
int xd, int nx_to_read, const std::vector<int>& size, FieldPerp& var);
180+
int xd, int nx_to_read, int zs, int zd, int nz_to_read,
181+
const std::vector<int>& size, FieldPerp& var);
161182
};
162183

163184
/*!

include/bout/invert_laplace.hxx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ class Laplacian;
5050

5151
#include "bout/dcomplex.hxx"
5252

53+
class DSTTransform;
54+
class FFTTransform;
5355
class Solver;
5456

5557
constexpr auto LAPLACE_SPT = "spt";
@@ -258,7 +260,7 @@ public:
258260
/// Coefficients in tridiagonal inversion
259261
void tridagCoefs(int jx, int jy, int jz, dcomplex& a, dcomplex& b, dcomplex& c,
260262
const Field2D* ccoef = nullptr, const Field2D* d = nullptr,
261-
CELL_LOC loc = CELL_DEFAULT);
263+
CELL_LOC loc = CELL_DEFAULT) const;
262264

263265
/*!
264266
* Create a new Laplacian solver
@@ -301,6 +303,10 @@ public:
301303
void savePerformance(Solver& solver, const std::string& name);
302304

303305
protected:
306+
// Give access for tridagMatrix
307+
friend class DSTTransform;
308+
friend class FFTTransform;
309+
304310
bool async_send; ///< If true, use asyncronous send in parallel algorithms
305311

306312
int maxmode; ///< The maximum Z mode to solve for
@@ -332,23 +338,24 @@ protected:
332338

333339
void tridagCoefs(int jx, int jy, BoutReal kwave, dcomplex& a, dcomplex& b, dcomplex& c,
334340
const Field2D* ccoef = nullptr, const Field2D* d = nullptr,
335-
CELL_LOC loc = CELL_DEFAULT) {
341+
CELL_LOC loc = CELL_DEFAULT) const {
336342
tridagCoefs(jx, jy, kwave, a, b, c, ccoef, ccoef, d, loc);
337343
}
338344
void tridagCoefs(int jx, int jy, BoutReal kwave, dcomplex& a, dcomplex& b, dcomplex& c,
339345
const Field2D* c1coef, const Field2D* c2coef, const Field2D* d,
340-
CELL_LOC loc = CELL_DEFAULT);
346+
CELL_LOC loc = CELL_DEFAULT) const;
341347

342348
void tridagMatrix(dcomplex* avec, dcomplex* bvec, dcomplex* cvec, dcomplex* bk, int jy,
343349
int kz, BoutReal kwave, const Field2D* a, const Field2D* ccoef,
344-
const Field2D* d, bool includeguards = true, bool zperiodic = true) {
350+
const Field2D* d, bool includeguards = true,
351+
bool zperiodic = true) const {
345352
tridagMatrix(avec, bvec, cvec, bk, jy, kz, kwave, a, ccoef, ccoef, d, includeguards,
346353
zperiodic);
347354
}
348355
void tridagMatrix(dcomplex* avec, dcomplex* bvec, dcomplex* cvec, dcomplex* bk, int jy,
349356
int kz, BoutReal kwave, const Field2D* a, const Field2D* c1coef,
350357
const Field2D* c2coef, const Field2D* d, bool includeguards = true,
351-
bool zperiodic = true);
358+
bool zperiodic = true) const;
352359
CELL_LOC location; ///< staggered grid location of this solver
353360
Mesh* localmesh; ///< Mesh object for this solver
354361
Coordinates* coords; ///< Coordinates object, so we only have to call

include/bout/mesh.hxx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ public:
349349
/// Send only the y-guard cells
350350
virtual comm_handle sendY(FieldGroup& g, comm_handle handle = nullptr) = 0;
351351

352+
/// Send only the z-guard cells
353+
virtual comm_handle sendZ(FieldGroup& g, comm_handle handle = nullptr) = 0;
354+
352355
/// Wait for the handle, return error code
353356
virtual int wait(comm_handle handle) = 0; ///< Wait for the handle, return error code
354357

@@ -812,9 +815,9 @@ protected:
812815
/// Read a 1D array of integers
813816
const std::vector<int> readInts(const std::string& name, int n);
814817

815-
/// Calculates the size of a message for a given x and y range
816-
int msg_len(const std::vector<FieldData*>& var_list, int xge, int xlt, int yge,
817-
int ylt);
818+
/// Calculates the size of a message for a given (x, y, z) range
819+
int msg_len(const std::vector<FieldData*>& var_list, int xge, int xlt, int yge, int ylt,
820+
int zge, int zlt);
818821

819822
/// Initialise derivatives
820823
void derivs_init(Options* options);

include/bout/region.hxx

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ struct SpecificInd {
170170
int ny = -1, nz = -1; ///< Sizes of y and z dimensions
171171

172172
SpecificInd() = default;
173-
SpecificInd(int i, int ny, int nz) : ind(i), ny(ny), nz(nz){};
174-
explicit SpecificInd(int i) : ind(i){};
173+
SpecificInd(int i, int ny, int nz) : ind(i), ny(ny), nz(nz) {};
174+
explicit SpecificInd(int i) : ind(i) {};
175175

176176
/// Allow explicit conversion to an int
177177
explicit operator int() const { return ind; }
@@ -290,26 +290,15 @@ struct SpecificInd {
290290
}
291291
/// The index one point -1 in y
292292
inline SpecificInd ym(int dy = 1) const { return yp(-dy); }
293-
/// The index one point +1 in z. Wraps around zend to zstart
294-
/// An alternative, non-branching calculation is :
295-
/// ind + dz - nz * ((ind + dz) / nz - ind / nz)
296-
/// but this appears no faster (and perhaps slower).
293+
/// The index one point +1 in z
297294
inline SpecificInd zp(int dz = 1) const {
298-
ASSERT3(dz >= 0);
299-
dz = dz <= nz ? dz : dz % nz; //Fix in case dz > nz, if not force it to be in range
300-
return {(ind + dz) % nz < dz ? ind - nz + dz : ind + dz, ny, nz};
301-
}
302-
/// The index one point -1 in z. Wraps around zstart to zend
303-
/// An alternative, non-branching calculation is :
304-
/// ind - dz + nz * ( (nz + ind) / nz - (nz + ind - dz) / nz)
305-
/// but this appears no faster (and perhaps slower).
306-
inline SpecificInd zm(int dz = 1) const {
307-
dz = dz <= nz ? dz : dz % nz; //Fix in case dz > nz, if not force it to be in range
308-
ASSERT3(dz >= 0);
309-
return {(ind) % nz < dz ? ind + nz - dz : ind - dz, ny, nz};
295+
if constexpr (N == IND_TYPE::IND_2D) {
296+
return *this;
297+
}
298+
return {ind + dz, ny, nz};
310299
}
311-
/// Automatically select zm or zp depending on sign
312-
inline SpecificInd zpm(int dz) const { return dz > 0 ? zp(dz) : zm(-dz); }
300+
/// The index one point -1 in z
301+
inline SpecificInd zm(int dz = 1) const { return zp(-dz); }
313302

314303
// and for 2 cells
315304
inline SpecificInd xpp() const { return xp(2); }
@@ -320,9 +309,7 @@ struct SpecificInd {
320309
inline SpecificInd zmm() const { return zm(2); }
321310

322311
/// Generic offset of \p index in multiple directions simultaneously
323-
inline SpecificInd offset(int dx, int dy, int dz) const {
324-
return zpm(dz).yp(dy).xp(dx);
325-
}
312+
inline SpecificInd offset(int dx, int dy, int dz) const { return zp(dz).yp(dy).xp(dx); }
326313
};
327314

328315
/// Relational operators
@@ -490,10 +477,9 @@ template <typename T = Ind3D>
490477
class Region {
491478
// Following prevents a Region being created with anything other
492479
// than Ind2D, Ind3D or IndPerp as template type
493-
static_assert(
494-
std::is_base_of_v<
495-
Ind2D, T> || std::is_base_of_v<Ind3D, T> || std::is_base_of_v<IndPerp, T>,
496-
"Region must be templated with one of IndPerp, Ind2D or Ind3D");
480+
static_assert(std::is_base_of_v<Ind2D, T> || std::is_base_of_v<Ind3D, T>
481+
|| std::is_base_of_v<IndPerp, T>,
482+
"Region must be templated with one of IndPerp, Ind2D or Ind3D");
497483

498484
public:
499485
using data_type = T;
@@ -569,7 +555,7 @@ public:
569555
};
570556

571557
Region(RegionIndices& indices, int maxregionblocksize = MAXREGIONBLOCKSIZE)
572-
: indices(indices), blocks(getContiguousBlocks(maxregionblocksize)){};
558+
: indices(indices), blocks(getContiguousBlocks(maxregionblocksize)) {};
573559

574560
// We need to first set the blocks, and only after that call getRegionIndices.
575561
// Do not put in the member initialisation

0 commit comments

Comments
 (0)