你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-08 07:24:19 +08:00
Correct fractal float/double issue, and update random number generation for grass.
这个提交包含在:
@@ -173,7 +173,7 @@ class AddGrass(UserObjectGeometry):
|
|||||||
# Set the fractal range to scale the fractal distribution between zero and one
|
# Set the fractal range to scale the fractal distribution between zero and one
|
||||||
surface.fractalrange = (0, 1)
|
surface.fractalrange = (0, 1)
|
||||||
surface.operatingonID = volume.ID
|
surface.operatingonID = volume.ID
|
||||||
surface.generate_fractal_surface(grid)
|
surface.generate_fractal_surface()
|
||||||
if n_blades > surface.fractalsurface.shape[0] * surface.fractalsurface.shape[1]:
|
if n_blades > surface.fractalsurface.shape[0] * surface.fractalsurface.shape[1]:
|
||||||
logger.exception(self.__str__() + ' the specified surface is not large enough for the number of grass blades/roots specified')
|
logger.exception(self.__str__() + ' the specified surface is not large enough for the number of grass blades/roots specified')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
@@ -191,7 +191,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
logger.exception(self.__str__() + f' has already been used on the {surface.surfaceID} surface')
|
logger.exception(self.__str__() + f' has already been used on the {surface.surfaceID} surface')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
surface.generate_fractal_surface(grid)
|
surface.generate_fractal_surface()
|
||||||
volume.fractalsurfaces.append(surface)
|
volume.fractalsurfaces.append(surface)
|
||||||
|
|
||||||
logger.info(self.grid_name(grid) + f'Fractal surface from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m with fractal dimension {surface.dimension:g}, fractal weightings {surface.weighting[0]:g}, {surface.weighting[1]:g}, fractal seeding {surface.seed}, and range {limits[0]:g}m to {limits[1]:g}m, added to {surface.operatingonID}.')
|
logger.info(self.grid_name(grid) + f'Fractal surface from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m with fractal dimension {surface.dimension:g}, fractal weightings {surface.weighting[0]:g}, {surface.weighting[1]:g}, fractal seeding {surface.seed}, and range {limits[0]:g}m to {limits[1]:g}m, added to {surface.operatingonID}.')
|
||||||
|
@@ -80,7 +80,7 @@ class FractalBoxBuilder(UserObjectGeometry):
|
|||||||
materialnumID = next(x.numID for x in grid.materials if x.ID == volume.operatingonID)
|
materialnumID = next(x.numID for x in grid.materials if x.ID == volume.operatingonID)
|
||||||
volume.fractalvolume *= materialnumID
|
volume.fractalvolume *= materialnumID
|
||||||
else:
|
else:
|
||||||
volume.generate_fractal_volume(grid)
|
volume.generate_fractal_volume()
|
||||||
volume.fractalvolume += volume.mixingmodel.startmaterialnum
|
volume.fractalvolume += volume.mixingmodel.startmaterialnum
|
||||||
|
|
||||||
volume.generate_volume_mask()
|
volume.generate_volume_mask()
|
||||||
@@ -306,7 +306,7 @@ class FractalBoxBuilder(UserObjectGeometry):
|
|||||||
logger.exception(self.__str__() + ' is being used with a single material and no modifications, therefore please use a #box command instead.')
|
logger.exception(self.__str__() + ' is being used with a single material and no modifications, therefore please use a #box command instead.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
else:
|
else:
|
||||||
volume.generate_fractal_volume(grid)
|
volume.generate_fractal_volume()
|
||||||
volume.fractalvolume += volume.mixingmodel.startmaterialnum
|
volume.fractalvolume += volume.mixingmodel.startmaterialnum
|
||||||
|
|
||||||
data = volume.fractalvolume.astype('int16', order='C')
|
data = volume.fractalvolume.astype('int16', order='C')
|
||||||
|
@@ -37,7 +37,7 @@ cpdef void generate_fractal2D(int nx, int ny, int nthreads, int b, np.float64_t[
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
cdef Py_ssize_t i, j
|
cdef Py_ssize_t i, j
|
||||||
cdef float v2x, v2y, rr
|
cdef double v2x, v2y, rr, B
|
||||||
|
|
||||||
for i in prange(nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(ny):
|
for j in range(ny):
|
||||||
@@ -47,12 +47,11 @@ cpdef void generate_fractal2D(int nx, int ny, int nthreads, int b, np.float64_t[
|
|||||||
|
|
||||||
# Calulate norm of v2 - v1
|
# Calulate norm of v2 - v1
|
||||||
rr = ((v2x - v1[0])**2 + (v2y - v1[1])**2)**(1/2)
|
rr = ((v2x - v1[0])**2 + (v2y - v1[1])**2)**(1/2)
|
||||||
|
B = rr**b
|
||||||
|
if B == 0:
|
||||||
|
B = 0.9
|
||||||
|
|
||||||
# Catch potential divide by zero
|
fractalsurface[i, j] = A[i, j] / B
|
||||||
if rr == 0:
|
|
||||||
rr = 0.9
|
|
||||||
|
|
||||||
fractalsurface[i, j] = A[i, j] * 1 / (rr**b)
|
|
||||||
|
|
||||||
|
|
||||||
cpdef void generate_fractal3D(int nx, int ny, int nz, int nthreads, int b, np.float64_t[:] weighting, np.float64_t[:] v1, np.complex128_t[:, :, ::1] A, float_or_double_complex[:, :, ::1] fractalvolume):
|
cpdef void generate_fractal3D(int nx, int ny, int nz, int nthreads, int b, np.float64_t[:] weighting, np.float64_t[:] v1, np.complex128_t[:, :, ::1] A, float_or_double_complex[:, :, ::1] fractalvolume):
|
||||||
@@ -69,7 +68,7 @@ cpdef void generate_fractal3D(int nx, int ny, int nz, int nthreads, int b, np.fl
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
cdef Py_ssize_t i, j, k
|
cdef Py_ssize_t i, j, k
|
||||||
cdef float v2x, v2y, v2z, rr
|
cdef double v2x, v2y, v2z, rr, B
|
||||||
|
|
||||||
for i in prange(nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(ny):
|
for j in range(ny):
|
||||||
@@ -81,9 +80,8 @@ cpdef void generate_fractal3D(int nx, int ny, int nz, int nthreads, int b, np.fl
|
|||||||
|
|
||||||
# Calulate norm of v2 - v1
|
# Calulate norm of v2 - v1
|
||||||
rr = ((v2x - v1[0])**2 + (v2y - v1[1])**2 + (v2z - v1[2])**2)**(1/2)
|
rr = ((v2x - v1[0])**2 + (v2y - v1[1])**2 + (v2z - v1[2])**2)**(1/2)
|
||||||
|
B = rr**b
|
||||||
|
if B == 0:
|
||||||
|
B = 0.9
|
||||||
|
|
||||||
# Catch potential divide by zero
|
fractalvolume[i, j, k] = A[i, j, k] / B
|
||||||
if rr == 0:
|
|
||||||
rr = 0.9
|
|
||||||
|
|
||||||
fractalvolume[i, j, k] = A[i, j, k] * 1 / (rr**b)
|
|
||||||
|
@@ -61,13 +61,8 @@ class FractalSurface:
|
|||||||
self.filldepth = 0
|
self.filldepth = 0
|
||||||
self.grass = []
|
self.grass = []
|
||||||
|
|
||||||
def generate_fractal_surface(self, G):
|
def generate_fractal_surface(self):
|
||||||
"""Generate a 2D array with a fractal distribution.
|
"""Generate a 2D array with a fractal distribution."""
|
||||||
|
|
||||||
Args:
|
|
||||||
G (class): Grid class instance - holds essential parameters
|
|
||||||
describing the model.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if self.xs == self.xf:
|
if self.xs == self.xf:
|
||||||
surfacedims = (self.ny, self.nz)
|
surfacedims = (self.ny, self.nz)
|
||||||
@@ -76,7 +71,7 @@ class FractalSurface:
|
|||||||
elif self.zs == self.zf:
|
elif self.zs == self.zf:
|
||||||
surfacedims = (self.nx, self.ny)
|
surfacedims = (self.nx, self.ny)
|
||||||
|
|
||||||
self.fractalsurface = np.zeros(surfacedims, dtype=config.sim_config.dtypes['complex'])
|
self.fractalsurface = np.zeros(surfacedims, dtype=np.complex128)
|
||||||
|
|
||||||
# Positional vector at centre of array, scaled by weighting
|
# Positional vector at centre of array, scaled by weighting
|
||||||
v1 = np.array([self.weighting[0] * (surfacedims[0]) / 2, self.weighting[1]
|
v1 = np.array([self.weighting[0] * (surfacedims[0]) / 2, self.weighting[1]
|
||||||
@@ -96,8 +91,13 @@ class FractalSurface:
|
|||||||
self.b, self.weighting, v1, A, self.fractalsurface)
|
self.b, self.weighting, v1, A, self.fractalsurface)
|
||||||
# Shift the zero frequency component to start of the array
|
# Shift the zero frequency component to start of the array
|
||||||
self.fractalsurface = fftpack.ifftshift(self.fractalsurface)
|
self.fractalsurface = fftpack.ifftshift(self.fractalsurface)
|
||||||
# Take the real part (numerical errors can give rise to an imaginary part) of the IFFT
|
# Set DC component of FFT to zero
|
||||||
self.fractalsurface = np.real(fftpack.ifftn(self.fractalsurface))
|
self.fractalsurface[0, 0] = 0
|
||||||
|
# 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
|
||||||
|
# must always be carried out at double precision, i.e. float64, complex128
|
||||||
|
self.fractalsurface = np.real(fftpack.ifftn(self.fractalsurface)).astype(config.sim_config.dtypes['float_or_double'],
|
||||||
|
copy=False)
|
||||||
# Scale the fractal volume according to requested range
|
# Scale the fractal volume according to requested range
|
||||||
fractalmin = np.amin(self.fractalsurface)
|
fractalmin = np.amin(self.fractalsurface)
|
||||||
fractalmax = np.amax(self.fractalsurface)
|
fractalmax = np.amax(self.fractalsurface)
|
||||||
@@ -145,13 +145,8 @@ class FractalVolume:
|
|||||||
self.nbins = 0
|
self.nbins = 0
|
||||||
self.fractalsurfaces = []
|
self.fractalsurfaces = []
|
||||||
|
|
||||||
def generate_fractal_volume(self, G):
|
def generate_fractal_volume(self):
|
||||||
"""Generate a 3D volume with a fractal distribution.
|
"""Generate a 3D volume with a fractal distribution."""
|
||||||
|
|
||||||
Args:
|
|
||||||
G (class): Grid class instance - holds essential parameters
|
|
||||||
describing the model.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Scale filter according to size of fractal volume
|
# Scale filter according to size of fractal volume
|
||||||
if self.nx == 1:
|
if self.nx == 1:
|
||||||
@@ -169,7 +164,7 @@ class FractalVolume:
|
|||||||
# Adjust weighting to account for filter scaling
|
# Adjust weighting to account for filter scaling
|
||||||
self.weighting = np.multiply(self.weighting, filterscaling)
|
self.weighting = np.multiply(self.weighting, filterscaling)
|
||||||
|
|
||||||
self.fractalvolume = np.zeros((self.nx, self.ny, self.nz), dtype=config.sim_config.dtypes['complex'])
|
self.fractalvolume = np.zeros((self.nx, self.ny, self.nz), dtype=np.complex128)
|
||||||
|
|
||||||
# Positional vector at centre of array, scaled by weighting
|
# Positional vector at centre of array, scaled by weighting
|
||||||
v1 = np.array([self.weighting[0] * self.nx / 2, self.weighting[1]
|
v1 = np.array([self.weighting[0] * self.nx / 2, self.weighting[1]
|
||||||
@@ -190,8 +185,14 @@ class FractalVolume:
|
|||||||
|
|
||||||
# Shift the zero frequency component to the start of the array
|
# Shift the zero frequency component to the start of the array
|
||||||
self.fractalvolume = fftpack.ifftshift(self.fractalvolume)
|
self.fractalvolume = fftpack.ifftshift(self.fractalvolume)
|
||||||
# Take the real part (numerical errors can give rise to an imaginary part) of the IFFT
|
# Set DC component of FFT to zero
|
||||||
self.fractalvolume = np.real(fftpack.ifftn(self.fractalvolume))
|
self.fractalvolume[0, 0, 0] = 0
|
||||||
|
# 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
|
||||||
|
# must always be carried out at double precision, i.e. float64, complex128
|
||||||
|
self.fractalvolume = np.real(fftpack.ifftn(self.fractalvolume)).astype(config.sim_config.dtypes['float_or_double'],
|
||||||
|
copy=False)
|
||||||
|
|
||||||
# Bin fractal values
|
# Bin fractal values
|
||||||
bins = np.linspace(np.amin(self.fractalvolume), np.amax(self.fractalvolume), self.nbins)
|
bins = np.linspace(np.amin(self.fractalvolume), np.amax(self.fractalvolume), self.nbins)
|
||||||
for j in range(self.ny):
|
for j in range(self.ny):
|
||||||
@@ -229,16 +230,16 @@ class Grass:
|
|||||||
self.seed = None
|
self.seed = None
|
||||||
|
|
||||||
# Randomly defined parameters that will be used to calculate geometry
|
# Randomly defined parameters that will be used to calculate geometry
|
||||||
self.R1 = np.random.RandomState(self.seed)
|
self.R1 = np.random.default_rng(seed=self.seed)
|
||||||
self.R2 = np.random.RandomState(self.seed)
|
self.R2 = np.random.default_rng(seed=self.seed)
|
||||||
self.R3 = np.random.RandomState(self.seed)
|
self.R3 = np.random.default_rng(seed=self.seed)
|
||||||
self.R4 = np.random.RandomState(self.seed)
|
self.R4 = np.random.default_rng(seed=self.seed)
|
||||||
self.R5 = np.random.RandomState(self.seed)
|
self.R5 = np.random.default_rng(seed=self.seed)
|
||||||
self.R6 = np.random.RandomState(self.seed)
|
self.R6 = np.random.default_rng(seed=self.seed)
|
||||||
|
|
||||||
for i in range(self.numblades):
|
for i in range(self.numblades):
|
||||||
self.geometryparams[i, 0] = 10 + 20 * self.R1.random_sample()
|
self.geometryparams[i, 0] = 10 + 20 * self.R1.random()
|
||||||
self.geometryparams[i, 1] = 10 + 20 * self.R2.random_sample()
|
self.geometryparams[i, 1] = 10 + 20 * self.R2.random()
|
||||||
self.geometryparams[i, 2] = self.R3.choice([-1, 1])
|
self.geometryparams[i, 2] = self.R3.choice([-1, 1])
|
||||||
self.geometryparams[i, 3] = self.R4.choice([-1, 1])
|
self.geometryparams[i, 3] = self.R4.choice([-1, 1])
|
||||||
|
|
||||||
@@ -273,8 +274,8 @@ class Grass:
|
|||||||
x, y (float): x and y coordinates of grass root.
|
x, y (float): x and y coordinates of grass root.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.geometryparams[root, 4] += -1 + 2 * self.R5.random_sample()
|
self.geometryparams[root, 4] += -1 + 2 * self.R5.random()
|
||||||
self.geometryparams[root, 5] += -1 + 2 * self.R6.random_sample()
|
self.geometryparams[root, 5] += -1 + 2 * self.R6.random()
|
||||||
x = round(self.geometryparams[root, 4])
|
x = round(self.geometryparams[root, 4])
|
||||||
y = round(self.geometryparams[root, 5])
|
y = round(self.geometryparams[root, 5])
|
||||||
|
|
||||||
|
在新工单中引用
屏蔽一个用户