你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 23:14:03 +08:00
Merge branch 'devel' of https://github.com/gprMax/gprMax into devel
这个提交包含在:
13
.github/FUNDING.yml
vendored
普通文件
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),
|
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',
|
dl=(dl, dl, dl), filename='antenna_like_GSSI_1500_pcb',
|
||||||
output_type='f')
|
output_type='f')
|
||||||
scene.add(gv1)
|
#scene.add(gv1)
|
||||||
#scene.add(gv2)
|
#scene.add(gv2)
|
||||||
|
|
||||||
# Run model
|
# Run model
|
||||||
|
二进制文件未显示。
@@ -89,17 +89,10 @@ gv1 = gprMax.GeometryView(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
|
|||||||
scene.add(gv1)
|
scene.add(gv1)
|
||||||
|
|
||||||
# Create some snapshots of entire domain
|
# 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):
|
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,
|
time=(i + 0.5) * 1e-9,
|
||||||
filename=fn.with_suffix('').parts[-1] + '_' + str(i + 1),
|
filename=fn.with_suffix('').parts[-1] + '_' + str(i + 1))
|
||||||
outputs=['Ez'])
|
scene.add(s)
|
||||||
subgrid.add(s)
|
|
||||||
|
|
||||||
gprMax.run(scenes=[scene], n=1, geometry_only=False, outputfile=fn, subgrid=True, autotranslate=True)
|
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)
|
scene.add(halfspace)
|
||||||
|
|
||||||
for i in range(1, 51):
|
for i in range(1, 51):
|
||||||
snap = gprMax.Snapshot(p1=(0, y / 2, 0), p2=(x, y / 2 + dl, z), dl=(dl, dl, dl),
|
snap = gprMax.Snapshot(p1=(0, y / 2, 0),
|
||||||
filename=Path(*parts[:-1], parts[-1] + '_' + str(i)).name,
|
p2=(x, y / 2 + dl, z),
|
||||||
time=i * tw / 50)
|
dl=(dl, dl, dl),
|
||||||
|
filename=Path(*parts[:-1], f'{parts[-1]}_{str(i)}').name,
|
||||||
|
time=i * tw / 50,)
|
||||||
scene.add(snap)
|
scene.add(snap)
|
||||||
|
|
||||||
# create a geometry view of the main grid and the sub grid stitched together
|
# 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,
|
from .cmds_multiuse import (PMLCFS, AddDebyeDispersion, AddDrudeDispersion,
|
||||||
AddLorentzDispersion, GeometryObjectsWrite,
|
AddLorentzDispersion, GeometryObjectsWrite,
|
||||||
GeometryView, HertzianDipole, MagneticDipole,
|
GeometryView, HertzianDipole, MagneticDipole,
|
||||||
Material, Rx, RxArray, Snapshot, SoilPeplinski,
|
Material, MaterialList, MaterialRange, Rx, RxArray,
|
||||||
TransmissionLine, VoltageSource, Waveform, MaterialRange, MaterialList)
|
Snapshot, SoilPeplinski, TransmissionLine,
|
||||||
|
VoltageSource, Waveform)
|
||||||
from .cmds_singleuse import (Discretisation, Domain, ExcitationFile,
|
from .cmds_singleuse import (Discretisation, Domain, ExcitationFile,
|
||||||
OMPThreads, PMLProps, RxSteps, SrcSteps,
|
OMPThreads, PMLProps, RxSteps, SrcSteps,
|
||||||
TimeStepStabilityFactor, TimeWindow, Title)
|
TimeStepStabilityFactor, TimeWindow, Title)
|
||||||
|
@@ -74,7 +74,7 @@ class AddGrass(UserObjectGeometry):
|
|||||||
limits = self.kwargs['limits']
|
limits = self.kwargs['limits']
|
||||||
n_blades = self.kwargs['n_blades']
|
n_blades = self.kwargs['n_blades']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' requires at least eleven parameters')
|
logger.exception(f'{self.__str__()} requires at least eleven parameters')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -90,7 +90,7 @@ class AddGrass(UserObjectGeometry):
|
|||||||
try:
|
try:
|
||||||
volume = volumes[0]
|
volume = volumes[0]
|
||||||
except NameError:
|
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
|
raise
|
||||||
|
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
@@ -98,32 +98,32 @@ class AddGrass(UserObjectGeometry):
|
|||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
if frac_dim < 0:
|
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')
|
'the fractal dimension')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if limits[0] < 0 or limits[1] < 0:
|
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')
|
'the minimum and maximum heights for grass blades')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
if xs == xf:
|
if xs == xf:
|
||||||
if ys == yf or zs == zf:
|
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
|
raise ValueError
|
||||||
if xs != volume.xs and xs != volume.xf:
|
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
|
raise ValueError
|
||||||
fractalrange = (round_value(limits[0] / grid.dx), round_value(limits[1] / grid.dx))
|
fractalrange = (round_value(limits[0] / grid.dx), round_value(limits[1] / grid.dx))
|
||||||
# xminus surface
|
# xminus surface
|
||||||
if xs == volume.xs:
|
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')
|
'on surfaces in the positive axis direction')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
# xplus surface
|
# xplus surface
|
||||||
elif xf == volume.xf:
|
elif xf == volume.xf:
|
||||||
if fractalrange[1] > grid.nx:
|
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 ' +
|
'fractal box as it would exceed the domain ' +
|
||||||
'size in the x direction')
|
'size in the x direction')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
@@ -131,21 +131,21 @@ class AddGrass(UserObjectGeometry):
|
|||||||
|
|
||||||
elif ys == yf:
|
elif ys == yf:
|
||||||
if xs == xf or zs == zf:
|
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
|
raise ValueError
|
||||||
if ys != volume.ys and ys != volume.yf:
|
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
|
raise ValueError
|
||||||
fractalrange = (round_value(limits[0] / grid.dy), round_value(limits[1] / grid.dy))
|
fractalrange = (round_value(limits[0] / grid.dy), round_value(limits[1] / grid.dy))
|
||||||
# yminus surface
|
# yminus surface
|
||||||
if ys == volume.ys:
|
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')
|
'on surfaces in the positive axis direction')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
# yplus surface
|
# yplus surface
|
||||||
elif yf == volume.yf:
|
elif yf == volume.yf:
|
||||||
if fractalrange[1] > grid.ny:
|
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 ' +
|
'fractal box as it would exceed the domain ' +
|
||||||
'size in the y direction')
|
'size in the y direction')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
@@ -153,28 +153,28 @@ class AddGrass(UserObjectGeometry):
|
|||||||
|
|
||||||
elif zs == zf:
|
elif zs == zf:
|
||||||
if xs == xf or ys == yf:
|
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
|
raise ValueError
|
||||||
if zs != volume.zs and zs != volume.zf:
|
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
|
raise ValueError
|
||||||
fractalrange = (round_value(limits[0] / grid.dz), round_value(limits[1] / grid.dz))
|
fractalrange = (round_value(limits[0] / grid.dz), round_value(limits[1] / grid.dz))
|
||||||
# zminus surface
|
# zminus surface
|
||||||
if zs == volume.zs:
|
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')
|
'on surfaces in the positive axis direction')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
# zplus surface
|
# zplus surface
|
||||||
elif zf == volume.zf:
|
elif zf == volume.zf:
|
||||||
if fractalrange[1] > grid.nz:
|
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 ' +
|
'fractal box as it would exceed the domain ' +
|
||||||
'size in the z direction')
|
'size in the z direction')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
requestedsurface = 'zplus'
|
requestedsurface = 'zplus'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.exception(self.__str__() + ' dimensions are not specified correctly')
|
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim)
|
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim)
|
||||||
@@ -187,7 +187,7 @@ class AddGrass(UserObjectGeometry):
|
|||||||
surface.operatingonID = volume.ID
|
surface.operatingonID = volume.ID
|
||||||
surface.generate_fractal_surface()
|
surface.generate_fractal_surface()
|
||||||
if n_blades > surface.fractalsurface.shape[0] * surface.fractalsurface.shape[1]:
|
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')
|
'enough for the number of grass blades/roots specified')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -234,13 +234,13 @@ class AddGrass(UserObjectGeometry):
|
|||||||
grass = next((x for x in grid.materials if x.ID == 'grass'))
|
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)
|
testgrass = next((x for x in grass.tau if x < grid.dt), None)
|
||||||
if testgrass:
|
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.')
|
'model to be less than the relaxation time required to model grass.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
volume.fractalsurfaces.append(surface)
|
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'{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'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 ' +
|
f'with fractal dimension {surface.dimension:g}, fractal seeding ' +
|
||||||
|
@@ -74,13 +74,13 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
limits = np.array(self.kwargs['limits'])
|
limits = np.array(self.kwargs['limits'])
|
||||||
fractal_box_id = self.kwargs['fractal_box_id']
|
fractal_box_id = self.kwargs['fractal_box_id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' incorrect parameters')
|
logger.exception(f'{self.__str__()} incorrect parameters')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
try:
|
try:
|
||||||
seed = self.kwargs['seed']
|
seed = self.kwargs['seed']
|
||||||
except KeyError:
|
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 ' +
|
'means you will get a different fractal distribution ' +
|
||||||
'every time the model runs.')
|
'every time the model runs.')
|
||||||
seed = None
|
seed = None
|
||||||
@@ -93,7 +93,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
if volumes:
|
if volumes:
|
||||||
volume = volumes[0]
|
volume = volumes[0]
|
||||||
else:
|
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
|
raise ValueError
|
||||||
|
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
@@ -101,25 +101,25 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
if frac_dim < 0:
|
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')
|
'fractal dimension')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if weighting[0] < 0:
|
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')
|
'fractal weighting in the first direction of the surface')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if weighting[1] < 0:
|
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')
|
'fractal weighting in the second direction of the surface')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
if xs == xf:
|
if xs == xf:
|
||||||
if ys == yf or zs == zf:
|
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
|
raise ValueError
|
||||||
if xs != volume.xs and xs != volume.xf:
|
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')
|
'surfaces of a fractal box')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
fractalrange = (round_value(limits[0] / grid.dx),
|
fractalrange = (round_value(limits[0] / grid.dx),
|
||||||
@@ -127,7 +127,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
# xminus surface
|
# xminus surface
|
||||||
if xs == volume.xs:
|
if xs == volume.xs:
|
||||||
if fractalrange[0] < 0 or fractalrange[1] > volume.xf:
|
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 ' +
|
'to fractal box as it would exceed either the ' +
|
||||||
'upper coordinates of the fractal box or the ' +
|
'upper coordinates of the fractal box or the ' +
|
||||||
'domain in the x direction')
|
'domain in the x direction')
|
||||||
@@ -136,7 +136,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
# xplus surface
|
# xplus surface
|
||||||
elif xf == volume.xf:
|
elif xf == volume.xf:
|
||||||
if fractalrange[0] < volume.xs or fractalrange[1] > grid.nx:
|
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 ' +
|
'to fractal box as it would exceed either the ' +
|
||||||
'lower coordinates of the fractal box or the ' +
|
'lower coordinates of the fractal box or the ' +
|
||||||
'domain in the x direction')
|
'domain in the x direction')
|
||||||
@@ -145,10 +145,10 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
|
|
||||||
elif ys == yf:
|
elif ys == yf:
|
||||||
if xs == xf or zs == zf:
|
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
|
raise ValueError
|
||||||
if ys != volume.ys and ys != volume.yf:
|
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')
|
'surfaces of a fractal box')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
fractalrange = (round_value(limits[0] / grid.dy),
|
fractalrange = (round_value(limits[0] / grid.dy),
|
||||||
@@ -156,7 +156,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
# yminus surface
|
# yminus surface
|
||||||
if ys == volume.ys:
|
if ys == volume.ys:
|
||||||
if fractalrange[0] < 0 or fractalrange[1] > volume.yf:
|
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 ' +
|
'to fractal box as it would exceed either the ' +
|
||||||
'upper coordinates of the fractal box or the ' +
|
'upper coordinates of the fractal box or the ' +
|
||||||
'domain in the y direction')
|
'domain in the y direction')
|
||||||
@@ -165,7 +165,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
# yplus surface
|
# yplus surface
|
||||||
elif yf == volume.yf:
|
elif yf == volume.yf:
|
||||||
if fractalrange[0] < volume.ys or fractalrange[1] > grid.ny:
|
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 ' +
|
'to fractal box as it would exceed either the ' +
|
||||||
'lower coordinates of the fractal box or the ' +
|
'lower coordinates of the fractal box or the ' +
|
||||||
'domain in the y direction')
|
'domain in the y direction')
|
||||||
@@ -174,10 +174,10 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
|
|
||||||
elif zs == zf:
|
elif zs == zf:
|
||||||
if xs == xf or ys == yf:
|
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
|
raise ValueError
|
||||||
if zs != volume.zs and zs != volume.zf:
|
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')
|
'surfaces of a fractal box')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
fractalrange = (round_value(limits[0] / grid.dz),
|
fractalrange = (round_value(limits[0] / grid.dz),
|
||||||
@@ -185,7 +185,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
# zminus surface
|
# zminus surface
|
||||||
if zs == volume.zs:
|
if zs == volume.zs:
|
||||||
if fractalrange[0] < 0 or fractalrange[1] > volume.zf:
|
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 ' +
|
'to fractal box as it would exceed either the ' +
|
||||||
'upper coordinates of the fractal box or the ' +
|
'upper coordinates of the fractal box or the ' +
|
||||||
'domain in the x direction')
|
'domain in the x direction')
|
||||||
@@ -194,7 +194,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
# zplus surface
|
# zplus surface
|
||||||
elif zf == volume.zf:
|
elif zf == volume.zf:
|
||||||
if fractalrange[0] < volume.zs or fractalrange[1] > grid.nz:
|
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 ' +
|
'to fractal box as it would exceed either the ' +
|
||||||
'lower coordinates of the fractal box or the ' +
|
'lower coordinates of the fractal box or the ' +
|
||||||
'domain in the z direction')
|
'domain in the z direction')
|
||||||
@@ -202,7 +202,7 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
requestedsurface = 'zplus'
|
requestedsurface = 'zplus'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.exception(self.__str__() + ' dimensions are not specified correctly')
|
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim)
|
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim)
|
||||||
@@ -218,14 +218,14 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
|||||||
# List of existing surfaces IDs
|
# List of existing surfaces IDs
|
||||||
existingsurfaceIDs = [x.surfaceID for x in volume.fractalsurfaces]
|
existingsurfaceIDs = [x.surfaceID for x in volume.fractalsurfaces]
|
||||||
if surface.surfaceID in existingsurfaceIDs:
|
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')
|
f'{surface.surfaceID} surface')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
surface.generate_fractal_surface()
|
surface.generate_fractal_surface()
|
||||||
volume.fractalsurfaces.append(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'{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'{yf * grid.dy:g}m, {zf * grid.dz:g}m with fractal dimension ' +
|
||||||
f'{surface.dimension:g}, fractal weightings {surface.weighting[0]:g}, ' +
|
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']
|
fractal_box_id = self.kwargs['fractal_box_id']
|
||||||
depth = self.kwargs['depth']
|
depth = self.kwargs['depth']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' requires exactly eight parameters')
|
logger.exception(f'{self.__str__()} requires exactly eight parameters')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.do_rotate:
|
if self.do_rotate:
|
||||||
self._do_rotate()
|
self._do_rotate()
|
||||||
|
|
||||||
# Get the correct fractal volume
|
if volumes := [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]:
|
||||||
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
|
|
||||||
if volumes:
|
|
||||||
volume = volumes[0]
|
volume = volumes[0]
|
||||||
else:
|
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
|
raise ValueError
|
||||||
|
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
@@ -87,18 +85,18 @@ class AddSurfaceWater(UserObjectGeometry):
|
|||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
if depth <= 0:
|
if depth <= 0:
|
||||||
logger.exception(self.__str__() + ' requires a positive value for ' +
|
logger.exception(f'{self.__str__()} requires a positive value for the ' +
|
||||||
'the depth of water')
|
f'depth of water')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
if xs == xf:
|
if xs == xf:
|
||||||
if ys == yf or zs == zf:
|
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
|
raise ValueError
|
||||||
if xs != volume.xs and xs != volume.xf:
|
if xs not in [volume.xs, volume.xf]:
|
||||||
logger.exception(self.__str__() + ' can only be used on the ' +
|
logger.exception(f'{self.__str__()} can only be used on the external surfaces '
|
||||||
'external surfaces of a fractal box')
|
f'of a fractal box')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
# xminus surface
|
# xminus surface
|
||||||
if xs == volume.xs:
|
if xs == volume.xs:
|
||||||
@@ -110,12 +108,12 @@ class AddSurfaceWater(UserObjectGeometry):
|
|||||||
filldepth = filldepthcells * grid.dx
|
filldepth = filldepthcells * grid.dx
|
||||||
|
|
||||||
elif ys == yf:
|
elif ys == yf:
|
||||||
if xs == xf or zs == zf:
|
if zs == zf:
|
||||||
logger.exception(self.__str__() + ' dimensions are not specified correctly')
|
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if ys != volume.ys and ys != volume.yf:
|
if ys not in [volume.ys, volume.yf]:
|
||||||
logger.exception(self.__str__() + ' can only be used on the ' +
|
logger.exception(f'{self.__str__()} can only be used on the external surfaces ' +
|
||||||
'external surfaces of a fractal box')
|
f'of a fractal box')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
# yminus surface
|
# yminus surface
|
||||||
if ys == volume.ys:
|
if ys == volume.ys:
|
||||||
@@ -127,12 +125,9 @@ class AddSurfaceWater(UserObjectGeometry):
|
|||||||
filldepth = filldepthcells * grid.dy
|
filldepth = filldepthcells * grid.dy
|
||||||
|
|
||||||
elif zs == zf:
|
elif zs == zf:
|
||||||
if xs == xf or ys == yf:
|
if zs not in [volume.zs, volume.zf]:
|
||||||
logger.exception(self.__str__() + ' dimensions are not specified correctly')
|
logger.exception(f'{self.__str__()} can only be used on the external surfaces '
|
||||||
raise ValueError
|
f'of a fractal box')
|
||||||
if zs != volume.zs and zs != volume.zf:
|
|
||||||
logger.exception(self.__str__() + ' can only be used on the ' +
|
|
||||||
'external surfaces of a fractal box')
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
# zminus surface
|
# zminus surface
|
||||||
if zs == volume.zs:
|
if zs == volume.zs:
|
||||||
@@ -144,38 +139,35 @@ class AddSurfaceWater(UserObjectGeometry):
|
|||||||
filldepth = filldepthcells * grid.dz
|
filldepth = filldepthcells * grid.dz
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.exception(self.__str__() + ' dimensions are not specified correctly')
|
logger.exception(f'{self.__str__()} dimensions are not specified correctly')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
surface = next((x for x in volume.fractalsurfaces if x.surfaceID == requestedsurface), None)
|
surface = next((x for x in volume.fractalsurfaces if x.surfaceID == requestedsurface), None)
|
||||||
if not surface:
|
if not surface:
|
||||||
logger.exception(self.__str__() + f' specified surface {requestedsurface} ' +
|
logger.exception(f'{self.__str__()} specified surface {requestedsurface} ' +
|
||||||
'does not have a rough surface applied')
|
f'does not have a rough surface applied')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
surface.filldepth = filldepthcells
|
surface.filldepth = filldepthcells
|
||||||
|
|
||||||
# Check that requested fill depth falls within range of surface roughness
|
# Check that requested fill depth falls within range of surface roughness
|
||||||
if surface.filldepth < surface.fractalrange[0] or surface.filldepth > surface.fractalrange[1]:
|
if surface.filldepth < surface.fractalrange[0] or surface.filldepth > surface.fractalrange[1]:
|
||||||
logger.exception(self.__str__() + ' requires a value for the depth ' +
|
logger.exception(f'{self.__str__()} requires a value for the depth of water that lies with the ' +
|
||||||
'of water that lies with the range of the requested ' +
|
f'range of the requested surface roughness')
|
||||||
'surface roughness')
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Check to see if water has been already defined as a material
|
# 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)
|
create_water(grid)
|
||||||
|
|
||||||
# Check if time step for model is suitable for using water
|
# Check if time step for model is suitable for using water
|
||||||
water = next((x for x in grid.materials if x.ID == '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 := next((x for x in water.tau if x < grid.dt), None):
|
||||||
if testwater:
|
logger.exception(f'{self.__str__()} requires the time step for the model '
|
||||||
logger.exception(self.__str__() + ' requires the time step for the ' +
|
f'to be less than the relaxation time required to model water.')
|
||||||
'model to be less than the relaxation time required ' +
|
|
||||||
'to model water.')
|
|
||||||
raise ValueError
|
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'{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'{yf * grid.dy:g}m, {zf * grid.dz:g}m with depth {filldepth:g}m, ' +
|
||||||
f'added to {surface.operatingonID}.')
|
f'added to {surface.operatingonID}.')
|
||||||
|
@@ -65,7 +65,7 @@ class Box(UserObjectGeometry):
|
|||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' Please specify two points.')
|
logger.exception(f'{self.__str__()} Please specify two points.')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.do_rotate:
|
if self.do_rotate:
|
||||||
@@ -80,7 +80,7 @@ class Box(UserObjectGeometry):
|
|||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' No materials have been specified')
|
logger.exception(f'{self.__str__()} No materials have been specified')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Check averaging
|
# Check averaging
|
||||||
@@ -103,7 +103,7 @@ class Box(UserObjectGeometry):
|
|||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
@@ -144,7 +144,7 @@ class Box(UserObjectGeometry):
|
|||||||
|
|
||||||
dielectricsmoothing = 'on' if averaging else 'off'
|
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"{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"material(s) {', '.join(materialsrequested)} created, " +
|
||||||
f"dielectric smoothing is {dielectricsmoothing}.")
|
f"dielectric smoothing is {dielectricsmoothing}.")
|
||||||
|
@@ -66,6 +66,5 @@ r = template.render(
|
|||||||
}]
|
}]
|
||||||
)
|
)
|
||||||
|
|
||||||
f = open('cython/dispersive_updates_test.pyx', 'w')
|
with open('cython/dispersive_updates_test.pyx', 'w') as f:
|
||||||
f.write(r)
|
f.write(r)
|
||||||
f.close()
|
|
||||||
|
@@ -38,9 +38,9 @@ class UserObjectGeometry:
|
|||||||
"""Readable string of parameters given to object."""
|
"""Readable string of parameters given to object."""
|
||||||
s = ''
|
s = ''
|
||||||
for _, v in self.kwargs.items():
|
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])
|
v = ' '.join([str(el) for el in v])
|
||||||
s += str(v) + ' '
|
s += f'{str(v)} '
|
||||||
|
|
||||||
return f'{self.hash}: {s[:-1]}'
|
return f'{self.hash}: {s[:-1]}'
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ def rotate_2point_object(pts, axis, angle, origin=None):
|
|||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Check axis is valid
|
# 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')
|
logger.exception('Axis of rotation must be x, y, or z')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
|
@@ -55,7 +55,7 @@ class Cone(UserObjectGeometry):
|
|||||||
r1 = self.kwargs['r1']
|
r1 = self.kwargs['r1']
|
||||||
r2 = self.kwargs['r2']
|
r2 = self.kwargs['r2']
|
||||||
except KeyError:
|
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
|
raise
|
||||||
|
|
||||||
# Check averaging
|
# Check averaging
|
||||||
@@ -75,7 +75,7 @@ class Cone(UserObjectGeometry):
|
|||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' no materials have been specified')
|
logger.exception(f'{self.__str__()} no materials have been specified')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
p3 = uip.round_to_grid_static_point(p1)
|
p3 = uip.round_to_grid_static_point(p1)
|
||||||
@@ -85,15 +85,15 @@ class Cone(UserObjectGeometry):
|
|||||||
x2, y2, z2 = uip.round_to_grid(p2)
|
x2, y2, z2 = uip.round_to_grid(p2)
|
||||||
|
|
||||||
if r1 < 0:
|
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
|
raise ValueError
|
||||||
|
|
||||||
if r2 < 0:
|
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
|
raise ValueError
|
||||||
|
|
||||||
if r1 == 0 and r2 == 0:
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
@@ -101,7 +101,7 @@ class Cone(UserObjectGeometry):
|
|||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
@@ -141,7 +141,7 @@ class Cone(UserObjectGeometry):
|
|||||||
grid.rigidE, grid.rigidH, grid.ID)
|
grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
dielectricsmoothing = 'on' if averaging else 'off'
|
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"{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"with radii {r1:g}m and {r2:g}, of material(s) {', '.join(materialsrequested)} " +
|
||||||
f"created, dielectric smoothing is {dielectricsmoothing}.")
|
f"created, dielectric smoothing is {dielectricsmoothing}.")
|
||||||
|
@@ -52,7 +52,7 @@ class Cylinder(UserObjectGeometry):
|
|||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
r = self.kwargs['r']
|
r = self.kwargs['r']
|
||||||
except KeyError:
|
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
|
raise
|
||||||
|
|
||||||
# Check averaging
|
# Check averaging
|
||||||
@@ -72,7 +72,7 @@ class Cylinder(UserObjectGeometry):
|
|||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' no materials have been specified')
|
logger.exception(f'{self.__str__()} no materials have been specified')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
p3 = uip.round_to_grid_static_point(p1)
|
p3 = uip.round_to_grid_static_point(p1)
|
||||||
@@ -82,7 +82,7 @@ class Cylinder(UserObjectGeometry):
|
|||||||
x2, y2, z2 = uip.round_to_grid(p2)
|
x2, y2, z2 = uip.round_to_grid(p2)
|
||||||
|
|
||||||
if r <= 0:
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
@@ -90,7 +90,7 @@ class Cylinder(UserObjectGeometry):
|
|||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
@@ -130,7 +130,7 @@ class Cylinder(UserObjectGeometry):
|
|||||||
grid.rigidE, grid.rigidH, grid.ID)
|
grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
dielectricsmoothing = 'on' if averaging else 'off'
|
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"{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"with radius {r:g}m, of material(s) {', '.join(materialsrequested)} " +
|
||||||
f"created, dielectric smoothing is {dielectricsmoothing}.")
|
f"created, dielectric smoothing is {dielectricsmoothing}.")
|
||||||
|
@@ -88,24 +88,25 @@ class CylindricalSector(UserObjectGeometry):
|
|||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' No materials have been specified')
|
logger.exception(f'{self.__str__()} No materials have been specified')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
sectorstartangle = 2 * np.pi * (start / 360)
|
sectorstartangle = 2 * np.pi * (start / 360)
|
||||||
sectorangle = 2 * np.pi * (end / 360)
|
sectorangle = 2 * np.pi * (end / 360)
|
||||||
|
|
||||||
if normal != 'x' and normal != 'y' and normal != 'z':
|
if normal not in ['x', 'y', 'z']:
|
||||||
logger.exception(self.__str__() + ' the normal direction must be either x, y or z.')
|
logger.exception(f'{self.__str__()} the normal direction must be either ' +
|
||||||
|
f'x, y or z.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if r <= 0:
|
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:
|
if sectorstartangle < 0 or sectorangle <= 0:
|
||||||
logger.exception(self.__str__() + ' the starting angle and sector ' +
|
logger.exception(f'{self.__str__()} the starting angle and sector angle should be ' +
|
||||||
'angle should be a positive values.')
|
f'a positive values.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if sectorstartangle >= 2 * np.pi or sectorangle >= 2 * np.pi:
|
if sectorstartangle >= 2 * np.pi or sectorangle >= 2 * np.pi:
|
||||||
logger.exception(self.__str__() + ' the starting angle and sector ' +
|
logger.exception(f'{self.__str__()} the starting angle and sector angle must be ' +
|
||||||
'angle must be less than 360 degrees.')
|
f'less than 360 degrees.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
@@ -113,7 +114,7 @@ class CylindricalSector(UserObjectGeometry):
|
|||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
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
|
raise ValueError
|
||||||
|
|
||||||
if thickness > 0:
|
if thickness > 0:
|
||||||
@@ -122,13 +123,12 @@ class CylindricalSector(UserObjectGeometry):
|
|||||||
averaging = materials[0].averagable and averagecylindricalsector
|
averaging = materials[0].averagable and averagecylindricalsector
|
||||||
numID = numIDx = numIDy = numIDz = materials[0].numID
|
numID = numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
|
||||||
elif len(materials) == 3:
|
elif len(materials) == 3:
|
||||||
averaging = False
|
averaging = False
|
||||||
numIDx = materials[0].numID
|
numIDx = materials[0].numID
|
||||||
numIDy = materials[1].numID
|
numIDy = materials[1].numID
|
||||||
numIDz = materials[2].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]
|
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
||||||
if averagedmaterial:
|
if averagedmaterial:
|
||||||
numID = averagedmaterial.numID
|
numID = averagedmaterial.numID
|
||||||
@@ -181,14 +181,14 @@ class CylindricalSector(UserObjectGeometry):
|
|||||||
|
|
||||||
if thickness > 0:
|
if thickness > 0:
|
||||||
dielectricsmoothing = 'on' if averaging else 'off'
|
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"{ctr1:g}m, {ctr2:g}m, radius {r:g}m, starting angle " +
|
||||||
f"{(sectorstartangle / (2 * np.pi)) * 360:.1f} degrees, " +
|
f"{(sectorstartangle / (2 * np.pi)) * 360:.1f} degrees, " +
|
||||||
f"sector angle {(sectorangle / (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"thickness {thickness:g}m, of material(s) {', '.join(materialsrequested)} " +
|
||||||
f"created, dielectric smoothing is {dielectricsmoothing}.")
|
f"created, dielectric smoothing is {dielectricsmoothing}.")
|
||||||
else:
|
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"{ctr1:g}m, {ctr2:g}m, radius {r:g}m, starting angle " +
|
||||||
f"{(sectorstartangle / (2 * np.pi)) * 360:.1f} degrees, " +
|
f"{(sectorstartangle / (2 * np.pi)) * 360:.1f} degrees, " +
|
||||||
f"sector angle {(sectorangle / (2 * np.pi)) * 360:.1f} " +
|
f"sector angle {(sectorangle / (2 * np.pi)) * 360:.1f} " +
|
||||||
|
@@ -62,7 +62,7 @@ class Edge(UserObjectGeometry):
|
|||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
material_id = self.kwargs['material_id']
|
material_id = self.kwargs['material_id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' requires exactly 3 parameters')
|
logger.exception(f'{self.__str__()} requires exactly 3 parameters')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.do_rotate:
|
if self.do_rotate:
|
||||||
@@ -83,32 +83,23 @@ class Edge(UserObjectGeometry):
|
|||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
# x-orientated edge
|
# x-orientated edge
|
||||||
if xs != xf:
|
if ((xs != xf and (ys != yf or zs != zf))
|
||||||
if ys != yf or zs != zf:
|
or (ys != yf and (xs != xf or zs != zf))
|
||||||
logger.exception(self.__str__() + ' the edge is not specified correctly')
|
or (zs != zf and (xs != xf or ys != yf))):
|
||||||
|
logger.exception(f'{self.__str__()} the edge is not specified correctly')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
else:
|
elif xs != xf:
|
||||||
for i in range(xs, xf):
|
for i in range(xs, xf):
|
||||||
build_edge_x(i, ys, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
build_edge_x(i, ys, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
# y-orientated edge
|
|
||||||
elif ys != yf:
|
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):
|
for j in range(ys, yf):
|
||||||
build_edge_y(xs, j, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
build_edge_y(xs, j, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
# z-orientated edge
|
|
||||||
elif zs != zf:
|
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):
|
for k in range(zs, zf):
|
||||||
build_edge_z(xs, ys, k, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
build_edge_z(xs, ys, k, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
logger.info(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'{p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m of ' +
|
||||||
f'material {material_id} created.')
|
f'material {material_id} created.')
|
||||||
|
@@ -53,7 +53,7 @@ class Ellipsoid(UserObjectGeometry):
|
|||||||
zr = self.kwargs['zr']
|
zr = self.kwargs['zr']
|
||||||
|
|
||||||
except KeyError:
|
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
|
raise
|
||||||
|
|
||||||
# Check averaging
|
# Check averaging
|
||||||
@@ -73,7 +73,7 @@ class Ellipsoid(UserObjectGeometry):
|
|||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' no materials have been specified')
|
logger.exception(f'{self.__str__()} no materials have been specified')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Centre of sphere
|
# Centre of sphere
|
||||||
@@ -86,7 +86,7 @@ class Ellipsoid(UserObjectGeometry):
|
|||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
@@ -126,7 +126,7 @@ class Ellipsoid(UserObjectGeometry):
|
|||||||
grid.rigidE, grid.rigidH, grid.ID)
|
grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
dielectricsmoothing = 'on' if averaging else 'off'
|
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"{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"{', '.join(materialsrequested)} created, dielectric " +
|
||||||
f"smoothing is {dielectricsmoothing}.")
|
f"smoothing is {dielectricsmoothing}.")
|
||||||
|
@@ -78,13 +78,13 @@ class FractalBox(UserObjectGeometry):
|
|||||||
mixing_model_id = self.kwargs['mixing_model_id']
|
mixing_model_id = self.kwargs['mixing_model_id']
|
||||||
ID = self.kwargs['id']
|
ID = self.kwargs['id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' Incorrect parameters')
|
logger.exception(f'{self.__str__()} Incorrect parameters')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
try:
|
try:
|
||||||
seed = self.kwargs['seed']
|
seed = self.kwargs['seed']
|
||||||
except KeyError:
|
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 ' +
|
'means you will get a different fractal distribution ' +
|
||||||
'every time the model runs.')
|
'every time the model runs.')
|
||||||
seed = None
|
seed = None
|
||||||
@@ -109,22 +109,22 @@ class FractalBox(UserObjectGeometry):
|
|||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
if frac_dim < 0:
|
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')
|
'fractal dimension')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if weighting[0] < 0:
|
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')
|
'fractal weighting in the x direction')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if weighting[1] < 0:
|
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')
|
'fractal weighting in the y direction')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if weighting[2] < 0:
|
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')
|
'fractal weighting in the z direction')
|
||||||
if n_materials < 0:
|
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')
|
'number of bins')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -136,14 +136,14 @@ class FractalBox(UserObjectGeometry):
|
|||||||
|
|
||||||
if mixingmodel:
|
if mixingmodel:
|
||||||
if nbins == 1:
|
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.')
|
'one material from the mixing model.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
# Create materials from mixing model as number of bins now known
|
# Create materials from mixing model as number of bins now known
|
||||||
# from fractal_box command.
|
# from fractal_box command.
|
||||||
mixingmodel.calculate_properties(nbins, grid)
|
mixingmodel.calculate_properties(nbins, grid)
|
||||||
elif not material:
|
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')
|
'ID {mixing_model_id} does not exist')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ class FractalBox(UserObjectGeometry):
|
|||||||
volume.mixingmodel = mixingmodel
|
volume.mixingmodel = mixingmodel
|
||||||
|
|
||||||
dielectricsmoothing = 'on' if volume.averaging else 'off'
|
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'{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'{p4[1]:g}m, {p4[2]:g}m with {volume.operatingonID}, ' +
|
||||||
f'fractal dimension {volume.dimension:g}, fractal weightings ' +
|
f'fractal dimension {volume.dimension:g}, fractal weightings ' +
|
||||||
|
@@ -319,7 +319,7 @@ class FractalBoxBuilder(UserObjectGeometry):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
if volume.nbins == 1:
|
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, ' +
|
'single material and no modifications, ' +
|
||||||
'therefore please use a #box command instead.')
|
'therefore please use a #box command instead.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
@@ -46,7 +46,7 @@ class GeometryObjectsRead(UserObjectGeometry):
|
|||||||
geofile = self.kwargs['geofile']
|
geofile = self.kwargs['geofile']
|
||||||
matfile = self.kwargs['matfile']
|
matfile = self.kwargs['matfile']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + 'requires exactly five parameters')
|
logger.exception(f'{self.__str__()} requires exactly five parameters')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Discretise the point using uip object. This has different behaviour
|
# 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
|
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[1] / grid.dy) != 1 or
|
||||||
round_value(dx_dy_dz[2] / grid.dz) != 1):
|
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 ' +
|
'of the geometry objects file to match the spatial ' +
|
||||||
'resolution of the model')
|
'resolution of the model')
|
||||||
raise ValueError
|
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.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.rigidH[:, xs:xs + rigidH.shape[1], ys:ys + rigidH.shape[2], zs:zs + rigidH.shape[3]] = rigidH
|
||||||
grid.ID[:, xs:xs + ID.shape[1], ys:ys + ID.shape[2], zs:zs + ID.shape[3]] = ID + numexistmaterials
|
grid.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'inserted at {xs * grid.dx:g}m, {ys * grid.dy:g}m, ' +
|
||||||
f'{zs * grid.dz:g}m, with corresponding materials file ' +
|
f'{zs * grid.dz:g}m, with corresponding materials file ' +
|
||||||
f'{matfile}.')
|
f'{matfile}.')
|
||||||
@@ -131,7 +131,7 @@ class GeometryObjectsRead(UserObjectGeometry):
|
|||||||
build_voxels_from_array(xs, ys, zs, config.get_model_config().ompthreads,
|
build_voxels_from_array(xs, ys, zs, config.get_model_config().ompthreads,
|
||||||
numexistmaterials, averaging, data,
|
numexistmaterials, averaging, data,
|
||||||
grid.solid, grid.rigidE, grid.rigidH, grid.ID)
|
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'(voxels only){geofile} inserted at {xs * grid.dx:g}m, ' +
|
||||||
f'{ys * grid.dy:g}m, {zs * grid.dz:g}m, with corresponding ' +
|
f'{ys * grid.dy:g}m, {zs * grid.dz:g}m, with corresponding ' +
|
||||||
f'materials file {matfile}.')
|
f'materials file {matfile}.')
|
||||||
|
@@ -61,7 +61,7 @@ class Plate(UserObjectGeometry):
|
|||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' 2 points must be specified')
|
logger.exception(f'{self.__str__()} 2 points must be specified')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# isotropic
|
# isotropic
|
||||||
@@ -72,7 +72,7 @@ class Plate(UserObjectGeometry):
|
|||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' No materials have been specified')
|
logger.exception(f'{self.__str__()} No materials have been specified')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.do_rotate:
|
if self.do_rotate:
|
||||||
@@ -86,23 +86,10 @@ class Plate(UserObjectGeometry):
|
|||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
if xs == xf:
|
if ((xs == xf and (ys == yf or zs == zf))
|
||||||
if ys == yf or zs == zf:
|
or (ys == yf and (xs == xf or zs == zf))
|
||||||
logger.exception(self.__str__() + ' the plate is not specified correctly')
|
or (zs == zf and (ys != yf and xs != xf))):
|
||||||
raise ValueError
|
logger.exception(f'{self.__str__()} the plate is not specified correctly')
|
||||||
|
|
||||||
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')
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
@@ -110,7 +97,7 @@ class Plate(UserObjectGeometry):
|
|||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
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
|
raise ValueError
|
||||||
|
|
||||||
# yz-plane plate
|
# yz-plane plate
|
||||||
@@ -161,6 +148,6 @@ class Plate(UserObjectGeometry):
|
|||||||
build_face_xy(i, j, zs, numIDx, numIDy, grid.rigidE,
|
build_face_xy(i, j, zs, numIDx, numIDy, grid.rigidE,
|
||||||
grid.rigidH, grid.ID)
|
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"{p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m of " +
|
||||||
f"material(s) {', '.join(materialsrequested)} created.")
|
f"material(s) {', '.join(materialsrequested)} created.")
|
||||||
|
@@ -48,7 +48,7 @@ class Sphere(UserObjectGeometry):
|
|||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
r = self.kwargs['r']
|
r = self.kwargs['r']
|
||||||
except KeyError:
|
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
|
raise
|
||||||
|
|
||||||
# Check averaging
|
# Check averaging
|
||||||
@@ -68,7 +68,7 @@ class Sphere(UserObjectGeometry):
|
|||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' no materials have been specified')
|
logger.exception(f'{self.__str__()} no materials have been specified')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Centre of sphere
|
# Centre of sphere
|
||||||
@@ -85,7 +85,7 @@ class Sphere(UserObjectGeometry):
|
|||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
@@ -125,7 +125,7 @@ class Sphere(UserObjectGeometry):
|
|||||||
grid.rigidE, grid.rigidH, grid.ID)
|
grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
dielectricsmoothing = 'on' if averaging else 'off'
|
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"{p2[1]:g}m, {p2[2]:g}m, radius {r:g}m, of material(s) " +
|
||||||
f"{', '.join(materialsrequested)} created, dielectric " +
|
f"{', '.join(materialsrequested)} created, dielectric " +
|
||||||
f"smoothing is {dielectricsmoothing}.")
|
f"smoothing is {dielectricsmoothing}.")
|
||||||
|
@@ -70,7 +70,7 @@ class Triangle(UserObjectGeometry):
|
|||||||
up3 = self.kwargs['p3']
|
up3 = self.kwargs['p3']
|
||||||
thickness = self.kwargs['thickness']
|
thickness = self.kwargs['thickness']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' specify 3 points and a thickness')
|
logger.exception(f'{self.__str__()} specify 3 points and a thickness')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.do_rotate:
|
if self.do_rotate:
|
||||||
@@ -93,7 +93,7 @@ class Triangle(UserObjectGeometry):
|
|||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' no materials have been specified')
|
logger.exception(f'{self.__str__()} no materials have been specified')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
p4 = uip.round_to_grid_static_point(up1)
|
p4 = uip.round_to_grid_static_point(up1)
|
||||||
@@ -108,21 +108,21 @@ class Triangle(UserObjectGeometry):
|
|||||||
x3, y3, z3 = uip.round_to_grid(up3)
|
x3, y3, z3 = uip.round_to_grid(up3)
|
||||||
|
|
||||||
if thickness < 0:
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
# yz-plane triangle
|
# yz-plane triangle
|
||||||
if x1 == x2 and x2 == x3:
|
if x1 == x2 == x3:
|
||||||
normal = 'x'
|
normal = 'x'
|
||||||
# xz-plane triangle
|
# xz-plane triangle
|
||||||
elif y1 == y2 and y2 == y3:
|
elif y1 == y2 == y3:
|
||||||
normal = 'y'
|
normal = 'y'
|
||||||
# xy-plane triangle
|
# xy-plane triangle
|
||||||
elif z1 == z2 and z2 == z3:
|
elif z1 == z2 == z3:
|
||||||
normal = 'z'
|
normal = 'z'
|
||||||
else:
|
else:
|
||||||
logger.exception(self.__str__() + ' the triangle is not specified correctly')
|
logger.exception(f'{self.__str__()} the triangle is not specified correctly')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
@@ -130,7 +130,7 @@ class Triangle(UserObjectGeometry):
|
|||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
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
|
raise ValueError
|
||||||
|
|
||||||
if thickness > 0:
|
if thickness > 0:
|
||||||
@@ -185,13 +185,13 @@ class Triangle(UserObjectGeometry):
|
|||||||
|
|
||||||
if thickness > 0:
|
if thickness > 0:
|
||||||
dielectricsmoothing = 'on' if averaging else 'off'
|
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"{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"{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"{thickness:g}m of material(s) {', '.join(materialsrequested)} " +
|
||||||
f"created, dielectric smoothing is {dielectricsmoothing}.")
|
f"created, dielectric smoothing is {dielectricsmoothing}.")
|
||||||
else:
|
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"{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"{p5[2]:g}m, {p6[0]:g}m {p6[1]:g}m {p6[2]:g}m of material(s) " +
|
||||||
f"{', '.join(materialsrequested)} created.")
|
f"{', '.join(materialsrequested)} created.")
|
||||||
|
@@ -61,9 +61,9 @@ class UserObjectMulti:
|
|||||||
"""Readable user string as per hash commands."""
|
"""Readable user string as per hash commands."""
|
||||||
s = ''
|
s = ''
|
||||||
for _, v in self.kwargs.items():
|
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])
|
v = ' '.join([str(el) for el in v])
|
||||||
s += str(v) + ' '
|
s += f'{str(v)} '
|
||||||
|
|
||||||
return f'{self.hash}: {s[:-1]}'
|
return f'{self.hash}: {s[:-1]}'
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ class UserObjectMulti:
|
|||||||
|
|
||||||
def params_str(self):
|
def params_str(self):
|
||||||
"""Readable string of parameters given to object."""
|
"""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):
|
def grid_name(self, grid):
|
||||||
"""Returns subgrid name for use with logging info. Returns an empty
|
"""Returns subgrid name for use with logging info. Returns an empty
|
||||||
@@ -114,12 +114,12 @@ class Waveform(UserObjectMulti):
|
|||||||
try:
|
try:
|
||||||
wavetype = self.kwargs['wave_type'].lower()
|
wavetype = self.kwargs['wave_type'].lower()
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + (f" must have one of the "
|
logger.exception(f"{self.params_str()} must have one of the " +
|
||||||
f"following types {','.join(WaveformUser.types)}."))
|
f"following types {','.join(WaveformUser.types)}.")
|
||||||
raise
|
raise
|
||||||
if wavetype not in WaveformUser.types:
|
if wavetype not in WaveformUser.types:
|
||||||
logger.exception(self.params_str() + (f" must have one of the "
|
logger.exception(f"{self.params_str()} must have one of the " +
|
||||||
f"following types {','.join(WaveformUser.types)}."))
|
f"following types {','.join(WaveformUser.types)}.")
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
if wavetype != 'user':
|
if wavetype != 'user':
|
||||||
@@ -243,18 +243,15 @@ class VoltageSource(UserObjectMulti):
|
|||||||
logger.exception(self.params_str() + (' polarisation must be '
|
logger.exception(self.params_str() + (' polarisation must be '
|
||||||
'x, y, or z.'))
|
'x, y, or z.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if ('2D TMx' in config.get_model_config().mode and
|
if '2D TMx' in config.get_model_config().mode and polarisation in ['y','z',]:
|
||||||
(polarisation == 'y' or polarisation == 'z')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be x in '
|
logger.exception(self.params_str() + (' polarisation must be x in '
|
||||||
'2D TMx mode.'))
|
'2D TMx mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
elif ('2D TMy' in config.get_model_config().mode and
|
elif '2D TMy' in config.get_model_config().mode and polarisation in ['x','z',]:
|
||||||
(polarisation == 'x' or polarisation == 'z')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be y in '
|
logger.exception(self.params_str() + (' polarisation must be y in '
|
||||||
'2D TMy mode.'))
|
'2D TMy mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
elif ('2D TMz' in config.get_model_config().mode and
|
elif '2D TMz' in config.get_model_config().mode and polarisation in ['x','y',]:
|
||||||
(polarisation == 'x' or polarisation == 'y')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be z in '
|
logger.exception(self.params_str() + (' polarisation must be z in '
|
||||||
'2D TMz mode.'))
|
'2D TMz mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
@@ -305,10 +302,7 @@ class VoltageSource(UserObjectMulti):
|
|||||||
'less.'))
|
'less.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
v.start = start
|
v.start = start
|
||||||
if stop > grid.timewindow:
|
v.stop = min(stop, grid.timewindow)
|
||||||
v.stop = grid.timewindow
|
|
||||||
else:
|
|
||||||
v.stop = stop
|
|
||||||
startstop = (f' start time {v.start:g} secs, finish time '
|
startstop = (f' start time {v.start:g} secs, finish time '
|
||||||
f'{v.stop:g} secs ')
|
f'{v.stop:g} secs ')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -318,7 +312,7 @@ class VoltageSource(UserObjectMulti):
|
|||||||
|
|
||||||
v.calculate_waveform_values(grid)
|
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'{v.polarisation} at {p2[0]:g}m, {p2[1]:g}m, {p2[2]:g}m, '
|
||||||
f'resistance {v.resistance:.1f} Ohms,' + startstop +
|
f'resistance {v.resistance:.1f} Ohms,' + startstop +
|
||||||
f'using waveform {v.waveformID} created.')
|
f'using waveform {v.waveformID} created.')
|
||||||
@@ -367,8 +361,7 @@ class HertzianDipole(UserObjectMulti):
|
|||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
waveform_id = self.kwargs['waveform_id']
|
waveform_id = self.kwargs['waveform_id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires at least 3 ' +
|
logger.exception(f'{self.params_str()} requires at least 3 parameters.')
|
||||||
'parameters.')
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.do_rotate:
|
if self.do_rotate:
|
||||||
@@ -379,18 +372,15 @@ class HertzianDipole(UserObjectMulti):
|
|||||||
logger.exception(self.params_str() + (' polarisation must be '
|
logger.exception(self.params_str() + (' polarisation must be '
|
||||||
'x, y, or z.'))
|
'x, y, or z.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if ('2D TMx' in config.get_model_config().mode and
|
if '2D TMx' in config.get_model_config().mode and polarisation in ['y','z',]:
|
||||||
(polarisation == 'y' or polarisation == 'z')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be x in '
|
logger.exception(self.params_str() + (' polarisation must be x in '
|
||||||
'2D TMx mode.'))
|
'2D TMx mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
elif ('2D TMy' in config.get_model_config().mode and
|
elif '2D TMy' in config.get_model_config().mode and polarisation in ['x','z',]:
|
||||||
(polarisation == 'x' or polarisation == 'z')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be y in '
|
logger.exception(self.params_str() + (' polarisation must be y in '
|
||||||
'2D TMy mode.'))
|
'2D TMy mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
elif ('2D TMz' in config.get_model_config().mode and
|
elif '2D TMz' in config.get_model_config().mode and polarisation in ['x','y',]:
|
||||||
(polarisation == 'x' or polarisation == 'y')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be z in '
|
logger.exception(self.params_str() + (' polarisation must be z in '
|
||||||
'2D TMz mode.'))
|
'2D TMz mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
@@ -401,7 +391,7 @@ class HertzianDipole(UserObjectMulti):
|
|||||||
|
|
||||||
# Check if there is a waveformID in the waveforms list
|
# Check if there is a waveformID in the waveforms list
|
||||||
if not any(x.ID == waveform_id for x in grid.waveforms):
|
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}.')
|
f'with the identifier {waveform_id}.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -422,8 +412,7 @@ class HertzianDipole(UserObjectMulti):
|
|||||||
h.xcoordorigin = xcoord
|
h.xcoordorigin = xcoord
|
||||||
h.ycoordorigin = ycoord
|
h.ycoordorigin = ycoord
|
||||||
h.zcoordorigin = zcoord
|
h.zcoordorigin = zcoord
|
||||||
h.ID = (h.__class__.__name__ + '(' + str(h.xcoord) + ',' +
|
h.ID = f'{h.__class__.__name__}({str(h.xcoord)},{str(h.ycoord)},{str(h.zcoord)})'
|
||||||
str(h.ycoord) + ',' + str(h.zcoord) + ')')
|
|
||||||
h.waveformID = waveform_id
|
h.waveformID = waveform_id
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -431,25 +420,19 @@ class HertzianDipole(UserObjectMulti):
|
|||||||
start = self.kwargs['start']
|
start = self.kwargs['start']
|
||||||
stop = self.kwargs['stop']
|
stop = self.kwargs['stop']
|
||||||
if start < 0:
|
if start < 0:
|
||||||
logger.exception(self.params_str() + (' delay of the initiation '
|
logger.exception(f'{self.params_str()} delay of the initiation of the ' +
|
||||||
'of the source should not '
|
f'source should not be less than zero.')
|
||||||
'be less than zero.'))
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if stop < 0:
|
if stop < 0:
|
||||||
logger.exception(self.params_str() + (' time to remove the '
|
logger.exception(f'{self.params_str()} time to remove the source ' +
|
||||||
'source should not be '
|
f'should not be less than zero.')
|
||||||
'less than zero.'))
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if stop - start <= 0:
|
if stop - start <= 0:
|
||||||
logger.exception(self.params_str() + (' duration of the source '
|
logger.exception(
|
||||||
'should not be zero or '
|
f'{self.params_str()} duration of the source should not be zero or less.')
|
||||||
'less.'))
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
h.start = start
|
h.start = start
|
||||||
if stop > grid.timewindow:
|
h.stop = min(stop, grid.timewindow)
|
||||||
h.stop = grid.timewindow
|
|
||||||
else:
|
|
||||||
h.stop = stop
|
|
||||||
startstop = (f' start time {h.start:g} secs, finish time '
|
startstop = (f' start time {h.start:g} secs, finish time '
|
||||||
f'{h.stop:g} secs ')
|
f'{h.stop:g} secs ')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -460,12 +443,12 @@ class HertzianDipole(UserObjectMulti):
|
|||||||
h.calculate_waveform_values(grid)
|
h.calculate_waveform_values(grid)
|
||||||
|
|
||||||
if config.get_model_config().mode == '2D':
|
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'source in 2D with polarity {h.polarisation} at ' +
|
||||||
f'{p2[0]:g}m, {p2[1]:g}m, {p2[2]:g}m,' + startstop +
|
f'{p2[0]:g}m, {p2[1]:g}m, {p2[2]:g}m,' + startstop +
|
||||||
f'using waveform {h.waveformID} created.')
|
f'using waveform {h.waveformID} created.')
|
||||||
else:
|
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'polarity {h.polarisation} at {p2[0]:g}m, ' +
|
||||||
f'{p2[1]:g}m, {p2[2]:g}m,' + startstop +
|
f'{p2[1]:g}m, {p2[2]:g}m,' + startstop +
|
||||||
f'using waveform {h.waveformID} created.')
|
f'using waveform {h.waveformID} created.')
|
||||||
@@ -514,8 +497,7 @@ class MagneticDipole(UserObjectMulti):
|
|||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
waveform_id = self.kwargs['waveform_id']
|
waveform_id = self.kwargs['waveform_id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires at least five '
|
logger.exception(f'{self.params_str()} requires at least five parameters.')
|
||||||
'parameters.')
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.do_rotate:
|
if self.do_rotate:
|
||||||
@@ -526,18 +508,15 @@ class MagneticDipole(UserObjectMulti):
|
|||||||
logger.exception(self.params_str() + (' polarisation must be '
|
logger.exception(self.params_str() + (' polarisation must be '
|
||||||
'x, y, or z.'))
|
'x, y, or z.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if ('2D TMx' in config.get_model_config().mode and
|
if '2D TMx' in config.get_model_config().mode and polarisation in ['y','z',]:
|
||||||
(polarisation == 'y' or polarisation == 'z')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be x in '
|
logger.exception(self.params_str() + (' polarisation must be x in '
|
||||||
'2D TMx mode.'))
|
'2D TMx mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
elif ('2D TMy' in config.get_model_config().mode and
|
elif '2D TMy' in config.get_model_config().mode and polarisation in ['x','z',]:
|
||||||
(polarisation == 'x' or polarisation == 'z')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be y in '
|
logger.exception(self.params_str() + (' polarisation must be y in '
|
||||||
'2D TMy mode.'))
|
'2D TMy mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
elif ('2D TMz' in config.get_model_config().mode and
|
elif '2D TMz' in config.get_model_config().mode and polarisation in ['x','y',]:
|
||||||
(polarisation == 'x' or polarisation == 'y')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be z in '
|
logger.exception(self.params_str() + (' polarisation must be z in '
|
||||||
'2D TMz mode.'))
|
'2D TMz mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
@@ -548,7 +527,7 @@ class MagneticDipole(UserObjectMulti):
|
|||||||
|
|
||||||
# Check if there is a waveformID in the waveforms list
|
# Check if there is a waveformID in the waveforms list
|
||||||
if not any(x.ID == waveform_id for x in grid.waveforms):
|
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}.')
|
f'with the identifier {waveform_id}.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -584,10 +563,7 @@ class MagneticDipole(UserObjectMulti):
|
|||||||
'less.'))
|
'less.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
m.start = start
|
m.start = start
|
||||||
if stop > grid.timewindow:
|
m.stop = min(stop, grid.timewindow)
|
||||||
m.stop = grid.timewindow
|
|
||||||
else:
|
|
||||||
m.stop = stop
|
|
||||||
startstop = (f' start time {m.start:g} secs, '
|
startstop = (f' start time {m.start:g} secs, '
|
||||||
f'finish time {m.stop:g} secs ')
|
f'finish time {m.stop:g} secs ')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -597,7 +573,7 @@ class MagneticDipole(UserObjectMulti):
|
|||||||
|
|
||||||
m.calculate_waveform_values(grid)
|
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,' +
|
f'{m.polarisation} at {p2[0]:g}m, {p2[1]:g}m, {p2[2]:g}m,' +
|
||||||
startstop + f'using waveform {m.waveformID} created.')
|
startstop + f'using waveform {m.waveformID} created.')
|
||||||
|
|
||||||
@@ -647,17 +623,15 @@ class TransmissionLine(UserObjectMulti):
|
|||||||
waveform_id = self.kwargs['waveform_id']
|
waveform_id = self.kwargs['waveform_id']
|
||||||
resistance = self.kwargs['resistance']
|
resistance = self.kwargs['resistance']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires at least six '
|
logger.exception(f'{self.params_str()} requires at least six parameters.')
|
||||||
'parameters.')
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.do_rotate:
|
if self.do_rotate:
|
||||||
self._do_rotate(grid)
|
self._do_rotate(grid)
|
||||||
|
|
||||||
# Warn about using a transmission line on GPU
|
# Warn about using a transmission line on GPU
|
||||||
if (config.sim_config.general['solver'] == 'cuda' or
|
if (config.sim_config.general['solver'] in ['cuda', 'opencl']):
|
||||||
config.sim_config.general['solver'] == 'opencl'):
|
logger.exception(f'{self.params_str()} cannot currently be used ' +
|
||||||
logger.exception(self.params_str() + ' cannot currently be used ' +
|
|
||||||
'with the CUDA or OpenCL-based solver. Consider ' +
|
'with the CUDA or OpenCL-based solver. Consider ' +
|
||||||
'using a #voltage_source instead.')
|
'using a #voltage_source instead.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
@@ -667,18 +641,15 @@ class TransmissionLine(UserObjectMulti):
|
|||||||
logger.exception(self.params_str() + (' polarisation must be '
|
logger.exception(self.params_str() + (' polarisation must be '
|
||||||
'x, y, or z.'))
|
'x, y, or z.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if ('2D TMx' in config.get_model_config().mode and
|
if '2D TMx' in config.get_model_config().mode and polarisation in ['y','z',]:
|
||||||
(polarisation == 'y' or polarisation == 'z')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be x in '
|
logger.exception(self.params_str() + (' polarisation must be x in '
|
||||||
'2D TMx mode.'))
|
'2D TMx mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
elif ('2D TMy' in config.get_model_config().mode and
|
elif '2D TMy' in config.get_model_config().mode and polarisation in ['x','z',]:
|
||||||
(polarisation == 'x' or polarisation == 'z')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be y in '
|
logger.exception(self.params_str() + (' polarisation must be y in '
|
||||||
'2D TMy mode.'))
|
'2D TMy mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
elif ('2D TMz' in config.get_model_config().mode and
|
elif '2D TMz' in config.get_model_config().mode and polarisation in ['x','y',]:
|
||||||
(polarisation == 'x' or polarisation == 'y')):
|
|
||||||
logger.exception(self.params_str() + (' polarisation must be z in '
|
logger.exception(self.params_str() + (' polarisation must be z in '
|
||||||
'2D TMz mode.'))
|
'2D TMz mode.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
@@ -688,14 +659,14 @@ class TransmissionLine(UserObjectMulti):
|
|||||||
|
|
||||||
|
|
||||||
if resistance <= 0 or resistance >= config.sim_config.em_consts['z0']:
|
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 ' +
|
'greater than zero and less than the impedance ' +
|
||||||
'of free space, i.e. 376.73 Ohms.')
|
'of free space, i.e. 376.73 Ohms.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Check if there is a waveformID in the waveforms list
|
# Check if there is a waveformID in the waveforms list
|
||||||
if not any(x.ID == waveform_id for x in grid.waveforms):
|
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}.')
|
f'with the identifier {waveform_id}.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -729,11 +700,8 @@ class TransmissionLine(UserObjectMulti):
|
|||||||
'less.'))
|
'less.'))
|
||||||
raise ValueError
|
raise ValueError
|
||||||
t.start = start
|
t.start = start
|
||||||
if stop > grid.timewindow:
|
t.stop = min(stop, grid.timewindow)
|
||||||
t.stop = grid.timewindow
|
startstop = (f' start time {t.start:g} secs, finish time ' +
|
||||||
else:
|
|
||||||
t.stop = stop
|
|
||||||
startstop = (f' start time {t.start:g} secs, finish time '
|
|
||||||
f'{t.stop:g} secs ')
|
f'{t.stop:g} secs ')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
t.start = 0
|
t.start = 0
|
||||||
@@ -743,7 +711,7 @@ class TransmissionLine(UserObjectMulti):
|
|||||||
t.calculate_waveform_values(grid)
|
t.calculate_waveform_values(grid)
|
||||||
t.calculate_incident_V_I(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'{t.polarisation} at {p2[0]:g}m, {p2[1]:g}m, ' +
|
||||||
f'{p2[2]:g}m, resistance {t.resistance:.1f} Ohms,' +
|
f'{p2[2]:g}m, resistance {t.resistance:.1f} Ohms,' +
|
||||||
startstop + f'using waveform {t.waveformID} created.')
|
startstop + f'using waveform {t.waveformID} created.')
|
||||||
@@ -817,16 +785,14 @@ class Rx(UserObjectMulti):
|
|||||||
outputs = [self.kwargs['outputs']]
|
outputs = [self.kwargs['outputs']]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# If no ID or outputs are specified, use default
|
# If no ID or outputs are specified, use default
|
||||||
r.ID = (r.__class__.__name__ + '(' + str(r.xcoord) + ',' +
|
r.ID = f'{r.__class__.__name__}({str(r.xcoord)},{str(r.ycoord)},{str(r.zcoord)})'
|
||||||
str(r.ycoord) + ',' + str(r.zcoord) + ')')
|
|
||||||
for key in RxUser.defaultoutputs:
|
for key in RxUser.defaultoutputs:
|
||||||
r.outputs[key] = np.zeros(grid.iterations,
|
r.outputs[key] = np.zeros(grid.iterations,
|
||||||
dtype=config.sim_config.dtypes['float_or_double'])
|
dtype=config.sim_config.dtypes['float_or_double'])
|
||||||
else:
|
else:
|
||||||
outputs.sort()
|
outputs.sort()
|
||||||
# Get allowable outputs
|
# Get allowable outputs
|
||||||
if (config.sim_config.general['solver'] =='cuda' or
|
if config.sim_config.general['solver'] in ['cuda', 'opencl']:
|
||||||
config.sim_config.general['solver'] =='opencl'):
|
|
||||||
allowableoutputs = RxUser.allowableoutputs_dev
|
allowableoutputs = RxUser.allowableoutputs_dev
|
||||||
else:
|
else:
|
||||||
allowableoutputs = RxUser.allowableoutputs
|
allowableoutputs = RxUser.allowableoutputs
|
||||||
@@ -836,14 +802,14 @@ class Rx(UserObjectMulti):
|
|||||||
r.outputs[field] = np.zeros(grid.iterations,
|
r.outputs[field] = np.zeros(grid.iterations,
|
||||||
dtype=config.sim_config.dtypes['float_or_double'])
|
dtype=config.sim_config.dtypes['float_or_double'])
|
||||||
else:
|
else:
|
||||||
logger.exception(self.params_str() + ' contains an '
|
logger.exception(f'{self.params_str()} contains an output '
|
||||||
'output type that is not allowable. '
|
f'type that is not allowable. Allowable '
|
||||||
'Allowable outputs in current context are '
|
f'outputs in current context are '
|
||||||
f'{allowableoutputs}.')
|
f'{allowableoutputs}.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
logger.info(self.grid_name(grid) + f"Receiver at {p2[0]:g}m, "
|
logger.info(f"{self.grid_name(grid)}Receiver at {p2[0]:g}m, {p2[1]:g}m, "
|
||||||
f"{p2[1]:g}m, {p2[2]:g}m with output component(s) "
|
f"{p2[2]:g}m with output component(s) "
|
||||||
f"{', '.join(r.outputs)} created.")
|
f"{', '.join(r.outputs)} created.")
|
||||||
|
|
||||||
grid.rxs.append(r)
|
grid.rxs.append(r)
|
||||||
@@ -871,8 +837,7 @@ class RxArray(UserObjectMulti):
|
|||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
dl = self.kwargs['dl']
|
dl = self.kwargs['dl']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires exactly 9 '
|
logger.exception(f'{self.params_str()} requires exactly 9 parameters')
|
||||||
'parameters')
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
xs, ys, zs = uip.check_src_rx_point(p1, self.params_str(), 'lower')
|
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)
|
dx, dy, dz = uip.discretise_point(dl)
|
||||||
|
|
||||||
if xs > xf or ys > yf or zs > zf:
|
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.')
|
'should be less than the upper coordinates.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if dx < 0 or dy < 0 or dz < 0:
|
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.')
|
'be less than zero.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if dx < 1:
|
if dx < 1:
|
||||||
if dx == 0:
|
if dx == 0:
|
||||||
dx = 1
|
dx = 1
|
||||||
else:
|
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.')
|
'not be less than the spatial discretisation.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if dy < 1:
|
if dy < 1:
|
||||||
if dy == 0:
|
if dy == 0:
|
||||||
dy = 1
|
dy = 1
|
||||||
else:
|
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.')
|
'not be less than the spatial discretisation.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if dz < 1:
|
if dz < 1:
|
||||||
if dz == 0:
|
if dz == 0:
|
||||||
dz = 1
|
dz = 1
|
||||||
else:
|
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.')
|
'not be less than the spatial discretisation.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
logger.info(self.grid_name(grid) + f'Receiver array {p3[0]:g}m, '
|
logger.info(f'{self.grid_name(grid)}Receiver array '
|
||||||
f'{p3[1]:g}m, {p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m, '
|
f'{p3[0]:g}m, {p3[1]:g}m, {p3[2]:g}m, to '
|
||||||
f'{p4[2]:g}m with steps {dx * grid.dx:g}m, '
|
f'{p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m with steps '
|
||||||
f'{dy * grid.dy:g}m, {dz * grid.dz:g}m')
|
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 x in range(xs, xf + 1, dx):
|
||||||
for y in range(ys, yf + 1, dy):
|
for y in range(ys, yf + 1, dy):
|
||||||
@@ -930,8 +895,7 @@ class RxArray(UserObjectMulti):
|
|||||||
p5 = np.array([x, y, z])
|
p5 = np.array([x, y, z])
|
||||||
p5 = uip.descretised_to_continuous(p5)
|
p5 = uip.descretised_to_continuous(p5)
|
||||||
p5 = uip.round_to_grid_static_point(p5)
|
p5 = uip.round_to_grid_static_point(p5)
|
||||||
r.ID = (r.__class__.__name__ + '(' + str(x) + ',' +
|
r.ID = f'{r.__class__.__name__}({str(x)},{str(y)},{str(z)})'
|
||||||
str(y) + ',' + str(z) + ')')
|
|
||||||
for key in RxUser.defaultoutputs:
|
for key in RxUser.defaultoutputs:
|
||||||
r.outputs[key] = np.zeros(grid.iterations, dtype=config.sim_config.dtypes['float_or_double'])
|
r.outputs[key] = np.zeros(grid.iterations, dtype=config.sim_config.dtypes['float_or_double'])
|
||||||
logger.info(f" Receiver at {p5[0]:g}m, {p5[1]:g}m, "
|
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):
|
def create(self, grid, uip):
|
||||||
if isinstance(grid, SubGridBaseGrid):
|
if isinstance(grid, SubGridBaseGrid):
|
||||||
logger.exception(self.params_str() + ' do not add snapshots to '
|
logger.exception(f'{self.params_str()} do not add snapshots to subgrids.')
|
||||||
'subgrids.')
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
try:
|
try:
|
||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
@@ -977,8 +940,7 @@ class Snapshot(UserObjectMulti):
|
|||||||
dl = self.kwargs['dl']
|
dl = self.kwargs['dl']
|
||||||
filename = self.kwargs['filename']
|
filename = self.kwargs['filename']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires exactly 11 '
|
logger.exception(f'{self.params_str()} requires exactly 11 parameters.')
|
||||||
'parameters.')
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -986,7 +948,7 @@ class Snapshot(UserObjectMulti):
|
|||||||
p4 = uip.round_to_grid_static_point(p2)
|
p4 = uip.round_to_grid_static_point(p2)
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.params_str())
|
p1, p2 = uip.check_box_points(p1, p2, self.params_str())
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.exception(self.params_str() + ' point is outside the domain.')
|
logger.exception(f'{self.params_str()} point is outside the domain.')
|
||||||
raise
|
raise
|
||||||
xs, ys, zs = p1
|
xs, ys, zs = p1
|
||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
@@ -1001,13 +963,12 @@ class Snapshot(UserObjectMulti):
|
|||||||
try:
|
try:
|
||||||
time = self.kwargs['time']
|
time = self.kwargs['time']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires exactly 5 '
|
logger.exception(f'{self.params_str()} requires exactly 5 parameters.')
|
||||||
'parameters.')
|
|
||||||
raise
|
raise
|
||||||
if time > 0:
|
if time > 0:
|
||||||
iterations = round_value((time / grid.dt)) + 1
|
iterations = round_value((time / grid.dt)) + 1
|
||||||
else:
|
else:
|
||||||
logger.exception(self.params_str() + ' time value must be '
|
logger.exception(f'{self.params_str()} time value must be ' +
|
||||||
'greater than zero.')
|
'greater than zero.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -1027,9 +988,9 @@ class Snapshot(UserObjectMulti):
|
|||||||
# Check and set output names
|
# Check and set output names
|
||||||
for output in tmp:
|
for output in tmp:
|
||||||
if output not in SnapshotUser.allowableoutputs.keys():
|
if output not in SnapshotUser.allowableoutputs.keys():
|
||||||
logger.exception(self.params_str() + " contains an "
|
logger.exception(f"{self.params_str()} contains an output "
|
||||||
"output type that is not allowable. "
|
f"type that is not allowable. Allowable "
|
||||||
"Allowable outputs in current context are "
|
f"outputs in current context are "
|
||||||
f"{', '.join(SnapshotUser.allowableoutputs.keys())}.")
|
f"{', '.join(SnapshotUser.allowableoutputs.keys())}.")
|
||||||
raise ValueError
|
raise ValueError
|
||||||
else:
|
else:
|
||||||
@@ -1039,15 +1000,15 @@ class Snapshot(UserObjectMulti):
|
|||||||
outputs = dict.fromkeys(SnapshotUser.allowableoutputs, True)
|
outputs = dict.fromkeys(SnapshotUser.allowableoutputs, True)
|
||||||
|
|
||||||
if dx < 0 or dy < 0 or dz < 0:
|
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.')
|
'be less than zero.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if dx < 1 or dy < 1 or dz < 1:
|
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.')
|
'be less than the spatial discretisation.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if iterations <= 0 or iterations > grid.iterations:
|
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
|
raise ValueError
|
||||||
|
|
||||||
s = SnapshotUser(xs, ys, zs, xf, yf, zf, dx, dy, dz, iterations,
|
s = SnapshotUser(xs, ys, zs, xf, yf, zf, dx, dy, dz, iterations,
|
||||||
@@ -1088,39 +1049,37 @@ class Material(UserObjectMulti):
|
|||||||
sm = self.kwargs['sm']
|
sm = self.kwargs['sm']
|
||||||
material_id = self.kwargs['id']
|
material_id = self.kwargs['id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires exactly five '
|
logger.exception(f'{self.params_str()} requires exactly five parameters.')
|
||||||
'parameters.')
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if er < 1:
|
if er < 1:
|
||||||
logger.exception(self.params_str() + ' requires a positive value '
|
logger.exception(f'{self.params_str()} requires a positive value of ' +
|
||||||
'of one or greater for static (DC) permittivity.')
|
f'one or greater for static (DC) permittivity.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if se != 'inf':
|
if se != 'inf':
|
||||||
se = float(se)
|
se = float(se)
|
||||||
if se < 0:
|
if se < 0:
|
||||||
logger.exception(self.params_str() + ' requires a positive '
|
logger.exception(f'{self.params_str()} requires a positive ' +
|
||||||
'value for electric conductivity.')
|
f'value for electric conductivity.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
else:
|
else:
|
||||||
se = float('inf')
|
se = float('inf')
|
||||||
if mr < 1:
|
if mr < 1:
|
||||||
logger.exception(self.params_str() + ' requires a positive value '
|
logger.exception(f'{self.params_str()} requires a positive value of ' +
|
||||||
'of one or greater for magnetic permeability.')
|
f'one or greater for magnetic permeability.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if sm < 0:
|
if sm < 0:
|
||||||
logger.exception(self.params_str() + ' requires a positive value '
|
logger.exception(f'{self.params_str()} requires a positive value ' +
|
||||||
'for magnetic loss.')
|
f'for magnetic loss.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if any(x.ID == material_id for x in grid.materials):
|
if any(x.ID == material_id for x in grid.materials):
|
||||||
logger.exception(self.params_str() + f' with ID {material_id} '
|
logger.exception(f'{self.params_str()} with ID {material_id} ' +
|
||||||
'already exists')
|
f'already exists')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Create a new instance of the Material class material
|
# Create a new instance of the Material class material
|
||||||
# (start index after pec & free_space)
|
# (start index after pec & free_space)
|
||||||
m = MaterialUser(len(grid.materials), material_id)
|
m = MaterialUser(len(grid.materials), material_id)
|
||||||
m.er = er
|
|
||||||
m.se = se
|
m.se = se
|
||||||
m.mr = mr
|
m.mr = mr
|
||||||
m.sm = sm
|
m.sm = sm
|
||||||
@@ -1129,9 +1088,10 @@ class Material(UserObjectMulti):
|
|||||||
if m.se == float('inf'):
|
if m.se == float('inf'):
|
||||||
m.averagable = False
|
m.averagable = False
|
||||||
|
|
||||||
logger.info(self.grid_name(grid) + f'Material {m.ID} with '
|
m.er = er
|
||||||
f'eps_r={m.er:g}, sigma={m.se:g} S/m; mu_r={m.mr:g}, '
|
logger.info(f'{self.grid_name(grid)}Material {m.ID} with eps_r={m.er:g}, '
|
||||||
f'sigma*={m.sm:g} Ohm/m created.')
|
f'sigma={m.se:g} S/m; mu_r={m.mr:g}, sigma*={m.sm:g} Ohm/m '
|
||||||
|
f'created.')
|
||||||
|
|
||||||
grid.materials.append(m)
|
grid.materials.append(m)
|
||||||
|
|
||||||
@@ -1162,12 +1122,11 @@ class AddDebyeDispersion(UserObjectMulti):
|
|||||||
tau = self.kwargs['tau']
|
tau = self.kwargs['tau']
|
||||||
material_ids = self.kwargs['material_ids']
|
material_ids = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires at least four '
|
logger.exception(f'{self.params_str()} requires at least four parameters.')
|
||||||
'parameters.')
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if poles < 0:
|
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.')
|
'for number of poles.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -1176,8 +1135,7 @@ class AddDebyeDispersion(UserObjectMulti):
|
|||||||
|
|
||||||
if len(materials) != len(material_ids):
|
if len(materials) != len(material_ids):
|
||||||
notfound = [x for x in material_ids if x not in materials]
|
notfound = [x for x in material_ids if x not in materials]
|
||||||
logger.exception(self.params_str() + f' material(s) {notfound} do '
|
logger.exception(f'{self.params_str()} material(s) {notfound} do not exist')
|
||||||
'not exist')
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
for material in materials:
|
for material in materials:
|
||||||
@@ -1189,14 +1147,14 @@ class AddDebyeDispersion(UserObjectMulti):
|
|||||||
disp_material.type = 'debye'
|
disp_material.type = 'debye'
|
||||||
disp_material.poles = poles
|
disp_material.poles = poles
|
||||||
disp_material.averagable = False
|
disp_material.averagable = False
|
||||||
for i in range(0, poles):
|
for i in range(poles):
|
||||||
if tau[i] > 0:
|
if tau[i] > 0:
|
||||||
logger.debug('Not checking if relaxation times are '
|
logger.debug('Not checking if relaxation times are '
|
||||||
'greater than time-step.')
|
'greater than time-step.')
|
||||||
disp_material.deltaer.append(er_delta[i])
|
disp_material.deltaer.append(er_delta[i])
|
||||||
disp_material.tau.append(tau[i])
|
disp_material.tau.append(tau[i])
|
||||||
else:
|
else:
|
||||||
logger.exception(self.params_str() + ' requires positive '
|
logger.exception(f'{self.params_str()} requires positive ' +
|
||||||
'values for the permittivity difference.')
|
'values for the permittivity difference.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if disp_material.poles > config.get_model_config().materials['maxpoles']:
|
if disp_material.poles > config.get_model_config().materials['maxpoles']:
|
||||||
@@ -1205,7 +1163,7 @@ class AddDebyeDispersion(UserObjectMulti):
|
|||||||
# Replace original material with newly created DispersiveMaterial
|
# Replace original material with newly created DispersiveMaterial
|
||||||
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
|
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
|
||||||
|
|
||||||
logger.info(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"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.")
|
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']
|
delta = self.kwargs['delta']
|
||||||
material_ids = self.kwargs['material_ids']
|
material_ids = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires at least five '
|
logger.exception(f'{self.params_str()} requires at least five parameters.')
|
||||||
'parameters.')
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if poles < 0:
|
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.')
|
'for number of poles.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -1252,8 +1209,7 @@ class AddLorentzDispersion(UserObjectMulti):
|
|||||||
|
|
||||||
if len(materials) != len(material_ids):
|
if len(materials) != len(material_ids):
|
||||||
notfound = [x for x in material_ids if x not in materials]
|
notfound = [x for x in material_ids if x not in materials]
|
||||||
logger.exception(self.params_str() + f' material(s) {notfound} do '
|
logger.exception(f'{self.params_str()} material(s) {notfound} do not exist')
|
||||||
'not exist')
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
for material in materials:
|
for material in materials:
|
||||||
@@ -1265,13 +1221,13 @@ class AddLorentzDispersion(UserObjectMulti):
|
|||||||
disp_material.type = 'lorentz'
|
disp_material.type = 'lorentz'
|
||||||
disp_material.poles = poles
|
disp_material.poles = poles
|
||||||
disp_material.averagable = False
|
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:
|
if er_delta[i] > 0 and omega[i] > grid.dt and delta[i] > grid.dt:
|
||||||
disp_material.deltaer.append(er_delta[i])
|
disp_material.deltaer.append(er_delta[i])
|
||||||
disp_material.tau.append(omega[i])
|
disp_material.tau.append(omega[i])
|
||||||
disp_material.alpha.append(delta[i])
|
disp_material.alpha.append(delta[i])
|
||||||
else:
|
else:
|
||||||
logger.exception(self.params_str() + ' requires positive '
|
logger.exception(f'{self.params_str()} requires positive '
|
||||||
'values for the permittivity difference '
|
'values for the permittivity difference '
|
||||||
'and frequencies, and associated times '
|
'and frequencies, and associated times '
|
||||||
'that are greater than the time step for '
|
'that are greater than the time step for '
|
||||||
@@ -1283,9 +1239,10 @@ class AddLorentzDispersion(UserObjectMulti):
|
|||||||
# Replace original material with newly created DispersiveMaterial
|
# Replace original material with newly created DispersiveMaterial
|
||||||
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
|
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
|
||||||
|
|
||||||
logger.info(self.grid_name(grid) + f"Lorentz disperion added to {disp_material.ID} "
|
logger.info(
|
||||||
f"with delta_eps_r={', '.join('%4.2f' % deltaer for deltaer in disp_material.deltaer)}, "
|
f"{self.grid_name(grid)}Lorentz disperion added to {disp_material.ID} " +
|
||||||
f"omega={', '.join('%4.3e' % omega for omega in disp_material.tau)} secs, "
|
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.")
|
f"and gamma={', '.join('%4.3e' % delta for delta in disp_material.alpha)} created.")
|
||||||
|
|
||||||
|
|
||||||
@@ -1313,12 +1270,12 @@ class AddDrudeDispersion(UserObjectMulti):
|
|||||||
alpha = self.kwargs['alpha']
|
alpha = self.kwargs['alpha']
|
||||||
material_ids = self.kwargs['material_ids']
|
material_ids = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires at least four '
|
logger.exception(f'{self.params_str()} requires at least four ' +
|
||||||
'parameters.')
|
'parameters.')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if poles < 0:
|
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.')
|
'for number of poles.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -1327,8 +1284,7 @@ class AddDrudeDispersion(UserObjectMulti):
|
|||||||
|
|
||||||
if len(materials) != len(material_ids):
|
if len(materials) != len(material_ids):
|
||||||
notfound = [x for x in material_ids if x not in materials]
|
notfound = [x for x in material_ids if x not in materials]
|
||||||
logger.exception(self.params_str() + f' material(s) {notfound} do '
|
logger.exception(f'{self.params_str()} material(s) {notfound} do not exist.')
|
||||||
'not exist.')
|
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
for material in materials:
|
for material in materials:
|
||||||
@@ -1340,14 +1296,14 @@ class AddDrudeDispersion(UserObjectMulti):
|
|||||||
disp_material.type = 'drude'
|
disp_material.type = 'drude'
|
||||||
disp_material.poles = poles
|
disp_material.poles = poles
|
||||||
disp_material.averagable = False
|
disp_material.averagable = False
|
||||||
for i in range(0, poles):
|
for i in range(poles):
|
||||||
if omega[i] > 0 and alpha[i] > grid.dt:
|
if omega[i] > 0 and alpha[i] > grid.dt:
|
||||||
disp_material.tau.append(omega[i])
|
disp_material.tau.append(omega[i])
|
||||||
disp_material.alpha.append(alpha[i])
|
disp_material.alpha.append(alpha[i])
|
||||||
else:
|
else:
|
||||||
logger.exception(self.params_str() + ' requires positive '
|
logger.exception(f'{self.params_str()} requires positive ' +
|
||||||
'values for the frequencies, and '
|
'values for the frequencies, and ' +
|
||||||
'associated times that are greater than '
|
'associated times that are greater than ' +
|
||||||
'the time step for the model.')
|
'the time step for the model.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if disp_material.poles > config.get_model_config().materials['maxpoles']:
|
if disp_material.poles > config.get_model_config().materials['maxpoles']:
|
||||||
@@ -1356,7 +1312,8 @@ class AddDrudeDispersion(UserObjectMulti):
|
|||||||
# Replace original material with newly created DispersiveMaterial
|
# Replace original material with newly created DispersiveMaterial
|
||||||
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
|
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
|
||||||
|
|
||||||
logger.info(self.grid_name(grid) + f"Drude disperion added to {disp_material.ID} "
|
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"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.")
|
f"and gamma={', '.join('%4.3e' % alpha for alpha in disp_material.alpha)} secs created.")
|
||||||
|
|
||||||
@@ -1392,38 +1349,38 @@ class SoilPeplinski(UserObjectMulti):
|
|||||||
water_fraction_upper = self.kwargs['water_fraction_upper']
|
water_fraction_upper = self.kwargs['water_fraction_upper']
|
||||||
ID = self.kwargs['id']
|
ID = self.kwargs['id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires at exactly seven '
|
logger.exception(f'{self.params_str()} requires at exactly seven ' +
|
||||||
'parameters.')
|
'parameters.')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if sand_fraction < 0:
|
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.')
|
'for the sand fraction.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if clay_fraction < 0:
|
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.')
|
'for the clay fraction.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if bulk_density < 0:
|
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.')
|
'for the bulk density.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if sand_density < 0:
|
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.')
|
'for the sand particle density.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if water_fraction_lower < 0:
|
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 '
|
'for the lower limit of the water volumetric '
|
||||||
'fraction.')
|
'fraction.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if water_fraction_upper < 0:
|
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 '
|
'for the upper limit of the water volumetric '
|
||||||
'fraction.')
|
'fraction.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if any(x.ID == ID for x in grid.mixingmodels):
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Create a new instance of the Material class material
|
# 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,
|
s = PeplinskiSoilUser(ID, sand_fraction, clay_fraction, bulk_density,
|
||||||
sand_density, (water_fraction_lower, water_fraction_upper))
|
sand_density, (water_fraction_lower, water_fraction_upper))
|
||||||
|
|
||||||
logger.info(self.grid_name(grid) + 'Mixing model (Peplinski) used to '
|
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'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'{s.C:g}, bulk density {s.rb:g}g/cm3, sand particle ' +
|
||||||
f'density {s.rs:g}g/cm3, and water volumetric fraction '
|
f'density {s.rs:g}g/cm3, and water volumetric fraction ' +
|
||||||
f'{s.mu[0]:g} to {s.mu[1]:g} created.')
|
f'{s.mu[0]:g} to {s.mu[1]:g} created.')
|
||||||
|
|
||||||
grid.mixingmodels.append(s)
|
grid.mixingmodels.append(s)
|
||||||
@@ -1474,56 +1431,57 @@ class MaterialRange(UserObjectMulti):
|
|||||||
ro_upper = self.kwargs['ro_upper']
|
ro_upper = self.kwargs['ro_upper']
|
||||||
ID = self.kwargs['id']
|
ID = self.kwargs['id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires at exactly nine '
|
logger.exception(f'{self.params_str()} requires at exactly nine ' +
|
||||||
'parameters.')
|
'parameters.')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if er_lower < 1:
|
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.')
|
'for the lower range of relative permittivity.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if mr_lower < 1:
|
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.')
|
'for the lower range of relative magnetic permeability.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if sigma_lower < 0:
|
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.')
|
'for the lower limit of conductivity.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if ro_lower < 0:
|
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.')
|
'for the lower range magnetic loss.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if er_upper < 1:
|
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.')
|
'for the upper range of relative permittivity.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
if mr_upper < 1:
|
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')
|
'for the upper range of relative magnetic permeability')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
if sigma_upper < 0:
|
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.')
|
'for the upper range of conductivity.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if ro_upper < 0:
|
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.')
|
'for the upper range of magnetic loss.')
|
||||||
|
|
||||||
|
|
||||||
if any(x.ID == ID for x in grid.mixingmodels):
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Create a new instance of the Material class material
|
# Create a new instance of the Material class material
|
||||||
# (start index after pec & free_space)
|
# (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 '
|
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'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.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')
|
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']
|
list_of_materials = self.kwargs['list_of_materials']
|
||||||
ID = self.kwargs['id']
|
ID = self.kwargs['id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires at at least 2 '
|
logger.exception(f'{self.params_str()} requires at at least 2 ' +
|
||||||
'parameters.')
|
'parameters.')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
if any(x.ID == ID for x in grid.mixingmodels):
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Create a new instance of the Material class material
|
# Create a new instance of the Material class material
|
||||||
# (start index after pec & free_space)
|
# (start index after pec & free_space)
|
||||||
s = ListMaterialUser(ID, list_of_materials)
|
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')
|
f'create {s.ID} that includes {s.mat}, created')
|
||||||
|
|
||||||
|
|
||||||
grid.mixingmodels.append(s)
|
grid.mixingmodels.append(s)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GeometryView(UserObjectMulti):
|
class GeometryView(UserObjectMulti):
|
||||||
"""Outputs to file(s) information about the geometry (mesh) of model.
|
"""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()
|
output_type = self.kwargs['output_type'].lower()
|
||||||
filename = self.kwargs['filename']
|
filename = self.kwargs['filename']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires exactly eleven '
|
logger.exception(f'{self.params_str()} requires exactly eleven ' +
|
||||||
'parameters.')
|
'parameters.')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@@ -1624,45 +1580,44 @@ class GeometryView(UserObjectMulti):
|
|||||||
p4 = uip.round_to_grid_static_point(p2)
|
p4 = uip.round_to_grid_static_point(p2)
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.params_str())
|
p1, p2 = uip.check_box_points(p1, p2, self.params_str())
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.exception(self.params_str() + ' point is outside the domain.')
|
logger.exception(f'{self.params_str()} point is outside the domain.')
|
||||||
raise
|
raise
|
||||||
xs, ys, zs = p1
|
xs, ys, zs = p1
|
||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
dx, dy, dz = uip.discretise_static_point(dl)
|
dx, dy, dz = uip.discretise_static_point(dl)
|
||||||
|
|
||||||
|
|
||||||
if dx < 0 or dy < 0 or dz < 0:
|
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.')
|
'less than zero.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if dx > grid.nx or dy > grid.ny or dz > grid.nz:
|
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.')
|
'less than the domain size.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if dx < 1 or dy < 1 or dz < 1:
|
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.')
|
'be less than the spatial discretisation.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if output_type != 'n' and output_type != 'f':
|
if output_type not in ['n', 'f']:
|
||||||
logger.exception(self.params_str() + ' requires type to be either '
|
logger.exception(f'{self.params_str()} requires type to be either ' +
|
||||||
'n (normal) or f (fine).')
|
'n (normal) or f (fine).')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if output_type == 'f' and (dx * grid.dx != grid.dx or
|
if output_type == 'f' and (dx * grid.dx != grid.dx or
|
||||||
dy * grid.dy != grid.dy or
|
dy * grid.dy != grid.dy or
|
||||||
dz * grid.dz != grid.dz):
|
dz * grid.dz != grid.dz):
|
||||||
logger.exception(self.params_str() + ' requires the spatial '
|
logger.exception(f'{self.params_str()} requires the spatial ' +
|
||||||
'discretisation for the geometry view to be the '
|
'discretisation for the geometry view to be the ' +
|
||||||
'same as the model for geometry view of '
|
'same as the model for geometry view of ' +
|
||||||
'type f (fine)')
|
'type f (fine)')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
g = GeometryViewUser(xs, ys, zs, xf, yf, zf, dx, dy, dz, filename, grid)
|
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, '
|
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'{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'{p4[2]:g}m, discretisation {dx * grid.dx:g}m, ' +
|
||||||
f'{dy * grid.dy:g}m, {dz * grid.dz:g}m, with filename '
|
f'{dy * grid.dy:g}m, {dz * grid.dz:g}m, with filename ' +
|
||||||
f'base {g.filename} created.')
|
f'base {g.filename} created.')
|
||||||
|
|
||||||
grid.geometryviews.append(g)
|
grid.geometryviews.append(g)
|
||||||
@@ -1692,7 +1647,7 @@ class GeometryObjectsWrite(UserObjectMulti):
|
|||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
basefilename = self.kwargs['filename']
|
basefilename = self.kwargs['filename']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires exactly seven '
|
logger.exception(f'{self.params_str()} requires exactly seven ' +
|
||||||
'parameters.')
|
'parameters.')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@@ -1756,30 +1711,30 @@ class PMLCFS(UserObjectMulti):
|
|||||||
sigmamin = self.kwargs['sigmamin']
|
sigmamin = self.kwargs['sigmamin']
|
||||||
sigmamax = self.kwargs['sigmamax']
|
sigmamax = self.kwargs['sigmamax']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.params_str() + ' requires exactly twelve '
|
logger.exception(f'{self.params_str()} requires exactly twelve ' +
|
||||||
'parameters.')
|
'parameters.')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if (alphascalingprofile not in CFSParameter.scalingprofiles.keys() or
|
if (alphascalingprofile not in CFSParameter.scalingprofiles.keys() or
|
||||||
kappascalingprofile not in CFSParameter.scalingprofiles.keys() or
|
kappascalingprofile not in CFSParameter.scalingprofiles.keys() or
|
||||||
sigmascalingprofile not in CFSParameter.scalingprofiles.keys()):
|
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())}")
|
f"{','.join(CFSParameter.scalingprofiles.keys())}")
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if (alphascalingdirection not in CFSParameter.scalingdirections or
|
if (alphascalingdirection not in CFSParameter.scalingdirections or
|
||||||
kappascalingdirection not in CFSParameter.scalingdirections or
|
kappascalingdirection not in CFSParameter.scalingdirections or
|
||||||
sigmascalingdirection not in CFSParameter.scalingdirections):
|
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)}")
|
f"{','.join(CFSParameter.scalingdirections)}")
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if (float(alphamin) < 0 or float(alphamax) < 0 or
|
if (float(alphamin) < 0 or float(alphamax) < 0 or
|
||||||
float(kappamin) < 0 or float(kappamax) < 0 or float(sigmamin) < 0):
|
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.')
|
'values must be greater than zero.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
# TODO: Fix handling of kappa for 2nd order PMLs
|
# TODO: Fix handling of kappa for 2nd order PMLs
|
||||||
# if float(kappamin) < 1:
|
# 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.')
|
# 'kappa must be greater than or equal to one.')
|
||||||
# raise ValueError
|
# raise ValueError
|
||||||
|
|
||||||
@@ -1819,7 +1774,7 @@ class PMLCFS(UserObjectMulti):
|
|||||||
grid.pmls['cfs'].append(cfs)
|
grid.pmls['cfs'].append(cfs)
|
||||||
|
|
||||||
if len(grid.pmls['cfs']) > 2:
|
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.')
|
'times, for up to a 2nd order PML.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
|
@@ -93,20 +93,20 @@ class Discretisation(UserObjectSingle):
|
|||||||
G.dl = np.array(self.kwargs['p1'])
|
G.dl = np.array(self.kwargs['p1'])
|
||||||
G.dx, G.dy, G.dz = self.kwargs['p1']
|
G.dx, G.dy, G.dz = self.kwargs['p1']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' discretisation requires a point')
|
logger.exception(f'{self.__str__()} discretisation requires a point')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if G.dl[0] <= 0:
|
if G.dl[0] <= 0:
|
||||||
logger.exception(self.__str__() + ' discretisation requires the ' +
|
logger.exception(f'{self.__str__()} discretisation requires the '
|
||||||
'x-direction spatial step to be greater than zero')
|
f'x-direction spatial step to be greater than zero')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if G.dl[1] <= 0:
|
if G.dl[1] <= 0:
|
||||||
logger.exception(self.__str__() + ' discretisation requires the ' +
|
logger.exception(f'{self.__str__()} discretisation requires the '
|
||||||
'y-direction spatial step to be greater than zero')
|
f'y-direction spatial step to be greater than zero')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if G.dl[2] <= 0:
|
if G.dl[2] <= 0:
|
||||||
logger.exception(self.__str__() + ' discretisation requires the ' +
|
logger.exception(f'{self.__str__()} discretisation requires the '
|
||||||
'z-direction spatial step to be greater than zero')
|
f'z-direction spatial step to be greater than zero')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
logger.info(f'Spatial discretisation: {G.dl[0]:g} x {G.dl[1]:g} x {G.dl[2]:g}m')
|
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:
|
try:
|
||||||
G.nx, G.ny, G.nz = uip.discretise_point(self.kwargs['p1'])
|
G.nx, G.ny, G.nz = uip.discretise_point(self.kwargs['p1'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' please specify a point')
|
logger.exception(f'{self.__str__()} please specify a point')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if G.nx == 0 or G.ny == 0 or G.nz == 0:
|
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
|
raise ValueError
|
||||||
|
|
||||||
logger.info(f"Domain size: {self.kwargs['p1'][0]:g} x {self.kwargs['p1'][1]:g} x " +
|
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:
|
try:
|
||||||
f = self.kwargs['f']
|
f = self.kwargs['f']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' requires exactly one parameter')
|
logger.exception(f'{self.__str__()} requires exactly one parameter')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if f <= 0 or f > 1:
|
if f <= 0 or f > 1:
|
||||||
logger.exception(self.__str__() + ' requires the value of the time ' +
|
logger.exception(f'{self.__str__()} requires the value of the time '
|
||||||
'step stability factor to be between zero and one')
|
f'step stability factor to be between zero and one')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
G.dt = G.dt * f
|
G.dt = G.dt * f
|
||||||
|
|
||||||
@@ -250,12 +251,12 @@ class OMPThreads(UserObjectSingle):
|
|||||||
try:
|
try:
|
||||||
n = self.kwargs['n']
|
n = self.kwargs['n']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' requires exactly one parameter ' +
|
logger.exception(f'{self.__str__()} requires exactly one parameter '
|
||||||
'to specify the number of CPU OpenMP threads to use')
|
f'to specify the number of CPU OpenMP threads to use')
|
||||||
raise
|
raise
|
||||||
if n < 1:
|
if n < 1:
|
||||||
logger.exception(self.__str__() + ' requires the value to be an ' +
|
logger.exception(f'{self.__str__()} requires the value to be an '
|
||||||
'integer not less than one')
|
f'integer not less than one')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
config.get_model_config().ompthreads = set_omp_threads(n)
|
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']['ymax'] = int(self.kwargs['ymax'])
|
||||||
G.pmls['thickness']['zmax'] = int(self.kwargs['zmax'])
|
G.pmls['thickness']['zmax'] = int(self.kwargs['zmax'])
|
||||||
except KeyError:
|
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
|
raise
|
||||||
|
|
||||||
if (2 * G.pmls['thickness']['x0'] >= G.nx or
|
if (2 * G.pmls['thickness']['x0'] >= G.nx or
|
||||||
@@ -311,7 +312,7 @@ class PMLProps(UserObjectSingle):
|
|||||||
2 * G.pmls['thickness']['xmax'] >= G.nx or
|
2 * G.pmls['thickness']['xmax'] >= G.nx or
|
||||||
2 * G.pmls['thickness']['ymax'] >= G.ny or
|
2 * G.pmls['thickness']['ymax'] >= G.ny or
|
||||||
2 * G.pmls['thickness']['zmax'] >= G.nz):
|
2 * G.pmls['thickness']['zmax'] >= G.nz):
|
||||||
logger.exception(self.__str__() + ' has too many cells for the domain size')
|
logger.exception(f'{self.__str__()} has too many cells for the domain size')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
|
|
||||||
@@ -330,12 +331,12 @@ class SrcSteps(UserObjectSingle):
|
|||||||
try:
|
try:
|
||||||
G.srcsteps = uip.discretise_point(self.kwargs['p1'])
|
G.srcsteps = uip.discretise_point(self.kwargs['p1'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' requires exactly three parameters')
|
logger.exception(f'{self.__str__()} requires exactly three parameters')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
logger.info(f'Simple sources will step {G.srcsteps[0] * G.dx:g}m, ' +
|
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'{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):
|
class RxSteps(UserObjectSingle):
|
||||||
@@ -353,12 +354,12 @@ class RxSteps(UserObjectSingle):
|
|||||||
try:
|
try:
|
||||||
G.rxsteps = uip.discretise_point(self.kwargs['p1'])
|
G.rxsteps = uip.discretise_point(self.kwargs['p1'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception(self.__str__() + ' requires exactly three parameters')
|
logger.exception(f'{self.__str__()} requires exactly three parameters')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
logger.info(f'All receivers will step {G.rxsteps[0] * G.dx:g}m, ' +
|
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'{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):
|
class ExcitationFile(UserObjectSingle):
|
||||||
@@ -378,7 +379,7 @@ class ExcitationFile(UserObjectSingle):
|
|||||||
|
|
||||||
def create(self, G, uip):
|
def create(self, G, uip):
|
||||||
try:
|
try:
|
||||||
kwargs = dict()
|
kwargs = {}
|
||||||
excitationfile = self.kwargs['filepath']
|
excitationfile = self.kwargs['filepath']
|
||||||
kwargs['kind'] = self.kwargs['kind']
|
kwargs['kind'] = self.kwargs['kind']
|
||||||
kwargs['fill_value'] = self.kwargs['fill_value']
|
kwargs['fill_value'] = self.kwargs['fill_value']
|
||||||
@@ -389,7 +390,7 @@ class ExcitationFile(UserObjectSingle):
|
|||||||
args, varargs, keywords, defaults = inspect.getargspec(interpolate.interp1d)
|
args, varargs, keywords, defaults = inspect.getargspec(interpolate.interp1d)
|
||||||
kwargs = dict(zip(reversed(args), reversed(defaults)))
|
kwargs = dict(zip(reversed(args), reversed(defaults)))
|
||||||
except KeyError:
|
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
|
raise
|
||||||
|
|
||||||
# See if file exists at specified path and if not try input file directory
|
# See if file exists at specified path and if not try input file directory
|
||||||
|
@@ -224,14 +224,14 @@ class SimulationConfig:
|
|||||||
# solver: cpu, cuda, opencl.
|
# solver: cpu, cuda, opencl.
|
||||||
# subgrid: whether the simulation uses sub-grids.
|
# subgrid: whether the simulation uses sub-grids.
|
||||||
# precision: data type for electromagnetic field output (single/double).
|
# 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',
|
self.general = {'solver': 'cpu',
|
||||||
'subgrid': False,
|
'subgrid': False,
|
||||||
'precision': 'single'}
|
'precision': 'single',
|
||||||
|
'progressbars': args.log_level <= 20}
|
||||||
# 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
|
|
||||||
|
|
||||||
self.em_consts = {'c': c, # Speed of light in free space (m/s)
|
self.em_consts = {'c': c, # Speed of light in free space (m/s)
|
||||||
'e0': e0, # Permittivity of free space (F/m)
|
'e0': e0, # Permittivity of free space (F/m)
|
||||||
@@ -289,7 +289,6 @@ class SimulationConfig:
|
|||||||
|
|
||||||
# Set more complex parameters
|
# Set more complex parameters
|
||||||
self._set_precision()
|
self._set_precision()
|
||||||
self._get_byteorder()
|
|
||||||
self._set_input_file_path()
|
self._set_input_file_path()
|
||||||
self._set_model_start_end()
|
self._set_model_start_end()
|
||||||
|
|
||||||
@@ -348,12 +347,6 @@ class SimulationConfig:
|
|||||||
elif self.general['solver'] == 'opencl':
|
elif self.general['solver'] == 'opencl':
|
||||||
self.dtypes['C_complex'] = 'cdouble'
|
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):
|
def _set_model_start_end(self):
|
||||||
"""Sets range for number of models to run (internally 0 index)."""
|
"""Sets range for number of models to run (internally 0 index)."""
|
||||||
if self.args.i:
|
if self.args.i:
|
||||||
|
@@ -92,7 +92,7 @@ class Context:
|
|||||||
|
|
||||||
def print_logo_copyright(self):
|
def print_logo_copyright(self):
|
||||||
"""Prints gprMax logo, version, and copyright/licencing information."""
|
"""Prints gprMax logo, version, and copyright/licencing information."""
|
||||||
logo_copyright = logo(__version__ + ' (' + codename + ')')
|
logo_copyright = logo(f'{__version__} ({codename})')
|
||||||
logger.basic(logo_copyright)
|
logger.basic(logo_copyright)
|
||||||
|
|
||||||
def print_sim_time_taken(self):
|
def print_sim_time_taken(self):
|
||||||
@@ -164,19 +164,15 @@ class MPIContext(Context):
|
|||||||
executor = self.MPIExecutor(self._run_model, comm=self.comm)
|
executor = self.MPIExecutor(self._run_model, comm=self.comm)
|
||||||
|
|
||||||
# Check GPU resources versus number of MPI tasks
|
# Check GPU resources versus number of MPI tasks
|
||||||
if executor.is_master():
|
if (executor.is_master() and
|
||||||
if config.sim_config.general['solver'] == 'cuda':
|
config.sim_config.general['solver'] == 'cuda' and
|
||||||
if executor.size - 1 > len(config.sim_config.devices['devs']):
|
executor.size - 1 > len(config.sim_config.devices['devs'])):
|
||||||
logger.exception('Not enough GPU resources for number of '
|
logger.exception('Not enough GPU resources for number of '
|
||||||
'MPI tasks requested. Number of MPI tasks '
|
'MPI tasks requested. Number of MPI tasks '
|
||||||
'should be equal to number of GPUs + 1.')
|
'should be equal to number of GPUs + 1.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
# Create job list
|
jobs = [{'i': i} for i in self.model_range]
|
||||||
jobs = []
|
|
||||||
for i in self.model_range:
|
|
||||||
jobs.append({'i': i})
|
|
||||||
|
|
||||||
# Send the workers to their work loop
|
# Send the workers to their work loop
|
||||||
executor.start()
|
executor.start()
|
||||||
if executor.is_master():
|
if executor.is_master():
|
||||||
|
70
gprMax/cython/pml_build.pyx
普通文件
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
|
# Write meta data and data for any subgrids
|
||||||
if sg_rxs:
|
if sg_rxs:
|
||||||
for sg in G.subgrids:
|
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)
|
write_hd5_data(grp, sg, is_subgrid=True)
|
||||||
|
|
||||||
if G.rxs or sg_rxs:
|
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
|
# Create group for sources (except transmission lines); add type and positional data attributes
|
||||||
srclist = G.voltagesources + G.hertziandipoles + G.magneticdipoles
|
srclist = G.voltagesources + G.hertziandipoles + G.magneticdipoles
|
||||||
for srcindex, src in enumerate(srclist):
|
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['Type'] = type(src).__name__
|
||||||
grp.attrs['Position'] = (src.xcoord * G.dx, src.ycoord * G.dy, src.zcoord * G.dz)
|
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 for Paraview macro
|
||||||
comments = {}
|
comments = {'gprMax_version': __version__,
|
||||||
|
'dx_dy_dz': self.dx_dy_dz_comment(),
|
||||||
comments['gprMax_version'] = __version__
|
'nx_ny_nz': self.nx_ny_nz_comment(),
|
||||||
comments['dx_dy_dz'] = self.dx_dy_dz_comment()
|
'Materials': self.materials_comment()} # Write the name and numeric ID for each material
|
||||||
comments['nx_ny_nz'] = self.nx_ny_nz_comment()
|
|
||||||
|
|
||||||
# Write the name and numeric ID for each material
|
|
||||||
comments['Materials'] = self.materials_comment()
|
|
||||||
|
|
||||||
# Write information on PMLs, sources, and receivers
|
# Write information on PMLs, sources, and receivers
|
||||||
if not self.materials_only:
|
if not self.materials_only:
|
||||||
@@ -345,7 +341,7 @@ class Comments():
|
|||||||
|
|
||||||
def materials_comment(self):
|
def materials_comment(self):
|
||||||
if not self.averaged_materials:
|
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:
|
else:
|
||||||
return [m.ID for m in self.grid.materials]
|
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
|
parts = config.sim_config.input_file_path.with_suffix('').parts
|
||||||
self.filename_hdf5 = Path(*parts[:-1], self.basefilename)
|
self.filename_hdf5 = Path(*parts[:-1], self.basefilename)
|
||||||
self.filename_hdf5 = self.filename_hdf5.with_suffix('.h5')
|
self.filename_hdf5 = self.filename_hdf5.with_suffix('.h5')
|
||||||
self.filename_materials = Path(
|
self.filename_materials = Path(*parts[:-1], f'{self.basefilename}_materials')
|
||||||
*parts[:-1], self.basefilename + '_materials')
|
|
||||||
self.filename_materials = self.filename_materials.with_suffix('.txt')
|
self.filename_materials = self.filename_materials.with_suffix('.txt')
|
||||||
|
|
||||||
# Sizes of arrays to write necessary to update progress bar
|
# Sizes of arrays to write necessary to update progress bar
|
||||||
|
@@ -178,8 +178,8 @@ def write_processed_file(processedlines):
|
|||||||
for item in processedlines:
|
for item in processedlines:
|
||||||
f.write(f'{item}')
|
f.write(f'{item}')
|
||||||
|
|
||||||
logger.info(f'Written input commands, after processing any Python code and ' +
|
logger.info(f'Written input commands, after processing any Python ' +
|
||||||
f'include commands, to file: {processedfile}\n')
|
f'code and include commands, to file: {processedfile}\n')
|
||||||
|
|
||||||
|
|
||||||
def check_cmd_names(processedlines, checkessential=True):
|
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
|
# - these will be lists within the dictionary
|
||||||
multiplecmds = {key: [] for key in ['#geometry_view',
|
multiplecmds = {key: [] for key in ['#geometry_view',
|
||||||
'#geometry_objects_write', '#material',
|
'#geometry_objects_write', '#material',
|
||||||
|
'#material_range', '#material_list',
|
||||||
'#soil_peplinski',
|
'#soil_peplinski',
|
||||||
'#add_dispersion_debye',
|
'#add_dispersion_debye',
|
||||||
'#add_dispersion_lorentz',
|
'#add_dispersion_lorentz',
|
||||||
@@ -219,14 +220,14 @@ def check_cmd_names(processedlines, checkessential=True):
|
|||||||
'#waveform', '#voltage_source',
|
'#waveform', '#voltage_source',
|
||||||
'#hertzian_dipole', '#magnetic_dipole',
|
'#hertzian_dipole', '#magnetic_dipole',
|
||||||
'#transmission_line', '#rx', '#rx_array',
|
'#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
|
# Geometry object building commands that there can be multiple instances
|
||||||
# of in a model - these will be lists within the dictionary
|
# of in a model - these will be lists within the dictionary
|
||||||
geometrycmds = ['#geometry_objects_read', '#edge', '#plate', '#triangle',
|
geometrycmds = ['#geometry_objects_read', '#edge', '#plate', '#triangle',
|
||||||
'#box', '#sphere', '#ellipsoid', '#cone', '#cylinder', '#cylindrical_sector',
|
'#box', '#sphere', '#ellipsoid', '#cone', '#cylinder',
|
||||||
'#fractal_box', '#add_surface_roughness',
|
'#cylindrical_sector', '#fractal_box',
|
||||||
'#add_surface_water', '#add_grass']
|
'#add_surface_roughness', '#add_surface_water', '#add_grass']
|
||||||
# List to store all geometry object commands in order from input file
|
# List to store all geometry object commands in order from input file
|
||||||
geometry = []
|
geometry = []
|
||||||
|
|
||||||
|
@@ -17,21 +17,22 @@
|
|||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from .cmds_geometry.add_grass import AddGrass
|
from .cmds_geometry.add_grass import AddGrass
|
||||||
from .cmds_geometry.add_surface_roughness import AddSurfaceRoughness
|
from .cmds_geometry.add_surface_roughness import AddSurfaceRoughness
|
||||||
from .cmds_geometry.add_surface_water import AddSurfaceWater
|
from .cmds_geometry.add_surface_water import AddSurfaceWater
|
||||||
from .cmds_geometry.box import Box
|
from .cmds_geometry.box import Box
|
||||||
from .cmds_geometry.cylinder import Cylinder
|
|
||||||
from .cmds_geometry.cone import Cone
|
from .cmds_geometry.cone import Cone
|
||||||
|
from .cmds_geometry.cylinder import Cylinder
|
||||||
from .cmds_geometry.cylindrical_sector import CylindricalSector
|
from .cmds_geometry.cylindrical_sector import CylindricalSector
|
||||||
from .cmds_geometry.edge import Edge
|
from .cmds_geometry.edge import Edge
|
||||||
|
from .cmds_geometry.ellipsoid import Ellipsoid
|
||||||
from .cmds_geometry.fractal_box import FractalBox
|
from .cmds_geometry.fractal_box import FractalBox
|
||||||
from .cmds_geometry.plate import Plate
|
from .cmds_geometry.plate import Plate
|
||||||
from .cmds_geometry.sphere import Sphere
|
from .cmds_geometry.sphere import Sphere
|
||||||
from .cmds_geometry.triangle import Triangle
|
from .cmds_geometry.triangle import Triangle
|
||||||
from .cmds_geometry.ellipsoid import Ellipsoid
|
|
||||||
from .utilities.utilities import round_value
|
from .utilities.utilities import round_value
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -76,7 +77,8 @@ def process_geometrycmds(geometry):
|
|||||||
tmp = object.split()
|
tmp = object.split()
|
||||||
|
|
||||||
if tmp[0] == '#geometry_objects_read:':
|
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:
|
if len(tmp) != 6:
|
||||||
logger.exception("'" + ' '.join(tmp) + "'" +
|
logger.exception("'" + ' '.join(tmp) + "'" +
|
||||||
@@ -219,7 +221,6 @@ def process_geometrycmds(geometry):
|
|||||||
|
|
||||||
scene_objects.append(cylinder)
|
scene_objects.append(cylinder)
|
||||||
|
|
||||||
|
|
||||||
elif tmp[0] == '#cone:':
|
elif tmp[0] == '#cone:':
|
||||||
if len(tmp) < 10:
|
if len(tmp) < 10:
|
||||||
logger.exception("'" + ' '.join(tmp) + "'" +
|
logger.exception("'" + ' '.join(tmp) + "'" +
|
||||||
@@ -252,7 +253,6 @@ def process_geometrycmds(geometry):
|
|||||||
|
|
||||||
scene_objects.append(cone)
|
scene_objects.append(cone)
|
||||||
|
|
||||||
|
|
||||||
elif tmp[0] == '#cylindrical_sector:':
|
elif tmp[0] == '#cylindrical_sector:':
|
||||||
if len(tmp) < 10:
|
if len(tmp) < 10:
|
||||||
logger.exception("'" + ' '.join(tmp) + "'" +
|
logger.exception("'" + ' '.join(tmp) + "'" +
|
||||||
@@ -331,7 +331,6 @@ def process_geometrycmds(geometry):
|
|||||||
|
|
||||||
scene_objects.append(sphere)
|
scene_objects.append(sphere)
|
||||||
|
|
||||||
|
|
||||||
elif tmp[0] == '#ellipsoid:':
|
elif tmp[0] == '#ellipsoid:':
|
||||||
if len(tmp) < 8:
|
if len(tmp) < 8:
|
||||||
logger.exception("'" + ' '.join(tmp) + "'" +
|
logger.exception("'" + ' '.join(tmp) + "'" +
|
||||||
@@ -345,17 +344,19 @@ def process_geometrycmds(geometry):
|
|||||||
|
|
||||||
# Isotropic case with no user specified averaging
|
# Isotropic case with no user specified averaging
|
||||||
if len(tmp) == 8:
|
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
|
# Isotropic case with user specified averaging
|
||||||
elif len(tmp) == 9:
|
elif len(tmp) == 9:
|
||||||
averaging = check_averaging(tmp[8].lower())
|
averaging = check_averaging(tmp[8].lower())
|
||||||
ellipsoid = Ellipsoid(p1=p1, xr=xr, yr=yr, zr=zr, material_id=tmp[7],
|
ellipsoid = Ellipsoid(p1=p1, xr=xr, yr=yr, zr=zr,
|
||||||
averaging=averaging)
|
material_id=tmp[7], averaging=averaging)
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(tmp) == 8:
|
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:
|
else:
|
||||||
logger.exception("'" + ' '.join(tmp) + "'" +
|
logger.exception("'" + ' '.join(tmp) + "'" +
|
||||||
@@ -364,8 +365,6 @@ def process_geometrycmds(geometry):
|
|||||||
|
|
||||||
scene_objects.append(ellipsoid)
|
scene_objects.append(ellipsoid)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
elif tmp[0] == '#fractal_box:':
|
elif tmp[0] == '#fractal_box:':
|
||||||
# Default is no dielectric smoothing for a fractal box
|
# Default is no dielectric smoothing for a fractal box
|
||||||
|
|
||||||
|
@@ -21,8 +21,9 @@ import logging
|
|||||||
from .cmds_multiuse import (AddDebyeDispersion, AddDrudeDispersion,
|
from .cmds_multiuse import (AddDebyeDispersion, AddDrudeDispersion,
|
||||||
AddLorentzDispersion, GeometryObjectsWrite,
|
AddLorentzDispersion, GeometryObjectsWrite,
|
||||||
GeometryView, HertzianDipole, MagneticDipole,
|
GeometryView, HertzianDipole, MagneticDipole,
|
||||||
Material, Rx, RxArray, Snapshot, SoilPeplinski,
|
Material, MaterialList, MaterialRange, Rx, RxArray,
|
||||||
TransmissionLine, VoltageSource, Waveform, MaterialRange, MaterialList)
|
Snapshot, SoilPeplinski, TransmissionLine,
|
||||||
|
VoltageSource, Waveform)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -362,7 +363,6 @@ def process_multicmds(multicmds):
|
|||||||
id=tmp[8])
|
id=tmp[8])
|
||||||
scene_objects.append(material_range)
|
scene_objects.append(material_range)
|
||||||
|
|
||||||
|
|
||||||
cmdname = '#material_list'
|
cmdname = '#material_list'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
@@ -375,14 +375,11 @@ def process_multicmds(multicmds):
|
|||||||
|
|
||||||
tokens = len(tmp)
|
tokens = len(tmp)
|
||||||
lmats = []
|
lmats = []
|
||||||
for iter in range(0,tokens-1):
|
for iter in range(tokens-1):
|
||||||
lmats.append(tmp[iter])
|
lmats.append(tmp[iter])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
material_list = MaterialList(list_of_materials=lmats,
|
material_list = MaterialList(list_of_materials=lmats,
|
||||||
id=tmp[tokens-1])
|
id=tmp[tokens-1])
|
||||||
scene_objects.append(material_list)
|
scene_objects.append(material_list)
|
||||||
|
|
||||||
|
|
||||||
return scene_objects
|
return scene_objects
|
@@ -55,8 +55,8 @@ def process_singlecmds(singlecmds):
|
|||||||
if singlecmds[cmd] is not None:
|
if singlecmds[cmd] is not None:
|
||||||
tmp = tuple(int(x) for x in singlecmds[cmd].split())
|
tmp = tuple(int(x) for x in singlecmds[cmd].split())
|
||||||
if len(tmp) != 1:
|
if len(tmp) != 1:
|
||||||
logger.exception(cmd + ' requires exactly one parameter to specify ' +
|
logger.exception(f'{cmd} requires exactly one parameter to specify ' +
|
||||||
'the number of CPU OpenMP threads to use')
|
f'the number of CPU OpenMP threads to use')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
omp_threads = OMPThreads(n=tmp[0])
|
omp_threads = OMPThreads(n=tmp[0])
|
||||||
@@ -66,7 +66,7 @@ def process_singlecmds(singlecmds):
|
|||||||
if singlecmds[cmd] is not None:
|
if singlecmds[cmd] is not None:
|
||||||
tmp = [float(x) for x in singlecmds[cmd].split()]
|
tmp = [float(x) for x in singlecmds[cmd].split()]
|
||||||
if len(tmp) != 3:
|
if len(tmp) != 3:
|
||||||
logger.exception(cmd + ' requires exactly three parameters')
|
logger.exception(f'{cmd} requires exactly three parameters')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
dl = (tmp[0], tmp[1], tmp[2])
|
dl = (tmp[0], tmp[1], tmp[2])
|
||||||
@@ -77,7 +77,7 @@ def process_singlecmds(singlecmds):
|
|||||||
if singlecmds[cmd] is not None:
|
if singlecmds[cmd] is not None:
|
||||||
tmp = [float(x) for x in singlecmds[cmd].split()]
|
tmp = [float(x) for x in singlecmds[cmd].split()]
|
||||||
if len(tmp) != 3:
|
if len(tmp) != 3:
|
||||||
logger.exception(cmd + ' requires exactly three parameters')
|
logger.exception(f'{cmd} requires exactly three parameters')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
p1 = (tmp[0], tmp[1], tmp[2])
|
p1 = (tmp[0], tmp[1], tmp[2])
|
||||||
@@ -94,8 +94,8 @@ def process_singlecmds(singlecmds):
|
|||||||
if singlecmds[cmd] is not None:
|
if singlecmds[cmd] is not None:
|
||||||
tmp = singlecmds[cmd].split()
|
tmp = singlecmds[cmd].split()
|
||||||
if len(tmp) != 1:
|
if len(tmp) != 1:
|
||||||
logger.exception(cmd + ' requires exactly one parameter to specify ' +
|
logger.exception(f'{cmd} requires exactly one parameter to specify the ' +
|
||||||
'the time window. Either in seconds or number of iterations.')
|
f'time window. Either in seconds or number of iterations.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
tmp = tmp[0].lower()
|
tmp = tmp[0].lower()
|
||||||
|
|
||||||
@@ -113,8 +113,8 @@ def process_singlecmds(singlecmds):
|
|||||||
cmd = '#pml_cells'
|
cmd = '#pml_cells'
|
||||||
if singlecmds[cmd] is not None:
|
if singlecmds[cmd] is not None:
|
||||||
tmp = singlecmds[cmd].split()
|
tmp = singlecmds[cmd].split()
|
||||||
if len(tmp) != 1 and len(tmp) != 6:
|
if len(tmp) not in [1, 6]:
|
||||||
logger.exception(cmd + ' requires either one or six parameter(s)')
|
logger.exception(f'{cmd} requires either one or six parameter(s)')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if len(tmp) == 1:
|
if len(tmp) == 1:
|
||||||
pml_cells = PMLProps(thickness=int(tmp[0]))
|
pml_cells = PMLProps(thickness=int(tmp[0]))
|
||||||
@@ -132,7 +132,7 @@ def process_singlecmds(singlecmds):
|
|||||||
if singlecmds[cmd] is not None:
|
if singlecmds[cmd] is not None:
|
||||||
tmp = singlecmds[cmd].split()
|
tmp = singlecmds[cmd].split()
|
||||||
if len(tmp) != 3:
|
if len(tmp) != 3:
|
||||||
logger.exception(cmd + ' requires exactly three parameters')
|
logger.exception(f'{cmd} requires exactly three parameters')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
p1 = (float(tmp[0]), float(tmp[1]), float(tmp[2]))
|
p1 = (float(tmp[0]), float(tmp[1]), float(tmp[2]))
|
||||||
@@ -143,7 +143,7 @@ def process_singlecmds(singlecmds):
|
|||||||
if singlecmds[cmd] is not None:
|
if singlecmds[cmd] is not None:
|
||||||
tmp = singlecmds[cmd].split()
|
tmp = singlecmds[cmd].split()
|
||||||
if len(tmp) != 3:
|
if len(tmp) != 3:
|
||||||
logger.exception(cmd + ' requires exactly three parameters')
|
logger.exception(f'{cmd} requires exactly three parameters')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
p1 = (float(tmp[0]), float(tmp[1]), float(tmp[2]))
|
p1 = (float(tmp[0]), float(tmp[1]), float(tmp[2]))
|
||||||
@@ -154,8 +154,8 @@ def process_singlecmds(singlecmds):
|
|||||||
cmd = '#excitation_file'
|
cmd = '#excitation_file'
|
||||||
if singlecmds[cmd] is not None:
|
if singlecmds[cmd] is not None:
|
||||||
tmp = singlecmds[cmd].split()
|
tmp = singlecmds[cmd].split()
|
||||||
if len(tmp) != 1 and len(tmp) != 3:
|
if len(tmp) not in [1, 3]:
|
||||||
logger.exception(cmd + ' requires either one or three parameter(s)')
|
logger.exception(f'{cmd} requires either one or three parameter(s)')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
if len(tmp) > 1:
|
if len(tmp) > 1:
|
||||||
|
@@ -215,77 +215,6 @@ class DispersiveMaterial(Material):
|
|||||||
return er
|
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:
|
class PeplinskiSoil:
|
||||||
"""Soil objects that are characterised according to a mixing model
|
"""Soil objects that are characterised according to a mixing model
|
||||||
by Peplinski (http://dx.doi.org/10.1109/36.387598).
|
by Peplinski (http://dx.doi.org/10.1109/36.387598).
|
||||||
@@ -356,7 +285,6 @@ class PeplinskiSoil:
|
|||||||
#mumaterials = mubins + (mubins[1] - mubins[0]) / 2
|
#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
|
# Create an iterator
|
||||||
muiter = np.nditer(mumaterials, flags=['c_index'])
|
muiter = np.nditer(mumaterials, flags=['c_index'])
|
||||||
while not muiter.finished:
|
while not muiter.finished:
|
||||||
@@ -399,7 +327,6 @@ class PeplinskiSoil:
|
|||||||
muiter.iternext()
|
muiter.iternext()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RangeMaterial:
|
class RangeMaterial:
|
||||||
"""Material objects defined by a given range of their parameters to be used for
|
"""Material objects defined by a given range of their parameters to be used for
|
||||||
factal spatial disttibutions.
|
factal spatial disttibutions.
|
||||||
@@ -425,7 +352,6 @@ class RangeMaterial:
|
|||||||
# and assume that all must be sequentially numbered. This allows for more general mixing models
|
# and assume that all must be sequentially numbered. This allows for more general mixing models
|
||||||
self.matID = []
|
self.matID = []
|
||||||
|
|
||||||
|
|
||||||
def calculate_properties(self, nbins, G):
|
def calculate_properties(self, nbins, G):
|
||||||
"""Calculates the specific properties of each of the materials.
|
"""Calculates the specific properties of each of the materials.
|
||||||
|
|
||||||
@@ -436,6 +362,7 @@ class RangeMaterial:
|
|||||||
|
|
||||||
# Generate a set of relative permittivity bins based on the given range
|
# Generate a set of relative permittivity bins based on the given range
|
||||||
erbins = np.linspace(self.er[0], self.er[1], nbins+1)
|
erbins = np.linspace(self.er[0], self.er[1], nbins+1)
|
||||||
|
|
||||||
# Generate a range of relative permittivity values the mid-point of
|
# Generate a range of relative permittivity values the mid-point of
|
||||||
# each bin to make materials from
|
# each bin to make materials from
|
||||||
#ermaterials = erbins + np.abs((erbins[1] - erbins[0])) / 2
|
#ermaterials = erbins + np.abs((erbins[1] - erbins[0])) / 2
|
||||||
@@ -443,6 +370,7 @@ class RangeMaterial:
|
|||||||
|
|
||||||
# Generate a set of conductivity bins based on the given range
|
# 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
|
# Generate a range of conductivity values the mid-point of
|
||||||
# each bin to make materials from
|
# each bin to make materials from
|
||||||
#sigmamaterials = sigmabins + (sigmabins[1] - sigmabins[0]) / 2
|
#sigmamaterials = sigmabins + (sigmabins[1] - sigmabins[0]) / 2
|
||||||
@@ -450,6 +378,7 @@ class RangeMaterial:
|
|||||||
|
|
||||||
# Generate a set of magnetic permeability bins based on the given range
|
# 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
|
# Generate a range of magnetic permeability values the mid-point of
|
||||||
# each bin to make materials from
|
# each bin to make materials from
|
||||||
#mumaterials = mubins + np.abs((mubins[1] - mubins[0])) / 2
|
#mumaterials = mubins + np.abs((mubins[1] - mubins[0])) / 2
|
||||||
@@ -457,29 +386,26 @@ class RangeMaterial:
|
|||||||
|
|
||||||
# Generate a set of magnetic loss bins based on the given range
|
# Generate a set of magnetic loss bins based on the given range
|
||||||
robins = np.linspace(self.ro[0], self.ro[1], nbins + 1)
|
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
|
# 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 = 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
|
# Iterate over the bins
|
||||||
for iter in np.arange(0,nbins):
|
for iter in np.arange(nbins):
|
||||||
|
|
||||||
# Relative permittivity
|
# Relative permittivity
|
||||||
er = ermaterials[iter]
|
er = ermaterials[iter]
|
||||||
|
|
||||||
# Effective conductivity
|
# Effective conductivity
|
||||||
se = sigmamaterials[iter]
|
se = sigmamaterials[iter]
|
||||||
|
# Magnetic permeability
|
||||||
# magnetic permeability
|
|
||||||
mr = mumaterials[iter]
|
mr = mumaterials[iter]
|
||||||
|
# Magnetic loss
|
||||||
# magnetic loss
|
|
||||||
sm = romaterials[iter]
|
sm = romaterials[iter]
|
||||||
|
|
||||||
# Check to see if the material already exists before creating a new one
|
# 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)
|
material = next((x for x in G.materials if x.ID == requiredID), None)
|
||||||
if iter == 0:
|
if iter == 0:
|
||||||
if material:
|
if material:
|
||||||
@@ -499,11 +425,10 @@ class RangeMaterial:
|
|||||||
self.matID.append(m.numID)
|
self.matID.append(m.numID)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ListMaterial:
|
class ListMaterial:
|
||||||
"""A list of predefined materials that are to be used for
|
"""A list of predefined materials to be used for
|
||||||
factal spatial disttibutions. No new materials are created but the ones specified are
|
factal spatial disttibutions. This command does not create new materials but collects them to be used in a
|
||||||
grouped together to be used in fractal spatial distributions.
|
stochastic distribution by a fractal box.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, ID, listofmaterials):
|
def __init__(self, ID, listofmaterials):
|
||||||
@@ -524,21 +449,18 @@ class ListMaterial:
|
|||||||
|
|
||||||
|
|
||||||
def calculate_properties(self, nbins, G):
|
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
|
"""Calculates the properties of the materials.
|
||||||
class that needs Debye
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
nbins: int for number of bins to use to create the different materials.
|
nbins: int for number of bins to use to create the different materials.
|
||||||
G: FDTDGrid class describing a grid in a model.
|
G: FDTDGrid class describing a grid in a model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
# Iterate over the bins
|
# Iterate over the bins
|
||||||
for iter in np.arange(0,nbins):
|
for iter in np.arange(nbins):
|
||||||
|
|
||||||
# Check to see if the material already exists before creating a new one
|
|
||||||
#requiredID = '|{:}_in_{:}|'.format((self.mat[iter]),(self.ID))
|
#requiredID = '|{:}_in_{:}|'.format((self.mat[iter]),(self.ID))
|
||||||
requiredID = self.mat[iter]
|
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)
|
material = next((x for x in G.materials if x.ID == requiredID), None)
|
||||||
self.matID.append(material.numID)
|
self.matID.append(material.numID)
|
||||||
|
|
||||||
@@ -555,15 +477,11 @@ class ListMaterial:
|
|||||||
# m.numID = len(G.materials)
|
# m.numID = len(G.materials)
|
||||||
# G.materials.append(m)
|
# G.materials.append(m)
|
||||||
|
|
||||||
|
|
||||||
if not material:
|
if not material:
|
||||||
logger.exception(self.__str__() + f' material(s) {material} do not exist')
|
logger.exception(self.__str__() + f' material(s) {material} do not exist')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_built_in_materials(G):
|
def create_built_in_materials(G):
|
||||||
"""Creates pre-defined (built-in) materials.
|
"""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: FDTDGrid class describing a grid in a model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
G.n_built_in_materials = len(G.materials)
|
|
||||||
|
|
||||||
m = Material(0, 'pec')
|
m = Material(0, 'pec')
|
||||||
m.se = float('inf')
|
m.se = float('inf')
|
||||||
m.type = 'builtin'
|
m.type = 'builtin'
|
||||||
@@ -583,8 +499,6 @@ def create_built_in_materials(G):
|
|||||||
m.type = 'builtin'
|
m.type = 'builtin'
|
||||||
G.materials.append(m)
|
G.materials.append(m)
|
||||||
|
|
||||||
G.n_built_in_materials = len(G.materials)
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_water_properties(T=25, S=0):
|
def calculate_water_properties(T=25, S=0):
|
||||||
"""Get extended Debye model properties for water.
|
"""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)
|
eri, er, tau, sig = calculate_water_properties(T, S)
|
||||||
|
|
||||||
G.n_built_in_materials = len(G.materials)
|
|
||||||
|
|
||||||
m = DispersiveMaterial(len(G.materials), 'water')
|
m = DispersiveMaterial(len(G.materials), 'water')
|
||||||
m.averagable = False
|
m.averagable = False
|
||||||
m.type = 'builtin, debye'
|
m.type = 'builtin, debye'
|
||||||
@@ -641,8 +553,6 @@ def create_water(G, T=25, S=0):
|
|||||||
if config.get_model_config().materials['maxpoles'] == 0:
|
if config.get_model_config().materials['maxpoles'] == 0:
|
||||||
config.get_model_config().materials['maxpoles'] = 1
|
config.get_model_config().materials['maxpoles'] = 1
|
||||||
|
|
||||||
G.n_built_in_materials = len(G.materials)
|
|
||||||
|
|
||||||
|
|
||||||
def create_grass(G):
|
def create_grass(G):
|
||||||
"""Creates single-pole Debye model for grass
|
"""Creates single-pole Debye model for grass
|
||||||
@@ -657,8 +567,6 @@ def create_grass(G):
|
|||||||
tau = 1.0793e-11
|
tau = 1.0793e-11
|
||||||
sig = 0
|
sig = 0
|
||||||
|
|
||||||
G.n_built_in_materials = len(G.materials)
|
|
||||||
|
|
||||||
m = DispersiveMaterial(len(G.materials), 'grass')
|
m = DispersiveMaterial(len(G.materials), 'grass')
|
||||||
m.averagable = False
|
m.averagable = False
|
||||||
m.type = 'builtin, debye'
|
m.type = 'builtin, debye'
|
||||||
@@ -671,4 +579,70 @@ def create_grass(G):
|
|||||||
if config.get_model_config().materials['maxpoles'] == 0:
|
if config.get_model_config().materials['maxpoles'] == 0:
|
||||||
config.get_model_config().materials['maxpoles'] = 1
|
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()
|
self.p = psutil.Process()
|
||||||
|
|
||||||
# Normal model reading/building process; bypassed if geometry information to be reused
|
# 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()}')
|
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
|
# Write files for any geometry views and geometry object outputs
|
||||||
gvs = G.geometryviews + [gv for sg in G.subgrids for gv in sg.geometryviews]
|
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.')
|
logger.exception('\nNo geometry views or geometry objects found.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
save_geometry_views(gvs)
|
save_geometry_views(gvs)
|
||||||
@@ -271,8 +271,7 @@ class ModelBuildRun:
|
|||||||
logger.warning(f"You have specified more threads ({config.get_model_config().ompthreads}) "
|
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"than available physical CPU cores ({config.sim_config.hostinfo['physicalcores']}). "
|
||||||
f"This may lead to degraded performance.")
|
f"This may lead to degraded performance.")
|
||||||
# Print information about any compute device, e.g. GPU, in use
|
elif config.sim_config.general['solver'] in ['cuda', 'opencl']:
|
||||||
elif config.sim_config.general['solver'] == 'cuda' or config.sim_config.general['solver'] == 'opencl':
|
|
||||||
if config.sim_config.general['solver'] == 'opencl':
|
if config.sim_config.general['solver'] == 'opencl':
|
||||||
solvername = 'OpenCL'
|
solvername = 'OpenCL'
|
||||||
platformname = ' on ' + ' '.join(config.get_model_config().device['dev'].platform.name.split())
|
platformname = ' on ' + ' '.join(config.get_model_config().device['dev'].platform.name.split())
|
||||||
@@ -338,11 +337,11 @@ class GridBuilder:
|
|||||||
pbar.close()
|
pbar.close()
|
||||||
|
|
||||||
def tm_grid_update(self):
|
def tm_grid_update(self):
|
||||||
if '2D TMx' == config.get_model_config().mode:
|
if config.get_model_config().mode == '2D TMx':
|
||||||
self.grid.tmx()
|
self.grid.tmx()
|
||||||
elif '2D TMy' == config.get_model_config().mode:
|
elif config.get_model_config().mode == '2D TMy':
|
||||||
self.grid.tmy()
|
self.grid.tmy()
|
||||||
elif '2D TMz' == config.get_model_config().mode:
|
elif config.get_model_config().mode == '2D TMz':
|
||||||
self.grid.tmz()
|
self.grid.tmz()
|
||||||
|
|
||||||
def update_voltage_source_materials(self):
|
def update_voltage_source_materials(self):
|
||||||
|
@@ -220,8 +220,8 @@ class MPIExecutor(object):
|
|||||||
|
|
||||||
def join(self):
|
def join(self):
|
||||||
"""Joins the workers."""
|
"""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.')
|
logger.debug(f'({self.comm.name}) - Terminating. Sending sentinel to all workers.')
|
||||||
# Send sentinel to all workers
|
# Send sentinel to all workers
|
||||||
for worker in self.workers:
|
for worker in self.workers:
|
||||||
|
@@ -22,6 +22,8 @@ import numpy as np
|
|||||||
|
|
||||||
import gprMax.config as config
|
import gprMax.config as config
|
||||||
|
|
||||||
|
from .cython.pml_build import pml_average_er_mr
|
||||||
|
|
||||||
|
|
||||||
class CFSParameter:
|
class CFSParameter:
|
||||||
"""Individual CFS parameter (e.g. alpha, kappa, or sigma)."""
|
"""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':
|
elif config.sim_config.general['solver'] == 'opencl':
|
||||||
pml_type = OpenCLPML
|
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[0] == 'x':
|
||||||
if key == 'x0':
|
if key == 'x0':
|
||||||
pml = pml_type(G, ID=key, direction='xminus',
|
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)
|
xs=G.nx - value, xf=G.nx, yf=G.ny, zf=G.nz)
|
||||||
pml.CFS = G.pmls['cfs']
|
pml.CFS = G.pmls['cfs']
|
||||||
G.pmls['slabs'].append(pml)
|
G.pmls['slabs'].append(pml)
|
||||||
for j in range(G.ny):
|
averageer, averagemr = pml_average_er_mr('x', pml.xs, G)
|
||||||
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)
|
|
||||||
|
|
||||||
elif key[0] == 'y':
|
elif key[0] == 'y':
|
||||||
if key == 'y0':
|
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)
|
ys=G.ny - value, xf=G.nx, yf=G.ny, zf=G.nz)
|
||||||
pml.CFS = G.pmls['cfs']
|
pml.CFS = G.pmls['cfs']
|
||||||
G.pmls['slabs'].append(pml)
|
G.pmls['slabs'].append(pml)
|
||||||
for i in range(G.nx):
|
averageer, averagemr = pml_average_er_mr('y', pml.ys, G)
|
||||||
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)
|
|
||||||
|
|
||||||
elif key[0] == 'z':
|
elif key[0] == 'z':
|
||||||
if key == 'z0':
|
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)
|
zs=G.nz - value, xf=G.nx, yf=G.ny, zf=G.nz)
|
||||||
pml.CFS = G.pmls['cfs']
|
pml.CFS = G.pmls['cfs']
|
||||||
G.pmls['slabs'].append(pml)
|
G.pmls['slabs'].append(pml)
|
||||||
for i in range(G.nx):
|
averageer, averagemr = pml_average_er_mr('z', pml.zs, G)
|
||||||
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)
|
|
||||||
|
|
||||||
pml.calculate_update_coeffs(averageer, averagemr)
|
pml.calculate_update_coeffs(averageer, averagemr)
|
||||||
|
@@ -105,7 +105,7 @@ class Scene:
|
|||||||
|
|
||||||
# Check essential commands and warn user if missing
|
# Check essential commands and warn user if missing
|
||||||
for cmd_type in self.essential_cmds:
|
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:
|
if not d:
|
||||||
logger.exception('Your input file is missing essential commands ' +
|
logger.exception('Your input file is missing essential commands ' +
|
||||||
'required to run a model. Essential commands ' +
|
'required to run a model. Essential commands ' +
|
||||||
|
@@ -96,7 +96,7 @@ class VoltageSource(Source):
|
|||||||
i = self.xcoord
|
i = self.xcoord
|
||||||
j = self.ycoord
|
j = self.ycoord
|
||||||
k = self.zcoord
|
k = self.zcoord
|
||||||
componentID = 'E' + self.polarisation
|
componentID = f'E{self.polarisation}'
|
||||||
|
|
||||||
if self.polarisation == 'x':
|
if self.polarisation == 'x':
|
||||||
if self.resistance != 0:
|
if self.resistance != 0:
|
||||||
@@ -130,16 +130,17 @@ class VoltageSource(Source):
|
|||||||
G: FDTDGrid class describing a grid in a model.
|
G: FDTDGrid class describing a grid in a model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.resistance != 0:
|
if self.resistance == 0:
|
||||||
|
return
|
||||||
i = self.xcoord
|
i = self.xcoord
|
||||||
j = self.ycoord
|
j = self.ycoord
|
||||||
k = self.zcoord
|
k = self.zcoord
|
||||||
|
|
||||||
componentID = 'E' + self.polarisation
|
componentID = f'E{self.polarisation}'
|
||||||
requirednumID = G.ID[G.IDlookup[componentID], i, j, k]
|
requirednumID = G.ID[G.IDlookup[componentID], i, j, k]
|
||||||
material = next(x for x in G.materials if x.numID == requirednumID)
|
material = next(x for x in G.materials if x.numID == requirednumID)
|
||||||
newmaterial = deepcopy(material)
|
newmaterial = deepcopy(material)
|
||||||
newmaterial.ID = material.ID + '+' + self.ID
|
newmaterial.ID = f'{material.ID}+{self.ID}'
|
||||||
newmaterial.numID = len(G.materials)
|
newmaterial.numID = len(G.materials)
|
||||||
newmaterial.averagable = False
|
newmaterial.averagable = False
|
||||||
newmaterial.type += ',\nvoltage-source' if newmaterial.type else 'voltage-source'
|
newmaterial.type += ',\nvoltage-source' if newmaterial.type else 'voltage-source'
|
||||||
@@ -180,7 +181,7 @@ class HertzianDipole(Source):
|
|||||||
i = self.xcoord
|
i = self.xcoord
|
||||||
j = self.ycoord
|
j = self.ycoord
|
||||||
k = self.zcoord
|
k = self.zcoord
|
||||||
componentID = 'E' + self.polarisation
|
componentID = f'E{self.polarisation}'
|
||||||
if self.polarisation == 'x':
|
if self.polarisation == 'x':
|
||||||
Ex[i, j, k] -= (updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] *
|
Ex[i, j, k] -= (updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] *
|
||||||
self.waveformvalues_halfdt[iteration] * self.dl *
|
self.waveformvalues_halfdt[iteration] * self.dl *
|
||||||
@@ -217,7 +218,7 @@ class MagneticDipole(Source):
|
|||||||
i = self.xcoord
|
i = self.xcoord
|
||||||
j = self.ycoord
|
j = self.ycoord
|
||||||
k = self.zcoord
|
k = self.zcoord
|
||||||
componentID = 'H' + self.polarisation
|
componentID = f'H{self.polarisation}'
|
||||||
|
|
||||||
if self.polarisation == 'x':
|
if self.polarisation == 'x':
|
||||||
Hx[i, j, k] -= (updatecoeffsH[ID[G.IDlookup[componentID], i, j, k], 4] *
|
Hx[i, j, k] -= (updatecoeffsH[ID[G.IDlookup[componentID], i, j, k], 4] *
|
||||||
|
@@ -174,7 +174,7 @@ class PrecursorNodesBase:
|
|||||||
|
|
||||||
for f in field_names:
|
for f in field_names:
|
||||||
try:
|
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:
|
except ValueError:
|
||||||
raise
|
raise
|
||||||
setattr(self, f, val)
|
setattr(self, f, val)
|
||||||
@@ -184,7 +184,7 @@ class PrecursorNodesBase:
|
|||||||
current main time step, i.e. ey_left = copy.ey_left_1
|
current main time step, i.e. ey_left = copy.ey_left_1
|
||||||
"""
|
"""
|
||||||
for f in field_names:
|
for f in field_names:
|
||||||
val = np.copy(getattr(self, f + '_1'))
|
val = np.copy(getattr(self, f'{f}_1'))
|
||||||
setattr(self, f, val)
|
setattr(self, f, val)
|
||||||
|
|
||||||
def calc_exact_magnetic_in_time(self):
|
def calc_exact_magnetic_in_time(self):
|
||||||
@@ -218,9 +218,9 @@ class PrecursorNodesBase:
|
|||||||
|
|
||||||
def update_previous_timestep_fields(self, field_names):
|
def update_previous_timestep_fields(self, field_names):
|
||||||
for fn in field_names:
|
for fn in field_names:
|
||||||
val = getattr(self, fn + '_1')
|
val = getattr(self, f'{fn}_1')
|
||||||
val_c = np.copy(val)
|
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):
|
def interpolate_to_sub_grid(self, field, coords):
|
||||||
x, z, x_sg, z_sg = coords
|
x, z, x_sg, z_sg = coords
|
||||||
|
@@ -33,10 +33,10 @@ def create_updates(G):
|
|||||||
sg_type = type(sg)
|
sg_type = type(sg)
|
||||||
if sg_type == SubGridHSG and sg.filter:
|
if sg_type == SubGridHSG and sg.filter:
|
||||||
precursors = PrecursorNodesFiltered(G, sg)
|
precursors = PrecursorNodesFiltered(G, sg)
|
||||||
elif sg_type == SubGridHSG and not sg.filter:
|
elif sg_type == SubGridHSG:
|
||||||
precursors = PrecursorNodes(G, sg)
|
precursors = PrecursorNodes(G, sg)
|
||||||
else:
|
else:
|
||||||
logger.exception(str(sg) + ' is not a subgrid type')
|
logger.exception(f'{str(sg)} is not a subgrid type')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
sgu = SubgridUpdater(sg, precursors, G)
|
sgu = SubgridUpdater(sg, precursors, G)
|
||||||
|
@@ -45,7 +45,7 @@ class SubGridBase(UserObjectMulti):
|
|||||||
elif isinstance(node, UserObjectGeometry):
|
elif isinstance(node, UserObjectGeometry):
|
||||||
self.children_geometry.append(node)
|
self.children_geometry.append(node)
|
||||||
else:
|
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
|
raise ValueError
|
||||||
|
|
||||||
def set_discretisation(self, sg, grid):
|
def set_discretisation(self, sg, grid):
|
||||||
@@ -123,12 +123,12 @@ class SubGridBase(UserObjectMulti):
|
|||||||
self.subgrid = sg
|
self.subgrid = sg
|
||||||
|
|
||||||
# Copy over built in materials
|
# 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
|
# Don't mix and match different subgrid types
|
||||||
for sg_made in grid.subgrids:
|
for sg_made in grid.subgrids:
|
||||||
if type(sg) != type(sg_made):
|
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
|
raise ValueError
|
||||||
|
|
||||||
# Reference the subgrid under the main grid to which it belongs
|
# Reference the subgrid under the main grid to which it belongs
|
||||||
|
@@ -378,7 +378,7 @@ class CUDAUpdates:
|
|||||||
for pml in self.grid.pmls['slabs']:
|
for pml in self.grid.pmls['slabs']:
|
||||||
pml.htod_field_arrays()
|
pml.htod_field_arrays()
|
||||||
pml.set_blocks_per_grid()
|
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
|
self.subs_name_args['FUNC'] = knl_name
|
||||||
|
|
||||||
knl_electric = getattr(knl_pml_updates_electric, knl_name)
|
knl_electric = getattr(knl_pml_updates_electric, knl_name)
|
||||||
@@ -880,21 +880,21 @@ class OpenCLUpdates:
|
|||||||
for pml in self.grid.pmls['slabs']:
|
for pml in self.grid.pmls['slabs']:
|
||||||
pml.set_queue(self.queue)
|
pml.set_queue(self.queue)
|
||||||
pml.htod_field_arrays()
|
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_electric_name = getattr(knl_pml_updates_electric, knl_name)
|
||||||
knl_magnetic_name = getattr(knl_pml_updates_magnetic, knl_name)
|
knl_magnetic_name = getattr(knl_pml_updates_magnetic, knl_name)
|
||||||
|
|
||||||
pml.update_electric_dev = self.elwise(self.ctx,
|
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['args_opencl'].substitute({'REAL': config.sim_config.dtypes['C_float_or_double']}),
|
||||||
knl_electric_name['func'].substitute(subs),
|
knl_electric_name['func'].substitute(subs),
|
||||||
'pml_updates_electric_' + knl_name,
|
f'pml_updates_electric_{knl_name}',
|
||||||
preamble=self.knl_common,
|
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,
|
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['args_opencl'].substitute({'REAL': config.sim_config.dtypes['C_float_or_double']}),
|
||||||
knl_magnetic_name['func'].substitute(subs),
|
knl_magnetic_name['func'].substitute(subs),
|
||||||
'pml_updates_magnetic_' + knl_name,
|
f'pml_updates_magnetic_{knl_name}',
|
||||||
preamble=self.knl_common,
|
preamble=self.knl_common,
|
||||||
options=config.sim_config.devices['compiler_opts'])
|
options=config.sim_config.devices['compiler_opts'])
|
||||||
|
|
||||||
|
@@ -65,7 +65,7 @@ class UserInput:
|
|||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
v = ['x', 'y', 'z']
|
v = ['x', 'y', 'z']
|
||||||
# Discretisation
|
# Discretisation
|
||||||
dl = getattr(self.grid, 'd' + err.args[0])
|
dl = getattr(self.grid, f'd{err.args[0]}')
|
||||||
# Incorrect index
|
# Incorrect index
|
||||||
i = p[v.index(err.args[0])]
|
i = p[v.index(err.args[0])]
|
||||||
if name:
|
if name:
|
||||||
|
@@ -515,7 +515,7 @@ def print_opencl_info(devs):
|
|||||||
if i == 0:
|
if i == 0:
|
||||||
platform = dev.platform.name
|
platform = dev.platform.name
|
||||||
logger.basic(f' |--->Platform: {platform}')
|
logger.basic(f' |--->Platform: {platform}')
|
||||||
if not platform == dev.platform.name:
|
if platform != dev.platform.name:
|
||||||
logger.basic(f' |--->Platform: {dev.platform.name}')
|
logger.basic(f' |--->Platform: {dev.platform.name}')
|
||||||
types = cl.device_type.to_string(dev.type)
|
types = cl.device_type.to_string(dev.type)
|
||||||
if 'CPU' in types:
|
if 'CPU' in types:
|
||||||
|
@@ -91,7 +91,7 @@ def logo(version):
|
|||||||
v""" + version + '\n\n'
|
v""" + version + '\n\n'
|
||||||
|
|
||||||
str = f"{description} {'=' * (get_terminal_width() - len(description) - 1)}\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,
|
str += Style.RESET_ALL + textwrap.fill(copyright,
|
||||||
width=get_terminal_width() - 1,
|
width=get_terminal_width() - 1,
|
||||||
initial_indent=' ') + '\n'
|
initial_indent=' ') + '\n'
|
||||||
|
@@ -54,18 +54,19 @@ class Waveform:
|
|||||||
waveforms.
|
waveforms.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if (self.type == 'gaussian' or self.type == 'gaussiandot' or
|
if self.type in ['gaussian',
|
||||||
self.type == 'gaussiandotnorm' or self.type == 'gaussianprime' or
|
'gaussiandot',
|
||||||
self.type == 'gaussiandoubleprime'):
|
'gaussiandotnorm',
|
||||||
|
'gaussianprime',
|
||||||
|
'gaussiandoubleprime']:
|
||||||
self.chi = 1 / self.freq
|
self.chi = 1 / self.freq
|
||||||
self.zeta = 2 * np.pi**2 * self.freq**2
|
self.zeta = 2 * np.pi**2 * self.freq**2
|
||||||
elif (self.type == 'gaussiandotdot' or
|
elif self.type in ['gaussiandotdot', 'gaussiandotdotnorm', 'ricker']:
|
||||||
self.type == 'gaussiandotdotnorm' or self.type == 'ricker'):
|
|
||||||
self.chi = np.sqrt(2) / self.freq
|
self.chi = np.sqrt(2) / self.freq
|
||||||
self.zeta = np.pi**2 * self.freq**2
|
self.zeta = np.pi**2 * self.freq**2
|
||||||
|
|
||||||
def calculate_value(self, time, dt):
|
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:
|
Args:
|
||||||
time: float for absolute time.
|
time: float for absolute time.
|
||||||
@@ -82,7 +83,7 @@ class Waveform:
|
|||||||
delay = time - self.chi
|
delay = time - self.chi
|
||||||
ampvalue = np.exp(-self.zeta * delay**2)
|
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
|
delay = time - self.chi
|
||||||
ampvalue = -2 * self.zeta * delay * np.exp(-self.zeta * delay**2)
|
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))
|
normalise = np.sqrt(np.exp(1) / (2 * self.zeta))
|
||||||
ampvalue = -2 * self.zeta * delay * np.exp(-self.zeta * delay**2) * normalise
|
ampvalue = -2 * self.zeta * delay * np.exp(-self.zeta * delay**2) * normalise
|
||||||
|
|
||||||
elif self.type == 'gaussiandotdot' or self.type == 'gaussiandoubleprime':
|
elif self.type in ['gaussiandotdot', 'gaussiandoubleprime']:
|
||||||
delay = time - self.chi
|
delay = time - self.chi
|
||||||
ampvalue = (2 * self.zeta * (2 * self.zeta * delay**2 - 1) *
|
ampvalue = (2 * self.zeta * (2 * self.zeta * delay**2 - 1) *
|
||||||
np.exp(-self.zeta * delay**2))
|
np.exp(-self.zeta * delay**2))
|
||||||
@@ -116,8 +117,8 @@ class Waveform:
|
|||||||
elif self.type == 'contsine':
|
elif self.type == 'contsine':
|
||||||
rampamp = 0.25
|
rampamp = 0.25
|
||||||
ramp = rampamp * time * self.freq
|
ramp = rampamp * time * self.freq
|
||||||
if ramp > 1:
|
ramp = min(ramp, 1)
|
||||||
ramp = 1
|
|
||||||
ampvalue = ramp * np.sin(2 * np.pi * self.freq * time)
|
ampvalue = ramp * np.sin(2 * np.pi * self.freq * time)
|
||||||
|
|
||||||
elif self.type == 'impulse':
|
elif self.type == 'impulse':
|
||||||
|
38
setup.py
38
setup.py
@@ -37,8 +37,9 @@ if sys.version_info[:2] < MIN_PYTHON_VERSION:
|
|||||||
|
|
||||||
# Importing gprMax _version__.py before building can cause issues.
|
# Importing gprMax _version__.py before building can cause issues.
|
||||||
with open('gprMax/_version.py', 'r') as fd:
|
with open('gprMax/_version.py', 'r') as fd:
|
||||||
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
|
version = re.search(
|
||||||
fd.read(), re.MULTILINE).group(1)
|
r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE
|
||||||
|
)[1]
|
||||||
|
|
||||||
def build_dispersive_material_templates():
|
def build_dispersive_material_templates():
|
||||||
"""Function to generate Cython .pyx file for dispersive media update.
|
"""Function to generate Cython .pyx file for dispersive media update.
|
||||||
@@ -46,7 +47,7 @@ def build_dispersive_material_templates():
|
|||||||
functions.
|
functions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
iswin = True if sys.platform == 'win32' else False
|
iswin = (sys.platform == 'win32')
|
||||||
|
|
||||||
env = Environment(loader = FileSystemLoader(os.path.join('gprMax', 'cython')), )
|
env = Environment(loader = FileSystemLoader(os.path.join('gprMax', 'cython')), )
|
||||||
|
|
||||||
@@ -133,12 +134,12 @@ if 'cleanall' in sys.argv:
|
|||||||
for file in cythonfiles:
|
for file in cythonfiles:
|
||||||
filebase = os.path.splitext(file)[0]
|
filebase = os.path.splitext(file)[0]
|
||||||
# Remove Cython C files
|
# Remove Cython C files
|
||||||
if os.path.isfile(filebase + '.c'):
|
if os.path.isfile(f'{filebase}.c'):
|
||||||
try:
|
try:
|
||||||
os.remove(filebase + '.c')
|
os.remove(f'{filebase}.c')
|
||||||
print(f'Removed: {filebase + ".c"}')
|
print(f'Removed: {filebase}.c')
|
||||||
except OSError:
|
except OSError:
|
||||||
print(f'Could not remove: {filebase + ".c"}')
|
print(f'Could not remove: {filebase}.c')
|
||||||
# Remove compiled Cython modules
|
# Remove compiled Cython modules
|
||||||
libfile = (glob.glob(os.path.join(os.getcwd(),
|
libfile = (glob.glob(os.path.join(os.getcwd(),
|
||||||
os.path.splitext(file)[0]) + '*.pyd') +
|
os.path.splitext(file)[0]) + '*.pyd') +
|
||||||
@@ -176,10 +177,6 @@ else:
|
|||||||
linker_args = []
|
linker_args = []
|
||||||
libraries = []
|
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':
|
elif sys.platform == 'darwin':
|
||||||
# Check for Intel or Apple M series CPU
|
# Check for Intel or Apple M series CPU
|
||||||
cpuID = subprocess.check_output("sysctl -n machdep.cpu.brand_string",
|
cpuID = subprocess.check_output("sysctl -n machdep.cpu.brand_string",
|
||||||
@@ -219,12 +216,14 @@ else:
|
|||||||
pass
|
pass
|
||||||
os.environ['MIN_SUPPORTED_MACOSX_DEPLOYMENT_TARGET'] = MIN_MACOS_VERSION
|
os.environ['MIN_SUPPORTED_MACOSX_DEPLOYMENT_TARGET'] = MIN_MACOS_VERSION
|
||||||
# Sometimes worth testing with '-fstrict-aliasing', '-fno-common'
|
# Sometimes worth testing with '-fstrict-aliasing', '-fno-common'
|
||||||
compile_args = ['-O3', '-w', '-fopenmp', '-march=native',
|
compile_args = ['-O3',
|
||||||
'-mmacosx-version-min=' + MIN_MACOS_VERSION]
|
'-w',
|
||||||
linker_args = ['-fopenmp', '-mmacosx-version-min=' + MIN_MACOS_VERSION]
|
'-fopenmp',
|
||||||
|
'-march=native',
|
||||||
|
f'-mmacosx-version-min={MIN_MACOS_VERSION}']
|
||||||
|
linker_args = ['-fopenmp', f'-mmacosx-version-min={MIN_MACOS_VERSION}']
|
||||||
libraries=['gomp']
|
libraries=['gomp']
|
||||||
|
|
||||||
# Compiler options - Linux
|
|
||||||
elif sys.platform == 'linux':
|
elif sys.platform == 'linux':
|
||||||
compile_args = ['-O3', '-w', '-fopenmp', '-march=native']
|
compile_args = ['-O3', '-w', '-fopenmp', '-march=native']
|
||||||
linker_args = ['-fopenmp']
|
linker_args = ['-fopenmp']
|
||||||
@@ -261,12 +260,12 @@ else:
|
|||||||
version=version,
|
version=version,
|
||||||
author='Craig Warren, Antonis Giannopoulos, and John Hartley',
|
author='Craig Warren, Antonis Giannopoulos, and John Hartley',
|
||||||
url='http://www.gprmax.com',
|
url='http://www.gprmax.com',
|
||||||
description='Electromagnetic Modelling Software based on the ' +
|
description='Electromagnetic Modelling Software based on the '
|
||||||
'Finite-Difference Time-Domain (FDTD) method',
|
+ 'Finite-Difference Time-Domain (FDTD) method',
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/x-rst",
|
long_description_content_type="text/x-rst",
|
||||||
license='GPLv3+',
|
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',
|
install_requires=['colorama',
|
||||||
'cython',
|
'cython',
|
||||||
'h5py',
|
'h5py',
|
||||||
@@ -289,4 +288,5 @@ else:
|
|||||||
'Operating System :: POSIX :: Linux',
|
'Operating System :: POSIX :: Linux',
|
||||||
'Programming Language :: Cython',
|
'Programming Language :: Cython',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Topic :: Scientific/Engineering'])
|
'Topic :: Scientific/Engineering'],
|
||||||
|
)
|
||||||
|
@@ -93,8 +93,8 @@ for x, model in enumerate(testmodels):
|
|||||||
# Diffs
|
# Diffs
|
||||||
datadiffs = np.zeros(datatest.shape, dtype=np.float64)
|
datadiffs = np.zeros(datatest.shape, dtype=np.float64)
|
||||||
for i in range(len(outputstest)):
|
for i in range(len(outputstest)):
|
||||||
max = np.amax(np.abs(dataref[:, i]))
|
maxi = 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
|
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)
|
# Calculate power (ignore warning from taking a log of any zero values)
|
||||||
with np.errstate(divide='ignore'):
|
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),
|
plate = gprMax.Plate(p1=(0.013, 0.013, 0.013),
|
||||||
p2=(0.038, 0.113, 0.013), material_id='pec')
|
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),
|
gv1 = gprMax.GeometryView(p1=(0, 0, 0),
|
||||||
filename=Path(*parts[:-1], parts[-1] + '_n'), output_type='n')
|
p2=(x, y, z),
|
||||||
gv2 = gprMax.GeometryView(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
|
dl=(dl, dl, dl),
|
||||||
filename=Path(*parts[:-1], parts[-1] + '_f'), output_type='f')
|
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),
|
pmls = {'CFS-PML': {'pml': gprMax.PMLProps(formulation='HORIPML', thickness=10),
|
||||||
# Parameters from http://dx.doi.org/10.1109/TAP.2018.2823864
|
# 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),
|
plate = gprMax.Plate(p1=(0.088, 0.088, 0.088),
|
||||||
p2=(0.113, 0.188, 0.088), material_id='pec')
|
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),
|
gv1 = gprMax.GeometryView(p1=(0, 0, 0),
|
||||||
filename=Path(*parts[:-1], parts[-1] + '_n'), output_type='n')
|
p2=(x, y, z),
|
||||||
gv2 = gprMax.GeometryView(p1=(0, 0, 0), p2=(x, y, z), dl=(dl, dl, dl),
|
dl=(dl, dl, dl),
|
||||||
filename=Path(*parts[:-1], parts[-1] + '_f'), output_type='f')
|
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)
|
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])
|
difftime = - (timemodel[modelmax] - real[realmax, 0])
|
||||||
|
|
||||||
# Plot modelled and real data
|
# Plot modelled and real data
|
||||||
fig, ax = plt.subplots(num=modelfile.stem + '_vs_' + realfile.stem,
|
fig, ax = plt.subplots(num=f'{modelfile.stem}_vs_{realfile.stem}',
|
||||||
figsize=(20, 10), facecolor='w', edgecolor='w')
|
figsize=(20, 10),
|
||||||
|
facecolor='w',
|
||||||
|
edgecolor='w',)
|
||||||
ax.plot(timemodel + difftime, model, 'r', lw=2, label='Model')
|
ax.plot(timemodel + difftime, model, 'r', lw=2, label='Model')
|
||||||
ax.plot(real[:, 0], real[:, 1], 'r', ls='--', lw=2, label='Experiment')
|
ax.plot(real[:, 0], real[:, 1], 'r', ls='--', lw=2, label='Experiment')
|
||||||
ax.set_xlabel('Time [s]')
|
ax.set_xlabel('Time [s]')
|
||||||
@@ -93,7 +95,7 @@ ax.legend()
|
|||||||
ax.grid()
|
ax.grid()
|
||||||
|
|
||||||
# Save a PDF/PNG of the figure
|
# Save a PDF/PNG of the figure
|
||||||
savename = modelfile.stem + '_vs_' + realfile.stem
|
savename = f'{modelfile.stem}_vs_{realfile.stem}'
|
||||||
savename = modelfile.parent / savename
|
savename = modelfile.parent / savename
|
||||||
# fig.savefig(savename.with_suffix('.pdf'), dpi=None, format='pdf',
|
# fig.savefig(savename.with_suffix('.pdf'), dpi=None, format='pdf',
|
||||||
# bbox_inches='tight', pad_inches=0.1)
|
# bbox_inches='tight', pad_inches=0.1)
|
||||||
|
@@ -112,11 +112,9 @@ for i, model in enumerate(testmodels):
|
|||||||
filetest.attrs['dt'],
|
filetest.attrs['dt'],
|
||||||
filetest.attrs['dx_dy_dz'], rxposrelative)
|
filetest.attrs['dx_dy_dz'], rxposrelative)
|
||||||
|
|
||||||
filetest.close()
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Get output for model and reference files
|
# Get output for model and reference files
|
||||||
fileref = file.stem + '_ref'
|
fileref = f'{file.stem}_ref'
|
||||||
fileref = file.parent / Path(fileref)
|
fileref = file.parent / Path(fileref)
|
||||||
fileref = h5py.File(fileref.with_suffix('.h5'), 'r')
|
fileref = h5py.File(fileref.with_suffix('.h5'), 'r')
|
||||||
filetest = h5py.File(file.with_suffix('.h5'), 'r')
|
filetest = h5py.File(file.with_suffix('.h5'), 'r')
|
||||||
@@ -164,10 +162,10 @@ for i, model in enumerate(testmodels):
|
|||||||
# Diffs
|
# Diffs
|
||||||
datadiffs = np.zeros(datatest.shape, dtype=np.float64)
|
datadiffs = np.zeros(datatest.shape, dtype=np.float64)
|
||||||
for i in range(len(outputstest)):
|
for i in range(len(outputstest)):
|
||||||
max = np.amax(np.abs(dataref[:, i]))
|
maxi = np.amax(np.abs(dataref[:, i]))
|
||||||
datadiffs[:, i] = np.divide(np.abs(dataref[:, i] - datatest[:, i]), max,
|
datadiffs[:, i] = np.divide(np.abs(dataref[:, i] - datatest[:, i]), maxi,
|
||||||
out=np.zeros_like(dataref[:, i]),
|
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)
|
# Calculate power (ignore warning from taking a log of any zero values)
|
||||||
with np.errstate(divide='ignore'):
|
with np.errstate(divide='ignore'):
|
||||||
@@ -188,17 +186,17 @@ for i, model in enumerate(testmodels):
|
|||||||
facecolor='w',
|
facecolor='w',
|
||||||
edgecolor='w')
|
edgecolor='w')
|
||||||
ex1.plot(timetest, datatest[:, 0], 'r', lw=2, label=model)
|
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(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(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(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(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(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]',
|
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_y$, field strength [V/m]', '$H_y$, field strength [A/m]',
|
||||||
'$E_z$, field strength [V/m]', '$H_z$, 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()
|
ax.grid()
|
||||||
|
|
||||||
# Save a PDF/PNG of the figure
|
# Save a PDF/PNG of the figure
|
||||||
filediffs = file.stem + '_diffs'
|
filediffs = f'{file.stem}_diffs'
|
||||||
filediffs = file.parent / Path(filediffs)
|
filediffs = file.parent / Path(filediffs)
|
||||||
# fig1.savefig(file.with_suffix('.pdf'), dpi=None, format='pdf',
|
# fig1.savefig(file.with_suffix('.pdf'), dpi=None, format='pdf',
|
||||||
# bbox_inches='tight', pad_inches=0.1)
|
# bbox_inches='tight', pad_inches=0.1)
|
||||||
|
在新工单中引用
屏蔽一个用户