你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 15:10:13 +08:00
Fix bug when objects start in a positive halo
Objects with a thickness (triangles and circular sectors) can no longer extend beyond the grid in the dimension they are aligned to. Building these objects where the lower extent is aligned with a positive halo, no longer corrupts memory due to out of bounds memory access
这个提交包含在:
@@ -140,6 +140,9 @@ class UserInput(Generic[GridType]):
|
|||||||
"""
|
"""
|
||||||
return self.discretise_point(point) * self.grid.dl
|
return self.discretise_point(point) * self.grid.dl
|
||||||
|
|
||||||
|
def discrete_to_continuous(self, point: npt.NDArray[np.int32]) -> npt.NDArray[np.float64]:
|
||||||
|
return point * self.grid.dl
|
||||||
|
|
||||||
|
|
||||||
class MainGridUserInput(UserInput[GridType]):
|
class MainGridUserInput(UserInput[GridType]):
|
||||||
"""Handles (x, y, z) points supplied by the user in the main grid."""
|
"""Handles (x, y, z) points supplied by the user in the main grid."""
|
||||||
@@ -199,30 +202,29 @@ class MainGridUserInput(UserInput[GridType]):
|
|||||||
p2: Tuple[float, float, float],
|
p2: Tuple[float, float, float],
|
||||||
p3: Tuple[float, float, float],
|
p3: Tuple[float, float, float],
|
||||||
cmd_str: str,
|
cmd_str: str,
|
||||||
) -> Tuple[bool, npt.NDArray[np.int32], npt.NDArray[np.int32], npt.NDArray[np.int32]]:
|
) -> Tuple[npt.NDArray[np.int32], npt.NDArray[np.int32], npt.NDArray[np.int32]]:
|
||||||
p1_within_grid, p1_checked = self.check_point(p1, cmd_str, name="vertex_1")
|
# We only care if the point are in the global grid (an error
|
||||||
p2_within_grid, p2_checked = self.check_point(p2, cmd_str, name="vertex_2")
|
# will be thrown if that is not the case).
|
||||||
p3_within_grid, p3_checked = self.check_point(p3, cmd_str, name="vertex_3")
|
_, p1_checked = self.check_point(p1, cmd_str, name="vertex_1")
|
||||||
|
_, p2_checked = self.check_point(p2, cmd_str, name="vertex_2")
|
||||||
|
_, p3_checked = self.check_point(p3, cmd_str, name="vertex_3")
|
||||||
|
|
||||||
return (
|
return p1_checked, p2_checked, p3_checked
|
||||||
p1_within_grid and p2_within_grid and p3_within_grid,
|
|
||||||
p1_checked,
|
|
||||||
p2_checked,
|
|
||||||
p3_checked,
|
|
||||||
)
|
|
||||||
|
|
||||||
def check_thickness(
|
def check_thickness(
|
||||||
self, dimension: str, start: float, thickness: float
|
self,
|
||||||
|
dimension: str,
|
||||||
|
lower_extent: float,
|
||||||
|
thickness: float,
|
||||||
|
cmd_str: str,
|
||||||
) -> Tuple[bool, float, float]:
|
) -> Tuple[bool, float, float]:
|
||||||
"""Check the thickness of an object in a specified dimension.
|
"""Check the thickness of an object in a specified dimension.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
dimension: Dimension to check the thickness value for.
|
dimension: Dimension to check the thickness value for.
|
||||||
This must have value x, y, or z.
|
This must have value x, y, or z.
|
||||||
start: Start coordinate of the object in the specified
|
lower_extent: Lower extent of the object in the specified
|
||||||
dimension. This must be in the local grid coordinate
|
dimension.
|
||||||
system - i.e. previously translated using the
|
|
||||||
round_to_grid function.
|
|
||||||
thickness: Thickness of the object.
|
thickness: Thickness of the object.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
@@ -231,35 +233,71 @@ class MainGridUserInput(UserInput[GridType]):
|
|||||||
Returns:
|
Returns:
|
||||||
within_grid: True if part of the object is within the
|
within_grid: True if part of the object is within the
|
||||||
current grid. False otherwise.
|
current grid. False otherwise.
|
||||||
start: Start value limited to the bounds of the grid.
|
lower_extent: Lower extent limited to the bounds of the
|
||||||
thickness: Thickness value such that start + thickness is
|
grid.
|
||||||
within the bounds of the grid.
|
thickness: Thickness value such that lower_extent +
|
||||||
|
thickness is within the bounds of the grid.
|
||||||
"""
|
"""
|
||||||
# TODO: This should throw an error if the bounds are outside the
|
if thickness < 0:
|
||||||
# global grid.
|
raise ValueError(f"'{cmd_str}' requires a non negative thickness")
|
||||||
|
|
||||||
|
if lower_extent < 0:
|
||||||
|
raise ValueError(
|
||||||
|
f"'{cmd_str}' lower extent should be non negative in the {dimension} dimension"
|
||||||
|
)
|
||||||
|
|
||||||
|
upper_extent = lower_extent + thickness
|
||||||
|
|
||||||
if dimension == "x":
|
if dimension == "x":
|
||||||
grid_size = self.grid.nx * self.grid.dx
|
lower_point = self.discretise_point((lower_extent, 0, 0))
|
||||||
|
upper_point = self.discretise_point((upper_extent, 0, 0))
|
||||||
|
thickness_point = self.discretise_static_point((thickness, 0, 0))
|
||||||
|
index = 0
|
||||||
elif dimension == "y":
|
elif dimension == "y":
|
||||||
grid_size = self.grid.ny * self.grid.dy
|
lower_point = self.discretise_point((0, lower_extent, 0))
|
||||||
|
upper_point = self.discretise_point((0, upper_extent, 0))
|
||||||
|
thickness_point = self.discretise_static_point((0, thickness, 0))
|
||||||
|
index = 1
|
||||||
elif dimension == "z":
|
elif dimension == "z":
|
||||||
grid_size = self.grid.nz * self.grid.dz
|
lower_point = self.discretise_point((0, 0, lower_extent))
|
||||||
|
upper_point = self.discretise_point((0, 0, upper_extent))
|
||||||
|
thickness_point = self.discretise_static_point((0, 0, thickness))
|
||||||
|
index = 2
|
||||||
else:
|
else:
|
||||||
raise ValueError("Dimension should have value x, y, or z")
|
raise ValueError("Dimension should have value x, y, or z")
|
||||||
|
|
||||||
end = start + thickness
|
try:
|
||||||
|
self.grid.within_bounds(upper_point)
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError(
|
||||||
|
f"'{cmd_str}' extends beyond the size of the model in the {dimension} dimension"
|
||||||
|
)
|
||||||
|
|
||||||
if start > grid_size:
|
# Work with discretised (int) values as reduces imprecision due
|
||||||
return False, start, thickness
|
# to floating point calculations
|
||||||
elif end < 0:
|
size = self.grid.size[index]
|
||||||
return False, start, thickness
|
lower_extent = lower_point[index]
|
||||||
|
upper_extent = upper_point[index]
|
||||||
|
thickness = thickness_point[index]
|
||||||
|
|
||||||
if start < 0:
|
# These should only trigger for MPIGrids.
|
||||||
thickness += start
|
# TODO: Can this be structured so these checks happen in the
|
||||||
start = 0
|
# MPIGridUserInput object?
|
||||||
if end > grid_size:
|
if lower_extent < 0:
|
||||||
thickness -= end - grid_size
|
thickness += lower_extent
|
||||||
|
lower_extent = 0
|
||||||
|
if upper_extent > size:
|
||||||
|
thickness -= upper_extent - size
|
||||||
|
|
||||||
return True, start, thickness
|
dl = self.grid.dl[index]
|
||||||
|
|
||||||
|
return (
|
||||||
|
lower_extent <= size
|
||||||
|
and upper_extent >= 0
|
||||||
|
and not (upper_extent > size and thickness <= 0),
|
||||||
|
lower_extent * dl,
|
||||||
|
thickness * dl,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MPIUserInput(MainGridUserInput[MPIGrid]):
|
class MPIUserInput(MainGridUserInput[MPIGrid]):
|
||||||
|
@@ -90,7 +90,9 @@ class CylindricalSector(GeometryUserObject):
|
|||||||
elif normal == "z":
|
elif normal == "z":
|
||||||
ctr1, ctr2, level = uip.round_to_grid((ctr1, ctr2, extent1))
|
ctr1, ctr2, level = uip.round_to_grid((ctr1, ctr2, extent1))
|
||||||
|
|
||||||
sector_within_grid, level, thickness = uip.check_thickness(normal, level, thickness)
|
sector_within_grid, level, thickness = uip.check_thickness(
|
||||||
|
normal, extent1, thickness, self.__str__()
|
||||||
|
)
|
||||||
|
|
||||||
# Exit early if none of the cylindrical sector is in this grid
|
# Exit early if none of the cylindrical sector is in this grid
|
||||||
# as there is nothing else to do.
|
# as there is nothing else to do.
|
||||||
|
@@ -96,37 +96,35 @@ class Triangle(RotatableMixin, GeometryUserObject):
|
|||||||
logger.exception(f"{self.__str__()} no materials have been specified")
|
logger.exception(f"{self.__str__()} no materials have been specified")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if thickness < 0:
|
|
||||||
logger.exception(f"{self.__str__()} requires a positive value for thickness")
|
|
||||||
raise ValueError
|
|
||||||
|
|
||||||
uip = self._create_uip(grid)
|
uip = self._create_uip(grid)
|
||||||
|
|
||||||
# Check whether points are valid against grid
|
# Check whether points are valid against grid
|
||||||
uip.check_tri_points(up1, up2, up3, self.__str__())
|
dp1, dp2, dp3 = uip.check_tri_points(up1, up2, up3, self.__str__())
|
||||||
# Convert points to metres
|
# Convert points to metres
|
||||||
x1, y1, z1 = uip.round_to_grid(up1)
|
x1, y1, z1 = uip.discrete_to_continuous(dp1)
|
||||||
x2, y2, z2 = uip.round_to_grid(up2)
|
x2, y2, z2 = uip.discrete_to_continuous(dp2)
|
||||||
x3, y3, z3 = uip.round_to_grid(up3)
|
x3, y3, z3 = uip.discrete_to_continuous(dp3)
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
# yz-plane triangle
|
# yz-plane triangle
|
||||||
if x1 == x2 == x3:
|
if x1 == x2 == x3:
|
||||||
normal = "x"
|
normal = "x"
|
||||||
start = x1
|
lower_extent = up1[0]
|
||||||
# xz-plane triangle
|
# xz-plane triangle
|
||||||
elif y1 == y2 == y3:
|
elif y1 == y2 == y3:
|
||||||
normal = "y"
|
normal = "y"
|
||||||
start = y1
|
lower_extent = up1[1]
|
||||||
# xy-plane triangle
|
# xy-plane triangle
|
||||||
elif z1 == z2 == z3:
|
elif z1 == z2 == z3:
|
||||||
normal = "z"
|
normal = "z"
|
||||||
start = z1
|
lower_extent = up1[2]
|
||||||
else:
|
else:
|
||||||
logger.exception(f"{self.__str__()} the triangle is not specified correctly")
|
logger.exception(f"{self.__str__()} the triangle is not specified correctly")
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
triangle_within_grid, start, thickness = uip.check_thickness(normal, start, thickness)
|
triangle_within_grid, lower_extent, thickness = uip.check_thickness(
|
||||||
|
normal, lower_extent, thickness, self.__str__()
|
||||||
|
)
|
||||||
|
|
||||||
# Exit early if none of the triangle is in this grid as there is
|
# Exit early if none of the triangle is in this grid as there is
|
||||||
# nothing else to do.
|
# nothing else to do.
|
||||||
@@ -136,19 +134,13 @@ class Triangle(RotatableMixin, GeometryUserObject):
|
|||||||
# Update start bound of the triangle
|
# Update start bound of the triangle
|
||||||
# yz-plane triangle
|
# yz-plane triangle
|
||||||
if normal == "x":
|
if normal == "x":
|
||||||
x1 = start
|
x1 = x2 = x3 = lower_extent
|
||||||
x2 = start
|
|
||||||
x3 = start
|
|
||||||
# xz-plane triangle
|
# xz-plane triangle
|
||||||
elif normal == "y":
|
elif normal == "y":
|
||||||
y1 = start
|
y1 = y2 = y3 = lower_extent
|
||||||
y2 = start
|
|
||||||
y3 = start
|
|
||||||
# xy-plane triangle
|
# xy-plane triangle
|
||||||
elif normal == "z":
|
elif normal == "z":
|
||||||
z1 = start
|
z1 = z2 = z3 = lower_extent
|
||||||
z2 = start
|
|
||||||
z3 = start
|
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
||||||
|
@@ -8,6 +8,6 @@
|
|||||||
#rx: 0.080 0.080 0.080
|
#rx: 0.080 0.080 0.080
|
||||||
|
|
||||||
#material: 8 0 1 0 half_space
|
#material: 8 0 1 0 half_space
|
||||||
#cylindrical_sector: z 0.07 0.06 0.04 0.12 0.05 30 240 half_space
|
#cylindrical_sector: z 0.07 0.06 0.04 0.1 0.05 30 240 half_space
|
||||||
|
|
||||||
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume
|
||||||
|
在新工单中引用
屏蔽一个用户