Updated with ruff formatter

这个提交包含在:
Craig Warren
2025-02-04 20:38:27 +00:00
父节点 e2c5a23f28
当前提交 548a0a550c
共有 70 个文件被更改,包括 3601 次插入982 次删除

查看文件

@@ -91,11 +91,15 @@ class AddGrass(UserObjectGeometry):
self._do_rotate()
# Get the correct fractal volume
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
volumes = [
volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id
]
try:
volume = volumes[0]
except NameError:
logger.exception(f"{self.__str__()} cannot find FractalBox {fractal_box_id}")
logger.exception(
f"{self.__str__()} cannot find FractalBox {fractal_box_id}"
)
raise
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
@@ -103,7 +107,9 @@ class AddGrass(UserObjectGeometry):
xf, yf, zf = p2
if frac_dim < 0:
logger.exception(f"{self.__str__()} requires a positive value for the fractal dimension")
logger.exception(
f"{self.__str__()} requires a positive value for the fractal dimension"
)
raise ValueError
if limits[0] < 0 or limits[1] < 0:
logger.exception(
@@ -114,12 +120,19 @@ class AddGrass(UserObjectGeometry):
# Check for valid orientations
if xs == xf:
if ys == yf or zs == zf:
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
logger.exception(
f"{self.__str__()} dimensions are not specified correctly"
)
raise ValueError
if xs not in [volume.xs, volume.xf]:
logger.exception(f"{self.__str__()} must specify external surfaces on a fractal box")
logger.exception(
f"{self.__str__()} must specify external surfaces on a fractal box"
)
raise ValueError
fractalrange = (round_value(limits[0] / grid.dx), round_value(limits[1] / grid.dx))
fractalrange = (
round_value(limits[0] / grid.dx),
round_value(limits[1] / grid.dx),
)
# xminus surface
if xs == volume.xs:
logger.exception(
@@ -139,12 +152,19 @@ class AddGrass(UserObjectGeometry):
elif ys == yf:
if zs == zf:
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
logger.exception(
f"{self.__str__()} dimensions are not specified correctly"
)
raise ValueError
if ys not in [volume.ys, volume.yf]:
logger.exception(f"{self.__str__()} must specify external surfaces on a fractal box")
logger.exception(
f"{self.__str__()} must specify external surfaces on a fractal box"
)
raise ValueError
fractalrange = (round_value(limits[0] / grid.dy), round_value(limits[1] / grid.dy))
fractalrange = (
round_value(limits[0] / grid.dy),
round_value(limits[1] / grid.dy),
)
# yminus surface
if ys == volume.ys:
logger.exception(
@@ -164,9 +184,14 @@ class AddGrass(UserObjectGeometry):
elif zs == zf:
if zs not in [volume.zs, volume.zf]:
logger.exception(f"{self.__str__()} must specify external surfaces on a fractal box")
logger.exception(
f"{self.__str__()} must specify external surfaces on a fractal box"
)
raise ValueError
fractalrange = (round_value(limits[0] / grid.dz), round_value(limits[1] / grid.dz))
fractalrange = (
round_value(limits[0] / grid.dz),
round_value(limits[1] / grid.dz),
)
# zminus surface
if zs == volume.zs:
logger.exception(
@@ -219,7 +244,8 @@ class AddGrass(UserObjectGeometry):
# probability values, and convert the 1D index back into a x, y index
# for the original surface.
bladesindex = np.unravel_index(
np.digitize(A, probability1D), (surface.fractalsurface.shape[0], surface.fractalsurface.shape[1])
np.digitize(A, probability1D),
(surface.fractalsurface.shape[0], surface.fractalsurface.shape[1]),
)
# Set the fractal range to minimum and maximum heights of the grass blades
@@ -227,7 +253,9 @@ class AddGrass(UserObjectGeometry):
# Set the fractal surface using the pre-calculated spatial distribution
# and a random height
surface.fractalsurface = np.zeros((surface.fractalsurface.shape[0], surface.fractalsurface.shape[1]))
surface.fractalsurface = np.zeros(
(surface.fractalsurface.shape[0], surface.fractalsurface.shape[1])
)
for i in range(len(bladesindex[0])):
surface.fractalsurface[bladesindex[0][i], bladesindex[1][i]] = R.randint(
surface.fractalrange[0], surface.fractalrange[1], size=1

查看文件

@@ -91,11 +91,15 @@ class AddSurfaceRoughness(UserObjectGeometry):
self._do_rotate()
# Get the correct fractal volume
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
volumes = [
volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id
]
if volumes:
volume = volumes[0]
else:
logger.exception(f"{self.__str__()} cannot find FractalBox {fractal_box_id}")
logger.exception(
f"{self.__str__()} cannot find FractalBox {fractal_box_id}"
)
raise ValueError
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
@@ -103,7 +107,10 @@ class AddSurfaceRoughness(UserObjectGeometry):
xf, yf, zf = p2
if frac_dim < 0:
logger.exception(f"{self.__str__()} requires a positive value for the " + "fractal dimension")
logger.exception(
f"{self.__str__()} requires a positive value for the "
+ "fractal dimension"
)
raise ValueError
if weighting[0] < 0:
logger.exception(
@@ -121,12 +128,19 @@ class AddSurfaceRoughness(UserObjectGeometry):
# Check for valid orientations
if xs == xf:
if ys == yf or zs == zf:
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
logger.exception(
f"{self.__str__()} dimensions are not specified correctly"
)
raise ValueError
if xs not in [volume.xs, volume.xf]:
logger.exception(f"{self.__str__()} can only be used on the external surfaces of a fractal box")
logger.exception(
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
)
raise ValueError
fractalrange = (round_value(limits[0] / grid.dx), round_value(limits[1] / grid.dx))
fractalrange = (
round_value(limits[0] / grid.dx),
round_value(limits[1] / grid.dx),
)
# xminus surface
if xs == volume.xs:
if fractalrange[0] < 0 or fractalrange[1] > volume.xf:
@@ -152,12 +166,20 @@ class AddSurfaceRoughness(UserObjectGeometry):
elif ys == yf:
if zs == zf:
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
logger.exception(
f"{self.__str__()} dimensions are not specified correctly"
)
raise ValueError
if ys not in [volume.ys, volume.yf]:
logger.exception(f"{self.__str__()} can only be used on the external " + "surfaces of a fractal box")
logger.exception(
f"{self.__str__()} can only be used on the external "
+ "surfaces of a fractal box"
)
raise ValueError
fractalrange = (round_value(limits[0] / grid.dy), round_value(limits[1] / grid.dy))
fractalrange = (
round_value(limits[0] / grid.dy),
round_value(limits[1] / grid.dy),
)
# yminus surface
if ys == volume.ys:
if fractalrange[0] < 0 or fractalrange[1] > volume.yf:
@@ -183,9 +205,15 @@ class AddSurfaceRoughness(UserObjectGeometry):
elif zs == zf:
if zs not in [volume.zs, volume.zf]:
logger.exception(f"{self.__str__()} can only be used on the external " + "surfaces of a fractal box")
logger.exception(
f"{self.__str__()} can only be used on the external "
+ "surfaces of a fractal box"
)
raise ValueError
fractalrange = (round_value(limits[0] / grid.dz), round_value(limits[1] / grid.dz))
fractalrange = (
round_value(limits[0] / grid.dz),
round_value(limits[1] / grid.dz),
)
# zminus surface
if zs == volume.zs:
if fractalrange[0] < 0 or fractalrange[1] > volume.zf:
@@ -222,7 +250,9 @@ class AddSurfaceRoughness(UserObjectGeometry):
# List of existing surfaces IDs
existingsurfaceIDs = [x.surfaceID for x in volume.fractalsurfaces]
if surface.surfaceID in existingsurfaceIDs:
logger.exception(f"{self.__str__()} has already been used on the {surface.surfaceID} surface")
logger.exception(
f"{self.__str__()} has already been used on the {surface.surfaceID} surface"
)
raise ValueError
surface.generate_fractal_surface()

查看文件

@@ -74,10 +74,14 @@ class AddSurfaceWater(UserObjectGeometry):
if self.do_rotate:
self._do_rotate()
if volumes := [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]:
if volumes := [
volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id
]:
volume = volumes[0]
else:
logger.exception(f"{self.__str__()} cannot find FractalBox {fractal_box_id}")
logger.exception(
f"{self.__str__()} cannot find FractalBox {fractal_box_id}"
)
raise ValueError
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
@@ -85,16 +89,22 @@ class AddSurfaceWater(UserObjectGeometry):
xf, yf, zf = p2
if depth <= 0:
logger.exception(f"{self.__str__()} requires a positive value for the depth of water")
logger.exception(
f"{self.__str__()} requires a positive value for the depth of water"
)
raise ValueError
# Check for valid orientations
if xs == xf:
if ys == yf or zs == zf:
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
logger.exception(
f"{self.__str__()} dimensions are not specified correctly"
)
raise ValueError
if xs not in [volume.xs, volume.xf]:
logger.exception(f"{self.__str__()} can only be used on the external surfaces of a fractal box")
logger.exception(
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
)
raise ValueError
# xminus surface
if xs == volume.xs:
@@ -107,10 +117,14 @@ class AddSurfaceWater(UserObjectGeometry):
elif ys == yf:
if zs == zf:
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
logger.exception(
f"{self.__str__()} dimensions are not specified correctly"
)
raise ValueError
if ys not in [volume.ys, volume.yf]:
logger.exception(f"{self.__str__()} can only be used on the external surfaces of a fractal box")
logger.exception(
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
)
raise ValueError
# yminus surface
if ys == volume.ys:
@@ -123,7 +137,9 @@ class AddSurfaceWater(UserObjectGeometry):
elif zs == zf:
if zs not in [volume.zs, volume.zf]:
logger.exception(f"{self.__str__()} can only be used on the external surfaces of a fractal box")
logger.exception(
f"{self.__str__()} can only be used on the external surfaces of a fractal box"
)
raise ValueError
# zminus surface
if zs == volume.zs:
@@ -138,7 +154,9 @@ class AddSurfaceWater(UserObjectGeometry):
logger.exception(f"{self.__str__()} dimensions are not specified correctly")
raise ValueError
surface = next((x for x in volume.fractalsurfaces if x.surfaceID == requestedsurface), None)
surface = next(
(x for x in volume.fractalsurfaces if x.surfaceID == requestedsurface), None
)
if not surface:
logger.exception(
f"{self.__str__()} specified surface {requestedsurface} does not have a rough surface applied"
@@ -148,7 +166,10 @@ class AddSurfaceWater(UserObjectGeometry):
surface.filldepth = filldepthcells
# Check that requested fill depth falls within range of surface roughness
if surface.filldepth < surface.fractalrange[0] or surface.filldepth > surface.fractalrange[1]:
if (
surface.filldepth < surface.fractalrange[0]
or surface.filldepth > surface.fractalrange[1]
):
logger.exception(
f"{self.__str__()} requires a value for the depth of water that lies with the "
f"range of the requested surface roughness"

查看文件

@@ -24,8 +24,7 @@ import gprMax.config as config
from ..cython.geometry_primitives import build_box
from ..materials import Material
from .cmds_geometry import (UserObjectGeometry, check_averaging,
rotate_2point_object)
from .cmds_geometry import UserObjectGeometry, check_averaging, rotate_2point_object
logger = logging.getLogger(__name__)
@@ -128,10 +127,18 @@ class Box(UserObjectGeometry):
m = Material(numID, requiredID)
m.type = "dielectric-smoothed"
# Create dielectric-smoothed constituents for material
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
m.sm = np.mean((materials[0].sm, materials[1].sm, materials[2].sm), axis=0)
m.er = np.mean(
(materials[0].er, materials[1].er, materials[2].er), axis=0
)
m.se = np.mean(
(materials[0].se, materials[1].se, materials[2].se), axis=0
)
m.mr = np.mean(
(materials[0].mr, materials[1].mr, materials[2].mr), axis=0
)
m.sm = np.mean(
(materials[0].sm, materials[1].sm, materials[2].sm), axis=0
)
# Append the new material object to the materials list
grid.materials.append(m)

查看文件

@@ -55,7 +55,9 @@ class Cone(UserObjectGeometry):
r1 = self.kwargs["r1"]
r2 = self.kwargs["r2"]
except KeyError:
logger.exception(f"{self.__str__()} please specify two points and two radii")
logger.exception(
f"{self.__str__()} please specify two points and two radii"
)
raise
# Check averaging
@@ -86,11 +88,15 @@ class Cone(UserObjectGeometry):
x2, y2, z2 = uip.round_to_grid(p2)
if r1 < 0:
logger.exception(f"{self.__str__()} the radius of the first face {r1:g} should be a positive value.")
logger.exception(
f"{self.__str__()} the radius of the first face {r1:g} should be a positive value."
)
raise ValueError
if r2 < 0:
logger.exception(f"{self.__str__()} the radius of the second face {r2:g} should be a positive value.")
logger.exception(
f"{self.__str__()} the radius of the second face {r2:g} should be a positive value."
)
raise ValueError
if r1 == 0 and r2 == 0:
@@ -125,10 +131,18 @@ class Cone(UserObjectGeometry):
m = Material(numID, requiredID)
m.type = "dielectric-smoothed"
# Create dielectric-smoothed constituents for material
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
m.sm = np.mean((materials[0].sm, materials[1].sm, materials[2].sm), axis=0)
m.er = np.mean(
(materials[0].er, materials[1].er, materials[2].er), axis=0
)
m.se = np.mean(
(materials[0].se, materials[1].se, materials[2].se), axis=0
)
m.mr = np.mean(
(materials[0].mr, materials[1].mr, materials[2].mr), axis=0
)
m.sm = np.mean(
(materials[0].sm, materials[1].sm, materials[2].sm), axis=0
)
# Append the new material object to the materials list
grid.materials.append(m)

查看文件

@@ -83,7 +83,9 @@ class Cylinder(UserObjectGeometry):
x2, y2, z2 = uip.round_to_grid(p2)
if r <= 0:
logger.exception(f"{self.__str__()} the radius {r:g} should be a positive value.")
logger.exception(
f"{self.__str__()} the radius {r:g} should be a positive value."
)
raise ValueError
# Look up requested materials in existing list of material instances
@@ -114,10 +116,18 @@ class Cylinder(UserObjectGeometry):
m = Material(numID, requiredID)
m.type = "dielectric-smoothed"
# Create dielectric-smoothed constituents for material
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
m.sm = np.mean((materials[0].sm, materials[1].sm, materials[2].sm), axis=0)
m.er = np.mean(
(materials[0].er, materials[1].er, materials[2].er), axis=0
)
m.se = np.mean(
(materials[0].se, materials[1].se, materials[2].se), axis=0
)
m.mr = np.mean(
(materials[0].mr, materials[1].mr, materials[2].mr), axis=0
)
m.sm = np.mean(
(materials[0].sm, materials[1].sm, materials[2].sm), axis=0
)
# Append the new material object to the materials list
grid.materials.append(m)

查看文件

@@ -95,15 +95,23 @@ class CylindricalSector(UserObjectGeometry):
sectorangle = 2 * np.pi * (end / 360)
if normal not in ["x", "y", "z"]:
logger.exception(f"{self.__str__()} the normal direction must be either x, y or z.")
logger.exception(
f"{self.__str__()} the normal direction must be either x, y or z."
)
raise ValueError
if r <= 0:
logger.exception(f"{self.__str__()} the radius {r:g} should be a positive value.")
logger.exception(
f"{self.__str__()} the radius {r:g} should be a positive value."
)
if sectorstartangle < 0 or sectorangle <= 0:
logger.exception(f"{self.__str__()} the starting angle and sector angle should be a positive values.")
logger.exception(
f"{self.__str__()} the starting angle and sector angle should be a positive values."
)
raise ValueError
if sectorstartangle >= 2 * np.pi or sectorangle >= 2 * np.pi:
logger.exception(f"{self.__str__()} the starting angle and sector angle must be less than 360 degrees.")
logger.exception(
f"{self.__str__()} the starting angle and sector angle must be less than 360 degrees."
)
raise ValueError
# Look up requested materials in existing list of material instances
@@ -134,10 +142,18 @@ class CylindricalSector(UserObjectGeometry):
m = Material(numID, requiredID)
m.type = "dielectric-smoothed"
# Create dielectric-smoothed constituents for material
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
m.sm = np.mean((materials[0].sm, materials[1].sm, materials[2].sm), axis=0)
m.er = np.mean(
(materials[0].er, materials[1].er, materials[2].er), axis=0
)
m.se = np.mean(
(materials[0].se, materials[1].se, materials[2].se), axis=0
)
m.mr = np.mean(
(materials[0].mr, materials[1].mr, materials[2].mr), axis=0
)
m.sm = np.mean(
(materials[0].sm, materials[1].sm, materials[2].sm), axis=0
)
# Append the new material object to the materials list
grid.materials.append(m)

查看文件

@@ -20,8 +20,7 @@ import logging
import numpy as np
from ..cython.geometry_primitives import (build_edge_x, build_edge_y,
build_edge_z)
from ..cython.geometry_primitives import build_edge_x, build_edge_y, build_edge_z
from .cmds_geometry import UserObjectGeometry, rotate_2point_object
logger = logging.getLogger(__name__)
@@ -92,15 +91,21 @@ class Edge(UserObjectGeometry):
raise ValueError
elif xs != xf:
for i in range(xs, xf):
build_edge_x(i, ys, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
build_edge_x(
i, ys, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID
)
elif ys != yf:
for j in range(ys, yf):
build_edge_y(xs, j, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
build_edge_y(
xs, j, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID
)
elif zs != zf:
for k in range(zs, zf):
build_edge_z(xs, ys, k, material.numID, grid.rigidE, grid.rigidH, grid.ID)
build_edge_z(
xs, ys, k, material.numID, grid.rigidE, grid.rigidH, grid.ID
)
logger.info(
f"{self.grid_name(grid)}Edge from {p3[0]:g}m, {p3[1]:g}m, "

查看文件

@@ -53,7 +53,9 @@ class Ellipsoid(UserObjectGeometry):
zr = self.kwargs["zr"]
except KeyError:
logger.exception(f"{self.__str__()} please specify a point and the three semiaxes.")
logger.exception(
f"{self.__str__()} please specify a point and the three semiaxes."
)
raise
# Check averaging
@@ -109,10 +111,18 @@ class Ellipsoid(UserObjectGeometry):
m = Material(numID, requiredID)
m.type = "dielectric-smoothed"
# Create dielectric-smoothed constituents for material
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
m.sm = np.mean((materials[0].sm, materials[1].sm, materials[2].sm), axis=0)
m.er = np.mean(
(materials[0].er, materials[1].er, materials[2].er), axis=0
)
m.se = np.mean(
(materials[0].se, materials[1].se, materials[2].se), axis=0
)
m.mr = np.mean(
(materials[0].mr, materials[1].mr, materials[2].mr), axis=0
)
m.sm = np.mean(
(materials[0].sm, materials[1].sm, materials[2].sm), axis=0
)
# Append the new material object to the materials list
grid.materials.append(m)

查看文件

@@ -21,13 +21,14 @@ import logging
import numpy as np
import gprMax.config as config
from gprMax.cmds_geometry.cmds_geometry import (UserObjectGeometry,
rotate_2point_object)
from gprMax.cmds_geometry.cmds_geometry import UserObjectGeometry, rotate_2point_object
from gprMax.fractals import FractalVolume
from gprMax.materials import ListMaterial
from ..cython.geometry_primitives import (build_voxels_from_array,
build_voxels_from_array_mask)
from ..cython.geometry_primitives import (
build_voxels_from_array,
build_voxels_from_array_mask,
)
logger = logging.getLogger(__name__)
@@ -118,40 +119,59 @@ class FractalBox(UserObjectGeometry):
xf, yf, zf = p2
if frac_dim < 0:
logger.exception(f"{self.__str__()} requires a positive value for the fractal dimension")
logger.exception(
f"{self.__str__()} requires a positive value for the fractal dimension"
)
raise ValueError
if weighting[0] < 0:
logger.exception(f"{self.__str__()} requires a positive value for the fractal weighting in the x direction")
logger.exception(
f"{self.__str__()} requires a positive value for the fractal weighting in the x direction"
)
raise ValueError
if weighting[1] < 0:
logger.exception(f"{self.__str__()} requires a positive value for the fractal weighting in the y direction")
logger.exception(
f"{self.__str__()} requires a positive value for the fractal weighting in the y direction"
)
raise ValueError
if weighting[2] < 0:
logger.exception(f"{self.__str__()} requires a positive value for the fractal weighting in the z direction")
logger.exception(
f"{self.__str__()} requires a positive value for the fractal weighting in the z direction"
)
if n_materials < 0:
logger.exception(f"{self.__str__()} requires a positive value for the number of bins")
logger.exception(
f"{self.__str__()} requires a positive value for the number of bins"
)
raise ValueError
# Find materials to use to build fractal volume, either from mixing
# models or normal materials.
mixingmodel = next((x for x in grid.mixingmodels if x.ID == mixing_model_id), None)
mixingmodel = next(
(x for x in grid.mixingmodels if x.ID == mixing_model_id), None
)
material = next((x for x in grid.materials if x.ID == mixing_model_id), None)
nbins = n_materials
if mixingmodel:
if nbins == 1:
logger.exception(f"{self.__str__()} must be used with more than one material from the mixing model.")
logger.exception(
f"{self.__str__()} must be used with more than one material from the mixing model."
)
raise ValueError
if isinstance(mixingmodel, ListMaterial) and nbins > len(mixingmodel.mat):
logger.exception(
f"{self.__str__()} too many materials/bins " "requested compared to materials in " "mixing model."
f"{self.__str__()} too many materials/bins "
"requested compared to materials in "
"mixing model."
)
raise ValueError
# Create materials from mixing model as number of bins now known
# from fractal_box command.
mixingmodel.calculate_properties(nbins, grid)
elif not material:
logger.exception(f"{self.__str__()} mixing model or material with " + "ID {mixing_model_id} does not exist")
logger.exception(
f"{self.__str__()} mixing model or material with "
+ "ID {mixing_model_id} does not exist"
)
raise ValueError
self.volume = FractalVolume(xs, xf, ys, yf, zs, zf, frac_dim, seed)
@@ -223,7 +243,11 @@ class FractalBox(UserObjectGeometry):
(self.volume.nx, self.volume.ny, self.volume.nz),
dtype=config.sim_config.dtypes["float_or_double"],
)
materialnumID = next(x.numID for x in grid.materials if x.ID == self.volume.operatingonID)
materialnumID = next(
x.numID
for x in grid.materials
if x.ID == self.volume.operatingonID
)
self.volume.fractalvolume *= materialnumID
else:
self.volume.generate_fractal_volume()
@@ -231,7 +255,9 @@ class FractalBox(UserObjectGeometry):
for j in range(0, self.volume.ny):
for k in range(0, self.volume.nz):
numberinbin = self.volume.fractalvolume[i, j, k]
self.volume.fractalvolume[i, j, k] = self.volume.mixingmodel.matID[int(numberinbin)]
self.volume.fractalvolume[i, j, k] = (
self.volume.mixingmodel.matID[int(numberinbin)]
)
self.volume.generate_volume_mask()
@@ -240,32 +266,69 @@ class FractalBox(UserObjectGeometry):
# TODO: Allow extract of rough surface profile (to print/file?)
for surface in self.volume.fractalsurfaces:
if surface.surfaceID == "xminus":
for i in range(surface.fractalrange[0], surface.fractalrange[1]):
for i in range(
surface.fractalrange[0], surface.fractalrange[1]
):
for j in range(surface.ys, surface.yf):
for k in range(surface.zs, surface.zf):
if i > surface.fractalsurface[j - surface.ys, k - surface.zs]:
self.volume.mask[i - self.volume.xs, j - self.volume.ys, k - self.volume.zs] = 1
elif surface.filldepth > 0 and i > surface.filldepth:
self.volume.mask[i - self.volume.xs, j - self.volume.ys, k - self.volume.zs] = 2
if (
i
> surface.fractalsurface[
j - surface.ys, k - surface.zs
]
):
self.volume.mask[
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 1
elif (
surface.filldepth > 0 and i > surface.filldepth
):
self.volume.mask[
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 2
else:
self.volume.mask[i - self.volume.xs, j - self.volume.ys, k - self.volume.zs] = 0
self.volume.mask[
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 0
elif surface.surfaceID == "xplus":
if not surface.ID:
for i in range(surface.fractalrange[0], surface.fractalrange[1]):
for i in range(
surface.fractalrange[0], surface.fractalrange[1]
):
for j in range(surface.ys, surface.yf):
for k in range(surface.zs, surface.zf):
if i < surface.fractalsurface[j - surface.ys, k - surface.zs]:
if (
i
< surface.fractalsurface[
j - surface.ys, k - surface.zs
]
):
self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 1
elif surface.filldepth > 0 and i < surface.filldepth:
elif (
surface.filldepth > 0
and i < surface.filldepth
):
self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 2
else:
self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 0
elif surface.ID == "grass":
g = surface.grass[0]
@@ -273,17 +336,31 @@ class FractalBox(UserObjectGeometry):
blade = 0
for j in range(surface.ys, surface.yf):
for k in range(surface.zs, surface.zf):
if surface.fractalsurface[j - surface.ys, k - surface.zs] > 0:
if (
surface.fractalsurface[
j - surface.ys, k - surface.zs
]
> 0
):
height = 0
for i in range(self.volume.xs, surface.fractalrange[1]):
for i in range(
self.volume.xs, surface.fractalrange[1]
):
if (
i < surface.fractalsurface[j - surface.ys, k - surface.zs]
i
< surface.fractalsurface[
j - surface.ys, k - surface.zs
]
and self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
]
!= 1
):
y, z = g.calculate_blade_geometry(blade, height)
y, z = g.calculate_blade_geometry(
blade, height
)
# Add y, z coordinates to existing location
yy = int(j - self.volume.ys + y)
zz = int(k - self.volume.zs + z)
@@ -297,7 +374,9 @@ class FractalBox(UserObjectGeometry):
):
break
else:
self.volume.mask[i - self.volume.xs, yy, zz] = 3
self.volume.mask[
i - self.volume.xs, yy, zz
] = 3
height += 1
blade += 1
@@ -305,7 +384,12 @@ class FractalBox(UserObjectGeometry):
root = 0
for j in range(surface.ys, surface.yf):
for k in range(surface.zs, surface.zf):
if surface.fractalsurface[j - surface.ys, k - surface.zs] > 0:
if (
surface.fractalsurface[
j - surface.ys, k - surface.zs
]
> 0
):
depth = 0
i = self.volume.xf - 1
while i > self.volume.xs:
@@ -313,15 +397,21 @@ class FractalBox(UserObjectGeometry):
i
> self.volume.originalxf
- (
surface.fractalsurface[j - surface.ys, k - surface.zs]
surface.fractalsurface[
j - surface.ys, k - surface.zs
]
- self.volume.originalxf
)
and self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
]
== 1
):
y, z = g.calculate_root_geometry(root, depth)
y, z = g.calculate_root_geometry(
root, depth
)
# Add y, z coordinates to existing location
yy = int(j - self.volume.ys + y)
zz = int(k - self.volume.zs + z)
@@ -335,38 +425,77 @@ class FractalBox(UserObjectGeometry):
):
break
else:
self.volume.mask[i - self.volume.xs, yy, zz] = 3
self.volume.mask[
i - self.volume.xs, yy, zz
] = 3
depth += 1
i -= 1
root += 1
elif surface.surfaceID == "yminus":
for i in range(surface.xs, surface.xf):
for j in range(surface.fractalrange[0], surface.fractalrange[1]):
for j in range(
surface.fractalrange[0], surface.fractalrange[1]
):
for k in range(surface.zs, surface.zf):
if j > surface.fractalsurface[i - surface.xs, k - surface.zs]:
self.volume.mask[i - self.volume.xs, j - self.volume.ys, k - self.volume.zs] = 1
elif surface.filldepth > 0 and j > surface.filldepth:
self.volume.mask[i - self.volume.xs, j - self.volume.ys, k - self.volume.zs] = 2
if (
j
> surface.fractalsurface[
i - surface.xs, k - surface.zs
]
):
self.volume.mask[
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 1
elif (
surface.filldepth > 0 and j > surface.filldepth
):
self.volume.mask[
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 2
else:
self.volume.mask[i - self.volume.xs, j - self.volume.ys, k - self.volume.zs] = 0
self.volume.mask[
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 0
elif surface.surfaceID == "yplus":
if not surface.ID:
for i in range(surface.xs, surface.xf):
for j in range(surface.fractalrange[0], surface.fractalrange[1]):
for j in range(
surface.fractalrange[0], surface.fractalrange[1]
):
for k in range(surface.zs, surface.zf):
if j < surface.fractalsurface[i - surface.xs, k - surface.zs]:
if (
j
< surface.fractalsurface[
i - surface.xs, k - surface.zs
]
):
self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 1
elif surface.filldepth > 0 and j < surface.filldepth:
elif (
surface.filldepth > 0
and j < surface.filldepth
):
self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 2
else:
self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 0
elif surface.ID == "grass":
g = surface.grass[0]
@@ -374,17 +503,31 @@ class FractalBox(UserObjectGeometry):
blade = 0
for i in range(surface.xs, surface.xf):
for k in range(surface.zs, surface.zf):
if surface.fractalsurface[i - surface.xs, k - surface.zs] > 0:
if (
surface.fractalsurface[
i - surface.xs, k - surface.zs
]
> 0
):
height = 0
for j in range(self.volume.ys, surface.fractalrange[1]):
for j in range(
self.volume.ys, surface.fractalrange[1]
):
if (
j < surface.fractalsurface[i - surface.xs, k - surface.zs]
j
< surface.fractalsurface[
i - surface.xs, k - surface.zs
]
and self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
]
!= 1
):
x, z = g.calculate_blade_geometry(blade, height)
x, z = g.calculate_blade_geometry(
blade, height
)
# Add x, z coordinates to existing location
xx = int(i - self.volume.xs + x)
zz = int(k - self.volume.zs + z)
@@ -398,7 +541,9 @@ class FractalBox(UserObjectGeometry):
):
break
else:
self.volume.mask[xx, j - self.volume.ys, zz] = 3
self.volume.mask[
xx, j - self.volume.ys, zz
] = 3
height += 1
blade += 1
@@ -406,7 +551,12 @@ class FractalBox(UserObjectGeometry):
root = 0
for i in range(surface.xs, surface.xf):
for k in range(surface.zs, surface.zf):
if surface.fractalsurface[i - surface.xs, k - surface.zs] > 0:
if (
surface.fractalsurface[
i - surface.xs, k - surface.zs
]
> 0
):
depth = 0
j = self.volume.yf - 1
while j > self.volume.ys:
@@ -414,15 +564,21 @@ class FractalBox(UserObjectGeometry):
j
> self.volume.originalyf
- (
surface.fractalsurface[i - surface.xs, k - surface.zs]
surface.fractalsurface[
i - surface.xs, k - surface.zs
]
- self.volume.originalyf
)
and self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
]
== 1
):
x, z = g.calculate_root_geometry(root, depth)
x, z = g.calculate_root_geometry(
root, depth
)
# Add x, z coordinates to existing location
xx = int(i - self.volume.xs + x)
zz = int(k - self.volume.zs + z)
@@ -436,7 +592,9 @@ class FractalBox(UserObjectGeometry):
):
break
else:
self.volume.mask[xx, j - self.volume.ys, zz] = 3
self.volume.mask[
xx, j - self.volume.ys, zz
] = 3
depth += 1
j -= 1
root += 1
@@ -444,30 +602,67 @@ class FractalBox(UserObjectGeometry):
elif surface.surfaceID == "zminus":
for i in range(surface.xs, surface.xf):
for j in range(surface.ys, surface.yf):
for k in range(surface.fractalrange[0], surface.fractalrange[1]):
if k > surface.fractalsurface[i - surface.xs, j - surface.ys]:
self.volume.mask[i - self.volume.xs, j - self.volume.ys, k - self.volume.zs] = 1
elif surface.filldepth > 0 and k > surface.filldepth:
self.volume.mask[i - self.volume.xs, j - self.volume.ys, k - self.volume.zs] = 2
for k in range(
surface.fractalrange[0], surface.fractalrange[1]
):
if (
k
> surface.fractalsurface[
i - surface.xs, j - surface.ys
]
):
self.volume.mask[
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 1
elif (
surface.filldepth > 0 and k > surface.filldepth
):
self.volume.mask[
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 2
else:
self.volume.mask[i - self.volume.xs, j - self.volume.ys, k - self.volume.zs] = 0
self.volume.mask[
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 0
elif surface.surfaceID == "zplus":
if not surface.ID:
for i in range(surface.xs, surface.xf):
for j in range(surface.ys, surface.yf):
for k in range(surface.fractalrange[0], surface.fractalrange[1]):
if k < surface.fractalsurface[i - surface.xs, j - surface.ys]:
for k in range(
surface.fractalrange[0], surface.fractalrange[1]
):
if (
k
< surface.fractalsurface[
i - surface.xs, j - surface.ys
]
):
self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 1
elif surface.filldepth > 0 and k < surface.filldepth:
elif (
surface.filldepth > 0
and k < surface.filldepth
):
self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 2
else:
self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
] = 0
elif surface.ID == "grass":
g = surface.grass[0]
@@ -475,17 +670,31 @@ class FractalBox(UserObjectGeometry):
blade = 0
for i in range(surface.xs, surface.xf):
for j in range(surface.ys, surface.yf):
if surface.fractalsurface[i - surface.xs, j - surface.ys] > 0:
if (
surface.fractalsurface[
i - surface.xs, j - surface.ys
]
> 0
):
height = 0
for k in range(self.volume.zs, surface.fractalrange[1]):
for k in range(
self.volume.zs, surface.fractalrange[1]
):
if (
k < surface.fractalsurface[i - surface.xs, j - surface.ys]
k
< surface.fractalsurface[
i - surface.xs, j - surface.ys
]
and self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
]
!= 1
):
x, y = g.calculate_blade_geometry(blade, height)
x, y = g.calculate_blade_geometry(
blade, height
)
# Add x, y coordinates to existing location
xx = int(i - self.volume.xs + x)
yy = int(j - self.volume.ys + y)
@@ -499,7 +708,9 @@ class FractalBox(UserObjectGeometry):
):
break
else:
self.volume.mask[xx, yy, k - self.volume.zs] = 3
self.volume.mask[
xx, yy, k - self.volume.zs
] = 3
height += 1
blade += 1
@@ -507,7 +718,12 @@ class FractalBox(UserObjectGeometry):
root = 0
for i in range(surface.xs, surface.xf):
for j in range(surface.ys, surface.yf):
if surface.fractalsurface[i - surface.xs, j - surface.ys] > 0:
if (
surface.fractalsurface[
i - surface.xs, j - surface.ys
]
> 0
):
depth = 0
k = self.volume.zf - 1
while k > self.volume.zs:
@@ -515,15 +731,21 @@ class FractalBox(UserObjectGeometry):
k
> self.volume.originalzf
- (
surface.fractalsurface[i - surface.xs, j - surface.ys]
surface.fractalsurface[
i - surface.xs, j - surface.ys
]
- self.volume.originalzf
)
and self.volume.mask[
i - self.volume.xs, j - self.volume.ys, k - self.volume.zs
i - self.volume.xs,
j - self.volume.ys,
k - self.volume.zs,
]
== 1
):
x, y = g.calculate_root_geometry(root, depth)
x, y = g.calculate_root_geometry(
root, depth
)
# Add x, y coordinates to existing location
xx = int(i - self.volume.xs + x)
yy = int(j - self.volume.ys + y)
@@ -537,14 +759,20 @@ class FractalBox(UserObjectGeometry):
):
break
else:
self.volume.mask[xx, yy, k - self.volume.zs] = 3
self.volume.mask[
xx, yy, k - self.volume.zs
] = 3
depth += 1
k -= 1
root += 1
# Build voxels from any true values of the 3D mask array
waternumID = next((x.numID for x in grid.materials if x.ID == "water"), 0)
grassnumID = next((x.numID for x in grid.materials if x.ID == "grass"), 0)
waternumID = next(
(x.numID for x in grid.materials if x.ID == "water"), 0
)
grassnumID = next(
(x.numID for x in grid.materials if x.ID == "grass"), 0
)
data = self.volume.fractalvolume.astype("int16", order="C")
mask = self.volume.mask.copy(order="C")
build_voxels_from_array_mask(
@@ -576,7 +804,9 @@ class FractalBox(UserObjectGeometry):
for j in range(0, self.volume.ny):
for k in range(0, self.volume.nz):
numberinbin = self.volume.fractalvolume[i, j, k]
self.volume.fractalvolume[i, j, k] = self.volume.mixingmodel.matID[int(numberinbin)]
self.volume.fractalvolume[i, j, k] = (
self.volume.mixingmodel.matID[int(numberinbin)]
)
data = self.volume.fractalvolume.astype("int16", order="C")
build_voxels_from_array(

查看文件

@@ -71,7 +71,11 @@ class GeometryObjectsRead(UserObjectGeometry):
materials = [
line.rstrip() + "{" + matstr + "}\n"
for line in f
if (line.startswith("#") and not line.startswith("##") and line.rstrip("\n"))
if (
line.startswith("#")
and not line.startswith("##")
and line.rstrip("\n")
)
]
# Build scene
@@ -126,12 +130,26 @@ class GeometryObjectsRead(UserObjectGeometry):
rigidE = f["/rigidE"][:]
rigidH = f["/rigidH"][:]
ID = f["/ID"][:]
grid.solid[xs : xs + data.shape[0], ys : ys + data.shape[1], zs : zs + data.shape[2]] = (
data + numexistmaterials
)
grid.rigidE[:, xs : xs + rigidE.shape[1], ys : ys + rigidE.shape[2], zs : zs + rigidE.shape[3]] = rigidE
grid.rigidH[:, xs : xs + rigidH.shape[1], ys : ys + rigidH.shape[2], zs : zs + rigidH.shape[3]] = rigidH
grid.ID[:, xs : xs + ID.shape[1], ys : ys + ID.shape[2], zs : zs + ID.shape[3]] = ID + numexistmaterials
grid.solid[
xs : xs + data.shape[0],
ys : ys + data.shape[1],
zs : zs + data.shape[2],
] = data + numexistmaterials
grid.rigidE[
:,
xs : xs + rigidE.shape[1],
ys : ys + rigidE.shape[2],
zs : zs + rigidE.shape[3],
] = rigidE
grid.rigidH[
:,
xs : xs + rigidH.shape[1],
ys : ys + rigidH.shape[2],
zs : zs + rigidH.shape[3],
] = rigidH
grid.ID[
:, xs : xs + ID.shape[1], ys : ys + ID.shape[2], zs : zs + ID.shape[3]
] = ID + numexistmaterials
logger.info(
f"{self.grid_name(grid)}Geometry objects from file {geofile} "
f"inserted at {xs * grid.dx:g}m, {ys * grid.dy:g}m, "

查看文件

@@ -20,8 +20,7 @@ import logging
import numpy as np
from ..cython.geometry_primitives import (build_face_xy, build_face_xz,
build_face_yz)
from ..cython.geometry_primitives import build_face_xy, build_face_xz, build_face_yz
from .cmds_geometry import UserObjectGeometry, rotate_2point_object
logger = logging.getLogger(__name__)
@@ -115,7 +114,9 @@ class Plate(UserObjectGeometry):
for j in range(ys, yf):
for k in range(zs, zf):
build_face_yz(xs, j, k, numIDy, numIDz, grid.rigidE, grid.rigidH, grid.ID)
build_face_yz(
xs, j, k, numIDy, numIDz, grid.rigidE, grid.rigidH, grid.ID
)
# xz-plane plate
elif ys == yf:
@@ -130,7 +131,9 @@ class Plate(UserObjectGeometry):
for i in range(xs, xf):
for k in range(zs, zf):
build_face_xz(i, ys, k, numIDx, numIDz, grid.rigidE, grid.rigidH, grid.ID)
build_face_xz(
i, ys, k, numIDx, numIDz, grid.rigidE, grid.rigidH, grid.ID
)
# xy-plane plate
elif zs == zf:
@@ -145,7 +148,9 @@ class Plate(UserObjectGeometry):
for i in range(xs, xf):
for j in range(ys, yf):
build_face_xy(i, j, zs, numIDx, numIDy, grid.rigidE, grid.rigidH, grid.ID)
build_face_xy(
i, j, zs, numIDx, numIDy, grid.rigidE, grid.rigidH, grid.ID
)
logger.info(
f"{self.grid_name(grid)}Plate from {p3[0]:g}m, {p3[1]:g}m, "

查看文件

@@ -104,10 +104,18 @@ class Sphere(UserObjectGeometry):
m = Material(numID, requiredID)
m.type = "dielectric-smoothed"
# Create dielectric-smoothed constituents for material
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
m.sm = np.mean((materials[0].sm, materials[1].sm, materials[2].sm), axis=0)
m.er = np.mean(
(materials[0].er, materials[1].er, materials[2].er), axis=0
)
m.se = np.mean(
(materials[0].se, materials[1].se, materials[2].se), axis=0
)
m.mr = np.mean(
(materials[0].mr, materials[1].mr, materials[2].mr), axis=0
)
m.sm = np.mean(
(materials[0].sm, materials[1].sm, materials[2].sm), axis=0
)
# Append the new material object to the materials list
grid.materials.append(m)

查看文件

@@ -109,7 +109,9 @@ class Triangle(UserObjectGeometry):
x3, y3, z3 = uip.round_to_grid(up3)
if thickness < 0:
logger.exception(f"{self.__str__()} requires a positive value for thickness")
logger.exception(
f"{self.__str__()} requires a positive value for thickness"
)
raise ValueError
# Check for valid orientations
@@ -123,7 +125,9 @@ class Triangle(UserObjectGeometry):
elif z1 == z2 == z3:
normal = "z"
else:
logger.exception(f"{self.__str__()} the triangle is not specified correctly")
logger.exception(
f"{self.__str__()} the triangle is not specified correctly"
)
raise ValueError
# Look up requested materials in existing list of material instances
@@ -146,7 +150,9 @@ class Triangle(UserObjectGeometry):
numIDx = materials[0].numID
numIDy = materials[1].numID
numIDz = materials[2].numID
requiredID = materials[0].ID + "+" + materials[1].ID + "+" + materials[2].ID
requiredID = (
materials[0].ID + "+" + materials[1].ID + "+" + materials[2].ID
)
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
if averagedmaterial:
numID = averagedmaterial.numID
@@ -155,10 +161,18 @@ class Triangle(UserObjectGeometry):
m = Material(numID, requiredID)
m.type = "dielectric-smoothed"
# Create dielectric-smoothed constituents for material
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
m.sm = np.mean((materials[0].sm, materials[1].sm, materials[2].sm), axis=0)
m.er = np.mean(
(materials[0].er, materials[1].er, materials[2].er), axis=0
)
m.se = np.mean(
(materials[0].se, materials[1].se, materials[2].se), axis=0
)
m.mr = np.mean(
(materials[0].mr, materials[1].mr, materials[2].mr), axis=0
)
m.sm = np.mean(
(materials[0].sm, materials[1].sm, materials[2].sm), axis=0
)
# Append the new material object to the materials list
grid.materials.append(m)

查看文件

@@ -25,9 +25,11 @@ from scipy import interpolate
import gprMax.config as config
from .cmds_geometry.cmds_geometry import (UserObjectGeometry,
rotate_2point_object,
rotate_polarisation)
from .cmds_geometry.cmds_geometry import (
UserObjectGeometry,
rotate_2point_object,
rotate_polarisation,
)
from .geometry_outputs import GeometryObjects as GeometryObjectsUser
from .materials import DispersiveMaterial as DispersiveMaterialUser
from .materials import ListMaterial as ListMaterialUser
@@ -118,16 +120,22 @@ class ExcitationFile(UserObjectMulti):
try:
excitationfile = self.kwargs["filepath"]
fullargspec = inspect.getfullargspec(interpolate.interp1d)
kwargs = dict(zip(reversed(fullargspec.args), reversed(fullargspec.defaults)))
kwargs = dict(
zip(reversed(fullargspec.args), reversed(fullargspec.defaults))
)
except KeyError:
logger.exception(f"{self.__str__()} requires either one or three parameter(s)")
logger.exception(
f"{self.__str__()} requires either one or three parameter(s)"
)
raise
# See if file exists at specified path and if not try input file directory
excitationfile = Path(excitationfile)
# excitationfile = excitationfile.resolve()
if not excitationfile.exists():
excitationfile = Path(config.sim_config.input_file_path.parent, excitationfile)
excitationfile = Path(
config.sim_config.input_file_path.parent, excitationfile
)
logger.info(self.grid_name(grid) + f"Excitation file: {excitationfile}")
@@ -135,7 +143,11 @@ class ExcitationFile(UserObjectMulti):
waveformIDs = np.loadtxt(excitationfile, max_rows=1, dtype=str)
# Read all waveform values into an array
waveformvalues = np.loadtxt(excitationfile, skiprows=1, dtype=config.sim_config.dtypes["float_or_double"])
waveformvalues = np.loadtxt(
excitationfile,
skiprows=1,
dtype=config.sim_config.dtypes["float_or_double"],
)
# Time array (if specified) for interpolation, otherwise use simulation time
if waveformIDs[0].lower() == "time":
@@ -156,7 +168,11 @@ class ExcitationFile(UserObjectMulti):
w.type = "user"
# Select correct column of waveform values depending on array shape
singlewaveformvalues = waveformvalues[:] if len(waveformvalues.shape) == 1 else waveformvalues[:, i]
singlewaveformvalues = (
waveformvalues[:]
if len(waveformvalues.shape) == 1
else waveformvalues[:, i]
)
# Truncate waveform array if it is longer than time array
if len(singlewaveformvalues) > len(waveformtime):
@@ -171,10 +187,13 @@ class ExcitationFile(UserObjectMulti):
)
# Interpolate waveform values
w.userfunc = interpolate.interp1d(waveformtime, singlewaveformvalues, **kwargs)
w.userfunc = interpolate.interp1d(
waveformtime, singlewaveformvalues, **kwargs
)
logger.info(
self.grid_name(grid) + f"User waveform {w.ID} created using {timestr} and, if "
self.grid_name(grid)
+ f"User waveform {w.ID} created using {timestr} and, if "
f"required, interpolation parameters (kind: {kwargs['kind']}, "
f"fill value: {kwargs['fill_value']})."
)
@@ -222,15 +241,19 @@ class Waveform(UserObjectMulti):
freq = self.kwargs["freq"]
ID = self.kwargs["id"]
except KeyError:
logger.exception(self.params_str() + (" builtin waveforms " "require exactly four parameters."))
logger.exception(
self.params_str()
+ (" builtin waveforms require exactly four parameters.")
)
raise
if freq <= 0:
logger.exception(
self.params_str() + (" requires an excitation " "frequency value of greater than zero.")
self.params_str()
+ (" requires an excitation frequency value of greater than zero.")
)
raise ValueError
if any(x.ID == ID for x in grid.waveforms):
logger.exception(self.params_str() + (f" with ID {ID} already " "exists."))
logger.exception(self.params_str() + (f" with ID {ID} already exists."))
raise ValueError
w = WaveformUser()
@@ -253,9 +276,14 @@ class Waveform(UserObjectMulti):
uservalues = self.kwargs["user_values"]
ID = self.kwargs["id"]
fullargspec = inspect.getfullargspec(interpolate.interp1d)
kwargs = dict(zip(reversed(fullargspec.args), reversed(fullargspec.defaults)))
kwargs = dict(
zip(reversed(fullargspec.args), reversed(fullargspec.defaults))
)
except KeyError:
logger.exception(self.params_str() + (" a user-defined " "waveform requires at least two parameters."))
logger.exception(
self.params_str()
+ (" a user-defined waveform requires at least two parameters.")
)
raise
if "user_time" in self.kwargs:
@@ -270,7 +298,7 @@ class Waveform(UserObjectMulti):
kwargs["fill_value"] = self.kwargs["fill_value"]
if any(x.ID == ID for x in grid.waveforms):
logger.exception(self.params_str() + (f" with ID {ID} already " "exists."))
logger.exception(self.params_str() + (f" with ID {ID} already exists."))
raise ValueError
w = WaveformUser()
@@ -278,7 +306,10 @@ class Waveform(UserObjectMulti):
w.type = wavetype
w.userfunc = interpolate.interp1d(waveformtime, uservalues, **kwargs)
logger.info(self.grid_name(grid) + (f"Waveform {w.ID} that is " "user-defined created."))
logger.info(
self.grid_name(grid)
+ (f"Waveform {w.ID} that is user-defined created.")
)
grid.waveforms.append(w)
@@ -323,7 +354,7 @@ class VoltageSource(UserObjectMulti):
resistance = self.kwargs["resistance"]
waveform_id = self.kwargs["waveform_id"]
except KeyError:
logger.exception(self.params_str() + (" requires at least six " "parameters."))
logger.exception(self.params_str() + (" requires at least six parameters."))
raise
if self.do_rotate:
@@ -331,37 +362,49 @@ class VoltageSource(UserObjectMulti):
# Check polarity & position parameters
if polarisation not in ("x", "y", "z"):
logger.exception(self.params_str() + (" polarisation must be " "x, y, or z."))
logger.exception(self.params_str() + (" polarisation must be x, y, or z."))
raise ValueError
if "2D TMx" in config.get_model_config().mode and polarisation in [
"y",
"z",
]:
logger.exception(self.params_str() + (" polarisation must be x in " "2D TMx mode."))
logger.exception(
self.params_str() + (" polarisation must be x in 2D TMx mode.")
)
raise ValueError
elif "2D TMy" in config.get_model_config().mode and polarisation in [
"x",
"z",
]:
logger.exception(self.params_str() + (" polarisation must be y in " "2D TMy mode."))
logger.exception(
self.params_str() + (" polarisation must be y in 2D TMy mode.")
)
raise ValueError
elif "2D TMz" in config.get_model_config().mode and polarisation in [
"x",
"y",
]:
logger.exception(self.params_str() + (" polarisation must be z in " "2D TMz mode."))
logger.exception(
self.params_str() + (" polarisation must be z in 2D TMz mode.")
)
raise ValueError
xcoord, ycoord, zcoord = uip.check_src_rx_point(p1, self.params_str())
p2 = uip.round_to_grid_static_point(p1)
if resistance < 0:
logger.exception(self.params_str() + (" requires a source " "resistance of zero " "or greater."))
logger.exception(
self.params_str()
+ (" requires a source resistance of zero or greater.")
)
raise ValueError
# Check if there is a waveformID in the waveforms list
if not any(x.ID == waveform_id for x in grid.waveforms):
logger.exception(self.params_str() + (" there is no waveform with " "the identifier {waveform_id}."))
logger.exception(
self.params_str()
+ (" there is no waveform with the identifier {waveform_id}.")
)
raise ValueError
v = VoltageSourceUser()
@@ -369,7 +412,16 @@ class VoltageSource(UserObjectMulti):
v.xcoord = xcoord
v.ycoord = ycoord
v.zcoord = zcoord
v.ID = v.__class__.__name__ + "(" + str(v.xcoord) + "," + str(v.ycoord) + "," + str(v.zcoord) + ")"
v.ID = (
v.__class__.__name__
+ "("
+ str(v.xcoord)
+ ","
+ str(v.ycoord)
+ ","
+ str(v.zcoord)
+ ")"
)
v.resistance = resistance
v.waveformID = waveform_id
@@ -379,14 +431,25 @@ class VoltageSource(UserObjectMulti):
# Check source start & source remove time parameters
if start < 0:
logger.exception(
self.params_str() + (" delay of the initiation " "of the source should not " "be less than zero.")
self.params_str()
+ (
" delay of the initiation "
"of the source should not "
"be less than zero."
)
)
raise ValueError
if stop < 0:
logger.exception(self.params_str() + (" time to remove the " "source should not be " "less than zero."))
logger.exception(
self.params_str()
+ (" time to remove the source should not be less than zero.")
)
raise ValueError
if stop - start <= 0:
logger.exception(self.params_str() + (" duration of the source " "should not be zero or " "less."))
logger.exception(
self.params_str()
+ (" duration of the source should not be zero or less.")
)
raise ValueError
v.start = start
v.stop = min(stop, grid.timewindow)
@@ -401,7 +464,9 @@ class VoltageSource(UserObjectMulti):
logger.info(
f"{self.grid_name(grid)}Voltage source with polarity "
f"{v.polarisation} at {p2[0]:g}m, {p2[1]:g}m, {p2[2]:g}m, "
f"resistance {v.resistance:.1f} Ohms," + startstop + f"using waveform {v.waveformID} created."
f"resistance {v.resistance:.1f} Ohms,"
+ startstop
+ f"using waveform {v.waveformID} created."
)
grid.voltagesources.append(v)
@@ -454,25 +519,31 @@ class HertzianDipole(UserObjectMulti):
# Check polarity & position parameters
if polarisation not in ("x", "y", "z"):
logger.exception(self.params_str() + (" polarisation must be " "x, y, or z."))
logger.exception(self.params_str() + (" polarisation must be x, y, or z."))
raise ValueError
if "2D TMx" in config.get_model_config().mode and polarisation in [
"y",
"z",
]:
logger.exception(self.params_str() + (" polarisation must be x in " "2D TMx mode."))
logger.exception(
self.params_str() + (" polarisation must be x in 2D TMx mode.")
)
raise ValueError
elif "2D TMy" in config.get_model_config().mode and polarisation in [
"x",
"z",
]:
logger.exception(self.params_str() + (" polarisation must be y in " "2D TMy mode."))
logger.exception(
self.params_str() + (" polarisation must be y in 2D TMy mode.")
)
raise ValueError
elif "2D TMz" in config.get_model_config().mode and polarisation in [
"x",
"y",
]:
logger.exception(self.params_str() + (" polarisation must be z in " "2D TMz mode."))
logger.exception(
self.params_str() + (" polarisation must be z in 2D TMz mode.")
)
raise ValueError
xcoord, ycoord, zcoord = uip.check_src_rx_point(p1, self.params_str())
@@ -480,7 +551,9 @@ class HertzianDipole(UserObjectMulti):
# Check if there is a waveformID in the waveforms list
if not any(x.ID == waveform_id for x in grid.waveforms):
logger.exception(f"{self.params_str()} there is no waveform with the identifier {waveform_id}.")
logger.exception(
f"{self.params_str()} there is no waveform with the identifier {waveform_id}."
)
raise ValueError
h = HertzianDipoleUser()
@@ -500,7 +573,9 @@ class HertzianDipole(UserObjectMulti):
h.xcoordorigin = xcoord
h.ycoordorigin = ycoord
h.zcoordorigin = zcoord
h.ID = f"{h.__class__.__name__}({str(h.xcoord)},{str(h.ycoord)},{str(h.zcoord)})"
h.ID = (
f"{h.__class__.__name__}({str(h.xcoord)},{str(h.ycoord)},{str(h.zcoord)})"
)
h.waveformID = waveform_id
try:
@@ -513,10 +588,14 @@ class HertzianDipole(UserObjectMulti):
)
raise ValueError
if stop < 0:
logger.exception(f"{self.params_str()} time to remove the source should not be less than zero.")
logger.exception(
f"{self.params_str()} time to remove the source should not be less than zero."
)
raise ValueError
if stop - start <= 0:
logger.exception(f"{self.params_str()} duration of the source should not be zero or less.")
logger.exception(
f"{self.params_str()} duration of the source should not be zero or less."
)
raise ValueError
h.start = start
h.stop = min(stop, grid.timewindow)
@@ -595,25 +674,31 @@ class MagneticDipole(UserObjectMulti):
# Check polarity & position parameters
if polarisation not in ("x", "y", "z"):
logger.exception(self.params_str() + (" polarisation must be " "x, y, or z."))
logger.exception(self.params_str() + (" polarisation must be x, y, or z."))
raise ValueError
if "2D TMx" in config.get_model_config().mode and polarisation in [
"y",
"z",
]:
logger.exception(self.params_str() + (" polarisation must be x in " "2D TMx mode."))
logger.exception(
self.params_str() + (" polarisation must be x in 2D TMx mode.")
)
raise ValueError
elif "2D TMy" in config.get_model_config().mode and polarisation in [
"x",
"z",
]:
logger.exception(self.params_str() + (" polarisation must be y in " "2D TMy mode."))
logger.exception(
self.params_str() + (" polarisation must be y in 2D TMy mode.")
)
raise ValueError
elif "2D TMz" in config.get_model_config().mode and polarisation in [
"x",
"y",
]:
logger.exception(self.params_str() + (" polarisation must be z in " "2D TMz mode."))
logger.exception(
self.params_str() + (" polarisation must be z in 2D TMz mode.")
)
raise ValueError
xcoord, ycoord, zcoord = uip.check_src_rx_point(p1, self.params_str())
@@ -621,7 +706,9 @@ class MagneticDipole(UserObjectMulti):
# Check if there is a waveformID in the waveforms list
if not any(x.ID == waveform_id for x in grid.waveforms):
logger.exception(f"{self.params_str()} there is no waveform with the identifier {waveform_id}.")
logger.exception(
f"{self.params_str()} there is no waveform with the identifier {waveform_id}."
)
raise ValueError
m = MagneticDipoleUser()
@@ -632,7 +719,16 @@ class MagneticDipole(UserObjectMulti):
m.xcoordorigin = xcoord
m.ycoordorigin = ycoord
m.zcoordorigin = zcoord
m.ID = m.__class__.__name__ + "(" + str(m.xcoord) + "," + str(m.ycoord) + "," + str(m.zcoord) + ")"
m.ID = (
m.__class__.__name__
+ "("
+ str(m.xcoord)
+ ","
+ str(m.ycoord)
+ ","
+ str(m.zcoord)
+ ")"
)
m.waveformID = waveform_id
try:
@@ -641,14 +737,25 @@ class MagneticDipole(UserObjectMulti):
stop = self.kwargs["stop"]
if start < 0:
logger.exception(
self.params_str() + (" delay of the initiation " "of the source should not " "be less than zero.")
self.params_str()
+ (
" delay of the initiation "
"of the source should not "
"be less than zero."
)
)
raise ValueError
if stop < 0:
logger.exception(self.params_str() + (" time to remove the " "source should not be " "less than zero."))
logger.exception(
self.params_str()
+ (" time to remove the source should not be less than zero.")
)
raise ValueError
if stop - start <= 0:
logger.exception(self.params_str() + (" duration of the source " "should not be zero or " "less."))
logger.exception(
self.params_str()
+ (" duration of the source should not be zero or less.")
)
raise ValueError
m.start = start
m.stop = min(stop, grid.timewindow)
@@ -728,25 +835,31 @@ class TransmissionLine(UserObjectMulti):
# Check polarity & position parameters
if polarisation not in ("x", "y", "z"):
logger.exception(self.params_str() + (" polarisation must be " "x, y, or z."))
logger.exception(self.params_str() + (" polarisation must be x, y, or z."))
raise ValueError
if "2D TMx" in config.get_model_config().mode and polarisation in [
"y",
"z",
]:
logger.exception(self.params_str() + (" polarisation must be x in " "2D TMx mode."))
logger.exception(
self.params_str() + (" polarisation must be x in 2D TMx mode.")
)
raise ValueError
elif "2D TMy" in config.get_model_config().mode and polarisation in [
"x",
"z",
]:
logger.exception(self.params_str() + (" polarisation must be y in " "2D TMy mode."))
logger.exception(
self.params_str() + (" polarisation must be y in 2D TMy mode.")
)
raise ValueError
elif "2D TMz" in config.get_model_config().mode and polarisation in [
"x",
"y",
]:
logger.exception(self.params_str() + (" polarisation must be z in " "2D TMz mode."))
logger.exception(
self.params_str() + (" polarisation must be z in 2D TMz mode.")
)
raise ValueError
xcoord, ycoord, zcoord = uip.check_src_rx_point(p1, self.params_str())
@@ -762,7 +875,9 @@ class TransmissionLine(UserObjectMulti):
# Check if there is a waveformID in the waveforms list
if not any(x.ID == waveform_id for x in grid.waveforms):
logger.exception(f"{self.params_str()} there is no waveform with the identifier {waveform_id}.")
logger.exception(
f"{self.params_str()} there is no waveform with the identifier {waveform_id}."
)
raise ValueError
t = TransmissionLineUser(grid)
@@ -770,7 +885,16 @@ class TransmissionLine(UserObjectMulti):
t.xcoord = xcoord
t.ycoord = ycoord
t.zcoord = zcoord
t.ID = t.__class__.__name__ + "(" + str(t.xcoord) + "," + str(t.ycoord) + "," + str(t.zcoord) + ")"
t.ID = (
t.__class__.__name__
+ "("
+ str(t.xcoord)
+ ","
+ str(t.ycoord)
+ ","
+ str(t.zcoord)
+ ")"
)
t.resistance = resistance
t.waveformID = waveform_id
@@ -780,14 +904,25 @@ class TransmissionLine(UserObjectMulti):
stop = self.kwargs["stop"]
if start < 0:
logger.exception(
self.params_str() + (" delay of the initiation " "of the source should not " "be less than zero.")
self.params_str()
+ (
" delay of the initiation "
"of the source should not "
"be less than zero."
)
)
raise ValueError
if stop < 0:
logger.exception(self.params_str() + (" time to remove the " "source should not be " "less than zero."))
logger.exception(
self.params_str()
+ (" time to remove the source should not be less than zero.")
)
raise ValueError
if stop - start <= 0:
logger.exception(self.params_str() + (" duration of the source " "should not be zero or " "less."))
logger.exception(
self.params_str()
+ (" duration of the source should not be zero or less.")
)
raise ValueError
t.start = start
t.stop = min(stop, grid.timewindow)
@@ -839,7 +974,11 @@ class Rx(UserObjectMulti):
def _do_rotate(self, grid):
"""Performs rotation."""
new_pt = (self.kwargs["p1"][0] + grid.dx, self.kwargs["p1"][1] + grid.dy, self.kwargs["p1"][2] + grid.dz)
new_pt = (
self.kwargs["p1"][0] + grid.dx,
self.kwargs["p1"][1] + grid.dy,
self.kwargs["p1"][2] + grid.dz,
)
pts = np.array([self.kwargs["p1"], new_pt])
rot_pts = rotate_2point_object(pts, self.axis, self.angle, self.origin)
self.kwargs["p1"] = tuple(rot_pts[0, :])
@@ -878,7 +1017,9 @@ class Rx(UserObjectMulti):
# If no ID or outputs are specified, use default
r.ID = f"{r.__class__.__name__}({str(r.xcoord)},{str(r.ycoord)},{str(r.zcoord)})"
for key in RxUser.defaultoutputs:
r.outputs[key] = np.zeros(grid.iterations, dtype=config.sim_config.dtypes["float_or_double"])
r.outputs[key] = np.zeros(
grid.iterations, dtype=config.sim_config.dtypes["float_or_double"]
)
else:
outputs.sort()
# Get allowable outputs
@@ -889,7 +1030,10 @@ class Rx(UserObjectMulti):
# Check and add field output names
for field in outputs:
if field in allowableoutputs:
r.outputs[field] = np.zeros(grid.iterations, dtype=config.sim_config.dtypes["float_or_double"])
r.outputs[field] = np.zeros(
grid.iterations,
dtype=config.sim_config.dtypes["float_or_double"],
)
else:
logger.exception(
f"{self.params_str()} contains an output "
@@ -940,10 +1084,14 @@ class RxArray(UserObjectMulti):
dx, dy, dz = uip.discretise_point(dl)
if xs > xf or ys > yf or zs > zf:
logger.exception(f"{self.params_str()} the lower coordinates should be less than the upper coordinates.")
logger.exception(
f"{self.params_str()} the lower coordinates should be less than the upper coordinates."
)
raise ValueError
if dx < 0 or dy < 0 or dz < 0:
logger.exception(f"{self.params_str()} the step size should not be less than zero.")
logger.exception(
f"{self.params_str()} the step size should not be less than zero."
)
raise ValueError
if dx < 1:
if dx == 0:
@@ -993,7 +1141,10 @@ class RxArray(UserObjectMulti):
p5 = uip.round_to_grid_static_point(p5)
r.ID = f"{r.__class__.__name__}({str(x)},{str(y)},{str(z)})"
for key in RxUser.defaultoutputs:
r.outputs[key] = np.zeros(grid.iterations, dtype=config.sim_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 {p5[0]:g}m, {p5[1]:g}m, "
f"{p5[2]:g}m with output component(s) "
@@ -1066,7 +1217,9 @@ class Snapshot(UserObjectMulti):
if time > 0:
iterations = round_value((time / grid.dt)) + 1
else:
logger.exception(f"{self.params_str()} time value must be greater than zero.")
logger.exception(
f"{self.params_str()} time value must be greater than zero."
)
raise ValueError
try:
@@ -1101,16 +1254,34 @@ class Snapshot(UserObjectMulti):
outputs = dict.fromkeys(SnapshotUser.allowableoutputs, True)
if dx < 0 or dy < 0 or dz < 0:
logger.exception(f"{self.params_str()} the step size should not be less than zero.")
logger.exception(
f"{self.params_str()} the step size should not be less than zero."
)
raise ValueError
if dx < 1 or dy < 1 or dz < 1:
logger.exception(f"{self.params_str()} the step size should not be less than the spatial discretisation.")
logger.exception(
f"{self.params_str()} the step size should not be less than the spatial discretisation."
)
raise ValueError
if iterations <= 0 or iterations > grid.iterations:
logger.exception(f"{self.params_str()} time value is not valid.")
raise ValueError
s = SnapshotUser(xs, ys, zs, xf, yf, zf, dx, dy, dz, iterations, filename, fileext=fileext, outputs=outputs)
s = SnapshotUser(
xs,
ys,
zs,
xf,
yf,
zf,
dx,
dy,
dz,
iterations,
filename,
fileext=fileext,
outputs=outputs,
)
logger.info(
f"Snapshot from {p3[0]:g}m, {p3[1]:g}m, {p3[2]:g}m, to "
@@ -1160,7 +1331,9 @@ class Material(UserObjectMulti):
if se != "inf":
se = float(se)
if se < 0:
logger.exception(f"{self.params_str()} requires a positive value for electric conductivity.")
logger.exception(
f"{self.params_str()} requires a positive value for electric conductivity."
)
raise ValueError
else:
se = float("inf")
@@ -1170,10 +1343,14 @@ class Material(UserObjectMulti):
)
raise ValueError
if sm < 0:
logger.exception(f"{self.params_str()} requires a positive value for magnetic loss.")
logger.exception(
f"{self.params_str()} requires a positive value for magnetic loss."
)
raise ValueError
if any(x.ID == material_id for x in grid.materials):
logger.exception(f"{self.params_str()} with ID {material_id} already exists")
logger.exception(
f"{self.params_str()} with ID {material_id} already exists"
)
raise ValueError
# Create a new instance of the Material class material
@@ -1227,7 +1404,9 @@ class AddDebyeDispersion(UserObjectMulti):
raise
if poles < 0:
logger.exception(f"{self.params_str()} requires a positive value for number of poles.")
logger.exception(
f"{self.params_str()} requires a positive value for number of poles."
)
raise ValueError
# Look up requested materials in existing list of material instances
@@ -1249,17 +1428,24 @@ class AddDebyeDispersion(UserObjectMulti):
disp_material.averagable = False
for i in range(poles):
if tau[i] > 0:
logger.debug("Not checking if relaxation times are " "greater than time-step.")
logger.debug(
"Not checking if relaxation times are greater than time-step."
)
disp_material.deltaer.append(er_delta[i])
disp_material.tau.append(tau[i])
else:
logger.exception(f"{self.params_str()} requires positive values for the permittivity difference.")
logger.exception(
f"{self.params_str()} requires positive values for the permittivity difference."
)
raise ValueError
if disp_material.poles > config.get_model_config().materials["maxpoles"]:
config.get_model_config().materials["maxpoles"] = disp_material.poles
# Replace original material with newly created DispersiveMaterial
grid.materials = [disp_material if mat.numID == material.numID else mat for mat in grid.materials]
grid.materials = [
disp_material if mat.numID == material.numID else mat
for mat in grid.materials
]
logger.info(
f"{self.grid_name(grid)}Debye disperion added to {disp_material.ID} "
@@ -1300,7 +1486,9 @@ class AddLorentzDispersion(UserObjectMulti):
raise
if poles < 0:
logger.exception(f"{self.params_str()} requires a positive value for number of poles.")
logger.exception(
f"{self.params_str()} requires a positive value for number of poles."
)
raise ValueError
# Look up requested materials in existing list of material instances
@@ -1338,7 +1526,10 @@ class AddLorentzDispersion(UserObjectMulti):
config.get_model_config().materials["maxpoles"] = disp_material.poles
# Replace original material with newly created DispersiveMaterial
grid.materials = [disp_material if mat.numID == material.numID else mat for mat in grid.materials]
grid.materials = [
disp_material if mat.numID == material.numID else mat
for mat in grid.materials
]
logger.info(
f"{self.grid_name(grid)}Lorentz disperion added to {disp_material.ID} "
@@ -1376,7 +1567,9 @@ class AddDrudeDispersion(UserObjectMulti):
raise
if poles < 0:
logger.exception(f"{self.params_str()} requires a positive value for number of poles.")
logger.exception(
f"{self.params_str()} requires a positive value for number of poles."
)
raise ValueError
# Look up requested materials in existing list of material instances
@@ -1384,7 +1577,9 @@ class AddDrudeDispersion(UserObjectMulti):
if len(materials) != len(material_ids):
notfound = [x for x in material_ids if x not in materials]
logger.exception(f"{self.params_str()} material(s) {notfound} do not exist.")
logger.exception(
f"{self.params_str()} material(s) {notfound} do not exist."
)
raise ValueError
for material in materials:
@@ -1412,7 +1607,10 @@ class AddDrudeDispersion(UserObjectMulti):
config.get_model_config().materials["maxpoles"] = disp_material.poles
# Replace original material with newly created DispersiveMaterial
grid.materials = [disp_material if mat.numID == material.numID else mat for mat in grid.materials]
grid.materials = [
disp_material if mat.numID == material.numID else mat
for mat in grid.materials
]
logger.info(
f"{self.grid_name(grid)}Drude disperion added to {disp_material.ID} "
@@ -1452,20 +1650,30 @@ class SoilPeplinski(UserObjectMulti):
water_fraction_upper = self.kwargs["water_fraction_upper"]
ID = self.kwargs["id"]
except KeyError:
logger.exception(f"{self.params_str()} requires at exactly seven parameters.")
logger.exception(
f"{self.params_str()} requires at exactly seven parameters."
)
raise
if sand_fraction < 0:
logger.exception(f"{self.params_str()} requires a positive value for the sand fraction.")
logger.exception(
f"{self.params_str()} requires a positive value for the sand fraction."
)
raise ValueError
if clay_fraction < 0:
logger.exception(f"{self.params_str()} requires a positive value for the clay fraction.")
logger.exception(
f"{self.params_str()} requires a positive value for the clay fraction."
)
raise ValueError
if bulk_density < 0:
logger.exception(f"{self.params_str()} requires a positive value for the bulk density.")
logger.exception(
f"{self.params_str()} requires a positive value for the bulk density."
)
raise ValueError
if sand_density < 0:
logger.exception(f"{self.params_str()} requires a positive value for the sand particle density.")
logger.exception(
f"{self.params_str()} requires a positive value for the sand particle density."
)
raise ValueError
if water_fraction_lower < 0:
logger.exception(
@@ -1486,7 +1694,12 @@ class SoilPeplinski(UserObjectMulti):
# Create a new instance of the Material class material
# (start index after pec & free_space)
s = PeplinskiSoilUser(
ID, sand_fraction, clay_fraction, bulk_density, sand_density, (water_fraction_lower, water_fraction_upper)
ID,
sand_fraction,
clay_fraction,
bulk_density,
sand_density,
(water_fraction_lower, water_fraction_upper),
)
logger.info(
@@ -1532,7 +1745,9 @@ class MaterialRange(UserObjectMulti):
ro_upper = self.kwargs["ro_upper"]
ID = self.kwargs["id"]
except KeyError:
logger.exception(f"{self.params_str()} requires at exactly nine parameters.")
logger.exception(
f"{self.params_str()} requires at exactly nine parameters."
)
raise
if er_lower < 1:
@@ -1548,10 +1763,14 @@ class MaterialRange(UserObjectMulti):
)
raise ValueError
if sigma_lower < 0:
logger.exception(f"{self.params_str()} requires a positive value for the lower limit of conductivity.")
logger.exception(
f"{self.params_str()} requires a positive value for the lower limit of conductivity."
)
raise ValueError
if ro_lower < 0:
logger.exception(f"{self.params_str()} requires a positive value for the lower range magnetic loss.")
logger.exception(
f"{self.params_str()} requires a positive value for the lower range magnetic loss."
)
raise ValueError
if er_upper < 1:
logger.exception(
@@ -1566,17 +1785,25 @@ class MaterialRange(UserObjectMulti):
)
raise ValueError
if sigma_upper < 0:
logger.exception(f"{self.params_str()} requires a positive value for the upper range of conductivity.")
logger.exception(
f"{self.params_str()} requires a positive value for the upper range of conductivity."
)
raise ValueError
if ro_upper < 0:
logger.exception(f"{self.params_str()} requires a positive value for the upper range of magnetic loss.")
logger.exception(
f"{self.params_str()} requires a positive value for the upper range of magnetic loss."
)
if any(x.ID == ID for x in grid.mixingmodels):
logger.exception(f"{self.params_str()} with ID {ID} already exists")
raise ValueError
s = RangeMaterialUser(
ID, (er_lower, er_upper), (sigma_lower, sigma_upper), (mr_lower, mr_upper), (ro_lower, ro_upper)
ID,
(er_lower, er_upper),
(sigma_lower, sigma_upper),
(mr_lower, mr_upper),
(ro_lower, ro_upper),
)
logger.info(
@@ -1616,7 +1843,9 @@ class MaterialList(UserObjectMulti):
s = ListMaterialUser(ID, list_of_materials)
logger.info(f"{self.grid_name(grid)}A list of materials used to create {s.ID} that includes {s.mat}, created")
logger.info(
f"{self.grid_name(grid)}A list of materials used to create {s.ID} that includes {s.mat}, created"
)
grid.mixingmodels.append(s)
@@ -1649,8 +1878,7 @@ class GeometryView(UserObjectMulti):
"""
if output_type == "n":
from .geometry_outputs import \
GeometryViewVoxels as GeometryViewUser
from .geometry_outputs import GeometryViewVoxels as GeometryViewUser
else:
from .geometry_outputs import GeometryViewLines as GeometryViewUser
@@ -1682,18 +1910,30 @@ class GeometryView(UserObjectMulti):
dx, dy, dz = uip.discretise_static_point(dl)
if dx < 0 or dy < 0 or dz < 0:
logger.exception(f"{self.params_str()} the step size should not be less than zero.")
logger.exception(
f"{self.params_str()} the step size should not be less than zero."
)
raise ValueError
if dx > grid.nx or dy > grid.ny or dz > grid.nz:
logger.exception(f"{self.params_str()} the step size should be less than the domain size.")
logger.exception(
f"{self.params_str()} the step size should be less than the domain size."
)
raise ValueError
if dx < 1 or dy < 1 or dz < 1:
logger.exception(f"{self.params_str()} the step size should not be less than the spatial discretisation.")
logger.exception(
f"{self.params_str()} the step size should not be less than the spatial discretisation."
)
raise ValueError
if output_type not in ["n", "f"]:
logger.exception(f"{self.params_str()} requires type to be either n (normal) or f (fine).")
logger.exception(
f"{self.params_str()} requires type to be either n (normal) or f (fine)."
)
raise ValueError
if output_type == "f" and (dx * grid.dx != grid.dx or dy * grid.dy != grid.dy or dz * grid.dz != grid.dz):
if output_type == "f" and (
dx * grid.dx != grid.dx
or dy * grid.dy != grid.dy
or dz * grid.dz != grid.dz
):
logger.exception(
f"{self.params_str()} requires the spatial "
"discretisation for the geometry view to be the "
@@ -1821,7 +2061,9 @@ class PMLCFS(UserObjectMulti):
or kappascalingdirection not in CFSParameter.scalingdirections
or sigmascalingdirection not in CFSParameter.scalingdirections
):
logger.exception(f"{self.params_str()} must have scaling type {','.join(CFSParameter.scalingdirections)}")
logger.exception(
f"{self.params_str()} must have scaling type {','.join(CFSParameter.scalingdirections)}"
)
raise ValueError
if (
float(alphamin) < 0
@@ -1830,7 +2072,9 @@ class PMLCFS(UserObjectMulti):
or float(kappamax) < 0
or float(sigmamin) < 0
):
logger.exception(f"{self.params_str()} minimum and maximum scaling values must be greater than zero.")
logger.exception(
f"{self.params_str()} minimum and maximum scaling values must be greater than zero."
)
raise ValueError
cfsalpha = CFSParameter()
@@ -1874,7 +2118,9 @@ class PMLCFS(UserObjectMulti):
grid.pmls["cfs"].append(cfs)
if len(grid.pmls["cfs"]) > 2:
logger.exception(f"{self.params_str()} can only be used up to two times, for up to a 2nd order PML.")
logger.exception(
f"{self.params_str()} can only be used up to two times, for up to a 2nd order PML."
)
raise ValueError

查看文件

@@ -95,17 +95,20 @@ class Discretisation(UserObjectSingle):
if G.dl[0] <= 0:
logger.exception(
f"{self.__str__()} discretisation requires the " f"x-direction spatial step to be greater than zero"
f"{self.__str__()} discretisation requires the "
f"x-direction spatial step to be greater than zero"
)
raise ValueError
if G.dl[1] <= 0:
logger.exception(
f"{self.__str__()} discretisation requires the " f"y-direction spatial step to be greater than zero"
f"{self.__str__()} discretisation requires the "
f"y-direction spatial step to be greater than zero"
)
raise ValueError
if G.dl[2] <= 0:
logger.exception(
f"{self.__str__()} discretisation requires the " f"z-direction spatial step to be greater than zero"
f"{self.__str__()} discretisation requires the "
f"z-direction spatial step to be greater than zero"
)
raise ValueError
@@ -131,7 +134,9 @@ class Domain(UserObjectSingle):
raise
if G.nx == 0 or G.ny == 0 or G.nz == 0:
logger.exception(f"{self.__str__()} requires at least one cell in " f"every dimension")
logger.exception(
f"{self.__str__()} requires at least one cell in every dimension"
)
raise ValueError
logger.info(
@@ -161,7 +166,10 @@ class Domain(UserObjectSingle):
# Sub-grids cannot be used with 2D models. There would typically be
# minimal performance benefit with sub-gridding and 2D models.
if "2D" in config.get_model_config().mode and config.sim_config.general["subgrid"]:
if (
"2D" in config.get_model_config().mode
and config.sim_config.general["subgrid"]
):
logger.exception("Sub-gridding cannot be used with 2D models")
raise ValueError
@@ -188,7 +196,8 @@ class TimeStepStabilityFactor(UserObjectSingle):
if f <= 0 or f > 1:
logger.exception(
f"{self.__str__()} requires the value of the time " f"step stability factor to be between zero and one"
f"{self.__str__()} requires the value of the time "
f"step stability factor to be between zero and one"
)
raise ValueError
@@ -227,7 +236,9 @@ class TimeWindow(UserObjectSingle):
G.timewindow = tmp
G.iterations = int(np.ceil(tmp / G.dt)) + 1
else:
logger.exception(self.__str__() + " must have a value greater than zero")
logger.exception(
self.__str__() + " must have a value greater than zero"
)
raise ValueError
except KeyError:
pass
@@ -261,7 +272,10 @@ class OMPThreads(UserObjectSingle):
)
raise
if n < 1:
logger.exception(f"{self.__str__()} requires the value to be an " f"integer not less than one")
logger.exception(
f"{self.__str__()} requires the value to be an "
f"integer not less than one"
)
raise ValueError
config.get_model_config().ompthreads = set_omp_threads(n)
@@ -290,7 +304,9 @@ class PMLProps(UserObjectSingle):
G.pmls["formulation"] = self.kwargs["formulation"]
if G.pmls["formulation"] not in PML.formulations:
logger.exception(
self.__str__() + f" requires the value to be " + f"one of {' '.join(PML.formulations)}"
self.__str__()
+ f" requires the value to be "
+ f"one of {' '.join(PML.formulations)}"
)
except KeyError:
pass
@@ -309,7 +325,9 @@ class PMLProps(UserObjectSingle):
G.pmls["thickness"]["ymax"] = int(self.kwargs["ymax"])
G.pmls["thickness"]["zmax"] = int(self.kwargs["zmax"])
except KeyError:
logger.exception(f"{self.__str__()} requires either one or six parameter(s)")
logger.exception(
f"{self.__str__()} requires either one or six parameter(s)"
)
raise
if (

查看文件

@@ -87,7 +87,11 @@ class ModelConfig:
except:
deviceID = 0
self.device = {"dev": sim_config.set_model_device(deviceID), "deviceID": deviceID, "snapsgpu2cpu": False}
self.device = {
"dev": sim_config.set_model_device(deviceID),
"deviceID": deviceID,
"snapsgpu2cpu": False,
}
# Total memory usage for all grids in the model. Starts with 50MB overhead.
self.mem_overhead = 65e6
@@ -96,11 +100,20 @@ class ModelConfig:
self.reuse_geometry = False
# String to print at start of each model run
s = f"\n--- Model {model_num + 1}/{sim_config.model_end}, " f"input file: {sim_config.input_file_path}"
self.inputfilestr = Fore.GREEN + f"{s} {'-' * (get_terminal_width() - 1 - len(s))}\n" + Style.RESET_ALL
s = (
f"\n--- Model {model_num + 1}/{sim_config.model_end}, "
f"input file: {sim_config.input_file_path}"
)
self.inputfilestr = (
Fore.GREEN
+ f"{s} {'-' * (get_terminal_width() - 1 - len(s))}\n"
+ Style.RESET_ALL
)
# Output file path and name for specific model
self.appendmodelnumber = "" if sim_config.args.n == 1 else str(model_num + 1) # Indexed from 1
self.appendmodelnumber = (
"" if sim_config.args.n == 1 else str(model_num + 1)
) # Indexed from 1
self.set_output_file_path()
# Numerical dispersion analysis parameters
@@ -111,7 +124,11 @@ class ModelConfig:
# phase-velocity phase error.
# mingridsampling: minimum grid sampling of smallest wavelength for
# physical wave propagation.
self.numdispersion = {"highestfreqthres": 40, "maxnumericaldisp": 2, "mingridsampling": 3}
self.numdispersion = {
"highestfreqthres": 40,
"maxnumericaldisp": 2,
"mingridsampling": 3,
}
# General information to configure materials
# maxpoles: Maximum number of dispersive material poles in a model.
@@ -221,7 +238,11 @@ class SimulationConfig:
# progressbars when logging level is greater than
# info (20)
self.general = {"solver": "cpu", "precision": "single", "progressbars": args.log_level <= 20}
self.general = {
"solver": "cpu",
"precision": "single",
"progressbars": args.log_level <= 20,
}
self.em_consts = {
"c": c, # Speed of light in free space (m/s)
@@ -239,7 +260,10 @@ class SimulationConfig:
# Both single and double precision are possible on GPUs, but single
# provides best performance.
self.general["precision"] = "single"
self.devices = {"devs": [], "nvcc_opts": None} # pycuda device objects; nvcc compiler options
self.devices = {
"devs": [],
"nvcc_opts": None,
} # pycuda device objects; nvcc compiler options
# Suppress nvcc warnings on Microsoft Windows
if sys.platform == "win32":
self.devices["nvcc_opts"] = ["-w"]
@@ -251,11 +275,14 @@ class SimulationConfig:
if self.args.opencl is not None:
self.general["solver"] = "opencl"
self.general["precision"] = "single"
self.devices = {"devs": [], "compiler_opts": None} # pyopencl device device(s); compiler options
self.devices = {
"devs": [],
"compiler_opts": None,
} # pyopencl device device(s); compiler options
# Suppress CompilerWarning (sub-class of UserWarning)
warnings.filterwarnings("ignore", category=UserWarning)
# Suppress unused variable warnings on gcc
# if sys.platform != 'win32': self.devices['compiler_opts'] = ['-w']
@@ -271,7 +298,8 @@ class SimulationConfig:
self.general["subgrid"] and self.general["solver"] == "opencl"
):
logger.exception(
"You cannot currently use CUDA or OpenCL-based " "solvers with models that contain sub-grids."
"You cannot currently use CUDA or OpenCL-based "
"solvers with models that contain sub-grids."
)
raise ValueError
else:
@@ -305,7 +333,9 @@ class SimulationConfig:
return dev
if not found:
logger.exception(f"Compute device with device ID {deviceID} does " "not exist.")
logger.exception(
f"Compute device with device ID {deviceID} does not exist."
)
raise ValueError
def _set_precision(self):

查看文件

@@ -31,8 +31,7 @@ import gprMax.config as config
from ._version import __version__, codename
from .model_build_run import ModelBuildRun
from .solvers import create_G, create_solver
from .utilities.host_info import (print_cuda_info, print_host_info,
print_opencl_info)
from .utilities.host_info import print_cuda_info, print_host_info, print_opencl_info
from .utilities.utilities import get_terminal_width, logo, timer
logger = logging.getLogger(__name__)
@@ -45,7 +44,9 @@ class Context:
"""
def __init__(self):
self.model_range = range(config.sim_config.model_start, config.sim_config.model_end)
self.model_range = range(
config.sim_config.model_start, config.sim_config.model_end
)
self.tsimend = None
self.tsimstart = None
@@ -64,7 +65,7 @@ class Context:
elif config.sim_config.general["solver"] == "opencl":
print_opencl_info(config.sim_config.devices["devs"])
# Clear list of model configs, which can be retained when gprMax is
# Clear list of model configs, which can be retained when gprMax is
# called in a loop, and want to avoid this.
config.model_configs = []
@@ -181,7 +182,11 @@ class MPIContext(Context):
print_opencl_info(config.sim_config.devices["devs"])
s = f"\n--- Input file: {config.sim_config.input_file_path}"
logger.basic(Fore.GREEN + f"{s} {'-' * (get_terminal_width() - 1 - len(s))}\n" + Style.RESET_ALL)
logger.basic(
Fore.GREEN
+ f"{s} {'-' * (get_terminal_width() - 1 - len(s))}\n"
+ Style.RESET_ALL
)
sys.stdout.flush()

查看文件

@@ -45,7 +45,9 @@ def store_outputs(G):
# Store current component
else:
func = globals()[output]
rx.outputs[output][iteration] = func(rx.xcoord, rx.ycoord, rx.zcoord, Hx, Hy, Hz, G)
rx.outputs[output][iteration] = func(
rx.xcoord, rx.ycoord, rx.zcoord, Hx, Hy, Hz, G
)
for tl in G.transmissionlines:
tl.Vtotal[iteration] = tl.voltage[tl.antpos]
@@ -92,7 +94,12 @@ def write_hd5_data(basegrp, grid, is_subgrid=False):
basegrp.attrs["nx_ny_nz"] = (grid.nx, grid.ny, grid.nz)
basegrp.attrs["dx_dy_dz"] = (grid.dx, grid.dy, grid.dz)
basegrp.attrs["dt"] = grid.dt
nsrc = len(grid.voltagesources + grid.hertziandipoles + grid.magneticdipoles + grid.transmissionlines)
nsrc = len(
grid.voltagesources
+ grid.hertziandipoles
+ grid.magneticdipoles
+ grid.transmissionlines
)
basegrp.attrs["nsrc"] = nsrc
basegrp.attrs["nrx"] = len(grid.rxs)
basegrp.attrs["srcsteps"] = grid.srcsteps
@@ -112,13 +119,21 @@ def write_hd5_data(basegrp, grid, is_subgrid=False):
for srcindex, src in enumerate(srclist):
grp = basegrp.create_group(f"srcs/src{str(srcindex + 1)}")
grp.attrs["Type"] = type(src).__name__
grp.attrs["Position"] = (src.xcoord * grid.dx, src.ycoord * grid.dy, src.zcoord * grid.dz)
grp.attrs["Position"] = (
src.xcoord * grid.dx,
src.ycoord * grid.dy,
src.zcoord * grid.dz,
)
# Create group for transmission lines; add positional data, line resistance and
# line discretisation attributes; write arrays for line voltages and currents
for tlindex, tl in enumerate(grid.transmissionlines):
grp = basegrp.create_group("tls/tl" + str(tlindex + 1))
grp.attrs["Position"] = (tl.xcoord * grid.dx, tl.ycoord * grid.dy, tl.zcoord * grid.dz)
grp.attrs["Position"] = (
tl.xcoord * grid.dx,
tl.ycoord * grid.dy,
tl.zcoord * grid.dz,
)
grp.attrs["Resistance"] = tl.resistance
grp.attrs["dl"] = tl.dl
# Save incident voltage and current
@@ -133,7 +148,11 @@ def write_hd5_data(basegrp, grid, is_subgrid=False):
grp = basegrp.create_group("rxs/rx" + str(rxindex + 1))
if rx.ID:
grp.attrs["Name"] = rx.ID
grp.attrs["Position"] = (rx.xcoord * grid.dx, rx.ycoord * grid.dy, rx.zcoord * grid.dz)
grp.attrs["Position"] = (
rx.xcoord * grid.dx,
rx.ycoord * grid.dy,
rx.zcoord * grid.dz,
)
for output in rx.outputs:
basegrp["rxs/rx" + str(rxindex + 1) + "/" + output] = rx.outputs[output]
@@ -151,7 +170,9 @@ def Ix(x, y, z, Hx, Hy, Hz, G):
if y == 0 or z == 0:
Ix = 0
else:
Ix = G.dy * (Hy[x, y, z - 1] - Hy[x, y, z]) + G.dz * (Hz[x, y, z] - Hz[x, y - 1, z])
Ix = G.dy * (Hy[x, y, z - 1] - Hy[x, y, z]) + G.dz * (
Hz[x, y, z] - Hz[x, y - 1, z]
)
return Ix
@@ -168,7 +189,9 @@ def Iy(x, y, z, Hx, Hy, Hz, G):
if x == 0 or z == 0:
Iy = 0
else:
Iy = G.dx * (Hx[x, y, z] - Hx[x, y, z - 1]) + G.dz * (Hz[x - 1, y, z] - Hz[x, y, z])
Iy = G.dx * (Hx[x, y, z] - Hx[x, y, z - 1]) + G.dz * (
Hz[x - 1, y, z] - Hz[x, y, z]
)
return Iy
@@ -185,6 +208,8 @@ def Iz(x, y, z, Hx, Hy, Hz, G):
if x == 0 or y == 0:
Iz = 0
else:
Iz = G.dx * (Hx[x, y - 1, z] - Hx[x, y, z]) + G.dy * (Hy[x, y, z] - Hy[x - 1, y, z])
Iz = G.dx * (Hx[x, y - 1, z] - Hx[x, y, z]) + G.dy * (
Hy[x, y, z] - Hy[x - 1, y, z]
)
return Iz

查看文件

@@ -56,7 +56,7 @@ class FractalSurface:
self.nz = zf - zs
self.dtype = np.dtype(np.complex128)
self.seed = seed
self.dimension = dimension # Fractal dimension from: http://dx.doi.org/10.1017/CBO9781139174695
self.dimension = dimension # Fractal dimension from: http://dx.doi.org/10.1017/CBO9781139174695
self.weighting = np.array([1, 1], dtype=np.float64)
self.fractalrange = (0, 0)
self.filldepth = 0
@@ -82,7 +82,12 @@ class FractalSurface:
self.fractalsurface = np.zeros(surfacedims, dtype=self.dtype)
# Positional vector at centre of array, scaled by weighting
v1 = np.array([self.weighting[0] * (surfacedims[0]) / 2, self.weighting[1] * (surfacedims[1]) / 2])
v1 = np.array(
[
self.weighting[0] * (surfacedims[0]) / 2,
self.weighting[1] * (surfacedims[1]) / 2,
]
)
# 2D array of random numbers to be convolved with the fractal function
rng = np.random.default_rng(seed=self.seed)
@@ -119,9 +124,11 @@ class FractalSurface:
fractalmax = np.amax(self.fractalsurface)
fractalrange = fractalmax - fractalmin
self.fractalsurface = (
self.fractalsurface * ((self.fractalrange[1] - self.fractalrange[0]) / fractalrange)
self.fractalsurface
* ((self.fractalrange[1] - self.fractalrange[0]) / fractalrange)
+ self.fractalrange[0]
- ((self.fractalrange[1] - self.fractalrange[0]) / fractalrange) * fractalmin
- ((self.fractalrange[1] - self.fractalrange[0]) / fractalrange)
* fractalmin
)
@@ -157,7 +164,7 @@ class FractalVolume:
self.averaging = False
self.dtype = np.dtype(np.complex128)
self.seed = seed
self.dimension = dimension # Fractal dimension from: http://dx.doi.org/10.1017/CBO9781139174695
self.dimension = dimension # Fractal dimension from: http://dx.doi.org/10.1017/CBO9781139174695
self.weighting = np.array([1, 1, 1], dtype=np.float64)
self.nbins = 0
self.fractalsurfaces = []
@@ -167,16 +174,24 @@ class FractalVolume:
# Scale filter according to size of fractal volume
if self.nx == 1:
filterscaling = np.amin(np.array([self.ny, self.nz])) / np.array([self.ny, self.nz])
filterscaling = np.amin(np.array([self.ny, self.nz])) / np.array(
[self.ny, self.nz]
)
filterscaling = np.insert(filterscaling, 0, 1)
elif self.ny == 1:
filterscaling = np.amin(np.array([self.nx, self.nz])) / np.array([self.nx, self.nz])
filterscaling = np.amin(np.array([self.nx, self.nz])) / np.array(
[self.nx, self.nz]
)
filterscaling = np.insert(filterscaling, 1, 1)
elif self.nz == 1:
filterscaling = np.amin(np.array([self.nx, self.ny])) / np.array([self.nx, self.ny])
filterscaling = np.amin(np.array([self.nx, self.ny])) / np.array(
[self.nx, self.ny]
)
filterscaling = np.insert(filterscaling, 2, 1)
else:
filterscaling = np.amin(np.array([self.nx, self.ny, self.nz])) / np.array([self.nx, self.ny, self.nz])
filterscaling = np.amin(np.array([self.nx, self.ny, self.nz])) / np.array(
[self.nx, self.ny, self.nz]
)
# Adjust weighting to account for filter scaling
self.weighting = np.multiply(self.weighting, filterscaling)
@@ -185,7 +200,11 @@ class FractalVolume:
# Positional vector at centre of array, scaled by weighting
v1 = np.array(
[self.weighting[0] * self.nx / 2, self.weighting[1] * self.ny / 2, self.weighting[2] * self.nz / 2]
[
self.weighting[0] * self.nx / 2,
self.weighting[1] * self.ny / 2,
self.weighting[2] * self.nz / 2,
]
)
# 3D array of random numbers to be convolved with the fractal function
@@ -222,10 +241,14 @@ class FractalVolume:
)
# Bin fractal values
bins = np.linspace(np.amin(self.fractalvolume), np.amax(self.fractalvolume), self.nbins)
bins = np.linspace(
np.amin(self.fractalvolume), np.amax(self.fractalvolume), self.nbins
)
for j in range(self.ny):
for k in range(self.nz):
self.fractalvolume[:, j, k] = np.digitize(self.fractalvolume[:, j, k], bins, right=True)
self.fractalvolume[:, j, k] = np.digitize(
self.fractalvolume[:, j, k], bins, right=True
)
def generate_volume_mask(self):
"""Generate a 3D volume to use as a mask for adding rough surfaces,
@@ -254,7 +277,9 @@ class Grass:
"""
self.numblades = numblades
self.geometryparams = np.zeros((self.numblades, 6), dtype=config.sim_config.dtypes["float_or_double"])
self.geometryparams = np.zeros(
(self.numblades, 6), dtype=config.sim_config.dtypes["float_or_double"]
)
self.seed = seed
self.set_geometry_parameters()

查看文件

@@ -52,7 +52,8 @@ def save_geometry_views(gvs):
total=gv.nbytes,
unit="byte",
unit_scale=True,
desc=f"Writing geometry view file {i + 1}/{len(gvs)}, " f"{gv.filename.name}{gv.vtkfiletype.ext}",
desc=f"Writing geometry view file {i + 1}/{len(gvs)}, "
f"{gv.filename.name}{gv.vtkfiletype.ext}",
ncols=get_terminal_width() - 1,
file=sys.stdout,
disable=not config.sim_config.general["progressbars"],
@@ -96,7 +97,9 @@ class GeometryView:
def set_filename(self):
"""Constructs filename from user-supplied name and model run number."""
parts = config.get_model_config().output_file_path.parts
self.filename = Path(*parts[:-1], self.filenamebase + config.get_model_config().appendmodelnumber)
self.filename = Path(
*parts[:-1], self.filenamebase + config.get_model_config().appendmodelnumber
)
class GeometryViewLines(GeometryView):
@@ -122,7 +125,12 @@ class GeometryViewLines(GeometryView):
):
# Require contiguous for evtk library
ID = np.ascontiguousarray(
self.grid.ID[:, self.xs : self.xf : self.dx, self.ys : self.yf : self.dy, self.zs : self.zf : self.dz]
self.grid.ID[
:,
self.xs : self.xf : self.dx,
self.ys : self.yf : self.dy,
self.zs : self.zf : self.dz,
]
)
else:
# This array is contiguous by design
@@ -158,7 +166,15 @@ class GeometryViewLines(GeometryView):
offsets_size = np.arange(start=2, step=2, stop=len(x) + 1, dtype="int32").nbytes
connect_size = len(x) * np.dtype("int32").itemsize
cell_type_size = len(x) * np.dtype("uint8").itemsize
self.nbytes = x.nbytes + y.nbytes + z.nbytes + lines.nbytes + offsets_size + connect_size + cell_type_size
self.nbytes = (
x.nbytes
+ y.nbytes
+ z.nbytes
+ lines.nbytes
+ offsets_size
+ connect_size
+ cell_type_size
)
vtk_data = {"x": x, "y": y, "z": z, "data": lines, "comments": comments}
@@ -205,7 +221,11 @@ class GeometryViewVoxels(GeometryView):
):
# Require contiguous for evtk library
solid = np.ascontiguousarray(
self.grid.solid[self.xs : self.xf : self.dx, self.ys : self.yf : self.dy, self.zs : self.zf : self.dz]
self.grid.solid[
self.xs : self.xf : self.dx,
self.ys : self.yf : self.dy,
self.zs : self.zf : self.dz,
]
)
else:
# This array is contiguous by design
@@ -236,13 +256,21 @@ class GeometryViewVoxels(GeometryView):
(self.grid.k0 * self.grid.dz * self.grid.ratio),
)
else:
origin = ((self.xs * self.grid.dx), (self.ys * self.grid.dy), (self.zs * self.grid.dz))
origin = (
(self.xs * self.grid.dx),
(self.ys * self.grid.dy),
(self.zs * self.grid.dz),
)
# Write the VTK file .vti
imageToVTK(
str(self.filename),
origin=origin,
spacing=((self.dx * self.grid.dx), (self.dy * self.grid.dy), (self.dz * self.grid.dz)),
spacing=(
(self.dx * self.grid.dx),
(self.dy * self.grid.dy),
(self.dz * self.grid.dz),
),
cellData={"Material": vtk_data["data"]},
comments=[vtk_data["comments"]],
)
@@ -304,11 +332,17 @@ class Comments:
if grid.pmls["thickness"]["z0"] - self.gv.zs > 0:
pmlstorender["z0"] = int(grid.pmls["thickness"]["z0"] - self.gv.zs)
if self.gv.xf > grid.nx - grid.pmls["thickness"]["xmax"]:
pmlstorender["xmax"] = int(self.gv.xf - (grid.nx - grid.pmls["thickness"]["xmax"]))
pmlstorender["xmax"] = int(
self.gv.xf - (grid.nx - grid.pmls["thickness"]["xmax"])
)
if self.gv.yf > grid.ny - grid.pmls["thickness"]["ymax"]:
pmlstorender["ymax"] = int(self.gv.yf - (grid.ny - grid.pmls["thickness"]["ymax"]))
pmlstorender["ymax"] = int(
self.gv.yf - (grid.ny - grid.pmls["thickness"]["ymax"])
)
if self.gv.zf > grid.nz - grid.pmls["thickness"]["zmax"]:
pmlstorender["zmax"] = int(self.gv.zf - (grid.nz - grid.pmls["thickness"]["zmax"]))
pmlstorender["zmax"] = int(
self.gv.zf - (grid.nz - grid.pmls["thickness"]["zmax"])
)
return list(pmlstorender.values())
@@ -316,7 +350,11 @@ class Comments:
"""Used to name sources and/or receivers."""
sc = []
for src in srcs:
p = (src.xcoord * self.grid.dx, src.ycoord * self.grid.dy, src.zcoord * self.grid.dz)
p = (
src.xcoord * self.grid.dx,
src.ycoord * self.grid.dy,
src.zcoord * self.grid.dz,
)
p = list(map(float, p))
s = {"name": src.ID, "position": p}
@@ -332,7 +370,9 @@ class Comments:
def materials_comment(self):
if not self.averaged_materials:
return [m.ID for m in self.grid.materials if m.type != "dielectric-smoothed"]
return [
m.ID for m in self.grid.materials if m.type != "dielectric-smoothed"
]
else:
return [m.ID for m in self.grid.materials]
@@ -340,7 +380,9 @@ class Comments:
class GeometryObjects:
"""Geometry objects to be written to file."""
def __init__(self, xs=None, ys=None, zs=None, xf=None, yf=None, zf=None, basefilename=None):
def __init__(
self, xs=None, ys=None, zs=None, xf=None, yf=None, zf=None, basefilename=None
):
"""
Args:
xs, xf, ys, yf, zs, zf: ints for extent of the volume in cells.
@@ -366,9 +408,23 @@ class GeometryObjects:
self.filename_materials = self.filename_materials.with_suffix(".txt")
# Sizes of arrays to write necessary to update progress bar
self.solidsize = (self.nx + 1) * (self.ny + 1) * (self.nz + 1) * np.dtype(np.uint32).itemsize
self.rigidsize = 18 * (self.nx + 1) * (self.ny + 1) * (self.nz + 1) * np.dtype(np.int8).itemsize
self.IDsize = 6 * (self.nx + 1) * (self.ny + 1) * (self.nz + 1) * np.dtype(np.uint32).itemsize
self.solidsize = (
(self.nx + 1) * (self.ny + 1) * (self.nz + 1) * np.dtype(np.uint32).itemsize
)
self.rigidsize = (
18
* (self.nx + 1)
* (self.ny + 1)
* (self.nz + 1)
* np.dtype(np.int8).itemsize
)
self.IDsize = (
6
* (self.nx + 1)
* (self.ny + 1)
* (self.nz + 1)
* np.dtype(np.uint32).itemsize
)
self.datawritesize = self.solidsize + self.rigidsize + self.IDsize
def write_hdf5(self, G, pbar):
@@ -385,16 +441,45 @@ class GeometryObjects:
fdata.attrs["dx_dy_dz"] = (G.dx, G.dy, G.dz)
# Get minimum and maximum integers of materials in geometry objects volume
minmat = np.amin(G.ID[:, self.xs : self.xf + 1, self.ys : self.yf + 1, self.zs : self.zf + 1])
maxmat = np.amax(G.ID[:, self.xs : self.xf + 1, self.ys : self.yf + 1, self.zs : self.zf + 1])
minmat = np.amin(
G.ID[
:,
self.xs : self.xf + 1,
self.ys : self.yf + 1,
self.zs : self.zf + 1,
]
)
maxmat = np.amax(
G.ID[
:,
self.xs : self.xf + 1,
self.ys : self.yf + 1,
self.zs : self.zf + 1,
]
)
fdata["/data"] = (
G.solid[self.xs : self.xf + 1, self.ys : self.yf + 1, self.zs : self.zf + 1].astype("int16") - minmat
G.solid[
self.xs : self.xf + 1, self.ys : self.yf + 1, self.zs : self.zf + 1
].astype("int16")
- minmat
)
pbar.update(self.solidsize)
fdata["/rigidE"] = G.rigidE[:, self.xs : self.xf + 1, self.ys : self.yf + 1, self.zs : self.zf + 1]
fdata["/rigidH"] = G.rigidH[:, self.xs : self.xf + 1, self.ys : self.yf + 1, self.zs : self.zf + 1]
fdata["/rigidE"] = G.rigidE[
:, self.xs : self.xf + 1, self.ys : self.yf + 1, self.zs : self.zf + 1
]
fdata["/rigidH"] = G.rigidH[
:, self.xs : self.xf + 1, self.ys : self.yf + 1, self.zs : self.zf + 1
]
pbar.update(self.rigidsize)
fdata["/ID"] = G.ID[:, self.xs : self.xf + 1, self.ys : self.yf + 1, self.zs : self.zf + 1] - minmat
fdata["/ID"] = (
G.ID[
:,
self.xs : self.xf + 1,
self.ys : self.yf + 1,
self.zs : self.zf + 1,
]
- minmat
)
pbar.update(self.IDsize)
# Write materials list to a text file
@@ -409,11 +494,18 @@ class GeometryObjects:
)
if hasattr(material, "poles"):
if "debye" in material.type:
dispersionstr = "#add_dispersion_debye: " f"{material.poles:g} "
dispersionstr = (
f"#add_dispersion_debye: {material.poles:g} "
)
for pole in range(material.poles):
dispersionstr += f"{material.deltaer[pole]:g} " f"{material.tau[pole]:g} "
dispersionstr += (
f"{material.deltaer[pole]:g} "
f"{material.tau[pole]:g} "
)
elif "lorenz" in material.type:
dispersionstr = f"#add_dispersion_lorenz: " f"{material.poles:g} "
dispersionstr = (
f"#add_dispersion_lorenz: {material.poles:g} "
)
for pole in range(material.poles):
dispersionstr += (
f"{material.deltaer[pole]:g} "
@@ -421,8 +513,13 @@ class GeometryObjects:
f"{material.alpha[pole]:g} "
)
elif "drude" in material.type:
dispersionstr = f"#add_dispersion_drude: " f"{material.poles:g} "
dispersionstr = (
f"#add_dispersion_drude: {material.poles:g} "
)
for pole in range(material.poles):
dispersionstr += f"{material.tau[pole]:g} " f"{material.alpha[pole]:g} "
dispersionstr += (
f"{material.tau[pole]:g} "
f"{material.alpha[pole]:g} "
)
dispersionstr += material.ID
fmaterials.write(dispersionstr + "\n")

查看文件

@@ -47,7 +47,8 @@ help_msg = {
"scenes": "(list, req): Scenes to run the model. Multiple scene objects "
"can given in order to run multiple simulation runs. Each scene "
"must contain the essential simulation objects",
"inputfile": "(str, opt): Input file path. Can also run simulation by " "providing an input file.",
"inputfile": "(str, opt): Input file path. Can also run simulation by "
"providing an input file.",
"outputfile": "(str, req): File path to the output data file.",
"n": "(int, req): Number of required simulation runs.",
"i": "(int, opt): Model number to start/restart simulation from. It would "
@@ -59,16 +60,20 @@ help_msg = {
"models to be farmed out using a MPI task farm, e.g. to create a "
"B-scan with 60 traces and use MPI to farm out each trace. For "
"further details see the performance section of the User Guide.",
"gpu": "(list/bool, opt): Flag to use NVIDIA GPU or list of NVIDIA GPU " "device ID(s) for specific GPU card(s).",
"opencl": "(list/bool, opt): Flag to use OpenCL or list of OpenCL device " "ID(s) for specific compute device(s).",
"gpu": "(list/bool, opt): Flag to use NVIDIA GPU or list of NVIDIA GPU "
"device ID(s) for specific GPU card(s).",
"opencl": "(list/bool, opt): Flag to use OpenCL or list of OpenCL device "
"ID(s) for specific compute device(s).",
"subgrid": "(bool, opt): Flag to use sub-gridding.",
"autotranslate": "(bool, opt): For sub-gridding - auto translate objects "
"with main grid coordinates to their equivalent local "
"grid coordinate within the subgrid. If this option is "
"off users must specify sub-grid object point within the "
"global subgrid space.",
"geometry_only": "(bool, opt): Build a model and produce any geometry " "views but do not run the simulation.",
"geometry_fixed": "(bool, opt): Run a series of models where the geometry " "does not change between models.",
"geometry_only": "(bool, opt): Build a model and produce any geometry "
"views but do not run the simulation.",
"geometry_fixed": "(bool, opt): Run a series of models where the geometry "
"does not change between models.",
"write_processed": "(bool, opt): Writes another input file after any "
"Python code (#python blocks) and in the original input "
"file has been processed.",
@@ -163,15 +168,26 @@ def cli():
"""Entry point for command line interface (CLI)."""
# Parse command line arguments
parser = argparse.ArgumentParser(prog="gprMax", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser = argparse.ArgumentParser(
prog="gprMax", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("inputfile", help=help_msg["inputfile"])
parser.add_argument("-n", default=args_defaults["n"], type=int, help=help_msg["n"])
parser.add_argument("-i", type=int, help=help_msg["i"])
parser.add_argument("-mpi", action="store_true", default=args_defaults["mpi"], help=help_msg["mpi"])
parser.add_argument("-gpu", type=int, action="append", nargs="*", help=help_msg["gpu"])
parser.add_argument("-opencl", type=int, action="append", nargs="*", help=help_msg["opencl"])
parser.add_argument(
"--geometry-only", action="store_true", default=args_defaults["geometry_only"], help=help_msg["geometry_only"]
"-mpi", action="store_true", default=args_defaults["mpi"], help=help_msg["mpi"]
)
parser.add_argument(
"-gpu", type=int, action="append", nargs="*", help=help_msg["gpu"]
)
parser.add_argument(
"-opencl", type=int, action="append", nargs="*", help=help_msg["opencl"]
)
parser.add_argument(
"--geometry-only",
action="store_true",
default=args_defaults["geometry_only"],
help=help_msg["geometry_only"],
)
parser.add_argument(
"--geometry-fixed",
@@ -185,8 +201,18 @@ def cli():
default=args_defaults["write_processed"],
help=help_msg["write_processed"],
)
parser.add_argument("--log-level", type=int, default=args_defaults["log_level"], help=help_msg["log_level"])
parser.add_argument("--log-file", action="store_true", default=args_defaults["log_file"], help=help_msg["log_file"])
parser.add_argument(
"--log-level",
type=int,
default=args_defaults["log_level"],
help=help_msg["log_level"],
)
parser.add_argument(
"--log-file",
action="store_true",
default=args_defaults["log_file"],
help=help_msg["log_file"],
)
args = parser.parse_args()
results = run_main(args)

查看文件

@@ -128,30 +128,67 @@ class FDTDGrid:
def initialise_field_arrays(self):
"""Initialise arrays for the electric and magnetic field components."""
self.Ex = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"])
self.Ey = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"])
self.Ez = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"])
self.Hx = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"])
self.Hy = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"])
self.Hz = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"])
self.Ex = np.zeros(
(self.nx + 1, self.ny + 1, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.Ey = np.zeros(
(self.nx + 1, self.ny + 1, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.Ez = np.zeros(
(self.nx + 1, self.ny + 1, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.Hx = np.zeros(
(self.nx + 1, self.ny + 1, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.Hy = np.zeros(
(self.nx + 1, self.ny + 1, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.Hz = np.zeros(
(self.nx + 1, self.ny + 1, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
def initialise_std_update_coeff_arrays(self):
"""Initialise arrays for storing update coefficients."""
self.updatecoeffsE = np.zeros((len(self.materials), 5), dtype=config.sim_config.dtypes["float_or_double"])
self.updatecoeffsH = np.zeros((len(self.materials), 5), dtype=config.sim_config.dtypes["float_or_double"])
self.updatecoeffsE = np.zeros(
(len(self.materials), 5), dtype=config.sim_config.dtypes["float_or_double"]
)
self.updatecoeffsH = np.zeros(
(len(self.materials), 5), dtype=config.sim_config.dtypes["float_or_double"]
)
def initialise_dispersive_arrays(self):
"""Initialise field arrays when there are dispersive materials present."""
self.Tx = np.zeros(
(config.get_model_config().materials["maxpoles"], self.nx + 1, self.ny + 1, self.nz + 1),
(
config.get_model_config().materials["maxpoles"],
self.nx + 1,
self.ny + 1,
self.nz + 1,
),
dtype=config.get_model_config().materials["dispersivedtype"],
)
self.Ty = np.zeros(
(config.get_model_config().materials["maxpoles"], self.nx + 1, self.ny + 1, self.nz + 1),
(
config.get_model_config().materials["maxpoles"],
self.nx + 1,
self.ny + 1,
self.nz + 1,
),
dtype=config.get_model_config().materials["dispersivedtype"],
)
self.Tz = np.zeros(
(config.get_model_config().materials["maxpoles"], self.nx + 1, self.ny + 1, self.nz + 1),
(
config.get_model_config().materials["maxpoles"],
self.nx + 1,
self.ny + 1,
self.nz + 1,
),
dtype=config.get_model_config().materials["dispersivedtype"],
)
@@ -185,7 +222,9 @@ class FDTDGrid:
solidarray = self.nx * self.ny * self.nz * np.dtype(np.uint32).itemsize
# 12 x rigidE array components + 6 x rigidH array components
rigidarrays = (12 + 6) * self.nx * self.ny * self.nz * np.dtype(np.int8).itemsize
rigidarrays = (
(12 + 6) * self.nx * self.ny * self.nz * np.dtype(np.int8).itemsize
)
# 6 x field arrays + 6 x ID arrays
fieldarrays = (
@@ -288,14 +327,24 @@ class FDTDGrid:
def calculate_dt(self):
"""Calculate time step at the CFL limit."""
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)))
self.dt = 1 / (
config.sim_config.em_consts["c"]
* np.sqrt((1 / self.dy**2) + (1 / self.dz**2))
)
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)))
self.dt = 1 / (
config.sim_config.em_consts["c"]
* np.sqrt((1 / self.dx**2) + (1 / self.dz**2))
)
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)))
self.dt = 1 / (
config.sim_config.em_consts["c"]
* np.sqrt((1 / self.dx**2) + (1 / self.dy**2))
)
else:
self.dt = 1 / (
config.sim_config.em_consts["c"] * np.sqrt((1 / self.dx**2) + (1 / self.dy**2) + (1 / self.dz**2))
config.sim_config.em_consts["c"]
* np.sqrt((1 / self.dx**2) + (1 / self.dy**2) + (1 / self.dz**2))
)
# Round down time step to nearest float with precision one less than
@@ -319,10 +368,14 @@ class CUDAGrid(FDTDGrid):
def set_blocks_per_grid(self):
"""Set the blocks per grid size used for updating the electric and
magnetic field arrays on a GPU.
magnetic field arrays on a GPU.
"""
self.bpg = (int(np.ceil(((self.nx + 1) * (self.ny + 1) * (self.nz + 1)) / self.tpb[0])), 1, 1)
self.bpg = (
int(np.ceil(((self.nx + 1) * (self.ny + 1) * (self.nz + 1)) / self.tpb[0])),
1,
1,
)
def htod_geometry_arrays(self):
"""Initialise an array for cell edge IDs (ID) on compute device."""
@@ -342,11 +395,13 @@ class CUDAGrid(FDTDGrid):
def htod_dispersive_arrays(self):
"""Initialise dispersive material coefficient arrays on compute device."""
self.updatecoeffsdispersive_dev = self.gpuarray.to_gpu(self.updatecoeffsdispersive)
self.updatecoeffsdispersive_dev = self.gpuarray.to_gpu(
self.updatecoeffsdispersive
)
self.Tx_dev = self.gpuarray.to_gpu(self.Tx)
self.Ty_dev = self.gpuarray.to_gpu(self.Ty)
self.Tz_dev = self.gpuarray.to_gpu(self.Tz)
class OpenCLGrid(FDTDGrid):
"""Additional grid methods for solving on compute device using OpenCL."""
@@ -385,13 +440,15 @@ class OpenCLGrid(FDTDGrid):
Args:
queue: pyopencl queue.
"""
self.updatecoeffsdispersive_dev = self.clarray.to_device(queue, self.updatecoeffsdispersive)
self.updatecoeffsdispersive_dev = self.clarray.to_device(
queue, self.updatecoeffsdispersive
)
# self.updatecoeffsdispersive_dev = self.clarray.to_device(queue, np.ones((95,95,95), dtype=np.float32))
self.Tx_dev = self.clarray.to_device(queue, self.Tx)
self.Ty_dev = self.clarray.to_device(queue, self.Ty)
self.Tz_dev = self.clarray.to_device(queue, self.Tz)
def dispersion_analysis(G):
"""Analysis of numerical dispersion (Taflove et al, 2005, p112) -
@@ -431,7 +488,9 @@ def dispersion_analysis(G):
iterations = min(iterations, G.iterations)
waveformvalues = np.zeros(G.iterations)
for iteration in range(G.iterations):
waveformvalues[iteration] = waveform.calculate_value(iteration * G.dt, G.dt)
waveformvalues[iteration] = waveform.calculate_value(
iteration * G.dt, G.dt
)
# Ensure source waveform is not being overly truncated before attempting any FFT
if np.abs(waveformvalues[-1]) < np.abs(np.amax(waveformvalues)) / 100:
@@ -444,7 +503,10 @@ def dispersion_analysis(G):
try:
freqthres = (
np.where(
power[freqmaxpower:] < -config.get_model_config().numdispersion["highestfreqthres"]
power[freqmaxpower:]
< -config.get_model_config().numdispersion[
"highestfreqthres"
]
)[0][0]
+ freqmaxpower
)
@@ -463,7 +525,8 @@ def dispersion_analysis(G):
# If waveform is truncated don't do any further analysis
else:
results["error"] = (
"waveform does not fit within specified " + "time window and is therefore being truncated."
"waveform does not fit within specified "
+ "time window and is therefore being truncated."
)
else:
results["error"] = "no waveform detected."
@@ -511,9 +574,14 @@ def dispersion_analysis(G):
results["N"] = minwavelength / delta
# Check grid sampling will result in physical wave propagation
if int(np.floor(results["N"])) >= config.get_model_config().numdispersion["mingridsampling"]:
if (
int(np.floor(results["N"]))
>= config.get_model_config().numdispersion["mingridsampling"]
):
# Numerical phase velocity
vp = np.pi / (results["N"] * np.arcsin((1 / S) * np.sin((np.pi * S) / results["N"])))
vp = np.pi / (
results["N"] * np.arcsin((1 / S) * np.sin((np.pi * S) / results["N"]))
)
# Physical phase velocity error (percentage)
results["deltavp"] = (((vp * config.c) - config.c) / config.c) * 100

查看文件

@@ -48,7 +48,11 @@ def process_python_include_code(inputfile, usernamespace):
"""
# Strip out any newline characters and comments that must begin with double hashes
inputlines = [line.rstrip() for line in inputfile if (not line.startswith("##") and line.rstrip("\n"))]
inputlines = [
line.rstrip()
for line in inputfile
if (not line.startswith("##") and line.rstrip("\n"))
]
# Rewind input file in preparation for any subsequent reading function
inputfile.seek(0)
@@ -74,7 +78,8 @@ def process_python_include_code(inputfile, usernamespace):
x += 1
if x == len(inputlines):
logger.exception(
"Cannot find the end of the Python code " + "block, i.e. missing #end_python: command."
"Cannot find the end of the Python code "
+ "block, i.e. missing #end_python: command."
)
raise SyntaxError
# Compile code for faster execution
@@ -147,7 +152,9 @@ def process_include_files(hashcmds):
# See if file exists at specified path and if not try input file directory
includefile = Path(includefile)
if not includefile.exists():
includefile = Path(config.sim_config.input_file_path.parent, includefile)
includefile = Path(
config.sim_config.input_file_path.parent, includefile
)
with open(includefile, "r") as f:
# Strip out any newline characters and comments that must begin with double hashes
@@ -289,7 +296,9 @@ def check_cmd_names(processedlines, checkessential=True):
# are no parameters for a command, e.g. for #taguchi:
if " " not in cmdparams[0] and len(cmdparams.strip("\n")) != 0:
logger.exception(
"There must be a space between the command name " + "and parameters in " + processedlines[lindex]
"There must be a space between the command name "
+ "and parameters in "
+ processedlines[lindex]
)
raise SyntaxError
@@ -312,7 +321,11 @@ def check_cmd_names(processedlines, checkessential=True):
if singlecmds[cmdname] is None:
singlecmds[cmdname] = cmd[1].strip(" \t\n")
else:
logger.exception("You can only have a single instance of " + cmdname + " in your model")
logger.exception(
"You can only have a single instance of "
+ cmdname
+ " in your model"
)
raise SyntaxError
elif cmdname in multiplecmds:
@@ -384,7 +397,10 @@ def parse_hash_commands(scene):
for key, value in sorted(usernamespace.items()):
if key != "__builtins__":
uservars += f"{key}: {value}, "
logger.info(f"Constants/variables used/available for Python scripting: " + f"{{{uservars[:-2]}}}\n")
logger.info(
f"Constants/variables used/available for Python scripting: "
+ f"{{{uservars[:-2]}}}\n"
)
# Write a file containing the input commands after Python or include
# file commands have been processed

查看文件

@@ -56,11 +56,12 @@ def process_geometrycmds(geometry):
tmp = object.split()
if tmp[0] == "#geometry_objects_read:":
from .cmds_geometry.geometry_objects_read import \
GeometryObjectsRead
from .cmds_geometry.geometry_objects_read import GeometryObjectsRead
if len(tmp) != 6:
logger.exception("'" + " ".join(tmp) + "'" + " requires exactly five parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires exactly five parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -70,7 +71,9 @@ def process_geometrycmds(geometry):
elif tmp[0] == "#edge:":
if len(tmp) != 8:
logger.exception("'" + " ".join(tmp) + "'" + " requires exactly seven parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires exactly seven parameters"
)
raise ValueError
edge = Edge(
@@ -83,7 +86,9 @@ def process_geometrycmds(geometry):
elif tmp[0] == "#plate:":
if len(tmp) < 8:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least seven parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires at least seven parameters"
)
raise ValueError
# Isotropic case
@@ -103,14 +108,18 @@ def process_geometrycmds(geometry):
)
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'" + " ".join(tmp) + "'" + " too many parameters have been given"
)
raise ValueError
scene_objects.append(plate)
elif tmp[0] == "#triangle:":
if len(tmp) < 12:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least eleven parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires at least eleven parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -120,26 +129,40 @@ def process_geometrycmds(geometry):
# Isotropic case with no user specified averaging
if len(tmp) == 12:
triangle = Triangle(p1=p1, p2=p2, p3=p3, thickness=thickness, material_id=tmp[11])
triangle = Triangle(
p1=p1, p2=p2, p3=p3, thickness=thickness, material_id=tmp[11]
)
# Isotropic case with user specified averaging
elif len(tmp) == 13:
triangle = Triangle(p1=p1, p2=p2, p3=p3, thickness=thickness,
material_id=tmp[11], averaging=tmp[12].lower())
triangle = Triangle(
p1=p1,
p2=p2,
p3=p3,
thickness=thickness,
material_id=tmp[11],
averaging=tmp[12].lower(),
)
# Uniaxial anisotropic case
elif len(tmp) == 14:
triangle = Triangle(p1=p1, p2=p2, p3=p3, thickness=thickness, material_ids=tmp[11:])
triangle = Triangle(
p1=p1, p2=p2, p3=p3, thickness=thickness, material_ids=tmp[11:]
)
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'" + " ".join(tmp) + "'" + " too many parameters have been given"
)
raise ValueError
scene_objects.append(triangle)
elif tmp[0] == "#box:":
if len(tmp) < 8:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least seven parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires at least seven parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -158,14 +181,18 @@ def process_geometrycmds(geometry):
box = Box(p1=p1, p2=p2, material_ids=tmp[7:])
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'" + " ".join(tmp) + "'" + " too many parameters have been given"
)
raise ValueError
scene_objects.append(box)
elif tmp[0] == "#cylinder:":
if len(tmp) < 9:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least eight parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires at least eight parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -178,21 +205,27 @@ def process_geometrycmds(geometry):
# Isotropic case with user specified averaging
elif len(tmp) == 10:
cylinder = Cylinder(p1=p1, p2=p2, r=r, material_id=tmp[8], averaging=tmp[9].lower())
cylinder = Cylinder(
p1=p1, p2=p2, r=r, material_id=tmp[8], averaging=tmp[9].lower()
)
# Uniaxial anisotropic case
elif len(tmp) == 11:
cylinder = Cylinder(p1=p1, p2=p2, r=r, material_ids=tmp[8:])
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'" + " ".join(tmp) + "'" + " too many parameters have been given"
)
raise ValueError
scene_objects.append(cylinder)
elif tmp[0] == "#cone:":
if len(tmp) < 10:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least nine parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires at least nine parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -206,21 +239,32 @@ def process_geometrycmds(geometry):
# Isotropic case with user specified averaging
elif len(tmp) == 11:
cone = Cone(p1=p1, p2=p2, r1=r1, r2=r2, material_id=tmp[9], averaging=tmp[10].lower())
cone = Cone(
p1=p1,
p2=p2,
r1=r1,
r2=r2,
material_id=tmp[9],
averaging=tmp[10].lower(),
)
# Uniaxial anisotropic case
elif len(tmp) == 12:
cone = Cone(p1=p1, p2=p2, r1=r1, r2=r2, material_ids=tmp[9:])
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'" + " ".join(tmp) + "'" + " too many parameters have been given"
)
raise ValueError
scene_objects.append(cone)
elif tmp[0] == "#cylindrical_sector:":
if len(tmp) < 10:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least nine parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires at least nine parameters"
)
raise ValueError
normal = tmp[1].lower()
@@ -276,14 +320,18 @@ def process_geometrycmds(geometry):
)
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'" + " ".join(tmp) + "'" + " too many parameters have been given"
)
raise ValueError
scene_objects.append(cylindrical_sector)
elif tmp[0] == "#sphere:":
if len(tmp) < 6:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least five parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires at least five parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -295,21 +343,27 @@ def process_geometrycmds(geometry):
# Isotropic case with user specified averaging
elif len(tmp) == 7:
sphere = Sphere(p1=p1, r=r, material_id=tmp[5], averaging=tmp[6].lower())
sphere = Sphere(
p1=p1, r=r, material_id=tmp[5], averaging=tmp[6].lower()
)
# Uniaxial anisotropic case
elif len(tmp) == 8:
sphere = Sphere(p1=p1, r=r, material_id=tmp[5:])
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'" + " ".join(tmp) + "'" + " too many parameters have been given"
)
raise ValueError
scene_objects.append(sphere)
elif tmp[0] == "#ellipsoid:":
if len(tmp) < 8:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least seven parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires at least seven parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -323,15 +377,23 @@ def process_geometrycmds(geometry):
# Isotropic case with user specified averaging
elif len(tmp) == 9:
ellipsoid = Ellipsoid(p1=p1, xr=xr, yr=yr, zr=zr,
material_id=tmp[7], averaging=tmp[8].lower())
ellipsoid = Ellipsoid(
p1=p1,
xr=xr,
yr=yr,
zr=zr,
material_id=tmp[7],
averaging=tmp[8].lower(),
)
# Uniaxial anisotropic case
elif len(tmp) == 8:
ellipsoid = Ellipsoid(p1=p1, xr=xr, yr=yr, zr=zr, material_id=tmp[7:])
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'" + " ".join(tmp) + "'" + " too many parameters have been given"
)
raise ValueError
scene_objects.append(ellipsoid)
@@ -340,7 +402,9 @@ def process_geometrycmds(geometry):
# Default is no dielectric smoothing for a fractal box
if len(tmp) < 14:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least thirteen parameters")
logger.exception(
"'" + " ".join(tmp) + "'" + " requires at least thirteen parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -385,7 +449,9 @@ def process_geometrycmds(geometry):
averaging=tmp[15].lower(),
)
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'" + " ".join(tmp) + "'" + " too many parameters have been given"
)
raise ValueError
scene_objects.append(fb)
@@ -396,7 +462,12 @@ def process_geometrycmds(geometry):
if tmp[0] == "#add_surface_roughness:":
if len(tmp) < 13:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least twelve parameters")
logger.exception(
"'"
+ " ".join(tmp)
+ "'"
+ " requires at least twelve parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -426,14 +497,24 @@ def process_geometrycmds(geometry):
seed=int(tmp[13]),
)
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'"
+ " ".join(tmp)
+ "'"
+ " too many parameters have been given"
)
raise ValueError
scene_objects.append(asr)
if tmp[0] == "#add_surface_water:":
if len(tmp) != 9:
logger.exception("'" + " ".join(tmp) + "'" + " requires exactly eight parameters")
logger.exception(
"'"
+ " ".join(tmp)
+ "'"
+ " requires exactly eight parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -441,12 +522,19 @@ def process_geometrycmds(geometry):
depth = float(tmp[7])
fractal_box_id = tmp[8]
asf = AddSurfaceWater(p1=p1, p2=p2, depth=depth, fractal_box_id=fractal_box_id)
asf = AddSurfaceWater(
p1=p1, p2=p2, depth=depth, fractal_box_id=fractal_box_id
)
scene_objects.append(asf)
if tmp[0] == "#add_grass:":
if len(tmp) < 12:
logger.exception("'" + " ".join(tmp) + "'" + " requires at least eleven parameters")
logger.exception(
"'"
+ " ".join(tmp)
+ "'"
+ " requires at least eleven parameters"
)
raise ValueError
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
@@ -476,7 +564,12 @@ def process_geometrycmds(geometry):
seed=int(tmp[12]),
)
else:
logger.exception("'" + " ".join(tmp) + "'" + " too many parameters have been given")
logger.exception(
"'"
+ " ".join(tmp)
+ "'"
+ " too many parameters have been given"
)
raise ValueError
scene_objects.append(grass)

查看文件

@@ -18,13 +18,27 @@
import logging
from .cmds_multiuse import (PMLCFS, AddDebyeDispersion, AddDrudeDispersion,
AddLorentzDispersion, ExcitationFile,
GeometryObjectsWrite, GeometryView, HertzianDipole,
MagneticDipole, Material, MaterialList,
MaterialRange, Rx, RxArray, Snapshot,
SoilPeplinski, TransmissionLine, VoltageSource,
Waveform)
from .cmds_multiuse import (
PMLCFS,
AddDebyeDispersion,
AddDrudeDispersion,
AddLorentzDispersion,
ExcitationFile,
GeometryObjectsWrite,
GeometryView,
HertzianDipole,
MagneticDipole,
Material,
MaterialList,
MaterialRange,
Rx,
RxArray,
Snapshot,
SoilPeplinski,
TransmissionLine,
VoltageSource,
Waveform,
)
logger = logging.getLogger(__name__)
@@ -47,10 +61,19 @@ def process_multicmds(multicmds):
for cmdinstance in multicmds[cmdname]:
tmp = cmdinstance.split()
if len(tmp) != 4:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires exactly four parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires exactly four parameters"
)
raise ValueError
waveform = Waveform(wave_type=tmp[0], amp=float(tmp[1]), freq=float(tmp[2]), id=tmp[3])
waveform = Waveform(
wave_type=tmp[0], amp=float(tmp[1]), freq=float(tmp[2]), id=tmp[3]
)
scene_objects.append(waveform)
cmdname = "#voltage_source"
@@ -74,7 +97,14 @@ def process_multicmds(multicmds):
end=float(tmp[7]),
)
else:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires at least six parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires at least six parameters"
)
raise ValueError
scene_objects.append(voltage_source)
@@ -84,11 +114,20 @@ def process_multicmds(multicmds):
for cmdinstance in multicmds[cmdname]:
tmp = cmdinstance.split()
if len(tmp) < 5:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires at least five parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires at least five parameters"
)
raise ValueError
if len(tmp) == 5:
hertzian_dipole = HertzianDipole(
polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), waveform_id=tmp[4]
polarisation=tmp[0],
p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])),
waveform_id=tmp[4],
)
elif len(tmp) == 7:
hertzian_dipole = HertzianDipole(
@@ -99,7 +138,9 @@ def process_multicmds(multicmds):
end=float(tmp[6]),
)
else:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " too many parameters")
logger.exception(
"'" + cmdname + ": " + " ".join(tmp) + "'" + " too many parameters"
)
raise ValueError
scene_objects.append(hertzian_dipole)
@@ -109,11 +150,20 @@ def process_multicmds(multicmds):
for cmdinstance in multicmds[cmdname]:
tmp = cmdinstance.split()
if len(tmp) < 5:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires at least five parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires at least five parameters"
)
raise ValueError
if len(tmp) == 5:
magnetic_dipole = MagneticDipole(
polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), waveform_id=tmp[4]
polarisation=tmp[0],
p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])),
waveform_id=tmp[4],
)
elif len(tmp) == 7:
magnetic_dipole = MagneticDipole(
@@ -124,7 +174,9 @@ def process_multicmds(multicmds):
end=float(tmp[6]),
)
else:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " too many parameters")
logger.exception(
"'" + cmdname + ": " + " ".join(tmp) + "'" + " too many parameters"
)
raise ValueError
scene_objects.append(magnetic_dipole)
@@ -134,7 +186,14 @@ def process_multicmds(multicmds):
for cmdinstance in multicmds[cmdname]:
tmp = cmdinstance.split()
if len(tmp) < 6:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires at least six parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires at least six parameters"
)
raise ValueError
if len(tmp) == 6:
@@ -154,7 +213,9 @@ def process_multicmds(multicmds):
end=tmp[7],
)
else:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " too many parameters")
logger.exception(
"'" + cmdname + ": " + " ".join(tmp) + "'" + " too many parameters"
)
raise ValueError
scene_objects.append(tl)
@@ -168,7 +229,9 @@ def process_multicmds(multicmds):
raise ValueError
if len(tmp) > 1:
ex_file = ExcitationFile(filepath=tmp[0], kind=tmp[1], fill_value=tmp[2])
ex_file = ExcitationFile(
filepath=tmp[0], kind=tmp[1], fill_value=tmp[2]
)
else:
ex_file = ExcitationFile(filepath=tmp[0])
@@ -179,12 +242,23 @@ def process_multicmds(multicmds):
for cmdinstance in multicmds[cmdname]:
tmp = cmdinstance.split()
if len(tmp) != 3 and len(tmp) < 5:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " has an incorrect number of parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " has an incorrect number of parameters"
)
raise ValueError
if len(tmp) == 3:
rx = Rx(p1=(float(tmp[0]), float(tmp[1]), float(tmp[2])))
else:
rx = Rx(p1=(float(tmp[0]), float(tmp[1]), float(tmp[2])), id=tmp[3], outputs=[" ".join(tmp[4:])])
rx = Rx(
p1=(float(tmp[0]), float(tmp[1]), float(tmp[2])),
id=tmp[3],
outputs=[" ".join(tmp[4:])],
)
scene_objects.append(rx)
@@ -193,7 +267,14 @@ def process_multicmds(multicmds):
for cmdinstance in multicmds[cmdname]:
tmp = cmdinstance.split()
if len(tmp) != 9:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires exactly nine parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires exactly nine parameters"
)
raise ValueError
p1 = (float(tmp[0]), float(tmp[1]), float(tmp[2]))
@@ -208,7 +289,14 @@ def process_multicmds(multicmds):
for cmdinstance in multicmds[cmdname]:
tmp = cmdinstance.split()
if len(tmp) != 11:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires exactly eleven parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires exactly eleven parameters"
)
raise ValueError
p1 = (float(tmp[0]), float(tmp[1]), float(tmp[2]))
@@ -218,7 +306,9 @@ def process_multicmds(multicmds):
try:
iterations = int(tmp[9])
snapshot = Snapshot(p1=p1, p2=p2, dl=dl, iterations=iterations, filename=filename)
snapshot = Snapshot(
p1=p1, p2=p2, dl=dl, iterations=iterations, filename=filename
)
except ValueError:
time = float(tmp[9])
@@ -231,10 +321,23 @@ def process_multicmds(multicmds):
for cmdinstance in multicmds[cmdname]:
tmp = cmdinstance.split()
if len(tmp) != 5:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires exactly five parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires exactly five parameters"
)
raise ValueError
material = Material(er=float(tmp[0]), se=float(tmp[1]), mr=float(tmp[2]), sm=float(tmp[3]), id=tmp[4])
material = Material(
er=float(tmp[0]),
se=float(tmp[1]),
mr=float(tmp[2]),
sm=float(tmp[3]),
id=tmp[4],
)
scene_objects.append(material)
cmdname = "#add_dispersion_debye"
@@ -243,7 +346,14 @@ def process_multicmds(multicmds):
tmp = cmdinstance.split()
if len(tmp) < 4:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires at least four parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires at least four parameters"
)
raise ValueError
poles = int(tmp[0])
@@ -255,7 +365,9 @@ def process_multicmds(multicmds):
er_delta.append(float(tmp[pole]))
tau.append(float(tmp[pole + 1]))
debye_dispersion = AddDebyeDispersion(poles=poles, er_delta=er_delta, tau=tau, material_ids=material_ids)
debye_dispersion = AddDebyeDispersion(
poles=poles, er_delta=er_delta, tau=tau, material_ids=material_ids
)
scene_objects.append(debye_dispersion)
cmdname = "#add_dispersion_lorentz"
@@ -264,7 +376,14 @@ def process_multicmds(multicmds):
tmp = cmdinstance.split()
if len(tmp) < 5:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires at least five parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires at least five parameters"
)
raise ValueError
poles = int(tmp[0])
@@ -279,7 +398,11 @@ def process_multicmds(multicmds):
alpha.append(float(tmp[pole + 2]))
lorentz_dispersion = AddLorentzDispersion(
poles=poles, material_ids=material_ids, er_delta=er_delta, tau=tau, alpha=alpha
poles=poles,
material_ids=material_ids,
er_delta=er_delta,
tau=tau,
alpha=alpha,
)
scene_objects.append(lorentz_dispersion)
@@ -289,7 +412,14 @@ def process_multicmds(multicmds):
tmp = cmdinstance.split()
if len(tmp) < 5:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires at least five parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires at least five parameters"
)
raise ValueError
poles = int(tmp[0])
@@ -301,7 +431,9 @@ def process_multicmds(multicmds):
tau.append(float(tmp[pole]))
alpha.append(float(tmp[pole + 1]))
drude_dispersion = AddDrudeDispersion(poles=poles, material_ids=material_ids, tau=tau, alpha=alpha)
drude_dispersion = AddDrudeDispersion(
poles=poles, material_ids=material_ids, tau=tau, alpha=alpha
)
scene_objects.append(drude_dispersion)
cmdname = "#soil_peplinski"
@@ -310,7 +442,14 @@ def process_multicmds(multicmds):
tmp = cmdinstance.split()
if len(tmp) != 7:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires at exactly seven parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires at exactly seven parameters"
)
raise ValueError
soil = SoilPeplinski(
sand_fraction=float(tmp[0]),
@@ -328,14 +467,23 @@ def process_multicmds(multicmds):
for cmdinstance in multicmds[cmdname]:
tmp = cmdinstance.split()
if len(tmp) != 11:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires exactly eleven parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires exactly eleven parameters"
)
raise ValueError
p1 = float(tmp[0]), float(tmp[1]), float(tmp[2])
p2 = float(tmp[3]), float(tmp[4]), float(tmp[5])
dl = float(tmp[6]), float(tmp[7]), float(tmp[8])
geometry_view = GeometryView(p1=p1, p2=p2, dl=dl, filename=tmp[9], output_type=tmp[10])
geometry_view = GeometryView(
p1=p1, p2=p2, dl=dl, filename=tmp[9], output_type=tmp[10]
)
scene_objects.append(geometry_view)
cmdname = "#geometry_objects_write"
@@ -343,7 +491,14 @@ def process_multicmds(multicmds):
for cmdinstance in multicmds[cmdname]:
tmp = cmdinstance.split()
if len(tmp) != 7:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires exactly seven parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires exactly seven parameters"
)
raise ValueError
p1 = float(tmp[0]), float(tmp[1]), float(tmp[2])
@@ -357,7 +512,14 @@ def process_multicmds(multicmds):
tmp = cmdinstance.split()
if len(tmp) != 9:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires at exactly nine parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires at exactly nine parameters"
)
raise ValueError
material_range = MaterialRange(
er_lower=float(tmp[0]),
@@ -378,7 +540,14 @@ def process_multicmds(multicmds):
tmp = cmdinstance.split()
if len(tmp) < 2:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires at least two parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires at least two parameters"
)
raise ValueError
tokens = len(tmp)
@@ -395,7 +564,14 @@ def process_multicmds(multicmds):
tmp = cmdinstance.split()
if len(tmp) != 12:
logger.exception("'" + cmdname + ": " + " ".join(tmp) + "'" + " requires exactly twelve parameters")
logger.exception(
"'"
+ cmdname
+ ": "
+ " ".join(tmp)
+ "'"
+ " requires exactly twelve parameters"
)
raise ValueError
pml_cfs = PMLCFS(

查看文件

@@ -18,9 +18,18 @@
import logging
from .cmds_singleuse import (Discretisation, Domain, OMPThreads, OutputDir,
PMLProps, RxSteps, SrcSteps,
TimeStepStabilityFactor, TimeWindow, Title)
from .cmds_singleuse import (
Discretisation,
Domain,
OMPThreads,
OutputDir,
PMLProps,
RxSteps,
SrcSteps,
TimeStepStabilityFactor,
TimeWindow,
Title,
)
logger = logging.getLogger(__name__)
@@ -54,7 +63,9 @@ def process_singlecmds(singlecmds):
if singlecmds[cmd] is not None:
tmp = tuple(int(x) for x in singlecmds[cmd].split())
if len(tmp) != 1:
logger.exception(f"{cmd} requires exactly one parameter to specify the number of CPU OpenMP threads to use")
logger.exception(
f"{cmd} requires exactly one parameter to specify the number of CPU OpenMP threads to use"
)
raise ValueError
omp_threads = OMPThreads(n=tmp[0])
@@ -144,7 +155,12 @@ def process_singlecmds(singlecmds):
pml_props = PMLProps(thickness=int(tmp[0]))
else:
pml_props = PMLProps(
x0=int(tmp[0]), y0=int(tmp[1]), z0=int(tmp[2]), xmax=int(tmp[3]), ymax=int(tmp[4]), zmax=int(tmp[5])
x0=int(tmp[0]),
y0=int(tmp[1]),
z0=int(tmp[2]),
xmax=int(tmp[3]),
ymax=int(tmp[4]),
zmax=int(tmp[5]),
)
scene_objects.append(pml_props)

查看文件

@@ -168,7 +168,9 @@ class DispersiveMaterial(Material):
# tau for Lorentz materials are pole frequencies
# alpha for Lorentz materials are the damping coefficients
wp2 = (2 * np.pi * self.tau[x]) ** 2
self.w[x] = -1j * ((wp2 * self.deltaer[x]) / np.sqrt(wp2 - self.alpha[x] ** 2))
self.w[x] = -1j * (
(wp2 * self.deltaer[x]) / np.sqrt(wp2 - self.alpha[x] ** 2)
)
self.q[x] = -self.alpha[x] + (1j * np.sqrt(wp2 - self.alpha[x] ** 2))
elif "drude" in self.type:
# tau for Drude materials are pole frequencies
@@ -239,7 +241,15 @@ class PeplinskiSoil:
by Peplinski (http://dx.doi.org/10.1109/36.387598).
"""
def __init__(self, ID, sandfraction, clayfraction, bulkdensity, sandpartdensity, watervolfraction):
def __init__(
self,
ID,
sandfraction,
clayfraction,
bulkdensity,
sandpartdensity,
watervolfraction,
):
"""
Args:
ID: string for name of the soil.
@@ -282,7 +292,9 @@ class PeplinskiSoil:
erealw = watereri + (waterdeltaer / (1 + (w * watertau) ** 2))
a = 0.65 # Experimentally derived constant
es = (1.01 + 0.44 * self.rs) ** 2 - 0.062 #  Relative permittivity of sand particles
es = (
1.01 + 0.44 * self.rs
) ** 2 - 0.062 #  Relative permittivity of sand particles
b1 = 1.2748 - 0.519 * self.S - 0.152 * self.C
b2 = 1.33797 - 0.603 * self.S - 0.166 * self.C
@@ -304,7 +316,12 @@ class PeplinskiSoil:
muiter = np.nditer(mumaterials, flags=["c_index"])
while not muiter.finished:
# Real part for frequencies in the range 1.4GHz to 18GHz
er = (1 + (self.rb / self.rs) * ((es**a) - 1) + (muiter[0] ** b1 * erealw**a) - muiter[0]) ** (1 / a)
er = (
1
+ (self.rb / self.rs) * ((es**a) - 1)
+ (muiter[0] ** b1 * erealw**a)
- muiter[0]
) ** (1 / a)
# Real part for frequencies in the range 0.3GHz to 1.3GHz (linear
# correction to 1.4-18GHz value)
er = 1.15 * er - 0.68
@@ -313,7 +330,9 @@ class PeplinskiSoil:
eri = er - (muiter[0] ** (b2 / a) * waterdeltaer)
# Effective conductivity
sig = muiter[0] ** (b2 / a) * ((sigf * (self.rs - self.rb)) / (self.rs * muiter[0]))
sig = muiter[0] ** (b2 / a) * (
(sigf * (self.rs - self.rb)) / (self.rs * muiter[0])
)
# Create individual materials
m = DispersiveMaterial(len(G.materials), None)
@@ -406,7 +425,9 @@ class RangeMaterial:
sm = romaterials[iter]
# Check to see if the material already exists before creating a new one
requiredID = f"|{float(er):.4f}+{float(se):.4f}+{float(mr):.4f}+{float(sm):.4f}|"
requiredID = (
f"|{float(er):.4f}+{float(se):.4f}+{float(mr):.4f}+{float(sm):.4f}|"
)
material = next((x for x in G.materials if x.ID == requiredID), None)
if iter == 0 and material:
self.matID.append(material.numID)
@@ -456,7 +477,9 @@ class ListMaterial:
self.matID.append(material.numID)
if not material:
logger.exception(self.__str__() + f" material(s) {material} do not exist")
logger.exception(
self.__str__() + f" material(s) {material} do not exist"
)
raise ValueError
@@ -495,11 +518,16 @@ def calculate_water_properties(T=25, S=0):
# Properties of water from: https://doi.org/10.1109/JOE.1977.1145319
eri = 4.9
er = 88.045 - 0.4147 * T + 6.295e-4 * T**2 + 1.075e-5 * T**3
tau = (1 / (2 * np.pi)) * (1.1109e-10 - 3.824e-12 * T + 6.938e-14 * T**2 - 5.096e-16 * T**3)
tau = (1 / (2 * np.pi)) * (
1.1109e-10 - 3.824e-12 * T + 6.938e-14 * T**2 - 5.096e-16 * T**3
)
delta = 25 - T
beta = (
2.033e-2 + 1.266e-4 * delta + 2.464e-6 * delta**2 - S * (1.849e-5 - 2.551e-7 * delta + 2.551e-8 * delta**2)
2.033e-2
+ 1.266e-4 * delta
+ 2.464e-6 * delta**2
- S * (1.849e-5 - 2.551e-7 * delta + 2.551e-8 * delta**2)
)
sig_25s = S * (0.182521 - 1.46192e-3 * S + 2.09324e-5 * S**2 - 1.28205e-7 * S**3)
sig = sig_25s * np.exp(-delta * beta)
@@ -608,8 +636,20 @@ def process_materials(G):
material.calculate_update_coeffsH(G)
# Add update coefficients to overall storage for all materials
G.updatecoeffsE[material.numID, :] = material.CA, material.CBx, material.CBy, material.CBz, material.srce
G.updatecoeffsH[material.numID, :] = material.DA, material.DBx, material.DBy, material.DBz, material.srcm
G.updatecoeffsE[material.numID, :] = (
material.CA,
material.CBx,
material.CBy,
material.CBz,
material.srce,
)
G.updatecoeffsH[material.numID, :] = (
material.DA,
material.DBx,
material.DBy,
material.DBz,
material.srcm,
)
# Add update coefficients to overall storage for dispersive materials
if hasattr(material, "poles"):
@@ -632,11 +672,15 @@ def process_materials(G):
]
if config.get_model_config().materials["maxpoles"] > 0:
if "debye" in material.type:
materialtext.append("\n".join(f"{deltaer:g}" for deltaer in material.deltaer))
materialtext.append(
"\n".join(f"{deltaer:g}" for deltaer in material.deltaer)
)
materialtext.append("\n".join(f"{tau:g}" for tau in material.tau))
materialtext.extend(["", "", ""])
elif "lorentz" in material.type:
materialtext.append(", ".join(f"{deltaer:g}" for deltaer in material.deltaer))
materialtext.append(
", ".join(f"{deltaer:g}" for deltaer in material.deltaer)
)
materialtext.append("")
materialtext.append(", ".join(f"{tau:g}" for tau in material.tau))
materialtext.append(", ".join(f"{alpha:g}" for alpha in material.alpha))
@@ -649,7 +693,9 @@ def process_materials(G):
else:
materialtext.extend(["", "", "", "", ""])
materialtext.extend((f"{material.mr:g}", f"{material.sm:g}", material.averagable))
materialtext.extend(
(f"{material.mr:g}", f"{material.sm:g}", material.averagable)
)
materialsdata.append(materialtext)
return materialsdata

查看文件

@@ -33,8 +33,7 @@ from tqdm import tqdm
import gprMax.config as config
from .cython.yee_cell_build import (build_electric_components,
build_magnetic_components)
from .cython.yee_cell_build import build_electric_components, build_magnetic_components
from .fields_outputs import write_hdf5_outputfile
from .geometry_outputs import save_geometry_views
from .grid import dispersion_analysis
@@ -43,8 +42,7 @@ from .materials import process_materials
from .pml import CFS, build_pml, print_pml_info
from .scene import Scene
from .snapshots import save_snapshots
from .utilities.host_info import (mem_check_build_all, mem_check_run_all,
set_omp_threads)
from .utilities.host_info import mem_check_build_all, mem_check_run_all, set_omp_threads
from .utilities.utilities import get_terminal_width
logger = logging.getLogger(__name__)
@@ -62,7 +60,9 @@ class ModelBuildRun:
# used with threaded model building methods, e.g. fractals. Can be
# changed by the user via #num_threads command in input file or via API
# later for use with CPU solver.
config.get_model_config().ompthreads = set_omp_threads(config.get_model_config().ompthreads)
config.get_model_config().ompthreads = set_omp_threads(
config.get_model_config().ompthreads
)
def build(self):
"""Builds the Yee cells for a model."""
@@ -75,7 +75,9 @@ class ModelBuildRun:
# Normal model reading/building process; bypassed if geometry information to be reused
self.reuse_geometry() if config.get_model_config().reuse_geometry else self.build_geometry()
logger.info(f"\nOutput directory: {config.get_model_config().output_file_path.parent.resolve()}")
logger.info(
f"\nOutput directory: {config.get_model_config().output_file_path.parent.resolve()}"
)
# Adjust position of simple sources and receivers if required
if G.srcsteps[0] != 0 or G.srcsteps[1] != 0 or G.srcsteps[2] != 0:
@@ -83,13 +85,20 @@ class ModelBuildRun:
if config.model_num == 0:
if (
source.xcoord + G.srcsteps[0] * config.sim_config.model_end < 0
or source.xcoord + G.srcsteps[0] * config.sim_config.model_end > G.nx
or source.ycoord + G.srcsteps[1] * config.sim_config.model_end < 0
or source.ycoord + G.srcsteps[1] * config.sim_config.model_end > G.ny
or source.zcoord + G.srcsteps[2] * config.sim_config.model_end < 0
or source.zcoord + G.srcsteps[2] * config.sim_config.model_end > G.nz
or source.xcoord + G.srcsteps[0] * config.sim_config.model_end
> G.nx
or source.ycoord + G.srcsteps[1] * config.sim_config.model_end
< 0
or source.ycoord + G.srcsteps[1] * config.sim_config.model_end
> G.ny
or source.zcoord + G.srcsteps[2] * config.sim_config.model_end
< 0
or source.zcoord + G.srcsteps[2] * config.sim_config.model_end
> G.nz
):
logger.exception("Source(s) will be stepped to a position outside the domain.")
logger.exception(
"Source(s) will be stepped to a position outside the domain."
)
raise ValueError
source.xcoord = source.xcoordorigin + config.model_num * G.srcsteps[0]
source.ycoord = source.ycoordorigin + config.model_num * G.srcsteps[1]
@@ -99,21 +108,38 @@ class ModelBuildRun:
if config.model_num == 0:
if (
receiver.xcoord + G.rxsteps[0] * config.sim_config.model_end < 0
or receiver.xcoord + G.rxsteps[0] * config.sim_config.model_end > G.nx
or receiver.ycoord + G.rxsteps[1] * config.sim_config.model_end < 0
or receiver.ycoord + G.rxsteps[1] * config.sim_config.model_end > G.ny
or receiver.zcoord + G.rxsteps[2] * config.sim_config.model_end < 0
or receiver.zcoord + G.rxsteps[2] * config.sim_config.model_end > G.nz
or receiver.xcoord + G.rxsteps[0] * config.sim_config.model_end
> G.nx
or receiver.ycoord + G.rxsteps[1] * config.sim_config.model_end
< 0
or receiver.ycoord + G.rxsteps[1] * config.sim_config.model_end
> G.ny
or receiver.zcoord + G.rxsteps[2] * config.sim_config.model_end
< 0
or receiver.zcoord + G.rxsteps[2] * config.sim_config.model_end
> G.nz
):
logger.exception("Receiver(s) will be stepped to a position outside the domain.")
logger.exception(
"Receiver(s) will be stepped to a position outside the domain."
)
raise ValueError
receiver.xcoord = receiver.xcoordorigin + config.model_num * G.rxsteps[0]
receiver.ycoord = receiver.ycoordorigin + config.model_num * G.rxsteps[1]
receiver.zcoord = receiver.zcoordorigin + config.model_num * G.rxsteps[2]
receiver.xcoord = (
receiver.xcoordorigin + config.model_num * G.rxsteps[0]
)
receiver.ycoord = (
receiver.ycoordorigin + config.model_num * G.rxsteps[1]
)
receiver.zcoord = (
receiver.zcoordorigin + config.model_num * G.rxsteps[2]
)
# Write files for any geometry views and geometry object outputs
gvs = G.geometryviews + [gv for sg in G.subgrids for gv in sg.geometryviews]
if not gvs and not G.geometryobjectswrite and config.sim_config.args.geometry_only:
if (
not gvs
and not G.geometryobjectswrite
and config.sim_config.args.geometry_only
):
logger.exception("\nNo geometry views or geometry objects found.")
raise ValueError
save_geometry_views(gvs)
@@ -154,7 +180,11 @@ class ModelBuildRun:
for grid in grids:
if config.get_model_config().materials["maxpoles"] != 0:
config.get_model_config().materials["drudelorentz"] = any(
[m for m in grid.materials if "drude" in m.type or "lorentz" in m.type]
[
m
for m in grid.materials
if "drude" in m.type or "lorentz" in m.type
]
)
# Set data type if any dispersive materials (must be done before memory checks)
@@ -171,13 +201,13 @@ class ModelBuildRun:
if total_mem_build > total_mem_run:
logger.info(
f'\nMemory required (estimated): {" + ".join(mem_strs_build)} + '
f"\nMemory required (estimated): {' + '.join(mem_strs_build)} + "
f"~{humanize.naturalsize(config.get_model_config().mem_overhead)} "
f"overhead = {humanize.naturalsize(total_mem_build)}"
)
else:
logger.info(
f'\nMemory required (estimated): {" + ".join(mem_strs_run)} + '
f"\nMemory required (estimated): {' + '.join(mem_strs_run)} + "
f"~{humanize.naturalsize(config.get_model_config().mem_overhead)} "
f"overhead = {humanize.naturalsize(total_mem_run)}"
)
@@ -206,9 +236,13 @@ class ModelBuildRun:
results = dispersion_analysis(gb.grid)
if results["error"]:
logger.warning(
f"\nNumerical dispersion analysis [{gb.grid.name}] " f"not carried out as {results['error']}"
f"\nNumerical dispersion analysis [{gb.grid.name}] "
f"not carried out as {results['error']}"
)
elif results["N"] < config.get_model_config().numdispersion["mingridsampling"]:
elif (
results["N"]
< config.get_model_config().numdispersion["mingridsampling"]
):
logger.exception(
f"\nNon-physical wave propagation in [{gb.grid.name}] "
f"detected. Material '{results['material'].ID}' "
@@ -220,7 +254,8 @@ class ModelBuildRun:
raise ValueError
elif (
results["deltavp"]
and np.abs(results["deltavp"]) > config.get_model_config().numdispersion["maxnumericaldisp"]
and np.abs(results["deltavp"])
> config.get_model_config().numdispersion["maxnumericaldisp"]
):
logger.warning(
f"\n[{gb.grid.name}] has potentially significant "
@@ -248,7 +283,9 @@ class ModelBuildRun:
f"{config.sim_config.input_file_path}"
)
config.get_model_config().inputfilestr = (
Fore.GREEN + f"{s} {'-' * (get_terminal_width() - 1 - len(s))}\n" + Style.RESET_ALL
Fore.GREEN
+ f"{s} {'-' * (get_terminal_width() - 1 - len(s))}\n"
+ Style.RESET_ALL
)
logger.basic(config.get_model_config().inputfilestr)
for grid in [self.G] + self.G.subgrids:
@@ -280,7 +317,9 @@ class ModelBuildRun:
sg_rxs = [True for sg in self.G.subgrids if sg.rxs]
sg_tls = [True for sg in self.G.subgrids if sg.transmissionlines]
if self.G.rxs or sg_rxs or self.G.transmissionlines or sg_tls:
write_hdf5_outputfile(config.get_model_config().output_file_path_ext, self.G)
write_hdf5_outputfile(
config.get_model_config().output_file_path_ext, self.G
)
# Write any snapshots to file for each grid
for grid in [self.G] + self.G.subgrids:
@@ -301,7 +340,10 @@ class ModelBuildRun:
f"on {config.sim_config.hostinfo['hostname']} "
f"with OpenMP backend using {config.get_model_config().ompthreads} thread(s)"
)
if config.get_model_config().ompthreads > config.sim_config.hostinfo["physicalcores"]:
if (
config.get_model_config().ompthreads
> config.sim_config.hostinfo["physicalcores"]
):
logger.warning(
f"You have specified more threads ({config.get_model_config().ompthreads}) "
f"than available physical CPU cores ({config.sim_config.hostinfo['physicalcores']}). "
@@ -310,17 +352,22 @@ class ModelBuildRun:
elif config.sim_config.general["solver"] in ["cuda", "opencl"]:
if config.sim_config.general["solver"] == "opencl":
solvername = "OpenCL"
platformname = " ".join(config.get_model_config().device["dev"].platform.name.split()) + " with "
platformname = (
" ".join(
config.get_model_config().device["dev"].platform.name.split()
)
+ " with "
)
devicename = (
f'Device {config.get_model_config().device["deviceID"]}: '
f'{" ".join(config.get_model_config().device["dev"].name.split())}'
f"Device {config.get_model_config().device['deviceID']}: "
f"{' '.join(config.get_model_config().device['dev'].name.split())}"
)
else:
solvername = "CUDA"
platformname = ""
devicename = (
f'Device {config.get_model_config().device["deviceID"]}: '
f'{" ".join(config.get_model_config().device["dev"].name().split())}'
f"Device {config.get_model_config().device['deviceID']}: "
f"{' '.join(config.get_model_config().device['dev'].name().split())}"
)
logger.basic(
@@ -353,11 +400,15 @@ class ModelBuildRun:
if config.sim_config.general["solver"] == "cuda":
mem_str = f" host + ~{humanize.naturalsize(solver.memused)} device"
elif config.sim_config.general["solver"] == "opencl":
mem_str = f" host + unknown for device"
mem_str = f" host + unknown for device"
logger.info(f"\nMemory used (estimated): " + f"~{humanize.naturalsize(self.p.memory_full_info().uss)}{mem_str}")
logger.info(
f"Time taken: " + f"{humanize.precisedelta(datetime.timedelta(seconds=solver.solvetime), format='%0.4f')}"
f"\nMemory used (estimated): "
+ f"~{humanize.naturalsize(self.p.memory_full_info().uss)}{mem_str}"
)
logger.info(
f"Time taken: "
+ f"{humanize.precisedelta(datetime.timedelta(seconds=solver.solvetime), format='%0.4f')}"
)
@@ -390,9 +441,13 @@ class GridBuilder:
file=sys.stdout,
disable=not config.sim_config.general["progressbars"],
)
build_electric_components(self.grid.solid, self.grid.rigidE, self.grid.ID, self.grid)
build_electric_components(
self.grid.solid, self.grid.rigidE, self.grid.ID, self.grid
)
pbar.update()
build_magnetic_components(self.grid.solid, self.grid.rigidH, self.grid.ID, self.grid)
build_magnetic_components(
self.grid.solid, self.grid.rigidH, self.grid.ID, self.grid
)
pbar.update()
pbar.close()

查看文件

@@ -165,7 +165,9 @@ class MPIExecutor(object):
self.busy = [False] * len(self.workers)
if self.is_master():
logger.basic(f"\n({self.comm.name}) - Master: {self.master}, Workers: {self.workers}")
logger.basic(
f"\n({self.comm.name}) - Master: {self.master}, Workers: {self.workers}"
)
def __enter__(self):
"""Context manager enter. Only the master returns an executor, all other
@@ -222,7 +224,9 @@ class MPIExecutor(object):
"""Joins the workers."""
if not self.is_master():
return
logger.debug(f"({self.comm.name}) - Terminating. Sending sentinel to all workers.")
logger.debug(
f"({self.comm.name}) - Terminating. Sending sentinel to all workers."
)
# Send sentinel to all workers
for worker in self.workers:
self.comm.send(None, dest=worker, tag=Tags.EXIT)
@@ -269,7 +273,9 @@ class MPIExecutor(object):
for i, worker in enumerate(self.workers):
if self.comm.Iprobe(source=worker, tag=Tags.DONE):
job_idx, result = self.comm.recv(source=worker, tag=Tags.DONE)
logger.debug(f"({self.comm.name}) - Received finished job {job_idx} from worker {worker:d}.")
logger.debug(
f"({self.comm.name}) - Received finished job {job_idx} from worker {worker:d}."
)
results[job_idx] = result
self.busy[i] = False
elif self.comm.Iprobe(source=worker, tag=Tags.READY):
@@ -277,10 +283,16 @@ class MPIExecutor(object):
self.comm.recv(source=worker, tag=Tags.READY)
self.busy[i] = True
job_idx = num_jobs - len(my_jobs)
logger.debug(f"({self.comm.name}) - Sending job {job_idx} to worker {worker:d}.")
self.comm.send((job_idx, my_jobs.pop(0)), dest=worker, tag=Tags.START)
logger.debug(
f"({self.comm.name}) - Sending job {job_idx} to worker {worker:d}."
)
self.comm.send(
(job_idx, my_jobs.pop(0)), dest=worker, tag=Tags.START
)
elif self.comm.Iprobe(source=worker, tag=Tags.EXIT):
logger.debug(f"({self.comm.name}) - Worker on rank {worker:d} has terminated.")
logger.debug(
f"({self.comm.name}) - Worker on rank {worker:d} has terminated."
)
self.comm.recv(source=worker, tag=Tags.EXIT)
self.busy[i] = False
@@ -304,16 +316,22 @@ class MPIExecutor(object):
while True:
self.comm.send(None, dest=self.master, tag=Tags.READY)
logger.debug(f"({self.comm.name}) - Worker on rank {self.rank} waiting for job.")
logger.debug(
f"({self.comm.name}) - Worker on rank {self.rank} waiting for job."
)
data = self.comm.recv(source=self.master, tag=MPI.ANY_TAG, status=status)
tag = status.tag
if tag == Tags.START:
job_idx, work = data
logger.debug(f"({self.comm.name}) - Received job {job_idx} (work={work}).")
logger.debug(
f"({self.comm.name}) - Received job {job_idx} (work={work})."
)
result = self.__guarded_work(work)
logger.debug(f"({self.comm.name}) - Finished job. Sending results to master.")
logger.debug(
f"({self.comm.name}) - Finished job. Sending results to master."
)
self.comm.send((job_idx, result), dest=self.master, tag=Tags.DONE)
elif tag == Tags.EXIT:
logger.debug(f"({self.comm.name}) - Received sentinel from master.")

查看文件

@@ -45,7 +45,15 @@ class CFSParameter:
}
scalingdirections = ["forward", "reverse"]
def __init__(self, ID=None, scaling="polynomial", scalingprofile=None, scalingdirection="forward", min=0, max=0):
def __init__(
self,
ID=None,
scaling="polynomial",
scalingprofile=None,
scalingdirection="forward",
min=0,
max=0,
):
"""
Args:
ID: string identifier for CFS parameter, can be: 'alpha', 'kappa' or
@@ -95,7 +103,9 @@ class CFS:
# Calculation of the maximum value of sigma from http://dx.doi.org/10.1109/8.546249
m = CFSParameter.scalingprofiles[self.sigma.scalingprofile]
self.sigma.max = (0.8 * (m + 1)) / (config.sim_config.em_consts["z0"] * d * np.sqrt(er * mr))
self.sigma.max = (0.8 * (m + 1)) / (
config.sim_config.em_consts["z0"] * d * np.sqrt(er * mr)
)
def scaling_polynomial(self, order, Evalues, Hvalues):
"""Applies the polynomial to be used for the scaling profile for
@@ -115,7 +125,10 @@ class CFS:
magnetic PML update.
"""
tmp = (np.linspace(0, (len(Evalues) - 1) + 0.5, num=2 * len(Evalues)) / (len(Evalues) - 1)) ** order
tmp = (
np.linspace(0, (len(Evalues) - 1) + 0.5, num=2 * len(Evalues))
/ (len(Evalues) - 1)
) ** order
Evalues = tmp[0:-1:2]
Hvalues = tmp[1::2]
@@ -138,8 +151,12 @@ class CFS:
# Extra cell of thickness added to allow correct scaling of electric and
# magnetic values
Evalues = np.zeros(thickness + 1, dtype=config.sim_config.dtypes["float_or_double"])
Hvalues = np.zeros(thickness + 1, dtype=config.sim_config.dtypes["float_or_double"])
Evalues = np.zeros(
thickness + 1, dtype=config.sim_config.dtypes["float_or_double"]
)
Hvalues = np.zeros(
thickness + 1, dtype=config.sim_config.dtypes["float_or_double"]
)
if parameter.scalingprofile == "constant":
Evalues += parameter.max
@@ -237,7 +254,10 @@ class PML:
kappamin = sum(cfs.kappa.min for cfs in self.CFS)
if kappamin < 1:
logger.exception(f"Sum of kappamin value(s) for PML is {kappamin} " "and must be greater than one.")
logger.exception(
f"Sum of kappamin value(s) for PML is {kappamin} "
"and must be greater than one."
)
raise ValueError
def initialise_field_arrays(self):
@@ -245,42 +265,54 @@ class PML:
if self.direction[0] == "x":
self.EPhi1 = np.zeros(
(len(self.CFS), self.nx + 1, self.ny, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx + 1, self.ny, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.EPhi2 = np.zeros(
(len(self.CFS), self.nx + 1, self.ny + 1, self.nz), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx + 1, self.ny + 1, self.nz),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.HPhi1 = np.zeros(
(len(self.CFS), self.nx, self.ny + 1, self.nz), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx, self.ny + 1, self.nz),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.HPhi2 = np.zeros(
(len(self.CFS), self.nx, self.ny, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx, self.ny, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
elif self.direction[0] == "y":
self.EPhi1 = np.zeros(
(len(self.CFS), self.nx, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx, self.ny + 1, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.EPhi2 = np.zeros(
(len(self.CFS), self.nx + 1, self.ny + 1, self.nz), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx + 1, self.ny + 1, self.nz),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.HPhi1 = np.zeros(
(len(self.CFS), self.nx + 1, self.ny, self.nz), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx + 1, self.ny, self.nz),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.HPhi2 = np.zeros(
(len(self.CFS), self.nx, self.ny, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx, self.ny, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
elif self.direction[0] == "z":
self.EPhi1 = np.zeros(
(len(self.CFS), self.nx, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx, self.ny + 1, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.EPhi2 = np.zeros(
(len(self.CFS), self.nx + 1, self.ny, self.nz + 1), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx + 1, self.ny, self.nz + 1),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.HPhi1 = np.zeros(
(len(self.CFS), self.nx + 1, self.ny, self.nz), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx + 1, self.ny, self.nz),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.HPhi2 = np.zeros(
(len(self.CFS), self.nx, self.ny + 1, self.nz), dtype=config.sim_config.dtypes["float_or_double"]
(len(self.CFS), self.nx, self.ny + 1, self.nz),
dtype=config.sim_config.dtypes["float_or_double"],
)
def calculate_update_coeffs(self, er, mr):
@@ -291,14 +323,38 @@ class PML:
mr: float of average permeability of underlying material
"""
self.ERA = np.zeros((len(self.CFS), self.thickness), dtype=config.sim_config.dtypes["float_or_double"])
self.ERB = np.zeros((len(self.CFS), self.thickness), dtype=config.sim_config.dtypes["float_or_double"])
self.ERE = np.zeros((len(self.CFS), self.thickness), dtype=config.sim_config.dtypes["float_or_double"])
self.ERF = np.zeros((len(self.CFS), self.thickness), dtype=config.sim_config.dtypes["float_or_double"])
self.HRA = np.zeros((len(self.CFS), self.thickness), dtype=config.sim_config.dtypes["float_or_double"])
self.HRB = np.zeros((len(self.CFS), self.thickness), dtype=config.sim_config.dtypes["float_or_double"])
self.HRE = np.zeros((len(self.CFS), self.thickness), dtype=config.sim_config.dtypes["float_or_double"])
self.HRF = np.zeros((len(self.CFS), self.thickness), dtype=config.sim_config.dtypes["float_or_double"])
self.ERA = np.zeros(
(len(self.CFS), self.thickness),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.ERB = np.zeros(
(len(self.CFS), self.thickness),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.ERE = np.zeros(
(len(self.CFS), self.thickness),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.ERF = np.zeros(
(len(self.CFS), self.thickness),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.HRA = np.zeros(
(len(self.CFS), self.thickness),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.HRB = np.zeros(
(len(self.CFS), self.thickness),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.HRE = np.zeros(
(len(self.CFS), self.thickness),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.HRF = np.zeros(
(len(self.CFS), self.thickness),
dtype=config.sim_config.dtypes["float_or_double"],
)
for x, cfs in enumerate(self.CFS):
if not cfs.sigma.max:
@@ -310,20 +366,30 @@ class PML:
# Define different parameters depending on PML formulation
if self.G.pmls["formulation"] == "HORIPML":
# HORIPML electric update coefficients
tmp = (2 * config.sim_config.em_consts["e0"] * Ekappa) + self.G.dt * (Ealpha * Ekappa + Esigma)
self.ERA[x, :] = (2 * config.sim_config.em_consts["e0"] + self.G.dt * Ealpha) / tmp
tmp = (2 * config.sim_config.em_consts["e0"] * Ekappa) + self.G.dt * (
Ealpha * Ekappa + Esigma
)
self.ERA[x, :] = (
2 * config.sim_config.em_consts["e0"] + self.G.dt * Ealpha
) / tmp
self.ERB[x, :] = (2 * config.sim_config.em_consts["e0"] * Ekappa) / tmp
self.ERE[x, :] = (
(2 * config.sim_config.em_consts["e0"] * Ekappa) - self.G.dt * (Ealpha * Ekappa + Esigma)
(2 * config.sim_config.em_consts["e0"] * Ekappa)
- self.G.dt * (Ealpha * Ekappa + Esigma)
) / tmp
self.ERF[x, :] = (2 * Esigma * self.G.dt) / (Ekappa * tmp)
# HORIPML magnetic update coefficients
tmp = (2 * config.sim_config.em_consts["e0"] * Hkappa) + self.G.dt * (Halpha * Hkappa + Hsigma)
self.HRA[x, :] = (2 * config.sim_config.em_consts["e0"] + self.G.dt * Halpha) / tmp
tmp = (2 * config.sim_config.em_consts["e0"] * Hkappa) + self.G.dt * (
Halpha * Hkappa + Hsigma
)
self.HRA[x, :] = (
2 * config.sim_config.em_consts["e0"] + self.G.dt * Halpha
) / tmp
self.HRB[x, :] = (2 * config.sim_config.em_consts["e0"] * Hkappa) / tmp
self.HRE[x, :] = (
(2 * config.sim_config.em_consts["e0"] * Hkappa) - self.G.dt * (Halpha * Hkappa + Hsigma)
(2 * config.sim_config.em_consts["e0"] * Hkappa)
- self.G.dt * (Halpha * Hkappa + Hsigma)
) / tmp
self.HRF[x, :] = (2 * Hsigma * self.G.dt) / (Hkappa * tmp)
@@ -332,14 +398,18 @@ class PML:
tmp = 2 * config.sim_config.em_consts["e0"] + self.G.dt * Ealpha
self.ERA[x, :] = Ekappa + (self.G.dt * Esigma) / tmp
self.ERB[x, :] = (2 * config.sim_config.em_consts["e0"]) / tmp
self.ERE[x, :] = ((2 * config.sim_config.em_consts["e0"]) - self.G.dt * Ealpha) / tmp
self.ERE[x, :] = (
(2 * config.sim_config.em_consts["e0"]) - self.G.dt * Ealpha
) / tmp
self.ERF[x, :] = (2 * Esigma * self.G.dt) / tmp
# MRIPML magnetic update coefficients
tmp = 2 * config.sim_config.em_consts["e0"] + self.G.dt * Halpha
self.HRA[x, :] = Hkappa + (self.G.dt * Hsigma) / tmp
self.HRB[x, :] = (2 * config.sim_config.em_consts["e0"]) / tmp
self.HRE[x, :] = ((2 * config.sim_config.em_consts["e0"]) - self.G.dt * Halpha) / tmp
self.HRE[x, :] = (
(2 * config.sim_config.em_consts["e0"]) - self.G.dt * Halpha
) / tmp
self.HRF[x, :] = (2 * Hsigma * self.G.dt) / tmp
def update_electric(self):
@@ -348,7 +418,10 @@ class PML:
"""
pmlmodule = "gprMax.cython.pml_updates_electric_" + self.G.pmls["formulation"]
func = getattr(import_module(pmlmodule), "order" + str(len(self.CFS)) + "_" + self.direction)
func = getattr(
import_module(pmlmodule),
"order" + str(len(self.CFS)) + "_" + self.direction,
)
func(
self.xs,
self.xf,
@@ -380,7 +453,10 @@ class PML:
"""
pmlmodule = "gprMax.cython.pml_updates_magnetic_" + self.G.pmls["formulation"]
func = getattr(import_module(pmlmodule), "order" + str(len(self.CFS)) + "_" + self.direction)
func = getattr(
import_module(pmlmodule),
"order" + str(len(self.CFS)) + "_" + self.direction,
)
func(
self.xs,
self.xf,
@@ -439,7 +515,11 @@ class CUDAPML(PML):
self.bpg = (
int(
np.ceil(
((self.EPhi1_dev.shape[1] + 1) * (self.EPhi1_dev.shape[2] + 1) * (self.EPhi1_dev.shape[3] + 1))
(
(self.EPhi1_dev.shape[1] + 1)
* (self.EPhi1_dev.shape[2] + 1)
* (self.EPhi1_dev.shape[3] + 1)
)
/ self.G.tpb[0]
)
),
@@ -631,7 +711,9 @@ def print_pml_info(G):
if all(value == 0 for value in G.pmls["thickness"].values()):
return f"\nPML boundaries [{G.name}]: switched off"
if all(value == G.pmls["thickness"]["x0"] for value in G.pmls["thickness"].values()):
if all(
value == G.pmls["thickness"]["x0"] for value in G.pmls["thickness"].values()
):
pmlinfo = str(G.pmls["thickness"]["x0"])
else:
pmlinfo = ""
@@ -673,29 +755,104 @@ def build_pml(G, pml_ID, thickness):
pml_type = OpenCLPML
if pml_ID == "x0":
pml = pml_type(G, ID=pml_ID, direction="xminus", xs=0, xf=thickness, ys=0, yf=G.ny, zs=0, zf=G.nz)
pml = pml_type(
G,
ID=pml_ID,
direction="xminus",
xs=0,
xf=thickness,
ys=0,
yf=G.ny,
zs=0,
zf=G.nz,
)
elif pml_ID == "xmax":
pml = pml_type(G, ID=pml_ID, direction="xplus", xs=G.nx - thickness, xf=G.nx, ys=0, yf=G.ny, zs=0, zf=G.nz)
pml = pml_type(
G,
ID=pml_ID,
direction="xplus",
xs=G.nx - thickness,
xf=G.nx,
ys=0,
yf=G.ny,
zs=0,
zf=G.nz,
)
elif pml_ID == "y0":
pml = pml_type(G, ID=pml_ID, direction="yminus", xs=0, xf=G.nx, ys=0, yf=thickness, zs=0, zf=G.nz)
pml = pml_type(
G,
ID=pml_ID,
direction="yminus",
xs=0,
xf=G.nx,
ys=0,
yf=thickness,
zs=0,
zf=G.nz,
)
elif pml_ID == "ymax":
pml = pml_type(G, ID=pml_ID, direction="yplus", xs=0, xf=G.nx, ys=G.ny - thickness, yf=G.ny, zs=0, zf=G.nz)
pml = pml_type(
G,
ID=pml_ID,
direction="yplus",
xs=0,
xf=G.nx,
ys=G.ny - thickness,
yf=G.ny,
zs=0,
zf=G.nz,
)
elif pml_ID == "z0":
pml = pml_type(G, ID=pml_ID, direction="zminus", xs=0, xf=G.nx, ys=0, yf=G.ny, zs=0, zf=thickness)
pml = pml_type(
G,
ID=pml_ID,
direction="zminus",
xs=0,
xf=G.nx,
ys=0,
yf=G.ny,
zs=0,
zf=thickness,
)
elif pml_ID == "zmax":
pml = pml_type(G, ID=pml_ID, direction="zplus", xs=0, xf=G.nx, ys=0, yf=G.ny, zs=G.nz - thickness, zf=G.nz)
pml = pml_type(
G,
ID=pml_ID,
direction="zplus",
xs=0,
xf=G.nx,
ys=0,
yf=G.ny,
zs=G.nz - thickness,
zf=G.nz,
)
if pml_ID[0] == "x":
averageer, averagemr = pml_average_er_mr(
G.ny, G.nz, config.get_model_config().ompthreads, G.solid[pml.xs, :, :], ers, mrs
G.ny,
G.nz,
config.get_model_config().ompthreads,
G.solid[pml.xs, :, :],
ers,
mrs,
)
elif pml_ID[0] == "y":
averageer, averagemr = pml_average_er_mr(
G.nx, G.nz, config.get_model_config().ompthreads, G.solid[:, pml.ys, :], ers, mrs
G.nx,
G.nz,
config.get_model_config().ompthreads,
G.solid[:, pml.ys, :],
ers,
mrs,
)
elif pml_ID[0] == "z":
averageer, averagemr = pml_average_er_mr(
G.nx, G.ny, config.get_model_config().ompthreads, G.solid[:, :, pml.zs], ers, mrs
G.nx,
G.ny,
config.get_model_config().ompthreads,
G.solid[:, :, pml.zs],
ers,
mrs,
)
pml.calculate_update_coeffs(averageer, averagemr)

查看文件

@@ -63,7 +63,8 @@ def htod_rx_arrays(G, queue=None):
# Array to store field components for receivers on compute device -
# rows are field components; columns are iterations; pages are receivers
rxs = np.zeros(
(len(Rx.allowableoutputs_dev), G.iterations, len(G.rxs)), dtype=config.sim_config.dtypes["float_or_double"]
(len(Rx.allowableoutputs_dev), G.iterations, len(G.rxs)),
dtype=config.sim_config.dtypes["float_or_double"],
)
# Copy arrays to compute device
@@ -102,4 +103,6 @@ def dtoh_rx_array(rxs_dev, rxcoords_dev, G):
and rx.zcoord == rxcoords_dev[rxd, 2]
):
for output in rx.outputs.keys():
rx.outputs[output] = rxs_dev[Rx.allowableoutputs_dev.index(output), :, rxd]
rx.outputs[output] = rxs_dev[
Rx.allowableoutputs_dev.index(output), :, rxd
]

查看文件

@@ -24,8 +24,7 @@ from gprMax.cmds_geometry.add_surface_water import AddSurfaceWater
from gprMax.cmds_geometry.cmds_geometry import UserObjectGeometry
from gprMax.cmds_geometry.fractal_box import FractalBox
from gprMax.cmds_multiuse import UserObjectMulti
from gprMax.cmds_singleuse import (Discretisation, Domain, TimeWindow,
UserObjectSingle)
from gprMax.cmds_singleuse import Discretisation, Domain, TimeWindow, UserObjectSingle
from gprMax.materials import create_built_in_materials
from gprMax.subgrids.user_objects import SubGridBase as SubGridUserBase
from gprMax.user_inputs import create_user_input_points
@@ -106,7 +105,9 @@ class Scene:
# Check for fractal boxes and modifications and pre-process them first
proc_cmds = []
for obj in commands:
if isinstance(obj, (FractalBox, AddGrass, AddSurfaceRoughness, AddSurfaceWater)):
if isinstance(
obj, (FractalBox, AddGrass, AddSurfaceRoughness, AddSurfaceWater)
):
self.build_obj(obj, grid)
if isinstance(obj, (FractalBox)):
proc_cmds.append(obj)

查看文件

@@ -55,7 +55,9 @@ def save_snapshots(grid):
leave=True,
unit="byte",
unit_scale=True,
desc=f"Writing snapshot file {i + 1} " f"of {len(grid.snapshots)}, " f"{snap.filename.name}",
desc=f"Writing snapshot file {i + 1} "
f"of {len(grid.snapshots)}, "
f"{snap.filename.name}",
ncols=get_terminal_width() - 1,
file=sys.stdout,
disable=not config.sim_config.general["progressbars"],
@@ -68,7 +70,14 @@ def save_snapshots(grid):
class Snapshot:
"""Snapshots of the electric and magnetic field values."""
allowableoutputs = {"Ex": None, "Ey": None, "Ez": None, "Hx": None, "Hy": None, "Hz": None}
allowableoutputs = {
"Ex": None,
"Ey": None,
"Ez": None,
"Hx": None,
"Hy": None,
"Hz": None,
}
# Snapshots can be output as VTK ImageData (.vti) format or
# HDF5 format (.h5) files
@@ -136,13 +145,16 @@ class Snapshot:
for k, v in self.outputs.items():
if v:
self.snapfields[k] = np.zeros(
(self.nx, self.ny, self.nz), dtype=config.sim_config.dtypes["float_or_double"]
(self.nx, self.ny, self.nz),
dtype=config.sim_config.dtypes["float_or_double"],
)
self.nbytes += self.snapfields[k].nbytes
else:
# If output is not required for snapshot just use a mimimal
# size of array - still required to pass to Cython function
self.snapfields[k] = np.zeros((1, 1, 1), dtype=config.sim_config.dtypes["float_or_double"])
self.snapfields[k] = np.zeros(
(1, 1, 1), dtype=config.sim_config.dtypes["float_or_double"]
)
def store(self, G):
"""Store (in memory) electric and magnetic field values for snapshot.
@@ -208,11 +220,19 @@ class Snapshot:
G: FDTDGrid class describing a grid in a model.
"""
celldata = {k: self.snapfields[k] for k in ["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"] if self.outputs.get(k)}
celldata = {
k: self.snapfields[k]
for k in ["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"]
if self.outputs.get(k)
}
imageToVTK(
str(self.filename.with_suffix("")),
origin=((self.xs * self.dx * G.dx), (self.ys * self.dy * G.dy), (self.zs * self.dz * G.dz)),
origin=(
(self.xs * self.dx * G.dx),
(self.ys * self.dy * G.dy),
(self.zs * self.dz * G.dz),
),
spacing=((self.dx * G.dx), (self.dy * G.dy), (self.dz * G.dz)),
cellData=celldata,
)
@@ -271,35 +291,52 @@ def htod_snapshot_array(G, queue=None):
if config.sim_config.general["solver"] == "cuda":
# Blocks per grid - according to largest requested snapshot
Snapshot.bpg = (
int(np.ceil(((Snapshot.nx_max) * (Snapshot.ny_max) * (Snapshot.nz_max)) / Snapshot.tpb[0])),
int(
np.ceil(
((Snapshot.nx_max) * (Snapshot.ny_max) * (Snapshot.nz_max))
/ Snapshot.tpb[0]
)
),
1,
1,
)
elif config.sim_config.general["solver"] == "opencl":
# Workgroup size - according to largest requested snapshot
Snapshot.wgs = (int(np.ceil(((Snapshot.nx_max) * (Snapshot.ny_max) * (Snapshot.nz_max)))), 1, 1)
Snapshot.wgs = (
int(np.ceil(((Snapshot.nx_max) * (Snapshot.ny_max) * (Snapshot.nz_max)))),
1,
1,
)
# 4D arrays to store snapshots on GPU, e.g. snapEx(time, x, y, z);
# if snapshots are not being stored on the GPU during the simulation then
# they are copied back to the host after each iteration, hence numsnaps = 1
numsnaps = 1 if config.get_model_config().device["snapsgpu2cpu"] else len(G.snapshots)
numsnaps = (
1 if config.get_model_config().device["snapsgpu2cpu"] else len(G.snapshots)
)
snapEx = np.zeros(
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max), dtype=config.sim_config.dtypes["float_or_double"]
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max),
dtype=config.sim_config.dtypes["float_or_double"],
)
snapEy = np.zeros(
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max), dtype=config.sim_config.dtypes["float_or_double"]
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max),
dtype=config.sim_config.dtypes["float_or_double"],
)
snapEz = np.zeros(
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max), dtype=config.sim_config.dtypes["float_or_double"]
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max),
dtype=config.sim_config.dtypes["float_or_double"],
)
snapHx = np.zeros(
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max), dtype=config.sim_config.dtypes["float_or_double"]
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max),
dtype=config.sim_config.dtypes["float_or_double"],
)
snapHy = np.zeros(
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max), dtype=config.sim_config.dtypes["float_or_double"]
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max),
dtype=config.sim_config.dtypes["float_or_double"],
)
snapHz = np.zeros(
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max), dtype=config.sim_config.dtypes["float_or_double"]
(numsnaps, Snapshot.nx_max, Snapshot.ny_max, Snapshot.nz_max),
dtype=config.sim_config.dtypes["float_or_double"],
)
# Copy arrays to compute device
@@ -326,7 +363,9 @@ def htod_snapshot_array(G, queue=None):
return snapEx_dev, snapEy_dev, snapEz_dev, snapHx_dev, snapHy_dev, snapHz_dev
def dtoh_snapshot_array(snapEx_dev, snapEy_dev, snapEz_dev, snapHx_dev, snapHy_dev, snapHz_dev, i, snap):
def dtoh_snapshot_array(
snapEx_dev, snapEy_dev, snapEz_dev, snapHx_dev, snapHy_dev, snapHz_dev, i, snap
):
"""Copies snapshot array used on compute device back to snapshot objects and
store in format for Paraview.
@@ -336,9 +375,21 @@ def dtoh_snapshot_array(snapEx_dev, snapEy_dev, snapEz_dev, snapHx_dev, snapHy_d
snap: Snapshot class instance
"""
snap.snapfields["Ex"] = snapEx_dev[i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf]
snap.snapfields["Ey"] = snapEy_dev[i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf]
snap.snapfields["Ez"] = snapEz_dev[i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf]
snap.snapfields["Hx"] = snapHx_dev[i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf]
snap.snapfields["Hy"] = snapHy_dev[i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf]
snap.snapfields["Hz"] = snapHz_dev[i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf]
snap.snapfields["Ex"] = snapEx_dev[
i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf
]
snap.snapfields["Ey"] = snapEy_dev[
i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf
]
snap.snapfields["Ez"] = snapEz_dev[
i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf
]
snap.snapfields["Hx"] = snapHx_dev[
i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf
]
snap.snapfields["Hy"] = snapHy_dev[
i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf
]
snap.snapfields["Hz"] = snapHz_dev[
i, snap.xs : snap.xf, snap.ys : snap.yf, snap.zs : snap.zf
]

查看文件

@@ -42,7 +42,7 @@ class Source:
self.stop = None
self.waveformID = None
# Waveform values for sources that need to be calculated on whole timesteps
self.waveformvalues_wholedt = None
self.waveformvalues_wholedt = None
# Waveform values for sources that need to be calculated on half timesteps
self.waveformvalues_halfdt = None
@@ -66,7 +66,7 @@ class VoltageSource(Source):
"""
# Check if a source matches existing source in terms of waveform and
# does not have a customised start/stop time. If so, use its
# does not have a customised start/stop time. If so, use its
# pre-calculated waveform values, otherwise calculate them.
src_match = False
@@ -77,8 +77,10 @@ class VoltageSource(Source):
self.waveformvalues_wholedt = src.waveformvalues_wholedt
if not src_match:
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
self.waveformvalues_wholedt = np.zeros((G.iterations), dtype=config.sim_config.dtypes["float_or_double"])
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
self.waveformvalues_wholedt = np.zeros(
(G.iterations), dtype=config.sim_config.dtypes["float_or_double"]
)
for iteration in range(G.iterations):
time = G.dt * iteration
@@ -86,7 +88,9 @@ class VoltageSource(Source):
# Set the time of the waveform evaluation to account for any
# delay in the start
time -= self.start
self.waveformvalues_wholedt[iteration] = waveform.calculate_value(time, G.dt)
self.waveformvalues_wholedt[iteration] = waveform.calculate_value(
time, G.dt
)
def update_electric(self, iteration, updatecoeffsE, ID, Ex, Ey, Ez, G):
"""Updates electric field values for a voltage source.
@@ -158,7 +162,9 @@ class VoltageSource(Source):
newmaterial.ID = f"{material.ID}+{self.ID}"
newmaterial.numID = len(G.materials)
newmaterial.averagable = False
newmaterial.type += ",\nvoltage-source" if newmaterial.type else "voltage-source"
newmaterial.type += (
",\nvoltage-source" if newmaterial.type else "voltage-source"
)
# Add conductivity of voltage source to underlying conductivity
if self.polarisation == "x":
@@ -187,7 +193,7 @@ class HertzianDipole(Source):
"""
# Check if a source matches existing source in terms of waveform and
# does not have a customised start/stop time. If so, use its
# does not have a customised start/stop time. If so, use its
# pre-calculated waveform values, otherwise calculate them.
src_match = False
@@ -198,8 +204,10 @@ class HertzianDipole(Source):
self.waveformvalues_halfdt = src.waveformvalues_halfdt
if not src_match:
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
self.waveformvalues_halfdt = np.zeros((G.iterations), dtype=config.sim_config.dtypes["float_or_double"])
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
self.waveformvalues_halfdt = np.zeros(
(G.iterations), dtype=config.sim_config.dtypes["float_or_double"]
)
for iteration in range(G.iterations):
time = G.dt * iteration
@@ -207,7 +215,9 @@ class HertzianDipole(Source):
# Set the time of the waveform evaluation to account for any
# delay in the start
time -= self.start
self.waveformvalues_halfdt[iteration] = waveform.calculate_value(time + 0.5 * G.dt, G.dt)
self.waveformvalues_halfdt[iteration] = waveform.calculate_value(
time + 0.5 * G.dt, G.dt
)
def update_electric(self, iteration, updatecoeffsE, ID, Ex, Ey, Ez, G):
"""Updates electric field values for a Hertzian dipole.
@@ -263,7 +273,7 @@ class MagneticDipole(Source):
"""
# Check if a source matches existing source in terms of waveform and
# does not have a customised start/stop time. If so, use its
# does not have a customised start/stop time. If so, use its
# pre-calculated waveform values, otherwise calculate them.
src_match = False
@@ -274,8 +284,10 @@ class MagneticDipole(Source):
self.waveformvalues_wholedt = src.waveformvalues_wholedt
if not src_match:
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
self.waveformvalues_wholedt = np.zeros((G.iterations), dtype=config.sim_config.dtypes["float_or_double"])
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
self.waveformvalues_wholedt = np.zeros(
(G.iterations), dtype=config.sim_config.dtypes["float_or_double"]
)
for iteration in range(G.iterations):
time = G.dt * iteration
@@ -283,7 +295,9 @@ class MagneticDipole(Source):
# Set the time of the waveform evaluation to account for any
# delay in the start
time -= self.start
self.waveformvalues_wholedt[iteration] = waveform.calculate_value(time, G.dt)
self.waveformvalues_wholedt[iteration] = waveform.calculate_value(
time, G.dt
)
def update_magnetic(self, iteration, updatecoeffsH, ID, Hx, Hy, Hz, G):
"""Updates magnetic field values for a magnetic dipole.
@@ -344,8 +358,12 @@ def htod_src_arrays(sources, G, queue=None):
"""
srcinfo1 = np.zeros((len(sources), 4), dtype=np.int32)
srcinfo2 = np.zeros((len(sources)), dtype=config.sim_config.dtypes["float_or_double"])
srcwaves = np.zeros((len(sources), G.iterations), dtype=config.sim_config.dtypes["float_or_double"])
srcinfo2 = np.zeros(
(len(sources)), dtype=config.sim_config.dtypes["float_or_double"]
)
srcwaves = np.zeros(
(len(sources), G.iterations), dtype=config.sim_config.dtypes["float_or_double"]
)
for i, src in enumerate(sources):
srcinfo1[i, 0] = src.xcoord
srcinfo1[i, 1] = src.ycoord
@@ -422,12 +440,24 @@ class TransmissionLine(Source):
# Cell position of where line connects to antenna/main grid
self.antpos = 10
self.voltage = np.zeros(self.nl, dtype=config.sim_config.dtypes["float_or_double"])
self.current = np.zeros(self.nl, dtype=config.sim_config.dtypes["float_or_double"])
self.Vinc = np.zeros(G.iterations, dtype=config.sim_config.dtypes["float_or_double"])
self.Iinc = np.zeros(G.iterations, dtype=config.sim_config.dtypes["float_or_double"])
self.Vtotal = np.zeros(G.iterations, dtype=config.sim_config.dtypes["float_or_double"])
self.Itotal = np.zeros(G.iterations, dtype=config.sim_config.dtypes["float_or_double"])
self.voltage = np.zeros(
self.nl, dtype=config.sim_config.dtypes["float_or_double"]
)
self.current = np.zeros(
self.nl, dtype=config.sim_config.dtypes["float_or_double"]
)
self.Vinc = np.zeros(
G.iterations, dtype=config.sim_config.dtypes["float_or_double"]
)
self.Iinc = np.zeros(
G.iterations, dtype=config.sim_config.dtypes["float_or_double"]
)
self.Vtotal = np.zeros(
G.iterations, dtype=config.sim_config.dtypes["float_or_double"]
)
self.Itotal = np.zeros(
G.iterations, dtype=config.sim_config.dtypes["float_or_double"]
)
def calculate_waveform_values(self, G):
"""Calculates all waveform values for source for duration of simulation.
@@ -437,7 +467,7 @@ class TransmissionLine(Source):
"""
# Check if a source matches existing source in terms of waveform and
# does not have a customised start/stop time. If so, use its
# does not have a customised start/stop time. If so, use its
# pre-calculated waveform values, otherwise calculate them.
src_match = False
@@ -449,9 +479,13 @@ class TransmissionLine(Source):
self.waveformvalues_halfdt = src.waveformvalues_halfdt
if not src_match:
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
self.waveformvalues_wholedt = np.zeros((G.iterations), dtype=config.sim_config.dtypes["float_or_double"])
self.waveformvalues_halfdt = np.zeros((G.iterations), dtype=config.sim_config.dtypes["float_or_double"])
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
self.waveformvalues_wholedt = np.zeros(
(G.iterations), dtype=config.sim_config.dtypes["float_or_double"]
)
self.waveformvalues_halfdt = np.zeros(
(G.iterations), dtype=config.sim_config.dtypes["float_or_double"]
)
for iteration in range(G.iterations):
time = G.dt * iteration
@@ -459,8 +493,12 @@ class TransmissionLine(Source):
# Set the time of the waveform evaluation to account for any
# delay in the start
time -= self.start
self.waveformvalues_wholedt[iteration] = waveform.calculate_value(time, G.dt)
self.waveformvalues_halfdt[iteration] = waveform.calculate_value(time + 0.5 * G.dt, G.dt)
self.waveformvalues_wholedt[iteration] = waveform.calculate_value(
time, G.dt
)
self.waveformvalues_halfdt[iteration] = waveform.calculate_value(
time + 0.5 * G.dt, G.dt
)
def calculate_incident_V_I(self, G):
"""Calculates the incident voltage and current with a long length
@@ -503,11 +541,15 @@ class TransmissionLine(Source):
# Update all the voltage values along the line
self.voltage[1 : self.nl] -= (
self.resistance * (config.c * G.dt / self.dl) * (self.current[1 : self.nl] - self.current[0 : self.nl - 1])
self.resistance
* (config.c * G.dt / self.dl)
* (self.current[1 : self.nl] - self.current[0 : self.nl - 1])
)
# Update the voltage at the position of the one-way injector excitation
self.voltage[self.srcpos] += (config.c * G.dt / self.dl) * self.waveformvalues_halfdt[iteration]
self.voltage[self.srcpos] += (
config.c * G.dt / self.dl
) * self.waveformvalues_halfdt[iteration]
# Update ABC before updating current
self.update_abc(G)
@@ -529,7 +571,9 @@ class TransmissionLine(Source):
# Update the current one cell before the position of the one-way injector excitation
self.current[self.srcpos - 1] += (
(1 / self.resistance) * (config.c * G.dt / self.dl) * self.waveformvalues_wholedt[iteration]
(1 / self.resistance)
* (config.c * G.dt / self.dl)
* self.waveformvalues_wholedt[iteration]
)
def update_electric(self, iteration, updatecoeffsE, ID, Ex, Ey, Ez, G):

查看文件

@@ -233,7 +233,9 @@ class PrecursorNodesBase:
def interpolate_to_sub_grid(self, field, coords):
x, z, x_sg, z_sg = coords
interp_f = interpolate.RectBivariateSpline(x, z, field, kx=self.interpolation, ky=self.interpolation)
interp_f = interpolate.RectBivariateSpline(
x, z, field, kx=self.interpolation, ky=self.interpolation
)
f_i = interp_f(x_sg, z_sg)
return f_i
@@ -417,18 +419,78 @@ class PrecursorNodes(PrecursorNodesBase):
# Spatially interpolate nodes
slices = [
["ex_front_1", True, (slice(i0, i1, 1), self.j0, slice(k0, k1 + 1, 1)), self.Ex],
["ex_back_1", True, (slice(i0, i1, 1), self.j1, slice(k0, k1 + 1, 1)), self.Ex],
["ez_front_1", False, (slice(i0, i1 + 1, 1), self.j0, slice(k0, k1, 1)), self.Ez],
["ez_back_1", False, (slice(i0, i1 + 1, 1), self.j1, slice(k0, k1, 1)), self.Ez],
["ey_left_1", True, (self.i0, slice(j0, j1, 1), slice(k0, k1 + 1, 1)), self.Ey],
["ey_right_1", True, (self.i1, slice(j0, j1, 1), slice(k0, k1 + 1, 1)), self.Ey],
["ez_left_1", False, (self.i0, slice(j0, j1 + 1, 1), slice(k0, k1, 1)), self.Ez],
["ez_right_1", False, (self.i1, slice(j0, j1 + 1, 1), slice(k0, k1, 1)), self.Ez],
["ex_bottom_1", True, (slice(i0, i1, 1), slice(j0, j1 + 1, 1), self.k0), self.Ex],
["ex_top_1", True, (slice(i0, i1, 1), slice(j0, j1 + 1, 1), self.k1), self.Ex],
["ey_bottom_1", False, (slice(i0, i1 + 1, 1), slice(j0, j1, 1), self.k0), self.Ey],
["ey_top_1", False, (slice(i0, i1 + 1, 1), slice(j0, j1, 1), self.k1), self.Ey],
[
"ex_front_1",
True,
(slice(i0, i1, 1), self.j0, slice(k0, k1 + 1, 1)),
self.Ex,
],
[
"ex_back_1",
True,
(slice(i0, i1, 1), self.j1, slice(k0, k1 + 1, 1)),
self.Ex,
],
[
"ez_front_1",
False,
(slice(i0, i1 + 1, 1), self.j0, slice(k0, k1, 1)),
self.Ez,
],
[
"ez_back_1",
False,
(slice(i0, i1 + 1, 1), self.j1, slice(k0, k1, 1)),
self.Ez,
],
[
"ey_left_1",
True,
(self.i0, slice(j0, j1, 1), slice(k0, k1 + 1, 1)),
self.Ey,
],
[
"ey_right_1",
True,
(self.i1, slice(j0, j1, 1), slice(k0, k1 + 1, 1)),
self.Ey,
],
[
"ez_left_1",
False,
(self.i0, slice(j0, j1 + 1, 1), slice(k0, k1, 1)),
self.Ez,
],
[
"ez_right_1",
False,
(self.i1, slice(j0, j1 + 1, 1), slice(k0, k1, 1)),
self.Ez,
],
[
"ex_bottom_1",
True,
(slice(i0, i1, 1), slice(j0, j1 + 1, 1), self.k0),
self.Ex,
],
[
"ex_top_1",
True,
(slice(i0, i1, 1), slice(j0, j1 + 1, 1), self.k1),
self.Ex,
],
[
"ey_bottom_1",
False,
(slice(i0, i1 + 1, 1), slice(j0, j1, 1), self.k0),
self.Ey,
],
[
"ey_top_1",
False,
(slice(i0, i1 + 1, 1), slice(j0, j1, 1), self.k1),
self.Ey,
],
]
for obj in slices:

查看文件

@@ -20,7 +20,11 @@ import logging
import gprMax.config as config
from ..cython.fields_updates_hsg import update_electric_os, update_is, update_magnetic_os
from ..cython.fields_updates_hsg import (
update_electric_os,
update_is,
update_magnetic_os,
)
from .grid import SubGridBaseGrid
logger = logging.getLogger(__name__)
@@ -673,16 +677,27 @@ class SubGridHSG(SubGridBaseGrid):
# Working region
xs, ys, zs = self.round_to_grid(
(self.i0 * self.dx * self.ratio, self.j0 * self.dy * self.ratio, self.k0 * self.dz * self.ratio)
(
self.i0 * self.dx * self.ratio,
self.j0 * self.dy * self.ratio,
self.k0 * self.dz * self.ratio,
)
)
xf, yf, zf = self.round_to_grid(
(self.i1 * self.dx * self.ratio, self.j1 * self.dy * self.ratio, self.k1 * self.dz * self.ratio)
(
self.i1 * self.dx * self.ratio,
self.j1 * self.dy * self.ratio,
self.k1 * self.dz * self.ratio,
)
)
logger.info("")
logger.debug(f"[{self.name}] Type: {self.__class__.__name__}")
logger.info(f"[{self.name}] Ratio: 1:{self.ratio}")
logger.info(f"[{self.name}] Spatial discretisation: {self.dx:g} x " + f"{self.dy:g} x {self.dz:g}m")
logger.info(
f"[{self.name}] Spatial discretisation: {self.dx:g} x "
+ f"{self.dy:g} x {self.dz:g}m"
)
logger.info(
f"[{self.name}] Extent (working region): {xs}m, {ys}m, {zs}m to {xf}m, {yf}m, {zf}m "
+ f"(({self.nwx} x {self.nwy} x {self.nwz} = {self.nwx * self.nwy * self.nwz} cells)"

查看文件

@@ -131,7 +131,9 @@ class SubGridBase(UserObjectMulti):
# Don't mix and match different subgrid types
for sg_made in grid.subgrids:
if type(sg) != type(sg_made):
logger.exception(f"{self.__str__()} please only use one type of subgrid")
logger.exception(
f"{self.__str__()} please only use one type of subgrid"
)
raise ValueError
# Reference the subgrid under the main grid to which it belongs

查看文件

@@ -25,12 +25,14 @@ from jinja2 import Environment, PackageLoader
import gprMax.config as config
from .cuda_opencl import (knl_fields_updates, knl_snapshots,
knl_source_updates, knl_store_outputs)
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 .cuda_opencl import (
knl_fields_updates,
knl_snapshots,
knl_source_updates,
knl_store_outputs,
)
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 .receivers import dtoh_rx_array, htod_rx_arrays
from .snapshots import Snapshot, dtoh_snapshot_array, htod_snapshot_array
@@ -151,7 +153,11 @@ class CPUUpdates:
"""Updates electric field components from sources -
update any Hertzian dipole sources last.
"""
for source in self.grid.voltagesources + self.grid.transmissionlines + self.grid.hertziandipoles:
for source in (
self.grid.voltagesources
+ self.grid.transmissionlines
+ self.grid.hertziandipoles
):
source.update_electric(
self.grid.iteration,
self.grid.updatecoeffsE,
@@ -191,10 +197,13 @@ class CPUUpdates:
"""Sets dispersive update functions."""
poles = "multi" if config.get_model_config().materials["maxpoles"] > 1 else "1"
precision = "float" if config.sim_config.general["precision"] == "single" else "double"
precision = (
"float" if config.sim_config.general["precision"] == "single" else "double"
)
dispersion = (
"complex"
if config.get_model_config().materials["dispersivedtype"] == config.sim_config.dtypes["complex"]
if config.get_model_config().materials["dispersivedtype"]
== config.sim_config.dtypes["complex"]
else "real"
)
@@ -202,8 +211,12 @@ class CPUUpdates:
disp_a = update_f.format(poles, "A", precision, dispersion)
disp_b = update_f.format(poles, "B", precision, dispersion)
disp_a_f = getattr(import_module("gprMax.cython.fields_updates_dispersive"), disp_a)
disp_b_f = getattr(import_module("gprMax.cython.fields_updates_dispersive"), disp_b)
disp_a_f = getattr(
import_module("gprMax.cython.fields_updates_dispersive"), disp_a
)
disp_b_f = getattr(
import_module("gprMax.cython.fields_updates_dispersive"), disp_b
)
self.dispersive_update_a = disp_a_f
self.dispersive_update_b = disp_b_f
@@ -271,7 +284,11 @@ class CUDAUpdates:
self._set_pml_knls()
if self.grid.rxs:
self._set_rx_knl()
if self.grid.voltagesources + self.grid.hertziandipoles + self.grid.magneticdipoles:
if (
self.grid.voltagesources
+ self.grid.hertziandipoles
+ self.grid.magneticdipoles
):
self._set_src_knls()
if self.grid.snapshots:
self._set_snapshot_knl()
@@ -344,11 +361,15 @@ class CUDAUpdates:
gets kernel functions.
"""
bld = self._build_knl(knl_fields_updates.update_electric, self.subs_name_args, self.subs_func)
bld = self._build_knl(
knl_fields_updates.update_electric, self.subs_name_args, self.subs_func
)
knlE = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
self.update_electric_dev = knlE.get_function("update_electric")
bld = self._build_knl(knl_fields_updates.update_magnetic, self.subs_name_args, self.subs_func)
bld = self._build_knl(
knl_fields_updates.update_magnetic, self.subs_name_args, self.subs_func
)
knlH = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
self.update_magnetic_dev = knlH.get_function("update_magnetic")
@@ -367,13 +388,25 @@ class CUDAUpdates:
}
)
bld = self._build_knl(knl_fields_updates.update_electric_dispersive_A, self.subs_name_args, self.subs_func)
knl = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
bld = self._build_knl(
knl_fields_updates.update_electric_dispersive_A,
self.subs_name_args,
self.subs_func,
)
knl = self.source_module(
bld, options=config.sim_config.devices["nvcc_opts"]
)
self.dispersive_update_a = knl.get_function("update_electric_dispersive_A")
self._copy_mat_coeffs(knl, knl)
bld = self._build_knl(knl_fields_updates.update_electric_dispersive_B, self.subs_name_args, self.subs_func)
knl = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
bld = self._build_knl(
knl_fields_updates.update_electric_dispersive_B,
self.subs_name_args,
self.subs_func,
)
knl = self.source_module(
bld, options=config.sim_config.devices["nvcc_opts"]
)
self.dispersive_update_b = knl.get_function("update_electric_dispersive_B")
self._copy_mat_coeffs(knl, knl)
@@ -387,10 +420,12 @@ class CUDAUpdates:
def _set_pml_knls(self):
"""PMLS - prepares kernels and gets kernel functions."""
knl_pml_updates_electric = import_module(
"gprMax.cuda_opencl.knl_pml_updates_electric_" + self.grid.pmls["formulation"]
"gprMax.cuda_opencl.knl_pml_updates_electric_"
+ self.grid.pmls["formulation"]
)
knl_pml_updates_magnetic = import_module(
"gprMax.cuda_opencl.knl_pml_updates_magnetic_" + self.grid.pmls["formulation"]
"gprMax.cuda_opencl.knl_pml_updates_magnetic_"
+ self.grid.pmls["formulation"]
)
# Initialise arrays on GPU, set block per grid, and get kernel functions
@@ -402,12 +437,16 @@ class CUDAUpdates:
knl_electric = getattr(knl_pml_updates_electric, knl_name)
bld = self._build_knl(knl_electric, self.subs_name_args, self.subs_func)
knlE = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
knlE = self.source_module(
bld, options=config.sim_config.devices["nvcc_opts"]
)
pml.update_electric_dev = knlE.get_function(knl_name)
knl_magnetic = getattr(knl_pml_updates_magnetic, knl_name)
bld = self._build_knl(knl_magnetic, self.subs_name_args, self.subs_func)
knlH = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
knlH = self.source_module(
bld, options=config.sim_config.devices["nvcc_opts"]
)
pml.update_magnetic_dev = knlH.get_function(knl_name)
# Copy material coefficient arrays to constant memory of GPU - must
@@ -430,7 +469,9 @@ class CUDAUpdates:
}
)
bld = self._build_knl(knl_store_outputs.store_outputs, self.subs_name_args, self.subs_func)
bld = self._build_knl(
knl_store_outputs.store_outputs, self.subs_name_args, self.subs_func
)
knl = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
self.store_outputs_dev = knl.get_function("store_outputs")
@@ -441,25 +482,49 @@ class CUDAUpdates:
self.subs_func.update({"NY_SRCINFO": 4, "NY_SRCWAVES": self.grid.iteration})
if self.grid.hertziandipoles:
self.srcinfo1_hertzian_dev, self.srcinfo2_hertzian_dev, self.srcwaves_hertzian_dev = htod_src_arrays(
self.grid.hertziandipoles, self.grid
(
self.srcinfo1_hertzian_dev,
self.srcinfo2_hertzian_dev,
self.srcwaves_hertzian_dev,
) = htod_src_arrays(self.grid.hertziandipoles, self.grid)
bld = self._build_knl(
knl_source_updates.update_hertzian_dipole,
self.subs_name_args,
self.subs_func,
)
knl = self.source_module(
bld, options=config.sim_config.devices["nvcc_opts"]
)
bld = self._build_knl(knl_source_updates.update_hertzian_dipole, self.subs_name_args, self.subs_func)
knl = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
self.update_hertzian_dipole_dev = knl.get_function("update_hertzian_dipole")
if self.grid.magneticdipoles:
self.srcinfo1_magnetic_dev, self.srcinfo2_magnetic_dev, self.srcwaves_magnetic_dev = htod_src_arrays(
self.grid.magneticdipoles, self.grid
(
self.srcinfo1_magnetic_dev,
self.srcinfo2_magnetic_dev,
self.srcwaves_magnetic_dev,
) = htod_src_arrays(self.grid.magneticdipoles, self.grid)
bld = self._build_knl(
knl_source_updates.update_magnetic_dipole,
self.subs_name_args,
self.subs_func,
)
knl = self.source_module(
bld, options=config.sim_config.devices["nvcc_opts"]
)
bld = self._build_knl(knl_source_updates.update_magnetic_dipole, self.subs_name_args, self.subs_func)
knl = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
self.update_magnetic_dipole_dev = knl.get_function("update_magnetic_dipole")
if self.grid.voltagesources:
self.srcinfo1_voltage_dev, self.srcinfo2_voltage_dev, self.srcwaves_voltage_dev = htod_src_arrays(
self.grid.voltagesources, self.grid
(
self.srcinfo1_voltage_dev,
self.srcinfo2_voltage_dev,
self.srcwaves_voltage_dev,
) = htod_src_arrays(self.grid.voltagesources, self.grid)
bld = self._build_knl(
knl_source_updates.update_voltage_source,
self.subs_name_args,
self.subs_func,
)
knl = self.source_module(
bld, options=config.sim_config.devices["nvcc_opts"]
)
bld = self._build_knl(knl_source_updates.update_voltage_source, self.subs_name_args, self.subs_func)
knl = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
self.update_voltage_source_dev = knl.get_function("update_voltage_source")
self._copy_mat_coeffs(knl, knl)
@@ -486,7 +551,9 @@ class CUDAUpdates:
}
)
bld = self._build_knl(knl_snapshots.store_snapshot, self.subs_name_args, self.subs_func)
bld = self._build_knl(
knl_snapshots.store_snapshot, self.subs_name_args, self.subs_func
)
knl = self.source_module(bld, options=config.sim_config.devices["nvcc_opts"])
self.store_snapshot_dev = knl.get_function("store_snapshot")
@@ -805,12 +872,16 @@ class OpenCLUpdates:
# Import pyopencl module
self.cl = import_module("pyopencl")
self.elwiseknl = getattr(import_module("pyopencl.elementwise"), "ElementwiseKernel")
self.elwiseknl = getattr(
import_module("pyopencl.elementwise"), "ElementwiseKernel"
)
# Select device, create context and command queue
self.dev = config.get_model_config().device["dev"]
self.ctx = self.cl.Context(devices=[self.dev])
self.queue = self.cl.CommandQueue(self.ctx, properties=self.cl.command_queue_properties.PROFILING_ENABLE)
self.queue = self.cl.CommandQueue(
self.ctx, properties=self.cl.command_queue_properties.PROFILING_ENABLE
)
# Enviroment for templating kernels
self.env = Environment(loader=PackageLoader("gprMax", "cuda_opencl"))
@@ -822,7 +893,11 @@ class OpenCLUpdates:
self._set_pml_knls()
if self.grid.rxs:
self._set_rx_knl()
if self.grid.voltagesources + self.grid.hertziandipoles + self.grid.magneticdipoles:
if (
self.grid.voltagesources
+ self.grid.hertziandipoles
+ self.grid.magneticdipoles
):
self._set_src_knls()
if self.grid.snapshots:
self._set_snapshot_knl()
@@ -872,7 +947,7 @@ class OpenCLUpdates:
def _set_field_knls(self):
"""Electric and magnetic field updates - prepares kernels, and
gets kernel functions.
gets kernel functions.
"""
subs = {
@@ -884,7 +959,7 @@ class OpenCLUpdates:
"NY_ID": self.grid.ID.shape[2],
"NZ_ID": self.grid.ID.shape[3],
}
self.update_electric_dev = self.elwiseknl(
self.ctx,
knl_fields_updates.update_electric["args_opencl"].substitute(
@@ -924,30 +999,42 @@ class OpenCLUpdates:
"NY_T": self.grid.Tx.shape[2],
"NZ_T": self.grid.Tx.shape[3],
}
self.dispersive_update_a = self.elwiseknl(
self.ctx,
knl_fields_updates.update_electric_dispersive_A["args_opencl"].substitute(
knl_fields_updates.update_electric_dispersive_A[
"args_opencl"
].substitute(
{
"REAL": config.sim_config.dtypes["C_float_or_double"],
"COMPLEX": config.get_model_config().materials["dispersiveCdtype"],
"COMPLEX": config.get_model_config().materials[
"dispersiveCdtype"
],
}
),
knl_fields_updates.update_electric_dispersive_A["func"].substitute(subs),
knl_fields_updates.update_electric_dispersive_A["func"].substitute(
subs
),
"update_electric_dispersive_A",
preamble=self.knl_common,
options=config.sim_config.devices["compiler_opts"],
)
self.dispersive_update_b = self.elwiseknl(
self.ctx,
knl_fields_updates.update_electric_dispersive_B["args_opencl"].substitute(
knl_fields_updates.update_electric_dispersive_B[
"args_opencl"
].substitute(
{
"REAL": config.sim_config.dtypes["C_float_or_double"],
"COMPLEX": config.get_model_config().materials["dispersiveCdtype"],
"COMPLEX": config.get_model_config().materials[
"dispersiveCdtype"
],
}
),
knl_fields_updates.update_electric_dispersive_B["func"].substitute(subs),
knl_fields_updates.update_electric_dispersive_B["func"].substitute(
subs
),
"update_electric_dispersive_B",
preamble=self.knl_common,
options=config.sim_config.devices["compiler_opts"],
@@ -962,10 +1049,12 @@ class OpenCLUpdates:
def _set_pml_knls(self):
"""PMLS - prepares kernels and gets kernel functions."""
knl_pml_updates_electric = import_module(
"gprMax.cuda_opencl.knl_pml_updates_electric_" + self.grid.pmls["formulation"]
"gprMax.cuda_opencl.knl_pml_updates_electric_"
+ self.grid.pmls["formulation"]
)
knl_pml_updates_magnetic = import_module(
"gprMax.cuda_opencl.knl_pml_updates_magnetic_" + self.grid.pmls["formulation"]
"gprMax.cuda_opencl.knl_pml_updates_magnetic_"
+ self.grid.pmls["formulation"]
)
subs = {
@@ -990,7 +1079,9 @@ class OpenCLUpdates:
pml.update_electric_dev = self.elwiseknl(
self.ctx,
knl_electric_name["args_opencl"].substitute({"REAL": config.sim_config.dtypes["C_float_or_double"]}),
knl_electric_name["args_opencl"].substitute(
{"REAL": config.sim_config.dtypes["C_float_or_double"]}
),
knl_electric_name["func"].substitute(subs),
f"pml_updates_electric_{knl_name}",
preamble=self.knl_common,
@@ -999,7 +1090,9 @@ class OpenCLUpdates:
pml.update_magnetic_dev = self.elwiseknl(
self.ctx,
knl_magnetic_name["args_opencl"].substitute({"REAL": config.sim_config.dtypes["C_float_or_double"]}),
knl_magnetic_name["args_opencl"].substitute(
{"REAL": config.sim_config.dtypes["C_float_or_double"]}
),
knl_magnetic_name["func"].substitute(subs),
f"pml_updates_magnetic_{knl_name}",
preamble=self.knl_common,
@@ -1027,48 +1120,63 @@ class OpenCLUpdates:
gets kernel function.
"""
if self.grid.hertziandipoles:
self.srcinfo1_hertzian_dev, self.srcinfo2_hertzian_dev, self.srcwaves_hertzian_dev = htod_src_arrays(
self.grid.hertziandipoles, self.grid, self.queue
)
(
self.srcinfo1_hertzian_dev,
self.srcinfo2_hertzian_dev,
self.srcwaves_hertzian_dev,
) = htod_src_arrays(self.grid.hertziandipoles, self.grid, self.queue)
self.update_hertzian_dipole_dev = self.elwiseknl(
self.ctx,
knl_source_updates.update_hertzian_dipole["args_opencl"].substitute(
{"REAL": config.sim_config.dtypes["C_float_or_double"]}
),
knl_source_updates.update_hertzian_dipole["func"].substitute(
{"CUDA_IDX": "", "REAL": config.sim_config.dtypes["C_float_or_double"]}
{
"CUDA_IDX": "",
"REAL": config.sim_config.dtypes["C_float_or_double"],
}
),
"update_hertzian_dipole",
preamble=self.knl_common,
options=config.sim_config.devices["compiler_opts"],
)
if self.grid.magneticdipoles:
self.srcinfo1_magnetic_dev, self.srcinfo2_magnetic_dev, self.srcwaves_magnetic_dev = htod_src_arrays(
self.grid.magneticdipoles, self.grid, self.queue
)
(
self.srcinfo1_magnetic_dev,
self.srcinfo2_magnetic_dev,
self.srcwaves_magnetic_dev,
) = htod_src_arrays(self.grid.magneticdipoles, self.grid, self.queue)
self.update_magnetic_dipole_dev = self.elwiseknl(
self.ctx,
knl_source_updates.update_magnetic_dipole["args_opencl"].substitute(
{"REAL": config.sim_config.dtypes["C_float_or_double"]}
),
knl_source_updates.update_magnetic_dipole["func"].substitute(
{"CUDA_IDX": "", "REAL": config.sim_config.dtypes["C_float_or_double"]}
{
"CUDA_IDX": "",
"REAL": config.sim_config.dtypes["C_float_or_double"],
}
),
"update_magnetic_dipole",
preamble=self.knl_common,
options=config.sim_config.devices["compiler_opts"],
)
if self.grid.voltagesources:
self.srcinfo1_voltage_dev, self.srcinfo2_voltage_dev, self.srcwaves_voltage_dev = htod_src_arrays(
self.grid.voltagesources, self.grid, self.queue
)
(
self.srcinfo1_voltage_dev,
self.srcinfo2_voltage_dev,
self.srcwaves_voltage_dev,
) = htod_src_arrays(self.grid.voltagesources, self.grid, self.queue)
self.update_voltage_source_dev = self.elwiseknl(
self.ctx,
knl_source_updates.update_voltage_source["args_opencl"].substitute(
{"REAL": config.sim_config.dtypes["C_float_or_double"]}
),
knl_source_updates.update_voltage_source["func"].substitute(
{"CUDA_IDX": "", "REAL": config.sim_config.dtypes["C_float_or_double"]}
{
"CUDA_IDX": "",
"REAL": config.sim_config.dtypes["C_float_or_double"],
}
),
"update_voltage_source",
preamble=self.knl_common,
@@ -1093,7 +1201,12 @@ class OpenCLUpdates:
{"REAL": config.sim_config.dtypes["C_float_or_double"]}
),
knl_snapshots.store_snapshot["func"].substitute(
{"CUDA_IDX": "", "NX_SNAPS": Snapshot.nx_max, "NY_SNAPS": Snapshot.ny_max, "NZ_SNAPS": Snapshot.nz_max}
{
"CUDA_IDX": "",
"NX_SNAPS": Snapshot.nx_max,
"NY_SNAPS": Snapshot.ny_max,
"NZ_SNAPS": Snapshot.nz_max,
}
),
"store_snapshot",
preamble=self.knl_common,
@@ -1238,7 +1351,7 @@ class OpenCLUpdates:
self.grid.Ty_dev,
self.grid.Tz_dev,
)
def update_electric_pml(self):
"""Updates electric field components with the PML correction."""
for pml in self.grid.pmls["slabs"]:
@@ -1311,7 +1424,7 @@ class OpenCLUpdates:
self.event_marker1.wait()
def calculate_memory_used(self, iteration):
"""Calculates memory used on last iteration.
"""Calculates memory used on last iteration.
Args:
iteration: int for iteration number.

查看文件

@@ -108,7 +108,9 @@ class MainGridUserInput(UserInput):
p = self.check_point(p, cmd_str, name)
if self.grid.within_pml(p):
logger.warning(f"'{cmd_str}' sources and receivers should not normally be positioned within the PML.")
logger.warning(
f"'{cmd_str}' sources and receivers should not normally be positioned within the PML."
)
return p
@@ -117,7 +119,9 @@ class MainGridUserInput(UserInput):
p2 = self.check_point(p2, cmd_str, name="upper")
if np.greater(p1, p2).any():
logger.exception(f"'{cmd_str}' the lower coordinates should be less than the upper coordinates.")
logger.exception(
f"'{cmd_str}' the lower coordinates should be less than the upper coordinates."
)
raise ValueError
return p1, p2
@@ -152,7 +156,9 @@ class SubgridUserInput(MainGridUserInput):
super().__init__(grid)
# Defines the region exposed to the user
self.inner_bound = np.array([grid.n_boundary_cells_x, grid.n_boundary_cells_y, grid.n_boundary_cells_z])
self.inner_bound = np.array(
[grid.n_boundary_cells_x, grid.n_boundary_cells_y, grid.n_boundary_cells_z]
)
self.outer_bound = np.subtract([grid.nx, grid.ny, grid.nz], self.inner_bound)
@@ -185,8 +191,13 @@ class SubgridUserInput(MainGridUserInput):
# Provide user within a warning if they have placed objects within
# the OS non-working region.
if np.less(p_t, self.inner_bound).any() or np.greater(p_t, self.outer_bound).any():
logger.warning(f"'{cmd_str}' this object traverses the Outer Surface. This is an advanced feature.")
if (
np.less(p_t, self.inner_bound).any()
or np.greater(p_t, self.outer_bound).any()
):
logger.warning(
f"'{cmd_str}' this object traverses the Outer Surface. This is an advanced feature."
)
return p_t
def discretise_static_point(self, p):

查看文件

@@ -66,7 +66,13 @@ class Waveform:
waveforms.
"""
if self.type in ["gaussian", "gaussiandot", "gaussiandotnorm", "gaussianprime", "gaussiandoubleprime"]:
if self.type in [
"gaussian",
"gaussiandot",
"gaussiandotnorm",
"gaussianprime",
"gaussiandoubleprime",
]:
self.chi = 1 / self.freq
self.zeta = 2 * np.pi**2 * self.freq**2
elif self.type in ["gaussiandotdot", "gaussiandotdotnorm", "ricker"]:
@@ -98,22 +104,41 @@ class Waveform:
elif self.type == "gaussiandotnorm":
delay = time - self.chi
normalise = np.sqrt(np.exp(1) / (2 * self.zeta))
ampvalue = -2 * self.zeta * delay * np.exp(-self.zeta * delay**2) * normalise
ampvalue = (
-2 * self.zeta * delay * np.exp(-self.zeta * delay**2) * normalise
)
elif self.type in ["gaussiandotdot", "gaussiandoubleprime"]:
delay = time - self.chi
ampvalue = 2 * self.zeta * (2 * self.zeta * delay**2 - 1) * np.exp(-self.zeta * delay**2)
ampvalue = (
2
* self.zeta
* (2 * self.zeta * delay**2 - 1)
* np.exp(-self.zeta * delay**2)
)
elif self.type == "gaussiandotdotnorm":
delay = time - self.chi
normalise = 1 / (2 * self.zeta)
ampvalue = 2 * self.zeta * (2 * self.zeta * delay**2 - 1) * np.exp(-self.zeta * delay**2) * normalise
ampvalue = (
2
* self.zeta
* (2 * self.zeta * delay**2 - 1)
* np.exp(-self.zeta * delay**2)
* normalise
)
elif self.type == "ricker":
delay = time - self.chi
normalise = 1 / (2 * self.zeta)
ampvalue = -(
(2 * self.zeta * (2 * self.zeta * delay**2 - 1) * np.exp(-self.zeta * delay**2)) * normalise
(
2
* self.zeta
* (2 * self.zeta * delay**2 - 1)
* np.exp(-self.zeta * delay**2)
)
* normalise
)
elif self.type == "sine":

查看文件

@@ -33,11 +33,15 @@ from setuptools import Extension, find_packages, setup
# Check Python version
MIN_PYTHON_VERSION = (3, 7)
if sys.version_info[:2] < MIN_PYTHON_VERSION:
sys.exit("\nExited: Requires Python {MIN_PYTHON_VERSION[0]}.{MIN_PYTHON_VERSION[1]} or newer!\n")
sys.exit(
"\nExited: Requires Python {MIN_PYTHON_VERSION[0]}.{MIN_PYTHON_VERSION[1]} or newer!\n"
)
# Importing gprMax _version__.py before building can cause issues.
with open("gprMax/_version.py", "r") as fd:
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE)[1]
version = re.search(
r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE
)[1]
def build_dispersive_material_templates():
@@ -108,7 +112,9 @@ def build_dispersive_material_templates():
]
)
with open(os.path.join("gprMax", "cython", "fields_updates_dispersive.pyx"), "w") as f:
with open(
os.path.join("gprMax", "cython", "fields_updates_dispersive.pyx"), "w"
) as f:
f.write(r)
@@ -144,9 +150,9 @@ if "cleanall" in sys.argv:
except OSError:
print(f"Could not remove: {filebase}.c")
# Remove compiled Cython modules
libfile = glob.glob(os.path.join(os.getcwd(), os.path.splitext(file)[0]) + "*.pyd") + glob.glob(
os.path.join(os.getcwd(), os.path.splitext(file)[0]) + "*.so"
)
libfile = glob.glob(
os.path.join(os.getcwd(), os.path.splitext(file)[0]) + "*.pyd"
) + glob.glob(os.path.join(os.getcwd(), os.path.splitext(file)[0]) + "*.so")
if libfile:
libfile = libfile[0]
try:
@@ -182,7 +188,11 @@ else:
elif sys.platform == "darwin":
# Check for Intel or Apple M series CPU
cpuID = (
subprocess.check_output("sysctl -n machdep.cpu.brand_string", shell=True, stderr=subprocess.STDOUT)
subprocess.check_output(
"sysctl -n machdep.cpu.brand_string",
shell=True,
stderr=subprocess.STDOUT,
)
.decode("utf-8")
.strip()
)
@@ -196,7 +206,11 @@ else:
# Use newest gcc found
os.environ["CC"] = gccpath[-1].split(os.sep)[-1]
if "Apple" in cpuID:
rpath = "/opt/homebrew/opt/gcc/lib/gcc/" + gccpath[-1].split(os.sep)[-1][-1] + "/"
rpath = (
"/opt/homebrew/opt/gcc/lib/gcc/"
+ gccpath[-1].split(os.sep)[-1][-1]
+ "/"
)
else:
raise (
f"Cannot find gcc in {gccbasepath}. gprMax requires gcc "
@@ -214,7 +228,13 @@ else:
pass
os.environ["MIN_SUPPORTED_MACOSX_DEPLOYMENT_TARGET"] = MIN_MACOS_VERSION
# Sometimes worth testing with '-fstrict-aliasing', '-fno-common'
compile_args = ["-O3", "-w", "-fopenmp", "-march=native", f"-mmacosx-version-min={MIN_MACOS_VERSION}"]
compile_args = [
"-O3",
"-w",
"-fopenmp",
"-march=native",
f"-mmacosx-version-min={MIN_MACOS_VERSION}",
]
linker_args = ["-fopenmp", f"-mmacosx-version-min={MIN_MACOS_VERSION}"]
libraries = ["gomp"]
@@ -261,7 +281,8 @@ else:
version=version,
author="Craig Warren, Antonis Giannopoulos, and John Hartley",
url="http://www.gprmax.com",
description="Electromagnetic Modelling Software based on the " + "Finite-Difference Time-Domain (FDTD) method",
description="Electromagnetic Modelling Software based on the "
+ "Finite-Difference Time-Domain (FDTD) method",
long_description=long_description,
long_description_content_type="text/x-rst",
license="GPLv3+",

查看文件

@@ -157,14 +157,18 @@ def hertzian_dipole_fs(iterations, dt, dxdydz, rx):
)
# Hx
fields[timestep, 3] = -(Hx_y / (4 * np.pi * Hr_x**3)) * (f_Hx + (tau_Hx * fdot_Hx))
fields[timestep, 3] = -(Hx_y / (4 * np.pi * Hr_x**3)) * (
f_Hx + (tau_Hx * fdot_Hx)
)
# Hy
try:
tmp = Hy_x / Hy_y
except ZeroDivisionError:
tmp = 0
fields[timestep, 4] = -tmp * (-(Hy_y / (4 * np.pi * Hr_y**3)) * (f_Hy + (tau_Hy * fdot_Hy)))
fields[timestep, 4] = -tmp * (
-(Hy_y / (4 * np.pi * Hr_y**3)) * (f_Hy + (tau_Hy * fdot_Hy))
)
# Hz
fields[timestep, 5] = 0

查看文件

@@ -1,9 +1,8 @@
"""A series of models with different domain sizes used for benchmarking.
The domain is free space with a simple source (Hertzian Dipole) and
receiver at the centre.
The domain is free space with a simple source (Hertzian Dipole) and
receiver at the centre.
"""
import itertools
from pathlib import Path
@@ -36,7 +35,9 @@ for d, threads in itertools.product(domains, ompthreads):
dxdydz = gprMax.Discretisation(p1=(dl, dl, dl))
time_window = gprMax.TimeWindow(time=3e-9)
wv = gprMax.Waveform(wave_type="gaussiandotnorm", amp=1, freq=900e6, id="MySource")
src = gprMax.HertzianDipole(p1=(x / 2, y / 2, z / 2), polarisation="x", waveform_id="MySource")
src = gprMax.HertzianDipole(
p1=(x / 2, y / 2, z / 2), polarisation="x", waveform_id="MySource"
)
omp = gprMax.OMPThreads(n=threads)

查看文件

@@ -60,9 +60,13 @@ def diff_output_files(filename1, filename2):
# Arrays for storing time
time1 = np.zeros((file1.attrs["Iterations"]), dtype=floattype1)
time1 = np.linspace(0, (file1.attrs["Iterations"] - 1), num=file1.attrs["Iterations"])
time1 = np.linspace(
0, (file1.attrs["Iterations"] - 1), num=file1.attrs["Iterations"]
)
time2 = np.zeros((file2.attrs["Iterations"]), dtype=floattype2)
time2 = np.linspace(0, (file2.attrs["Iterations"] - 1), num=file2.attrs["Iterations"])
time2 = np.linspace(
0, (file2.attrs["Iterations"] - 1), num=file2.attrs["Iterations"]
)
# Arrays for storing field data
data1 = np.zeros((file1.attrs["Iterations"], len(outputs1)), dtype=floattype1)
@@ -82,7 +86,10 @@ def diff_output_files(filename1, filename2):
for i in range(len(outputs2)):
maxi = np.amax(np.abs(data1[:, i]))
datadiffs[:, i] = np.divide(
np.abs(data2[:, i] - data1[:, i]), maxi, out=np.zeros_like(data1[:, i]), where=maxi != 0
np.abs(data2[:, i] - data1[:, i]),
maxi,
out=np.zeros_like(data1[:, i]),
where=maxi != 0,
) # Replace any division by zero with zero
# Calculate power (ignore warning from taking a log of any zero values)

查看文件

@@ -46,12 +46,16 @@ maxerrors = []
testmodels = [basename + "_" + s for s in PMLIDs]
fig, ax = plt.subplots(
subplot_kw=dict(xlabel="Iterations", ylabel="Error [dB]"), figsize=(20, 10), facecolor="w", edgecolor="w"
subplot_kw=dict(xlabel="Iterations", ylabel="Error [dB]"),
figsize=(20, 10),
facecolor="w",
edgecolor="w",
)
for x, model in enumerate(testmodels):
time, datadiffs = diff_output_files(
fn.parent.joinpath(basename + "_ref.h5"), fn.parent.joinpath(basename + str(x + 1) + ".h5")
fn.parent.joinpath(basename + "_ref.h5"),
fn.parent.joinpath(basename + str(x + 1) + ".h5"),
)
# Print maximum error value
@@ -60,7 +64,14 @@ for x, model in enumerate(testmodels):
logger.info(f"{model}: Max. error {maxerrors[x]}")
# Plot diffs (select column to choose field component, 0-Ex, 1-Ey etc..)
ax.plot(time[start::], datadiffs[start::, 1], color=next(colors), lw=2, ls=next(lines), label=model)
ax.plot(
time[start::],
datadiffs[start::, 1],
color=next(colors),
lw=2,
ls=next(lines),
label=model,
)
ax.set_xticks(np.arange(0, 2200, step=100))
ax.set_xlim([0, 2100])
ax.set_yticks(np.arange(-160, 0, step=20))

查看文件

@@ -21,11 +21,17 @@ dxdydz = gprMax.Discretisation(p1=(dl, dl, dl))
time_window = gprMax.TimeWindow(iterations=2100)
tssf = gprMax.TimeStepStabilityFactor(f=0.99)
waveform = gprMax.Waveform(wave_type="gaussiandotnorm", amp=1, freq=9.42e9, id="mypulse")
hertzian_dipole = gprMax.HertzianDipole(polarisation="z", p1=(0.013, 0.013, 0.014), waveform_id="mypulse")
waveform = gprMax.Waveform(
wave_type="gaussiandotnorm", amp=1, freq=9.42e9, id="mypulse"
)
hertzian_dipole = gprMax.HertzianDipole(
polarisation="z", p1=(0.013, 0.013, 0.014), waveform_id="mypulse"
)
rx = gprMax.Rx(p1=(0.038, 0.114, 0.013))
plate = gprMax.Plate(p1=(0.013, 0.013, 0.013), p2=(0.038, 0.113, 0.013), material_id="pec")
plate = gprMax.Plate(
p1=(0.013, 0.013, 0.013), p2=(0.038, 0.113, 0.013), material_id="pec"
)
gv1 = gprMax.GeometryView(
p1=(0, 0, 0),

查看文件

@@ -21,11 +21,17 @@ dxdydz = gprMax.Discretisation(p1=(dl, dl, dl))
time_window = gprMax.TimeWindow(iterations=2100)
tssf = gprMax.TimeStepStabilityFactor(f=0.99)
waveform = gprMax.Waveform(wave_type="gaussiandotnorm", amp=1, freq=9.42e9, id="mypulse")
hertzian_dipole = gprMax.HertzianDipole(polarisation="z", p1=(0.088, 0.088, 0.089), waveform_id="mypulse")
waveform = gprMax.Waveform(
wave_type="gaussiandotnorm", amp=1, freq=9.42e9, id="mypulse"
)
hertzian_dipole = gprMax.HertzianDipole(
polarisation="z", p1=(0.088, 0.088, 0.089), waveform_id="mypulse"
)
rx = gprMax.Rx(p1=(0.113, 0.189, 0.088))
plate = gprMax.Plate(p1=(0.088, 0.088, 0.088), p2=(0.113, 0.188, 0.088), material_id="pec")
plate = gprMax.Plate(
p1=(0.088, 0.088, 0.088), p2=(0.113, 0.188, 0.088), material_id="pec"
)
gv1 = gprMax.GeometryView(
p1=(0, 0, 0),

查看文件

@@ -74,7 +74,13 @@ for x, PMLID in enumerate(PMLIDs):
ax.set_ylabel(f"{output} error [dB]")
# Save a PDF/PNG of the figure
fig.savefig(basename + "_diffs_" + PMLID + ".pdf", dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
fig.savefig(
basename + "_diffs_" + PMLID + ".pdf",
dpi=None,
format="pdf",
bbox_inches="tight",
pad_inches=0.1,
)
# fig.savefig(basename + "_diffs_" + PMLID + ".png", dpi=150, format='png', bbox_inches='tight', pad_inches=0.1)
plt.show()

查看文件

@@ -18,7 +18,9 @@ dxdydz = gprMax.Discretisation(p1=(dl, dl, dl))
time_window = gprMax.TimeWindow(time=3e-9)
waveform = gprMax.Waveform(wave_type="gaussian", amp=1, freq=1e9, id="mypulse")
hertzian_dipole = gprMax.HertzianDipole(polarisation="z", p1=(0.050, 0.050, 0.050), waveform_id="mypulse")
hertzian_dipole = gprMax.HertzianDipole(
polarisation="z", p1=(0.050, 0.050, 0.050), waveform_id="mypulse"
)
rx = gprMax.Rx(p1=(0.070, 0.070, 0.070))
# PML cases

查看文件

@@ -31,7 +31,10 @@ tx_pos = (x / 2, y / 2, z / 2)
# Source excitation and type
wave = gprMax.Waveform(wave_type="gaussian", amp=1, freq=1.5e9, id="mypulse")
tl = gprMax.TransmissionLine(
p1=(tx_pos[0], tx_pos[1], tx_pos[2]), polarisation="x", resistance=50, waveform_id="mypulse"
p1=(tx_pos[0], tx_pos[1], tx_pos[2]),
polarisation="x",
resistance=50,
waveform_id="mypulse",
)
scene.add(wave)
scene.add(tl)
@@ -59,8 +62,16 @@ scene.add(t2)
# Detailed geometry view around bowtie and feed position
gv1 = gprMax.GeometryView(
p1=(tx_pos[0] - bowtie_dims[0] - 2 * dl, tx_pos[1] - bowtie_dims[1] / 2 - 2 * dl, tx_pos[2] - 2 * dl),
p2=(tx_pos[0] + bowtie_dims[0] + 2 * dl, tx_pos[1] + bowtie_dims[1] / 2 + 2 * dl, tx_pos[2] + 2 * dl),
p1=(
tx_pos[0] - bowtie_dims[0] - 2 * dl,
tx_pos[1] - bowtie_dims[1] / 2 - 2 * dl,
tx_pos[2] - 2 * dl,
),
p2=(
tx_pos[0] + bowtie_dims[0] + 2 * dl,
tx_pos[1] + bowtie_dims[1] / 2 + 2 * dl,
tx_pos[2] + 2 * dl,
),
dl=(dl, dl, dl),
filename="antenna_bowtie_fs_pcb",
output_type="f",

查看文件

@@ -32,11 +32,14 @@ logger = logging.getLogger(__name__)
# Parse command line arguments
parser = argparse.ArgumentParser(
description="Plots a comparison of fields between " + "given simulation output and experimental data files.",
description="Plots a comparison of fields between "
+ "given simulation output and experimental data files.",
usage="cd gprMax; python -m testing.test_experimental modelfile realfile output",
)
parser.add_argument("modelfile", help="name of model output file including path")
parser.add_argument("realfile", help="name of file containing experimental data including path")
parser.add_argument(
"realfile", help="name of file containing experimental data including path"
)
parser.add_argument("output", help="output to be plotted, i.e. Ex Ey Ez", nargs="+")
args = parser.parse_args()

查看文件

@@ -90,13 +90,19 @@ for i, model in enumerate(testmodels):
# Arrays for storing time
float_or_double = filetest[path + outputstest[0]].dtype
timetest = (
np.linspace(0, (filetest.attrs["Iterations"] - 1) * filetest.attrs["dt"], num=filetest.attrs["Iterations"])
np.linspace(
0,
(filetest.attrs["Iterations"] - 1) * filetest.attrs["dt"],
num=filetest.attrs["Iterations"],
)
/ 1e-9
)
timeref = timetest
# Arrays for storing field data
datatest = np.zeros((filetest.attrs["Iterations"], len(outputstest)), dtype=float_or_double)
datatest = np.zeros(
(filetest.attrs["Iterations"], len(outputstest)), dtype=float_or_double
)
for ID, name in enumerate(outputstest):
datatest[:, ID] = filetest[path + str(name)][:]
if np.any(np.isnan(datatest[:, ID])):
@@ -106,11 +112,18 @@ for i, model in enumerate(testmodels):
# Tx/Rx position to feed to analytical solution
rxpos = filetest[path].attrs["Position"]
txpos = filetest["/srcs/src1/"].attrs["Position"]
rxposrelative = ((rxpos[0] - txpos[0]), (rxpos[1] - txpos[1]), (rxpos[2] - txpos[2]))
rxposrelative = (
(rxpos[0] - txpos[0]),
(rxpos[1] - txpos[1]),
(rxpos[2] - txpos[2]),
)
# Analytical solution of a dipole in free space
dataref = hertzian_dipole_fs(
filetest.attrs["Iterations"], filetest.attrs["dt"], filetest.attrs["dx_dy_dz"], rxposrelative
filetest.attrs["Iterations"],
filetest.attrs["dt"],
filetest.attrs["dx_dy_dz"],
rxposrelative,
)
filetest.close()
@@ -143,18 +156,30 @@ for i, model in enumerate(testmodels):
# Arrays for storing time
timeref = np.zeros((fileref.attrs["Iterations"]), dtype=float_or_doubleref)
timeref = (
np.linspace(0, (fileref.attrs["Iterations"] - 1) * fileref.attrs["dt"], num=fileref.attrs["Iterations"])
np.linspace(
0,
(fileref.attrs["Iterations"] - 1) * fileref.attrs["dt"],
num=fileref.attrs["Iterations"],
)
/ 1e-9
)
timetest = np.zeros((filetest.attrs["Iterations"]), dtype=float_or_doubletest)
timetest = (
np.linspace(0, (filetest.attrs["Iterations"] - 1) * filetest.attrs["dt"], num=filetest.attrs["Iterations"])
np.linspace(
0,
(filetest.attrs["Iterations"] - 1) * filetest.attrs["dt"],
num=filetest.attrs["Iterations"],
)
/ 1e-9
)
# Arrays for storing field data
dataref = np.zeros((fileref.attrs["Iterations"], len(outputsref)), dtype=float_or_doubleref)
datatest = np.zeros((filetest.attrs["Iterations"], len(outputstest)), dtype=float_or_doubletest)
dataref = np.zeros(
(fileref.attrs["Iterations"], len(outputsref)), dtype=float_or_doubleref
)
datatest = np.zeros(
(filetest.attrs["Iterations"], len(outputstest)), dtype=float_or_doubletest
)
for ID, name in enumerate(outputsref):
dataref[:, ID] = fileref[path + str(name)][:]
datatest[:, ID] = filetest[path + str(name)][:]
@@ -170,7 +195,10 @@ for i, model in enumerate(testmodels):
for i in range(len(outputstest)):
maxi = np.amax(np.abs(dataref[:, i]))
datadiffs[:, i] = np.divide(
np.abs(dataref[:, i] - datatest[:, i]), maxi, out=np.zeros_like(dataref[:, i]), where=maxi != 0
np.abs(dataref[:, i] - datatest[:, i]),
maxi,
out=np.zeros_like(dataref[:, i]),
where=maxi != 0,
) # Replace any division by zero with zero
# Calculate power (ignore warning from taking a log of any zero values)
@@ -260,8 +288,20 @@ for i, model in enumerate(testmodels):
# bbox_inches='tight', pad_inches=0.1)
# fig2.savefig(savediffs.with_suffix('.pdf'), dpi=None, format='pdf',
# bbox_inches='tight', pad_inches=0.1)
fig1.savefig(file.with_suffix(".png"), dpi=150, format="png", bbox_inches="tight", pad_inches=0.1)
fig2.savefig(filediffs.with_suffix(".png"), dpi=150, format="png", bbox_inches="tight", pad_inches=0.1)
fig1.savefig(
file.with_suffix(".png"),
dpi=150,
format="png",
bbox_inches="tight",
pad_inches=0.1,
)
fig2.savefig(
filediffs.with_suffix(".png"),
dpi=150,
format="png",
bbox_inches="tight",
pad_inches=0.1,
)
# Summary of results
for name, data in sorted(testresults.items()):

查看文件

@@ -100,12 +100,18 @@ if epsr:
ax.plot([0, np.deg2rad(180 + thetac)], [min, 0], color="0.7", lw=2)
ax.plot([np.deg2rad(270), np.deg2rad(90)], [0, 0], color="0.7", lw=2)
ax.annotate("Air", xy=(np.deg2rad(270), 0), xytext=(8, 8), textcoords="offset points")
ax.annotate("Ground", xy=(np.deg2rad(270), 0), xytext=(8, -15), textcoords="offset points")
ax.annotate(
"Ground", xy=(np.deg2rad(270), 0), xytext=(8, -15), textcoords="offset points"
)
# Plot patterns
for patt in range(0, len(radii)):
pattplot = np.append(patterns[patt, :], patterns[patt, 0]) # Append start value to close circle
pattplot = pattplot / np.max(np.max(patterns)) # Normalise, based on set of patterns
pattplot = np.append(
patterns[patt, :], patterns[patt, 0]
) # Append start value to close circle
pattplot = pattplot / np.max(
np.max(patterns)
) # Normalise, based on set of patterns
# Calculate power (ignore warning from taking a log of any zero values)
with np.errstate(divide="ignore"):
@@ -140,7 +146,11 @@ ax.set_yticklabels(yticks)
ax.grid(True)
handles, existlabels = ax.get_legend_handles_labels()
leg = ax.legend(
[handles[0], handles[-1]], [existlabels[0], existlabels[-1]], ncol=2, loc=(0.27, -0.12), frameon=False
[handles[0], handles[-1]],
[existlabels[0], existlabels[-1]],
ncol=2,
loc=(0.27, -0.12),
frameon=False,
) # Plot just first and last legend entries
# leg = ax.legend([handles[0], handles[-3], handles[-2], handles[-1]], [existlabels[0], existlabels[-3], existlabels[-2], existlabels[-1]], ncol=4, loc=(-0.13,-0.12), frameon=False)
[legobj.set_linewidth(2) for legobj in leg.legendHandles]

查看文件

@@ -9,9 +9,13 @@ logger = logging.getLogger(__name__)
# Parse command line arguments
parser = argparse.ArgumentParser(
description="Writes a HDF5 file of AustinMan or AustinWoman head only.", usage="python head_only_hdf5 filename"
description="Writes a HDF5 file of AustinMan or AustinWoman head only.",
usage="python head_only_hdf5 filename",
)
parser.add_argument(
"filename",
help="name and path to (HDF5) file containing AustinMan or AustinWoman model",
)
parser.add_argument("filename", help="name and path to (HDF5) file containing AustinMan or AustinWoman model")
args = parser.parse_args()
# Read full body HDF5 file
@@ -22,7 +26,9 @@ data = f["/data"][:, :, :]
# Define head as last 1/8 of total body height
nzhead = 7 * int(data.shape[2] / 8)
logger.info(f"Dimensions of head model: {data.shape[0]:g} x {data.shape[1]:g} x {data.shape[2] - nzhead:g} cells")
logger.info(
f"Dimensions of head model: {data.shape[0]:g} x {data.shape[1]:g} x {data.shape[2] - nzhead:g} cells"
)
# Write HDF5 file
headfile = os.path.splitext(args.filename)[0] + "_head.h5"

查看文件

@@ -100,7 +100,15 @@ class Relaxation(object):
def check_inputs(self):
"""Check the validity of the inputs."""
try:
d = [float(i) for i in [self.number_of_debye_poles, self.sigma, self.mu, self.mu_sigma]]
d = [
float(i)
for i in [
self.number_of_debye_poles,
self.sigma,
self.mu,
self.mu_sigma,
]
]
except ValueError:
sys.exit("The inputs should be numeric.")
if not isinstance(self.number_of_debye_poles, int):
@@ -120,7 +128,9 @@ class Relaxation(object):
Returns:
s (str): Info about chosen function and its parameters.
"""
print(f"Approximating {self.name}" f" using {self.number_of_debye_poles} Debye poles")
print(
f"Approximating {self.name} using {self.number_of_debye_poles} Debye poles"
)
print(f"{self.name} parameters: ")
s = "".join(f"{k:10s} = {v}\n" for k, v in self.params.items())
print(s)
@@ -172,7 +182,12 @@ class Relaxation(object):
self.rl, self.im = q.real, q.imag
if self.number_of_debye_poles == -1:
print("\n#########", "Try to automaticaly fit number of Debye poles, up to 20!", "##########\n", sep="")
print(
"\n#########",
"Try to automaticaly fit number of Debye poles, up to 20!",
"##########\n",
sep="",
)
error = np.infty # artificial best error starting value
self.number_of_debye_poles = 1
iteration = 1
@@ -195,7 +210,11 @@ class Relaxation(object):
# Print the results in gprMax format style
properties = self.print_output(tau, weights, ee)
print(f"The average fractional error for:\n" f"- real part: {err_real}\n" f"- imaginary part: {err_imag}\n")
print(
f"The average fractional error for:\n"
f"- real part: {err_real}\n"
f"- imaginary part: {err_imag}\n"
)
if self.save:
self.save_result(properties)
# Plot the actual and the approximate dielectric properties
@@ -220,16 +239,20 @@ class Relaxation(object):
print(f" |{'e_inf':^14s}|{'De':^14s}|{'log(tau_0)':^25s}|")
print("_" * 65)
for i in range(0, len(tau)):
print(f"Debye {i + 1}|{ee / len(tau):^14.5f}|{weights[i]:^14.5f}|{tau[i]:^25.5f}|")
print(
f"Debye {i + 1}|{ee / len(tau):^14.5f}|{weights[i]:^14.5f}|{tau[i]:^25.5f}|"
)
print("_" * 65)
# Print the Debye expnasion in a gprMax format
material_prop = []
material_prop.append(f"#material: {ee} {self.sigma} {self.mu} {self.mu_sigma} {self.material_name}\n")
material_prop.append(
f"#material: {ee} {self.sigma} {self.mu} {self.mu_sigma} {self.material_name}\n"
)
print(material_prop[0], end="")
dispersion_prop = f"#add_dispersion_debye: {len(tau)}"
for i in range(len(tau)):
dispersion_prop += f" {weights[i]} {10**tau[i]}"
dispersion_prop += f" {weights[i]} {10 ** tau[i]}"
dispersion_prop += f" {self.material_name}"
print(dispersion_prop)
material_prop.append(dispersion_prop + "\n")
@@ -251,10 +274,34 @@ class Relaxation(object):
gs = gridspec.GridSpec(2, 1)
ax = fig.add_subplot(gs[0])
ax.grid(b=True, which="major", linewidth=0.2, linestyle="--")
ax.semilogx(self.freq * 1e-6, rl_exp, "b-", linewidth=2.0, label="Debye Expansion: Real part")
ax.semilogx(self.freq * 1e-6, -im_exp, "k-", linewidth=2.0, label="Debye Expansion: Imaginary part")
ax.semilogx(self.freq * 1e-6, self.rl, "r.", linewidth=2.0, label=f"{self.name}: Real part")
ax.semilogx(self.freq * 1e-6, -self.im, "g.", linewidth=2.0, label=f"{self.name}: Imaginary part")
ax.semilogx(
self.freq * 1e-6,
rl_exp,
"b-",
linewidth=2.0,
label="Debye Expansion: Real part",
)
ax.semilogx(
self.freq * 1e-6,
-im_exp,
"k-",
linewidth=2.0,
label="Debye Expansion: Imaginary part",
)
ax.semilogx(
self.freq * 1e-6,
self.rl,
"r.",
linewidth=2.0,
label=f"{self.name}: Real part",
)
ax.semilogx(
self.freq * 1e-6,
-self.im,
"g.",
linewidth=2.0,
label=f"{self.name}: Imaginary part",
)
ax.set_ylim([-1, np.max(np.concatenate([self.rl, -self.im])) + 1])
ax.legend()
ax.set_xlabel("Frequency (MHz)")
@@ -262,8 +309,20 @@ class Relaxation(object):
ax = fig.add_subplot(gs[1])
ax.grid(b=True, which="major", linewidth=0.2, linestyle="--")
ax.semilogx(self.freq * 1e-6, (rl_exp - self.rl) / (self.rl + 1), "b-", linewidth=2.0, label="Real part")
ax.semilogx(self.freq * 1e-6, (-im_exp + self.im) / (self.im + 1), "k-", linewidth=2.0, label="Imaginary part")
ax.semilogx(
self.freq * 1e-6,
(rl_exp - self.rl) / (self.rl + 1),
"b-",
linewidth=2.0,
label="Real part",
)
ax.semilogx(
self.freq * 1e-6,
(-im_exp + self.im) / (self.im + 1),
"k-",
linewidth=2.0,
label="Imaginary part",
)
ax.legend()
ax.set_xlabel("Frequency (MHz)")
ax.set_ylabel("Relative approximation error")
@@ -284,8 +343,12 @@ class Relaxation(object):
avg_err_imag (float): average fractional error
for conductivity (imaginary part)
"""
avg_err_real = np.sum(np.abs((rl_exp - self.rl) / (self.rl + 1)) * 100) / len(rl_exp)
avg_err_imag = np.sum(np.abs((-im_exp + self.im) / (self.im + 1)) * 100) / len(im_exp)
avg_err_real = np.sum(np.abs((rl_exp - self.rl) / (self.rl + 1)) * 100) / len(
rl_exp
)
avg_err_imag = np.sum(np.abs((-im_exp + self.im) / (self.im + 1)) * 100) / len(
im_exp
)
return avg_err_real, avg_err_imag
@staticmethod
@@ -306,7 +369,10 @@ class Relaxation(object):
elif os.path.isdir("user_libs/materials"):
file_path = os.path.join("user_libs", "materials", "my_materials.txt")
else:
sys.exit("Cannot save material properties " f"in {os.path.join(fdir, 'my_materials.txt')}!")
sys.exit(
"Cannot save material properties "
f"in {os.path.join(fdir, 'my_materials.txt')}!"
)
with open(file_path, "a") as fileH:
fileH.write(f"## {output[0].split(' ')[-1]}")
fileH.writelines(output)
@@ -382,7 +448,13 @@ class HavriliakNegami(Relaxation):
self.f_min, self.f_max = f_min, f_max
# Choosing n frequencies logarithmicaly equally spaced between the bounds given
self.set_freq(self.f_min, self.f_max, self.f_n)
self.e_inf, self.alpha, self.beta, self.de, self.tau_0 = e_inf, alpha, beta, de, tau_0
self.e_inf, self.alpha, self.beta, self.de, self.tau_0 = (
e_inf,
alpha,
beta,
de,
tau_0,
)
self.params = {
"f_min": self.f_min,
"f_max": self.f_max,
@@ -412,7 +484,11 @@ class HavriliakNegami(Relaxation):
def calculation(self):
"""Calculates the Havriliak-Negami function for
the given parameters."""
return self.e_inf + self.de / (1 + (1j * 2 * np.pi * self.freq * self.tau_0) ** self.alpha) ** self.beta
return (
self.e_inf
+ self.de
/ (1 + (1j * 2 * np.pi * self.freq * self.tau_0) ** self.alpha) ** self.beta
)
class Jonscher(Relaxation):
@@ -501,9 +577,9 @@ class Jonscher(Relaxation):
def calculation(self):
"""Calculates the Q function for the given parameters"""
return self.e_inf + (self.a_p * (2 * np.pi * self.freq / self.omega_p) ** (self.n_p - 1)) * (
1 - 1j / np.tan(self.n_p * np.pi / 2)
)
return self.e_inf + (
self.a_p * (2 * np.pi * self.freq / self.omega_p) ** (self.n_p - 1)
) * (1 - 1j / np.tan(self.n_p * np.pi / 2))
class Crim(Relaxation):
@@ -583,7 +659,9 @@ class Crim(Relaxation):
if (np.array(d) < 0).sum() != 0:
sys.exit("The inputs should be positive.")
if len(self.volumetric_fractions) != len(self.materials):
sys.exit("Number of volumetric volumes does not match the dielectric properties")
sys.exit(
"Number of volumetric volumes does not match the dielectric properties"
)
# Check if the materials are at least two
if len(self.volumetric_fractions) < 2:
sys.exit("The materials should be at least 2")
@@ -604,7 +682,10 @@ class Crim(Relaxation):
def print_info(self):
"""Print information about chosen approximation settings"""
print(f"Approximating Complex Refractive Index Model (CRIM)" f" using {self.number_of_debye_poles} Debye poles")
print(
f"Approximating Complex Refractive Index Model (CRIM)"
f" using {self.number_of_debye_poles} Debye poles"
)
print("CRIM parameters: ")
for i in range(len(self.volumetric_fractions)):
print(f"Material {i + 1}.:")
@@ -617,7 +698,9 @@ class Crim(Relaxation):
def calculation(self):
"""Calculates the Crim function for the given parameters"""
return np.sum(
np.repeat(self.volumetric_fractions, len(self.freq)).reshape((-1, len(self.materials)))
np.repeat(self.volumetric_fractions, len(self.freq)).reshape(
(-1, len(self.materials))
)
* (
self.materials[:, 0]
+ self.materials[:, 1]
@@ -626,7 +709,9 @@ class Crim(Relaxation):
+ 1j
* 2
* np.pi
* np.repeat(self.freq, len(self.materials)).reshape((-1, len(self.materials)))
* np.repeat(self.freq, len(self.materials)).reshape(
(-1, len(self.materials))
)
* self.materials[:, 2]
)
)
@@ -691,13 +776,19 @@ class Rawdata(Relaxation):
# Read the file
with open(self.filename) as f:
try:
array = np.array([[float(x) for x in line.split(self.delimiter)] for line in f])
array = np.array(
[[float(x) for x in line.split(self.delimiter)] for line in f]
)
except ValueError:
sys.exit("Error: The inputs should be numeric")
self.set_freq(min(array[:, 0]), max(array[:, 0]), self.f_n)
rl_interp = scipy.interpolate.interp1d(array[:, 0], array[:, 1], fill_value="extrapolate")
im_interp = scipy.interpolate.interp1d(array[:, 0], array[:, 2], fill_value="extrapolate")
rl_interp = scipy.interpolate.interp1d(
array[:, 0], array[:, 1], fill_value="extrapolate"
)
im_interp = scipy.interpolate.interp1d(
array[:, 0], array[:, 2], fill_value="extrapolate"
)
return rl_interp(self.freq) - 1j * im_interp(self.freq)
@@ -774,17 +865,63 @@ if __name__ == "__main__":
setup.run()
# Testing setup
setup = Rawdata(
"examples/Test.txt", 0.1, 1, 0.1, "M1", number_of_debye_poles=3, plot=True, optimizer_options={"seed": 111}
"examples/Test.txt",
0.1,
1,
0.1,
"M1",
number_of_debye_poles=3,
plot=True,
optimizer_options={"seed": 111},
)
setup.run()
np.random.seed(111)
setup = HavriliakNegami(1e12, 1e-3, 0.5, 1, 10, 5, 1e-6, 0.1, 1, 0, "M2", number_of_debye_poles=6, plot=True)
setup = HavriliakNegami(
1e12,
1e-3,
0.5,
1,
10,
5,
1e-6,
0.1,
1,
0,
"M2",
number_of_debye_poles=6,
plot=True,
)
setup.run()
setup = Jonscher(1e6, 1e-5, 50, 1, 1e5, 0.7, 0.1, 1, 0.1, "M3", number_of_debye_poles=4, plot=True)
setup = Jonscher(
1e6,
1e-5,
50,
1,
1e5,
0.7,
0.1,
1,
0.1,
"M3",
number_of_debye_poles=4,
plot=True,
)
setup.run()
f = np.array([0.5, 0.5])
material1 = [3, 25, 1e6]
material2 = [3, 0, 1e3]
materials = np.array([material1, material2])
setup = Crim(1 * 1e-1, 1e-9, 0.5, f, materials, 0.1, 1, 0, "M4", number_of_debye_poles=2, plot=True)
setup = Crim(
1 * 1e-1,
1e-9,
0.5,
f,
materials,
0.1,
1,
0,
"M4",
number_of_debye_poles=2,
plot=True,
)
setup.run()

查看文件

@@ -121,7 +121,16 @@ class PSO_DLS(Optimizer):
"""
def __init__(
self, swarmsize=40, maxiter=50, omega=0.9, phip=0.9, phig=0.9, minstep=1e-8, minfun=1e-8, pflag=False, seed=None
self,
swarmsize=40,
maxiter=50,
omega=0.9,
phip=0.9,
phig=0.9,
minstep=1e-8,
minfun=1e-8,
pflag=False,
seed=None,
):
super(PSO_DLS, self).__init__(maxiter, seed)
self.swarmsize = swarmsize
@@ -159,7 +168,9 @@ class PSO_DLS(Optimizer):
assert hasattr(func, "__call__"), "Invalid function handle"
lb = np.array(lb)
ub = np.array(ub)
assert np.all(ub > lb), "All upper-bound values must be greater than lower-bound values"
assert np.all(ub > lb), (
"All upper-bound values must be greater than lower-bound values"
)
vhigh = np.abs(ub - lb)
vlow = -vhigh
@@ -226,10 +237,16 @@ class PSO_DLS(Optimizer):
tmp = x[i, :].copy()
stepsize = np.sqrt(np.sum((g - tmp) ** 2))
if np.abs(fg - fx) <= self.minfun:
print(f"Stopping search: Swarm best objective " f"change less than {self.minfun}")
print(
f"Stopping search: Swarm best objective "
f"change less than {self.minfun}"
)
return tmp, fx
elif stepsize <= self.minstep:
print(f"Stopping search: Swarm best position " f"change less than {self.minstep}")
print(
f"Stopping search: Swarm best position "
f"change less than {self.minstep}"
)
return tmp, fx
else:
g = tmp.copy()
@@ -471,7 +488,10 @@ def DLS(logt, rl, im, freq):
# Solving the overdetermined system y=Ax
x = np.abs(np.linalg.lstsq(d.imag, im, rcond=None)[0])
# x - absolute damped least-squares solution
rp, ip = np.matmul(d.real, x[np.newaxis].T).T[0], np.matmul(d.imag, x[np.newaxis].T).T[0]
rp, ip = (
np.matmul(d.real, x[np.newaxis].T).T[0],
np.matmul(d.imag, x[np.newaxis].T).T[0],
)
cost_i = np.sum(np.abs(ip - im)) / len(im)
ee = np.mean(rl - rp)
ee = max(ee, 1)

查看文件

@@ -64,7 +64,9 @@ def antenna_like_GSSI_1500(x, y, z, resolution=0.001, **kwargs):
patchheight = 0.016
tx = x + 0.114, y + 0.052, z + skidthickness
else:
logger.exception("This antenna module can only be used with a spatial discretisation of 1mm or 2mm")
logger.exception(
"This antenna module can only be used with a spatial discretisation of 1mm or 2mm"
)
raise ValueError
# If using parameters from an optimisation
@@ -80,8 +82,12 @@ def antenna_like_GSSI_1500(x, y, z, resolution=0.001, **kwargs):
hdpesig = kwargs["hdpesig"]
sourceresistance = 195
rxres = 50
absorber1 = gprMax.Material(er=absorber1Er, se=absorber1sig, mr=1, sm=0, id="absorber1")
absorber2 = gprMax.Material(er=absorber2Er, se=absorber2sig, mr=1, sm=0, id="absorber2")
absorber1 = gprMax.Material(
er=absorber1Er, se=absorber1sig, mr=1, sm=0, id="absorber1"
)
absorber2 = gprMax.Material(
er=absorber2Er, se=absorber2sig, mr=1, sm=0, id="absorber2"
)
pcb = gprMax.Material(er=pcbEr, se=pcbsig, mr=1, sm=0, id="pcb")
hdpe = gprMax.Material(er=hdpeEr, se=hdpesig, mr=1, sm=0, id="hdpe")
scene_objects.extend((absorber1, absorber2, pcb, hdpe))
@@ -95,19 +101,27 @@ def antenna_like_GSSI_1500(x, y, z, resolution=0.001, **kwargs):
if optstate == "WarrenThesis":
# Original optimised values from http://hdl.handle.net/1842/4074
excitationfreq = 1.71e9
sourceresistance = 230 # Correction for old (< 123) GprMax3D bug (optimised to 4)
sourceresistance = (
230 # Correction for old (< 123) GprMax3D bug (optimised to 4)
)
rxres = 925 # Resistance at Rx bowtie
absorber1 = gprMax.Material(er=1.58, se=0.428, mr=1, sm=0, id="absorber1")
absorber2 = gprMax.Material(er=3, se=0, mr=1, sm=0, id="absorber2") # Foam modelled as PCB material
absorber2 = gprMax.Material(
er=3, se=0, mr=1, sm=0, id="absorber2"
) # Foam modelled as PCB material
pcb = gprMax.Material(er=3, se=0, mr=1, sm=0, id="pcb")
hdpe = gprMax.Material(er=2.35, se=0, mr=1, sm=0, id="hdpe")
rxres = gprMax.Material(er=3, se=(1 / rxres) * (dy / (dx * dz)), mr=1, sm=0, id="rxres")
rxres = gprMax.Material(
er=3, se=(1 / rxres) * (dy / (dx * dz)), mr=1, sm=0, id="rxres"
)
scene_objects.extend((absorber1, absorber2, pcb, hdpe, rxres))
elif optstate == "DebyeAbsorber":
# Same values as WarrenThesis but uses dispersive absorber properties for Eccosorb LS22
excitationfreq = 1.71e9
sourceresistance = 230 # Correction for old (< 123) GprMax3D bug (optimised to 4)
sourceresistance = (
230 # Correction for old (< 123) GprMax3D bug (optimised to 4)
)
rxres = 925 # Resistance at Rx bowtie
absorber1 = gprMax.Material(er=1, se=0, mr=1, sm=0, id="absorber1")
# Eccosorb LS22 3-pole Debye model (https://bitbucket.org/uoyaeg/aegboxts/wiki/Home)
@@ -117,11 +131,17 @@ def antenna_like_GSSI_1500(x, y, z, resolution=0.001, **kwargs):
tau=[1.00723e-11, 1.55686e-10, 3.44129e-10],
material_ids=["absorber1"],
)
absorber2 = gprMax.Material(er=3, se=0, mr=1, sm=0, id="absorber2") # Foam modelled as PCB material
absorber2 = gprMax.Material(
er=3, se=0, mr=1, sm=0, id="absorber2"
) # Foam modelled as PCB material
pcb = gprMax.Material(er=3, se=0, mr=1, sm=0, id="pcb")
hdpe = gprMax.Material(er=2.35, se=0, mr=1, sm=0, id="hdpe")
rxres = gprMax.Material(er=3, se=(1 / rxres) * (dy / (dx * dz)), mr=1, sm=0, id="rxres")
scene_objects.extend((absorber1, absorber1_disp, absorber2, pcb, hdpe, rxres))
rxres = gprMax.Material(
er=3, se=(1 / rxres) * (dy / (dx * dz)), mr=1, sm=0, id="rxres"
)
scene_objects.extend(
(absorber1, absorber1_disp, absorber2, pcb, hdpe, rxres)
)
elif optstate == "GiannakisPaper":
# Further optimised values from https://doi.org/10.1109/TGRS.2018.2869027
@@ -152,13 +172,21 @@ def antenna_like_GSSI_1500(x, y, z, resolution=0.001, **kwargs):
# Metallic enclosure
b3 = gprMax.Box(
p1=(x + 0.025, y + casethickness, z + skidthickness),
p2=(x + casesize[0] - 0.025, y + casesize[1] - casethickness, z + skidthickness + 0.027),
p2=(
x + casesize[0] - 0.025,
y + casesize[1] - casethickness,
z + skidthickness + 0.027,
),
material_id="pec",
)
# Absorber material (absorber1) and foam (absorber2) around edge of absorber
b4 = gprMax.Box(
p1=(x + 0.025 + shieldthickness, y + casethickness + shieldthickness, z + skidthickness),
p1=(
x + 0.025 + shieldthickness,
y + casethickness + shieldthickness,
z + skidthickness,
),
p2=(
x + 0.025 + shieldthickness + 0.057,
y + casesize[1] - casethickness - shieldthickness,
@@ -299,12 +327,24 @@ def antenna_like_GSSI_1500(x, y, z, resolution=0.001, **kwargs):
scene_objects.extend((p9, p10))
# Edges that represent wire between bowtie halves in 1mm model
e1 = gprMax.Edge(p1=(tx[0] - 0.059, tx[1] - dy, tx[2]), p2=(tx[0] - 0.059, tx[1], tx[2]), material_id="pec")
e2 = gprMax.Edge(
p1=(tx[0] - 0.059, tx[1] + dy, tx[2]), p2=(tx[0] - 0.059, tx[1] + 0.002, tx[2]), material_id="pec"
e1 = gprMax.Edge(
p1=(tx[0] - 0.059, tx[1] - dy, tx[2]),
p2=(tx[0] - 0.059, tx[1], tx[2]),
material_id="pec",
)
e2 = gprMax.Edge(
p1=(tx[0] - 0.059, tx[1] + dy, tx[2]),
p2=(tx[0] - 0.059, tx[1] + 0.002, tx[2]),
material_id="pec",
)
e3 = gprMax.Edge(
p1=(tx[0], tx[1] - dy, tx[2]), p2=(tx[0], tx[1], tx[2]), material_id="pec"
)
e4 = gprMax.Edge(
p1=(tx[0], tx[1] + dz, tx[2]),
p2=(tx[0], tx[1] + 0.002, tx[2]),
material_id="pec",
)
e3 = gprMax.Edge(p1=(tx[0], tx[1] - dy, tx[2]), p2=(tx[0], tx[1], tx[2]), material_id="pec")
e4 = gprMax.Edge(p1=(tx[0], tx[1] + dz, tx[2]), p2=(tx[0], tx[1] + 0.002, tx[2]), material_id="pec")
scene_objects.extend((e1, e2, e3, e4))
elif resolution == 0.002:
@@ -359,13 +399,21 @@ def antenna_like_GSSI_1500(x, y, z, resolution=0.001, **kwargs):
scene_objects.extend((p11, p12))
# Skid
b10 = gprMax.Box(p1=(x, y, z), p2=(x + casesize[0], y + casesize[1], z + skidthickness), material_id="hdpe")
b10 = gprMax.Box(
p1=(x, y, z),
p2=(x + casesize[0], y + casesize[1], z + skidthickness),
material_id="hdpe",
)
scene_objects.append(b10)
# Geometry views
gv1 = gprMax.GeometryView(
p1=(x - dx, y - dy, z - dz),
p2=(x + casesize[0] + dx, y + casesize[1] + dy, z + skidthickness + casesize[2] + dz),
p2=(
x + casesize[0] + dx,
y + casesize[1] + dy,
z + skidthickness + casesize[2] + dz,
),
dl=(dx, dy, dz),
filename="antenna_like_GSSI_1500",
output_type="n",
@@ -382,19 +430,29 @@ def antenna_like_GSSI_1500(x, y, z, resolution=0.001, **kwargs):
# Excitation
if optstate == "WarrenThesis" or optstate == "DebyeAbsorber":
# Gaussian pulse
w1 = gprMax.Waveform(wave_type="gaussian", amp=1, freq=excitationfreq, id="my_gaussian")
w1 = gprMax.Waveform(
wave_type="gaussian", amp=1, freq=excitationfreq, id="my_gaussian"
)
vs1 = gprMax.VoltageSource(
polarisation="y", p1=(tx[0], tx[1], tx[2]), resistance=sourceresistance, waveform_id="my_gaussian"
polarisation="y",
p1=(tx[0], tx[1], tx[2]),
resistance=sourceresistance,
waveform_id="my_gaussian",
)
scene_objects.extend((w1, vs1))
elif optstate == "GiannakisPaper":
# Optimised custom pulse
exc1 = gprMax.ExcitationFile(
filepath="toolboxes/GPRAntennaModels/GSSI_1500MHz_pulse.txt", kind="linear", fill_value="extrapolate"
filepath="toolboxes/GPRAntennaModels/GSSI_1500MHz_pulse.txt",
kind="linear",
fill_value="extrapolate",
)
vs1 = gprMax.VoltageSource(
polarisation="y", p1=(tx[0], tx[1], tx[2]), resistance=sourceresistance, waveform_id="my_pulse"
polarisation="y",
p1=(tx[0], tx[1], tx[2]),
resistance=sourceresistance,
waveform_id="my_pulse",
)
scene_objects.extend((exc1, vs1))
@@ -402,7 +460,9 @@ def antenna_like_GSSI_1500(x, y, z, resolution=0.001, **kwargs):
if resolution == 0.001:
if optstate == "WarrenThesis" or optstate == "DebyeAbsorber":
e1 = gprMax.Edge(
p1=(tx[0] - 0.059, tx[1], tx[2]), p2=(tx[0] - 0.059, tx[1] + dy, tx[2]), material_id="rxres"
p1=(tx[0] - 0.059, tx[1], tx[2]),
p2=(tx[0] - 0.059, tx[1] + dy, tx[2]),
material_id="rxres",
)
scene_objects.append(e1)
r1 = gprMax.Rx(p1=(tx[0] - 0.059, tx[1], tx[2]), id="rxbowtie", outputs=["Ey"])
@@ -411,7 +471,9 @@ def antenna_like_GSSI_1500(x, y, z, resolution=0.001, **kwargs):
elif resolution == 0.002:
if optstate == "WarrenThesis" or optstate == "DebyeAbsorber":
e1 = gprMax.Edge(
p1=(tx[0] - 0.060, tx[1], tx[2]), p2=(tx[0] - 0.060, tx[1] + dy, tx[2]), material_id="rxres"
p1=(tx[0] - 0.060, tx[1], tx[2]),
p2=(tx[0] - 0.060, tx[1] + dy, tx[2]),
material_id="rxres",
)
scene_objects.append(e1)
r1 = gprMax.Rx(p1=(tx[0] - 0.060, tx[1], tx[2]), id="rxbowtie", outputs=["Ey"])
@@ -492,7 +554,11 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
dz = 0.002
foamsurroundthickness = 0.002
metalboxheight = 0.088
tx = x + 0.01 + 0.004 + 0.056, y + casethickness + 0.005 + 0.143 - 0.002, z + skidthickness - 0.002
tx = (
x + 0.01 + 0.004 + 0.056,
y + casethickness + 0.005 + 0.143 - 0.002,
z + skidthickness - 0.002,
)
# Material definitions
absorber = gprMax.Material(er=absorberEr, se=absorbersig, mr=1, sm=0, id="absorber")
@@ -510,17 +576,28 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
)
b2 = gprMax.Box(
p1=(x + casethickness, y + casethickness, z + skidthickness - 0.002),
p2=(x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + casesize[2] - casethickness),
p2=(
x + casesize[0] - casethickness,
y + casesize[1] - casethickness,
z + casesize[2] - casethickness,
),
material_id="free_space",
)
# Metallic enclosure
b3 = gprMax.Box(
p1=(x + casethickness, y + casethickness, z + skidthickness + (metalmiddleplateheight - metalboxheight)),
p1=(
x + casethickness,
y + casethickness,
z + skidthickness + (metalmiddleplateheight - metalboxheight),
),
p2=(
x + casesize[0] - casethickness,
y + casesize[1] - casethickness,
z + skidthickness + (metalmiddleplateheight - metalboxheight) + metalboxheight,
z
+ skidthickness
+ (metalmiddleplateheight - metalboxheight)
+ metalboxheight,
),
material_id="pec",
)
@@ -552,7 +629,11 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
# PCB
b6 = gprMax.Box(
p1=(x + 0.01 + 0.005 + 0.017, y + casethickness + 0.005 + 0.021, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.017,
y + casethickness + 0.005 + 0.021,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.033 + bowtiebase,
y + casethickness + 0.006 + 0.202 + patchheight,
@@ -561,7 +642,11 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
material_id="pcb",
)
b7 = gprMax.Box(
p1=(x + 0.01 + 0.005 + 0.179, y + casethickness + 0.005 + 0.021, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.179,
y + casethickness + 0.005 + 0.021,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.195 + bowtiebase,
y + casethickness + 0.006 + 0.202 + patchheight,
@@ -581,18 +666,29 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
)
b9 = gprMax.Box(
p1=(x + casethickness, y + casethickness, z + skidthickness - 0.002),
p2=(x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + casesize[2] - casethickness),
p2=(
x + casesize[0] - casethickness,
y + casesize[1] - casethickness,
z + casesize[2] - casethickness,
),
material_id="free_space",
averaging="n",
)
# Metallic enclosure
b10 = gprMax.Box(
p1=(x + casethickness, y + casethickness, z + skidthickness + (metalmiddleplateheight - metalboxheight)),
p1=(
x + casethickness,
y + casethickness,
z + skidthickness + (metalmiddleplateheight - metalboxheight),
),
p2=(
x + casesize[0] - casethickness,
y + casesize[1] - casethickness,
z + skidthickness + (metalmiddleplateheight - metalboxheight) + metalboxheight,
z
+ skidthickness
+ (metalmiddleplateheight - metalboxheight)
+ metalboxheight,
),
material_id="pec",
)
@@ -626,7 +722,11 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
# PCB
b13 = gprMax.Box(
p1=(x + 0.01 + 0.005 + 0.017, y + casethickness + 0.005 + 0.021, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.017,
y + casethickness + 0.005 + 0.021,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.033 + bowtiebase,
y + casethickness + 0.006 + 0.202 + patchheight,
@@ -636,7 +736,11 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
averaging="n",
)
b14 = gprMax.Box(
p1=(x + 0.01 + 0.005 + 0.179, y + casethickness + 0.005 + 0.021, z + skidthickness),
p1=(
x + 0.01 + 0.005 + 0.179,
y + casethickness + 0.005 + 0.021,
z + skidthickness,
),
p2=(
x + 0.01 + 0.005 + 0.195 + bowtiebase,
y + casethickness + 0.006 + 0.202 + patchheight,
@@ -652,7 +756,11 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
# "left" side
# extension plates
p1 = gprMax.Plate(
p1=(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.021, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.025,
y + casethickness + 0.005 + 0.021,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.025 + bowtiebase,
y + casethickness + 0.005 + 0.021 + patchheight,
@@ -661,7 +769,11 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
material_id="pec",
)
p2 = gprMax.Plate(
p1=(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.203, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.025,
y + casethickness + 0.005 + 0.203,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.025 + bowtiebase,
y + casethickness + 0.005 + 0.203 + patchheight,
@@ -671,8 +783,16 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
)
# triangles
t1 = gprMax.Triangle(
p1=(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.081, z + skidthickness - 0.002),
p2=(x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.081, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.025,
y + casethickness + 0.005 + 0.081,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.025 + bowtiebase,
y + casethickness + 0.005 + 0.081,
z + skidthickness - 0.002,
),
p3=(
x + 0.01 + 0.005 + 0.025 + (bowtiebase / 2),
y + casethickness + 0.005 + 0.081 + bowtieheight,
@@ -682,8 +802,16 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
material_id="pec",
)
t2 = gprMax.Triangle(
p1=(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.203, z + skidthickness - 0.002),
p2=(x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.203, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.025,
y + casethickness + 0.005 + 0.203,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.025 + bowtiebase,
y + casethickness + 0.005 + 0.203,
z + skidthickness - 0.002,
),
p3=(
x + 0.01 + 0.005 + 0.025 + (bowtiebase / 2),
y + casethickness + 0.005 + 0.203 - bowtieheight,
@@ -694,7 +822,11 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
)
# "right" side
p3 = gprMax.Plate(
p1=(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.021, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.187,
y + casethickness + 0.005 + 0.021,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.187 + bowtiebase,
y + casethickness + 0.005 + 0.021 + patchheight,
@@ -703,7 +835,11 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
material_id="pec",
)
p4 = gprMax.Plate(
p1=(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.203, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.187,
y + casethickness + 0.005 + 0.203,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.187 + bowtiebase,
y + casethickness + 0.005 + 0.203 + patchheight,
@@ -713,8 +849,16 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
)
# triangles
t3 = gprMax.Triangle(
p1=(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.081, z + skidthickness - 0.002),
p2=(x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.081, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.187,
y + casethickness + 0.005 + 0.081,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.187 + bowtiebase,
y + casethickness + 0.005 + 0.081,
z + skidthickness - 0.002,
),
p3=(
x + 0.01 + 0.005 + 0.187 + (bowtiebase / 2),
y + casethickness + 0.005 + 0.081 + bowtieheight,
@@ -724,8 +868,16 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
material_id="pec",
)
t4 = gprMax.Triangle(
p1=(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.203, z + skidthickness - 0.002),
p2=(x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.203, z + skidthickness - 0.002),
p1=(
x + 0.01 + 0.005 + 0.187,
y + casethickness + 0.005 + 0.203,
z + skidthickness - 0.002,
),
p2=(
x + 0.01 + 0.005 + 0.187 + bowtiebase,
y + casethickness + 0.005 + 0.203,
z + skidthickness - 0.002,
),
p3=(
x + 0.01 + 0.005 + 0.187 + (bowtiebase / 2),
y + casethickness + 0.005 + 0.203 - bowtieheight,
@@ -736,12 +888,24 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
)
# Edges that represent wire between bowtie halves in 2mm model
e1 = gprMax.Edge(p1=(tx[0] + 0.162, tx[1] - dy, tx[2]), p2=(tx[0] + 0.162, tx[1], tx[2]), material_id="pec")
e2 = gprMax.Edge(
p1=(tx[0] + 0.162, tx[1] + dy, tx[2]), p2=(tx[0] + 0.162, tx[1] + 2 * dy, tx[2]), material_id="pec"
e1 = gprMax.Edge(
p1=(tx[0] + 0.162, tx[1] - dy, tx[2]),
p2=(tx[0] + 0.162, tx[1], tx[2]),
material_id="pec",
)
e2 = gprMax.Edge(
p1=(tx[0] + 0.162, tx[1] + dy, tx[2]),
p2=(tx[0] + 0.162, tx[1] + 2 * dy, tx[2]),
material_id="pec",
)
e3 = gprMax.Edge(
p1=(tx[0], tx[1] - dy, tx[2]), p2=(tx[0], tx[1], tx[2]), material_id="pec"
)
e4 = gprMax.Edge(
p1=(tx[0], tx[1] + dy, tx[2]),
p2=(tx[0], tx[1] + 2 * dy, tx[2]),
material_id="pec",
)
e3 = gprMax.Edge(p1=(tx[0], tx[1] - dy, tx[2]), p2=(tx[0], tx[1], tx[2]), material_id="pec")
e4 = gprMax.Edge(p1=(tx[0], tx[1] + dy, tx[2]), p2=(tx[0], tx[1] + 2 * dy, tx[2]), material_id="pec")
scene_objects.extend((p1, p2, t1, t2, p3, p4, t3, t4, e1, e2, e3, e4))
# Metallic plate extension
@@ -758,7 +922,9 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
# Skid
if smooth_dec == "yes":
b16 = gprMax.Box(
p1=(x, y, z), p2=(x + casesize[0], y + casesize[1], z + skidthickness - 0.002), material_id="hdpe"
p1=(x, y, z),
p2=(x + casesize[0], y + casesize[1], z + skidthickness - 0.002),
material_id="hdpe",
)
elif smooth_dec == "no":
b16 = gprMax.Box(
@@ -771,31 +937,48 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
# Source
if src_type == "voltage_source":
w1 = gprMax.Waveform(wave_type="gaussian", amp=1, freq=excitationfreq, id="my_gaussian")
w1 = gprMax.Waveform(
wave_type="gaussian", amp=1, freq=excitationfreq, id="my_gaussian"
)
vs1 = gprMax.VoltageSource(
polarisation="y", p1=(tx[0], tx[1], tx[2]), resistance=sourceresistance, waveform_id="my_gaussian"
polarisation="y",
p1=(tx[0], tx[1], tx[2]),
resistance=sourceresistance,
waveform_id="my_gaussian",
)
scene_objects.extend((w1, vs1))
elif src_type == "transmission_line":
w1 = gprMax.Waveform(wave_type="gaussian", amp=1, freq=excitationfreq, id="my_gaussian")
w1 = gprMax.Waveform(
wave_type="gaussian", amp=1, freq=excitationfreq, id="my_gaussian"
)
tl1 = gprMax.TransmissionLine(
polarisation="y", p1=(tx[0], tx[1], tx[2]), resistance=sourceresistance, waveform_id="my_gaussian"
polarisation="y",
p1=(tx[0], tx[1], tx[2]),
resistance=sourceresistance,
waveform_id="my_gaussian",
)
scene_objects.extend((w1, tl1))
else:
# Optimised custom pulse
exc1 = gprMax.ExcitationFile(
filepath="toolboxes/GPRAntennaModels/GSSI_400MHz_pulse.txt", kind="linear", fill_value="extrapolate"
filepath="toolboxes/GPRAntennaModels/GSSI_400MHz_pulse.txt",
kind="linear",
fill_value="extrapolate",
)
vs1 = gprMax.VoltageSource(
polarisation="y", p1=(tx[0], tx[1], tx[2]), resistance=sourceresistance, waveform_id="my_pulse"
polarisation="y",
p1=(tx[0], tx[1], tx[2]),
resistance=sourceresistance,
waveform_id="my_pulse",
)
scene_objects.extend((exc1, vs1))
# Receiver
if src_type == "transmission_line":
# Zero waveform to use with transmission line at receiver output
w2 = gprMax.Waveform(wave_type="gaussian", amp=0, freq=excitationfreq, id="my_zero_wave")
w2 = gprMax.Waveform(
wave_type="gaussian", amp=0, freq=excitationfreq, id="my_zero_wave"
)
tl2 = gprMax.TransmissionLine(
polarisation="y",
p1=(tx[0] + 0.162, tx[1], tx[2]),
@@ -810,7 +993,11 @@ def antenna_like_GSSI_400(x, y, z, resolution=0.002, **kwargs):
# Geometry views
gv1 = gprMax.GeometryView(
p1=(x - dx, y - dy, z - dz),
p2=(x + casesize[0] + dx, y + casesize[1] + dy, z + skidthickness + casesize[2] + dz),
p2=(
x + casesize[0] + dx,
y + casesize[1] + dy,
z + skidthickness + casesize[2] + dz,
),
dl=(dx, dy, dz),
filename="antenna_like_GSSI_400",
output_type="n",

查看文件

@@ -84,20 +84,30 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
bowtieheight = 0.024
tx = x + 0.062, y + 0.052, z + skidthickness
else:
logger.exception("This antenna module can only be used with a spatial resolution of 1mm or 2mm")
logger.exception(
"This antenna module can only be used with a spatial resolution of 1mm or 2mm"
)
raise ValueError
# SMD resistors - 3 on each Tx & Rx bowtie arm
txres = 470 # Ohms
txrescellupper = txres / 3 # Resistor over 3 cells
txsigupper = ((1 / txrescellupper) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor
txsigupper = (
(1 / txrescellupper) * (dy / (dx * dz))
) / 2 # Divide by number of parallel edges per resistor
txrescelllower = txres / 4 # Resistor over 4 cells
txsiglower = ((1 / txrescelllower) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor
txsiglower = (
(1 / txrescelllower) * (dy / (dx * dz))
) / 2 # Divide by number of parallel edges per resistor
rxres = 150 # Ohms
rxrescellupper = rxres / 3 # Resistor over 3 cells
rxsigupper = ((1 / rxrescellupper) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor
rxsigupper = (
(1 / rxrescellupper) * (dy / (dx * dz))
) / 2 # Divide by number of parallel edges per resistor
rxrescelllower = rxres / 4 # Resistor over 4 cells
rxsiglower = ((1 / rxrescelllower) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor
rxsiglower = (
(1 / rxrescelllower) * (dy / (dx * dz))
) / 2 # Divide by number of parallel edges per resistor
# Material definitions
absorber = gprMax.Material(er=absorberEr, se=absorbersig, mr=1, sm=0, id="absorber")
@@ -108,7 +118,18 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
txresupper = gprMax.Material(er=3, se=txsigupper, mr=1, sm=0, id="txresupper")
rxreslower = gprMax.Material(er=3, se=rxsiglower, mr=1, sm=0, id="rxreslower")
rxresupper = gprMax.Material(er=3, se=rxsigupper, mr=1, sm=0, id="rxresupper")
scene_objects.extend((absorber, pcb, hdpe, polypropylene, txreslower, txresupper, rxreslower, rxresupper))
scene_objects.extend(
(
absorber,
pcb,
hdpe,
polypropylene,
txreslower,
txresupper,
rxreslower,
rxresupper,
)
)
# Antenna geometry
# Shield - metallic enclosure
@@ -119,19 +140,31 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
)
b2 = gprMax.Box(
p1=(x + 0.020, y + casethickness, z + skidthickness),
p2=(x + 0.100, y + casesize[1] - casethickness, z + skidthickness + casethickness),
p2=(
x + 0.100,
y + casesize[1] - casethickness,
z + skidthickness + casethickness,
),
material_id="free_space",
)
b3 = gprMax.Box(
p1=(x + 0.100, y + casethickness, z + skidthickness),
p2=(x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + casethickness),
p2=(
x + casesize[0] - casethickness,
y + casesize[1] - casethickness,
z + skidthickness + casethickness,
),
material_id="free_space",
)
# Absorber material
b4 = gprMax.Box(
p1=(x + 0.020, y + casethickness, z + skidthickness),
p2=(x + 0.100, y + casesize[1] - casethickness, z + skidthickness + casesize[2] - casethickness),
p2=(
x + 0.100,
y + casesize[1] - casethickness,
z + skidthickness + casesize[2] - casethickness,
),
material_id="absorber",
)
b5 = gprMax.Box(
@@ -148,7 +181,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
# Shield - cylindrical sections
c1 = gprMax.Cylinder(
p1=(x + 0.055, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.055, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness),
p2=(
x + 0.055,
y + casesize[1] - 0.008,
z + skidthickness + casesize[2] - casethickness,
),
r=0.008,
material_id="pec",
)
@@ -160,7 +197,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
)
c3 = gprMax.Cylinder(
p1=(x + 0.147, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.147, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness),
p2=(
x + 0.147,
y + casesize[1] - 0.008,
z + skidthickness + casesize[2] - casethickness,
),
r=0.008,
material_id="pec",
)
@@ -172,7 +213,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
)
c5 = gprMax.Cylinder(
p1=(x + 0.055, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.055, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness),
p2=(
x + 0.055,
y + casesize[1] - 0.008,
z + skidthickness + casesize[2] - casethickness,
),
r=0.007,
material_id="free_space",
)
@@ -184,7 +229,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
)
c7 = gprMax.Cylinder(
p1=(x + 0.147, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.147, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness),
p2=(
x + 0.147,
y + casesize[1] - 0.008,
z + skidthickness + casesize[2] - casethickness,
),
r=0.007,
material_id="free_space",
)
@@ -196,7 +245,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
)
b6 = gprMax.Box(
p1=(x + 0.054, y + casesize[1] - 0.016, z + skidthickness),
p2=(x + 0.056, y + casesize[1] - 0.014, z + skidthickness + casesize[2] - casethickness),
p2=(
x + 0.056,
y + casesize[1] - 0.014,
z + skidthickness + casesize[2] - casethickness,
),
material_id="free_space",
)
b7 = gprMax.Box(
@@ -206,7 +259,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
)
b8 = gprMax.Box(
p1=(x + 0.146, y + casesize[1] - 0.016, z + skidthickness),
p2=(x + 0.148, y + casesize[1] - 0.014, z + skidthickness + casesize[2] - casethickness),
p2=(
x + 0.148,
y + casesize[1] - 0.014,
z + skidthickness + casesize[2] - casethickness,
),
material_id="free_space",
)
b9 = gprMax.Box(
@@ -219,18 +276,30 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
# PCB
b10 = gprMax.Box(
p1=(x + 0.020, y + 0.018, z + skidthickness),
p2=(x + casesize[0] - casethickness, y + casesize[1] - 0.018, z + skidthickness + pcbthickness),
p2=(
x + casesize[0] - casethickness,
y + casesize[1] - 0.018,
z + skidthickness + pcbthickness,
),
material_id="pcb",
)
# Shield - Tx & Rx cavities
b11 = gprMax.Box(
p1=(x + 0.032, y + 0.022, z + skidthickness),
p2=(x + 0.032 + cavitysize[0], y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2]),
p2=(
x + 0.032 + cavitysize[0],
y + 0.022 + cavitysize[1],
z + skidthickness + cavitysize[2],
),
material_id="pec",
)
b12 = gprMax.Box(
p1=(x + 0.032 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness),
p1=(
x + 0.032 + cavitythickness,
y + 0.022 + cavitythickness,
z + skidthickness,
),
p2=(
x + 0.032 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
@@ -240,11 +309,19 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
)
b13 = gprMax.Box(
p1=(x + 0.108, y + 0.022, z + skidthickness),
p2=(x + 0.108 + cavitysize[0], y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2]),
p2=(
x + 0.108 + cavitysize[0],
y + 0.022 + cavitysize[1],
z + skidthickness + cavitysize[2],
),
material_id="pec",
)
b14 = gprMax.Box(
p1=(x + 0.108 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness),
p1=(
x + 0.108 + cavitythickness,
y + 0.022 + cavitythickness,
z + skidthickness,
),
p2=(
x + 0.108 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
@@ -264,14 +341,22 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
material_id="pec",
)
b16 = gprMax.Box(
p1=(x + 0.032 + cavitysize[0], y + 0.022, z + skidthickness + cavitysize[2] - casethickness),
p1=(
x + 0.032 + cavitysize[0],
y + 0.022,
z + skidthickness + cavitysize[2] - casethickness,
),
p2=(x + 0.108, y + 0.022 + 0.006, z + skidthickness + cavitysize[2]),
material_id="pec",
)
# PCB - replace bits chopped by TX & Rx cavities
b17 = gprMax.Box(
p1=(x + 0.032 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness),
p1=(
x + 0.032 + cavitythickness,
y + 0.022 + cavitythickness,
z + skidthickness,
),
p2=(
x + 0.032 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
@@ -280,7 +365,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
material_id="pcb",
)
b18 = gprMax.Box(
p1=(x + 0.108 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness),
p1=(
x + 0.108 + cavitythickness,
y + 0.022 + cavitythickness,
z + skidthickness,
),
p2=(
x + 0.108 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
@@ -300,7 +389,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
thickness=0,
material_id="pec",
)
e1 = gprMax.Edge(p1=(tx[0], tx[1] - 0.001, tx[2]), p2=(tx[0], tx[1], tx[2]), material_id="pec")
e1 = gprMax.Edge(
p1=(tx[0], tx[1] - 0.001, tx[2]),
p2=(tx[0], tx[1], tx[2]),
material_id="pec",
)
t2 = gprMax.Triangle(
p1=(tx[0], tx[1] + 0.002, tx[2]),
p2=(tx[0] - 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
@@ -308,7 +401,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
thickness=0,
material_id="pec",
)
e2 = gprMax.Edge(p1=(tx[0], tx[1] + 0.001, tx[2]), p2=(tx[0], tx[1] + 0.002, tx[2]), material_id="pec")
e2 = gprMax.Edge(
p1=(tx[0], tx[1] + 0.001, tx[2]),
p2=(tx[0], tx[1] + 0.002, tx[2]),
material_id="pec",
)
scene_objects.extend((t1, t2, e1, e2))
elif resolution == 0.002:
t1 = gprMax.Triangle(
@@ -336,7 +433,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
thickness=0,
material_id="pec",
)
e3 = gprMax.Edge(p1=(tx[0] + 0.076, tx[1] - 0.001, tx[2]), p2=(tx[0] + 0.076, tx[1], tx[2]), material_id="pec")
e3 = gprMax.Edge(
p1=(tx[0] + 0.076, tx[1] - 0.001, tx[2]),
p2=(tx[0] + 0.076, tx[1], tx[2]),
material_id="pec",
)
t4 = gprMax.Triangle(
p1=(tx[0] + 0.076, tx[1] + 0.002, tx[2]),
p2=(tx[0] + 0.076 - 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
@@ -345,7 +446,9 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
material_id="pec",
)
e4 = gprMax.Edge(
p1=(tx[0] + 0.076, tx[1] + 0.001, tx[2]), p2=(tx[0] + 0.076, tx[1] + 0.002, tx[2]), material_id="pec"
p1=(tx[0] + 0.076, tx[1] + 0.001, tx[2]),
p2=(tx[0] + 0.076, tx[1] + 0.002, tx[2]),
material_id="pec",
)
scene_objects.extend((t3, e3, t4, e4))
elif resolution == 0.002:
@@ -631,20 +734,31 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
# Skid
b19 = gprMax.Box(
p1=(x, y, z), p2=(x + casesize[0], y + casesize[1], z + polypropylenethickness), material_id="polypropylene"
p1=(x, y, z),
p2=(x + casesize[0], y + casesize[1], z + polypropylenethickness),
material_id="polypropylene",
)
b20 = gprMax.Box(
p1=(x, y, z + polypropylenethickness),
p2=(x + casesize[0], y + casesize[1], z + polypropylenethickness + hdpethickness),
p2=(
x + casesize[0],
y + casesize[1],
z + polypropylenethickness + hdpethickness,
),
material_id="hdpe",
)
scene_objects.extend((b19, b20))
# Excitation
w2 = gprMax.Waveform(wave_type="gaussian", amp=1, freq=excitationfreq, id="my_gaussian")
w2 = gprMax.Waveform(
wave_type="gaussian", amp=1, freq=excitationfreq, id="my_gaussian"
)
scene_objects.append(w2)
vs1 = gprMax.VoltageSource(
polarisation="y", p1=(tx[0], tx[1], tx[2]), resistance=sourceresistance, waveform_id="my_gaussian"
polarisation="y",
p1=(tx[0], tx[1], tx[2]),
resistance=sourceresistance,
waveform_id="my_gaussian",
)
scene_objects.append(vs1)
@@ -655,7 +769,11 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
# Geometry views
gv1 = gprMax.GeometryView(
p1=(x - dx, y - dy, z - dz),
p2=(x + casesize[0] + dx, y + casesize[1] + dy, z + skidthickness + casesize[2] + dz),
p2=(
x + casesize[0] + dx,
y + casesize[1] + dy,
z + skidthickness + casesize[2] + dz,
),
dl=(dx, dy, dz),
filename="antenna_like_MALA_1200",
output_type="n",

查看文件

@@ -81,7 +81,9 @@ def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False, save=False):
# Check for single output component when doing a FFT
if fft and not len(outputs) == 1:
logger.exception("A single output must be specified when using " + "the -fft option")
logger.exception(
"A single output must be specified when using " + "the -fft option"
)
raise ValueError
# New plot for each receiver
@@ -120,7 +122,11 @@ def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False, save=False):
# Set plotting range to -60dB from maximum power or 4 times
# frequency at maximum power
try:
pltrange = np.where(power[freqmaxpower:] < -60)[0][0] + freqmaxpower + 1
pltrange = (
np.where(power[freqmaxpower:] < -60)[0][0]
+ freqmaxpower
+ 1
)
except:
pltrange = freqmaxpower * 4
@@ -160,20 +166,27 @@ def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False, save=False):
plt.setp(line2, color="g")
plt.setp(ax1, ylabel=outputtext + " field strength [A/m]")
plt.setp(stemlines, "color", "g")
plt.setp(markerline, "markerfacecolor", "g", "markeredgecolor", "g")
plt.setp(
markerline, "markerfacecolor", "g", "markeredgecolor", "g"
)
elif "I" in outputs[0]:
plt.setp(line1, color="b")
plt.setp(line2, color="b")
plt.setp(ax1, ylabel=outputtext + " current [A]")
plt.setp(stemlines, "color", "b")
plt.setp(markerline, "markerfacecolor", "b", "markeredgecolor", "b")
plt.setp(
markerline, "markerfacecolor", "b", "markeredgecolor", "b"
)
plt.show()
# Plotting if no FFT required
else:
fig, ax = plt.subplots(
subplot_kw=dict(xlabel="Time [s]", ylabel=outputtext + " field strength [V/m]"),
subplot_kw=dict(
xlabel="Time [s]",
ylabel=outputtext + " field strength [V/m]",
),
num=rxpath + " - " + f[rxpath].attrs["Name"],
figsize=(20, 10),
facecolor="w",
@@ -279,7 +292,13 @@ def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False, save=False):
if save:
# Save a PDF of the figure
fig.savefig(filename[:-3] + ".pdf", dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
fig.savefig(
filename[:-3] + ".pdf",
dpi=None,
format="pdf",
bbox_inches="tight",
pad_inches=0.1,
)
# Save a PNG of the figure
# fig.savefig(filename[:-3] + '.png', dpi=150, format='png',
# bbox_inches='tight', pad_inches=0.1)
@@ -322,9 +341,17 @@ if __name__ == "__main__":
],
nargs="+",
)
parser.add_argument("-fft", action="store_true", default=False, help="plot FFT (single output must be specified)")
parser.add_argument(
"-save", action="store_true", default=False, help="save plot directly to file, i.e. do not display"
"-fft",
action="store_true",
default=False,
help="plot FFT (single output must be specified)",
)
parser.add_argument(
"-save",
action="store_true",
default=False,
help="save plot directly to file, i.e. do not display",
)
args = parser.parse_args()

查看文件

@@ -46,7 +46,12 @@ def mpl_plot(filename, outputdata, dt, rxnumber, rxcomponent, save=False):
file = Path(filename)
fig = plt.figure(num=file.stem + " - rx" + str(rxnumber), figsize=(20, 10), facecolor="w", edgecolor="w")
fig = plt.figure(
num=file.stem + " - rx" + str(rxnumber),
figsize=(20, 10),
facecolor="w",
edgecolor="w",
)
plt.imshow(
outputdata,
extent=[0, outputdata.shape[1], outputdata.shape[0] * dt, 0],
@@ -73,7 +78,13 @@ def mpl_plot(filename, outputdata, dt, rxnumber, rxcomponent, save=False):
if save:
# Save a PDF of the figure
fig.savefig(filename[:-3] + ".pdf", dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
fig.savefig(
filename[:-3] + ".pdf",
dpi=None,
format="pdf",
bbox_inches="tight",
pad_inches=0.1,
)
# Save a PNG of the figure
# fig.savefig(filename[:-3] + '.png', dpi=150, format='png',
# bbox_inches='tight', pad_inches=0.1)
@@ -94,10 +105,16 @@ if __name__ == "__main__":
choices=["Ex", "Ey", "Ez", "Hx", "Hy", "Hz", "Ix", "Iy", "Iz"],
)
parser.add_argument(
"-gather", action="store_true", default=False, help="gather together all receiver outputs in file"
"-gather",
action="store_true",
default=False,
help="gather together all receiver outputs in file",
)
parser.add_argument(
"-save", action="store_true", default=False, help="save plot directly to file, i.e. do not display"
"-save",
action="store_true",
default=False,
help="save plot directly to file, i.e. do not display",
)
args = parser.parse_args()
@@ -118,10 +135,14 @@ if __name__ == "__main__":
rxsgather = outputdata
rxsgather = np.column_stack((rxsgather, outputdata))
else:
plthandle = mpl_plot(args.outputfile, outputdata, dt, rx, args.rx_component, save=args.save)
plthandle = mpl_plot(
args.outputfile, outputdata, dt, rx, args.rx_component, save=args.save
)
# Plot all receivers from single output file together if required
if args.gather:
plthandle = mpl_plot(args.outputfile, rxsgather, dt, rx, args.rx_component, save=args.save)
plthandle = mpl_plot(
args.outputfile, rxsgather, dt, rx, args.rx_component, save=args.save
)
plthandle.show()

查看文件

@@ -28,7 +28,9 @@ import numpy as np
logger = logging.getLogger(__name__)
def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=None, rxcomponent=None):
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.
@@ -160,7 +162,9 @@ def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=N
"yin": yin,
}
if tlrxnumber or rxnumber:
with np.errstate(divide="ignore"): # Ignore warning from taking a log of any zero values
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
@@ -224,7 +228,10 @@ def mpl_plot(
# Print some useful values from s11, and input impedance
s11minfreq = np.where(s11[pltrange] == np.amin(s11[pltrange]))[0][0]
logger.info(f"s11 minimum: {np.amin(s11[pltrange]):g} dB at " + f"{freqs[s11minfreq + pltrangemin]:g} Hz")
logger.info(
f"s11 minimum: {np.amin(s11[pltrange]):g} dB at "
+ f"{freqs[s11minfreq + pltrangemin]:g} Hz"
)
logger.info(f"At {freqs[s11minfreq + pltrangemin]:g} Hz...")
logger.info(
f"Input impedance: {np.abs(zin[s11minfreq + pltrangemin]):.1f}"
@@ -236,7 +243,10 @@ def mpl_plot(
# Figure 1
# Plot incident voltage
fig1, ax = plt.subplots(
num="Transmitter transmission line parameters", figsize=(20, 12), facecolor="w", edgecolor="w"
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])
@@ -368,7 +378,9 @@ def mpl_plot(
# Figure 2
# Plot frequency spectra of s11
fig2, ax = plt.subplots(num="Antenna parameters", figsize=(20, 12), facecolor="w", edgecolor="w")
fig2, ax = plt.subplots(
num="Antenna parameters", figsize=(20, 12), facecolor="w", edgecolor="w"
)
gs2 = gridspec.GridSpec(2, 2, hspace=0.3)
ax = plt.subplot(gs2[0, 0])
markerline, stemlines, baseline = ax.stem(freqs[pltrange], s11[pltrange], "-.")
@@ -463,8 +475,20 @@ def mpl_plot(
savename2 = filename.stem + "_ant_params"
savename2 = filename.parent / savename2
# Save a PDF of the figure
fig1.savefig(savename1.with_suffix(".pdf"), dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
fig2.savefig(savename2.with_suffix(".pdf"), dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
fig1.savefig(
savename1.with_suffix(".pdf"),
dpi=None,
format="pdf",
bbox_inches="tight",
pad_inches=0.1,
)
fig2.savefig(
savename2.with_suffix(".pdf"),
dpi=None,
format="pdf",
bbox_inches="tight",
pad_inches=0.1,
)
# Save a PNG of the figure
# fig1.savefig(savename1.with_suffix('.png'), dpi=150, format='png',
# bbox_inches='tight', pad_inches=0.1)
@@ -485,8 +509,15 @@ if __name__ == "__main__":
usage="cd gprMax; python -m toolboxes.Plotting.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(
"--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",
@@ -495,7 +526,10 @@ if __name__ == "__main__":
choices=["Ex", "Ey", "Ez"],
)
parser.add_argument(
"-save", action="store_true", default=False, help="save plot directly to file, i.e. do not display"
"-save",
action="store_true",
default=False,
help="save plot directly to file, i.e. do not display",
)
args = parser.parse_args()

查看文件

@@ -90,7 +90,13 @@ def mpl_plot(w, timewindow, dt, iterations, fft=False, save=False):
if w.freq and w.type != "gaussian" and w.type != "impulse":
logging.info(f"Centre frequency: {w.freq:g} Hz")
if w.type in ["gaussian", "gaussiandot", "gaussiandotnorm", "gaussianprime", "gaussiandoubleprime"]:
if w.type in [
"gaussian",
"gaussiandot",
"gaussiandotnorm",
"gaussianprime",
"gaussiandoubleprime",
]:
delay = 1 / w.freq
logging.info(f"Time to centre of pulse: {delay:g} s")
elif w.type in ["gaussiandotdot", "gaussiandotdotnorm", "ricker"]:
@@ -113,7 +119,9 @@ def mpl_plot(w, timewindow, dt, iterations, fft=False, save=False):
pltrange = np.where(freqs > 4 * w.freq)[0][0]
pltrange = np.s_[0:pltrange]
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, num=w.type, figsize=(20, 10), facecolor="w", edgecolor="w")
fig, (ax1, ax2) = plt.subplots(
nrows=1, ncols=2, num=w.type, figsize=(20, 10), facecolor="w", edgecolor="w"
)
# Plot waveform
ax1.plot(time, waveform, "r", lw=2)
@@ -121,7 +129,9 @@ def mpl_plot(w, timewindow, dt, iterations, fft=False, save=False):
ax1.set_ylabel("Amplitude")
# Plot frequency spectra
markerline, stemlines, baseline = ax2.stem(freqs[pltrange], power[pltrange], "-.")
markerline, stemlines, baseline = ax2.stem(
freqs[pltrange], power[pltrange], "-."
)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "r")
plt.setp(markerline, "markerfacecolor", "r", "markeredgecolor", "r")
@@ -130,7 +140,9 @@ def mpl_plot(w, timewindow, dt, iterations, fft=False, save=False):
ax2.set_ylabel("Power [dB]")
else:
fig, ax1 = plt.subplots(num=w.type, figsize=(10, 10), facecolor="w", edgecolor="w")
fig, ax1 = plt.subplots(
num=w.type, figsize=(10, 10), facecolor="w", edgecolor="w"
)
# Plot waveform
ax1.plot(time, waveform, "r", lw=2)
@@ -143,9 +155,21 @@ def mpl_plot(w, timewindow, dt, iterations, fft=False, save=False):
if save:
savefile = Path(__file__).parent / w.type
# Save a PDF of the figure
fig.savefig(savefile.with_suffix(".pdf"), dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
fig.savefig(
savefile.with_suffix(".pdf"),
dpi=None,
format="pdf",
bbox_inches="tight",
pad_inches=0.1,
)
# Save a PNG of the figure
fig.savefig(savefile.with_suffix(".png"), dpi=150, format="png", bbox_inches="tight", pad_inches=0.1)
fig.savefig(
savefile.with_suffix(".png"),
dpi=150,
format="png",
bbox_inches="tight",
pad_inches=0.1,
)
return plt
@@ -161,18 +185,27 @@ if __name__ == "__main__":
parser.add_argument("freq", type=float, help="centre frequency of waveform")
parser.add_argument("timewindow", help="time window to view waveform")
parser.add_argument("dt", type=float, help="time step to view waveform")
parser.add_argument("-fft", action="store_true", default=False, help="plot FFT of waveform")
parser.add_argument(
"-save", action="store_true", default=False, help="save plot directly to file, i.e. do not display"
"-fft", action="store_true", default=False, help="plot FFT of waveform"
)
parser.add_argument(
"-save",
action="store_true",
default=False,
help="save plot directly to file, i.e. do not display",
)
args = parser.parse_args()
# Check waveform parameters
if args.type.lower() not in Waveform.types:
logging.exception(f"The waveform must have one of the following types {', '.join(Waveform.types)}")
logging.exception(
f"The waveform must have one of the following types {', '.join(Waveform.types)}"
)
raise ValueError
if args.freq <= 0:
logging.exception("The waveform requires an excitation frequency value of greater than zero")
logging.exception(
"The waveform requires an excitation frequency value of greater than zero"
)
raise ValueError
# Create waveform instance
@@ -182,5 +215,7 @@ if __name__ == "__main__":
w.freq = args.freq
timewindow, iterations = check_timewindow(args.timewindow, args.dt)
plthandle = mpl_plot(w, timewindow, args.dt, iterations, fft=args.fft, save=args.save)
plthandle = mpl_plot(
w, timewindow, args.dt, iterations, fft=args.fft, save=args.save
)
plthandle.show()

查看文件

@@ -21,12 +21,20 @@ def convert_file(input_file_path, discretization, pad=1, parallel=False):
return convert_files([input_file_path], discretization, pad=pad, parallel=parallel)
def convert_files(input_file_paths, discretization, colors=[(0, 0, 0)], pad=1, parallel=False):
def convert_files(
input_file_paths, discretization, colors=[(0, 0, 0)], pad=1, parallel=False
):
meshes = []
for input_file_path in input_file_paths:
mesh_obj = mesh.Mesh.from_file(input_file_path)
org_mesh = np.hstack((mesh_obj.v0[:, np.newaxis], mesh_obj.v1[:, np.newaxis], mesh_obj.v2[:, np.newaxis]))
org_mesh = np.hstack(
(
mesh_obj.v0[:, np.newaxis],
mesh_obj.v1[:, np.newaxis],
mesh_obj.v2[:, np.newaxis],
)
)
meshes.append(org_mesh)
vol, scale, shift = convert_meshes(meshes, discretization, parallel)
vol = np.transpose(vol)

查看文件

@@ -6,7 +6,9 @@ def lines_to_voxels(line_list, pixels):
x = 0
for event_x, status, line_ind in generate_line_events(line_list):
while event_x - x >= 0:
lines = reduce(lambda acc, cur: acc + [line_list[cur]], current_line_indices, [])
lines = reduce(
lambda acc, cur: acc + [line_list[cur]], current_line_indices, []
)
paint_y_axis(lines, pixels, x)
x += 1

查看文件

@@ -19,7 +19,12 @@ def mesh_to_plane(mesh, bounding_box, parallel):
current_mesh_indices = set()
z = 0
with tqdm(total=bounding_box[2], desc="Processing Layers", ncols=get_terminal_width() - 1, file=sys.stdout) as pbar:
with tqdm(
total=bounding_box[2],
desc="Processing Layers",
ncols=get_terminal_width() - 1,
file=sys.stdout,
) as pbar:
for event_z, status, tri_ind in generate_tri_events(mesh):
while event_z - z >= 0:
mesh_subset = [mesh[ind] for ind in current_mesh_indices]

查看文件

@@ -17,9 +17,15 @@ if __name__ == "__main__":
usage="cd gprMax; python -m toolboxes.STLtoVoxel.stltovoxel stlfilename -matindex -dxdydz",
)
parser.add_argument(
"stlfiles", help="can be the filename of a single STL file, or the path to folder containing multiple STL files"
"stlfiles",
help="can be the filename of a single STL file, or the path to folder containing multiple STL files",
)
parser.add_argument(
"-dxdydz",
type=float,
required=True,
help="discretisation to use in voxelisation process",
)
parser.add_argument("-dxdydz", type=float, required=True, help="discretisation to use in voxelisation process")
args = parser.parse_args()
if os.path.isdir(args.stlfiles):
@@ -38,7 +44,9 @@ if __name__ == "__main__":
newline = "\n\t"
logger.info(f"\nConverting STL file(s): {newline.join(files)}")
model_array = convert_files(files, dxdydz)
logger.info(f"Number of voxels: {model_array.shape[0]} x {model_array.shape[1]} x {model_array.shape[2]}")
logger.info(
f"Number of voxels: {model_array.shape[0]} x {model_array.shape[1]} x {model_array.shape[2]}"
)
logger.info(f"Spatial discretisation: {dxdydz[0]} x {dxdydz[1]} x {dxdydz[2]}m")
# Write HDF5 file for gprMax using voxels

查看文件

@@ -55,7 +55,9 @@ class Cursor(object):
) # Convert pixel values from float (0-1) to integer (0-255)
match = pixel_match(materials, pixel)
if match is False:
logger.info(f"x, y: {int(x)} {int(y)} px; RGB: {pixel[:-1]}; material ID: {len(self.materials)}")
logger.info(
f"x, y: {int(x)} {int(y)} px; RGB: {pixel[:-1]}; material ID: {len(self.materials)}"
)
materials.append(pixel)
@@ -85,10 +87,17 @@ if __name__ == "__main__":
)
parser.add_argument("imagefile", help="name of image file including path")
parser.add_argument(
"dxdydz", type=float, action="append", nargs=3, help="spatial resolution of model, e.g. dx dy dz"
"dxdydz",
type=float,
action="append",
nargs=3,
help="spatial resolution of model, e.g. dx dy dz",
)
parser.add_argument(
"-zcells", default=1, type=int, help="number of cells for domain in z-direction (infinite direction)"
"-zcells",
default=1,
type=int,
help="number of cells for domain in z-direction (infinite direction)",
)
args = parser.parse_args()
@@ -97,7 +106,9 @@ if __name__ == "__main__":
# Store image data to use for creating geometry
imdata = np.rot90(im, k=3) # Rotate 90CW
imdata = np.floor(imdata * 255).astype(np.int16) # Convert pixel values from float (0-1) to integer (0-255)
imdata = np.floor(imdata * 255).astype(
np.int16
) # Convert pixel values from float (0-1) to integer (0-255)
logger.info(f"Reading PNG image file: {os.path.split(args.imagefile)[1]}")
logger.info(

查看文件

@@ -33,7 +33,11 @@ logging.basicConfig(format="%(message)s", level=logging.INFO)
# Host machine info.
hostinfo = get_host_info()
hyperthreadingstr = f", {hostinfo['logicalcores']} cores with Hyper-Threading" if hostinfo["hyperthreading"] else ""
hyperthreadingstr = (
f", {hostinfo['logicalcores']} cores with Hyper-Threading"
if hostinfo["hyperthreading"]
else ""
)
hostname = f"\n=== {hostinfo['hostname']}"
logging.info(f"{hostname} {'=' * (get_terminal_width() - len(hostname) - 1)}")
logging.info(f"\n{'Mfr/model:':<12} {hostinfo['machineID']}")
@@ -46,7 +50,8 @@ logging.info(f"{'OS/Version:':<12} {hostinfo['osversion']}")
# OpenMP
logging.info(
"\n\n=== OpenMP capabilities (gprMax will not use Hyper-Threading " + "as there is no performance advantage)\n"
"\n\n=== OpenMP capabilities (gprMax will not use Hyper-Threading "
+ "as there is no performance advantage)\n"
)
logging.info(f"{'OpenMP threads: '} {hostinfo['physicalcores']}")

查看文件

@@ -107,7 +107,9 @@ def merge_files(outputfiles, removefiles=False):
availableoutputs = list(fin[path].keys())
for output in availableoutputs:
grp.create_dataset(
output, (fout.attrs["Iterations"], len(outputfiles)), dtype=fin[path + "/" + output].dtype
output,
(fout.attrs["Iterations"], len(outputfiles)),
dtype=fin[path + "/" + output].dtype,
)
# For all receivers
@@ -134,9 +136,14 @@ if __name__ == "__main__":
+ "optionally removes the series of output files.",
usage="cd gprMax; python -m tools.outputfiles_merge basefilename",
)
parser.add_argument("basefilename", help="base name of output file series including path")
parser.add_argument(
"--remove-files", action="store_true", default=False, help="flag to remove individual output files after merge"
"basefilename", help="base name of output file series including path"
)
parser.add_argument(
"--remove-files",
action="store_true",
default=False,
help="flag to remove individual output files after merge",
)
args = parser.parse_args()