From 70151168fa48c937b7c4c68807c3b71af63b5111 Mon Sep 17 00:00:00 2001 From: nmannall Date: Wed, 11 Dec 2024 18:59:23 +0000 Subject: [PATCH] Refactor geometry cmds to use new user object class --- .../user_objects/cmds_geometry/add_grass.py | 26 ++++++------- .../cmds_geometry/add_surface_roughness.py | 26 ++++++------- .../cmds_geometry/add_surface_water.py | 26 ++++++------- gprMax/user_objects/cmds_geometry/box.py | 26 ++++++------- .../cmds_geometry/cmds_geometry.py | 38 ------------------- gprMax/user_objects/cmds_geometry/cone.py | 14 ++++--- gprMax/user_objects/cmds_geometry/cylinder.py | 14 ++++--- .../cmds_geometry/cylindrical_sector.py | 14 ++++--- gprMax/user_objects/cmds_geometry/edge.py | 26 ++++++------- .../user_objects/cmds_geometry/ellipsoid.py | 14 ++++--- .../user_objects/cmds_geometry/fractal_box.py | 30 +++++++-------- .../cmds_geometry/geometry_objects_read.py | 19 +++++----- gprMax/user_objects/cmds_geometry/plate.py | 26 ++++++------- gprMax/user_objects/cmds_geometry/sphere.py | 14 ++++--- gprMax/user_objects/cmds_geometry/triangle.py | 26 ++++++------- gprMax/user_objects/user_objects.py | 8 +++- 16 files changed, 168 insertions(+), 179 deletions(-) diff --git a/gprMax/user_objects/cmds_geometry/add_grass.py b/gprMax/user_objects/cmds_geometry/add_grass.py index 517b39e5..236e593d 100644 --- a/gprMax/user_objects/cmds_geometry/add_grass.py +++ b/gprMax/user_objects/cmds_geometry/add_grass.py @@ -21,15 +21,18 @@ import logging import numpy as np from gprMax.fractals import FractalSurface, Grass +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.materials import create_grass +from gprMax.user_objects.rotatable import Rotatable +from gprMax.user_objects.user_objects import GeometryUserObject from gprMax.utilities.utilities import round_value -from .cmds_geometry import UserObjectGeometry, rotate_2point_object +from .cmds_geometry import rotate_2point_object logger = logging.getLogger(__name__) -class AddGrass(UserObjectGeometry): +class AddGrass(GeometryUserObject, Rotatable): """Adds grass with roots to a FractalBox class in the model. Attributes: @@ -47,25 +50,21 @@ class AddGrass(UserObjectGeometry): grass should be applied to. """ + @property + def hash(self): + return "#add_grass" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#add_grass" - def rotate(self, axis, angle, origin=None): - """Set parameters for rotation.""" - self.axis = axis - self.angle = angle - self.origin = origin - self.do_rotate = True - - def _do_rotate(self): + def _do_rotate(self, grid: FDTDGrid): """Perform rotation.""" pts = np.array([self.kwargs["p1"], self.kwargs["p2"]]) rot_pts = rotate_2point_object(pts, self.axis, self.angle, self.origin) self.kwargs["p1"] = tuple(rot_pts[0, :]) self.kwargs["p2"] = tuple(rot_pts[1, :]) - def build(self, grid, uip): + def build(self, grid: FDTDGrid): """Add Grass to fractal box.""" try: p1 = self.kwargs["p1"] @@ -89,7 +88,7 @@ class AddGrass(UserObjectGeometry): seed = None if self.do_rotate: - self._do_rotate() + self._do_rotate(grid) # Get the correct fractal volume volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id] @@ -99,6 +98,7 @@ class AddGrass(UserObjectGeometry): logger.exception(f"{self.__str__()} cannot find FractalBox {fractal_box_id}") raise + uip = self._create_uip(grid) p1, p2 = uip.check_box_points(p1, p2, self.__str__()) xs, ys, zs = p1 xf, yf, zf = p2 diff --git a/gprMax/user_objects/cmds_geometry/add_surface_roughness.py b/gprMax/user_objects/cmds_geometry/add_surface_roughness.py index 735def56..248e2d43 100644 --- a/gprMax/user_objects/cmds_geometry/add_surface_roughness.py +++ b/gprMax/user_objects/cmds_geometry/add_surface_roughness.py @@ -21,14 +21,17 @@ import logging import numpy as np from gprMax.fractals import FractalSurface +from gprMax.grid.fdtd_grid import FDTDGrid +from gprMax.user_objects.rotatable import Rotatable +from gprMax.user_objects.user_objects import GeometryUserObject from gprMax.utilities.utilities import round_value -from .cmds_geometry import UserObjectGeometry, rotate_2point_object +from .cmds_geometry import rotate_2point_object logger = logging.getLogger(__name__) -class AddSurfaceRoughness(UserObjectGeometry): +class AddSurfaceRoughness(GeometryUserObject, Rotatable): """Adds surface roughness to a FractalBox class in the model. Attributes: @@ -48,25 +51,21 @@ class AddSurfaceRoughness(UserObjectGeometry): number generator used to create the fractals. """ + @property + def hash(self): + return "#add_surface_roughness" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#add_surface_roughness" - def rotate(self, axis, angle, origin=None): - """Set parameters for rotation.""" - self.axis = axis - self.angle = angle - self.origin = origin - self.do_rotate = True - - def _do_rotate(self): + def _do_rotate(self, grid: FDTDGrid): """Perform rotation.""" pts = np.array([self.kwargs["p1"], self.kwargs["p2"]]) rot_pts = rotate_2point_object(pts, self.axis, self.angle, self.origin) self.kwargs["p1"] = tuple(rot_pts[0, :]) self.kwargs["p2"] = tuple(rot_pts[1, :]) - def build(self, grid, uip): + def build(self, grid: FDTDGrid): try: p1 = self.kwargs["p1"] p2 = self.kwargs["p2"] @@ -89,7 +88,7 @@ class AddSurfaceRoughness(UserObjectGeometry): seed = None if self.do_rotate: - self._do_rotate() + self._do_rotate(grid) # Get the correct fractal volume volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id] @@ -99,6 +98,7 @@ class AddSurfaceRoughness(UserObjectGeometry): logger.exception(f"{self.__str__()} cannot find FractalBox {fractal_box_id}") raise ValueError + uip = self._create_uip(grid) p1, p2 = uip.check_box_points(p1, p2, self.__str__()) xs, ys, zs = p1 xf, yf, zf = p2 diff --git a/gprMax/user_objects/cmds_geometry/add_surface_water.py b/gprMax/user_objects/cmds_geometry/add_surface_water.py index 79ec3df5..2a645da9 100644 --- a/gprMax/user_objects/cmds_geometry/add_surface_water.py +++ b/gprMax/user_objects/cmds_geometry/add_surface_water.py @@ -20,15 +20,18 @@ import logging import numpy as np +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.materials import create_water +from gprMax.user_objects.rotatable import Rotatable +from gprMax.user_objects.user_objects import GeometryUserObject from gprMax.utilities.utilities import round_value -from .cmds_geometry import UserObjectGeometry, rotate_2point_object +from .cmds_geometry import rotate_2point_object logger = logging.getLogger(__name__) -class AddSurfaceWater(UserObjectGeometry): +class AddSurfaceWater(GeometryUserObject, Rotatable): """Adds surface water to a FractalBox class in the model. Attributes: @@ -43,25 +46,21 @@ class AddSurfaceWater(UserObjectGeometry): surface water should be applied to. """ + @property + def hash(self): + return "#add_surface_water" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#add_surface_water" - def rotate(self, axis, angle, origin=None): - """Set parameters for rotation.""" - self.axis = axis - self.angle = angle - self.origin = origin - self.do_rotate = True - - def _do_rotate(self): + def _do_rotate(self, grid: FDTDGrid): """Perform rotation.""" pts = np.array([self.kwargs["p1"], self.kwargs["p2"]]) rot_pts = rotate_2point_object(pts, self.axis, self.angle, self.origin) self.kwargs["p1"] = tuple(rot_pts[0, :]) self.kwargs["p2"] = tuple(rot_pts[1, :]) - def build(self, grid, uip): + def build(self, grid: FDTDGrid): """ "Create surface water on fractal box.""" try: p1 = self.kwargs["p1"] @@ -73,7 +72,7 @@ class AddSurfaceWater(UserObjectGeometry): raise if self.do_rotate: - self._do_rotate() + self._do_rotate(grid) if volumes := [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]: volume = volumes[0] @@ -81,6 +80,7 @@ class AddSurfaceWater(UserObjectGeometry): logger.exception(f"{self.__str__()} cannot find FractalBox {fractal_box_id}") raise ValueError + uip = self._create_uip(grid) p1, p2 = uip.check_box_points(p1, p2, self.__str__()) xs, ys, zs = p1 xf, yf, zf = p2 diff --git a/gprMax/user_objects/cmds_geometry/box.py b/gprMax/user_objects/cmds_geometry/box.py index 0ebf05c6..718c59c6 100644 --- a/gprMax/user_objects/cmds_geometry/box.py +++ b/gprMax/user_objects/cmds_geometry/box.py @@ -22,14 +22,17 @@ import numpy as np import gprMax.config as config from gprMax.cython.geometry_primitives import build_box +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.materials import Material +from gprMax.user_objects.rotatable import Rotatable +from gprMax.user_objects.user_objects import GeometryUserObject -from .cmds_geometry import UserObjectGeometry, check_averaging, rotate_2point_object +from .cmds_geometry import rotate_2point_object logger = logging.getLogger(__name__) -class Box(UserObjectGeometry): +class Box(GeometryUserObject, Rotatable): """Introduces an orthogonal parallelepiped with specific properties into the model. @@ -42,25 +45,21 @@ class Box(UserObjectGeometry): averaging: string (y or n) used to switch on and off dielectric smoothing. """ + @property + def hash(self): + return "#box" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#box" - def rotate(self, axis, angle, origin=None): - """Set parameters for rotation.""" - self.axis = axis - self.angle = angle - self.origin = origin - self.do_rotate = True - - def _do_rotate(self): + def _do_rotate(self, grid: FDTDGrid): """Perform rotation.""" pts = np.array([self.kwargs["p1"], self.kwargs["p2"]]) rot_pts = rotate_2point_object(pts, self.axis, self.angle, self.origin) self.kwargs["p1"] = tuple(rot_pts[0, :]) self.kwargs["p2"] = tuple(rot_pts[1, :]) - def build(self, grid, uip): + def build(self, grid: FDTDGrid): try: p1 = self.kwargs["p1"] p2 = self.kwargs["p2"] @@ -69,7 +68,7 @@ class Box(UserObjectGeometry): raise if self.do_rotate: - self._do_rotate() + self._do_rotate(grid) # Check materials have been specified # Isotropic case @@ -91,6 +90,7 @@ class Box(UserObjectGeometry): # Otherwise go with the grid default averagebox = grid.averagevolumeobjects + uip = self._create_uip(grid) p3, p4 = uip.check_box_points(p1, p2, self.__str__()) # Find nearest point on grid without translation p5 = uip.round_to_grid_static_point(p1) diff --git a/gprMax/user_objects/cmds_geometry/cmds_geometry.py b/gprMax/user_objects/cmds_geometry/cmds_geometry.py index 41b6b778..13af63dd 100644 --- a/gprMax/user_objects/cmds_geometry/cmds_geometry.py +++ b/gprMax/user_objects/cmds_geometry/cmds_geometry.py @@ -26,44 +26,6 @@ import gprMax.config as config logger = logging.getLogger(__name__) -class UserObjectGeometry: - """Specific Geometry object.""" - - def __init__(self, **kwargs): - self.kwargs = kwargs - self.hash = "#example" - self.autotranslate = True - self.do_rotate = False - - def __str__(self): - """Readable string of parameters given to object.""" - s = "" - for _, v in self.kwargs.items(): - if isinstance(v, (tuple, list)): - v = " ".join([str(el) for el in v]) - s += f"{str(v)} " - - return f"{self.hash}: {s[:-1]}" - - def build(self, grid, uip): - """Creates object and adds it to the grid.""" - pass - - def rotate(self, axis, angle, origin=None): - """Rotates object - specialised for each object.""" - pass - - def grid_name(self, grid): - """Returns subgrid name for use with logging info. Returns an empty - string if the grid is the main grid. - """ - - if config.sim_config.general["subgrid"] and grid.name != "main_grid": - return f"[{grid.name}] " - else: - return "" - - def check_averaging(averaging): """Check and set material averaging value. diff --git a/gprMax/user_objects/cmds_geometry/cone.py b/gprMax/user_objects/cmds_geometry/cone.py index 11218c86..fffa1729 100644 --- a/gprMax/user_objects/cmds_geometry/cone.py +++ b/gprMax/user_objects/cmds_geometry/cone.py @@ -21,14 +21,14 @@ import logging import numpy as np from gprMax.cython.geometry_primitives import build_cone +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.materials import Material - -from .cmds_geometry import UserObjectGeometry, check_averaging +from gprMax.user_objects.user_objects import GeometryUserObject logger = logging.getLogger(__name__) -class Cone(UserObjectGeometry): +class Cone(GeometryUserObject): """Introduces a circular cone into the model. The difference with the cylinder is that the faces of the cone can have different radii and one of them can be zero. @@ -45,11 +45,14 @@ class Cone(UserObjectGeometry): averaging: string (y or n) used to switch on and off dielectric smoothing. """ + @property + def hash(self): + return "#cone" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#cone" - def build(self, grid, uip): + def build(self, grid: FDTDGrid) -> None: try: p1 = self.kwargs["p1"] p2 = self.kwargs["p2"] @@ -79,6 +82,7 @@ class Cone(UserObjectGeometry): logger.exception(f"{self.__str__()} no materials have been specified") raise + uip = self._create_uip(grid) p3 = uip.round_to_grid_static_point(p1) p4 = uip.round_to_grid_static_point(p2) diff --git a/gprMax/user_objects/cmds_geometry/cylinder.py b/gprMax/user_objects/cmds_geometry/cylinder.py index 8a668f3b..7bcb6c15 100644 --- a/gprMax/user_objects/cmds_geometry/cylinder.py +++ b/gprMax/user_objects/cmds_geometry/cylinder.py @@ -21,14 +21,14 @@ import logging import numpy as np from gprMax.cython.geometry_primitives import build_cylinder +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.materials import Material - -from .cmds_geometry import UserObjectGeometry, check_averaging +from gprMax.user_objects.user_objects import GeometryUserObject logger = logging.getLogger(__name__) -class Cylinder(UserObjectGeometry): +class Cylinder(GeometryUserObject): """Introduces a circular cylinder into the model. Attributes: @@ -43,11 +43,14 @@ class Cylinder(UserObjectGeometry): averaging: string (y or n) used to switch on and off dielectric smoothing. """ + @property + def hash(self): + return "#cylinder" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#cylinder" - def build(self, grid, uip): + def build(self, grid: FDTDGrid): try: p1 = self.kwargs["p1"] p2 = self.kwargs["p2"] @@ -76,6 +79,7 @@ class Cylinder(UserObjectGeometry): logger.exception(f"{self.__str__()} no materials have been specified") raise + uip = self._create_uip(grid) p3 = uip.round_to_grid_static_point(p1) p4 = uip.round_to_grid_static_point(p2) diff --git a/gprMax/user_objects/cmds_geometry/cylindrical_sector.py b/gprMax/user_objects/cmds_geometry/cylindrical_sector.py index d2f20d9d..6159f8c0 100644 --- a/gprMax/user_objects/cmds_geometry/cylindrical_sector.py +++ b/gprMax/user_objects/cmds_geometry/cylindrical_sector.py @@ -21,14 +21,14 @@ import logging import numpy as np from gprMax.cython.geometry_primitives import build_cylindrical_sector +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.materials import Material - -from .cmds_geometry import UserObjectGeometry, check_averaging +from gprMax.user_objects.user_objects import GeometryUserObject logger = logging.getLogger(__name__) -class CylindricalSector(UserObjectGeometry): +class CylindricalSector(GeometryUserObject): """Introduces a cylindrical sector (shaped like a slice of pie) into the model. Attributes: @@ -52,11 +52,14 @@ class CylindricalSector(UserObjectGeometry): averaging: string (y or n) used to switch on and off dielectric smoothing. """ + @property + def hash(self): + return "#cylindrical_sector" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#cylindrical_sector" - def build(self, grid, uip): + def build(self, grid: FDTDGrid): try: normal = self.kwargs["normal"].lower() ctr1 = self.kwargs["ctr1"] @@ -159,6 +162,7 @@ class CylindricalSector(UserObjectGeometry): numIDy = materials[1].numID numIDz = materials[2].numID + uip = self._create_uip(grid) # yz-plane cylindrical sector if normal == "x": level, ctr1, ctr2 = uip.round_to_grid((extent1, ctr1, ctr2)) diff --git a/gprMax/user_objects/cmds_geometry/edge.py b/gprMax/user_objects/cmds_geometry/edge.py index ddbc2101..7289b242 100644 --- a/gprMax/user_objects/cmds_geometry/edge.py +++ b/gprMax/user_objects/cmds_geometry/edge.py @@ -21,13 +21,16 @@ import logging import numpy as np from gprMax.cython.geometry_primitives import build_edge_x, build_edge_y, build_edge_z +from gprMax.grid.fdtd_grid import FDTDGrid +from gprMax.user_objects.rotatable import Rotatable +from gprMax.user_objects.user_objects import GeometryUserObject -from .cmds_geometry import UserObjectGeometry, rotate_2point_object +from .cmds_geometry import rotate_2point_object logger = logging.getLogger(__name__) -class Edge(UserObjectGeometry): +class Edge(GeometryUserObject, Rotatable): """Introduces a wire with specific properties into the model. Attributes: @@ -37,25 +40,21 @@ class Edge(UserObjectGeometry): to material that has already been defined. """ + @property + def hash(self): + return "#edge" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#edge" - def rotate(self, axis, angle, origin=None): - """Set parameters for rotation.""" - self.axis = axis - self.angle = angle - self.origin = origin - self.do_rotate = True - - def _do_rotate(self): + def _do_rotate(self, grid: FDTDGrid): """Performs rotation.""" pts = np.array([self.kwargs["p1"], self.kwargs["p2"]]) rot_pts = rotate_2point_object(pts, self.axis, self.angle, self.origin) self.kwargs["p1"] = tuple(rot_pts[0, :]) self.kwargs["p2"] = tuple(rot_pts[1, :]) - def build(self, grid, uip): + def build(self, grid: FDTDGrid): """Creates edge and adds it to the grid.""" try: p1 = self.kwargs["p1"] @@ -66,8 +65,9 @@ class Edge(UserObjectGeometry): raise if self.do_rotate: - self._do_rotate() + self._do_rotate(grid) + uip = self._create_uip(grid) p3 = uip.round_to_grid_static_point(p1) p4 = uip.round_to_grid_static_point(p2) diff --git a/gprMax/user_objects/cmds_geometry/ellipsoid.py b/gprMax/user_objects/cmds_geometry/ellipsoid.py index d78963c0..464c351f 100644 --- a/gprMax/user_objects/cmds_geometry/ellipsoid.py +++ b/gprMax/user_objects/cmds_geometry/ellipsoid.py @@ -21,14 +21,14 @@ import logging import numpy as np from gprMax.cython.geometry_primitives import build_ellipsoid +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.materials import Material - -from .cmds_geometry import UserObjectGeometry, check_averaging +from gprMax.user_objects.user_objects import GeometryUserObject logger = logging.getLogger(__name__) -class Ellipsoid(UserObjectGeometry): +class Ellipsoid(GeometryUserObject): """Introduces an ellipsoidal object with specific parameters into the model. Attributes: @@ -42,11 +42,14 @@ class Ellipsoid(UserObjectGeometry): averaging: string (y or n) used to switch on and off dielectric smoothing. """ + @property + def hash(self): + return "#ellipsoid" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#ellipsoid" - def build(self, grid, uip): + def build(self, grid: FDTDGrid): try: p1 = self.kwargs["p1"] xr = self.kwargs["xr"] @@ -78,6 +81,7 @@ class Ellipsoid(UserObjectGeometry): raise # Centre of ellipsoid + uip = self._create_uip(grid) p2 = uip.round_to_grid_static_point(p1) xc, yc, zc = uip.discretise_point(p1) diff --git a/gprMax/user_objects/cmds_geometry/fractal_box.py b/gprMax/user_objects/cmds_geometry/fractal_box.py index 1c8f611c..4181e227 100644 --- a/gprMax/user_objects/cmds_geometry/fractal_box.py +++ b/gprMax/user_objects/cmds_geometry/fractal_box.py @@ -23,13 +23,16 @@ import numpy as np import gprMax.config as config from gprMax.cython.geometry_primitives import build_voxels_from_array, build_voxels_from_array_mask from gprMax.fractals import FractalVolume +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.materials import ListMaterial -from gprMax.user_objects.cmds_geometry.cmds_geometry import UserObjectGeometry, rotate_2point_object +from gprMax.user_objects.cmds_geometry.cmds_geometry import rotate_2point_object +from gprMax.user_objects.rotatable import Rotatable +from gprMax.user_objects.user_objects import GeometryUserObject logger = logging.getLogger(__name__) -class FractalBox(UserObjectGeometry): +class FractalBox(GeometryUserObject, Rotatable): """Introduces an orthogonal parallelepiped with fractal distributed properties which are related to a mixing model or normal material into the model. @@ -53,26 +56,22 @@ class FractalBox(UserObjectGeometry): averaging: string (y or n) used to switch on and off dielectric smoothing. """ + @property + def hash(self): + return "#fractal_box" + def __init__(self, **kwargs): super().__init__(**kwargs) self.do_pre_build = True - self.hash = "#fractal_box" - def rotate(self, axis, angle, origin=None): - """Set parameters for rotation.""" - self.axis = axis - self.angle = angle - self.origin = origin - self.do_rotate = True - - def _do_rotate(self): + def _do_rotate(self, grid: FDTDGrid): """Performs rotation.""" pts = np.array([self.kwargs["p1"], self.kwargs["p2"]]) rot_pts = rotate_2point_object(pts, self.axis, self.angle, self.origin) self.kwargs["p1"] = tuple(rot_pts[0, :]) self.kwargs["p2"] = tuple(rot_pts[1, :]) - def pre_build(self, grid, uip): + def pre_build(self, grid: FDTDGrid): try: p1 = self.kwargs["p1"] p2 = self.kwargs["p2"] @@ -96,7 +95,7 @@ class FractalBox(UserObjectGeometry): seed = None if self.do_rotate: - self._do_rotate() + self._do_rotate(grid) # Check averaging try: @@ -107,6 +106,7 @@ class FractalBox(UserObjectGeometry): # a fractal box. averagefractalbox = False + uip = self._create_uip(grid) p3 = uip.round_to_grid_static_point(p1) p4 = uip.round_to_grid_static_point(p2) @@ -187,9 +187,9 @@ class FractalBox(UserObjectGeometry): ) grid.fractalvolumes.append(self.volume) - def build(self, grid, uip): + def build(self, grid: FDTDGrid): if self.do_pre_build: - self.pre_build(grid, uip) + self.pre_build(grid) self.do_pre_build = False else: if self.volume.fractalsurfaces: diff --git a/gprMax/user_objects/cmds_geometry/geometry_objects_read.py b/gprMax/user_objects/cmds_geometry/geometry_objects_read.py index 01526962..789a569e 100644 --- a/gprMax/user_objects/cmds_geometry/geometry_objects_read.py +++ b/gprMax/user_objects/cmds_geometry/geometry_objects_read.py @@ -23,23 +23,23 @@ import h5py import gprMax.config as config from gprMax.cython.geometry_primitives import build_voxels_from_array +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.hash_cmds_file import get_user_objects +from gprMax.user_objects.user_objects import GeometryUserObject from gprMax.utilities.utilities import round_value -from .cmds_geometry import UserObjectGeometry - logger = logging.getLogger(__name__) -class GeometryObjectsRead(UserObjectGeometry): +class GeometryObjectsRead(GeometryUserObject): + @property + def hash(self): + return "#geometry_objects_read" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#geometry_objects_read" - def rotate(self, axis, angle, origin=None): - pass - - def build(self, grid, uip): + def build(self, grid: FDTDGrid): """Creates the object and adds it to the grid.""" try: p1 = self.kwargs["p1"] @@ -52,6 +52,7 @@ class GeometryObjectsRead(UserObjectGeometry): # Discretise the point using uip object. This has different behaviour # depending on the type of uip object. So we can use it for # the main grid or the subgrid. + uip = self._create_uip(grid) xs, ys, zs = uip.discretise_point(p1) # See if material file exists at specified path and if not try input @@ -82,7 +83,7 @@ class GeometryObjectsRead(UserObjectGeometry): scene.add(material_obj) # Creates the internal simulation objects - scene.process_cmds(material_objs, grid) + scene.build_grid_objects(material_objs, grid) # Update material type for material in grid.materials: diff --git a/gprMax/user_objects/cmds_geometry/plate.py b/gprMax/user_objects/cmds_geometry/plate.py index 0702a6f4..0b245450 100644 --- a/gprMax/user_objects/cmds_geometry/plate.py +++ b/gprMax/user_objects/cmds_geometry/plate.py @@ -21,13 +21,16 @@ import logging import numpy as np from gprMax.cython.geometry_primitives import build_face_xy, build_face_xz, build_face_yz +from gprMax.grid.fdtd_grid import FDTDGrid +from gprMax.user_objects.rotatable import Rotatable +from gprMax.user_objects.user_objects import GeometryUserObject -from .cmds_geometry import UserObjectGeometry, rotate_2point_object +from .cmds_geometry import rotate_2point_object logger = logging.getLogger(__name__) -class Plate(UserObjectGeometry): +class Plate(GeometryUserObject, Rotatable): """Introduces a plate with specific properties into the model. Attributes: @@ -38,25 +41,21 @@ class Plate(UserObjectGeometry): material_ids: list of material identifiers in the x, y, z directions. """ + @property + def hash(self): + return "#plate" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#plate" - def rotate(self, axis, angle, origin=None): - """Set parameters for rotation.""" - self.axis = axis - self.angle = angle - self.origin = origin - self.do_rotate = True - - def _do_rotate(self): + def _do_rotate(self, grid: FDTDGrid): """Performs rotation.""" pts = np.array([self.kwargs["p1"], self.kwargs["p2"]]) rot_pts = rotate_2point_object(pts, self.axis, self.angle, self.origin) self.kwargs["p1"] = tuple(rot_pts[0, :]) self.kwargs["p2"] = tuple(rot_pts[1, :]) - def build(self, grid, uip): + def build(self, grid: FDTDGrid): try: p1 = self.kwargs["p1"] p2 = self.kwargs["p2"] @@ -76,8 +75,9 @@ class Plate(UserObjectGeometry): raise if self.do_rotate: - self._do_rotate() + self._do_rotate(grid) + uip = self._create_uip(grid) p3 = uip.round_to_grid_static_point(p1) p4 = uip.round_to_grid_static_point(p2) diff --git a/gprMax/user_objects/cmds_geometry/sphere.py b/gprMax/user_objects/cmds_geometry/sphere.py index 300f1bb1..ef2db9cd 100644 --- a/gprMax/user_objects/cmds_geometry/sphere.py +++ b/gprMax/user_objects/cmds_geometry/sphere.py @@ -21,14 +21,14 @@ import logging import numpy as np from gprMax.cython.geometry_primitives import build_sphere +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.materials import Material - -from .cmds_geometry import UserObjectGeometry, check_averaging +from gprMax.user_objects.user_objects import GeometryUserObject logger = logging.getLogger(__name__) -class Sphere(UserObjectGeometry): +class Sphere(GeometryUserObject): """Introduces a spherical object with specific parameters into the model. Attributes: @@ -40,11 +40,14 @@ class Sphere(UserObjectGeometry): averaging: string (y or n) used to switch on and off dielectric smoothing. """ + @property + def hash(self): + return "#sphere" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#sphere" - def build(self, grid, uip): + def build(self, grid: FDTDGrid): try: p1 = self.kwargs["p1"] r = self.kwargs["r"] @@ -73,6 +76,7 @@ class Sphere(UserObjectGeometry): raise # Centre of sphere + uip = self._create_uip(grid) p2 = uip.round_to_grid_static_point(p1) xc, yc, zc = uip.discretise_point(p1) diff --git a/gprMax/user_objects/cmds_geometry/triangle.py b/gprMax/user_objects/cmds_geometry/triangle.py index 8e9a646b..42cab100 100644 --- a/gprMax/user_objects/cmds_geometry/triangle.py +++ b/gprMax/user_objects/cmds_geometry/triangle.py @@ -21,14 +21,17 @@ import logging import numpy as np from gprMax.cython.geometry_primitives import build_triangle +from gprMax.grid.fdtd_grid import FDTDGrid from gprMax.materials import Material +from gprMax.user_objects.rotatable import Rotatable +from gprMax.user_objects.user_objects import GeometryUserObject -from .cmds_geometry import UserObjectGeometry, check_averaging, rotate_point +from .cmds_geometry import rotate_point logger = logging.getLogger(__name__) -class Triangle(UserObjectGeometry): +class Triangle(GeometryUserObject, Rotatable): """Introduces a triangular patch or a triangular prism with specific properties into the model. @@ -44,18 +47,14 @@ class Triangle(UserObjectGeometry): averaging: string (y or n) used to switch on and off dielectric smoothing. """ + @property + def hash(self): + return "#triangle" + def __init__(self, **kwargs): super().__init__(**kwargs) - self.hash = "#triangle" - def rotate(self, axis, angle, origin=None): - """Sets parameters for rotation.""" - self.axis = axis - self.angle = angle - self.origin = origin - self.do_rotate = True - - def _do_rotate(self): + def _do_rotate(self, grid: FDTDGrid): """Performs rotation.""" p1 = rotate_point(self.kwargs["p1"], self.axis, self.angle, self.origin) p2 = rotate_point(self.kwargs["p2"], self.axis, self.angle, self.origin) @@ -64,7 +63,7 @@ class Triangle(UserObjectGeometry): self.kwargs["p2"] = tuple(p2) self.kwargs["p3"] = tuple(p3) - def build(self, grid, uip): + def build(self, grid: FDTDGrid): try: up1 = self.kwargs["p1"] up2 = self.kwargs["p2"] @@ -75,7 +74,7 @@ class Triangle(UserObjectGeometry): raise if self.do_rotate: - self._do_rotate() + self._do_rotate(grid) # Check averaging try: @@ -97,6 +96,7 @@ class Triangle(UserObjectGeometry): logger.exception(f"{self.__str__()} no materials have been specified") raise + uip = self._create_uip(grid) p4 = uip.round_to_grid_static_point(up1) p5 = uip.round_to_grid_static_point(up2) p6 = uip.round_to_grid_static_point(up3) diff --git a/gprMax/user_objects/user_objects.py b/gprMax/user_objects/user_objects.py index 50ff33c5..b4c4c905 100644 --- a/gprMax/user_objects/user_objects.py +++ b/gprMax/user_objects/user_objects.py @@ -145,4 +145,10 @@ class OutputUserObject(UserObject): class GeometryUserObject(GridUserObject): """User defined object that adds geometry to a grid.""" - pass + @property + def order(self): + """Geometry Objects do not have an ordering. + + They should be built in the order they were added to the scene. + """ + return 1