From 07052347ded837682a8b2e8892eafabb63da7b72 Mon Sep 17 00:00:00 2001 From: nmannall Date: Fri, 17 May 2024 13:41:48 +0100 Subject: [PATCH] Setup UserObjectGeometry to build using a Model These now need to build from a model as they access materials from the Model class --- gprMax/cmds_geometry/cmds_geometry.py | 18 +++++++-- gprMax/scene.py | 53 +++++++++++---------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/gprMax/cmds_geometry/cmds_geometry.py b/gprMax/cmds_geometry/cmds_geometry.py index 00c19529..11f1f751 100644 --- a/gprMax/cmds_geometry/cmds_geometry.py +++ b/gprMax/cmds_geometry/cmds_geometry.py @@ -17,16 +17,21 @@ # along with gprMax. If not, see . import logging +from abc import ABC, abstractmethod import numpy as np from scipy.spatial.transform import Rotation as R import gprMax.config as config +from gprMax.grid.fdtd_grid import FDTDGrid +from gprMax.model import Model +from gprMax.subgrids.grid import SubGridBaseGrid +from gprMax.user_inputs import MainGridUserInput logger = logging.getLogger(__name__) -class UserObjectGeometry: +class UserObjectGeometry(ABC): """Specific Geometry object.""" def __init__(self, **kwargs): @@ -45,7 +50,8 @@ class UserObjectGeometry: return f"{self.hash}: {s[:-1]}" - def build(self, grid, uip): + @abstractmethod + def build(self, model: Model, uip: MainGridUserInput): """Creates object and adds it to the grid.""" pass @@ -53,16 +59,20 @@ class UserObjectGeometry: """Rotates object - specialised for each object.""" pass - def grid_name(self, grid): + def grid_name(self, grid: FDTDGrid) -> str: """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": + if isinstance(grid, SubGridBaseGrid): return f"[{grid.name}] " else: return "" + def model_name(self, model: Model) -> str: + """Returns model name for use with logging info.""" + return f"[{model.title}] " + def rotate_point(p, axis, angle, origin=(0, 0, 0)): """Rotates a point. diff --git a/gprMax/scene.py b/gprMax/scene.py index fda85c8c..6071fdab 100644 --- a/gprMax/scene.py +++ b/gprMax/scene.py @@ -62,28 +62,21 @@ class Scene: logger.exception("This object is unknown to gprMax") raise ValueError - def build_grid_obj(self, obj: Union[UserObjectMulti, UserObjectGeometry], grid: FDTDGrid): - """Builds objects in FDTDGrids. - - Args: - obj: user object - grid: FDTDGrid class describing a grid in a model. - """ - uip = create_user_input_points(grid, obj) - try: - obj.build(grid, uip) - except ValueError: - logger.exception("Error creating user input object") - raise - - def build_model_obj(self, obj: UserObjectSingle, model: Model): + def build_obj( + self, + obj: Union[UserObjectSingle, UserObjectMulti, UserObjectGeometry], + model: Model, + subgrid: Optional[FDTDGrid] = None, + ): """Builds objects in models. Args: obj: user object model: Model being built + subgrid: Optional subgrid if building an object in a subgrid """ - uip = create_user_input_points(model.G, obj) + grid = model.G if subgrid is None else subgrid + uip = create_user_input_points(grid, obj) try: obj.build(model, uip) except ValueError: @@ -105,7 +98,7 @@ class Scene: # to build in the correct subgrid. sg = sg_cmd.subgrid self.process_cmds(sg_cmd.children_multiple, model, sg) - self.process_geocmds(sg_cmd.children_geometry, sg) + self.process_geocmds(sg_cmd.children_geometry, model, sg) def process_cmds( self, @@ -114,22 +107,23 @@ class Scene: subgrid: Optional[SubGridBaseGrid] = None, ): """Process list of commands.""" - grid = model.G if subgrid is None else subgrid cmds_sorted = sorted(commands, key=lambda cmd: cmd.order) for obj in cmds_sorted: - if isinstance(obj, UserObjectSingle): - self.build_model_obj(obj, model) - else: - self.build_grid_obj(obj, grid) + self.build_obj(obj, model, subgrid) return self - def process_geocmds(self, commands, grid): + def process_geocmds( + self, + commands: List[UserObjectGeometry], + model: Model, + subgrid: Optional[SubGridBaseGrid] = None, + ): # Check for fractal boxes and modifications and pre-process them first proc_cmds = [] for obj in commands: if isinstance(obj, (FractalBox, AddGrass, AddSurfaceRoughness, AddSurfaceWater)): - self.build_grid_obj(obj, grid) + self.build_obj(obj, model, subgrid) if isinstance(obj, (FractalBox)): proc_cmds.append(obj) else: @@ -137,7 +131,7 @@ class Scene: # Process all geometry commands for obj in proc_cmds: - self.build_grid_obj(obj, grid) + self.build_obj(obj, model, subgrid) return self @@ -166,11 +160,8 @@ class Scene: presents the user with UserObjects in order to build the internal Rx(), Cylinder() etc... objects. """ - - G = model.G - # Create pre-defined (built-in) materials - create_built_in_materials(G) + create_built_in_materials(model.G) # Process commands that can only have a single instance self.process_singlecmds(model) @@ -179,11 +170,11 @@ class Scene: self.process_cmds(self.multiple_cmds, model) # Initialise geometry arrays for main and subgrids - for grid in [G] + G.subgrids: + for grid in [model.G] + model.subgrids: grid.initialise_geometry_arrays() # Process the main grid geometry commands - self.process_geocmds(self.geometry_cmds, G) + self.process_geocmds(self.geometry_cmds, model) # Process all the commands for subgrids self.process_subgrid_cmds(model)