Merge branch 'devel' of https://github.com/gprMax/gprMax into devel

这个提交包含在:
Antonis Giannopoulos
2023-04-21 17:04:04 +01:00
当前提交 5df218601b
共有 56 个文件被更改,包括 773 次插入823 次删除

13
.github/FUNDING.yml vendored 普通文件
查看文件

@@ -0,0 +1,13 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: gprMax
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

二进制文件未显示。

二进制文件未显示。

查看文件

@@ -41,7 +41,7 @@ gv2 = gprMax.GeometryView(p1=(ant_pos[0] - 0.170/2, ant_pos[1] - 0.108/2, ant_po
p2=(ant_pos[0] + 0.170/2, ant_pos[1] + 0.108/2, ant_pos[2] + 0.010),
dl=(dl, dl, dl), filename='antenna_like_GSSI_1500_pcb',
output_type='f')
scene.add(gv1)
#scene.add(gv1)
#scene.add(gv2)
# Run model

二进制文件未显示。

查看文件

@@ -89,17 +89,10 @@ gv1 = gprMax.GeometryView(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
scene.add(gv1)
# Create some snapshots of entire domain
# for i in range(5):
# s = gprMax.Snapshot(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
# time=(i + 0.5) * 1e-9,
# filename=fn.with_suffix('').parts[-1] + '_' + str(i + 1))
# scene.add(s)
for i in range(5):
s = gprMax.Snapshot(p1=sg1, p2=sg2, dl=(dl_sg, dl_sg, dl_sg),
s = gprMax.Snapshot(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
time=(i + 0.5) * 1e-9,
filename=fn.with_suffix('').parts[-1] + '_' + str(i + 1),
outputs=['Ez'])
subgrid.add(s)
filename=fn.with_suffix('').parts[-1] + '_' + str(i + 1))
scene.add(s)
gprMax.run(scenes=[scene], n=1, geometry_only=False, outputfile=fn, subgrid=True, autotranslate=True)

查看文件

@@ -102,9 +102,11 @@ halfspace = gprMax.Box(p1=(0, 0, 0), p2=(x, y, antenna_p[2]), material_id='soil'
scene.add(halfspace)
for i in range(1, 51):
snap = gprMax.Snapshot(p1=(0, y / 2, 0), p2=(x, y / 2 + dl, z), dl=(dl, dl, dl),
filename=Path(*parts[:-1], parts[-1] + '_' + str(i)).name,
time=i * tw / 50)
snap = gprMax.Snapshot(p1=(0, y / 2, 0),
p2=(x, y / 2 + dl, z),
dl=(dl, dl, dl),
filename=Path(*parts[:-1], f'{parts[-1]}_{str(i)}').name,
time=i * tw / 50,)
scene.add(snap)
# create a geometry view of the main grid and the sub grid stitched together

查看文件

@@ -25,8 +25,9 @@ from .cmds_geometry.triangle import Triangle
from .cmds_multiuse import (PMLCFS, AddDebyeDispersion, AddDrudeDispersion,
AddLorentzDispersion, GeometryObjectsWrite,
GeometryView, HertzianDipole, MagneticDipole,
Material, Rx, RxArray, Snapshot, SoilPeplinski,
TransmissionLine, VoltageSource, Waveform, MaterialRange, MaterialList)
Material, MaterialList, MaterialRange, Rx, RxArray,
Snapshot, SoilPeplinski, TransmissionLine,
VoltageSource, Waveform)
from .cmds_singleuse import (Discretisation, Domain, ExcitationFile,
OMPThreads, PMLProps, RxSteps, SrcSteps,
TimeStepStabilityFactor, TimeWindow, Title)

查看文件

@@ -74,7 +74,7 @@ class AddGrass(UserObjectGeometry):
limits = self.kwargs['limits']
n_blades = self.kwargs['n_blades']
except KeyError:
logger.exception(self.__str__() + ' requires at least eleven parameters')
logger.exception(f'{self.__str__()} requires at least eleven parameters')
raise
try:
@@ -90,7 +90,7 @@ class AddGrass(UserObjectGeometry):
try:
volume = volumes[0]
except NameError:
logger.exception(self.__str__() + f' 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__())
@@ -98,32 +98,32 @@ class AddGrass(UserObjectGeometry):
xf, yf, zf = p2
if frac_dim < 0:
logger.exception(self.__str__() + ' requires a positive value for ' +
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(self.__str__() + ' requires a positive value for ' +
logger.exception(f'{self.__str__()} requires a positive value for ' +
'the minimum and maximum heights for grass blades')
raise ValueError
# Check for valid orientations
if xs == xf:
if ys == yf or zs == zf:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
raise ValueError
if xs != volume.xs and xs != volume.xf:
logger.exception(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))
# xminus surface
if xs == volume.xs:
logger.exception(self.__str__() + ' grass can only be specified ' +
logger.exception(f'{self.__str__()} grass can only be specified ' +
'on surfaces in the positive axis direction')
raise ValueError
# xplus surface
elif xf == volume.xf:
if fractalrange[1] > grid.nx:
logger.exception(self.__str__() + ' cannot apply grass to ' +
logger.exception(f'{self.__str__()} cannot apply grass to ' +
'fractal box as it would exceed the domain ' +
'size in the x direction')
raise ValueError
@@ -131,21 +131,21 @@ class AddGrass(UserObjectGeometry):
elif ys == yf:
if xs == xf or zs == zf:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
raise ValueError
if ys != volume.ys and ys != volume.yf:
logger.exception(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))
# yminus surface
if ys == volume.ys:
logger.exception(self.__str__() + ' grass can only be specified ' +
logger.exception(f'{self.__str__()} grass can only be specified ' +
'on surfaces in the positive axis direction')
raise ValueError
# yplus surface
elif yf == volume.yf:
if fractalrange[1] > grid.ny:
logger.exception(self.__str__() + ' cannot apply grass to ' +
logger.exception(f'{self.__str__()} cannot apply grass to ' +
'fractal box as it would exceed the domain ' +
'size in the y direction')
raise ValueError
@@ -153,28 +153,28 @@ class AddGrass(UserObjectGeometry):
elif zs == zf:
if xs == xf or ys == yf:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
raise ValueError
if zs != volume.zs and zs != volume.zf:
logger.exception(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))
# zminus surface
if zs == volume.zs:
logger.exception(self.__str__() + ' grass can only be specified ' +
logger.exception(f'{self.__str__()} grass can only be specified ' +
'on surfaces in the positive axis direction')
raise ValueError
# zplus surface
elif zf == volume.zf:
if fractalrange[1] > grid.nz:
logger.exception(self.__str__() + ' cannot apply grass to ' +
logger.exception(f'{self.__str__()} cannot apply grass to ' +
'fractal box as it would exceed the domain ' +
'size in the z direction')
raise ValueError
requestedsurface = 'zplus'
else:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
raise ValueError
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim)
@@ -187,7 +187,7 @@ class AddGrass(UserObjectGeometry):
surface.operatingonID = volume.ID
surface.generate_fractal_surface()
if n_blades > surface.fractalsurface.shape[0] * surface.fractalsurface.shape[1]:
logger.exception(self.__str__() + ' the specified surface is not large ' +
logger.exception(f'{self.__str__()} the specified surface is not large ' +
'enough for the number of grass blades/roots specified')
raise ValueError
@@ -234,13 +234,13 @@ class AddGrass(UserObjectGeometry):
grass = next((x for x in grid.materials if x.ID == 'grass'))
testgrass = next((x for x in grass.tau if x < grid.dt), None)
if testgrass:
logger.exception(self.__str__() + ' requires the time step for the ' +
logger.exception(f'{self.__str__()} requires the time step for the ' +
'model to be less than the relaxation time required to model grass.')
raise ValueError
volume.fractalsurfaces.append(surface)
logger.info(self.grid_name(grid) + f'{n_blades} blades of grass on surface from ' +
logger.info(f'{self.grid_name(grid)}{n_blades} blades of grass on surface from ' +
f'{xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, ' +
f'to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m ' +
f'with fractal dimension {surface.dimension:g}, fractal seeding ' +

查看文件

@@ -74,13 +74,13 @@ class AddSurfaceRoughness(UserObjectGeometry):
limits = np.array(self.kwargs['limits'])
fractal_box_id = self.kwargs['fractal_box_id']
except KeyError:
logger.exception(self.__str__() + ' incorrect parameters')
logger.exception(f'{self.__str__()} incorrect parameters')
raise
try:
seed = self.kwargs['seed']
except KeyError:
logger.warning(self.__str__() + ' no value for seed detected. This ' +
logger.warning(f'{self.__str__()} no value for seed detected. This ' +
'means you will get a different fractal distribution ' +
'every time the model runs.')
seed = None
@@ -93,7 +93,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
if volumes:
volume = volumes[0]
else:
logger.exception(self.__str__() + f' 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__())
@@ -101,25 +101,25 @@ class AddSurfaceRoughness(UserObjectGeometry):
xf, yf, zf = p2
if frac_dim < 0:
logger.exception(self.__str__() + ' requires a positive value for the ' +
logger.exception(f'{self.__str__()} requires a positive value for the ' +
'fractal dimension')
raise ValueError
if weighting[0] < 0:
logger.exception(self.__str__() + ' requires a positive value for the ' +
logger.exception(f'{self.__str__()} requires a positive value for the ' +
'fractal weighting in the first direction of the surface')
raise ValueError
if weighting[1] < 0:
logger.exception(self.__str__() + ' requires a positive value for the ' +
logger.exception(f'{self.__str__()} requires a positive value for the ' +
'fractal weighting in the second direction of the surface')
raise ValueError
# Check for valid orientations
if xs == xf:
if ys == yf or zs == zf:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
raise ValueError
if xs != volume.xs and xs != volume.xf:
logger.exception(self.__str__() + ' can only be used on the external ' +
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),
@@ -127,7 +127,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
# xminus surface
if xs == volume.xs:
if fractalrange[0] < 0 or fractalrange[1] > volume.xf:
logger.exception(self.__str__() + ' cannot apply fractal surface ' +
logger.exception(f'{self.__str__()} cannot apply fractal surface ' +
'to fractal box as it would exceed either the ' +
'upper coordinates of the fractal box or the ' +
'domain in the x direction')
@@ -136,7 +136,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
# xplus surface
elif xf == volume.xf:
if fractalrange[0] < volume.xs or fractalrange[1] > grid.nx:
logger.exception(self.__str__() + ' cannot apply fractal surface ' +
logger.exception(f'{self.__str__()} cannot apply fractal surface ' +
'to fractal box as it would exceed either the ' +
'lower coordinates of the fractal box or the ' +
'domain in the x direction')
@@ -145,10 +145,10 @@ class AddSurfaceRoughness(UserObjectGeometry):
elif ys == yf:
if xs == xf or zs == zf:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
raise ValueError
if ys != volume.ys and ys != volume.yf:
logger.exception(self.__str__() + ' can only be used on the external ' +
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),
@@ -156,7 +156,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
# yminus surface
if ys == volume.ys:
if fractalrange[0] < 0 or fractalrange[1] > volume.yf:
logger.exception(self.__str__() + ' cannot apply fractal surface ' +
logger.exception(f'{self.__str__()} cannot apply fractal surface ' +
'to fractal box as it would exceed either the ' +
'upper coordinates of the fractal box or the ' +
'domain in the y direction')
@@ -165,7 +165,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
# yplus surface
elif yf == volume.yf:
if fractalrange[0] < volume.ys or fractalrange[1] > grid.ny:
logger.exception(self.__str__() + ' cannot apply fractal surface ' +
logger.exception(f'{self.__str__()} cannot apply fractal surface ' +
'to fractal box as it would exceed either the ' +
'lower coordinates of the fractal box or the ' +
'domain in the y direction')
@@ -174,10 +174,10 @@ class AddSurfaceRoughness(UserObjectGeometry):
elif zs == zf:
if xs == xf or ys == yf:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
raise ValueError
if zs != volume.zs and zs != volume.zf:
logger.exception(self.__str__() + ' can only be used on the external ' +
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),
@@ -185,7 +185,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
# zminus surface
if zs == volume.zs:
if fractalrange[0] < 0 or fractalrange[1] > volume.zf:
logger.exception(self.__str__() + ' cannot apply fractal surface ' +
logger.exception(f'{self.__str__()} cannot apply fractal surface ' +
'to fractal box as it would exceed either the ' +
'upper coordinates of the fractal box or the ' +
'domain in the x direction')
@@ -194,7 +194,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
# zplus surface
elif zf == volume.zf:
if fractalrange[0] < volume.zs or fractalrange[1] > grid.nz:
logger.exception(self.__str__() + ' cannot apply fractal surface ' +
logger.exception(f'{self.__str__()} cannot apply fractal surface ' +
'to fractal box as it would exceed either the ' +
'lower coordinates of the fractal box or the ' +
'domain in the z direction')
@@ -202,7 +202,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
requestedsurface = 'zplus'
else:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
raise ValueError
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim)
@@ -218,14 +218,14 @@ class AddSurfaceRoughness(UserObjectGeometry):
# List of existing surfaces IDs
existingsurfaceIDs = [x.surfaceID for x in volume.fractalsurfaces]
if surface.surfaceID in existingsurfaceIDs:
logger.exception(self.__str__() + f' has already been used on the ' +
logger.exception(f'{self.__str__()} has already been used on the ' +
f'{surface.surfaceID} surface')
raise ValueError
surface.generate_fractal_surface()
volume.fractalsurfaces.append(surface)
logger.info(self.grid_name(grid) + f'Fractal surface from {xs * grid.dx:g}m, ' +
logger.info(f'{self.grid_name(grid)}Fractal surface from {xs * grid.dx:g}m, ' +
f'{ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, ' +
f'{yf * grid.dy:g}m, {zf * grid.dz:g}m with fractal dimension ' +
f'{surface.dimension:g}, fractal weightings {surface.weighting[0]:g}, ' +

查看文件

@@ -68,18 +68,16 @@ class AddSurfaceWater(UserObjectGeometry):
fractal_box_id = self.kwargs['fractal_box_id']
depth = self.kwargs['depth']
except KeyError:
logger.exception(self.__str__() + ' requires exactly eight parameters')
logger.exception(f'{self.__str__()} requires exactly eight parameters')
raise
if self.do_rotate:
self._do_rotate()
# Get the correct fractal volume
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
if volumes:
if volumes := [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]:
volume = volumes[0]
else:
logger.exception(self.__str__() + f' 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__())
@@ -87,18 +85,18 @@ class AddSurfaceWater(UserObjectGeometry):
xf, yf, zf = p2
if depth <= 0:
logger.exception(self.__str__() + ' requires a positive value for ' +
'the depth of water')
logger.exception(f'{self.__str__()} requires a positive value for the ' +
f'depth of water')
raise ValueError
# Check for valid orientations
if xs == xf:
if ys == yf or zs == zf:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
raise ValueError
if xs != volume.xs and xs != volume.xf:
logger.exception(self.__str__() + ' can only be used on the ' +
'external surfaces of a fractal box')
if xs not in [volume.xs, volume.xf]:
logger.exception(f'{self.__str__()} can only be used on the external surfaces '
f'of a fractal box')
raise ValueError
# xminus surface
if xs == volume.xs:
@@ -110,12 +108,12 @@ class AddSurfaceWater(UserObjectGeometry):
filldepth = filldepthcells * grid.dx
elif ys == yf:
if xs == xf or zs == zf:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
if zs == zf:
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
raise ValueError
if ys != volume.ys and ys != volume.yf:
logger.exception(self.__str__() + ' can only be used on the ' +
'external surfaces of a fractal box')
if ys not in [volume.ys, volume.yf]:
logger.exception(f'{self.__str__()} can only be used on the external surfaces ' +
f'of a fractal box')
raise ValueError
# yminus surface
if ys == volume.ys:
@@ -127,12 +125,9 @@ class AddSurfaceWater(UserObjectGeometry):
filldepth = filldepthcells * grid.dy
elif zs == zf:
if xs == xf or ys == yf:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
raise ValueError
if zs != volume.zs and zs != volume.zf:
logger.exception(self.__str__() + ' can only be used on the ' +
'external surfaces of a fractal box')
if zs not in [volume.zs, volume.zf]:
logger.exception(f'{self.__str__()} can only be used on the external surfaces '
f'of a fractal box')
raise ValueError
# zminus surface
if zs == volume.zs:
@@ -144,38 +139,35 @@ class AddSurfaceWater(UserObjectGeometry):
filldepth = filldepthcells * grid.dz
else:
logger.exception(self.__str__() + ' dimensions are not specified correctly')
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)
if not surface:
logger.exception(self.__str__() + f' specified surface {requestedsurface} ' +
'does not have a rough surface applied')
logger.exception(f'{self.__str__()} specified surface {requestedsurface} ' +
f'does not have a rough surface applied')
raise ValueError
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]:
logger.exception(self.__str__() + ' requires a value for the depth ' +
'of water that lies with the range of the requested ' +
'surface roughness')
logger.exception(f'{self.__str__()} requires a value for the depth of water that lies with the ' +
f'range of the requested surface roughness')
raise ValueError
# Check to see if water has been already defined as a material
if not any(x.ID == 'water' for x in grid.materials):
if all(x.ID != 'water' for x in grid.materials):
create_water(grid)
# Check if time step for model is suitable for using water
water = next((x for x in grid.materials if x.ID == 'water'))
testwater = next((x for x in water.tau if x < grid.dt), None)
if testwater:
logger.exception(self.__str__() + ' requires the time step for the ' +
'model to be less than the relaxation time required ' +
'to model water.')
if testwater := next((x for x in water.tau if x < grid.dt), None):
logger.exception(f'{self.__str__()} requires the time step for the model '
f'to be less than the relaxation time required to model water.')
raise ValueError
logger.info(self.grid_name(grid) + f'Water on surface from {xs * grid.dx:g}m, ' +
logger.info(f'{self.grid_name(grid)}Water on surface from {xs * grid.dx:g}m, ' +
f'{ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, ' +
f'{yf * grid.dy:g}m, {zf * grid.dz:g}m with depth {filldepth:g}m, ' +
f'added to {surface.operatingonID}.')

查看文件

@@ -65,7 +65,7 @@ class Box(UserObjectGeometry):
p1 = self.kwargs['p1']
p2 = self.kwargs['p2']
except KeyError:
logger.exception(self.__str__() + ' Please specify two points.')
logger.exception(f'{self.__str__()} Please specify two points.')
raise
if self.do_rotate:
@@ -80,7 +80,7 @@ class Box(UserObjectGeometry):
try:
materialsrequested = self.kwargs['material_ids']
except KeyError:
logger.exception(self.__str__() + ' No materials have been specified')
logger.exception(f'{self.__str__()} No materials have been specified')
raise
# Check averaging
@@ -103,7 +103,7 @@ class Box(UserObjectGeometry):
if len(materials) != len(materialsrequested):
notfound = [x for x in materialsrequested if x not in materials]
logger.exception(self.__str__() + f' material(s) {notfound} do not exist')
logger.exception(f'{self.__str__()} material(s) {notfound} do not exist')
raise ValueError
# Isotropic case
@@ -144,7 +144,7 @@ class Box(UserObjectGeometry):
dielectricsmoothing = 'on' if averaging else 'off'
logger.info(self.grid_name(grid) + f"Box from {p5[0]:g}m, {p5[1]:g}m, " +
logger.info(f"{self.grid_name(grid)}Box from {p5[0]:g}m, {p5[1]:g}m, " +
f"{p5[2]:g}m, to {p6[0]:g}m, {p6[1]:g}m, {p6[2]:g}m of " +
f"material(s) {', '.join(materialsrequested)} created, " +
f"dielectric smoothing is {dielectricsmoothing}.")

查看文件

@@ -66,6 +66,5 @@ r = template.render(
}]
)
f = open('cython/dispersive_updates_test.pyx', 'w')
f.write(r)
f.close()
with open('cython/dispersive_updates_test.pyx', 'w') as f:
f.write(r)

查看文件

@@ -38,9 +38,9 @@ class UserObjectGeometry:
"""Readable string of parameters given to object."""
s = ''
for _, v in self.kwargs.items():
if isinstance(v, tuple) or isinstance(v, list):
if isinstance(v, (tuple, list)):
v = ' '.join([str(el) for el in v])
s += str(v) + ' '
s += f'{str(v)} '
return f'{self.hash}: {s[:-1]}'
@@ -120,7 +120,7 @@ def rotate_2point_object(pts, axis, angle, origin=None):
raise ValueError
# Check axis is valid
if axis != 'x' and axis != 'y' and axis != 'z':
if axis not in ['x', 'y', 'z']:
logger.exception('Axis of rotation must be x, y, or z')
raise ValueError

查看文件

@@ -55,7 +55,7 @@ class Cone(UserObjectGeometry):
r1 = self.kwargs['r1']
r2 = self.kwargs['r2']
except KeyError:
logger.exception(self.__str__() + ' please specify 2 points and two radii')
logger.exception(f'{self.__str__()} please specify 2 points and two radii')
raise
# Check averaging
@@ -75,7 +75,7 @@ class Cone(UserObjectGeometry):
try:
materialsrequested = self.kwargs['material_ids']
except KeyError:
logger.exception(self.__str__() + ' no materials have been specified')
logger.exception(f'{self.__str__()} no materials have been specified')
raise
p3 = uip.round_to_grid_static_point(p1)
@@ -85,15 +85,15 @@ class Cone(UserObjectGeometry):
x2, y2, z2 = uip.round_to_grid(p2)
if r1 < 0:
logger.exception(self.__str__() + f' 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(self.__str__() + f' 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:
logger.exception(self.__str__() + f' not both radii can be zero.')
logger.exception(f'{self.__str__()} not both radii can be zero.')
raise ValueError
# Look up requested materials in existing list of material instances
@@ -101,7 +101,7 @@ class Cone(UserObjectGeometry):
if len(materials) != len(materialsrequested):
notfound = [x for x in materialsrequested if x not in materials]
logger.exception(self.__str__() + f' material(s) {notfound} do not exist')
logger.exception(f'{self.__str__()} material(s) {notfound} do not exist')
raise ValueError
# Isotropic case
@@ -141,7 +141,7 @@ class Cone(UserObjectGeometry):
grid.rigidE, grid.rigidH, grid.ID)
dielectricsmoothing = 'on' if averaging else 'off'
logger.info(self.grid_name(grid) + f"Cone with face centres {p3[0]:g}m, " +
logger.info(f"{self.grid_name(grid)}Cone with face centres {p3[0]:g}m, " +
f"{p3[1]:g}m, {p3[2]:g}m and {p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m, " +
f"with radii {r1:g}m and {r2:g}, of material(s) {', '.join(materialsrequested)} " +
f"created, dielectric smoothing is {dielectricsmoothing}.")

查看文件

@@ -52,7 +52,7 @@ class Cylinder(UserObjectGeometry):
p2 = self.kwargs['p2']
r = self.kwargs['r']
except KeyError:
logger.exception(self.__str__() + ' please specify 2 points and a radius')
logger.exception(f'{self.__str__()} please specify 2 points and a radius')
raise
# Check averaging
@@ -72,7 +72,7 @@ class Cylinder(UserObjectGeometry):
try:
materialsrequested = self.kwargs['material_ids']
except KeyError:
logger.exception(self.__str__() + ' no materials have been specified')
logger.exception(f'{self.__str__()} no materials have been specified')
raise
p3 = uip.round_to_grid_static_point(p1)
@@ -82,7 +82,7 @@ class Cylinder(UserObjectGeometry):
x2, y2, z2 = uip.round_to_grid(p2)
if r <= 0:
logger.exception(self.__str__() + f' 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
@@ -90,7 +90,7 @@ class Cylinder(UserObjectGeometry):
if len(materials) != len(materialsrequested):
notfound = [x for x in materialsrequested if x not in materials]
logger.exception(self.__str__() + f' material(s) {notfound} do not exist')
logger.exception(f'{self.__str__()} material(s) {notfound} do not exist')
raise ValueError
# Isotropic case
@@ -130,7 +130,7 @@ class Cylinder(UserObjectGeometry):
grid.rigidE, grid.rigidH, grid.ID)
dielectricsmoothing = 'on' if averaging else 'off'
logger.info(self.grid_name(grid) + f"Cylinder with face centres {p3[0]:g}m, " +
logger.info(f"{self.grid_name(grid)}Cylinder with face centres {p3[0]:g}m, " +
f"{p3[1]:g}m, {p3[2]:g}m and {p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m, " +
f"with radius {r:g}m, of material(s) {', '.join(materialsrequested)} " +
f"created, dielectric smoothing is {dielectricsmoothing}.")

查看文件

@@ -88,24 +88,25 @@ class CylindricalSector(UserObjectGeometry):
try:
materialsrequested = self.kwargs['material_ids']
except KeyError:
logger.exception(self.__str__() + ' No materials have been specified')
logger.exception(f'{self.__str__()} No materials have been specified')
raise
sectorstartangle = 2 * np.pi * (start / 360)
sectorangle = 2 * np.pi * (end / 360)
if normal != 'x' and normal != 'y' and normal != 'z':
logger.exception(self.__str__() + ' the normal direction must be either x, y or z.')
if normal not in ['x', 'y', 'z']:
logger.exception(f'{self.__str__()} the normal direction must be either ' +
f'x, y or z.')
raise ValueError
if r <= 0:
logger.exception(self.__str__() + f' 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(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 ' +
f'a positive values.')
raise ValueError
if sectorstartangle >= 2 * np.pi or sectorangle >= 2 * np.pi:
logger.exception(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 ' +
f'less than 360 degrees.')
raise ValueError
# Look up requested materials in existing list of material instances
@@ -113,7 +114,7 @@ class CylindricalSector(UserObjectGeometry):
if len(materials) != len(materialsrequested):
notfound = [x for x in materialsrequested if x not in materials]
logger.exception(self.__str__() + f' material(s) {notfound} do not exist')
logger.exception(f'{self.__str__()} material(s) {notfound} do not exist')
raise ValueError
if thickness > 0:
@@ -122,13 +123,12 @@ class CylindricalSector(UserObjectGeometry):
averaging = materials[0].averagable and averagecylindricalsector
numID = numIDx = numIDy = numIDz = materials[0].numID
# Uniaxial anisotropic case
elif len(materials) == 3:
averaging = False
numIDx = materials[0].numID
numIDy = materials[1].numID
numIDz = materials[2].numID
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
requiredID = f'{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
@@ -181,14 +181,14 @@ class CylindricalSector(UserObjectGeometry):
if thickness > 0:
dielectricsmoothing = 'on' if averaging else 'off'
logger.info(self.grid_name(grid) + f"Cylindrical sector with centre " +
logger.info(f"{self.grid_name(grid)}Cylindrical sector with centre " +
f"{ctr1:g}m, {ctr2:g}m, radius {r:g}m, starting angle " +
f"{(sectorstartangle / (2 * np.pi)) * 360:.1f} degrees, " +
f"sector angle {(sectorangle / (2 * np.pi)) * 360:.1f} degrees, " +
f"thickness {thickness:g}m, of material(s) {', '.join(materialsrequested)} " +
f"created, dielectric smoothing is {dielectricsmoothing}.")
else:
logger.info(self.grid_name(grid) + f"Cylindrical sector with centre " +
logger.info(f"{self.grid_name(grid)}Cylindrical sector with centre " +
f"{ctr1:g}m, {ctr2:g}m, radius {r:g}m, starting angle " +
f"{(sectorstartangle / (2 * np.pi)) * 360:.1f} degrees, " +
f"sector angle {(sectorangle / (2 * np.pi)) * 360:.1f} " +

查看文件

@@ -62,7 +62,7 @@ class Edge(UserObjectGeometry):
p2 = self.kwargs['p2']
material_id = self.kwargs['material_id']
except KeyError:
logger.exception(self.__str__() + ' requires exactly 3 parameters')
logger.exception(f'{self.__str__()} requires exactly 3 parameters')
raise
if self.do_rotate:
@@ -83,32 +83,23 @@ class Edge(UserObjectGeometry):
# Check for valid orientations
# x-orientated edge
if xs != xf:
if ys != yf or zs != zf:
logger.exception(self.__str__() + ' the edge is not specified correctly')
raise ValueError
else:
for i in range(xs, xf):
build_edge_x(i, ys, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
if ((xs != xf and (ys != yf or zs != zf))
or (ys != yf and (xs != xf or zs != zf))
or (zs != zf and (xs != xf or ys != yf))):
logger.exception(f'{self.__str__()} the edge is not specified correctly')
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)
# y-orientated edge
elif ys != yf:
if xs != xf or zs != zf:
logger.exception(self.__str__() + ' the edge is not specified correctly')
raise ValueError
else:
for j in range(ys, yf):
build_edge_y(xs, j, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
for j in range(ys, yf):
build_edge_y(xs, j, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
# z-orientated edge
elif zs != zf:
if xs != xf or ys != yf:
logger.exception(self.__str__() + ' the edge is not specified correctly')
raise ValueError
else:
for k in range(zs, zf):
build_edge_z(xs, ys, k, material.numID, grid.rigidE, grid.rigidH, grid.ID)
for k in range(zs, zf):
build_edge_z(xs, ys, k, material.numID, grid.rigidE, grid.rigidH, grid.ID)
logger.info(self.grid_name(grid) + f'Edge from {p3[0]:g}m, {p3[1]:g}m, ' +
logger.info(f'{self.grid_name(grid)}Edge from {p3[0]:g}m, {p3[1]:g}m, ' +
f'{p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m of ' +
f'material {material_id} created.')

查看文件

@@ -53,7 +53,7 @@ class Ellipsoid(UserObjectGeometry):
zr = self.kwargs['zr']
except KeyError:
logger.exception(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
@@ -73,7 +73,7 @@ class Ellipsoid(UserObjectGeometry):
try:
materialsrequested = self.kwargs['material_ids']
except KeyError:
logger.exception(self.__str__() + ' no materials have been specified')
logger.exception(f'{self.__str__()} no materials have been specified')
raise
# Centre of sphere
@@ -86,7 +86,7 @@ class Ellipsoid(UserObjectGeometry):
if len(materials) != len(materialsrequested):
notfound = [x for x in materialsrequested if x not in materials]
logger.exception(self.__str__() + f' material(s) {notfound} do not exist')
logger.exception(f'{self.__str__()} material(s) {notfound} do not exist')
raise ValueError
# Isotropic case
@@ -126,7 +126,7 @@ class Ellipsoid(UserObjectGeometry):
grid.rigidE, grid.rigidH, grid.ID)
dielectricsmoothing = 'on' if averaging else 'off'
logger.info(self.grid_name(grid) + f"Ellipsoid with centre {p2[0]:g}m, " +
logger.info(f"{self.grid_name(grid)}Ellipsoid with centre {p2[0]:g}m, " +
f"{p2[1]:g}m, {p2[2]:g}m, x-semiaxis {xr:g}m, y-semiaxis {yr:g}m and z-semiaxis {zr:g}m of material(s) " +
f"{', '.join(materialsrequested)} created, dielectric " +
f"smoothing is {dielectricsmoothing}.")

查看文件

@@ -78,13 +78,13 @@ class FractalBox(UserObjectGeometry):
mixing_model_id = self.kwargs['mixing_model_id']
ID = self.kwargs['id']
except KeyError:
logger.exception(self.__str__() + ' Incorrect parameters')
logger.exception(f'{self.__str__()} Incorrect parameters')
raise
try:
seed = self.kwargs['seed']
except KeyError:
logger.warning(self.__str__() + ' no value for seed detected. This ' +
logger.warning(f'{self.__str__()} no value for seed detected. This ' +
'means you will get a different fractal distribution ' +
'every time the model runs.')
seed = None
@@ -109,22 +109,22 @@ class FractalBox(UserObjectGeometry):
xf, yf, zf = p2
if frac_dim < 0:
logger.exception(self.__str__() + ' requires a positive value for the ' +
logger.exception(f'{self.__str__()} requires a positive value for the ' +
'fractal dimension')
raise ValueError
if weighting[0] < 0:
logger.exception(self.__str__() + ' requires a positive value for the ' +
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(self.__str__() + ' requires a positive value for the ' +
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(self.__str__() + ' requires a positive value for the ' +
logger.exception(f'{self.__str__()} requires a positive value for the ' +
'fractal weighting in the z direction')
if n_materials < 0:
logger.exception(self.__str__() + ' requires a positive value for the ' +
logger.exception(f'{self.__str__()} requires a positive value for the ' +
'number of bins')
raise ValueError
@@ -136,14 +136,14 @@ class FractalBox(UserObjectGeometry):
if mixingmodel:
if nbins == 1:
logger.exception(self.__str__() + ' must be used with more than ' +
logger.exception(f'{self.__str__()} must be used with more than ' +
'one material from the 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(self.__str__() + f' mixing model or material with ' +
logger.exception(f'{self.__str__()} mixing model or material with ' +
'ID {mixing_model_id} does not exist')
raise ValueError
@@ -160,7 +160,7 @@ class FractalBox(UserObjectGeometry):
volume.mixingmodel = mixingmodel
dielectricsmoothing = 'on' if volume.averaging else 'off'
logger.info(self.grid_name(grid) + f'Fractal box {volume.ID} from ' +
logger.info(f'{self.grid_name(grid)}Fractal box {volume.ID} from ' +
f'{p3[0]:g}m, {p3[1]:g}m, {p3[2]:g}m, to {p4[0]:g}m, ' +
f'{p4[1]:g}m, {p4[2]:g}m with {volume.operatingonID}, ' +
f'fractal dimension {volume.dimension:g}, fractal weightings ' +

查看文件

@@ -319,7 +319,7 @@ class FractalBoxBuilder(UserObjectGeometry):
else:
if volume.nbins == 1:
logger.exception(self.__str__() + ' is being used with a ' +
logger.exception(f'{self.__str__()} is being used with a ' +
'single material and no modifications, ' +
'therefore please use a #box command instead.')
raise ValueError

查看文件

@@ -46,7 +46,7 @@ class GeometryObjectsRead(UserObjectGeometry):
geofile = self.kwargs['geofile']
matfile = self.kwargs['matfile']
except KeyError:
logger.exception(self.__str__() + 'requires exactly five parameters')
logger.exception(f'{self.__str__()} requires exactly five parameters')
raise
# Discretise the point using uip object. This has different behaviour
@@ -100,7 +100,7 @@ class GeometryObjectsRead(UserObjectGeometry):
if round_value((dx_dy_dz[0] / grid.dx) != 1 or
round_value(dx_dy_dz[1] / grid.dy) != 1 or
round_value(dx_dy_dz[2] / grid.dz) != 1):
logger.exception(self.__str__() + ' requires the spatial resolution ' +
logger.exception(f'{self.__str__()} requires the spatial resolution ' +
'of the geometry objects file to match the spatial ' +
'resolution of the model')
raise ValueError
@@ -122,7 +122,7 @@ class GeometryObjectsRead(UserObjectGeometry):
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(self.grid_name(grid) + f'Geometry objects from file {geofile} ' +
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, ' +
f'{zs * grid.dz:g}m, with corresponding materials file ' +
f'{matfile}.')
@@ -131,7 +131,7 @@ class GeometryObjectsRead(UserObjectGeometry):
build_voxels_from_array(xs, ys, zs, config.get_model_config().ompthreads,
numexistmaterials, averaging, data,
grid.solid, grid.rigidE, grid.rigidH, grid.ID)
logger.info(self.grid_name(grid) + f'Geometry objects from file ' +
logger.info(f'{self.grid_name(grid)}Geometry objects from file ' +
f'(voxels only){geofile} inserted at {xs * grid.dx:g}m, ' +
f'{ys * grid.dy:g}m, {zs * grid.dz:g}m, with corresponding ' +
f'materials file {matfile}.')

查看文件

@@ -61,7 +61,7 @@ class Plate(UserObjectGeometry):
p1 = self.kwargs['p1']
p2 = self.kwargs['p2']
except KeyError:
logger.exception(self.__str__() + ' 2 points must be specified')
logger.exception(f'{self.__str__()} 2 points must be specified')
raise
# isotropic
@@ -72,7 +72,7 @@ class Plate(UserObjectGeometry):
try:
materialsrequested = self.kwargs['material_ids']
except KeyError:
logger.exception(self.__str__() + ' No materials have been specified')
logger.exception(f'{self.__str__()} No materials have been specified')
raise
if self.do_rotate:
@@ -86,23 +86,10 @@ class Plate(UserObjectGeometry):
xf, yf, zf = p2
# Check for valid orientations
if xs == xf:
if ys == yf or zs == zf:
logger.exception(self.__str__() + ' the plate is not specified correctly')
raise ValueError
elif ys == yf:
if xs == xf or zs == zf:
logger.exception(self.__str__() + ' the plate is not specified correctly')
raise ValueError
elif zs == zf:
if xs == xf or ys == yf:
logger.exception(self.__str__() + ' the plate is not specified correctly')
raise ValueError
else:
logger.exception(self.__str__() + ' the plate is not specified correctly')
if ((xs == xf and (ys == yf or zs == zf))
or (ys == yf and (xs == xf or zs == zf))
or (zs == zf and (ys != yf and xs != xf))):
logger.exception(f'{self.__str__()} the plate is not specified correctly')
raise ValueError
# Look up requested materials in existing list of material instances
@@ -110,7 +97,7 @@ class Plate(UserObjectGeometry):
if len(materials) != len(materialsrequested):
notfound = [x for x in materialsrequested if x not in materials]
logger.exception(self.__str__() + f' material(s) {notfound} do not exist')
logger.exception(f'{self.__str__()} material(s) {notfound} do not exist')
raise ValueError
# yz-plane plate
@@ -161,6 +148,6 @@ class Plate(UserObjectGeometry):
build_face_xy(i, j, zs, numIDx, numIDy, grid.rigidE,
grid.rigidH, grid.ID)
logger.info(self.grid_name(grid) + f"Plate from {p3[0]:g}m, {p3[1]:g}m, " +
logger.info(f"{self.grid_name(grid)}Plate from {p3[0]:g}m, {p3[1]:g}m, " +
f"{p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m of " +
f"material(s) {', '.join(materialsrequested)} created.")

查看文件

@@ -48,7 +48,7 @@ class Sphere(UserObjectGeometry):
p1 = self.kwargs['p1']
r = self.kwargs['r']
except KeyError:
logger.exception(self.__str__() + ' please specify a point and a radius.')
logger.exception(f'{self.__str__()} please specify a point and a radius.')
raise
# Check averaging
@@ -68,7 +68,7 @@ class Sphere(UserObjectGeometry):
try:
materialsrequested = self.kwargs['material_ids']
except KeyError:
logger.exception(self.__str__() + ' no materials have been specified')
logger.exception(f'{self.__str__()} no materials have been specified')
raise
# Centre of sphere
@@ -85,7 +85,7 @@ class Sphere(UserObjectGeometry):
if len(materials) != len(materialsrequested):
notfound = [x for x in materialsrequested if x not in materials]
logger.exception(self.__str__() + f' material(s) {notfound} do not exist')
logger.exception(f'{self.__str__()} material(s) {notfound} do not exist')
raise ValueError
# Isotropic case
@@ -125,7 +125,7 @@ class Sphere(UserObjectGeometry):
grid.rigidE, grid.rigidH, grid.ID)
dielectricsmoothing = 'on' if averaging else 'off'
logger.info(self.grid_name(grid) + f"Sphere with centre {p2[0]:g}m, " +
logger.info(f"{self.grid_name(grid)}Sphere with centre {p2[0]:g}m, " +
f"{p2[1]:g}m, {p2[2]:g}m, radius {r:g}m, of material(s) " +
f"{', '.join(materialsrequested)} created, dielectric " +
f"smoothing is {dielectricsmoothing}.")

查看文件

@@ -70,7 +70,7 @@ class Triangle(UserObjectGeometry):
up3 = self.kwargs['p3']
thickness = self.kwargs['thickness']
except KeyError:
logger.exception(self.__str__() + ' specify 3 points and a thickness')
logger.exception(f'{self.__str__()} specify 3 points and a thickness')
raise
if self.do_rotate:
@@ -93,7 +93,7 @@ class Triangle(UserObjectGeometry):
try:
materialsrequested = self.kwargs['material_ids']
except KeyError:
logger.exception(self.__str__() + ' no materials have been specified')
logger.exception(f'{self.__str__()} no materials have been specified')
raise
p4 = uip.round_to_grid_static_point(up1)
@@ -108,21 +108,21 @@ class Triangle(UserObjectGeometry):
x3, y3, z3 = uip.round_to_grid(up3)
if thickness < 0:
logger.exception(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
# yz-plane triangle
if x1 == x2 and x2 == x3:
if x1 == x2 == x3:
normal = 'x'
# xz-plane triangle
elif y1 == y2 and y2 == y3:
elif y1 == y2 == y3:
normal = 'y'
# xy-plane triangle
elif z1 == z2 and z2 == z3:
elif z1 == z2 == z3:
normal = 'z'
else:
logger.exception(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
@@ -130,7 +130,7 @@ class Triangle(UserObjectGeometry):
if len(materials) != len(materialsrequested):
notfound = [x for x in materialsrequested if x not in materials]
logger.exception(self.__str__() + f' material(s) {notfound} do not exist')
logger.exception(f'{self.__str__()} material(s) {notfound} do not exist')
raise ValueError
if thickness > 0:
@@ -185,13 +185,13 @@ class Triangle(UserObjectGeometry):
if thickness > 0:
dielectricsmoothing = 'on' if averaging else 'off'
logger.info(self.grid_name(grid) + f"Triangle with coordinates " +
logger.info(f"{self.grid_name(grid)}Triangle with coordinates " +
f"{p4[0]:g}m {p4[1]:g}m {p4[2]:g}m, {p5[0]:g}m {p5[1]:g}m " +
f"{p5[2]:g}m, {p6[0]:g}m {p6[1]:g}m {p6[2]:g}m and thickness " +
f"{thickness:g}m of material(s) {', '.join(materialsrequested)} " +
f"created, dielectric smoothing is {dielectricsmoothing}.")
else:
logger.info(self.grid_name(grid) + f"Triangle with coordinates " +
logger.info(f"{self.grid_name(grid)}Triangle with coordinates " +
f"{p4[0]:g}m {p4[1]:g}m {p4[2]:g}m, {p5[0]:g}m {p5[1]:g}m " +
f"{p5[2]:g}m, {p6[0]:g}m {p6[1]:g}m {p6[2]:g}m of material(s) " +
f"{', '.join(materialsrequested)} created.")

查看文件

@@ -61,9 +61,9 @@ class UserObjectMulti:
"""Readable user string as per hash commands."""
s = ''
for _, v in self.kwargs.items():
if isinstance(v, tuple) or isinstance(v, list):
if isinstance(v, (tuple, list)):
v = ' '.join([str(el) for el in v])
s += str(v) + ' '
s += f'{str(v)} '
return f'{self.hash}: {s[:-1]}'
@@ -77,7 +77,7 @@ class UserObjectMulti:
def params_str(self):
"""Readable string of parameters given to object."""
return self.hash + ': ' + str(self.kwargs)
return f'{self.hash}: {str(self.kwargs)}'
def grid_name(self, grid):
"""Returns subgrid name for use with logging info. Returns an empty
@@ -114,12 +114,12 @@ class Waveform(UserObjectMulti):
try:
wavetype = self.kwargs['wave_type'].lower()
except KeyError:
logger.exception(self.params_str() + (f" must have one of the "
f"following types {','.join(WaveformUser.types)}."))
logger.exception(f"{self.params_str()} must have one of the " +
f"following types {','.join(WaveformUser.types)}.")
raise
if wavetype not in WaveformUser.types:
logger.exception(self.params_str() + (f" must have one of the "
f"following types {','.join(WaveformUser.types)}."))
logger.exception(f"{self.params_str()} must have one of the " +
f"following types {','.join(WaveformUser.types)}.")
raise ValueError
if wavetype != 'user':
@@ -243,18 +243,15 @@ class VoltageSource(UserObjectMulti):
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 == 'y' or polarisation == 'z')):
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.'))
raise ValueError
elif ('2D TMy' in config.get_model_config().mode and
(polarisation == 'x' or polarisation == 'z')):
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.'))
raise ValueError
elif ('2D TMz' in config.get_model_config().mode and
(polarisation == 'x' or polarisation == 'y')):
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.'))
raise ValueError
@@ -305,10 +302,7 @@ class VoltageSource(UserObjectMulti):
'less.'))
raise ValueError
v.start = start
if stop > grid.timewindow:
v.stop = grid.timewindow
else:
v.stop = stop
v.stop = min(stop, grid.timewindow)
startstop = (f' start time {v.start:g} secs, finish time '
f'{v.stop:g} secs ')
except KeyError:
@@ -318,7 +312,7 @@ class VoltageSource(UserObjectMulti):
v.calculate_waveform_values(grid)
logger.info(self.grid_name(grid) + f'Voltage source with polarity '
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.')
@@ -367,8 +361,7 @@ class HertzianDipole(UserObjectMulti):
p1 = self.kwargs['p1']
waveform_id = self.kwargs['waveform_id']
except KeyError:
logger.exception(self.params_str() + ' requires at least 3 ' +
'parameters.')
logger.exception(f'{self.params_str()} requires at least 3 parameters.')
raise
if self.do_rotate:
@@ -379,18 +372,15 @@ class HertzianDipole(UserObjectMulti):
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 == 'y' or polarisation == 'z')):
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.'))
raise ValueError
elif ('2D TMy' in config.get_model_config().mode and
(polarisation == 'x' or polarisation == 'z')):
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.'))
raise ValueError
elif ('2D TMz' in config.get_model_config().mode and
(polarisation == 'x' or polarisation == 'y')):
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.'))
raise ValueError
@@ -401,7 +391,7 @@ 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(self.params_str() + ' there is no waveform ' +
logger.exception(f'{self.params_str()} there is no waveform ' +
f'with the identifier {waveform_id}.')
raise ValueError
@@ -422,8 +412,7 @@ class HertzianDipole(UserObjectMulti):
h.xcoordorigin = xcoord
h.ycoordorigin = ycoord
h.zcoordorigin = zcoord
h.ID = (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:
@@ -431,25 +420,19 @@ class HertzianDipole(UserObjectMulti):
start = self.kwargs['start']
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.'))
logger.exception(f'{self.params_str()} delay of the initiation of the ' +
f'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(f'{self.params_str()} time to remove the source ' +
f'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(
f'{self.params_str()} duration of the source should not be zero or less.')
raise ValueError
h.start = start
if stop > grid.timewindow:
h.stop = grid.timewindow
else:
h.stop = stop
h.stop = min(stop, grid.timewindow)
startstop = (f' start time {h.start:g} secs, finish time '
f'{h.stop:g} secs ')
except KeyError:
@@ -460,12 +443,12 @@ class HertzianDipole(UserObjectMulti):
h.calculate_waveform_values(grid)
if config.get_model_config().mode == '2D':
logger.info(self.grid_name(grid) + f'Hertzian dipole is a line ' +
logger.info(f'{self.grid_name(grid)}Hertzian dipole is a line ' +
f'source in 2D with polarity {h.polarisation} at ' +
f'{p2[0]:g}m, {p2[1]:g}m, {p2[2]:g}m,' + startstop +
f'using waveform {h.waveformID} created.')
else:
logger.info(self.grid_name(grid) + f'Hertzian dipole with ' +
logger.info(f'{self.grid_name(grid)}Hertzian dipole with ' +
f'polarity {h.polarisation} at {p2[0]:g}m, ' +
f'{p2[1]:g}m, {p2[2]:g}m,' + startstop +
f'using waveform {h.waveformID} created.')
@@ -514,8 +497,7 @@ class MagneticDipole(UserObjectMulti):
p1 = self.kwargs['p1']
waveform_id = self.kwargs['waveform_id']
except KeyError:
logger.exception(self.params_str() + ' requires at least five '
'parameters.')
logger.exception(f'{self.params_str()} requires at least five parameters.')
raise
if self.do_rotate:
@@ -526,18 +508,15 @@ class MagneticDipole(UserObjectMulti):
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 == 'y' or polarisation == 'z')):
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.'))
raise ValueError
elif ('2D TMy' in config.get_model_config().mode and
(polarisation == 'x' or polarisation == 'z')):
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.'))
raise ValueError
elif ('2D TMz' in config.get_model_config().mode and
(polarisation == 'x' or polarisation == 'y')):
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.'))
raise ValueError
@@ -548,7 +527,7 @@ 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(self.params_str() + ' there is no waveform ' +
logger.exception(f'{self.params_str()} there is no waveform ' +
f'with the identifier {waveform_id}.')
raise ValueError
@@ -584,10 +563,7 @@ class MagneticDipole(UserObjectMulti):
'less.'))
raise ValueError
m.start = start
if stop > grid.timewindow:
m.stop = grid.timewindow
else:
m.stop = stop
m.stop = min(stop, grid.timewindow)
startstop = (f' start time {m.start:g} secs, '
f'finish time {m.stop:g} secs ')
except KeyError:
@@ -597,7 +573,7 @@ class MagneticDipole(UserObjectMulti):
m.calculate_waveform_values(grid)
logger.info(self.grid_name(grid) + f'Magnetic dipole with polarity ' +
logger.info(f'{self.grid_name(grid)}Magnetic dipole with polarity ' +
f'{m.polarisation} at {p2[0]:g}m, {p2[1]:g}m, {p2[2]:g}m,' +
startstop + f'using waveform {m.waveformID} created.')
@@ -647,17 +623,15 @@ class TransmissionLine(UserObjectMulti):
waveform_id = self.kwargs['waveform_id']
resistance = self.kwargs['resistance']
except KeyError:
logger.exception(self.params_str() + ' requires at least six '
'parameters.')
logger.exception(f'{self.params_str()} requires at least six parameters.')
raise
if self.do_rotate:
self._do_rotate(grid)
# Warn about using a transmission line on GPU
if (config.sim_config.general['solver'] == 'cuda' or
config.sim_config.general['solver'] == 'opencl'):
logger.exception(self.params_str() + ' cannot currently be used ' +
if (config.sim_config.general['solver'] in ['cuda', 'opencl']):
logger.exception(f'{self.params_str()} cannot currently be used ' +
'with the CUDA or OpenCL-based solver. Consider ' +
'using a #voltage_source instead.')
raise ValueError
@@ -667,18 +641,15 @@ class TransmissionLine(UserObjectMulti):
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 == 'y' or polarisation == 'z')):
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.'))
raise ValueError
elif ('2D TMy' in config.get_model_config().mode and
(polarisation == 'x' or polarisation == 'z')):
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.'))
raise ValueError
elif ('2D TMz' in config.get_model_config().mode and
(polarisation == 'x' or polarisation == 'y')):
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.'))
raise ValueError
@@ -688,14 +659,14 @@ class TransmissionLine(UserObjectMulti):
if resistance <= 0 or resistance >= config.sim_config.em_consts['z0']:
logger.exception(self.params_str() + ' requires a resistance ' +
logger.exception(f'{self.params_str()} requires a resistance ' +
'greater than zero and less than the impedance ' +
'of free space, i.e. 376.73 Ohms.')
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 ' +
logger.exception(f'{self.params_str()} there is no waveform ' +
f'with the identifier {waveform_id}.')
raise ValueError
@@ -729,11 +700,8 @@ class TransmissionLine(UserObjectMulti):
'less.'))
raise ValueError
t.start = start
if stop > grid.timewindow:
t.stop = grid.timewindow
else:
t.stop = stop
startstop = (f' start time {t.start:g} secs, finish time '
t.stop = min(stop, grid.timewindow)
startstop = (f' start time {t.start:g} secs, finish time ' +
f'{t.stop:g} secs ')
except KeyError:
t.start = 0
@@ -743,7 +711,7 @@ class TransmissionLine(UserObjectMulti):
t.calculate_waveform_values(grid)
t.calculate_incident_V_I(grid)
logger.info(self.grid_name(grid) + f'Transmission line with polarity ' +
logger.info(f'{self.grid_name(grid)}Transmission line with polarity ' +
f'{t.polarisation} at {p2[0]:g}m, {p2[1]:g}m, ' +
f'{p2[2]:g}m, resistance {t.resistance:.1f} Ohms,' +
startstop + f'using waveform {t.waveformID} created.')
@@ -817,16 +785,14 @@ class Rx(UserObjectMulti):
outputs = [self.kwargs['outputs']]
except KeyError:
# If no ID or outputs are specified, use default
r.ID = (r.__class__.__name__ + '(' + str(r.xcoord) + ',' +
str(r.ycoord) + ',' + str(r.zcoord) + ')')
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'])
else:
outputs.sort()
# Get allowable outputs
if (config.sim_config.general['solver'] =='cuda' or
config.sim_config.general['solver'] =='opencl'):
if config.sim_config.general['solver'] in ['cuda', 'opencl']:
allowableoutputs = RxUser.allowableoutputs_dev
else:
allowableoutputs = RxUser.allowableoutputs
@@ -836,14 +802,14 @@ class Rx(UserObjectMulti):
r.outputs[field] = np.zeros(grid.iterations,
dtype=config.sim_config.dtypes['float_or_double'])
else:
logger.exception(self.params_str() + ' contains an '
'output type that is not allowable. '
'Allowable outputs in current context are '
logger.exception(f'{self.params_str()} contains an output '
f'type that is not allowable. Allowable '
f'outputs in current context are '
f'{allowableoutputs}.')
raise ValueError
logger.info(self.grid_name(grid) + f"Receiver at {p2[0]:g}m, "
f"{p2[1]:g}m, {p2[2]:g}m with output component(s) "
logger.info(f"{self.grid_name(grid)}Receiver at {p2[0]:g}m, {p2[1]:g}m, "
f"{p2[2]:g}m with output component(s) "
f"{', '.join(r.outputs)} created.")
grid.rxs.append(r)
@@ -871,8 +837,7 @@ class RxArray(UserObjectMulti):
p2 = self.kwargs['p2']
dl = self.kwargs['dl']
except KeyError:
logger.exception(self.params_str() + ' requires exactly 9 '
'parameters')
logger.exception(f'{self.params_str()} requires exactly 9 parameters')
raise
xs, ys, zs = uip.check_src_rx_point(p1, self.params_str(), 'lower')
@@ -882,39 +847,39 @@ class RxArray(UserObjectMulti):
dx, dy, dz = uip.discretise_point(dl)
if xs > xf or ys > yf or zs > zf:
logger.exception(self.params_str() + ' the lower 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(self.params_str() + ' the step size should not '
logger.exception(f'{self.params_str()} the step size should not ' +
'be less than zero.')
raise ValueError
if dx < 1:
if dx == 0:
dx = 1
else:
logger.exception(self.params_str() + ' the step size should '
logger.exception(f'{self.params_str()} the step size should ' +
'not be less than the spatial discretisation.')
raise ValueError
if dy < 1:
if dy == 0:
dy = 1
else:
logger.exception(self.params_str() + ' the step size should '
logger.exception(f'{self.params_str()} the step size should ' +
'not be less than the spatial discretisation.')
raise ValueError
if dz < 1:
if dz == 0:
dz = 1
else:
logger.exception(self.params_str() + ' the step size should '
logger.exception(f'{self.params_str()} the step size should ' +
'not be less than the spatial discretisation.')
raise ValueError
logger.info(self.grid_name(grid) + f'Receiver array {p3[0]:g}m, '
f'{p3[1]:g}m, {p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m, '
f'{p4[2]:g}m with steps {dx * grid.dx:g}m, '
f'{dy * grid.dy:g}m, {dz * grid.dz:g}m')
logger.info(f'{self.grid_name(grid)}Receiver array '
f'{p3[0]:g}m, {p3[1]:g}m, {p3[2]:g}m, to '
f'{p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m with steps '
f'{dx * grid.dx:g}m, {dy * grid.dy:g}m, {dz * grid.dz:g}m')
for x in range(xs, xf + 1, dx):
for y in range(ys, yf + 1, dy):
@@ -930,8 +895,7 @@ class RxArray(UserObjectMulti):
p5 = np.array([x, y, z])
p5 = uip.descretised_to_continuous(p5)
p5 = uip.round_to_grid_static_point(p5)
r.ID = (r.__class__.__name__ + '(' + str(x) + ',' +
str(y) + ',' + str(z) + ')')
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'])
logger.info(f" Receiver at {p5[0]:g}m, {p5[1]:g}m, "
@@ -968,8 +932,7 @@ class Snapshot(UserObjectMulti):
def create(self, grid, uip):
if isinstance(grid, SubGridBaseGrid):
logger.exception(self.params_str() + ' do not add snapshots to '
'subgrids.')
logger.exception(f'{self.params_str()} do not add snapshots to subgrids.')
raise ValueError
try:
p1 = self.kwargs['p1']
@@ -977,8 +940,7 @@ class Snapshot(UserObjectMulti):
dl = self.kwargs['dl']
filename = self.kwargs['filename']
except KeyError:
logger.exception(self.params_str() + ' requires exactly 11 '
'parameters.')
logger.exception(f'{self.params_str()} requires exactly 11 parameters.')
raise
try:
@@ -986,7 +948,7 @@ class Snapshot(UserObjectMulti):
p4 = uip.round_to_grid_static_point(p2)
p1, p2 = uip.check_box_points(p1, p2, self.params_str())
except ValueError:
logger.exception(self.params_str() + ' point is outside the domain.')
logger.exception(f'{self.params_str()} point is outside the domain.')
raise
xs, ys, zs = p1
xf, yf, zf = p2
@@ -1001,13 +963,12 @@ class Snapshot(UserObjectMulti):
try:
time = self.kwargs['time']
except KeyError:
logger.exception(self.params_str() + ' requires exactly 5 '
'parameters.')
logger.exception(f'{self.params_str()} requires exactly 5 parameters.')
raise
if time > 0:
iterations = round_value((time / grid.dt)) + 1
else:
logger.exception(self.params_str() + ' time value must be '
logger.exception(f'{self.params_str()} time value must be ' +
'greater than zero.')
raise ValueError
@@ -1027,10 +988,10 @@ class Snapshot(UserObjectMulti):
# Check and set output names
for output in tmp:
if output not in SnapshotUser.allowableoutputs.keys():
logger.exception(self.params_str() + " contains an "
"output type that is not allowable. "
"Allowable outputs in current context are "
f"{', '.join(SnapshotUser.allowableoutputs.keys())}.")
logger.exception(f"{self.params_str()} contains an output "
f"type that is not allowable. Allowable "
f"outputs in current context are "
f"{', '.join(SnapshotUser.allowableoutputs.keys())}.")
raise ValueError
else:
outputs[output] = True
@@ -1039,15 +1000,15 @@ class Snapshot(UserObjectMulti):
outputs = dict.fromkeys(SnapshotUser.allowableoutputs, True)
if dx < 0 or dy < 0 or dz < 0:
logger.exception(self.params_str() + ' the step size should not '
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(self.params_str() + ' the step size should not '
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(self.params_str() + ' time value is not valid.')
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,
@@ -1088,39 +1049,37 @@ class Material(UserObjectMulti):
sm = self.kwargs['sm']
material_id = self.kwargs['id']
except KeyError:
logger.exception(self.params_str() + ' requires exactly five '
'parameters.')
logger.exception(f'{self.params_str()} requires exactly five parameters.')
raise
if er < 1:
logger.exception(self.params_str() + ' requires a positive value '
'of one or greater for static (DC) permittivity.')
logger.exception(f'{self.params_str()} requires a positive value of ' +
f'one or greater for static (DC) permittivity.')
raise ValueError
if se != 'inf':
se = float(se)
if se < 0:
logger.exception(self.params_str() + ' requires a positive '
'value for electric conductivity.')
logger.exception(f'{self.params_str()} requires a positive ' +
f'value for electric conductivity.')
raise ValueError
else:
se = float('inf')
if mr < 1:
logger.exception(self.params_str() + ' requires a positive value '
'of one or greater for magnetic permeability.')
logger.exception(f'{self.params_str()} requires a positive value of ' +
f'one or greater for magnetic permeability.')
raise ValueError
if sm < 0:
logger.exception(self.params_str() + ' requires a positive value '
'for magnetic loss.')
logger.exception(f'{self.params_str()} requires a positive value ' +
f'for magnetic loss.')
raise ValueError
if any(x.ID == material_id for x in grid.materials):
logger.exception(self.params_str() + f' with ID {material_id} '
'already exists')
logger.exception(f'{self.params_str()} with ID {material_id} ' +
f'already exists')
raise ValueError
# Create a new instance of the Material class material
# (start index after pec & free_space)
m = MaterialUser(len(grid.materials), material_id)
m.er = er
m.se = se
m.mr = mr
m.sm = sm
@@ -1129,9 +1088,10 @@ class Material(UserObjectMulti):
if m.se == float('inf'):
m.averagable = False
logger.info(self.grid_name(grid) + f'Material {m.ID} with '
f'eps_r={m.er:g}, sigma={m.se:g} S/m; mu_r={m.mr:g}, '
f'sigma*={m.sm:g} Ohm/m created.')
m.er = er
logger.info(f'{self.grid_name(grid)}Material {m.ID} with eps_r={m.er:g}, '
f'sigma={m.se:g} S/m; mu_r={m.mr:g}, sigma*={m.sm:g} Ohm/m '
f'created.')
grid.materials.append(m)
@@ -1162,12 +1122,11 @@ class AddDebyeDispersion(UserObjectMulti):
tau = self.kwargs['tau']
material_ids = self.kwargs['material_ids']
except KeyError:
logger.exception(self.params_str() + ' requires at least four '
'parameters.')
logger.exception(f'{self.params_str()} requires at least four parameters.')
raise
if poles < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for number of poles.')
raise ValueError
@@ -1176,8 +1135,7 @@ class AddDebyeDispersion(UserObjectMulti):
if len(materials) != len(material_ids):
notfound = [x for x in material_ids if x not in materials]
logger.exception(self.params_str() + f' material(s) {notfound} do '
'not exist')
logger.exception(f'{self.params_str()} material(s) {notfound} do not exist')
raise ValueError
for material in materials:
@@ -1189,14 +1147,14 @@ class AddDebyeDispersion(UserObjectMulti):
disp_material.type = 'debye'
disp_material.poles = poles
disp_material.averagable = False
for i in range(0, poles):
for i in range(poles):
if tau[i] > 0:
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(self.params_str() + ' requires positive '
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']:
@@ -1205,7 +1163,7 @@ class AddDebyeDispersion(UserObjectMulti):
# Replace original material with newly created DispersiveMaterial
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
logger.info(self.grid_name(grid) + f"Debye disperion added to {disp_material.ID} "
logger.info(f"{self.grid_name(grid)}Debye disperion added to {disp_material.ID} "
f"with delta_eps_r={', '.join('%4.2f' % deltaer for deltaer in disp_material.deltaer)}, "
f"and tau={', '.join('%4.3e' % tau for tau in disp_material.tau)} secs created.")
@@ -1238,12 +1196,11 @@ class AddLorentzDispersion(UserObjectMulti):
delta = self.kwargs['delta']
material_ids = self.kwargs['material_ids']
except KeyError:
logger.exception(self.params_str() + ' requires at least five '
'parameters.')
logger.exception(f'{self.params_str()} requires at least five parameters.')
raise
if poles < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for number of poles.')
raise ValueError
@@ -1252,8 +1209,7 @@ class AddLorentzDispersion(UserObjectMulti):
if len(materials) != len(material_ids):
notfound = [x for x in material_ids if x not in materials]
logger.exception(self.params_str() + f' material(s) {notfound} do '
'not exist')
logger.exception(f'{self.params_str()} material(s) {notfound} do not exist')
raise ValueError
for material in materials:
@@ -1265,13 +1221,13 @@ class AddLorentzDispersion(UserObjectMulti):
disp_material.type = 'lorentz'
disp_material.poles = poles
disp_material.averagable = False
for i in range(0, poles):
for i in range(poles):
if er_delta[i] > 0 and omega[i] > grid.dt and delta[i] > grid.dt:
disp_material.deltaer.append(er_delta[i])
disp_material.tau.append(omega[i])
disp_material.alpha.append(delta[i])
else:
logger.exception(self.params_str() + ' requires positive '
logger.exception(f'{self.params_str()} requires positive '
'values for the permittivity difference '
'and frequencies, and associated times '
'that are greater than the time step for '
@@ -1283,10 +1239,11 @@ class AddLorentzDispersion(UserObjectMulti):
# Replace original material with newly created DispersiveMaterial
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
logger.info(self.grid_name(grid) + f"Lorentz disperion added to {disp_material.ID} "
f"with delta_eps_r={', '.join('%4.2f' % deltaer for deltaer in disp_material.deltaer)}, "
f"omega={', '.join('%4.3e' % omega for omega in disp_material.tau)} secs, "
f"and gamma={', '.join('%4.3e' % delta for delta in disp_material.alpha)} created.")
logger.info(
f"{self.grid_name(grid)}Lorentz disperion added to {disp_material.ID} " +
f"with delta_eps_r={', '.join('%4.2f' % deltaer for deltaer in disp_material.deltaer)}, " +
f"omega={', '.join('%4.3e' % omega for omega in disp_material.tau)} secs, " +
f"and gamma={', '.join('%4.3e' % delta for delta in disp_material.alpha)} created.")
class AddDrudeDispersion(UserObjectMulti):
@@ -1313,12 +1270,12 @@ class AddDrudeDispersion(UserObjectMulti):
alpha = self.kwargs['alpha']
material_ids = self.kwargs['material_ids']
except KeyError:
logger.exception(self.params_str() + ' requires at least four '
logger.exception(f'{self.params_str()} requires at least four ' +
'parameters.')
raise
if poles < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for number of poles.')
raise ValueError
@@ -1327,8 +1284,7 @@ class AddDrudeDispersion(UserObjectMulti):
if len(materials) != len(material_ids):
notfound = [x for x in material_ids if x not in materials]
logger.exception(self.params_str() + f' material(s) {notfound} do '
'not exist.')
logger.exception(f'{self.params_str()} material(s) {notfound} do not exist.')
raise ValueError
for material in materials:
@@ -1340,14 +1296,14 @@ class AddDrudeDispersion(UserObjectMulti):
disp_material.type = 'drude'
disp_material.poles = poles
disp_material.averagable = False
for i in range(0, poles):
for i in range(poles):
if omega[i] > 0 and alpha[i] > grid.dt:
disp_material.tau.append(omega[i])
disp_material.alpha.append(alpha[i])
else:
logger.exception(self.params_str() + ' requires positive '
'values for the frequencies, and '
'associated times that are greater than '
logger.exception(f'{self.params_str()} requires positive ' +
'values for the frequencies, and ' +
'associated times that are greater than ' +
'the time step for the model.')
raise ValueError
if disp_material.poles > config.get_model_config().materials['maxpoles']:
@@ -1356,9 +1312,10 @@ class AddDrudeDispersion(UserObjectMulti):
# Replace original material with newly created DispersiveMaterial
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
logger.info(self.grid_name(grid) + f"Drude disperion added to {disp_material.ID} "
f"with omega={', '.join('%4.3e' % omega for omega in disp_material.tau)} secs, "
f"and gamma={', '.join('%4.3e' % alpha for alpha in disp_material.alpha)} secs created.")
logger.info(
f"{self.grid_name(grid)}Drude disperion added to {disp_material.ID} "
f"with omega={', '.join('%4.3e' % omega for omega in disp_material.tau)} secs, "
f"and gamma={', '.join('%4.3e' % alpha for alpha in disp_material.alpha)} secs created.")
class SoilPeplinski(UserObjectMulti):
@@ -1392,38 +1349,38 @@ class SoilPeplinski(UserObjectMulti):
water_fraction_upper = self.kwargs['water_fraction_upper']
ID = self.kwargs['id']
except KeyError:
logger.exception(self.params_str() + ' requires at exactly seven '
logger.exception(f'{self.params_str()} requires at exactly seven ' +
'parameters.')
raise
if sand_fraction < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for the sand fraction.')
raise ValueError
if clay_fraction < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for the clay fraction.')
raise ValueError
if bulk_density < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for the bulk density.')
raise ValueError
if sand_density < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for the sand particle density.')
raise ValueError
if water_fraction_lower < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for the lower limit of the water volumetric '
'fraction.')
raise ValueError
if water_fraction_upper < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for the upper limit of the water volumetric '
'fraction.')
raise ValueError
if any(x.ID == ID for x in grid.mixingmodels):
logger.exception(self.params_str() + f' with ID {ID} already exists')
logger.exception(f'{self.params_str()} with ID {ID} already exists')
raise ValueError
# Create a new instance of the Material class material
@@ -1431,10 +1388,10 @@ class SoilPeplinski(UserObjectMulti):
s = PeplinskiSoilUser(ID, sand_fraction, clay_fraction, bulk_density,
sand_density, (water_fraction_lower, water_fraction_upper))
logger.info(self.grid_name(grid) + 'Mixing model (Peplinski) used to '
f'create {s.ID} with sand fraction {s.S:g}, clay fraction '
f'{s.C:g}, bulk density {s.rb:g}g/cm3, sand particle '
f'density {s.rs:g}g/cm3, and water volumetric fraction '
logger.info(f'{self.grid_name(grid)}Mixing model (Peplinski) used to ' +
f'create {s.ID} with sand fraction {s.S:g}, clay fraction ' +
f'{s.C:g}, bulk density {s.rb:g}g/cm3, sand particle ' +
f'density {s.rs:g}g/cm3, and water volumetric fraction ' +
f'{s.mu[0]:g} to {s.mu[1]:g} created.')
grid.mixingmodels.append(s)
@@ -1474,56 +1431,57 @@ class MaterialRange(UserObjectMulti):
ro_upper = self.kwargs['ro_upper']
ID = self.kwargs['id']
except KeyError:
logger.exception(self.params_str() + ' requires at exactly nine '
logger.exception(f'{self.params_str()} requires at exactly nine ' +
'parameters.')
raise
if er_lower < 1:
logger.exception(self.params_str() + ' requires a value greater or equal to 1 '
logger.exception(f'{self.params_str()} requires a value greater or equal to 1 ' +
'for the lower range of relative permittivity.')
raise ValueError
if mr_lower < 1:
logger.exception(self.params_str() + ' requires a value greater or equal to 1 '
logger.exception(f'{self.params_str()} requires a value greater or equal to 1 ' +
'for the lower range of relative magnetic permeability.')
raise ValueError
if sigma_lower < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for the lower limit of conductivity.')
raise ValueError
if ro_lower < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for the lower range magnetic loss.')
raise ValueError
if er_upper < 1:
logger.exception(self.params_str() + ' requires a value greater or equal to 1'
logger.exception(f'{self.params_str()} requires a value greater or equal to 1' +
'for the upper range of relative permittivity.')
raise ValueError
if mr_upper < 1:
logger.exception(self.params_str() + ' requires a value greater or equal to 1'
logger.exception(f'{self.params_str()} requires a value greater or equal to 1' +
'for the upper range of relative magnetic permeability')
raise ValueError
if sigma_upper < 0:
logger.exception(self.params_str() + ' requires a positive value '
logger.exception(f'{self.params_str()} requires a positive value ' +
'for the upper range of conductivity.')
raise ValueError
if ro_upper < 0:
logger.exception(self.params_str() + ' requires a positive value '
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(self.params_str() + f' with ID {ID} already exists')
logger.exception(f'{self.params_str()} with ID {ID} already exists')
raise ValueError
# Create a new instance of the Material class material
# (start index after pec & free_space)
s = RangeMaterialUser(ID, (er_lower, er_upper), (sigma_lower, sigma_upper), (mr_lower, mr_upper), (ro_lower, ro_upper))
s = RangeMaterialUser(ID, (er_lower, er_upper), (sigma_lower, sigma_upper),
(mr_lower, mr_upper), (ro_lower, ro_upper))
logger.info(self.grid_name(grid) + 'Material properties used to '
f'create {s.ID} with range(s) {s.er[0]:g} to {s.er[1]:g}, relative permittivity '
f'{s.sig[0]:g} to {s.sig[1]:g}, S/m conductivity, {s.mu[0]:g} to {s.mu[1]:g} relative magnetic permeability '
logger.info(f'{self.grid_name(grid)}Material properties used to ' +
f'create {s.ID} with range(s) {s.er[0]:g} to {s.er[1]:g}, relative permittivity ' +
f'{s.sig[0]:g} to {s.sig[1]:g}, S/m conductivity, {s.mu[0]:g} to {s.mu[1]:g} relative magnetic permeability ' +
f'{s.ro[0]:g} to {s.ro[1]:g} Ohm/m magnetic loss, created')
@@ -1550,27 +1508,25 @@ class MaterialList(UserObjectMulti):
list_of_materials = self.kwargs['list_of_materials']
ID = self.kwargs['id']
except KeyError:
logger.exception(self.params_str() + ' requires at at least 2 '
logger.exception(f'{self.params_str()} requires at at least 2 ' +
'parameters.')
raise
if any(x.ID == ID for x in grid.mixingmodels):
logger.exception(self.params_str() + f' with ID {ID} already exists')
logger.exception(f'{self.params_str()} with ID {ID} already exists')
raise ValueError
# Create a new instance of the Material class material
# (start index after pec & free_space)
s = ListMaterialUser(ID, list_of_materials)
logger.info(self.grid_name(grid) + 'A list of materials used to '
logger.info(f'{self.grid_name(grid)}A list of materials used to ' +
f'create {s.ID} that includes {s.mat}, created')
grid.mixingmodels.append(s)
class GeometryView(UserObjectMulti):
"""Outputs to file(s) information about the geometry (mesh) of model.
@@ -1613,7 +1569,7 @@ class GeometryView(UserObjectMulti):
output_type = self.kwargs['output_type'].lower()
filename = self.kwargs['filename']
except KeyError:
logger.exception(self.params_str() + ' requires exactly eleven '
logger.exception(f'{self.params_str()} requires exactly eleven ' +
'parameters.')
raise
@@ -1624,45 +1580,44 @@ class GeometryView(UserObjectMulti):
p4 = uip.round_to_grid_static_point(p2)
p1, p2 = uip.check_box_points(p1, p2, self.params_str())
except ValueError:
logger.exception(self.params_str() + ' point is outside the domain.')
logger.exception(f'{self.params_str()} point is outside the domain.')
raise
xs, ys, zs = p1
xf, yf, zf = p2
dx, dy, dz = uip.discretise_static_point(dl)
if dx < 0 or dy < 0 or dz < 0:
logger.exception(self.params_str() + ' the step size should not be '
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(self.params_str() + ' the step size should be '
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(self.params_str() + ' the step size should not '
logger.exception(f'{self.params_str()} the step size should not ' +
'be less than the spatial discretisation.')
raise ValueError
if output_type != 'n' and output_type != 'f':
logger.exception(self.params_str() + ' requires type to be either '
if output_type not in ['n', 'f']:
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):
logger.exception(self.params_str() + ' requires the spatial '
'discretisation for the geometry view to be the '
'same as the model for geometry view of '
logger.exception(f'{self.params_str()} requires the spatial ' +
'discretisation for the geometry view to be the ' +
'same as the model for geometry view of ' +
'type f (fine)')
raise ValueError
g = GeometryViewUser(xs, ys, zs, xf, yf, zf, dx, dy, dz, filename, grid)
logger.info(self.grid_name(grid) + f'Geometry view from {p3[0]:g}m, '
f'{p3[1]:g}m, {p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m, '
f'{p4[2]:g}m, discretisation {dx * grid.dx:g}m, '
f'{dy * grid.dy:g}m, {dz * grid.dz:g}m, with filename '
logger.info(f'{self.grid_name(grid)}Geometry view from {p3[0]:g}m, ' +
f'{p3[1]:g}m, {p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m, ' +
f'{p4[2]:g}m, discretisation {dx * grid.dx:g}m, ' +
f'{dy * grid.dy:g}m, {dz * grid.dz:g}m, with filename ' +
f'base {g.filename} created.')
grid.geometryviews.append(g)
@@ -1692,7 +1647,7 @@ class GeometryObjectsWrite(UserObjectMulti):
p2 = self.kwargs['p2']
basefilename = self.kwargs['filename']
except KeyError:
logger.exception(self.params_str() + ' requires exactly seven '
logger.exception(f'{self.params_str()} requires exactly seven ' +
'parameters.')
raise
@@ -1756,30 +1711,30 @@ class PMLCFS(UserObjectMulti):
sigmamin = self.kwargs['sigmamin']
sigmamax = self.kwargs['sigmamax']
except KeyError:
logger.exception(self.params_str() + ' requires exactly twelve '
logger.exception(f'{self.params_str()} requires exactly twelve ' +
'parameters.')
raise
if (alphascalingprofile not in CFSParameter.scalingprofiles.keys() or
kappascalingprofile not in CFSParameter.scalingprofiles.keys() or
sigmascalingprofile not in CFSParameter.scalingprofiles.keys()):
logger.exception(self.params_str() + ' must have scaling type '
logger.exception(f'{self.params_str()} must have scaling type ' +
f"{','.join(CFSParameter.scalingprofiles.keys())}")
raise ValueError
if (alphascalingdirection not in CFSParameter.scalingdirections or
kappascalingdirection not in CFSParameter.scalingdirections or
sigmascalingdirection not in CFSParameter.scalingdirections):
logger.exception(self.params_str() + ' must have scaling type '
logger.exception(f'{self.params_str()} must have scaling type ' +
f"{','.join(CFSParameter.scalingdirections)}")
raise ValueError
if (float(alphamin) < 0 or float(alphamax) < 0 or
float(kappamin) < 0 or float(kappamax) < 0 or float(sigmamin) < 0):
logger.exception(self.params_str() + ' minimum and maximum scaling '
logger.exception(f'{self.params_str()} minimum and maximum scaling ' +
'values must be greater than zero.')
raise ValueError
# TODO: Fix handling of kappa for 2nd order PMLs
# if float(kappamin) < 1:
# logger.exception(self.params_str() + ' minimum scaling value for '
# logger.exception(f'{self.params_str()} minimum scaling value for '
# 'kappa must be greater than or equal to one.')
# raise ValueError
@@ -1819,7 +1774,7 @@ class PMLCFS(UserObjectMulti):
grid.pmls['cfs'].append(cfs)
if len(grid.pmls['cfs']) > 2:
logger.exception(self.params_str() + ' can only be used up to two '
logger.exception(f'{self.params_str()} can only be used up to two ' +
'times, for up to a 2nd order PML.')
raise ValueError

查看文件

@@ -93,20 +93,20 @@ class Discretisation(UserObjectSingle):
G.dl = np.array(self.kwargs['p1'])
G.dx, G.dy, G.dz = self.kwargs['p1']
except KeyError:
logger.exception(self.__str__() + ' discretisation requires a point')
logger.exception(f'{self.__str__()} discretisation requires a point')
raise
if G.dl[0] <= 0:
logger.exception(self.__str__() + ' discretisation requires the ' +
'x-direction spatial step to be greater than zero')
logger.exception(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(self.__str__() + ' discretisation requires the ' +
'y-direction spatial step to be greater than zero')
logger.exception(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(self.__str__() + ' discretisation requires the ' +
'z-direction spatial step to be greater than zero')
logger.exception(f'{self.__str__()} discretisation requires the '
f'z-direction spatial step to be greater than zero')
raise ValueError
logger.info(f'Spatial discretisation: {G.dl[0]:g} x {G.dl[1]:g} x {G.dl[2]:g}m')
@@ -127,11 +127,12 @@ class Domain(UserObjectSingle):
try:
G.nx, G.ny, G.nz = uip.discretise_point(self.kwargs['p1'])
except KeyError:
logger.exception(self.__str__() + ' please specify a point')
logger.exception(f'{self.__str__()} please specify a point')
raise
if G.nx == 0 or G.ny == 0 or G.nz == 0:
logger.exception(self.__str__() + ' requires at least one cell in every dimension')
logger.exception(f'{self.__str__()} requires at least one cell in '
f'every dimension')
raise ValueError
logger.info(f"Domain size: {self.kwargs['p1'][0]:g} x {self.kwargs['p1'][1]:g} x " +
@@ -181,12 +182,12 @@ class TimeStepStabilityFactor(UserObjectSingle):
try:
f = self.kwargs['f']
except KeyError:
logger.exception(self.__str__() + ' requires exactly one parameter')
logger.exception(f'{self.__str__()} requires exactly one parameter')
raise
if f <= 0 or f > 1:
logger.exception(self.__str__() + ' requires the value of the time ' +
'step stability factor to be between zero and one')
logger.exception(f'{self.__str__()} requires the value of the time '
f'step stability factor to be between zero and one')
raise ValueError
G.dt = G.dt * f
@@ -250,12 +251,12 @@ class OMPThreads(UserObjectSingle):
try:
n = self.kwargs['n']
except KeyError:
logger.exception(self.__str__() + ' requires exactly one parameter ' +
'to specify the number of CPU OpenMP threads to use')
logger.exception(f'{self.__str__()} requires exactly one parameter '
f'to specify the number of CPU OpenMP threads to use')
raise
if n < 1:
logger.exception(self.__str__() + ' requires the value to be an ' +
'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)
@@ -302,7 +303,7 @@ class PMLProps(UserObjectSingle):
G.pmls['thickness']['ymax'] = int(self.kwargs['ymax'])
G.pmls['thickness']['zmax'] = int(self.kwargs['zmax'])
except KeyError:
logger.exception(self.__str__() + ' requires either one or six parameter(s)')
logger.exception(f'{self.__str__()} requires either one or six parameter(s)')
raise
if (2 * G.pmls['thickness']['x0'] >= G.nx or
@@ -311,8 +312,8 @@ class PMLProps(UserObjectSingle):
2 * G.pmls['thickness']['xmax'] >= G.nx or
2 * G.pmls['thickness']['ymax'] >= G.ny or
2 * G.pmls['thickness']['zmax'] >= G.nz):
logger.exception(self.__str__() + ' has too many cells for the domain size')
raise ValueError
logger.exception(f'{self.__str__()} has too many cells for the domain size')
raise ValueError
class SrcSteps(UserObjectSingle):
@@ -330,12 +331,12 @@ class SrcSteps(UserObjectSingle):
try:
G.srcsteps = uip.discretise_point(self.kwargs['p1'])
except KeyError:
logger.exception(self.__str__() + ' requires exactly three parameters')
logger.exception(f'{self.__str__()} requires exactly three parameters')
raise
logger.info(f'Simple sources will step {G.srcsteps[0] * G.dx:g}m, ' +
f'{G.srcsteps[1] * G.dy:g}m, {G.srcsteps[2] * G.dz:g}m ' +
f'for each model run.')
'for each model run.')
class RxSteps(UserObjectSingle):
@@ -353,12 +354,12 @@ class RxSteps(UserObjectSingle):
try:
G.rxsteps = uip.discretise_point(self.kwargs['p1'])
except KeyError:
logger.exception(self.__str__() + ' requires exactly three parameters')
logger.exception(f'{self.__str__()} requires exactly three parameters')
raise
logger.info(f'All receivers will step {G.rxsteps[0] * G.dx:g}m, ' +
f'{G.rxsteps[1] * G.dy:g}m, {G.rxsteps[2] * G.dz:g}m ' +
f'for each model run.')
'for each model run.')
class ExcitationFile(UserObjectSingle):
@@ -378,7 +379,7 @@ class ExcitationFile(UserObjectSingle):
def create(self, G, uip):
try:
kwargs = dict()
kwargs = {}
excitationfile = self.kwargs['filepath']
kwargs['kind'] = self.kwargs['kind']
kwargs['fill_value'] = self.kwargs['fill_value']
@@ -389,7 +390,7 @@ class ExcitationFile(UserObjectSingle):
args, varargs, keywords, defaults = inspect.getargspec(interpolate.interp1d)
kwargs = dict(zip(reversed(args), reversed(defaults)))
except KeyError:
logger.exception(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

查看文件

@@ -224,14 +224,14 @@ class SimulationConfig:
# solver: cpu, cuda, opencl.
# subgrid: whether the simulation uses sub-grids.
# precision: data type for electromagnetic field output (single/double).
# progressbars: progress bars on stdoout or not - switch off
# progressbars when logging level is greater than
# info (20)
self.general = {'solver': 'cpu',
'subgrid': False,
'precision': 'single'}
# Progress bars on stdoout or not - switch off progressbars when
# logging level is greater than info (20)
self.general['progressbars'] = False if args.log_level > 20 else True
'precision': 'single',
'progressbars': args.log_level <= 20}
self.em_consts = {'c': c, # Speed of light in free space (m/s)
'e0': e0, # Permittivity of free space (F/m)
@@ -289,7 +289,6 @@ class SimulationConfig:
# Set more complex parameters
self._set_precision()
self._get_byteorder()
self._set_input_file_path()
self._set_model_start_end()
@@ -348,12 +347,6 @@ class SimulationConfig:
elif self.general['solver'] == 'opencl':
self.dtypes['C_complex'] = 'cdouble'
def _get_byteorder(self):
"""Checks the byte order of system to use for VTK files, i.e. geometry
views and snapshots.
"""
self.vtk_byteorder = 'LittleEndian' if sys.byteorder == 'little' else 'BigEndian'
def _set_model_start_end(self):
"""Sets range for number of models to run (internally 0 index)."""
if self.args.i:

查看文件

@@ -92,7 +92,7 @@ class Context:
def print_logo_copyright(self):
"""Prints gprMax logo, version, and copyright/licencing information."""
logo_copyright = logo(__version__ + ' (' + codename + ')')
logo_copyright = logo(f'{__version__} ({codename})')
logger.basic(logo_copyright)
def print_sim_time_taken(self):
@@ -164,19 +164,15 @@ class MPIContext(Context):
executor = self.MPIExecutor(self._run_model, comm=self.comm)
# Check GPU resources versus number of MPI tasks
if executor.is_master():
if config.sim_config.general['solver'] == 'cuda':
if executor.size - 1 > len(config.sim_config.devices['devs']):
logger.exception('Not enough GPU resources for number of '
'MPI tasks requested. Number of MPI tasks '
'should be equal to number of GPUs + 1.')
raise ValueError
# Create job list
jobs = []
for i in self.model_range:
jobs.append({'i': i})
if (executor.is_master() and
config.sim_config.general['solver'] == 'cuda' and
executor.size - 1 > len(config.sim_config.devices['devs'])):
logger.exception('Not enough GPU resources for number of '
'MPI tasks requested. Number of MPI tasks '
'should be equal to number of GPUs + 1.')
raise ValueError
jobs = [{'i': i} for i in self.model_range]
# Send the workers to their work loop
executor.start()
if executor.is_master():

70
gprMax/cython/pml_build.pyx 普通文件
查看文件

@@ -0,0 +1,70 @@
# Copyright (C) 2015-2023: The University of Edinburgh, United Kingdom
# Authors: Craig Warren, Antonis Giannopoulos, and John Hartley
#
# This file is part of gprMax.
#
# gprMax is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# gprMax is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
cpdef pml_average_er_mr(
str dir,
int s,
G
):
"""Calculates average permittivity and permeability for building PML
(based on underlying material er and mr from solid array).
Args:
dir: string identifier for direction of PML.
s: int for starting cell of PML.
G: FDTDGrid class describing a grid in a model.
"""
sumer = 0 # Sum of relative permittivities in PML slab
summr = 0 # Sum of relative permeabilities in PML slab
if dir == 'x':
for j in range(G.ny):
for k in range(G.nz):
numID = G.solid[s, j, k]
material = [x for x in G.materials if x.numID == numID]
material = material[0]
sumer += material.er
summr += material.mr
averageer = sumer / (G.ny * G.nz)
averagemr = summr / (G.ny * G.nz)
elif dir == 'y':
for i in range(G.nx):
for k in range(G.nz):
numID = G.solid[i, s, k]
material = [x for x in G.materials if x.numID == numID]
material = material[0]
sumer += material.er
summr += material.mr
averageer = sumer / (G.nx * G.nz)
averagemr = summr / (G.nx * G.nz)
elif dir == 'z':
for i in range(G.nx):
for j in range(G.ny):
numID = G.solid[i, j, s]
material = [x for x in G.materials if x.numID == numID]
material = material[0]
sumer += material.er
summr += material.mr
averageer = sumer / (G.nx * G.ny)
averagemr = summr / (G.nx * G.ny)
return averageer, averagemr

查看文件

@@ -76,7 +76,7 @@ def write_hdf5_outputfile(outputfile, G):
# Write meta data and data for any subgrids
if sg_rxs:
for sg in G.subgrids:
grp = f.create_group('/subgrids/' + sg.name)
grp = f.create_group(f'/subgrids/{sg.name}')
write_hd5_data(grp, sg, is_subgrid=True)
if G.rxs or sg_rxs:
@@ -115,7 +115,7 @@ def write_hd5_data(basegrp, G, is_subgrid=False):
# Create group for sources (except transmission lines); add type and positional data attributes
srclist = G.voltagesources + G.hertziandipoles + G.magneticdipoles
for srcindex, src in enumerate(srclist):
grp = basegrp.create_group('srcs/src' + str(srcindex + 1))
grp = basegrp.create_group(f'srcs/src{str(srcindex + 1)}')
grp.attrs['Type'] = type(src).__name__
grp.attrs['Position'] = (src.xcoord * G.dx, src.ycoord * G.dy, src.zcoord * G.dz)

查看文件

@@ -277,14 +277,10 @@ class Comments():
"""
# Comments for Paraview macro
comments = {}
comments['gprMax_version'] = __version__
comments['dx_dy_dz'] = self.dx_dy_dz_comment()
comments['nx_ny_nz'] = self.nx_ny_nz_comment()
# Write the name and numeric ID for each material
comments['Materials'] = self.materials_comment()
comments = {'gprMax_version': __version__,
'dx_dy_dz': self.dx_dy_dz_comment(),
'nx_ny_nz': self.nx_ny_nz_comment(),
'Materials': self.materials_comment()} # Write the name and numeric ID for each material
# Write information on PMLs, sources, and receivers
if not self.materials_only:
@@ -345,7 +341,7 @@ class Comments():
def materials_comment(self):
if not self.averaged_materials:
return [m.ID for m in self.grid.materials if '+' not in m.ID]
return [m.ID for m in self.grid.materials if m.type is not 'dielectric-smoothed']
else:
return [m.ID for m in self.grid.materials]
@@ -375,8 +371,7 @@ class GeometryObjects:
parts = config.sim_config.input_file_path.with_suffix('').parts
self.filename_hdf5 = Path(*parts[:-1], self.basefilename)
self.filename_hdf5 = self.filename_hdf5.with_suffix('.h5')
self.filename_materials = Path(
*parts[:-1], self.basefilename + '_materials')
self.filename_materials = Path(*parts[:-1], f'{self.basefilename}_materials')
self.filename_materials = self.filename_materials.with_suffix('.txt')
# Sizes of arrays to write necessary to update progress bar

查看文件

@@ -178,8 +178,8 @@ def write_processed_file(processedlines):
for item in processedlines:
f.write(f'{item}')
logger.info(f'Written input commands, after processing any Python code and ' +
f'include commands, to file: {processedfile}\n')
logger.info(f'Written input commands, after processing any Python ' +
f'code and include commands, to file: {processedfile}\n')
def check_cmd_names(processedlines, checkessential=True):
@@ -212,6 +212,7 @@ def check_cmd_names(processedlines, checkessential=True):
# - these will be lists within the dictionary
multiplecmds = {key: [] for key in ['#geometry_view',
'#geometry_objects_write', '#material',
'#material_range', '#material_list',
'#soil_peplinski',
'#add_dispersion_debye',
'#add_dispersion_lorentz',
@@ -219,14 +220,14 @@ def check_cmd_names(processedlines, checkessential=True):
'#waveform', '#voltage_source',
'#hertzian_dipole', '#magnetic_dipole',
'#transmission_line', '#rx', '#rx_array',
'#snapshot', '#include_file', '#material_range', '#material_list']}
'#snapshot', '#include_file']}
# Geometry object building commands that there can be multiple instances
# of in a model - these will be lists within the dictionary
geometrycmds = ['#geometry_objects_read', '#edge', '#plate', '#triangle',
'#box', '#sphere', '#ellipsoid', '#cone', '#cylinder', '#cylindrical_sector',
'#fractal_box', '#add_surface_roughness',
'#add_surface_water', '#add_grass']
'#box', '#sphere', '#ellipsoid', '#cone', '#cylinder',
'#cylindrical_sector', '#fractal_box',
'#add_surface_roughness', '#add_surface_water', '#add_grass']
# List to store all geometry object commands in order from input file
geometry = []

查看文件

@@ -17,21 +17,22 @@
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
import logging
import numpy as np
from .cmds_geometry.add_grass import AddGrass
from .cmds_geometry.add_surface_roughness import AddSurfaceRoughness
from .cmds_geometry.add_surface_water import AddSurfaceWater
from .cmds_geometry.box import Box
from .cmds_geometry.cylinder import Cylinder
from .cmds_geometry.cone import Cone
from .cmds_geometry.cylinder import Cylinder
from .cmds_geometry.cylindrical_sector import CylindricalSector
from .cmds_geometry.edge import Edge
from .cmds_geometry.ellipsoid import Ellipsoid
from .cmds_geometry.fractal_box import FractalBox
from .cmds_geometry.plate import Plate
from .cmds_geometry.sphere import Sphere
from .cmds_geometry.triangle import Triangle
from .cmds_geometry.ellipsoid import Ellipsoid
from .utilities.utilities import round_value
logger = logging.getLogger(__name__)
@@ -76,7 +77,8 @@ 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) + "'" +
@@ -219,7 +221,6 @@ def process_geometrycmds(geometry):
scene_objects.append(cylinder)
elif tmp[0] == '#cone:':
if len(tmp) < 10:
logger.exception("'" + ' '.join(tmp) + "'" +
@@ -239,7 +240,7 @@ def process_geometrycmds(geometry):
elif len(tmp) == 11:
averaging = check_averaging(tmp[10].lower())
cone = Cone(p1=p1, p2=p2, r1=r1, r2=r2, material_id=tmp[9],
averaging=averaging)
averaging=averaging)
# Uniaxial anisotropic case
elif len(tmp) == 12:
@@ -252,7 +253,6 @@ def process_geometrycmds(geometry):
scene_objects.append(cone)
elif tmp[0] == '#cylindrical_sector:':
if len(tmp) < 10:
logger.exception("'" + ' '.join(tmp) + "'" +
@@ -331,7 +331,6 @@ def process_geometrycmds(geometry):
scene_objects.append(sphere)
elif tmp[0] == '#ellipsoid:':
if len(tmp) < 8:
logger.exception("'" + ' '.join(tmp) + "'" +
@@ -345,17 +344,19 @@ def process_geometrycmds(geometry):
# Isotropic case with no user specified averaging
if len(tmp) == 8:
ellipsoid = Ellipsoid(p1=p1, xr=xr, yr=yr, zr=zr, material_id=tmp[7])
ellipsoid = Ellipsoid(p1=p1, xr=xr, yr=yr, zr=zr,
material_id=tmp[7])
# Isotropic case with user specified averaging
elif len(tmp) == 9:
averaging = check_averaging(tmp[8].lower())
ellipsoid = Ellipsoid(p1=p1, xr=xr, yr=yr, zr=zr, material_id=tmp[7],
averaging=averaging)
ellipsoid = Ellipsoid(p1=p1, xr=xr, yr=yr, zr=zr,
material_id=tmp[7], averaging=averaging)
# Uniaxial anisotropic case
elif len(tmp) == 8:
ellipsoid = Ellipsoid(p1=p1, xr=xr, yr=yr, zr=zr, material_id=tmp[7:])
ellipsoid = Ellipsoid(p1=p1, xr=xr, yr=yr, zr=zr,
material_id=tmp[7:])
else:
logger.exception("'" + ' '.join(tmp) + "'" +
@@ -364,8 +365,6 @@ def process_geometrycmds(geometry):
scene_objects.append(ellipsoid)
elif tmp[0] == '#fractal_box:':
# Default is no dielectric smoothing for a fractal box

查看文件

@@ -21,8 +21,9 @@ import logging
from .cmds_multiuse import (AddDebyeDispersion, AddDrudeDispersion,
AddLorentzDispersion, GeometryObjectsWrite,
GeometryView, HertzianDipole, MagneticDipole,
Material, Rx, RxArray, Snapshot, SoilPeplinski,
TransmissionLine, VoltageSource, Waveform, MaterialRange, MaterialList)
Material, MaterialList, MaterialRange, Rx, RxArray,
Snapshot, SoilPeplinski, TransmissionLine,
VoltageSource, Waveform)
logger = logging.getLogger(__name__)
@@ -352,17 +353,16 @@ def process_multicmds(multicmds):
' requires at exactly nine parameters')
raise ValueError
material_range = MaterialRange(er_lower=float(tmp[0]),
er_upper=float(tmp[1]),
sigma_lower=float(tmp[2]),
sigma_upper=float(tmp[3]),
mr_lower=float(tmp[4]),
mr_upper=float(tmp[5]),
ro_lower=float(tmp[6]),
ro_upper=float(tmp[7]),
id=tmp[8])
er_upper=float(tmp[1]),
sigma_lower=float(tmp[2]),
sigma_upper=float(tmp[3]),
mr_lower=float(tmp[4]),
mr_upper=float(tmp[5]),
ro_lower=float(tmp[6]),
ro_upper=float(tmp[7]),
id=tmp[8])
scene_objects.append(material_range)
cmdname = '#material_list'
if multicmds[cmdname] is not None:
for cmdinstance in multicmds[cmdname]:
@@ -375,14 +375,11 @@ def process_multicmds(multicmds):
tokens = len(tmp)
lmats = []
for iter in range(0,tokens-1):
for iter in range(tokens-1):
lmats.append(tmp[iter])
material_list = MaterialList(list_of_materials=lmats,
id=tmp[tokens-1])
id=tmp[tokens-1])
scene_objects.append(material_list)
return scene_objects

查看文件

@@ -55,8 +55,8 @@ 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(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 ' +
f'the number of CPU OpenMP threads to use')
raise ValueError
omp_threads = OMPThreads(n=tmp[0])
@@ -66,7 +66,7 @@ def process_singlecmds(singlecmds):
if singlecmds[cmd] is not None:
tmp = [float(x) for x in singlecmds[cmd].split()]
if len(tmp) != 3:
logger.exception(cmd + ' requires exactly three parameters')
logger.exception(f'{cmd} requires exactly three parameters')
raise ValueError
dl = (tmp[0], tmp[1], tmp[2])
@@ -77,7 +77,7 @@ def process_singlecmds(singlecmds):
if singlecmds[cmd] is not None:
tmp = [float(x) for x in singlecmds[cmd].split()]
if len(tmp) != 3:
logger.exception(cmd + ' requires exactly three parameters')
logger.exception(f'{cmd} requires exactly three parameters')
raise ValueError
p1 = (tmp[0], tmp[1], tmp[2])
@@ -94,8 +94,8 @@ def process_singlecmds(singlecmds):
if singlecmds[cmd] is not None:
tmp = singlecmds[cmd].split()
if len(tmp) != 1:
logger.exception(cmd + ' requires exactly one parameter to specify ' +
'the time window. Either in seconds or number of iterations.')
logger.exception(f'{cmd} requires exactly one parameter to specify the ' +
f'time window. Either in seconds or number of iterations.')
raise ValueError
tmp = tmp[0].lower()
@@ -113,8 +113,8 @@ def process_singlecmds(singlecmds):
cmd = '#pml_cells'
if singlecmds[cmd] is not None:
tmp = singlecmds[cmd].split()
if len(tmp) != 1 and len(tmp) != 6:
logger.exception(cmd + ' requires either one or six parameter(s)')
if len(tmp) not in [1, 6]:
logger.exception(f'{cmd} requires either one or six parameter(s)')
raise ValueError
if len(tmp) == 1:
pml_cells = PMLProps(thickness=int(tmp[0]))
@@ -132,7 +132,7 @@ def process_singlecmds(singlecmds):
if singlecmds[cmd] is not None:
tmp = singlecmds[cmd].split()
if len(tmp) != 3:
logger.exception(cmd + ' requires exactly three parameters')
logger.exception(f'{cmd} requires exactly three parameters')
raise ValueError
p1 = (float(tmp[0]), float(tmp[1]), float(tmp[2]))
@@ -143,7 +143,7 @@ def process_singlecmds(singlecmds):
if singlecmds[cmd] is not None:
tmp = singlecmds[cmd].split()
if len(tmp) != 3:
logger.exception(cmd + ' requires exactly three parameters')
logger.exception(f'{cmd} requires exactly three parameters')
raise ValueError
p1 = (float(tmp[0]), float(tmp[1]), float(tmp[2]))
@@ -154,8 +154,8 @@ def process_singlecmds(singlecmds):
cmd = '#excitation_file'
if singlecmds[cmd] is not None:
tmp = singlecmds[cmd].split()
if len(tmp) != 1 and len(tmp) != 3:
logger.exception(cmd + ' requires either one or three parameter(s)')
if len(tmp) not in [1, 3]:
logger.exception(f'{cmd} requires either one or three parameter(s)')
raise ValueError
if len(tmp) > 1:

查看文件

@@ -215,77 +215,6 @@ class DispersiveMaterial(Material):
return er
def process_materials(G):
"""Processes complete list of materials - calculates update coefficients,
stores in arrays, and builds text list of materials/properties
Args:
G: FDTDGrid class describing a grid in a model.
Returns:
materialsdata: list of material IDs, names, and properties to
print a table.
"""
if config.get_model_config().materials['maxpoles'] == 0:
materialsdata = [['\nID', '\nName', '\nType', '\neps_r', 'sigma\n[S/m]',
'\nmu_r', 'sigma*\n[Ohm/m]', 'Dielectric\nsmoothable']]
else:
materialsdata = [['\nID', '\nName', '\nType', '\neps_r', 'sigma\n[S/m]',
'Delta\neps_r', 'tau\n[s]', 'omega\n[Hz]', 'delta\n[Hz]',
'gamma\n[Hz]', '\nmu_r', 'sigma*\n[Ohm/m]', 'Dielectric\nsmoothable']]
for material in G.materials:
# Calculate update coefficients for specific material
material.calculate_update_coeffsE(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
# Add update coefficients to overall storage for dispersive materials
if hasattr(material, 'poles'):
z = 0
for pole in range(config.get_model_config().materials['maxpoles']):
G.updatecoeffsdispersive[material.numID, z:z + 3] = (config.sim_config.em_consts['e0'] *
material.eqt2[pole], material.eqt[pole], material.zt[pole])
z += 3
# Construct information on material properties for printing table
materialtext = []
materialtext.append(str(material.numID))
materialtext.append(material.ID[:50] if len(material.ID) > 50 else material.ID)
materialtext.append(material.type)
materialtext.append(f'{material.er:g}')
materialtext.append(f'{material.se:g}')
if config.get_model_config().materials['maxpoles'] > 0:
if 'debye' in material.type:
materialtext.append('\n'.join('{:g}'.format(deltaer) for deltaer in material.deltaer))
materialtext.append('\n'.join('{:g}'.format(tau) for tau in material.tau))
materialtext.extend(['', '', ''])
elif 'lorentz' in material.type:
materialtext.append(', '.join('{:g}'.format(deltaer) for deltaer in material.deltaer))
materialtext.append('')
materialtext.append(', '.join('{:g}'.format(tau) for tau in material.tau))
materialtext.append(', '.join('{:g}'.format(alpha) for alpha in material.alpha))
materialtext.append('')
elif 'drude' in material.type:
materialtext.extend(['', ''])
materialtext.append(', '.join('{:g}'.format(tau) for tau in material.tau))
materialtext.append('')
materialtext.append(', '.join('{:g}'.format(alpha) for alpha in material.alpha))
else:
materialtext.extend(['', '', '', '', ''])
materialtext.append(f'{material.mr:g}')
materialtext.append(f'{material.sm:g}')
materialtext.append(material.averagable)
materialsdata.append(materialtext)
return materialsdata
class PeplinskiSoil:
"""Soil objects that are characterised according to a mixing model
by Peplinski (http://dx.doi.org/10.1109/36.387598).
@@ -350,12 +279,11 @@ class PeplinskiSoil:
# The limiting values of the ranges are not included in this.
#mubins = np.linspace(self.mu[0], self.mu[1], nbins)
mubins = np.linspace(self.mu[0], self.mu[1], nbins+1)
mubins = np.linspace(self.mu[0], self.mu[1], nbins + 1)
# Generate a range of volumetric water fraction values the mid-point of
# each bin to make materials from
#mumaterials = mubins + (mubins[1] - mubins[0]) / 2
mumaterials = 0.5*(mubins[1:nbins+1] + mubins[0:nbins])
mumaterials = 0.5 * (mubins[1:nbins+1] + mubins[0:nbins])
# Create an iterator
muiter = np.nditer(mumaterials, flags=['c_index'])
@@ -399,7 +327,6 @@ class PeplinskiSoil:
muiter.iternext()
class RangeMaterial:
"""Material objects defined by a given range of their parameters to be used for
factal spatial disttibutions.
@@ -425,7 +352,6 @@ class RangeMaterial:
# and assume that all must be sequentially numbered. This allows for more general mixing models
self.matID = []
def calculate_properties(self, nbins, G):
"""Calculates the specific properties of each of the materials.
@@ -436,50 +362,50 @@ class RangeMaterial:
# Generate a set of relative permittivity bins based on the given range
erbins = np.linspace(self.er[0], self.er[1], nbins+1)
# Generate a range of relative permittivity values the mid-point of
# each bin to make materials from
#ermaterials = erbins + np.abs((erbins[1] - erbins[0])) / 2
ermaterials = 0.5*(erbins[1:nbins+1] + erbins[0:nbins])
ermaterials = 0.5 * (erbins[1:nbins+1] + erbins[0:nbins])
# Generate a set of conductivity bins based on the given range
sigmabins = np.linspace(self.sig[0], self.sig[1], nbins+1)
sigmabins = np.linspace(self.sig[0], self.sig[1], nbins + 1)
# Generate a range of conductivity values the mid-point of
# each bin to make materials from
#sigmamaterials = sigmabins + (sigmabins[1] - sigmabins[0]) / 2
sigmamaterials = 0.5*(sigmabins[1:nbins+1] + sigmabins[0:nbins])
sigmamaterials = 0.5 * (sigmabins[1:nbins+1] + sigmabins[0:nbins])
# Generate a set of magnetic permeability bins based on the given range
mubins = np.linspace(self.mu[0], self.mu[1], nbins+1)
mubins = np.linspace(self.mu[0], self.mu[1], nbins + 1)
# Generate a range of magnetic permeability values the mid-point of
# each bin to make materials from
#mumaterials = mubins + np.abs((mubins[1] - mubins[0])) / 2
mumaterials = 0.5*(mubins[1:nbins+1] + mubins[0:nbins])
mumaterials = 0.5 * (mubins[1:nbins+1] + mubins[0:nbins])
# Generate a set of magnetic loss bins based on the given range
robins = np.linspace(self.ro[0], self.ro[1], nbins+1)
# Generate a range of magnetic loss values the mid-point of
# each bin to make materials from
robins = np.linspace(self.ro[0], self.ro[1], nbins + 1)
# Generate a range of magnetic loss values the mid-point of each bin to
# make materials from
#romaterials = robins + np.abs((robins[1] - robins[0])) / 2
romaterials = 0.5*(robins[1:nbins+1] + robins[0:nbins])
romaterials = 0.5 * (robins[1:nbins+1] + robins[0:nbins])
# Iterate over the bins
for iter in np.arange(0,nbins):
for iter in np.arange(nbins):
# Relative permittivity
er = ermaterials[iter]
# Effective conductivity
se = sigmamaterials[iter]
# magnetic permeability
# Magnetic permeability
mr = mumaterials[iter]
# magnetic loss
# Magnetic loss
sm = romaterials[iter]
# Check to see if the material already exists before creating a new one
requiredID = '|{:.4f}+{:.4f}+{:.4f}+{:.4f}|'.format(float(er),float(se),float(mr),float(sm))
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:
if material:
@@ -499,11 +425,10 @@ class RangeMaterial:
self.matID.append(m.numID)
class ListMaterial:
"""A list of predefined materials that are to be used for
factal spatial disttibutions. No new materials are created but the ones specified are
grouped together to be used in fractal spatial distributions.
"""A list of predefined materials to be used for
factal spatial disttibutions. This command does not create new materials but collects them to be used in a
stochastic distribution by a fractal box.
"""
def __init__(self, ID, listofmaterials):
@@ -524,21 +449,18 @@ class ListMaterial:
def calculate_properties(self, nbins, G):
"""Calculates the properties of the materials. No Debye is used but name kept the same as used in other
class that needs Debye
"""Calculates the properties of the materials.
Args:
nbins: int for number of bins to use to create the different materials.
G: FDTDGrid class describing a grid in a model.
"""
# Iterate over the bins
for iter in np.arange(0,nbins):
# Check to see if the material already exists before creating a new one
for iter in np.arange(nbins):
#requiredID = '|{:}_in_{:}|'.format((self.mat[iter]),(self.ID))
requiredID = self.mat[iter]
# Check if the material already exists before creating a new one
material = next((x for x in G.materials if x.ID == requiredID), None)
self.matID.append(material.numID)
@@ -555,15 +477,11 @@ class ListMaterial:
# m.numID = len(G.materials)
# G.materials.append(m)
if not material:
logger.exception(self.__str__() + f' material(s) {material} do not exist')
raise ValueError
def create_built_in_materials(G):
"""Creates pre-defined (built-in) materials.
@@ -571,8 +489,6 @@ def create_built_in_materials(G):
G: FDTDGrid class describing a grid in a model.
"""
G.n_built_in_materials = len(G.materials)
m = Material(0, 'pec')
m.se = float('inf')
m.type = 'builtin'
@@ -583,8 +499,6 @@ def create_built_in_materials(G):
m.type = 'builtin'
G.materials.append(m)
G.n_built_in_materials = len(G.materials)
def calculate_water_properties(T=25, S=0):
"""Get extended Debye model properties for water.
@@ -627,8 +541,6 @@ def create_water(G, T=25, S=0):
eri, er, tau, sig = calculate_water_properties(T, S)
G.n_built_in_materials = len(G.materials)
m = DispersiveMaterial(len(G.materials), 'water')
m.averagable = False
m.type = 'builtin, debye'
@@ -641,8 +553,6 @@ def create_water(G, T=25, S=0):
if config.get_model_config().materials['maxpoles'] == 0:
config.get_model_config().materials['maxpoles'] = 1
G.n_built_in_materials = len(G.materials)
def create_grass(G):
"""Creates single-pole Debye model for grass
@@ -657,8 +567,6 @@ def create_grass(G):
tau = 1.0793e-11
sig = 0
G.n_built_in_materials = len(G.materials)
m = DispersiveMaterial(len(G.materials), 'grass')
m.averagable = False
m.type = 'builtin, debye'
@@ -671,4 +579,70 @@ def create_grass(G):
if config.get_model_config().materials['maxpoles'] == 0:
config.get_model_config().materials['maxpoles'] = 1
G.n_built_in_materials = len(G.materials)
def process_materials(G):
"""Processes complete list of materials - calculates update coefficients,
stores in arrays, and builds text list of materials/properties
Args:
G: FDTDGrid class describing a grid in a model.
Returns:
materialsdata: list of material IDs, names, and properties to
print a table.
"""
if config.get_model_config().materials['maxpoles'] == 0:
materialsdata = [['\nID', '\nName', '\nType', '\neps_r', 'sigma\n[S/m]',
'\nmu_r', 'sigma*\n[Ohm/m]', 'Dielectric\nsmoothable']]
else:
materialsdata = [['\nID', '\nName', '\nType', '\neps_r', 'sigma\n[S/m]',
'Delta\neps_r', 'tau\n[s]', 'omega\n[Hz]', 'delta\n[Hz]',
'gamma\n[Hz]', '\nmu_r', 'sigma*\n[Ohm/m]', 'Dielectric\nsmoothable']]
for material in G.materials:
# Calculate update coefficients for specific material
material.calculate_update_coeffsE(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
# Add update coefficients to overall storage for dispersive materials
if hasattr(material, 'poles'):
z = 0
for pole in range(config.get_model_config().materials['maxpoles']):
G.updatecoeffsdispersive[material.numID, z:z + 3] = (config.sim_config.em_consts['e0'] *
material.eqt2[pole], material.eqt[pole], material.zt[pole])
z += 3
# Construct information on material properties for printing table
materialtext = [str(material.numID),
material.ID[:50] if len(material.ID) > 50 else material.ID,
material.type,
f'{material.er:g}',
f'{material.se:g}']
if config.get_model_config().materials['maxpoles'] > 0:
if 'debye' in material.type:
materialtext.append('\n'.join('{:g}'.format(deltaer) for deltaer in material.deltaer))
materialtext.append('\n'.join('{:g}'.format(tau) for tau in material.tau))
materialtext.extend(['', '', ''])
elif 'lorentz' in material.type:
materialtext.append(', '.join('{:g}'.format(deltaer) for deltaer in material.deltaer))
materialtext.append('')
materialtext.append(', '.join('{:g}'.format(tau) for tau in material.tau))
materialtext.append(', '.join('{:g}'.format(alpha) for alpha in material.alpha))
materialtext.append('')
elif 'drude' in material.type:
materialtext.extend(['', ''])
materialtext.append(', '.join('{:g}'.format(tau) for tau in material.tau))
materialtext.append('')
materialtext.append(', '.join('{:g}'.format(alpha) for alpha in material.alpha))
else:
materialtext.extend(['', '', '', '', ''])
materialtext.extend((f'{material.mr:g}', f'{material.sm:g}', material.averagable))
materialsdata.append(materialtext)
return materialsdata

查看文件

@@ -73,7 +73,7 @@ class ModelBuildRun:
self.p = psutil.Process()
# Normal model reading/building process; bypassed if geometry information to be reused
self.build_geometry() if not config.get_model_config().reuse_geometry else self.reuse_geometry()
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()}')
@@ -109,7 +109,7 @@ class ModelBuildRun:
# 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 or 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)
@@ -271,8 +271,7 @@ class ModelBuildRun:
logger.warning(f"You have specified more threads ({config.get_model_config().ompthreads}) "
f"than available physical CPU cores ({config.sim_config.hostinfo['physicalcores']}). "
f"This may lead to degraded performance.")
# Print information about any compute device, e.g. GPU, in use
elif config.sim_config.general['solver'] == 'cuda' or config.sim_config.general['solver'] == 'opencl':
elif config.sim_config.general['solver'] in ['cuda', 'opencl']:
if config.sim_config.general['solver'] == 'opencl':
solvername = 'OpenCL'
platformname = ' on ' + ' '.join(config.get_model_config().device['dev'].platform.name.split())
@@ -338,11 +337,11 @@ class GridBuilder:
pbar.close()
def tm_grid_update(self):
if '2D TMx' == config.get_model_config().mode:
if config.get_model_config().mode == '2D TMx':
self.grid.tmx()
elif '2D TMy' == config.get_model_config().mode:
elif config.get_model_config().mode == '2D TMy':
self.grid.tmy()
elif '2D TMz' == config.get_model_config().mode:
elif config.get_model_config().mode == '2D TMz':
self.grid.tmz()
def update_voltage_source_materials(self):

查看文件

@@ -220,26 +220,26 @@ class MPIExecutor(object):
def join(self):
"""Joins the workers."""
if self.is_master():
if not self.is_master():
return
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)
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)
logger.debug(f'({self.comm.name}) - Waiting for all workers to terminate.')
logger.debug(f'({self.comm.name}) - Waiting for all workers to terminate.')
down = [False] * len(self.workers)
while True:
for i, worker in enumerate(self.workers):
if self.comm.Iprobe(source=worker, tag=Tags.EXIT):
self.comm.recv(source=worker, tag=Tags.EXIT)
down[i] = True
if all(down):
break
down = [False] * len(self.workers)
while True:
for i, worker in enumerate(self.workers):
if self.comm.Iprobe(source=worker, tag=Tags.EXIT):
self.comm.recv(source=worker, tag=Tags.EXIT)
down[i] = True
if all(down):
break
self._up = False
logger.debug(f'({self.comm.name}) - All workers terminated.')
self._up = False
logger.debug(f'({self.comm.name}) - All workers terminated.')
def submit(self, jobs, sleep=0.0):
"""Submits a list of jobs to the workers and returns the results.

查看文件

@@ -22,6 +22,8 @@ import numpy as np
import gprMax.config as config
from .cython.pml_build import pml_average_er_mr
class CFSParameter:
"""Individual CFS parameter (e.g. alpha, kappa, or sigma)."""
@@ -609,9 +611,6 @@ def build_pml(G, key, value):
elif config.sim_config.general['solver'] == 'opencl':
pml_type = OpenCLPML
sumer = 0 # Sum of relative permittivities in PML slab
summr = 0 # Sum of relative permeabilities in PML slab
if key[0] == 'x':
if key == 'x0':
pml = pml_type(G, ID=key, direction='xminus',
@@ -621,14 +620,7 @@ def build_pml(G, key, value):
xs=G.nx - value, xf=G.nx, yf=G.ny, zf=G.nz)
pml.CFS = G.pmls['cfs']
G.pmls['slabs'].append(pml)
for j in range(G.ny):
for k in range(G.nz):
numID = G.solid[pml.xs, j, k]
material = next(x for x in G.materials if x.numID == numID)
sumer += material.er
summr += material.mr
averageer = sumer / (G.ny * G.nz)
averagemr = summr / (G.ny * G.nz)
averageer, averagemr = pml_average_er_mr('x', pml.xs, G)
elif key[0] == 'y':
if key == 'y0':
@@ -639,14 +631,7 @@ def build_pml(G, key, value):
ys=G.ny - value, xf=G.nx, yf=G.ny, zf=G.nz)
pml.CFS = G.pmls['cfs']
G.pmls['slabs'].append(pml)
for i in range(G.nx):
for k in range(G.nz):
numID = G.solid[i, pml.ys, k]
material = next(x for x in G.materials if x.numID == numID)
sumer += material.er
summr += material.mr
averageer = sumer / (G.nx * G.nz)
averagemr = summr / (G.nx * G.nz)
averageer, averagemr = pml_average_er_mr('y', pml.ys, G)
elif key[0] == 'z':
if key == 'z0':
@@ -657,13 +642,6 @@ def build_pml(G, key, value):
zs=G.nz - value, xf=G.nx, yf=G.ny, zf=G.nz)
pml.CFS = G.pmls['cfs']
G.pmls['slabs'].append(pml)
for i in range(G.nx):
for j in range(G.ny):
numID = G.solid[i, j, pml.zs]
material = next(x for x in G.materials if x.numID == numID)
sumer += material.er
summr += material.mr
averageer = sumer / (G.nx * G.ny)
averagemr = summr / (G.nx * G.ny)
averageer, averagemr = pml_average_er_mr('z', pml.zs, G)
pml.calculate_update_coeffs(averageer, averagemr)

查看文件

@@ -105,7 +105,7 @@ class Scene:
# Check essential commands and warn user if missing
for cmd_type in self.essential_cmds:
d = any([isinstance(cmd, cmd_type) for cmd in cmds_unique])
d = any(isinstance(cmd, cmd_type) for cmd in cmds_unique)
if not d:
logger.exception('Your input file is missing essential commands ' +
'required to run a model. Essential commands ' +

查看文件

@@ -96,7 +96,7 @@ class VoltageSource(Source):
i = self.xcoord
j = self.ycoord
k = self.zcoord
componentID = 'E' + self.polarisation
componentID = f'E{self.polarisation}'
if self.polarisation == 'x':
if self.resistance != 0:
@@ -130,30 +130,31 @@ class VoltageSource(Source):
G: FDTDGrid class describing a grid in a model.
"""
if self.resistance != 0:
i = self.xcoord
j = self.ycoord
k = self.zcoord
if self.resistance == 0:
return
i = self.xcoord
j = self.ycoord
k = self.zcoord
componentID = 'E' + self.polarisation
requirednumID = G.ID[G.IDlookup[componentID], i, j, k]
material = next(x for x in G.materials if x.numID == requirednumID)
newmaterial = deepcopy(material)
newmaterial.ID = material.ID + '+' + self.ID
newmaterial.numID = len(G.materials)
newmaterial.averagable = False
newmaterial.type += ',\nvoltage-source' if newmaterial.type else 'voltage-source'
componentID = f'E{self.polarisation}'
requirednumID = G.ID[G.IDlookup[componentID], i, j, k]
material = next(x for x in G.materials if x.numID == requirednumID)
newmaterial = deepcopy(material)
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'
# Add conductivity of voltage source to underlying conductivity
if self.polarisation == 'x':
newmaterial.se += G.dx / (self.resistance * G.dy * G.dz)
elif self.polarisation == 'y':
newmaterial.se += G.dy / (self.resistance * G.dx * G.dz)
elif self.polarisation == 'z':
newmaterial.se += G.dz / (self.resistance * G.dx * G.dy)
# Add conductivity of voltage source to underlying conductivity
if self.polarisation == 'x':
newmaterial.se += G.dx / (self.resistance * G.dy * G.dz)
elif self.polarisation == 'y':
newmaterial.se += G.dy / (self.resistance * G.dx * G.dz)
elif self.polarisation == 'z':
newmaterial.se += G.dz / (self.resistance * G.dx * G.dy)
G.ID[G.IDlookup[componentID], i, j, k] = newmaterial.numID
G.materials.append(newmaterial)
G.ID[G.IDlookup[componentID], i, j, k] = newmaterial.numID
G.materials.append(newmaterial)
class HertzianDipole(Source):
@@ -180,7 +181,7 @@ class HertzianDipole(Source):
i = self.xcoord
j = self.ycoord
k = self.zcoord
componentID = 'E' + self.polarisation
componentID = f'E{self.polarisation}'
if self.polarisation == 'x':
Ex[i, j, k] -= (updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] *
self.waveformvalues_halfdt[iteration] * self.dl *
@@ -217,7 +218,7 @@ class MagneticDipole(Source):
i = self.xcoord
j = self.ycoord
k = self.zcoord
componentID = 'H' + self.polarisation
componentID = f'H{self.polarisation}'
if self.polarisation == 'x':
Hx[i, j, k] -= (updatecoeffsH[ID[G.IDlookup[componentID], i, j, k], 4] *

查看文件

@@ -174,7 +174,7 @@ class PrecursorNodesBase:
for f in field_names:
try:
val = c1 * getattr(self, f + '_0') + c2 * getattr(self, f + '_1')
val = c1 * getattr(self, f'{f}_0') + c2 * getattr(self, f'{f}_1')
except ValueError:
raise
setattr(self, f, val)
@@ -184,7 +184,7 @@ class PrecursorNodesBase:
current main time step, i.e. ey_left = copy.ey_left_1
"""
for f in field_names:
val = np.copy(getattr(self, f + '_1'))
val = np.copy(getattr(self, f'{f}_1'))
setattr(self, f, val)
def calc_exact_magnetic_in_time(self):
@@ -218,9 +218,9 @@ class PrecursorNodesBase:
def update_previous_timestep_fields(self, field_names):
for fn in field_names:
val = getattr(self, fn + '_1')
val = getattr(self, f'{fn}_1')
val_c = np.copy(val)
setattr(self, fn + '_0', val_c)
setattr(self, f'{fn}_0', val_c)
def interpolate_to_sub_grid(self, field, coords):
x, z, x_sg, z_sg = coords

查看文件

@@ -33,10 +33,10 @@ def create_updates(G):
sg_type = type(sg)
if sg_type == SubGridHSG and sg.filter:
precursors = PrecursorNodesFiltered(G, sg)
elif sg_type == SubGridHSG and not sg.filter:
elif sg_type == SubGridHSG:
precursors = PrecursorNodes(G, sg)
else:
logger.exception(str(sg) + ' is not a subgrid type')
logger.exception(f'{str(sg)} is not a subgrid type')
raise ValueError
sgu = SubgridUpdater(sg, precursors, G)

查看文件

@@ -45,7 +45,7 @@ class SubGridBase(UserObjectMulti):
elif isinstance(node, UserObjectGeometry):
self.children_geometry.append(node)
else:
logger.exception(str(node) + ' this Object can not be added to a sub grid')
logger.exception(f'{str(node)} this Object can not be added to a sub grid')
raise ValueError
def set_discretisation(self, sg, grid):
@@ -123,12 +123,12 @@ class SubGridBase(UserObjectMulti):
self.subgrid = sg
# Copy over built in materials
sg.materials = [copy(m) for m in grid.materials if m.numID in range(0, grid.n_built_in_materials + 1)]
sg.materials = [copy(m) for m in grid.materials if m.type == 'builtin']
# Don't mix and match different subgrid types
for sg_made in grid.subgrids:
if type(sg) != type(sg_made):
logger.exception(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

查看文件

@@ -378,7 +378,7 @@ class CUDAUpdates:
for pml in self.grid.pmls['slabs']:
pml.htod_field_arrays()
pml.set_blocks_per_grid()
knl_name = 'order' + str(len(pml.CFS)) + '_' + pml.direction
knl_name = f'order{len(pml.CFS)}_{pml.direction}'
self.subs_name_args['FUNC'] = knl_name
knl_electric = getattr(knl_pml_updates_electric, knl_name)
@@ -880,21 +880,21 @@ class OpenCLUpdates:
for pml in self.grid.pmls['slabs']:
pml.set_queue(self.queue)
pml.htod_field_arrays()
knl_name = 'order' + str(len(pml.CFS)) + '_' + pml.direction
knl_name = f'order{len(pml.CFS)}_{pml.direction}'
knl_electric_name = getattr(knl_pml_updates_electric, knl_name)
knl_magnetic_name = getattr(knl_pml_updates_magnetic, knl_name)
pml.update_electric_dev = self.elwise(self.ctx,
knl_electric_name['args_opencl'].substitute({'REAL': config.sim_config.dtypes['C_float_or_double']}),
knl_electric_name['func'].substitute(subs),
'pml_updates_electric_' + knl_name,
f'pml_updates_electric_{knl_name}',
preamble=self.knl_common,
options=config.sim_config.devices['compiler_opts'])
options=config.sim_config.devices['compiler_opts'],)
pml.update_magnetic_dev = self.elwise(self.ctx,
knl_magnetic_name['args_opencl'].substitute({'REAL': config.sim_config.dtypes['C_float_or_double']}),
knl_magnetic_name['func'].substitute(subs),
'pml_updates_magnetic_' + knl_name,
f'pml_updates_magnetic_{knl_name}',
preamble=self.knl_common,
options=config.sim_config.devices['compiler_opts'])

查看文件

@@ -65,7 +65,7 @@ class UserInput:
except ValueError as err:
v = ['x', 'y', 'z']
# Discretisation
dl = getattr(self.grid, 'd' + err.args[0])
dl = getattr(self.grid, f'd{err.args[0]}')
# Incorrect index
i = p[v.index(err.args[0])]
if name:

查看文件

@@ -515,7 +515,7 @@ def print_opencl_info(devs):
if i == 0:
platform = dev.platform.name
logger.basic(f' |--->Platform: {platform}')
if not platform == dev.platform.name:
if platform != dev.platform.name:
logger.basic(f' |--->Platform: {dev.platform.name}')
types = cl.device_type.to_string(dev.type)
if 'CPU' in types:

查看文件

@@ -91,7 +91,7 @@ def logo(version):
v""" + version + '\n\n'
str = f"{description} {'=' * (get_terminal_width() - len(description) - 1)}\n\n"
str += Fore.CYAN + f'{logo}'
str += f'{Fore.CYAN}{logo}'
str += Style.RESET_ALL + textwrap.fill(copyright,
width=get_terminal_width() - 1,
initial_indent=' ') + '\n'

查看文件

@@ -54,18 +54,19 @@ class Waveform:
waveforms.
"""
if (self.type == 'gaussian' or self.type == 'gaussiandot' or
self.type == 'gaussiandotnorm' or self.type == 'gaussianprime' or
self.type == '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 == 'gaussiandotdot' or
self.type == 'gaussiandotdotnorm' or self.type == 'ricker'):
elif self.type in ['gaussiandotdot', 'gaussiandotdotnorm', 'ricker']:
self.chi = np.sqrt(2) / self.freq
self.zeta = np.pi**2 * self.freq**2
def calculate_value(self, time, dt):
"""Calculates value of the waveform at a specific time.
"""Calculates the value of the waveform at a specific time.
Args:
time: float for absolute time.
@@ -82,7 +83,7 @@ class Waveform:
delay = time - self.chi
ampvalue = np.exp(-self.zeta * delay**2)
elif self.type == 'gaussiandot' or self.type == 'gaussianprime':
elif self.type in ['gaussiandot', 'gaussianprime']:
delay = time - self.chi
ampvalue = -2 * self.zeta * delay * np.exp(-self.zeta * delay**2)
@@ -91,7 +92,7 @@ class Waveform:
normalise = np.sqrt(np.exp(1) / (2 * self.zeta))
ampvalue = -2 * self.zeta * delay * np.exp(-self.zeta * delay**2) * normalise
elif self.type == 'gaussiandotdot' or self.type == 'gaussiandoubleprime':
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))
@@ -116,8 +117,8 @@ class Waveform:
elif self.type == 'contsine':
rampamp = 0.25
ramp = rampamp * time * self.freq
if ramp > 1:
ramp = 1
ramp = min(ramp, 1)
ampvalue = ramp * np.sin(2 * np.pi * self.freq * time)
elif self.type == 'impulse':

查看文件

@@ -37,8 +37,9 @@ if sys.version_info[:2] < MIN_PYTHON_VERSION:
# 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).group(1)
version = re.search(
r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE
)[1]
def build_dispersive_material_templates():
"""Function to generate Cython .pyx file for dispersive media update.
@@ -46,7 +47,7 @@ def build_dispersive_material_templates():
functions.
"""
iswin = True if sys.platform == 'win32' else False
iswin = (sys.platform == 'win32')
env = Environment(loader = FileSystemLoader(os.path.join('gprMax', 'cython')), )
@@ -133,12 +134,12 @@ if 'cleanall' in sys.argv:
for file in cythonfiles:
filebase = os.path.splitext(file)[0]
# Remove Cython C files
if os.path.isfile(filebase + '.c'):
if os.path.isfile(f'{filebase}.c'):
try:
os.remove(filebase + '.c')
print(f'Removed: {filebase + ".c"}')
os.remove(f'{filebase}.c')
print(f'Removed: {filebase}.c')
except OSError:
print(f'Could not remove: {filebase + ".c"}')
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') +
@@ -176,10 +177,6 @@ else:
linker_args = []
libraries = []
# Compiler options - macOS - needs gcc (usually via HomeBrew) because the
# default compiler LLVM (clang) does not
# support OpenMP. With gcc -fopenmp option
# implies -pthread
elif sys.platform == 'darwin':
# Check for Intel or Apple M series CPU
cpuID = subprocess.check_output("sysctl -n machdep.cpu.brand_string",
@@ -219,12 +216,14 @@ 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',
'-mmacosx-version-min=' + MIN_MACOS_VERSION]
linker_args = ['-fopenmp', '-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']
# Compiler options - Linux
elif sys.platform == 'linux':
compile_args = ['-O3', '-w', '-fopenmp', '-march=native']
linker_args = ['-fopenmp']
@@ -261,12 +260,12 @@ 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+',
python_requires='>' + str(MIN_PYTHON_VERSION[0]) + '.' + str(MIN_PYTHON_VERSION[1]),
python_requires=f'>{str(MIN_PYTHON_VERSION[0])}.{str(MIN_PYTHON_VERSION[1])}',
install_requires=['colorama',
'cython',
'h5py',
@@ -289,4 +288,5 @@ else:
'Operating System :: POSIX :: Linux',
'Programming Language :: Cython',
'Programming Language :: Python :: 3',
'Topic :: Scientific/Engineering'])
'Topic :: Scientific/Engineering'],
)

查看文件

@@ -93,8 +93,8 @@ for x, model in enumerate(testmodels):
# Diffs
datadiffs = np.zeros(datatest.shape, dtype=np.float64)
for i in range(len(outputstest)):
max = np.amax(np.abs(dataref[:, i]))
datadiffs[:, i] = np.divide(np.abs(datatest[:, i] - dataref[:, i]), max, out=np.zeros_like(dataref[:, i]), where=max != 0) # Replace any division by zero with zero
maxi = np.amax(np.abs(dataref[:, i]))
datadiffs[:, i] = np.divide(np.abs(datatest[:, i] - dataref[:, 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)
with np.errstate(divide='ignore'):

查看文件

@@ -29,10 +29,16 @@ 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')
gv1 = gprMax.GeometryView(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
filename=Path(*parts[:-1], parts[-1] + '_n'), output_type='n')
gv2 = gprMax.GeometryView(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
filename=Path(*parts[:-1], parts[-1] + '_f'), output_type='f')
gv1 = gprMax.GeometryView(p1=(0, 0, 0),
p2=(x, y, z),
dl=(dl, dl, dl),
filename=Path(*parts[:-1], f'{parts[-1]}_n'),
output_type='n',)
gv2 = gprMax.GeometryView(p1=(0, 0, 0),
p2=(x, y, z),
dl=(dl, dl, dl),
filename=Path(*parts[:-1], f'{parts[-1]}_f'),
output_type='f',)
pmls = {'CFS-PML': {'pml': gprMax.PMLProps(formulation='HORIPML', thickness=10),
# Parameters from http://dx.doi.org/10.1109/TAP.2018.2823864

查看文件

@@ -29,10 +29,16 @@ 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')
gv1 = gprMax.GeometryView(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
filename=Path(*parts[:-1], parts[-1] + '_n'), output_type='n')
gv2 = gprMax.GeometryView(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
filename=Path(*parts[:-1], parts[-1] + '_f'), output_type='f')
gv1 = gprMax.GeometryView(p1=(0, 0, 0),
p2=(x, y, z),
dl=(dl, dl, dl),
filename=Path(*parts[:-1], f'{parts[-1]}_n'),
output_type='n',)
gv2 = gprMax.GeometryView(p1=(0, 0, 0),
p2=(x, y, z),
dl=(dl, dl, dl),
filename=Path(*parts[:-1], f'{parts[-1]}_f'),
output_type='f',)
pml = gprMax.PMLProps(formulation='HORIPML', thickness=10)

查看文件

@@ -81,8 +81,10 @@ realmax = np.where(np.abs(real[:, 1]) == 1)[0][0]
difftime = - (timemodel[modelmax] - real[realmax, 0])
# Plot modelled and real data
fig, ax = plt.subplots(num=modelfile.stem + '_vs_' + realfile.stem,
figsize=(20, 10), facecolor='w', edgecolor='w')
fig, ax = plt.subplots(num=f'{modelfile.stem}_vs_{realfile.stem}',
figsize=(20, 10),
facecolor='w',
edgecolor='w',)
ax.plot(timemodel + difftime, model, 'r', lw=2, label='Model')
ax.plot(real[:, 0], real[:, 1], 'r', ls='--', lw=2, label='Experiment')
ax.set_xlabel('Time [s]')
@@ -93,7 +95,7 @@ ax.legend()
ax.grid()
# Save a PDF/PNG of the figure
savename = modelfile.stem + '_vs_' + realfile.stem
savename = f'{modelfile.stem}_vs_{realfile.stem}'
savename = modelfile.parent / savename
# fig.savefig(savename.with_suffix('.pdf'), dpi=None, format='pdf',
# bbox_inches='tight', pad_inches=0.1)

查看文件

@@ -112,11 +112,9 @@ for i, model in enumerate(testmodels):
filetest.attrs['dt'],
filetest.attrs['dx_dy_dz'], rxposrelative)
filetest.close()
else:
# Get output for model and reference files
fileref = file.stem + '_ref'
fileref = f'{file.stem}_ref'
fileref = file.parent / Path(fileref)
fileref = h5py.File(fileref.with_suffix('.h5'), 'r')
filetest = h5py.File(file.with_suffix('.h5'), 'r')
@@ -159,15 +157,15 @@ for i, model in enumerate(testmodels):
raise ValueError
fileref.close()
filetest.close()
filetest.close()
# Diffs
datadiffs = np.zeros(datatest.shape, dtype=np.float64)
for i in range(len(outputstest)):
max = np.amax(np.abs(dataref[:, i]))
datadiffs[:, i] = np.divide(np.abs(dataref[:, i] - datatest[:, i]), max,
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=max != 0) # Replace any division by zero with zero
where=maxi != 0) # Replace any division by zero with zero
# Calculate power (ignore warning from taking a log of any zero values)
with np.errstate(divide='ignore'):
@@ -188,17 +186,17 @@ for i, model in enumerate(testmodels):
facecolor='w',
edgecolor='w')
ex1.plot(timetest, datatest[:, 0], 'r', lw=2, label=model)
ex1.plot(timeref, dataref[:, 0], 'g', lw=2, ls='--', label=model + '(Ref)')
ex1.plot(timeref, dataref[:, 0], 'g', lw=2, ls='--', label=f'{model}(Ref)')
ey1.plot(timetest, datatest[:, 1], 'r', lw=2, label=model)
ey1.plot(timeref, dataref[:, 1], 'g', lw=2, ls='--', label=model + '(Ref)')
ey1.plot(timeref, dataref[:, 1], 'g', lw=2, ls='--', label=f'{model}(Ref)')
ez1.plot(timetest, datatest[:, 2], 'r', lw=2, label=model)
ez1.plot(timeref, dataref[:, 2], 'g', lw=2, ls='--', label=model + '(Ref)')
ez1.plot(timeref, dataref[:, 2], 'g', lw=2, ls='--', label=f'{model}(Ref)')
hx1.plot(timetest, datatest[:, 3], 'r', lw=2, label=model)
hx1.plot(timeref, dataref[:, 3], 'g', lw=2, ls='--', label=model + '(Ref)')
hx1.plot(timeref, dataref[:, 3], 'g', lw=2, ls='--', label=f'{model}(Ref)')
hy1.plot(timetest, datatest[:, 4], 'r', lw=2, label=model)
hy1.plot(timeref, dataref[:, 4], 'g', lw=2, ls='--', label=model + '(Ref)')
hy1.plot(timeref, dataref[:, 4], 'g', lw=2, ls='--', label=f'{model}(Ref)')
hz1.plot(timetest, datatest[:, 5], 'r', lw=2, label=model)
hz1.plot(timeref, dataref[:, 5], 'g', lw=2, ls='--', label=model + '(Ref)')
hz1.plot(timeref, dataref[:, 5], 'g', lw=2, ls='--', label=f'{model}(Ref)')
ylabels = ['$E_x$, field strength [V/m]', '$H_x$, field strength [A/m]',
'$E_y$, field strength [V/m]', '$H_y$, field strength [A/m]',
'$E_z$, field strength [V/m]', '$H_z$, field strength [A/m]']
@@ -232,7 +230,7 @@ for i, model in enumerate(testmodels):
ax.grid()
# Save a PDF/PNG of the figure
filediffs = file.stem + '_diffs'
filediffs = f'{file.stem}_diffs'
filediffs = file.parent / Path(filediffs)
# fig1.savefig(file.with_suffix('.pdf'), dpi=None, format='pdf',
# bbox_inches='tight', pad_inches=0.1)