diff --git a/gprMax/user_objects/rotatable.py b/gprMax/user_objects/rotatable.py new file mode 100644 index 00000000..d29f689e --- /dev/null +++ b/gprMax/user_objects/rotatable.py @@ -0,0 +1,43 @@ +from abc import ABC, abstractmethod +from typing import Optional, Tuple + + +class Rotatable(ABC): + """Stores parameters and defines an interface for rotatable objects. + + Attributes: + axis (str): Defines the axis about which to perform the + rotation. Must have value "x", "y", or "z". Default x. + angle (int): Specifies the angle of rotation (degrees). + Default 0. + origin (tuple | None): Optional point about which to perform the + rotation (x, y, z). Default None. + do_rotate (bool): True if the object should be rotated. False + otherwise. Default False. + """ + + def __init__(self): + self.axis = "x" + self.angle = 0 + self.origin = None + self.do_rotate = False + + def rotate(self, axis: str, angle: int, origin: Optional[Tuple[float, float, float]] = None): + """Sets parameters for rotation. + + Args: + axis: Defines the axis about which to perform the rotation. + Must have value "x", "y", or "z". + angle: Specifies the angle of rotation (degrees). + origin: Optional point about which to perform the rotation + (x, y, z). Default None. + """ + self.axis = axis + self.angle = angle + self.origin = origin + self.do_rotate = True + + @abstractmethod + def _do_rotate(self): + """Performs the rotation.""" + pass diff --git a/gprMax/user_objects/user_objects.py b/gprMax/user_objects/user_objects.py new file mode 100644 index 00000000..7bddeb02 --- /dev/null +++ b/gprMax/user_objects/user_objects.py @@ -0,0 +1,127 @@ +from abc import ABC, abstractmethod +from typing import List, Union + +from gprMax import config +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_inputs import MainGridUserInput, SubgridUserInput + + +class UserObject(ABC): + """User defined object. + + Attributes: + order (int): Specifies the order user objects should be + constructed in. + hash (str): gprMax hash command used to create the user object + in an input file. + kwargs (dict): Keyword arguments used to construct the user + object. + autotranslate (bool): TODO + is_single_use (bool): True if the object can only appear once in a + given model. False otherwise. Default True. + is_geometry_object (bool): True if the object adds geometry to the + model. False otherwise. Default False. + """ + + @property + @abstractmethod + def order(self) -> int: + pass + + @property + @abstractmethod + def hash(self) -> str: + pass + + @property + def is_single_use(self) -> bool: + return True + + @property + def is_geometry_object(self) -> bool: + return False + + def __init__(self, **kwargs) -> None: + self.kwargs = kwargs + self.autotranslate = True + + def __str__(self) -> str: + """Readable user object as per hash commands.""" + args: List[str] = [] + for value in self.kwargs.values(): + if isinstance(value, (tuple, list)): + for element in value: + args.append(str(element)) + else: + args.append(str(value)) + + return f"{self.hash}: {' '.join(args)}" + + def _params_str(self) -> str: + """Readable string of parameters given to object.""" + return f"{self.hash}: {str(self.kwargs)}" + + def _create_uip(self, grid: FDTDGrid) -> Union[SubgridUserInput, MainGridUserInput]: + """Returns a point checker class based on the grid supplied. + + Args: + grid: Grid to get a UserInput object for. + + Returns: + uip: UserInput object for the grid provided. + """ + + # If autotranslate is set as True globally, local object + # configuration trumps. I.e. User can turn off autotranslate for + # specific objects. + if ( + isinstance(grid, SubGridBaseGrid) + and config.sim_config.args.autotranslate + and self.autotranslate + ): + return SubgridUserInput(grid) + else: + return MainGridUserInput(grid) + + +class MultiUserObject(UserObject): + """User defined object that can occur multiple times.""" + + @property + def is_single_use(self) -> bool: + return False + + +class ModelUserObject(UserObject): + """User defined object to add to the model.""" + + @abstractmethod + def build(self, model: Model): + pass + + +class GridUserObject(MultiUserObject): + """User defined object to add to a grid.""" + + @abstractmethod + def build(self, grid: FDTDGrid): + pass + + +class OutputUserObject(MultiUserObject): + """User defined object that controls the output of data.""" + + @abstractmethod + def build(self, model: Model, grid: FDTDGrid): + pass + + +class GeometryUserObject(GridUserObject): + """User defined object that adds geometry to a grid.""" + + @property + def is_geometry_object(self) -> bool: + return True