Improve variable names and documentation

这个提交包含在:
Nathan Mannall
2025-04-14 17:59:20 +01:00
父节点 4570aa4d09
当前提交 540207871e
共有 2 个文件被更改,包括 55 次插入54 次删除

查看文件

@@ -312,10 +312,15 @@ class MPIFractalVolume(FractalVolume):
self.stop = np.array([self.xf, self.yf, self.zf], dtype=np.int32) self.stop = np.array([self.xf, self.yf, self.zf], dtype=np.int32)
self.size = self.stop - self.start self.size = self.stop - self.start
# Exit early if this rank does not contain the Fractal Volume
# The size of a fractal volume can increase if a Fractal Surface
# is attached. Hence the check needs to happen here once that
# has happened.
if any(self.stop < 0): if any(self.stop < 0):
self.comm.Split(MPI.UNDEFINED) self.comm.Split(MPI.UNDEFINED)
return False return False
else: else:
# Create new cartsesian communicator for the Fractal Volume
comm = self.comm.Split() comm = self.comm.Split()
assert isinstance(comm, MPI.Intracomm) assert isinstance(comm, MPI.Intracomm)
min_coord = np.array(self.comm.coords, dtype=np.int32) min_coord = np.array(self.comm.coords, dtype=np.int32)
@@ -324,6 +329,13 @@ class MPIFractalVolume(FractalVolume):
comm.Allreduce(MPI.IN_PLACE, max_coord, MPI.MAX) comm.Allreduce(MPI.IN_PLACE, max_coord, MPI.MAX)
self.comm = comm.Create_cart((max_coord - min_coord).tolist()) self.comm = comm.Create_cart((max_coord - min_coord).tolist())
# Check domain decomosition is valid for the Fractal Volume
if all([dim > 1 for dim in self.comm.dims]):
raise ValueError(
"Fractal volume must be positioned such that its MPI decomposition is 1 in at least"
f" 1 dimension. Current decompostion is: {self.comm.dims}"
)
# Scale filter according to size of fractal volume # Scale filter according to size of fractal volume
sorted_size = np.sort(self.size) sorted_size = np.sort(self.size)
min_size = sorted_size[1] if sorted_size[0] == 1 else sorted_size[0] min_size = sorted_size[1] if sorted_size[0] == 1 else sorted_size[0]
@@ -335,15 +347,6 @@ class MPIFractalVolume(FractalVolume):
# Positional vector at centre of array, scaled by weighting # Positional vector at centre of array, scaled by weighting
v1 = self.weighting * self.size / 2 v1 = self.weighting * self.size / 2
# 3D array of random numbers to be convolved with the fractal function
rng = np.random.default_rng(seed=self.seed)
if all([dim > 1 for dim in self.comm.dims]):
raise ValueError(
"Fractal volume must be positioned such that its MPI decomposition is 1 in at least"
f" 1 dimension. Current decompostion is: {self.comm.dims}"
)
subcomm = Subcomm(self.comm) subcomm = Subcomm(self.comm)
A = DistArray(self.size, subcomm, dtype=self.dtype) A = DistArray(self.size, subcomm, dtype=self.dtype)
fft = PFFT( fft = PFFT(
@@ -355,15 +358,19 @@ class MPIFractalVolume(FractalVolume):
) )
# Decomposition of A may be different to the MPIGrid # Decomposition of A may be different to the MPIGrid
substart = np.array(A.substart) A_shape = np.array(A.shape)
shape = np.array(A.shape) A_substart = np.array(A.substart)
static_dimension = Dim(A.alignment)
# 3D array of random numbers to be convolved with the fractal function
rng = np.random.default_rng(seed=self.seed)
for index in np.ndindex(*A.global_shape): for index in np.ndindex(*A.global_shape):
index = np.array(index) index = np.array(index)
if any(index < substart) or any(index >= substart + shape): if any(index < A_substart) or any(index >= A_substart + A_shape):
rng.standard_normal() rng.standard_normal()
else: else:
index -= substart index -= A_substart
A[index[0], index[1], index[2]] = rng.standard_normal() A[index[0], index[1], index[2]] = rng.standard_normal()
A_hat = newDistArray(fft) A_hat = newDistArray(fft)
@@ -371,7 +378,6 @@ class MPIFractalVolume(FractalVolume):
# 3D FFT # 3D FFT
fft.forward(A, A_hat, normalize=False) fft.forward(A, A_hat, normalize=False)
A_hat_out = np.zeros_like(A_hat)
# Generate fractal # Generate fractal
generate_fractal3D( generate_fractal3D(
@@ -389,74 +395,67 @@ class MPIFractalVolume(FractalVolume):
self.weighting, self.weighting,
v1, v1,
A_hat, A_hat,
A_hat_out, A_hat,
) )
# Set DC component of FFT to zero # Set DC component of FFT to zero
if all(substart == 0): if all(A_substart == 0):
A_hat_out[0, 0, 0] = 0 A_hat[0, 0, 0] = 0
# Inverse 3D FFT transform
fft.backward(A_hat, A, normalize=True)
# Take the real part (numerical errors can give rise to an imaginary part) # Take the real part (numerical errors can give rise to an imaginary part)
# of the IFFT, and convert type to floattype. N.B calculation of fractals # of the IFFT, and convert type to floattype. N.B calculation of fractals
# must always be carried out at double precision, i.e. float64, complex128 # must always be carried out at double precision, i.e. float64, complex128
Aj = np.real(fft.backward(A_hat_out, normalize=True)).astype( A = np.real(A).astype(config.sim_config.dtypes["float_or_double"], copy=False)
config.sim_config.dtypes["float_or_double"], copy=False
)
min_value = np.array(np.amin(Aj), dtype=config.sim_config.dtypes["float_or_double"])
max_value = np.array(np.amax(Aj), dtype=config.sim_config.dtypes["float_or_double"])
# Allreduce to get min and max values in the fractal volume
min_value = np.array(np.amin(A), dtype=config.sim_config.dtypes["float_or_double"])
max_value = np.array(np.amax(A), dtype=config.sim_config.dtypes["float_or_double"])
self.comm.Allreduce(MPI.IN_PLACE, min_value, MPI.MIN) self.comm.Allreduce(MPI.IN_PLACE, min_value, MPI.MIN)
self.comm.Allreduce(MPI.IN_PLACE, max_value, MPI.MAX) self.comm.Allreduce(MPI.IN_PLACE, max_value, MPI.MAX)
fractalvolume_initial = np.zeros_like(Aj)
# Bin fractal values # Bin fractal values
bins = np.linspace(min_value, max_value, self.nbins) bins = np.linspace(min_value, max_value, self.nbins)
for j in range(shape[1]): for j in range(A_shape[1]):
for k in range(shape[2]): for k in range(A_shape[2]):
fractalvolume_initial[:, j, k] = np.digitize(Aj[:, j, k], bins, right=True) A[:, j, k] = np.digitize(A[:, j, k], bins, right=True)
# Distribute A (DistArray) to match the MPIGrid decomposition
local_shape = np.minimum(self.stop, self.upper_bound) - np.maximum(self.start, 0)
self.fractalvolume = np.zeros( self.fractalvolume = np.zeros(
self.upper_bound - np.where(self.start < 0, 0, self.start), local_shape,
dtype=config.sim_config.dtypes["float_or_double"], dtype=config.sim_config.dtypes["float_or_double"],
) )
static_dimension = Dim(A.alignment)
dims = [dim for dim in Dim if dim != static_dimension]
# Negative means send to negative neighbour # Negative means send to negative neighbour
# Positive means receive from negative neighbour # Positive means receive from negative neighbour
negative_offset = np.where(self.start >= 0, 0, self.start + substart) negative_offset = np.where(self.start >= 0, 0, self.start + A_substart)
# Negative means send to positive neighbour # Negative means send to positive neighbour
# Positive means receive from positive neighbour # Positive means receive from positive neighbour
positive_offset = self.upper_bound - (self.start + substart + shape) positive_offset = np.minimum(self.stop, self.upper_bound) - (
self.start + A_substart + A_shape
)
dirs = np.full(3, Dir.NONE) dirs = np.full(3, Dir.NONE)
shape = np.array(fractalvolume_initial.shape, dtype=np.int32)
starts, subshape = self.calculate_starts_and_subshape( starts, subshape = self.calculate_starts_and_subshape(
shape, -negative_offset, -positive_offset, dirs, sending=True A_shape, -negative_offset, -positive_offset, dirs, sending=True
) )
ends = starts + subshape ends = starts + subshape
local_fractalvolume = fractalvolume_initial[ A_local = A[starts[0] : ends[0], starts[1] : ends[1], starts[2] : ends[2]]
starts[0] : ends[0], starts[1] : ends[1], starts[2] : ends[2]
]
shape = np.array(self.fractalvolume.shape, dtype=np.int32)
starts, subshape = self.calculate_starts_and_subshape( starts, subshape = self.calculate_starts_and_subshape(
shape, negative_offset, positive_offset, dirs local_shape, negative_offset, positive_offset, dirs
) )
ends = starts + subshape ends = starts + subshape
self.fractalvolume[ self.fractalvolume[starts[0] : ends[0], starts[1] : ends[1], starts[2] : ends[2]] = A_local
starts[0] : ends[0], starts[1] : ends[1], starts[2] : ends[2]
] = local_fractalvolume
requests: List[MPI.Request] = [] requests: List[MPI.Request] = []
# Need to check neighbours in each direction (2D plane)
sections = [ sections = [
(Dir.NEG, Dir.NONE), (Dir.NEG, Dir.NONE),
(Dir.POS, Dir.NONE), (Dir.POS, Dir.NONE),
@@ -468,11 +467,15 @@ class MPIFractalVolume(FractalVolume):
(Dir.POS, Dir.POS), (Dir.POS, Dir.POS),
] ]
# Dimensions of the 2D plane
dims = [dim for dim in Dim if dim != static_dimension]
for section in sections: for section in sections:
dirs[dims[0]] = section[0] dirs[dims[0]] = section[0]
dirs[dims[1]] = section[1] dirs[dims[1]] = section[1]
rank = get_relative_neighbour(self.comm, dirs) rank = get_relative_neighbour(self.comm, dirs)
# Skip if no neighbour
if rank == -1: if rank == -1:
continue continue
@@ -483,13 +486,12 @@ class MPIFractalVolume(FractalVolume):
np.where(dirs == Dir.NEG, negative_offset <= 0, positive_offset <= 0), np.where(dirs == Dir.NEG, negative_offset <= 0, positive_offset <= 0),
) )
): ):
shape = np.array(fractalvolume_initial.shape, dtype=np.int32)
mpi_type = self.create_mpi_type( mpi_type = self.create_mpi_type(
shape, -negative_offset, -positive_offset, dirs, sending=True A_shape, -negative_offset, -positive_offset, dirs, sending=True
) )
logger.debug(f"Sending fractal volume to rank {rank}, MPI type={mpi_type.decode()}") logger.debug(f"Sending fractal volume to rank {rank}, MPI type={mpi_type.decode()}")
self.comm.Isend([fractalvolume_initial, mpi_type], rank) self.comm.Isend([A, mpi_type], rank)
# Check if any data to receive # Check if any data to receive
if all( if all(
@@ -498,8 +500,7 @@ class MPIFractalVolume(FractalVolume):
np.where(dirs == Dir.NEG, negative_offset > 0, positive_offset > 0), np.where(dirs == Dir.NEG, negative_offset > 0, positive_offset > 0),
) )
): ):
shape = np.array(self.fractalvolume.shape, dtype=np.int32) mpi_type = self.create_mpi_type(local_shape, negative_offset, positive_offset, dirs)
mpi_type = self.create_mpi_type(shape, negative_offset, positive_offset, dirs)
logger.debug( logger.debug(
f"Receiving fractal volume from rank {rank}, MPI type={mpi_type.decode()}" f"Receiving fractal volume from rank {rank}, MPI type={mpi_type.decode()}"

查看文件

@@ -179,9 +179,9 @@ class FractalBox(RotatableMixin, GeometryUserObject):
frac_dim, frac_dim,
seed, seed,
grid.comm, grid.comm,
min(grid.nx, xf), grid.nx,
min(grid.ny, yf), grid.ny,
min(grid.nz, zf), grid.nz,
) )
else: else:
self.volume = FractalVolume(xs, xf, ys, yf, zs, zf, frac_dim, seed) self.volume = FractalVolume(xs, xf, ys, yf, zs, zf, frac_dim, seed)