你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-08 15:27:57 +08:00
Update multiuse cmds to new user object classes
这个提交包含在:
@@ -110,7 +110,7 @@ class Snapshot:
|
|||||||
filename: str,
|
filename: str,
|
||||||
fileext: str,
|
fileext: str,
|
||||||
outputs: Dict[str, bool],
|
outputs: Dict[str, bool],
|
||||||
grid_dl: npt.NDArray[np.float32],
|
grid_dl: npt.NDArray[np.float64],
|
||||||
grid_dt: float,
|
grid_dt: float,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@@ -358,7 +358,7 @@ class MPISnapshot(Snapshot):
|
|||||||
filename: str,
|
filename: str,
|
||||||
fileext: str,
|
fileext: str,
|
||||||
outputs: Dict[str, bool],
|
outputs: Dict[str, bool],
|
||||||
grid_dl: npt.NDArray[np.float32],
|
grid_dl: npt.NDArray[np.float64],
|
||||||
grid_dt: float,
|
grid_dt: float,
|
||||||
):
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
|
文件差异内容过多而无法显示
加载差异
180
gprMax/user_objects/cmds_output.py
普通文件
180
gprMax/user_objects/cmds_output.py
普通文件
@@ -0,0 +1,180 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from gprMax.geometry_outputs import GeometryObjects as GeometryObjectsUser
|
||||||
|
from gprMax.geometry_outputs import MPIGeometryObjects as MPIGeometryObjectsUser
|
||||||
|
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||||
|
from gprMax.grid.mpi_grid import MPIGrid
|
||||||
|
from gprMax.model import Model
|
||||||
|
from gprMax.subgrids.grid import SubGridBaseGrid
|
||||||
|
from gprMax.user_objects.user_objects import OutputUserObject
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class GeometryView(OutputUserObject):
|
||||||
|
"""Outputs to file(s) information about the geometry (mesh) of model.
|
||||||
|
|
||||||
|
The geometry information is saved in Visual Toolkit (VTK) formats.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
p1: tuple required for lower left (x,y,z) coordinates of volume of
|
||||||
|
geometry view in metres.
|
||||||
|
p2: tuple required for upper right (x,y,z) coordinates of volume of
|
||||||
|
geometry view in metres.
|
||||||
|
dl: tuple required for spatial discretisation of geometry view in metres.
|
||||||
|
output_tuple: string required for per-cell 'n' (normal) or per-cell-edge
|
||||||
|
'f' (fine) geometry views.
|
||||||
|
filename: string required for filename where geometry view will be
|
||||||
|
stored in the same directory as input file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def order(self):
|
||||||
|
return 17
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hash(self):
|
||||||
|
return "#geometry_view"
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
def geometry_view_constructor(self, output_type):
|
||||||
|
"""Selects appropriate class for geometry view dependent on geometry
|
||||||
|
view type, i.e. normal or fine.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if output_type == "n":
|
||||||
|
from gprMax.geometry_outputs import GeometryViewVoxels as GeometryViewUser
|
||||||
|
else:
|
||||||
|
from gprMax.geometry_outputs import GeometryViewLines as GeometryViewUser
|
||||||
|
|
||||||
|
return GeometryViewUser
|
||||||
|
|
||||||
|
def build(self, model: Model, grid: FDTDGrid):
|
||||||
|
try:
|
||||||
|
p1 = self.kwargs["p1"]
|
||||||
|
p2 = self.kwargs["p2"]
|
||||||
|
dl = self.kwargs["dl"]
|
||||||
|
output_type = self.kwargs["output_type"].lower()
|
||||||
|
filename = self.kwargs["filename"]
|
||||||
|
except KeyError:
|
||||||
|
logger.exception(f"{self.params_str()} requires exactly eleven parameters.")
|
||||||
|
raise
|
||||||
|
|
||||||
|
GeometryViewUser = self.geometry_view_constructor(output_type)
|
||||||
|
|
||||||
|
uip = self._create_uip(grid)
|
||||||
|
try:
|
||||||
|
p3 = uip.round_to_grid_static_point(p1)
|
||||||
|
p4 = uip.round_to_grid_static_point(p2)
|
||||||
|
p1, p2 = uip.check_box_points(p1, p2, self.params_str())
|
||||||
|
except ValueError:
|
||||||
|
logger.exception(f"{self.params_str()} point is outside the domain.")
|
||||||
|
raise
|
||||||
|
xs, ys, zs = p1
|
||||||
|
xf, yf, zf = p2
|
||||||
|
|
||||||
|
dx, dy, dz = uip.discretise_static_point(dl)
|
||||||
|
|
||||||
|
if dx < 0 or dy < 0 or dz < 0:
|
||||||
|
logger.exception(f"{self.params_str()} the step size should not be less than zero.")
|
||||||
|
raise ValueError
|
||||||
|
if dx > grid.nx or dy > grid.ny or dz > grid.nz:
|
||||||
|
logger.exception(
|
||||||
|
f"{self.params_str()} the step size should be less than the domain size."
|
||||||
|
)
|
||||||
|
raise ValueError
|
||||||
|
if dx < 1 or dy < 1 or dz < 1:
|
||||||
|
logger.exception(
|
||||||
|
f"{self.params_str()} the step size should not be less than the spatial discretisation."
|
||||||
|
)
|
||||||
|
raise ValueError
|
||||||
|
if output_type not in ["n", "f"]:
|
||||||
|
logger.exception(
|
||||||
|
f"{self.params_str()} requires type to be either n (normal) or f (fine)."
|
||||||
|
)
|
||||||
|
raise ValueError
|
||||||
|
if output_type == "f" and (
|
||||||
|
dx * grid.dx != grid.dx or dy * grid.dy != grid.dy or dz * grid.dz != grid.dz
|
||||||
|
):
|
||||||
|
logger.exception(
|
||||||
|
f"{self.params_str()} requires the spatial "
|
||||||
|
"discretisation for the geometry view to be the "
|
||||||
|
"same as the model for geometry view of "
|
||||||
|
"type f (fine)"
|
||||||
|
)
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
g = GeometryViewUser(xs, ys, zs, xf, yf, zf, dx, dy, dz, filename, grid)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"{self.grid_name(grid)}Geometry view from {p3[0]:g}m, "
|
||||||
|
f"{p3[1]:g}m, {p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m, "
|
||||||
|
f"{p4[2]:g}m, discretisation {dx * grid.dx:g}m, "
|
||||||
|
f"{dy * grid.dy:g}m, {dz * grid.dz:g}m, with filename "
|
||||||
|
f"base {g.filename} created."
|
||||||
|
)
|
||||||
|
|
||||||
|
model.geometryviews.append(g)
|
||||||
|
|
||||||
|
|
||||||
|
class GeometryObjectsWrite(OutputUserObject):
|
||||||
|
"""Writes geometry generated in a model to file which can be imported into
|
||||||
|
other models.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
p1: tuple required for lower left (x,y,z) coordinates of volume of
|
||||||
|
output in metres.
|
||||||
|
p2: tuple required for upper right (x,y,z) coordinates of volume of
|
||||||
|
output in metres.
|
||||||
|
filename: string required for filename where output will be stored in
|
||||||
|
the same directory as input file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def order(self):
|
||||||
|
return 18
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hash(self):
|
||||||
|
return "#geometry_objects_write"
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
def build(self, model: Model, grid: FDTDGrid):
|
||||||
|
if isinstance(grid, SubGridBaseGrid):
|
||||||
|
logger.exception(f"{self.params_str()} do not add geometry objects to subgrids.")
|
||||||
|
raise ValueError
|
||||||
|
try:
|
||||||
|
p1 = self.kwargs["p1"]
|
||||||
|
p2 = self.kwargs["p2"]
|
||||||
|
basefilename = self.kwargs["filename"]
|
||||||
|
except KeyError:
|
||||||
|
logger.exception(f"{self.params_str()} requires exactly seven parameters.")
|
||||||
|
raise
|
||||||
|
|
||||||
|
uip = self._create_uip(grid)
|
||||||
|
p1, p2 = uip.check_box_points(p1, p2, self.params_str())
|
||||||
|
x0, y0, z0 = p1
|
||||||
|
x1, y1, z1 = p2
|
||||||
|
|
||||||
|
# TODO: Remove these when add parallel build
|
||||||
|
if isinstance(grid, MPIGrid):
|
||||||
|
geometry_object_type = MPIGeometryObjectsUser
|
||||||
|
else:
|
||||||
|
geometry_object_type = GeometryObjectsUser
|
||||||
|
|
||||||
|
g = geometry_object_type(x0, y0, z0, x1, y1, z1, basefilename)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"Geometry objects in the volume from {p1[0] * grid.dx:g}m, "
|
||||||
|
f"{p1[1] * grid.dy:g}m, {p1[2] * grid.dz:g}m, to "
|
||||||
|
f"{p2[0] * grid.dx:g}m, {p2[1] * grid.dy:g}m, "
|
||||||
|
f"{p2[2] * grid.dz:g}m, will be written to "
|
||||||
|
f"{g.filename_hdf5}, with materials written to "
|
||||||
|
f"{g.filename_materials}"
|
||||||
|
)
|
||||||
|
|
||||||
|
model.geometryobjects.append(g)
|
@@ -253,7 +253,7 @@ class TimeWindow(ModelUserObject):
|
|||||||
|
|
||||||
if self.time is not None and self.iterations is not None:
|
if self.time is not None and self.iterations is not None:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"{self._params_str()} Time and iterations were both specified, using 'time'"
|
f"{self.params_str()} Time and iterations were both specified, using 'time'"
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"Time window: {model.timewindow:g} secs ({model.iterations} iterations)")
|
logger.info(f"Time window: {model.timewindow:g} secs ({model.iterations} iterations)")
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
|
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||||
|
|
||||||
|
|
||||||
class Rotatable(ABC):
|
class Rotatable(ABC):
|
||||||
"""Stores parameters and defines an interface for rotatable objects.
|
"""Stores parameters and defines an interface for rotatable objects.
|
||||||
@@ -38,6 +40,6 @@ class Rotatable(ABC):
|
|||||||
self.do_rotate = True
|
self.do_rotate = True
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _do_rotate(self):
|
def _do_rotate(self, grid: FDTDGrid):
|
||||||
"""Performs the rotation."""
|
"""Performs the rotation."""
|
||||||
pass
|
pass
|
||||||
|
@@ -3,7 +3,6 @@ from typing import List, Union
|
|||||||
|
|
||||||
from gprMax import config
|
from gprMax import config
|
||||||
from gprMax.grid.fdtd_grid import FDTDGrid
|
from gprMax.grid.fdtd_grid import FDTDGrid
|
||||||
from gprMax.grid.mpi_grid import MPIGrid
|
|
||||||
from gprMax.model import Model
|
from gprMax.model import Model
|
||||||
from gprMax.subgrids.grid import SubGridBaseGrid
|
from gprMax.subgrids.grid import SubGridBaseGrid
|
||||||
from gprMax.user_inputs import MainGridUserInput, SubgridUserInput
|
from gprMax.user_inputs import MainGridUserInput, SubgridUserInput
|
||||||
@@ -60,7 +59,7 @@ class UserObject(ABC):
|
|||||||
|
|
||||||
return f"{self.hash}: {' '.join(args)}"
|
return f"{self.hash}: {' '.join(args)}"
|
||||||
|
|
||||||
def _params_str(self) -> str:
|
def params_str(self) -> str:
|
||||||
"""Readable string of parameters given to object."""
|
"""Readable string of parameters given to object."""
|
||||||
return f"{self.hash}: {str(self.kwargs)}"
|
return f"{self.hash}: {str(self.kwargs)}"
|
||||||
|
|
||||||
@@ -115,10 +114,42 @@ class GridUserObject(MultiUserObject):
|
|||||||
def build(self, grid: FDTDGrid):
|
def build(self, grid: FDTDGrid):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def grid_name(self, grid: FDTDGrid) -> str:
|
||||||
|
"""Format grid name for use with logging info.
|
||||||
|
|
||||||
|
Returns an empty string if the grid is the main grid.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
grid: Grid to get the name of.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
grid_name: Formatted version of the grid name.
|
||||||
|
"""
|
||||||
|
if isinstance(grid, SubGridBaseGrid):
|
||||||
|
return f"[{grid.name}] "
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
class OutputUserObject(MultiUserObject):
|
class OutputUserObject(MultiUserObject):
|
||||||
"""User defined object that controls the output of data."""
|
"""User defined object that controls the output of data."""
|
||||||
|
|
||||||
|
def grid_name(self, grid: FDTDGrid) -> str:
|
||||||
|
"""Format grid name for use with logging info.
|
||||||
|
|
||||||
|
Returns an empty string if the grid is the main grid.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
grid: Grid to get the name of.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
grid_name: Formatted version of the grid name.
|
||||||
|
"""
|
||||||
|
if isinstance(grid, SubGridBaseGrid):
|
||||||
|
return f"[{grid.name}] "
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def build(self, model: Model, grid: FDTDGrid):
|
def build(self, model: Model, grid: FDTDGrid):
|
||||||
pass
|
pass
|
||||||
|
在新工单中引用
屏蔽一个用户