From 1ef898384a1886957b55a5a8f113e55ce411cc7c Mon Sep 17 00:00:00 2001 From: craig-warren Date: Tue, 7 Apr 2020 15:24:22 +0100 Subject: [PATCH] Cleanup of imports and checking using pylint --- gprMax/__init__.py | 62 +-- gprMax/cmds_geometry/add_grass.py | 21 +- gprMax/cmds_geometry/add_surface_roughness.py | 5 +- gprMax/cmds_geometry/add_surface_water.py | 17 +- gprMax/cmds_geometry/box.py | 4 +- gprMax/cmds_geometry/build_templates.py | 4 +- gprMax/cmds_geometry/cylinder.py | 5 +- gprMax/cmds_geometry/cylindrical_sector.py | 4 +- gprMax/cmds_geometry/edge.py | 8 +- gprMax/cmds_geometry/fractal_box.py | 4 +- gprMax/cmds_geometry/fractal_box_builder.py | 8 +- gprMax/cmds_geometry/geometry_objects_read.py | 4 +- gprMax/cmds_geometry/plate.py | 8 +- gprMax/cmds_geometry/sphere.py | 4 +- gprMax/cmds_geometry/triangle.py | 4 +- gprMax/cmds_multiple.py | 21 +- gprMax/cmds_single_use.py | 43 +- gprMax/config.py | 12 +- gprMax/contexts.py | 9 +- gprMax/cython/fields_updates_hsg.pyx | 1 - gprMax/exceptions.py | 3 +- gprMax/fields_outputs.py | 2 +- gprMax/fractals.py | 7 +- gprMax/geometry_outputs.py | 9 +- gprMax/gprMax.py | 4 +- gprMax/grid.py | 33 +- gprMax/hash_cmds_file.py | 5 +- gprMax/hash_cmds_geometry.py | 22 +- gprMax/hash_cmds_multiuse.py | 28 +- gprMax/hash_cmds_singleuse.py | 15 +- gprMax/model_build_run.py | 28 +- gprMax/mpi.py | 2 +- gprMax/pml.py | 3 +- gprMax/receivers.py | 3 +- gprMax/scene.py | 8 +- gprMax/snapshots.py | 6 +- gprMax/solvers.py | 7 +- gprMax/sources.py | 6 +- gprMax/subgrids/subgrid_hsg.py | 16 +- gprMax/subgrids/updates.py | 5 +- gprMax/subgrids/user_objects.py | 5 +- gprMax/updates.py | 27 +- gprMax/user_inputs.py | 10 +- gprMax/utilities.py | 54 +-- gprMax/waveforms.py | 5 +- tests/analytical_solutions.py | 36 +- tests/test_experimental.py | 5 +- tests/test_models.py | 14 +- tools/HPC_scripts/gprmax_omp_mpi.sh | 4 +- tools/HPC_scripts/gprmax_omp_mpi_no_spawn.sh | 37 -- tools/inputfile_old2new.py | 2 +- tools/outputfiles_merge.py | 2 +- tools/plot_Ascan.py | 5 +- tools/plot_Bscan.py | 4 +- tools/plot_antenna_params.py | 13 +- tools/plot_antenna_params_UtEl.py | 429 ++++++++++++++++++ tools/plot_source_wave.py | 6 +- user_libs/antenna_patterns/initial_save.py | 17 +- user_libs/antenna_patterns/plot_fields.py | 13 +- 59 files changed, 719 insertions(+), 429 deletions(-) delete mode 100644 tools/HPC_scripts/gprmax_omp_mpi_no_spawn.sh create mode 100644 tools/plot_antenna_params_UtEl.py diff --git a/gprMax/__init__.py b/gprMax/__init__.py index 9010516f..1580cb9b 100644 --- a/gprMax/__init__.py +++ b/gprMax/__init__.py @@ -7,54 +7,32 @@ Electromagnetic wave propagation simulation software. """ -from ._version import __version__ -from .cmds_single_use import Discretisation -from .cmds_single_use import Domain -from .cmds_single_use import TimeWindow -from .cmds_single_use import Title -from .cmds_single_use import NumThreads -from .cmds_single_use import TimeStepStabilityFactor -from .cmds_single_use import PMLCells -from .cmds_single_use import SrcSteps -from .cmds_single_use import RxSteps -from .cmds_single_use import ExcitationFile -from .cmds_multiple import Waveform -from .cmds_multiple import VoltageSource -from .cmds_multiple import HertzianDipole -from .cmds_multiple import MagneticDipole -from .cmds_multiple import TransmissionLine -from .cmds_multiple import Rx -from .cmds_multiple import RxArray -from .cmds_multiple import Snapshot -from .cmds_multiple import Material -from .cmds_multiple import AddDebyeDispersion -from .cmds_multiple import AddLorentzDispersion -from .cmds_multiple import AddDrudeDispersion -from .cmds_multiple import SoilPeplinski -from .cmds_multiple import GeometryView -from .cmds_multiple import GeometryObjectsWrite -from .cmds_multiple import PMLCFS -from .subgrids.user_objects import SubGridHSG -from .subgrids.user_objects import ReferenceRx +import gprMax.config as config -from .cmds_geometry.edge import Edge -from .cmds_geometry.plate import Plate -from .cmds_geometry.triangle import Triangle +from ._version import __version__ +from .cmds_geometry.add_grass import AddGrass +from .cmds_geometry.add_surface_roughness import AddSurfaceRoughness +from .cmds_geometry.add_surface_water import AddSurfaceWater from .cmds_geometry.box import Box from .cmds_geometry.cylinder import Cylinder from .cmds_geometry.cylindrical_sector import CylindricalSector -from .cmds_geometry.sphere import Sphere +from .cmds_geometry.edge import Edge from .cmds_geometry.fractal_box import FractalBox -from .cmds_geometry.add_surface_roughness import AddSurfaceRoughness -from .cmds_geometry.add_surface_water import AddSurfaceWater -from .cmds_geometry.add_grass import AddGrass from .cmds_geometry.geometry_objects_read import GeometryObjectsRead - -from .hash_cmds_file import user_libs_fn_to_scene_obj - -from .scene import Scene +from .cmds_geometry.plate import Plate +from .cmds_geometry.sphere import Sphere +from .cmds_geometry.triangle import Triangle +from .cmds_multiple import (PMLCFS, AddDebyeDispersion, AddDrudeDispersion, + AddLorentzDispersion, GeometryObjectsWrite, + GeometryView, HertzianDipole, MagneticDipole, + Material, Rx, RxArray, Snapshot, SoilPeplinski, + TransmissionLine, VoltageSource, Waveform) +from .cmds_single_use import (Discretisation, Domain, ExcitationFile, + NumThreads, PMLCells, RxSteps, SrcSteps, + TimeStepStabilityFactor, TimeWindow, Title) from .gprMax import run as run - -import gprMax.config as config +from .hash_cmds_file import user_libs_fn_to_scene_obj +from .scene import Scene +from .subgrids.user_objects import ReferenceRx, SubGridHSG __name__ = 'gprMax' diff --git a/gprMax/cmds_geometry/add_grass.py b/gprMax/cmds_geometry/add_grass.py index 41220bde..741d0e4d 100644 --- a/gprMax/cmds_geometry/add_grass.py +++ b/gprMax/cmds_geometry/add_grass.py @@ -18,15 +18,14 @@ import logging +import gprMax.config as config import numpy as np -import gprMax.config as config -from .cmds_geometry import UserObjectGeometry from ..exceptions import CmdInputError -from ..fractals import FractalSurface -from ..fractals import Grass -from ..materials import Material +from ..fractals import FractalSurface, Grass +from ..materials import DispersiveMaterial from ..utilities import round_value +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) @@ -175,15 +174,15 @@ class AddGrass(UserObjectGeometry): # Check to see if grass has been already defined as a material if not any(x.ID == 'grass' for x in grid.materials): - m = Material(len(grid.materials), 'grass') + m = DispersiveMaterial(len(grid.materials), 'grass') m.averagable = False m.type = 'builtin, debye' - m.er = Material.grasseri - m.deltaer.append(Material.grassdeltaer) - m.tau.append(Material.grasstau) + m.er = DispersiveMaterial.grasseri + m.deltaer.append(DispersiveMaterial.grassdeltaer) + m.tau.append(DispersiveMaterial.grasstau) grid.materials.append(m) - if Material.maxpoles == 0: - Material.maxpoles = 1 + if config.get_model_config().materials['maxpoles'] == 0: + config.get_model_config().materials['maxpoles'] = 1 # Check if time step for model is suitable for using grass grass = next((x for x in grid.materials if x.ID == 'grass')) diff --git a/gprMax/cmds_geometry/add_surface_roughness.py b/gprMax/cmds_geometry/add_surface_roughness.py index 83aec2e2..6b20c22c 100644 --- a/gprMax/cmds_geometry/add_surface_roughness.py +++ b/gprMax/cmds_geometry/add_surface_roughness.py @@ -18,14 +18,13 @@ import logging +import gprMax.config as config import numpy as np -import gprMax.config as config -from .cmds_geometry import UserObjectGeometry -from ..cython.geometry_primitives import build_box from ..exceptions import CmdInputError from ..fractals import FractalSurface from ..utilities import round_value +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) diff --git a/gprMax/cmds_geometry/add_surface_water.py b/gprMax/cmds_geometry/add_surface_water.py index 2dc9d6f7..024135d2 100644 --- a/gprMax/cmds_geometry/add_surface_water.py +++ b/gprMax/cmds_geometry/add_surface_water.py @@ -19,10 +19,11 @@ import logging import gprMax.config as config -from .cmds_geometry import UserObjectGeometry + from ..exceptions import CmdInputError -from ..materials import Material +from ..materials import DispersiveMaterial from ..utilities import round_value +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) @@ -126,15 +127,15 @@ class AddSurfaceWater(UserObjectGeometry): # Check to see if water has been already defined as a material if not any(x.ID == 'water' for x in grid.materials): - m = Material(len(grid.materials), 'water') + m = DispersiveMaterial(len(grid.materials), 'water') m.averagable = False m.type = 'builtin, debye' - m.er = Material.watereri - m.deltaer.append(Material.waterdeltaer) - m.tau.append(Material.watertau) + m.er = DispersiveMaterial.watereri + m.deltaer.append(DispersiveMaterial.waterdeltaer) + m.tau.append(DispersiveMaterial.watertau) grid.materials.append(m) - if Material.maxpoles == 0: - Material.maxpoles = 1 + if config.get_model_config().materials['maxpoles'] == 0: + config.get_model_config().materials['maxpoles'] = 1 # Check if time step for model is suitable for using water water = next((x for x in grid.materials if x.ID == 'water')) diff --git a/gprMax/cmds_geometry/box.py b/gprMax/cmds_geometry/box.py index 06f19b9b..51b5cf28 100644 --- a/gprMax/cmds_geometry/box.py +++ b/gprMax/cmds_geometry/box.py @@ -18,13 +18,13 @@ import logging +import gprMax.config as config import numpy as np -import gprMax.config as config -from .cmds_geometry import UserObjectGeometry from ..cython.geometry_primitives import build_box from ..exceptions import CmdInputError from ..materials import Material +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) diff --git a/gprMax/cmds_geometry/build_templates.py b/gprMax/cmds_geometry/build_templates.py index c1ccad15..0c722459 100644 --- a/gprMax/cmds_geometry/build_templates.py +++ b/gprMax/cmds_geometry/build_templates.py @@ -16,9 +16,7 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from jinja2 import Environment -from jinja2 import PackageLoader -from jinja2 import select_autoescape +from jinja2 import Environment, PackageLoader, select_autoescape env = Environment( loader=PackageLoader(__name__, 'templates'), diff --git a/gprMax/cmds_geometry/cylinder.py b/gprMax/cmds_geometry/cylinder.py index f0bafebc..0ead2438 100644 --- a/gprMax/cmds_geometry/cylinder.py +++ b/gprMax/cmds_geometry/cylinder.py @@ -17,13 +17,14 @@ # along with gprMax. If not, see . import logging -import numpy as np import gprMax.config as config -from .cmds_geometry import UserObjectGeometry +import numpy as np + from ..cython.geometry_primitives import build_cylinder from ..exceptions import CmdInputError from ..materials import Material +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) diff --git a/gprMax/cmds_geometry/cylindrical_sector.py b/gprMax/cmds_geometry/cylindrical_sector.py index 4ef0fcbd..4ffa965e 100644 --- a/gprMax/cmds_geometry/cylindrical_sector.py +++ b/gprMax/cmds_geometry/cylindrical_sector.py @@ -18,13 +18,13 @@ import logging +import gprMax.config as config import numpy as np -import gprMax.config as config -from .cmds_geometry import UserObjectGeometry from ..cython.geometry_primitives import build_cylindrical_sector from ..exceptions import CmdInputError from ..materials import Material +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) diff --git a/gprMax/cmds_geometry/edge.py b/gprMax/cmds_geometry/edge.py index 19a81c24..9359ef7b 100644 --- a/gprMax/cmds_geometry/edge.py +++ b/gprMax/cmds_geometry/edge.py @@ -19,11 +19,11 @@ import logging import gprMax.config as config -from .cmds_geometry import UserObjectGeometry -from ..cython.geometry_primitives import build_edge_x -from ..cython.geometry_primitives import build_edge_y -from ..cython.geometry_primitives import build_edge_z + +from ..cython.geometry_primitives import (build_edge_x, build_edge_y, + build_edge_z) from ..exceptions import CmdInputError +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) diff --git a/gprMax/cmds_geometry/fractal_box.py b/gprMax/cmds_geometry/fractal_box.py index 965bff56..1c742abe 100644 --- a/gprMax/cmds_geometry/fractal_box.py +++ b/gprMax/cmds_geometry/fractal_box.py @@ -18,12 +18,12 @@ import logging +import gprMax.config as config import numpy as np -import gprMax.config as config -from .cmds_geometry import UserObjectGeometry from ..exceptions import CmdInputError from ..fractals import FractalVolume +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) diff --git a/gprMax/cmds_geometry/fractal_box_builder.py b/gprMax/cmds_geometry/fractal_box_builder.py index 9a329bd1..3f6ff9f7 100644 --- a/gprMax/cmds_geometry/fractal_box_builder.py +++ b/gprMax/cmds_geometry/fractal_box_builder.py @@ -16,13 +16,13 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . +import gprMax.config as config import numpy as np -import gprMax.config as config -from .cmds_geometry import UserObjectGeometry -from ..cython.geometry_primitives import build_voxels_from_array -from ..cython.geometry_primitives import build_voxels_from_array_mask +from ..cython.geometry_primitives import (build_voxels_from_array, + build_voxels_from_array_mask) from ..exceptions import CmdInputError +from .cmds_geometry import UserObjectGeometry class FractalBoxBuilder(UserObjectGeometry): diff --git a/gprMax/cmds_geometry/geometry_objects_read.py b/gprMax/cmds_geometry/geometry_objects_read.py index 51c25d84..ed8145e8 100644 --- a/gprMax/cmds_geometry/geometry_objects_read.py +++ b/gprMax/cmds_geometry/geometry_objects_read.py @@ -19,14 +19,14 @@ import logging from pathlib import Path +import gprMax.config as config import h5py -import gprMax.config as config -from .cmds_geometry import UserObjectGeometry from ..cython.geometry_primitives import build_voxels_from_array from ..exceptions import CmdInputError from ..hash_cmds_file import get_user_objects from ..utilities import round_value +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) diff --git a/gprMax/cmds_geometry/plate.py b/gprMax/cmds_geometry/plate.py index 4c43a295..f12ed285 100644 --- a/gprMax/cmds_geometry/plate.py +++ b/gprMax/cmds_geometry/plate.py @@ -19,11 +19,11 @@ import logging import gprMax.config as config -from .cmds_geometry import UserObjectGeometry -from ..cython.geometry_primitives import build_face_yz -from ..cython.geometry_primitives import build_face_xz -from ..cython.geometry_primitives import build_face_xy + +from ..cython.geometry_primitives import (build_face_xy, build_face_xz, + build_face_yz) from ..exceptions import CmdInputError +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) diff --git a/gprMax/cmds_geometry/sphere.py b/gprMax/cmds_geometry/sphere.py index 49a0f7c2..ab359fa5 100644 --- a/gprMax/cmds_geometry/sphere.py +++ b/gprMax/cmds_geometry/sphere.py @@ -18,13 +18,13 @@ import logging +import gprMax.config as config import numpy as np -import gprMax.config as config -from .cmds_geometry import UserObjectGeometry from ..cython.geometry_primitives import build_sphere from ..exceptions import CmdInputError from ..materials import Material +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) diff --git a/gprMax/cmds_geometry/triangle.py b/gprMax/cmds_geometry/triangle.py index ed1cbbb2..68046594 100644 --- a/gprMax/cmds_geometry/triangle.py +++ b/gprMax/cmds_geometry/triangle.py @@ -18,13 +18,13 @@ import logging +import gprMax.config as config import numpy as np -import gprMax.config as config -from .cmds_geometry import UserObjectGeometry from ..cython.geometry_primitives import build_triangle from ..exceptions import CmdInputError from ..materials import Material +from .cmds_geometry import UserObjectGeometry logger = logging.getLogger(__name__) diff --git a/gprMax/cmds_multiple.py b/gprMax/cmds_multiple.py index f0ededa4..86e5c767 100644 --- a/gprMax/cmds_multiple.py +++ b/gprMax/cmds_multiple.py @@ -18,23 +18,22 @@ import logging +import gprMax.config as config import numpy as np -import gprMax.config as config from .cmds_geometry.cmds_geometry import UserObjectGeometry -from .exceptions import CmdInputError +from .exceptions import CmdInputError, GeneralError from .geometry_outputs import GeometryObjects as GeometryObjectsUser -from .materials import Material as MaterialUser from .materials import DispersiveMaterial as DispersiveMaterialUser +from .materials import Material as MaterialUser from .materials import PeplinskiSoil as PeplinskiSoilUser -from .pml import CFSParameter -from .pml import CFS +from .pml import CFS, CFSParameter from .receivers import Rx as RxUser from .snapshots import Snapshot as SnapshotUser -from .sources import VoltageSource as VoltageSourceUser from .sources import HertzianDipole as HertzianDipoleUser from .sources import MagneticDipole as MagneticDipoleUser from .sources import TransmissionLine as TransmissionLineUser +from .sources import VoltageSource as VoltageSourceUser from .subgrids.base import SubGridBase from .utilities import round_value from .waveforms import Waveform as WaveformUser @@ -162,7 +161,7 @@ class VoltageSource(UserObjectMulti): # Check if there is a waveformID in the waveforms list if not any(x.ID == waveform_id for x in grid.waveforms): - raise CmdInputError(f"'{self.params_str()}' there is no waveform with the identifier {tmp[5]}") + raise CmdInputError(f"'{self.params_str()}' there is no waveform with the identifier {waveform_id}") v = VoltageSourceUser() v.polarisation = polarisation @@ -594,7 +593,7 @@ class RxArray(UserObjectMulti): r.zcoordorigin = z r.ID = r.__class__.__name__ + '(' + str(x) + ',' + str(y) + ',' + str(z) + ')' for key in RxUser.defaultoutputs: - r.outputs[key] = np.zeros(grid.iterations, dtype=config.dtypes['float_or_double']) + r.outputs[key] = np.zeros(grid.iterations, dtype=config.sim_config.dtypes['float_or_double']) logger.info(f" Receiver at {r.xcoord * grid.dx:g}m, {r.ycoord * grid.dy:g}m, {r.zcoord * grid.dz:g}m with output component(s) {', '.join(r.outputs)} created.") grid.rxs.append(r) @@ -1080,7 +1079,7 @@ class GeometryObjectsWrite(UserObjectMulti): try: p1 = self.kwargs['p1'] p2 = self.kwargs['p2'] - filename = self.kwargs['filename'] + basefilename = self.kwargs['filename'] except KeyError: raise CmdInputError(f"'{self.params_str()}' requires exactly seven parameters") @@ -1088,9 +1087,9 @@ class GeometryObjectsWrite(UserObjectMulti): x0, y0, z0 = p1 x1, y1, z1 = p2 - g = GeometryObjectsUser(x0, y0, z0, x1, y1, z1, filename) + g = GeometryObjectsUser(x0, y0, z0, x1, y1, z1, basefilename) - logger.info(f'Geometry objects in the volume from {p1[0] * grid.dx:g}m, {p1[1] * grid.dy:g}m, {p1[2] * grid.dz:g}m, to {p2[0] * grid.dx:g}m, {p2[1] * grid.dy:g}m, {p2[2] * grid.dz:g}m, will be written to {g.filename}, with materials written to {g.materialsfilename}') + logger.info(f'Geometry objects in the volume from {p1[0] * grid.dx:g}m, {p1[1] * grid.dy:g}m, {p1[2] * grid.dz:g}m, to {p2[0] * grid.dx:g}m, {p2[1] * grid.dy:g}m, {p2[2] * grid.dz:g}m, will be written to {g.filename_hdf5}, with materials written to {g.filename_materials}') # Append the new GeometryView object to the geometry objects to write list grid.geometryobjectswrite.append(g) diff --git a/gprMax/cmds_single_use.py b/gprMax/cmds_single_use.py index 0c26f773..10142ad2 100644 --- a/gprMax/cmds_single_use.py +++ b/gprMax/cmds_single_use.py @@ -20,19 +20,16 @@ import inspect import logging from pathlib import Path -from colorama import init -from colorama import Fore -from colorama import Style -init() -import numpy as np -from scipy.constants import c -from scipy import interpolate - import gprMax.config as config +import numpy as np +from colorama import Fore, Style, init +init() +from scipy import interpolate +from scipy.constants import c + from .exceptions import CmdInputError +from .utilities import round_value, set_omp_threads from .waveforms import Waveform -from .utilities import round_value -from .utilities import set_omp_threads logger = logging.getLogger(__name__) @@ -95,31 +92,31 @@ class Domain(UserObjectSingle): try: G.nx, G.ny, G.nz = uip.discretise_point(self.kwargs['p1']) except KeyError: - raise CmdInputError(f"'{self.params_str()}' please specify a point") + raise CmdInputError(self.__str__() + ' please specify a point') if G.nx == 0 or G.ny == 0 or G.nz == 0: - raise CmdInputError(f"'{self.params_str()}' requires at least one cell in every dimension") + raise CmdInputError(self.__str__() + ' requires at least one cell in every dimension') logger.info(f"Domain size: {self.kwargs['p1'][0]:g} x {self.kwargs['p1'][1]:g} x {self.kwargs['p1'][2]:g}m ({G.nx:d} x {G.ny:d} x {G.nz:d} = {(G.nx * G.ny * G.nz):g} cells)") # Calculate time step at CFL limit; switch off appropriate PMLs for 2D if G.nx == 1: - G.mode = '2D TMx' + config.get_model_config().mode = '2D TMx' G.pmlthickness['x0'] = 0 G.pmlthickness['xmax'] = 0 elif G.ny == 1: - G.mode = '2D TMy' + config.get_model_config().mode = '2D TMy' G.pmlthickness['y0'] = 0 G.pmlthickness['ymax'] = 0 elif G.nz == 1: - G.mode = '2D TMz' + config.get_model_config().mode = '2D TMz' G.pmlthickness['z0'] = 0 G.pmlthickness['zmax'] = 0 else: - G.mode = '3D' + config.get_model_config().mode = '3D' G.calculate_dt() - logger.info(f'Mode: {G.mode}') + logger.info(f'Mode: {config.get_model_config().mode}') logger.info(f'Time step (at CFL limit): {G.dt:g} secs') @@ -140,14 +137,14 @@ class Discretisation(UserObjectSingle): G.dl = np.array(self.kwargs['p1']) G.dx, G.dy, G.dz = self.kwargs['p1'] except KeyError: - raise CmdInputError(f"'{self.params_str()}' discretisation requires a point") + raise CmdInputError(self.__str__() + ' discretisation requires a point') if G.dl[0] <= 0: - raise CmdInputError(f"'{self.params_str()}' discretisation requires the x-direction spatial step to be greater than zero") + raise CmdInputError(self.__str__() + ' discretisation requires the x - direction spatial step to be greater than zero') if G.dl[1] <= 0: - raise CmdInputError(f"'{self.params_str()}' discretisation requires the y-direction spatial step to be greater than zero") + raise CmdInputError(self.__str__() + ' discretisation requires the y - direction spatial step to be greater than zero') if G.dl[2] <= 0: - raise CmdInputError(f"'{self.params_str()}' discretisation requires the z-direction spatial step to be greater than zero") + raise CmdInputError(self.__str__() + ' discretisation requires the z - direction spatial step to be greater than zero') logger.info(f'Spatial discretisation: {G.dl[0]:g} x {G.dl[1]:g} x {G.dl[2]:g}m') @@ -182,12 +179,12 @@ class TimeWindow(UserObjectSingle): G.timewindow = tmp G.iterations = int(np.ceil(tmp / G.dt)) + 1 else: - raise CmdInputError(f"'{self.params_str()}' must have a value greater than zero") + raise CmdInputError(self.__str__() + ' must have a value greater than zero') except KeyError: pass if not G.timewindow: - raise CmdInputError(f"'{self.params_str()}' specify a time or number of iterations") + raise CmdInputError(self.__str__() + ' specify a time or number of iterations') logger.info(f'Time window: {G.timewindow:g} secs ({G.iterations} iterations)') diff --git a/gprMax/config.py b/gprMax/config.py index 31bc69f1..a878bacb 100644 --- a/gprMax/config.py +++ b/gprMax/config.py @@ -17,23 +17,19 @@ # along with gprMax. If not, see . import logging -from pathlib import Path import sys +from pathlib import Path -from colorama import init -from colorama import Fore -from colorama import Style -init() import cython import numpy as np +from colorama import Fore, Style, init +init() from scipy.constants import c from scipy.constants import epsilon_0 as e0 from scipy.constants import mu_0 as m0 from .exceptions import GeneralError -from .utilities import detect_gpus -from .utilities import get_host_info -from .utilities import get_terminal_width +from .utilities import detect_gpus, get_host_info, get_terminal_width logger = logging.getLogger(__name__) diff --git a/gprMax/contexts.py b/gprMax/contexts.py index 0661fa2d..d51bf13f 100644 --- a/gprMax/contexts.py +++ b/gprMax/contexts.py @@ -21,15 +21,12 @@ import logging import sys import gprMax.config as config + from ._version import __version__, codename from .exceptions import GeneralError from .model_build_run import ModelBuildRun -from .solvers import create_solver -from .solvers import create_G -from .utilities import get_terminal_width -from .utilities import human_size -from .utilities import logo -from .utilities import timer +from .solvers import create_G, create_solver +from .utilities import get_terminal_width, human_size, logo, timer logger = logging.getLogger(__name__) diff --git a/gprMax/cython/fields_updates_hsg.pyx b/gprMax/cython/fields_updates_hsg.pyx index f212d628..4550b8a8 100644 --- a/gprMax/cython/fields_updates_hsg.pyx +++ b/gprMax/cython/fields_updates_hsg.pyx @@ -18,7 +18,6 @@ import numpy as np cimport numpy as np - from cython.parallel import prange diff --git a/gprMax/exceptions.py b/gprMax/exceptions.py index 2172a65c..28817a6c 100644 --- a/gprMax/exceptions.py +++ b/gprMax/exceptions.py @@ -18,8 +18,7 @@ import logging -from colorama import init -from colorama import Fore +from colorama import Fore, init init() logger = logging.getLogger(__name__) diff --git a/gprMax/fields_outputs.py b/gprMax/fields_outputs.py index 87b72289..3ea924ba 100644 --- a/gprMax/fields_outputs.py +++ b/gprMax/fields_outputs.py @@ -17,8 +17,8 @@ # along with gprMax. If not, see . import logging -from string import Template from pathlib import Path +from string import Template import h5py diff --git a/gprMax/fractals.py b/gprMax/fractals.py index 0fb8966b..14fee38b 100644 --- a/gprMax/fractals.py +++ b/gprMax/fractals.py @@ -16,12 +16,11 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . +import gprMax.config as config import numpy as np from scipy import fftpack -import gprMax.config as config -from .cython.fractals_generate import generate_fractal2D -from .cython.fractals_generate import generate_fractal3D +from .cython.fractals_generate import generate_fractal2D, generate_fractal3D from .utilities import round_value np.seterr(divide='raise') @@ -220,7 +219,7 @@ class Grass: self.numblades = numblades self.geometryparams = np.zeros((self.numblades, 6), - dtype=config.dtypes['float_or_double']) + dtype=config.sim_config.dtypes['float_or_double']) self.seed = None # Randomly defined parameters that will be used to calculate geometry diff --git a/gprMax/geometry_outputs.py b/gprMax/geometry_outputs.py index 57ff6fdd..a49b53b6 100644 --- a/gprMax/geometry_outputs.py +++ b/gprMax/geometry_outputs.py @@ -19,16 +19,15 @@ import logging import os from pathlib import Path - -import h5py -import numpy as np from struct import pack import gprMax.config as config +import h5py +import numpy as np from ._version import __version__ -from .cython.geometry_outputs import define_normal_geometry -from .cython.geometry_outputs import define_fine_geometry +from .cython.geometry_outputs import (define_fine_geometry, + define_normal_geometry) from .utilities import round_value logger = logging.getLogger(__name__) diff --git a/gprMax/gprMax.py b/gprMax/gprMax.py index b9dbaa15..76bbcc7e 100644 --- a/gprMax/gprMax.py +++ b/gprMax/gprMax.py @@ -20,8 +20,8 @@ import argparse import logging import gprMax.config as config -from .contexts import Context -from .contexts import MPIContext + +from .contexts import Context, MPIContext from .utilities import setup_logging logger = logging.getLogger(__name__) diff --git a/gprMax/grid.py b/gprMax/grid.py index 715efac6..7d41bc8c 100644 --- a/gprMax/grid.py +++ b/gprMax/grid.py @@ -16,22 +16,16 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from collections import OrderedDict import decimal as d - -from colorama import init -from colorama import Fore -from colorama import Style -init() -import numpy as np +from collections import OrderedDict import gprMax.config as config +import numpy as np +from colorama import Fore, Style, init +init() from .exceptions import GeneralError -from .pml import PML -from .pml import CFS -from .utilities import fft_power -from .utilities import human_size -from .utilities import round_value +from .pml import CFS, PML +from .utilities import fft_power, human_size, round_value np.seterr(invalid='raise') @@ -274,13 +268,13 @@ class FDTDGrid: def calculate_dt(self): """Calculate time step at the CFL limit.""" - if self.mode == '2D TMx': + if config.get_model_config().mode == '2D TMx': self.dt = 1 / (config.sim_config.em_consts['c'] * np.sqrt((1 / self.dy**2) + (1 / self.dz**2))) - elif self.mode == '2D TMy': + elif config.get_model_config().mode == '2D TMy': self.dt = 1 / (config.sim_config.em_consts['c'] * np.sqrt((1 / self.dx**2) + (1 / self.dz**2))) - elif self.mode == '2D TMz': + elif config.get_model_config().mode == '2D TMz': self.dt = 1 / (config.sim_config.em_consts['c'] * np.sqrt((1 / self.dx**2) + (1 / self.dy**2))) else: @@ -352,9 +346,12 @@ def dispersion_analysis(G): results (dict): Results from dispersion analysis """ - # Physical phase velocity error (percentage); grid sampling density; - # material with maximum permittivity; maximum significant frequency; error message - results = {'deltavp': False, 'N': False, 'material': False, 'maxfreq': [], 'error': ''} + # deltavp: physical phase velocity error (percentage) + # N: grid sampling density + # material: material with maximum permittivity + # maxfreq: maximum significant frequency + # error: error message + results = {'deltavp': None, 'N': None, 'material': None, 'maxfreq': [], 'error': ''} # Find maximum significant frequency if G.waveforms: diff --git a/gprMax/hash_cmds_file.py b/gprMax/hash_cmds_file.py index bc5900f1..b00843f2 100644 --- a/gprMax/hash_cmds_file.py +++ b/gprMax/hash_cmds_file.py @@ -16,13 +16,14 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from io import StringIO import logging import os -from pathlib import Path import sys +from io import StringIO +from pathlib import Path import gprMax.config as config + from .exceptions import CmdInputError from .hash_cmds_geometry import process_geometrycmds from .hash_cmds_multiuse import process_multicmds diff --git a/gprMax/hash_cmds_geometry.py b/gprMax/hash_cmds_geometry.py index 3b54b98f..275a123f 100644 --- a/gprMax/hash_cmds_geometry.py +++ b/gprMax/hash_cmds_geometry.py @@ -18,17 +18,18 @@ import numpy as np -from .cmds_geometry.edge import Edge -from .cmds_geometry.plate import Plate -from .cmds_geometry.triangle import Triangle +from .cmds_geometry.add_grass import AddGrass +from .cmds_geometry.add_surface_roughness import AddSurfaceRoughness +from .cmds_geometry.add_surface_water import AddSurfaceWater from .cmds_geometry.box import Box from .cmds_geometry.cylinder import Cylinder from .cmds_geometry.cylindrical_sector import CylindricalSector +from .cmds_geometry.edge import Edge from .cmds_geometry.fractal_box import FractalBox +from .cmds_geometry.plate import Plate from .cmds_geometry.sphere import Sphere -from .cmds_geometry.add_surface_roughness import AddSurfaceRoughness -from .cmds_geometry.add_surface_water import AddSurfaceWater -from .cmds_geometry.add_grass import AddGrass +from .cmds_geometry.triangle import Triangle +from .exceptions import CmdInputError from .utilities import round_value @@ -181,15 +182,18 @@ def process_geometrycmds(geometry): # Isotropic case with no user specified averaging if len(tmp) == 10: - CylindricalSector(normal=normal, ctl1=ctl1, ctl2=ctl2, extent1=extent1, extent2=extent2, r=r, start=start, end=end, msterial_id=tmp[9]) + cylindrical_sector = CylindricalSector(normal=normal, ctr1=ctr1, ctr2=ctr2, extent1=extent1, + extent2=extent2, r=r, start=start, end=end, msterial_id=tmp[9]) # Isotropic case with user specified averaging elif len(tmp) == 11: - CylindricalSector(normal=normal, ctl1=ctl1, ctl2=ctl2, extent1=extent1, extent2=extent2, r=r, start=start, end=end, averaging=tmp[10], material_id=tmp[9]) + cylindrical_sector = CylindricalSector(normal=normal, ctr1=ctr1, ctr2=ctr2, extent1=extent1, extent2=extent2, + r=r, start=start, end=end, averaging=tmp[10], material_id=tmp[9]) # Uniaxial anisotropic case elif len(tmp) == 12: - CylindricalSector(normal=normal, ctl1=ctl1, ctl2=ctl2, extent1=extent1, extent2=extent2, r=r, start=start, end=end, material_ids=tmp[9:]) + cylindrical_sector = CylindricalSector(normal=normal, ctr1=ctr1, ctr2=ctr2, extent1=extent1, + extent2=extent2, r=r, start=start, end=end, material_ids=tmp[9:]) else: raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given') diff --git a/gprMax/hash_cmds_multiuse.py b/gprMax/hash_cmds_multiuse.py index 1944da3d..d4ccd501 100644 --- a/gprMax/hash_cmds_multiuse.py +++ b/gprMax/hash_cmds_multiuse.py @@ -16,21 +16,11 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from .cmds_multiple import Waveform -from .cmds_multiple import VoltageSource -from .cmds_multiple import HertzianDipole -from .cmds_multiple import MagneticDipole -from .cmds_multiple import TransmissionLine -from .cmds_multiple import Material -from .cmds_multiple import Snapshot -from .cmds_multiple import AddDebyeDispersion -from .cmds_multiple import AddLorentzDispersion -from .cmds_multiple import AddDrudeDispersion -from .cmds_multiple import SoilPeplinski -from .cmds_multiple import GeometryView -from .cmds_multiple import GeometryObjectsWrite -from .cmds_multiple import PMLCFS -from .cmds_multiple import Rx +from .cmds_multiple import (PMLCFS, AddDebyeDispersion, AddDrudeDispersion, + AddLorentzDispersion, GeometryObjectsWrite, + GeometryView, HertzianDipole, MagneticDipole, + Material, Rx, RxArray, Snapshot, SoilPeplinski, + TransmissionLine, VoltageSource, Waveform) from .exceptions import CmdInputError @@ -275,9 +265,9 @@ def process_multicmds(multicmds): if len(tmp) != 7: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly seven parameters') - p1 = float(tmp[0]), float(tmp[1]), float(tmp[2]) - p2 = float(tmp[3]), float(tmp[4]), float(tmp[5]) - gow = GeometryObjectsWrite(p1=p1, p2=p2, filename=tmp[6]) - scene_objects.append(gow) + p1 = float(tmp[0]), float(tmp[1]), float(tmp[2]) + p2 = float(tmp[3]), float(tmp[4]), float(tmp[5]) + gow = GeometryObjectsWrite(p1=p1, p2=p2, filename=tmp[6]) + scene_objects.append(gow) return scene_objects diff --git a/gprMax/hash_cmds_singleuse.py b/gprMax/hash_cmds_singleuse.py index 30b22db2..5d1727bd 100644 --- a/gprMax/hash_cmds_singleuse.py +++ b/gprMax/hash_cmds_singleuse.py @@ -16,17 +16,10 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from .cmds_single_use import Title -from .cmds_single_use import NumThreads -from .cmds_single_use import Discretisation -from .cmds_single_use import Domain -from .cmds_single_use import TimeStepStabilityFactor -from .cmds_single_use import TimeWindow -from .cmds_single_use import PMLCells -from .cmds_single_use import SrcSteps -from .cmds_single_use import RxSteps -from .cmds_single_use import ExcitationFile -from .cmds_single_use import OutputDir +from .cmds_single_use import (Discretisation, Domain, ExcitationFile, + NumThreads, OutputDir, PMLCells, RxSteps, + SrcSteps, TimeStepStabilityFactor, TimeWindow, + Title) from .exceptions import CmdInputError diff --git a/gprMax/model_build_run.py b/gprMax/model_build_run.py index 907c6203..8ab05dbc 100644 --- a/gprMax/model_build_run.py +++ b/gprMax/model_build_run.py @@ -19,37 +19,31 @@ import datetime import itertools import logging -from pathlib import Path import platform -import psutil import sys +from pathlib import Path -from colorama import init -from colorama import Fore -from colorama import Style -init() +import gprMax.config as config import numpy as np +import psutil +from colorama import Fore, Style, init +init() from terminaltables import SingleTable from tqdm import tqdm -import gprMax.config as config -from .cython.yee_cell_build import build_electric_components -from .cython.yee_cell_build import build_magnetic_components +from .cython.yee_cell_build import (build_electric_components, + build_magnetic_components) from .exceptions import GeneralError from .fields_outputs import write_hdf5_outputfile from .grid import dispersion_analysis from .hash_cmds_file import parse_hash_commands -from .materials import Material -from .materials import process_materials -from .pml import build_pml -from .pml import print_pml_info +from .materials import Material, process_materials +from .pml import build_pml, print_pml_info from .scene import Scene from .snapshots import Snapshot from .solvers import create_solver -from .utilities import get_terminal_width -from .utilities import human_size -from .utilities import mem_check_all -from .utilities import set_omp_threads +from .utilities import (get_terminal_width, human_size, mem_check_all, + set_omp_threads) logger = logging.getLogger(__name__) diff --git a/gprMax/mpi.py b/gprMax/mpi.py index 9771cd76..63b0afff 100644 --- a/gprMax/mpi.py +++ b/gprMax/mpi.py @@ -16,9 +16,9 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from enum import IntEnum import logging import time +from enum import IntEnum from mpi4py import MPI diff --git a/gprMax/pml.py b/gprMax/pml.py index 366ff3e5..0fa14e9c 100644 --- a/gprMax/pml.py +++ b/gprMax/pml.py @@ -18,9 +18,8 @@ from importlib import import_module -import numpy as np - import gprMax.config as config +import numpy as np class CFSParameter: diff --git a/gprMax/receivers.py b/gprMax/receivers.py index c4d0df9e..c34de534 100644 --- a/gprMax/receivers.py +++ b/gprMax/receivers.py @@ -16,9 +16,8 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -import numpy as np - import gprMax.config as config +import numpy as np class Rx: diff --git a/gprMax/scene.py b/gprMax/scene.py index fc215a97..9fa1aa03 100644 --- a/gprMax/scene.py +++ b/gprMax/scene.py @@ -21,11 +21,9 @@ import logging from .cmds_geometry.cmds_geometry import UserObjectGeometry from .cmds_geometry.fractal_box_builder import FractalBoxBuilder from .cmds_multiple import UserObjectMulti -from .cmds_single_use import UserObjectSingle -from .cmds_single_use import Domain -from .cmds_single_use import Discretisation -from .cmds_single_use import TimeWindow -from .exceptions import CmdInputError +from .cmds_single_use import (Discretisation, Domain, TimeWindow, + UserObjectSingle) +from .exceptions import CmdInputError, GeneralError from .materials import create_built_in_materials from .subgrids.user_objects import SubGridBase as SubGridUserBase from .user_inputs import create_user_input_points diff --git a/gprMax/snapshots.py b/gprMax/snapshots.py index 972e2231..1af7a57b 100644 --- a/gprMax/snapshots.py +++ b/gprMax/snapshots.py @@ -16,12 +16,12 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from struct import pack import sys - -import numpy as np +from struct import pack import gprMax.config as config +import numpy as np + from .cython.snapshots import calculate_snapshot_fields from .utilities import round_value diff --git a/gprMax/solvers.py b/gprMax/solvers.py index 16fa1d4f..31e71c57 100644 --- a/gprMax/solvers.py +++ b/gprMax/solvers.py @@ -17,11 +17,10 @@ # along with gprMax. If not, see . import gprMax.config as config -from .grid import FDTDGrid -from .grid import CUDAGrid + +from .grid import CUDAGrid, FDTDGrid from .subgrids.updates import create_updates as create_subgrid_updates -from .updates import CPUUpdates -from .updates import CUDAUpdates +from .updates import CPUUpdates, CUDAUpdates def create_G(): diff --git a/gprMax/sources.py b/gprMax/sources.py index eb2376e6..952ce9d3 100644 --- a/gprMax/sources.py +++ b/gprMax/sources.py @@ -18,12 +18,10 @@ from copy import deepcopy +import gprMax.config as config import numpy as np -import gprMax.config as config -from .grid import Ix -from .grid import Iy -from .grid import Iz +from .grid import Ix, Iy, Iz from .utilities import round_value diff --git a/gprMax/subgrids/subgrid_hsg.py b/gprMax/subgrids/subgrid_hsg.py index c85784fc..5758cb7b 100644 --- a/gprMax/subgrids/subgrid_hsg.py +++ b/gprMax/subgrids/subgrid_hsg.py @@ -16,16 +16,16 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from colorama import init -from colorama import Fore -from colorama import Style +import gprMax.config as config +from colorama import Fore, Style, init + +from ..cython.fields_updates_hsg import (cython_update_electric_os, + cython_update_is, + cython_update_magnetic_os) +from .base import SubGridBase + init() -import gprMax.config as config -from .base import SubGridBase -from ..cython.fields_updates_hsg import cython_update_is -from ..cython.fields_updates_hsg import cython_update_magnetic_os -from ..cython.fields_updates_hsg import cython_update_electric_os class SubGridHSG(SubGridBase): diff --git a/gprMax/subgrids/updates.py b/gprMax/subgrids/updates.py index 594445c1..01267032 100644 --- a/gprMax/subgrids/updates.py +++ b/gprMax/subgrids/updates.py @@ -19,10 +19,9 @@ import logging from ..exceptions import GeneralError -from .precursor_nodes import PrecursorNodes -from .precursor_nodes import PrecursorNodesFiltered -from .subgrid_hsg import SubGridHSG from ..updates import CPUUpdates +from .precursor_nodes import PrecursorNodes, PrecursorNodesFiltered +from .subgrid_hsg import SubGridHSG log = logging.getLogger(__name__) diff --git a/gprMax/subgrids/user_objects.py b/gprMax/subgrids/user_objects.py index 8e6182c5..aa75b8ae 100644 --- a/gprMax/subgrids/user_objects.py +++ b/gprMax/subgrids/user_objects.py @@ -19,11 +19,10 @@ from copy import copy import numpy as np - from gprMax import config + from ..cmds_geometry.cmds_geometry import UserObjectGeometry -from ..cmds_multiple import UserObjectMulti -from ..cmds_multiple import Rx +from ..cmds_multiple import Rx, UserObjectMulti from ..exceptions import CmdInputError from .multi import ReferenceRx as ReferenceRxUser from .subgrid_hsg import SubGridHSG as SubGridHSGUser diff --git a/gprMax/updates.py b/gprMax/updates.py index 2c48cfd5..fcb42451 100644 --- a/gprMax/updates.py +++ b/gprMax/updates.py @@ -16,27 +16,26 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from importlib import import_module import logging - -import numpy as np +from importlib import import_module import gprMax.config as config +import numpy as np + from .cuda.fields_updates import kernel_template_fields from .cuda.snapshots import kernel_template_store_snapshot from .cuda.source_updates import kernel_template_sources -from .cython.fields_updates_normal import update_electric as update_electric_cpu -from .cython.fields_updates_normal import update_magnetic as update_magnetic_cpu -from .fields_outputs import store_outputs as store_outputs_cpu +from .cython.fields_updates_normal import \ + update_electric as update_electric_cpu +from .cython.fields_updates_normal import \ + update_magnetic as update_magnetic_cpu +from .exceptions import GeneralError from .fields_outputs import kernel_template_store_outputs -from .receivers import htod_rx_arrays -from .receivers import dtoh_rx_array -from .snapshots import Snapshot -from .snapshots import htod_snapshot_array -from .snapshots import dtoh_snapshot_array +from .fields_outputs import store_outputs as store_outputs_cpu +from .receivers import dtoh_rx_array, htod_rx_arrays +from .snapshots import Snapshot, dtoh_snapshot_array, htod_snapshot_array from .sources import htod_src_arrays -from .utilities import round32 -from .utilities import timer +from .utilities import human_size, round32, timer class CPUUpdates: @@ -692,7 +691,7 @@ class CUDAUpdates: # Copy data from any snapshots back to correct snapshot objects if self.grid.snapshots and not config.get_model_config().cuda['snapsgpu2cpu']: for i, snap in enumerate(self.grid.snapshots): - dtoh_snapshot_arra(self.snapEx_gpu.get(), + dtoh_snapshot_array(self.snapEx_gpu.get(), self.snapEy_gpu.get(), self.snapEz_gpu.get(), self.snapHx_gpu.get(), diff --git a/gprMax/user_inputs.py b/gprMax/user_inputs.py index 25778548..facf6df6 100644 --- a/gprMax/user_inputs.py +++ b/gprMax/user_inputs.py @@ -18,19 +18,17 @@ import logging -from colorama import init -from colorama import Fore -from colorama import Style -init() -import numpy as np - import gprMax.config as config +import numpy as np +from colorama import Fore, Style, init +init() from .exceptions import CmdInputError from .subgrids.base import SubGridBase from .utilities import round_value logger = logging.getLogger(__name__) + """Module contains classes to handle points supplied by a user. The classes implement a common interface such that geometry building objects such as box or triangle do not need to have any knowledge which grid to diff --git a/gprMax/utilities.py b/gprMax/utilities.py index da6457a2..180f248e 100644 --- a/gprMax/utilities.py +++ b/gprMax/utilities.py @@ -16,34 +16,30 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from contextlib import contextmanager import codecs import decimal as d import logging import os import platform -import psutil import re import subprocess -from shutil import get_terminal_size import sys import textwrap +from contextlib import contextmanager +from shutil import get_terminal_size + +import gprMax.config as config +import numpy as np +import psutil +from colorama import Fore, Style, init +init() +from .exceptions import GeneralError try: from time import thread_time as timer_fn except ImportError: from time import perf_counter as timer_fn - -from colorama import init -from colorama import Fore -from colorama import Style -init() -import numpy as np - -import gprMax.config as config -from .exceptions import GeneralError - logger = logging.getLogger(__name__) @@ -525,7 +521,7 @@ def detect_gpus(): else: deviceIDsavail = range(drv.Device.count()) - # Gather information about selected/detected GPUs + # Gather information about detected GPUs gpus = [] for ID in deviceIDsavail: gpu = GPU(deviceID=ID) @@ -535,24 +531,24 @@ def detect_gpus(): return gpus -def check_gpus(gpus): - """Check if requested Nvidia GPU(s) deviceID(s) exist. +# def check_gpus(gpus): +# """Check if requested Nvidia GPU(s) deviceID(s) exist. - Args: - gpus (list): List of GPU object(s). - """ +# Args: +# gpus (list): List of GPU object(s). +# """ - # Check if requested device ID(s) exist - for ID in deviceIDs: - if ID not in deviceIDsavail: - raise GeneralError(f'GPU with device ID {ID} does not exist') +# # Check if requested device ID(s) exist +# for ID in deviceIDs: +# if ID not in deviceIDsavail: +# raise GeneralError(f'GPU with device ID {ID} does not exist') - # Gather information about selected/detected GPUs - gpus = [] - for ID in deviceIDsavail: - gpu = GPU(deviceID=ID) - gpu.get_gpu_info(drv) - gpus.append(gpu) +# # Gather information about selected/detected GPUs +# gpus = [] +# for ID in deviceIDsavail: +# gpu = GPU(deviceID=ID) +# gpu.get_gpu_info(drv) +# gpus.append(gpu) def timer(): diff --git a/gprMax/waveforms.py b/gprMax/waveforms.py index 0bbcbf88..36eb643f 100644 --- a/gprMax/waveforms.py +++ b/gprMax/waveforms.py @@ -16,8 +16,11 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . +import logging import numpy as np +logger = logging.getLogger(__name__) + class Waveform: """Definitions of waveform shapes that can be used with sources.""" @@ -129,5 +132,5 @@ class Waveform: return ampvalue def __str__(self): - log.debug('Do we need this?') + logger.debug('Do we need this?') return f'Waveform: ID={self.ID}, type={self.type}, amp{self.amp}, freq={self.freq}' diff --git a/tests/analytical_solutions.py b/tests/analytical_solutions.py index 0ef302a1..4ce8610a 100644 --- a/tests/analytical_solutions.py +++ b/tests/analytical_solutions.py @@ -1,7 +1,6 @@ import numpy as np -from gprMax.config import c -from gprMax.config import e0 +import gprMax.config as config from gprMax.waveforms import Waveform @@ -52,52 +51,41 @@ def hertzian_dipole_fs(iterations, dt, dxdydz, rx): x = rx[0] y = rx[1] z = rx[2] - if z == 0: - sign_z = 1 - else: - sign_z = np.sign(z) # Coordinates of Rx for Ex FDTD component Ex_x = x + 0.5 * dx Ex_y = y Ex_z = z - 0.5 * dz Er_x = np.sqrt((Ex_x**2 + Ex_y**2 + Ex_z**2)) - tau_Ex = Er_x / c + tau_Ex = Er_x / config.sim_config.em_consts['c'] # Coordinates of Rx for Ey FDTD component Ey_x = x Ey_y = y + 0.5 * dy Ey_z = z - 0.5 * dz Er_y = np.sqrt((Ey_x**2 + Ey_y**2 + Ey_z**2)) - tau_Ey = Er_y / c + tau_Ey = Er_y / config.sim_config.em_consts['c'] # Coordinates of Rx for Ez FDTD component Ez_x = x Ez_y = y Ez_z = z Er_z = np.sqrt((Ez_x**2 + Ez_y**2 + Ez_z**2)) - tau_Ez = Er_z / c + tau_Ez = Er_z / config.sim_config.em_consts['c'] # Coordinates of Rx for Hx FDTD component Hx_x = x Hx_y = y + 0.5 * dy Hx_z = z Hr_x = np.sqrt((Hx_x**2 + Hx_y**2 + Hx_z**2)) - tau_Hx = Hr_x / c + tau_Hx = Hr_x / config.sim_config.em_consts['c'] # Coordinates of Rx for Hy FDTD component Hy_x = x + 0.5 * dx Hy_y = y Hy_z = z Hr_y = np.sqrt((Hy_x**2 + Hy_y**2 + Hy_z**2)) - tau_Hy = Hr_y / c - - # Coordinates of Rx for Hz FDTD component - Hz_x = x + 0.5 * dx - Hz_y = y + 0.5 * dy - Hz_z = z - 0.5 * dz - Hr_z = np.sqrt((Hz_x**2 + Hz_y**2 + Hz_z**2)) - tau_Hz = Hr_z / c + tau_Hy = Hr_y / config.sim_config.em_consts['c'] # Initialise fields fields = np.zeros((iterations, 6)) @@ -118,30 +106,24 @@ def hertzian_dipole_fs(iterations, dt, dxdydz, rx): f_Ez = w.calculate_value((timestep * dt) - tau_Ez, dt) * dl fdot_Ez = wdot.calculate_value((timestep * dt) - tau_Ez, dt) * dl - fint_Hx = wint.calculate_value((timestep * dt) - tau_Hx, dt) * dl f_Hx = w.calculate_value((timestep * dt) - tau_Hx, dt) * dl fdot_Hx = wdot.calculate_value((timestep * dt) - tau_Hx, dt) * dl - fint_Hy = wint.calculate_value((timestep * dt) - tau_Hy, dt) * dl f_Hy = w.calculate_value((timestep * dt) - tau_Hy, dt) * dl fdot_Hy = wdot.calculate_value((timestep * dt) - tau_Hy, dt) * dl - fint_Hz = wint.calculate_value((timestep * dt) - tau_Hz, dt) * dl - f_Hz = w.calculate_value((timestep * dt) - tau_Hz, dt) * dl - fdot_Hz = wdot.calculate_value((timestep * dt) - tau_Hz, dt) * dl - # Ex - fields[timestep, 0] = ((Ex_x * Ex_z) / (4 * np.pi * e0 * Er_x**5)) * (3 * (fint_Ex + (tau_Ex * f_Ex)) + (tau_Ex**2 * fdot_Ex)) + fields[timestep, 0] = ((Ex_x * Ex_z) / (4 * np.pi * config.sim_config.em_consts['e0'] * Er_x**5)) * (3 * (fint_Ex + (tau_Ex * f_Ex)) + (tau_Ex**2 * fdot_Ex)) # Ey try: tmp = Ey_y / Ey_x except ZeroDivisionError: tmp = 0 - fields[timestep, 1] = tmp * ((Ey_x * Ey_z) / (4 * np.pi * e0 * Er_y**5)) * (3 * (fint_Ey + (tau_Ey * f_Ey)) + (tau_Ey**2 * fdot_Ey)) + fields[timestep, 1] = tmp * ((Ey_x * Ey_z) / (4 * np.pi * config.sim_config.em_consts['e0'] * Er_y**5)) * (3 * (fint_Ey + (tau_Ey * f_Ey)) + (tau_Ey**2 * fdot_Ey)) # Ez - fields[timestep, 2] = (1 / (4 * np.pi * e0 * Er_z**5)) * ((2 * Ez_z**2 - (Ez_x**2 + Ez_y**2)) * (fint_Ez + (tau_Ez * f_Ez)) - (Ez_x**2 + Ez_y**2) * tau_Ez**2 * fdot_Ez) + fields[timestep, 2] = (1 / (4 * np.pi * config.sim_config.em_consts['e0'] * Er_z**5)) * ((2 * Ez_z**2 - (Ez_x**2 + Ez_y**2)) * (fint_Ez + (tau_Ez * f_Ez)) - (Ez_x**2 + Ez_y**2) * tau_Ez**2 * fdot_Ez) # Hx fields[timestep, 3] = - (Hx_y / (4 * np.pi * Hr_x**3)) * (f_Hx + (tau_Hx * fdot_Hx)) diff --git a/tests/test_experimental.py b/tests/test_experimental.py index 99235748..acc96189 100644 --- a/tests/test_experimental.py +++ b/tests/test_experimental.py @@ -17,13 +17,12 @@ # along with gprMax. If not, see . import argparse -from pathlib import Path import sys +from pathlib import Path import h5py -import numpy as np import matplotlib.pyplot as plt - +import numpy as np from gprMax.exceptions import CmdInputError """Plots a comparison of fields between given simulation output and experimental data files.""" diff --git a/tests/test_models.py b/tests/test_models.py index cc541b7b..eb580372 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -16,21 +16,21 @@ # You should have received a copy of the GNU General Public License # along with gprMax. If not, see . -from pathlib import Path import sys +from pathlib import Path -from colorama import init, Fore, Style -init() +import gprMax import h5py -import numpy as np import matplotlib.pyplot as plt +import numpy as np +from colorama import Fore, Style, init +init() +from gprMax.exceptions import GeneralError +from tests.analytical_solutions import hertzian_dipole_fs if sys.platform == 'linux': plt.switch_backend('agg') -import gprMax -from gprMax.exceptions import GeneralError -from tests.analytical_solutions import hertzian_dipole_fs """Compare field outputs diff --git a/tools/HPC_scripts/gprmax_omp_mpi.sh b/tools/HPC_scripts/gprmax_omp_mpi.sh index dc1d8599..3c511ed1 100644 --- a/tools/HPC_scripts/gprmax_omp_mpi.sh +++ b/tools/HPC_scripts/gprmax_omp_mpi.sh @@ -16,7 +16,7 @@ #$ -pe mpi 176 ### Job script name: -#$ -N gprmax_omp_mpi.sh +#$ -N gprmax_omp_mpi_no_spawn.sh ##################################################################################### ### Initialise environment module @@ -34,4 +34,4 @@ export OMP_NUM_THREADS=16 ### Run gprMax with input file cd $HOME/gprMax -python -m gprMax mymodel.in -n 10 -mpi 11 +mpirun -n 11 python -m gprMax mymodel.in -n 10 -mpi diff --git a/tools/HPC_scripts/gprmax_omp_mpi_no_spawn.sh b/tools/HPC_scripts/gprmax_omp_mpi_no_spawn.sh deleted file mode 100644 index 5cd91c3e..00000000 --- a/tools/HPC_scripts/gprmax_omp_mpi_no_spawn.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -##################################################################################### -### Change to current working directory: -#$ -cwd - -### Specify runtime (hh:mm:ss): -#$ -l h_rt=01:00:00 - -### Email options: -#$ -m ea -M joe.bloggs@email.com - -### Resource reservation: -#$ -R y - -### Parallel environment ($NSLOTS): -#$ -pe mpi 176 - -### Job script name: -#$ -N gprmax_omp_mpi_no_spawn.sh -##################################################################################### - -### Initialise environment module -. /etc/profile.d/modules.sh - -### Load and activate Anaconda environment for gprMax, i.e. Python 3 and required packages -module load anaconda -source activate gprMax - -### Load OpenMPI -module load openmpi - -### Set number of OpenMP threads per MPI task (each gprMax model) -export OMP_NUM_THREADS=16 - -### Run gprMax with input file -cd $HOME/gprMax -mpirun -n 11 python -m gprMax mymodel.in -n 10 --mpi-no-spawn diff --git a/tools/inputfile_old2new.py b/tools/inputfile_old2new.py index 0fca1f32..fd02a9f3 100644 --- a/tools/inputfile_old2new.py +++ b/tools/inputfile_old2new.py @@ -223,7 +223,7 @@ while(lindex < len(inputlines)): lindex += 1 elif cmdname == '#bowtie': - print("Command '{}', is no longer supported. You can create the bowtie shape using two triangle commands.".format(inputlines[lindex], replacement)) + print("Command '{}', is no longer supported. You can create the bowtie shape using two triangle commands.".format(inputlines[lindex])) inputlines.pop(lindex) elif cmdname == '#cylinder': diff --git a/tools/outputfiles_merge.py b/tools/outputfiles_merge.py index 475cade3..bfdaacde 100644 --- a/tools/outputfiles_merge.py +++ b/tools/outputfiles_merge.py @@ -23,8 +23,8 @@ from pathlib import Path import h5py import numpy as np - from gprMax._version import __version__ +from gprMax.exceptions import CmdInputError def get_output_data(filename, rxnumber, rxcomponent): diff --git a/tools/plot_Ascan.py b/tools/plot_Ascan.py index 6dbe200b..9a6a4520 100644 --- a/tools/plot_Ascan.py +++ b/tools/plot_Ascan.py @@ -20,10 +20,9 @@ import argparse from pathlib import Path import h5py -import numpy as np -import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec - +import matplotlib.pyplot as plt +import numpy as np from gprMax.exceptions import CmdInputError from gprMax.receivers import Rx from gprMax.utilities import fft_power diff --git a/tools/plot_Bscan.py b/tools/plot_Bscan.py index 11ea0578..336cc0d0 100644 --- a/tools/plot_Bscan.py +++ b/tools/plot_Bscan.py @@ -20,10 +20,10 @@ import argparse from pathlib import Path import h5py -import numpy as np import matplotlib.pyplot as plt - +import numpy as np from gprMax.exceptions import CmdInputError + from .outputfiles_merge import get_output_data diff --git a/tools/plot_antenna_params.py b/tools/plot_antenna_params.py index 92558467..83f93a4d 100644 --- a/tools/plot_antenna_params.py +++ b/tools/plot_antenna_params.py @@ -20,10 +20,9 @@ import argparse from pathlib import Path import h5py -import numpy as np -import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec - +import matplotlib.pyplot as plt +import numpy as np from gprMax.exceptions import CmdInputError @@ -412,10 +411,10 @@ def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp, Iref, # ax.grid(which='both', axis='both', linestyle='-.') # Save a PDF/PNG of the figure - savename1 = file.stem + '_tl_params' - savename1 = file.parent / savename1 - savename2 = file.stem + '_ant_params' - savename2 = file.parent / savename2 + savename1 = filename.stem + '_tl_params' + savename1 = filename.parent / savename1 + savename2 = filename.stem + '_ant_params' + savename2 = filename.parent / savename2 # fig1.savefig(savename1.with_suffix('.png'), dpi=150, format='png', # bbox_inches='tight', pad_inches=0.1) # fig2.savefig(savename2.with_suffix('.png'), dpi=150, format='png', diff --git a/tools/plot_antenna_params_UtEl.py b/tools/plot_antenna_params_UtEl.py new file mode 100644 index 00000000..5f24e7cb --- /dev/null +++ b/tools/plot_antenna_params_UtEl.py @@ -0,0 +1,429 @@ +# Copyright (C) 2015-2020: The University of Edinburgh +# Authors: Craig Warren and Antonis Giannopoulos +# +# This file is part of gprMax. +# +# gprMax is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# gprMax is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with gprMax. If not, see . + +import argparse +from pathlib import Path + +import h5py +import matplotlib.gridspec as gridspec +import matplotlib.pyplot as plt +import numpy as np +from gprMax.exceptions import CmdInputError +from scipy.io import loadmat + + +def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=None, rxcomponent=None): + """Calculates antenna parameters - incident, reflected and total volatges and currents; s11, (s21) and input impedance. + + Args: + filename (string): Filename (including path) of output file. + tltxnumber (int): Transmitter antenna - transmission line number + tlrxnumber (int): Receiver antenna - transmission line number + rxnumber (int): Receiver antenna - output number + rxcomponent (str): Receiver antenna - output electric field component + + Returns: + antennaparams (dict): Antenna parameters. + """ + + # Open output file and read some attributes + file = Path(filename) + f = h5py.File(file, 'r') + dxdydz = f.attrs['dx_dy_dz'] + dt = f.attrs['dt'] + iterations = f.attrs['Iterations'] + + # Calculate time array and frequency bin spacing + time = np.linspace(0, (iterations - 1) * dt, num=iterations) + df = 1 / np.amax(time) + + print(f'Time window: {np.amax(time):g} s ({iterations} iterations)') + print(f'Time step: {dt:g} s') + print(f'Frequency bin spacing: {df:g} Hz') + + # Read/calculate voltages and currents from transmitter antenna + tltxpath = '/tls/tl' + str(tltxnumber) + '/' + + # Incident voltages/currents + Vinc = f[tltxpath + 'Vinc'][:] + Iinc = f[tltxpath + 'Iinc'][:] + + # Total (incident + reflected) voltages/currents + Vtotal = f[tltxpath + 'Vtotal'][:] + Itotal = f[tltxpath + 'Itotal'][:] + + # Reflected voltages/currents + Vref = Vtotal - Vinc + Iref = Itotal - Iinc + + # If a receiver antenna is used (with a transmission line or receiver), get received voltage for s21 + if tlrxnumber: + tlrxpath = '/tls/tl' + str(tlrxnumber) + '/' + Vrec = f[tlrxpath + 'Vtotal'][:] + + elif rxnumber: + rxpath = '/rxs/rx' + str(rxnumber) + '/' + availableoutputs = list(f[rxpath].keys()) + + if rxcomponent not in availableoutputs: + raise CmdInputError(f"{rxcomponent} output requested, but the available output for receiver {rxnumber} is {', '.join(availableoutputs)}") + + rxpath += rxcomponent + + # Received voltage + if rxcomponent == 'Ex': + Vrec = f[rxpath][:] * -1 * dxdydz[0] + elif rxcomponent == 'Ey': + Vrec = f[rxpath][:] * -1 * dxdydz[1] + elif rxcomponent == 'Ez': + Vrec = f[rxpath][:] * -1 * dxdydz[2] + f.close() + + # Frequency bins + freqs = np.fft.fftfreq(Vinc.size, d=dt) + + # Delay correction - current lags voltage, so delay voltage to match current timestep + delaycorrection = np.exp(1j * 2 * np.pi * freqs * (dt / 2)) + + # Calculate s11 and (optionally) s21 + s11 = np.abs(np.fft.fft(Vref) / np.fft.fft(Vinc)) + if tlrxnumber or rxnumber: + s21 = np.abs(np.fft.fft(Vrec) / np.fft.fft(Vinc)) + + # Calculate input impedance + zin = (np.fft.fft(Vtotal) * delaycorrection) / np.fft.fft(Itotal) + + # Calculate input admittance + yin = np.fft.fft(Itotal) / (np.fft.fft(Vtotal) * delaycorrection) + + # Convert to decibels (ignore warning from taking a log of any zero values) + with np.errstate(divide='ignore'): + Vincp = 20 * np.log10(np.abs((np.fft.fft(Vinc) * delaycorrection))) + Iincp = 20 * np.log10(np.abs(np.fft.fft(Iinc))) + Vrefp = 20 * np.log10(np.abs((np.fft.fft(Vref) * delaycorrection))) + Irefp = 20 * np.log10(np.abs(np.fft.fft(Iref))) + Vtotalp = 20 * np.log10(np.abs((np.fft.fft(Vtotal) * delaycorrection))) + Itotalp = 20 * np.log10(np.abs(np.fft.fft(Itotal))) + s11 = 20 * np.log10(s11) + + # Replace any NaNs or Infs from zero division + Vincp[np.invert(np.isfinite(Vincp))] = 0 + Iincp[np.invert(np.isfinite(Iincp))] = 0 + Vrefp[np.invert(np.isfinite(Vrefp))] = 0 + Irefp[np.invert(np.isfinite(Irefp))] = 0 + Vtotalp[np.invert(np.isfinite(Vtotalp))] = 0 + Itotalp[np.invert(np.isfinite(Itotalp))] = 0 + s11[np.invert(np.isfinite(s11))] = 0 + + # Create dictionary of antenna parameters + antennaparams = {'time': time, 'freqs': freqs, 'Vinc': Vinc, 'Vincp': Vincp, 'Iinc': Iinc, 'Iincp': Iincp, + 'Vref': Vref, 'Vrefp': Vrefp, 'Iref': Iref, 'Irefp': Irefp, + 'Vtotal': Vtotal, 'Vtotalp': Vtotalp, 'Itotal': Itotal, 'Itotalp': Itotalp, + 's11': s11, 'zin': zin, 'yin': yin} + if tlrxnumber or rxnumber: + with np.errstate(divide='ignore'): # Ignore warning from taking a log of any zero values + s21 = 20 * np.log10(s21) + s21[np.invert(np.isfinite(s21))] = 0 + antennaparams['s21'] = s21 + + return antennaparams + + +def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp, Iref, Irefp, Vtotal, Vtotalp, Itotal, Itotalp, s11, zin, yin, s21=None): + """Plots antenna parameters - incident, reflected and total volatges and currents; s11, (s21) and input impedance. + + Args: + filename (string): Filename (including path) of output file. + time (array): Simulation time. + freq (array): Frequencies for FFTs. + Vinc, Vincp, Iinc, Iincp (array): Time and frequency domain representations of incident voltage and current. + Vref, Vrefp, Iref, Irefp (array): Time and frequency domain representations of reflected voltage and current. + Vtotal, Vtotalp, Itotal, Itotalp (array): Time and frequency domain representations of total voltage and current. + s11, s21 (array): s11 and, optionally, s21 parameters. + zin, yin (array): Input impedance and input admittance parameters. + + Returns: + plt (object): matplotlib plot object. + """ + + # Set plotting range + pltrangemin = 1 + # To a certain drop from maximum power + pltrangemax = np.where((np.amax(Vincp[1::]) - Vincp[1::]) > 60)[0][0] + 1 + # To a maximum frequency + pltrangemax = np.where(freqs > 3e9)[0][0] + pltrange = np.s_[pltrangemin:pltrangemax] + + # Print some useful values from s11, and input impedance + s11minfreq = np.where(s11[pltrange] == np.amin(s11[pltrange]))[0][0] + print(f's11 minimum: {np.amin(s11[pltrange]):g} dB at {freqs[s11minfreq + pltrangemin]:g} Hz') + print(f'At {freqs[s11minfreq + pltrangemin]:g} Hz...') + print(f'Input impedance: {np.abs(zin[s11minfreq + pltrangemin]):.1f}{zin[s11minfreq + pltrangemin].imag:+.1f}j Ohms') + # print(f'Input admittance (mag): {np.abs(yin[s11minfreq + pltrangemin]):g} S') + # print(f'Input admittance (phase): {np.angle(yin[s11minfreq + pltrangemin], deg=True):.1f} deg') + + # Figure 1 + # Plot incident voltage + # fig1, ax = plt.subplots(num='Transmitter transmission line parameters', figsize=(20, 12), facecolor='w', edgecolor='w') + # gs1 = gridspec.GridSpec(4, 2, hspace=0.7) + # ax = plt.subplot(gs1[0, 0]) + # ax.plot(time, Vinc, 'r', lw=2, label='Vinc') + # ax.set_title('Incident voltage') + # ax.set_xlabel('Time [s]') + # ax.set_ylabel('Voltage [V]') + # ax.set_xlim([0, np.amax(time)]) + # ax.grid(which='both', axis='both', linestyle='-.') + # + # # Plot frequency spectra of incident voltage + # ax = plt.subplot(gs1[0, 1]) + # markerline, stemlines, baseline = ax.stem(freqs[pltrange], Vincp[pltrange], '-.', use_line_collection=True) + # plt.setp(baseline, 'linewidth', 0) + # plt.setp(stemlines, 'color', 'r') + # plt.setp(markerline, 'markerfacecolor', 'r', 'markeredgecolor', 'r') + # ax.plot(freqs[pltrange], Vincp[pltrange], 'r', lw=2) + # ax.set_title('Incident voltage') + # ax.set_xlabel('Frequency [Hz]') + # ax.set_ylabel('Power [dB]') + # ax.grid(which='both', axis='both', linestyle='-.') + # + # # Plot incident current + # ax = plt.subplot(gs1[1, 0]) + # ax.plot(time, Iinc, 'b', lw=2, label='Vinc') + # ax.set_title('Incident current') + # ax.set_xlabel('Time [s]') + # ax.set_ylabel('Current [A]') + # ax.set_xlim([0, np.amax(time)]) + # ax.grid(which='both', axis='both', linestyle='-.') + # + # # Plot frequency spectra of incident current + # ax = plt.subplot(gs1[1, 1]) + # markerline, stemlines, baseline = ax.stem(freqs[pltrange], Iincp[pltrange], '-.', use_line_collection=True) + # plt.setp(baseline, 'linewidth', 0) + # plt.setp(stemlines, 'color', 'b') + # plt.setp(markerline, 'markerfacecolor', 'b', 'markeredgecolor', 'b') + # ax.plot(freqs[pltrange], Iincp[pltrange], 'b', lw=2) + # ax.set_title('Incident current') + # ax.set_xlabel('Frequency [Hz]') + # ax.set_ylabel('Power [dB]') + # ax.grid(which='both', axis='both', linestyle='-.') + # + # # Plot total voltage + # ax = plt.subplot(gs1[2, 0]) + # ax.plot(time, Vtotal, 'r', lw=2, label='Vinc') + # ax.set_title('Total (incident + reflected) voltage') + # ax.set_xlabel('Time [s]') + # ax.set_ylabel('Voltage [V]') + # ax.set_xlim([0, np.amax(time)]) + # ax.grid(which='both', axis='both', linestyle='-.') + # + # # Plot frequency spectra of total voltage + # ax = plt.subplot(gs1[2, 1]) + # markerline, stemlines, baseline = ax.stem(freqs[pltrange], Vtotalp[pltrange], '-.', use_line_collection=True) + # plt.setp(baseline, 'linewidth', 0) + # plt.setp(stemlines, 'color', 'r') + # plt.setp(markerline, 'markerfacecolor', 'r', 'markeredgecolor', 'r') + # ax.plot(freqs[pltrange], Vtotalp[pltrange], 'r', lw=2) + # ax.set_title('Total (incident + reflected) voltage') + # ax.set_xlabel('Frequency [Hz]') + # ax.set_ylabel('Power [dB]') + # ax.grid(which='both', axis='both', linestyle='-.') + # + # # Plot total current + # ax = plt.subplot(gs1[3, 0]) + # ax.plot(time, Itotal, 'b', lw=2, label='Vinc') + # ax.set_title('Total (incident + reflected) current') + # ax.set_xlabel('Time [s]') + # ax.set_ylabel('Current [A]') + # ax.set_xlim([0, np.amax(time)]) + # ax.grid(which='both', axis='both', linestyle='-.') + # + # # Plot frequency spectra of total current + # ax = plt.subplot(gs1[3, 1]) + # markerline, stemlines, baseline = ax.stem(freqs[pltrange], Itotalp[pltrange], '-.', use_line_collection=True) + # plt.setp(baseline, 'linewidth', 0) + # plt.setp(stemlines, 'color', 'b') + # plt.setp(markerline, 'markerfacecolor', 'b', 'markeredgecolor', 'b') + # ax.plot(freqs[pltrange], Itotalp[pltrange], 'b', lw=2) + # ax.set_title('Total (incident + reflected) current') + # ax.set_xlabel('Frequency [Hz]') + # ax.set_ylabel('Power [dB]') + # ax.grid(which='both', axis='both', linestyle='-.') + + # Plot reflected (reflected) voltage + # ax = plt.subplot(gs1[4, 0]) + # ax.plot(time, Vref, 'r', lw=2, label='Vref') + # ax.set_title('Reflected voltage') + # ax.set_xlabel('Time [s]') + # ax.set_ylabel('Voltage [V]') + # ax.set_xlim([0, np.amax(time)]) + # ax.grid(which='both', axis='both', linestyle='-.') + + # Plot frequency spectra of reflected voltage + # ax = plt.subplot(gs1[4, 1]) + # markerline, stemlines, baseline = ax.stem(freqs[pltrange], Vrefp[pltrange], '-.', use_line_collection=True) + # plt.setp(baseline, 'linewidth', 0) + # plt.setp(stemlines, 'color', 'r') + # plt.setp(markerline, 'markerfacecolor', 'r', 'markeredgecolor', 'r') + # ax.plot(freqs[pltrange], Vrefp[pltrange], 'r', lw=2) + # ax.set_title('Reflected voltage') + # ax.set_xlabel('Frequency [Hz]') + # ax.set_ylabel('Power [dB]') + # ax.grid(which='both', axis='both', linestyle='-.') + + # Plot reflected (reflected) current + # ax = plt.subplot(gs1[5, 0]) + # ax.plot(time, Iref, 'b', lw=2, label='Iref') + # ax.set_title('Reflected current') + # ax.set_xlabel('Time [s]') + # ax.set_ylabel('Current [A]') + # ax.set_xlim([0, np.amax(time)]) + # ax.grid(which='both', axis='both', linestyle='-.') + + # Plot frequency spectra of reflected current + # ax = plt.subplot(gs1[5, 1]) + # markerline, stemlines, baseline = ax.stem(freqs[pltrange], Irefp[pltrange], '-.', use_line_collection=True) + # plt.setp(baseline, 'linewidth', 0) + # plt.setp(stemlines, 'color', 'b') + # plt.setp(markerline, 'markerfacecolor', 'b', 'markeredgecolor', 'b') + # ax.plot(freqs[pltrange], Irefp[pltrange], 'b', lw=2) + # ax.set_title('Reflected current') + # ax.set_xlabel('Frequency [Hz]') + # ax.set_ylabel('Power [dB]') + # ax.grid(which='both', axis='both', linestyle='-.') + + # Figure 2 + # Load measured s11 + s11_meas = loadmat('/Volumes/Users/cwarren/Dropbox (Northumbria University)/Research/GPR-antennas/Utsi Electronics/500MHz_Vivaldi_antenna/measured/s11_measured.mat') + + # Plot frequency spectra of s11 + fig2, ax = plt.subplots(num='Antenna parameters', figsize=(20, 12), facecolor='w', edgecolor='w') + gs2 = gridspec.GridSpec(1, 1, hspace=0.3) + ax = plt.subplot(gs2[0, 0]) + markerline, stemlines, baseline = ax.stem(freqs[pltrange], s11[pltrange], '-.', use_line_collection=True) + markerline2, stemlines2, baseline2 = ax.stem(s11_meas['f'], s11_meas['s11_t'], '-.', use_line_collection=True) + plt.setp(baseline, 'linewidth', 0) + plt.setp(stemlines, 'color', 'w') + plt.setp(markerline, 'markerfacecolor', 'g', 'markeredgecolor', 'g') + plt.setp(baseline2, 'linewidth', 0) + plt.setp(stemlines2, 'color', 'w') + plt.setp(markerline2, 'markerfacecolor', 'b', 'markeredgecolor', 'b') + ax.plot(freqs[pltrange], s11[pltrange], 'g', lw=2, label='Simulation (Debye, 50$\Omega$)') + ax.plot(s11_meas['f'], s11_meas['s11_t'], 'b', lw=2, label='Measured') + ax.set_title('s11') + ax.set_xlabel('Frequency [Hz]') + ax.set_ylabel('Power [dB]') + ax.set_xlim([0, 3e9]) + ax.set_ylim([-40, 0]) + ax.grid(which='both', axis='both', linestyle='-.') + ax.legend(fontsize=12, frameon=False) + + # Plot frequency spectra of s21 + if s21 is not None: + ax = plt.subplot(gs2[0, 1]) + markerline, stemlines, baseline = ax.stem(freqs[pltrange], s21[pltrange], '-.', use_line_collection=True) + plt.setp(baseline, 'linewidth', 0) + plt.setp(stemlines, 'color', 'g') + plt.setp(markerline, 'markerfacecolor', 'g', 'markeredgecolor', 'g') + ax.plot(freqs[pltrange], s21[pltrange], 'g', lw=2) + ax.set_title('s21') + ax.set_xlabel('Frequency [Hz]') + ax.set_ylabel('Power [dB]') + # ax.set_xlim([0.88e9, 1.02e9]) + # ax.set_ylim([-25, 50]) + ax.grid(which='both', axis='both', linestyle='-.') + + # Plot input resistance (real part of impedance) + # ax = plt.subplot(gs2[1, 0]) + # markerline, stemlines, baseline = ax.stem(freqs[pltrange], zin[pltrange].real, '-.', use_line_collection=True) + # plt.setp(baseline, 'linewidth', 0) + # plt.setp(stemlines, 'color', 'g') + # plt.setp(markerline, 'markerfacecolor', 'g', 'markeredgecolor', 'g') + # ax.plot(freqs[pltrange], zin[pltrange].real, 'g', lw=2) + # ax.set_title('Input impedance (resistive)') + # ax.set_xlabel('Frequency [Hz]') + # ax.set_ylabel('Resistance [Ohms]') + # # ax.set_xlim([0.88e9, 1.02e9]) + # ax.set_ylim(bottom=0) + # # ax.set_ylim([0, 300]) + # ax.grid(which='both', axis='both', linestyle='-.') + # + # # Plot input reactance (imaginery part of impedance) + # ax = plt.subplot(gs2[1, 1]) + # markerline, stemlines, baseline = ax.stem(freqs[pltrange], zin[pltrange].imag, '-.', use_line_collection=True) + # plt.setp(baseline, 'linewidth', 0) + # plt.setp(stemlines, 'color', 'g') + # plt.setp(markerline, 'markerfacecolor', 'g', 'markeredgecolor', 'g') + # ax.plot(freqs[pltrange], zin[pltrange].imag, 'g', lw=2) + # ax.set_title('Input impedance (reactive)') + # ax.set_xlabel('Frequency [Hz]') + # ax.set_ylabel('Reactance [Ohms]') + # # ax.set_xlim([0.88e9, 1.02e9]) + # # ax.set_ylim([-300, 300]) + # ax.grid(which='both', axis='both', linestyle='-.') + + # Plot input admittance (magnitude) + # ax = plt.subplot(gs2[2, 0]) + # markerline, stemlines, baseline = ax.stem(freqs[pltrange], np.abs(yin[pltrange]), '-.', use_line_collection=True) + # plt.setp(baseline, 'linewidth', 0) + # plt.setp(stemlines, 'color', 'g') + # plt.setp(markerline, 'markerfacecolor', 'g', 'markeredgecolor', 'g') + # ax.plot(freqs[pltrange], np.abs(yin[pltrange]), 'g', lw=2) + # ax.set_title('Input admittance (magnitude)') + # ax.set_xlabel('Frequency [Hz]') + # ax.set_ylabel('Admittance [Siemens]') + # ax.set_xlim([0.88e9, 1.02e9]) + # ax.set_ylim([0, 0.035]) + # ax.grid(which='both', axis='both', linestyle='-.') + + # Plot input admittance (phase) + # ax = plt.subplot(gs2[2, 1]) + # markerline, stemlines, baseline = ax.stem(freqs[pltrange], np.angle(yin[pltrange], deg=True), '-.', use_line_collection=True) + # plt.setp(baseline, 'linewidth', 0) + # plt.setp(stemlines, 'color', 'g') + # plt.setp(markerline, 'markerfacecolor', 'g', 'markeredgecolor', 'g') + # ax.plot(freqs[pltrange], np.angle(yin[pltrange], deg=True), 'g', lw=2) + # ax.set_title('Input admittance (phase)') + # ax.set_xlabel('Frequency [Hz]') + # ax.set_ylabel('Phase [degrees]') + # ax.set_xlim([0.88e9, 1.02e9]) + # ax.set_ylim([-40, 100]) + # ax.grid(which='both', axis='both', linestyle='-.') + + # Save a PDF/PNG of the figure + # fig1.savefig(os.path.splitext(os.path.abspath(filename))[0] + '_tl_params.png', dpi=150, format='png', bbox_inches='tight', pad_inches=0.1) + # fig2.savefig(os.path.splitext(os.path.abspath(filename))[0] + '_ant_params.png', dpi=150, format='png', bbox_inches='tight', pad_inches=0.1) + # fig1.savefig(os.path.splitext(os.path.abspath(filename))[0] + '_tl_params.pdf', dpi=None, format='pdf', bbox_inches='tight', pad_inches=0.1) + fig2.savefig(filename.with_suffix('.pdf'), dpi=None, format='pdf', bbox_inches='tight', pad_inches=0.1) + + return plt + + +if __name__ == "__main__": + + # Parse command line arguments + parser = argparse.ArgumentParser(description='Plots antenna parameters (s11, s21 parameters and input impedance) from an output file containing a transmission line source.', usage='cd gprMax; python -m tools.plot_antenna_params outputfile') + parser.add_argument('outputfile', help='name of output file including path') + parser.add_argument('--tltx-num', default=1, type=int, help='transmitter antenna - transmission line number') + parser.add_argument('--tlrx-num', type=int, help='receiver antenna - transmission line number') + parser.add_argument('--rx-num', type=int, help='receiver antenna - output number') + parser.add_argument('--rx-component', type=str, help='receiver antenna - output electric field component', choices=['Ex', 'Ey', 'Ez']) + args = parser.parse_args() + + antennaparams = calculate_antenna_params(args.outputfile, args.tltx_num, args.tlrx_num, args.rx_num, args.rx_component) + plthandle = mpl_plot(args.outputfile, **antennaparams) + plthandle.show() diff --git a/tools/plot_source_wave.py b/tools/plot_source_wave.py index 5e51b7bd..7d7299cd 100644 --- a/tools/plot_source_wave.py +++ b/tools/plot_source_wave.py @@ -19,12 +19,10 @@ import argparse from pathlib import Path -import numpy as np import matplotlib.pyplot as plt - +import numpy as np from gprMax.exceptions import CmdInputError -from gprMax.utilities import fft_power -from gprMax.utilities import round_value +from gprMax.utilities import fft_power, round_value from gprMax.waveforms import Waveform diff --git a/user_libs/antenna_patterns/initial_save.py b/user_libs/antenna_patterns/initial_save.py index 38538d9c..b0fc312d 100644 --- a/user_libs/antenna_patterns/initial_save.py +++ b/user_libs/antenna_patterns/initial_save.py @@ -9,13 +9,10 @@ import argparse import os import sys +import gprMax.config as config import h5py -import numpy as np import matplotlib.pyplot as plt - -from gprMax.config import c -from gprMax.config import z0 - +import numpy as np # Parse command line arguments parser = argparse.ArgumentParser(description='Calculate and store (in a Numpy file) field patterns from a simulation with receivers positioned in circles around an antenna.', usage='cd gprMax; python -m user_libs.antenna_patterns.initial_save outputfile') @@ -55,9 +52,9 @@ traceno = np.s_[:] # All traces # Critical angle and velocity if epsr: mr = 1 - z1 = np.sqrt(mr / epsr) * z0 - v1 = c / np.sqrt(epsr) - thetac = np.round(np.arcsin(v1 / c) * (180 / np.pi)) + z1 = np.sqrt(mr / epsr) * config.sim_config.em_consts['z0'] + v1 = config.sim_config.em_consts['c'] / np.sqrt(epsr) + thetac = np.round(np.arcsin(v1 / config.sim_config.em_consts['c']) * (180 / np.pi)) wavelength = v1 / f # Print some useful information @@ -164,8 +161,8 @@ for radius in range(0, len(radii)): Ethetasum[index] = np.sum(Etheta[:, index]**2) / z1 Hthetasum[index] = np.sum(Htheta[:, index]**2) / z1 else: - Ethetasum[index] = np.sum(Etheta[:, index]**2) / z0 - Hthetasum[index] = np.sum(Htheta[:, index]**2) / z0 + Ethetasum[index] = np.sum(Etheta[:, index]**2) / config.sim_config.em_consts['z0'] + Hthetasum[index] = np.sum(Htheta[:, index]**2) / config.sim_config.em_consts['z0'] index += 1 diff --git a/user_libs/antenna_patterns/plot_fields.py b/user_libs/antenna_patterns/plot_fields.py index f78247ad..e3ff3351 100644 --- a/user_libs/antenna_patterns/plot_fields.py +++ b/user_libs/antenna_patterns/plot_fields.py @@ -9,12 +9,9 @@ import argparse import os import sys -import numpy as np +import gprMax.config as config import matplotlib.pyplot as plt - -from gprMax.config import c -from gprMax.config import z0 - +import numpy as np # Parse command line arguments parser = argparse.ArgumentParser(description='Plot field patterns from a simulation with receivers positioned in circles around an antenna. This module should be used after the field pattern data has been processed and stored using the initial_save.py module.', usage='cd gprMax; python -m user_libs.antenna_patterns.plot_fields numpyfile') @@ -52,9 +49,9 @@ step = 12 # Critical angle and velocity if epsr: mr = 1 - z1 = np.sqrt(mr / epsr) * z0 - v1 = c / np.sqrt(epsr) - thetac = np.round(np.rad2deg(np.arcsin(v1 / c))) + z1 = np.sqrt(mr / epsr) * config.sim_config.em_consts['z0'] + v1 = config.sim_config.em_consts['c'] / np.sqrt(epsr) + thetac = np.round(np.rad2deg(np.arcsin(v1 / config.sim_config.em_consts['c']))) wavelength = v1 / f # Print some useful information