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

这个提交包含在:
Sai Suraj
2023-04-18 01:22:44 +05:30
当前提交 4015c51bd7
共有 19 个文件被更改,包括 295 次插入328 次删除

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

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

二进制文件未显示。

二进制文件未显示。

查看文件

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

二进制文件未显示。

查看文件

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

查看文件

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

查看文件

@@ -61,9 +61,9 @@ class UserObjectMulti:
"""Readable user string as per hash commands."""
s = ''
for _, v in self.kwargs.items():
if isinstance(v, tuple) or isinstance(v, list):
if isinstance(v, (tuple, list)):
v = ' '.join([str(el) for el in v])
s += str(v) + ' '
s += f'{str(v)} '
return f'{self.hash}: {s[:-1]}'
@@ -77,7 +77,7 @@ class UserObjectMulti:
def params_str(self):
"""Readable string of parameters given to object."""
return self.hash + ': ' + str(self.kwargs)
return f'{self.hash}: {str(self.kwargs)}'
def grid_name(self, grid):
"""Returns subgrid name for use with logging info. Returns an empty
@@ -114,12 +114,12 @@ class Waveform(UserObjectMulti):
try:
wavetype = self.kwargs['wave_type'].lower()
except KeyError:
logger.exception(self.params_str() + (f" must have one of the "
f"following types {','.join(WaveformUser.types)}."))
logger.exception(f"{self.params_str()} must have one of the " +
f"following types {','.join(WaveformUser.types)}.")
raise
if wavetype not in WaveformUser.types:
logger.exception(self.params_str() + (f" must have one of the "
f"following types {','.join(WaveformUser.types)}."))
logger.exception(f"{self.params_str()} must have one of the " +
f"following types {','.join(WaveformUser.types)}.")
raise ValueError
if wavetype != 'user':
@@ -817,16 +817,14 @@ class Rx(UserObjectMulti):
outputs = [self.kwargs['outputs']]
except KeyError:
# If no ID or outputs are specified, use default
r.ID = (r.__class__.__name__ + '(' + str(r.xcoord) + ',' +
str(r.ycoord) + ',' + str(r.zcoord) + ')')
r.ID = f'{r.__class__.__name__}({str(r.xcoord)},{str(r.ycoord)},{str(r.zcoord)})'
for key in RxUser.defaultoutputs:
r.outputs[key] = np.zeros(grid.iterations,
dtype=config.sim_config.dtypes['float_or_double'])
else:
outputs.sort()
# Get allowable outputs
if (config.sim_config.general['solver'] =='cuda' or
config.sim_config.general['solver'] =='opencl'):
if config.sim_config.general['solver'] in ['cuda', 'opencl']:
allowableoutputs = RxUser.allowableoutputs_dev
else:
allowableoutputs = RxUser.allowableoutputs
@@ -836,14 +834,14 @@ class Rx(UserObjectMulti):
r.outputs[field] = np.zeros(grid.iterations,
dtype=config.sim_config.dtypes['float_or_double'])
else:
logger.exception(self.params_str() + ' contains an '
'output type that is not allowable. '
'Allowable outputs in current context are '
logger.exception(f'{self.params_str()} contains an output '
f'type that is not allowable. Allowable '
f'outputs in current context are '
f'{allowableoutputs}.')
raise ValueError
logger.info(self.grid_name(grid) + f"Receiver at {p2[0]:g}m, "
f"{p2[1]:g}m, {p2[2]:g}m with output component(s) "
logger.info(f"{self.grid_name(grid)}Receiver at {p2[0]:g}m, {p2[1]:g}m, "
f"{p2[2]:g}m with output component(s) "
f"{', '.join(r.outputs)} created.")
grid.rxs.append(r)
@@ -911,10 +909,10 @@ class RxArray(UserObjectMulti):
'not be less than the spatial discretisation.')
raise ValueError
logger.info(self.grid_name(grid) + f'Receiver array {p3[0]:g}m, '
f'{p3[1]:g}m, {p3[2]:g}m, to {p4[0]:g}m, {p4[1]:g}m, '
f'{p4[2]:g}m with steps {dx * grid.dx:g}m, '
f'{dy * grid.dy:g}m, {dz * grid.dz:g}m')
logger.info(f'{self.grid_name(grid)}Receiver array '
f'{p3[0]:g}m, {p3[1]:g}m, {p3[2]:g}m, to '
f'{p4[0]:g}m, {p4[1]:g}m, {p4[2]:g}m with steps '
f'{dx * grid.dx:g}m, {dy * grid.dy:g}m, {dz * grid.dz:g}m')
for x in range(xs, xf + 1, dx):
for y in range(ys, yf + 1, dy):
@@ -930,8 +928,7 @@ class RxArray(UserObjectMulti):
p5 = np.array([x, y, z])
p5 = uip.descretised_to_continuous(p5)
p5 = uip.round_to_grid_static_point(p5)
r.ID = (r.__class__.__name__ + '(' + str(x) + ',' +
str(y) + ',' + str(z) + ')')
r.ID = f'{r.__class__.__name__}({str(x)},{str(y)},{str(z)})'
for key in RxUser.defaultoutputs:
r.outputs[key] = np.zeros(grid.iterations, dtype=config.sim_config.dtypes['float_or_double'])
logger.info(f" Receiver at {p5[0]:g}m, {p5[1]:g}m, "
@@ -986,7 +983,7 @@ class Snapshot(UserObjectMulti):
p4 = uip.round_to_grid_static_point(p2)
p1, p2 = uip.check_box_points(p1, p2, self.params_str())
except ValueError:
logger.exception(self.params_str() + ' point is outside the domain.')
logger.exception(f'{self.params_str()} point is outside the domain.')
raise
xs, ys, zs = p1
xf, yf, zf = p2
@@ -1027,10 +1024,10 @@ class Snapshot(UserObjectMulti):
# Check and set output names
for output in tmp:
if output not in SnapshotUser.allowableoutputs.keys():
logger.exception(self.params_str() + " contains an "
"output type that is not allowable. "
"Allowable outputs in current context are "
f"{', '.join(SnapshotUser.allowableoutputs.keys())}.")
logger.exception(f"{self.params_str()} contains an output "
f"type that is not allowable. Allowable "
f"outputs in current context are "
f"{', '.join(SnapshotUser.allowableoutputs.keys())}.")
raise ValueError
else:
outputs[output] = True
@@ -1047,7 +1044,7 @@ class Snapshot(UserObjectMulti):
'be less than the spatial discretisation.')
raise ValueError
if iterations <= 0 or iterations > grid.iterations:
logger.exception(self.params_str() + ' time value is not valid.')
logger.exception(f'{self.params_str()} time value is not valid.')
raise ValueError
s = SnapshotUser(xs, ys, zs, xf, yf, zf, dx, dy, dz, iterations,
@@ -1088,39 +1085,38 @@ class Material(UserObjectMulti):
sm = self.kwargs['sm']
material_id = self.kwargs['id']
except KeyError:
logger.exception(self.params_str() + ' requires exactly five '
'parameters.')
logger.exception(f'{self.params_str()} requires exactly five '
f'parameters.')
raise
if er < 1:
logger.exception(self.params_str() + ' requires a positive value '
'of one or greater for static (DC) permittivity.')
logger.exception(f'{self.params_str()} requires a positive value of '
f'one or greater for static (DC) permittivity.')
raise ValueError
if se != 'inf':
se = float(se)
if se < 0:
logger.exception(self.params_str() + ' requires a positive '
'value for electric conductivity.')
logger.exception(f'{self.params_str()} requires a positive '
f'value for electric conductivity.')
raise ValueError
else:
se = float('inf')
if mr < 1:
logger.exception(self.params_str() + ' requires a positive value '
'of one or greater for magnetic permeability.')
logger.exception(f'{self.params_str()} requires a positive value of '
f'one or greater for magnetic permeability.')
raise ValueError
if sm < 0:
logger.exception(self.params_str() + ' requires a positive value '
'for magnetic loss.')
logger.exception(f'{self.params_str()} requires a positive value '
f'for magnetic loss.')
raise ValueError
if any(x.ID == material_id for x in grid.materials):
logger.exception(self.params_str() + f' with ID {material_id} '
'already exists')
logger.exception(f'{self.params_str()} with ID {material_id} '
f'already exists')
raise ValueError
# Create a new instance of the Material class material
# (start index after pec & free_space)
m = MaterialUser(len(grid.materials), material_id)
m.er = er
m.se = se
m.mr = mr
m.sm = sm
@@ -1129,9 +1125,10 @@ class Material(UserObjectMulti):
if m.se == float('inf'):
m.averagable = False
logger.info(self.grid_name(grid) + f'Material {m.ID} with '
f'eps_r={m.er:g}, sigma={m.se:g} S/m; mu_r={m.mr:g}, '
f'sigma*={m.sm:g} Ohm/m created.')
m.er = er
logger.info(f'{self.grid_name(grid)}Material {m.ID} with eps_r={m.er:g}, '
f'sigma={m.se:g} S/m; mu_r={m.mr:g}, sigma*={m.sm:g} Ohm/m '
f'created.')
grid.materials.append(m)
@@ -1176,8 +1173,7 @@ class AddDebyeDispersion(UserObjectMulti):
if len(materials) != len(material_ids):
notfound = [x for x in material_ids if x not in materials]
logger.exception(self.params_str() + f' material(s) {notfound} do '
'not exist')
logger.exception(f'{self.params_str()} material(s) {notfound} do not exist')
raise ValueError
for material in materials:
@@ -1189,7 +1185,7 @@ class AddDebyeDispersion(UserObjectMulti):
disp_material.type = 'debye'
disp_material.poles = poles
disp_material.averagable = False
for i in range(0, poles):
for i in range(poles):
if tau[i] > 0:
logger.debug('Not checking if relaxation times are '
'greater than time-step.')
@@ -1205,8 +1201,8 @@ class AddDebyeDispersion(UserObjectMulti):
# Replace original material with newly created DispersiveMaterial
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
logger.info(self.grid_name(grid) + f"Debye disperion added to {disp_material.ID} "
f"with delta_eps_r={', '.join('%4.2f' % deltaer for deltaer in disp_material.deltaer)}, "
logger.info(f"{self.grid_name(grid)}Debye disperion added to {disp_material.ID} "
f"with delta_eps_r={', '.join('%4.2f' % deltaer for deltaer in disp_material.deltaer)}, "
f"and tau={', '.join('%4.3e' % tau for tau in disp_material.tau)} secs created.")
@@ -1252,8 +1248,7 @@ class AddLorentzDispersion(UserObjectMulti):
if len(materials) != len(material_ids):
notfound = [x for x in material_ids if x not in materials]
logger.exception(self.params_str() + f' material(s) {notfound} do '
'not exist')
logger.exception(f'{self.params_str()} material(s) {notfound} do not exist')
raise ValueError
for material in materials:
@@ -1265,7 +1260,7 @@ class AddLorentzDispersion(UserObjectMulti):
disp_material.type = 'lorentz'
disp_material.poles = poles
disp_material.averagable = False
for i in range(0, poles):
for i in range(poles):
if er_delta[i] > 0 and omega[i] > grid.dt and delta[i] > grid.dt:
disp_material.deltaer.append(er_delta[i])
disp_material.tau.append(omega[i])
@@ -1283,10 +1278,11 @@ class AddLorentzDispersion(UserObjectMulti):
# Replace original material with newly created DispersiveMaterial
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
logger.info(self.grid_name(grid) + f"Lorentz disperion added to {disp_material.ID} "
f"with delta_eps_r={', '.join('%4.2f' % deltaer for deltaer in disp_material.deltaer)}, "
f"omega={', '.join('%4.3e' % omega for omega in disp_material.tau)} secs, "
f"and gamma={', '.join('%4.3e' % delta for delta in disp_material.alpha)} created.")
logger.info(
f"{self.grid_name(grid)}Lorentz disperion added to {disp_material.ID} "
f"with delta_eps_r={', '.join('%4.2f' % deltaer for deltaer in disp_material.deltaer)}, "
f"omega={', '.join('%4.3e' % omega for omega in disp_material.tau)} secs, "
f"and gamma={', '.join('%4.3e' % delta for delta in disp_material.alpha)} created.")
class AddDrudeDispersion(UserObjectMulti):
@@ -1327,8 +1323,7 @@ class AddDrudeDispersion(UserObjectMulti):
if len(materials) != len(material_ids):
notfound = [x for x in material_ids if x not in materials]
logger.exception(self.params_str() + f' material(s) {notfound} do '
'not exist.')
logger.exception(f'{self.params_str()} material(s) {notfound} do not exist.')
raise ValueError
for material in materials:
@@ -1340,7 +1335,7 @@ class AddDrudeDispersion(UserObjectMulti):
disp_material.type = 'drude'
disp_material.poles = poles
disp_material.averagable = False
for i in range(0, poles):
for i in range(poles):
if omega[i] > 0 and alpha[i] > grid.dt:
disp_material.tau.append(omega[i])
disp_material.alpha.append(alpha[i])
@@ -1356,9 +1351,10 @@ class AddDrudeDispersion(UserObjectMulti):
# Replace original material with newly created DispersiveMaterial
grid.materials = [disp_material if mat.numID==material.numID else mat for mat in grid.materials]
logger.info(self.grid_name(grid) + f"Drude disperion added to {disp_material.ID} "
f"with omega={', '.join('%4.3e' % omega for omega in disp_material.tau)} secs, "
f"and gamma={', '.join('%4.3e' % alpha for alpha in disp_material.alpha)} secs created.")
logger.info(
f"{self.grid_name(grid)}Drude disperion added to {disp_material.ID} "
f"with omega={', '.join('%4.3e' % omega for omega in disp_material.tau)} secs, "
f"and gamma={', '.join('%4.3e' % alpha for alpha in disp_material.alpha)} secs created.")
class SoilPeplinski(UserObjectMulti):
@@ -1423,7 +1419,7 @@ class SoilPeplinski(UserObjectMulti):
'fraction.')
raise ValueError
if any(x.ID == ID for x in grid.mixingmodels):
logger.exception(self.params_str() + f' with ID {ID} already exists')
logger.exception(f'{self.params_str()} with ID {ID} already exists')
raise ValueError
# Create a new instance of the Material class material
@@ -1519,7 +1515,8 @@ class MaterialRange(UserObjectMulti):
# Create a new instance of the Material class material
# (start index after pec & free_space)
s = RangeMaterialUser(ID, (er_lower, er_upper), (sigma_lower, sigma_upper), (mr_lower, mr_upper), (ro_lower, ro_upper))
s = RangeMaterialUser(ID, (er_lower, er_upper), (sigma_lower, sigma_upper),
(mr_lower, mr_upper), (ro_lower, ro_upper))
logger.info(self.grid_name(grid) + 'Material properties used to '
f'create {s.ID} with range(s) {s.er[0]:g} to {s.er[1]:g}, relative permittivity '
@@ -1553,8 +1550,7 @@ class MaterialList(UserObjectMulti):
logger.exception(self.params_str() + ' requires at at least 2 '
'parameters.')
raise
if any(x.ID == ID for x in grid.mixingmodels):
logger.exception(self.params_str() + f' with ID {ID} already exists')
raise ValueError
@@ -1570,7 +1566,6 @@ class MaterialList(UserObjectMulti):
grid.mixingmodels.append(s)
class GeometryView(UserObjectMulti):
"""Outputs to file(s) information about the geometry (mesh) of model.
@@ -1624,14 +1619,13 @@ class GeometryView(UserObjectMulti):
p4 = uip.round_to_grid_static_point(p2)
p1, p2 = uip.check_box_points(p1, p2, self.params_str())
except ValueError:
logger.exception(self.params_str() + ' point is outside the domain.')
logger.exception(f'{self.params_str()} point is outside the domain.')
raise
xs, ys, zs = p1
xf, yf, zf = p2
dx, dy, dz = uip.discretise_static_point(dl)
if dx < 0 or dy < 0 or dz < 0:
logger.exception(self.params_str() + ' the step size should not be '
'less than zero.')
@@ -1644,7 +1638,7 @@ class GeometryView(UserObjectMulti):
logger.exception(self.params_str() + ' the step size should not '
'be less than the spatial discretisation.')
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 '
'n (normal) or f (fine).')
raise ValueError

查看文件

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

查看文件

@@ -224,14 +224,14 @@ class SimulationConfig:
# solver: cpu, cuda, opencl.
# subgrid: whether the simulation uses sub-grids.
# precision: data type for electromagnetic field output (single/double).
# progressbars: progress bars on stdoout or not - switch off
# progressbars when logging level is greater than
# info (20)
self.general = {'solver': 'cpu',
'subgrid': False,
'precision': 'single'}
# Progress bars on stdoout or not - switch off progressbars when
# logging level is greater than info (20)
self.general['progressbars'] = False if args.log_level > 20 else True
'precision': 'single',
'progressbars': args.log_level <= 20}
self.em_consts = {'c': c, # Speed of light in free space (m/s)
'e0': e0, # Permittivity of free space (F/m)

查看文件

@@ -277,14 +277,10 @@ class Comments():
"""
# Comments for Paraview macro
comments = {}
comments['gprMax_version'] = __version__
comments['dx_dy_dz'] = self.dx_dy_dz_comment()
comments['nx_ny_nz'] = self.nx_ny_nz_comment()
# Write the name and numeric ID for each material
comments['Materials'] = self.materials_comment()
comments = {'gprMax_version': __version__,
'dx_dy_dz': self.dx_dy_dz_comment(),
'nx_ny_nz': self.nx_ny_nz_comment(),
'Materials': self.materials_comment()} # Write the name and numeric ID for each material
# Write information on PMLs, sources, and receivers
if not self.materials_only:

查看文件

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

查看文件

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

查看文件

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

查看文件

@@ -55,9 +55,8 @@ def process_singlecmds(singlecmds):
if singlecmds[cmd] is not None:
tmp = tuple(int(x) for x in singlecmds[cmd].split())
if len(tmp) != 1:
logger.exception(
f'{cmd} requires exactly one parameter to specify the number of CPU OpenMP threads to use'
)
logger.exception(f'{cmd} requires exactly one parameter to specify '
f'the number of CPU OpenMP threads to use')
raise ValueError
omp_threads = OMPThreads(n=tmp[0])
@@ -95,9 +94,8 @@ def process_singlecmds(singlecmds):
if singlecmds[cmd] is not None:
tmp = singlecmds[cmd].split()
if len(tmp) != 1:
logger.exception(
f'{cmd} requires exactly one parameter to specify the time window. Either in seconds or number of iterations.'
)
logger.exception(f'{cmd} requires exactly one parameter to specify the '
f'time window. Either in seconds or number of iterations.')
raise ValueError
tmp = tmp[0].lower()

查看文件

@@ -213,79 +213,7 @@ class DispersiveMaterial(Material):
er -= ersum
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 = [
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
class PeplinskiSoil:
"""Soil objects that are characterised according to a mixing model
@@ -351,12 +279,11 @@ class PeplinskiSoil:
# The limiting values of the ranges are not included in this.
#mubins = np.linspace(self.mu[0], self.mu[1], nbins)
mubins = np.linspace(self.mu[0], self.mu[1], nbins+1)
mubins = np.linspace(self.mu[0], self.mu[1], nbins + 1)
# Generate a range of volumetric water fraction values the mid-point of
# each bin to make materials from
#mumaterials = mubins + (mubins[1] - mubins[0]) / 2
mumaterials = 0.5*(mubins[1:nbins+1] + mubins[0:nbins])
mumaterials = 0.5 * (mubins[1:nbins+1] + mubins[0:nbins])
# Create an iterator
muiter = np.nditer(mumaterials, flags=['c_index'])
@@ -400,18 +327,19 @@ class PeplinskiSoil:
muiter.iternext()
class RangeMaterial:
"""Material defined with a given range of parameters to be used for
factal spatial disttibutions
"""Material defined with a given range of parameters to be used for fractal
spatial distributions.
"""
def __init__(self, ID, er_range, sigma_range, mu_range, ro_range):
"""
Args:
ID: string for name of the material.
er_range: tuple of floats for relative permittivity range of the material.
sigma_range: tuple of floats for electric conductivity range of the material.
er_range: tuple of floats for relative permittivity range of the
material.
sigma_range: tuple of floats for electric conductivity range of the
material.
mu_range: tuple of floats for magnetic permeability of material.
ro_range: tuple of floats for magnetic loss range of material.
"""
@@ -426,7 +354,6 @@ class RangeMaterial:
# and assume that all must be sequentially numbered. This allows for more general mixing models
self.matID = []
def calculate_properties(self, nbins, G):
"""Calculates the properties of the materials.
@@ -437,50 +364,50 @@ class RangeMaterial:
# Generate a set of relative permittivity bins based on the given range
erbins = np.linspace(self.er[0], self.er[1], nbins+1)
# Generate a range of relative permittivity values the mid-point of
# each bin to make materials from
#ermaterials = erbins + np.abs((erbins[1] - erbins[0])) / 2
ermaterials = 0.5*(erbins[1:nbins+1] + erbins[0:nbins])
ermaterials = 0.5 * (erbins[1:nbins+1] + erbins[0:nbins])
# Generate a set of conductivity bins based on the given range
sigmabins = np.linspace(self.sig[0], self.sig[1], nbins+1)
sigmabins = np.linspace(self.sig[0], self.sig[1], nbins + 1)
# Generate a range of conductivity values the mid-point of
# each bin to make materials from
#sigmamaterials = sigmabins + (sigmabins[1] - sigmabins[0]) / 2
sigmamaterials = 0.5*(sigmabins[1:nbins+1] + sigmabins[0:nbins])
sigmamaterials = 0.5 * (sigmabins[1:nbins+1] + sigmabins[0:nbins])
# Generate a set of magnetic permeability bins based on the given range
mubins = np.linspace(self.mu[0], self.mu[1], nbins+1)
mubins = np.linspace(self.mu[0], self.mu[1], nbins + 1)
# Generate a range of magnetic permeability values the mid-point of
# each bin to make materials from
#mumaterials = mubins + np.abs((mubins[1] - mubins[0])) / 2
mumaterials = 0.5*(mubins[1:nbins+1] + mubins[0:nbins])
mumaterials = 0.5 * (mubins[1:nbins+1] + mubins[0:nbins])
# Generate a set of magnetic loss bins based on the given range
robins = np.linspace(self.ro[0], self.ro[1], nbins+1)
# Generate a range of magnetic loss values the mid-point of
# each bin to make materials from
robins = np.linspace(self.ro[0], self.ro[1], nbins + 1)
# Generate a range of magnetic loss values the mid-point of each bin to
# make materials from
#romaterials = robins + np.abs((robins[1] - robins[0])) / 2
romaterials = 0.5*(robins[1:nbins+1] + robins[0:nbins])
romaterials = 0.5 * (robins[1:nbins+1] + robins[0:nbins])
# Iterate over the bins
for iter in np.arange(0,nbins):
for iter in np.arange(nbins):
# Relative permittivity
er = ermaterials[iter]
# Effective conductivity
se = sigmamaterials[iter]
# magnetic permeability
# Magnetic permeability
mr = mumaterials[iter]
# magnetic loss
# Magnetic loss
sm = romaterials[iter]
# Check to see if the material already exists before creating a new one
requiredID = '|{:.4f}+{:.4f}+{:.4f}+{:.4f}|'.format(float(er),float(se),float(mr),float(sm))
requiredID = f'|{float(er):.4f}+{float(se):.4f}+{float(mr):.4f}+{float(sm):.4f}|'
material = next((x for x in G.materials if x.ID == requiredID), None)
if iter == 0:
if material:
@@ -500,11 +427,10 @@ class RangeMaterial:
self.matID.append(m.numID)
class ListMaterial:
"""A list of predefined materials to be used for
factal spatial disttibutions. This command does not create new materials but collects them to be used in a
stochastic distribution by a fractal box.
"""A list of predefined materials to be used for fractal spatial
distributions. This command does not create new materials but collects
them to be used in a stochastic distribution by a fractal box.
"""
def __init__(self, ID, listofmaterials):
@@ -525,21 +451,18 @@ class ListMaterial:
def calculate_properties(self, nbins, G):
"""Calculates the properties of the materials. No Debye is used but name kept the same as used in other
class that needs Debye
"""Calculates the properties of the materials.
Args:
nbins: int for number of bins to use to create the different materials.
G: FDTDGrid class describing a grid in a model.
"""
# Iterate over the bins
for iter in np.arange(0,nbins):
# Check to see if the material already exists before creating a new one
for iter in np.arange(nbins):
#requiredID = '|{:}_in_{:}|'.format((self.mat[iter]),(self.ID))
requiredID = self.mat[iter]
# Check if the material already exists before creating a new one
material = next((x for x in G.materials if x.ID == requiredID), None)
self.matID.append(material.numID)
@@ -556,15 +479,11 @@ class ListMaterial:
# m.numID = len(G.materials)
# G.materials.append(m)
if not material:
logger.exception(self.__str__() + f' material(s) {material} do not exist')
raise ValueError
def create_built_in_materials(G):
"""Creates pre-defined (built-in) materials.
@@ -572,8 +491,6 @@ def create_built_in_materials(G):
G: FDTDGrid class describing a grid in a model.
"""
G.n_built_in_materials = len(G.materials)
m = Material(0, 'pec')
m.se = float('inf')
m.type = 'builtin'
@@ -584,8 +501,6 @@ def create_built_in_materials(G):
m.type = 'builtin'
G.materials.append(m)
G.n_built_in_materials = len(G.materials)
def calculate_water_properties(T=25, S=0):
"""Get extended Debye model properties for water.
@@ -628,8 +543,6 @@ def create_water(G, T=25, S=0):
eri, er, tau, sig = calculate_water_properties(T, S)
G.n_built_in_materials = len(G.materials)
m = DispersiveMaterial(len(G.materials), 'water')
m.averagable = False
m.type = 'builtin, debye'
@@ -642,8 +555,6 @@ def create_water(G, T=25, S=0):
if config.get_model_config().materials['maxpoles'] == 0:
config.get_model_config().materials['maxpoles'] = 1
G.n_built_in_materials = len(G.materials)
def create_grass(G):
"""Creates single-pole Debye model for grass
@@ -658,8 +569,6 @@ def create_grass(G):
tau = 1.0793e-11
sig = 0
G.n_built_in_materials = len(G.materials)
m = DispersiveMaterial(len(G.materials), 'grass')
m.averagable = False
m.type = 'builtin, debye'
@@ -672,4 +581,70 @@ def create_grass(G):
if config.get_model_config().materials['maxpoles'] == 0:
config.get_model_config().materials['maxpoles'] = 1
G.n_built_in_materials = len(G.materials)
def process_materials(G):
"""Processes complete list of materials - calculates update coefficients,
stores in arrays, and builds text list of materials/properties
Args:
G: FDTDGrid class describing a grid in a model.
Returns:
materialsdata: list of material IDs, names, and properties to
print a table.
"""
if config.get_model_config().materials['maxpoles'] == 0:
materialsdata = [['\nID', '\nName', '\nType', '\neps_r', 'sigma\n[S/m]',
'\nmu_r', 'sigma*\n[Ohm/m]', 'Dielectric\nsmoothable']]
else:
materialsdata = [['\nID', '\nName', '\nType', '\neps_r', 'sigma\n[S/m]',
'Delta\neps_r', 'tau\n[s]', 'omega\n[Hz]', 'delta\n[Hz]',
'gamma\n[Hz]', '\nmu_r', 'sigma*\n[Ohm/m]', 'Dielectric\nsmoothable']]
for material in G.materials:
# Calculate update coefficients for specific material
material.calculate_update_coeffsE(G)
material.calculate_update_coeffsH(G)
# Add update coefficients to overall storage for all materials
G.updatecoeffsE[material.numID, :] = material.CA, material.CBx, material.CBy, material.CBz, material.srce
G.updatecoeffsH[material.numID, :] = material.DA, material.DBx, material.DBy, material.DBz, material.srcm
# Add update coefficients to overall storage for dispersive materials
if hasattr(material, 'poles'):
z = 0
for pole in range(config.get_model_config().materials['maxpoles']):
G.updatecoeffsdispersive[material.numID, z:z + 3] = (config.sim_config.em_consts['e0'] *
material.eqt2[pole], material.eqt[pole], material.zt[pole])
z += 3
# Construct information on material properties for printing table
materialtext = [str(material.numID),
material.ID[:50] if len(material.ID) > 50 else material.ID,
material.type,
f'{material.er:g}',
f'{material.se:g}']
if config.get_model_config().materials['maxpoles'] > 0:
if 'debye' in material.type:
materialtext.append('\n'.join('{:g}'.format(deltaer) for deltaer in material.deltaer))
materialtext.append('\n'.join('{:g}'.format(tau) for tau in material.tau))
materialtext.extend(['', '', ''])
elif 'lorentz' in material.type:
materialtext.append(', '.join('{:g}'.format(deltaer) for deltaer in material.deltaer))
materialtext.append('')
materialtext.append(', '.join('{:g}'.format(tau) for tau in material.tau))
materialtext.append(', '.join('{:g}'.format(alpha) for alpha in material.alpha))
materialtext.append('')
elif 'drude' in material.type:
materialtext.extend(['', ''])
materialtext.append(', '.join('{:g}'.format(tau) for tau in material.tau))
materialtext.append('')
materialtext.append(', '.join('{:g}'.format(alpha) for alpha in material.alpha))
else:
materialtext.extend(['', '', '', '', ''])
materialtext.extend((f'{material.mr:g}', f'{material.sm:g}', material.averagable))
materialsdata.append(materialtext)
return materialsdata

查看文件

@@ -123,11 +123,7 @@ class SubGridBase(UserObjectMulti):
self.subgrid = sg
# Copy over built in materials
sg.materials = [
copy(m)
for m in grid.materials
if m.numID in range(grid.n_built_in_materials + 1)
]
sg.materials = [copy(m) for m in grid.materials if m.type == 'builtin']
# Don't mix and match different subgrid types
for sg_made in grid.subgrids:

查看文件

@@ -53,19 +53,22 @@ class Waveform:
"""Calculates coefficients (used to calculate values) for specific
waveforms.
"""
if self.freq is None:
raise ValueError("Frequency is not specified")
if (self.type == 'gaussian' or self.type == 'gaussiandot' or
self.type == 'gaussiandotnorm' or self.type == 'gaussianprime' or
self.type == 'gaussiandoubleprime'):
if self.type in ['gaussian',
'gaussiandot',
'gaussiandotnorm',
'gaussianprime',
'gaussiandoubleprime']:
self.chi = 1 / self.freq
self.zeta = 2 * np.pi**2 * self.freq**2
elif (self.type == 'gaussiandotdot' or
self.type == 'gaussiandotdotnorm' or self.type == 'ricker'):
elif self.type in ['gaussiandotdot', 'gaussiandotdotnorm', 'ricker']:
self.chi = np.sqrt(2) / self.freq
self.zeta = np.pi**2 * self.freq**2
def calculate_value(self, time, dt):
"""Calculates value of the waveform at a specific time.
"""Calculates the value of the waveform at a specific time.
Args:
time: float for absolute time.
@@ -82,7 +85,7 @@ class Waveform:
delay = time - self.chi
ampvalue = np.exp(-self.zeta * delay**2)
elif self.type == 'gaussiandot' or self.type == 'gaussianprime':
elif self.type in ['gaussiandot', 'gaussianprime']:
delay = time - self.chi
ampvalue = -2 * self.zeta * delay * np.exp(-self.zeta * delay**2)
@@ -91,7 +94,7 @@ class Waveform:
normalise = np.sqrt(np.exp(1) / (2 * self.zeta))
ampvalue = -2 * self.zeta * delay * np.exp(-self.zeta * delay**2) * normalise
elif self.type == 'gaussiandotdot' or self.type == 'gaussiandoubleprime':
elif self.type in ['gaussiandotdot', 'gaussiandoubleprime']:
delay = time - self.chi
ampvalue = (2 * self.zeta * (2 * self.zeta * delay**2 - 1) *
np.exp(-self.zeta * delay**2))
@@ -116,8 +119,8 @@ class Waveform:
elif self.type == 'contsine':
rampamp = 0.25
ramp = rampamp * time * self.freq
if ramp > 1:
ramp = 1
ramp = min(ramp, 1)
ampvalue = ramp * np.sin(2 * np.pi * self.freq * time)
elif self.type == 'impulse':
@@ -126,7 +129,7 @@ class Waveform:
ampvalue = 1
elif time >= dt:
ampvalue = 0
elif self.type == 'user':
ampvalue = self.userfunc(time)

查看文件

@@ -37,8 +37,9 @@ if sys.version_info[:2] < MIN_PYTHON_VERSION:
# Importing gprMax _version__.py before building can cause issues.
with open('gprMax/_version.py', 'r') as fd:
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
fd.read(), re.MULTILINE).group(1)
version = re.search(
r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE
)[1]
def build_dispersive_material_templates():
"""Function to generate Cython .pyx file for dispersive media update.
@@ -46,7 +47,7 @@ def build_dispersive_material_templates():
functions.
"""
iswin = True if sys.platform == 'win32' else False
iswin = (sys.platform == 'win32')
env = Environment(loader = FileSystemLoader(os.path.join('gprMax', 'cython')), )
@@ -151,7 +152,7 @@ if 'cleanall' in sys.argv:
print(f'Removed: {os.path.abspath(libfile)}')
except OSError:
print(f'Could not remove: {os.path.abspath(libfile)}')
# Remove build, dist, egg and __pycache__ directories
shutil.rmtree(Path.cwd().joinpath('build'), ignore_errors=True)
shutil.rmtree(Path.cwd().joinpath('dist'), ignore_errors=True)
@@ -163,7 +164,7 @@ if 'cleanall' in sys.argv:
# Remove 'gprMax/cython/fields_updates_dispersive.jinja' if its there
if os.path.isfile(cython_disp_file):
os.remove(cython_disp_file)
# Now do a normal clean
sys.argv[1] = 'clean' # this is what distutils understands
@@ -176,10 +177,6 @@ else:
linker_args = []
libraries = []
# Compiler options - macOS - needs gcc (usually via HomeBrew) because the
# default compiler LLVM (clang) does not
# support OpenMP. With gcc -fopenmp option
# implies -pthread
elif sys.platform == 'darwin':
# Check for Intel or Apple M series CPU
cpuID = subprocess.check_output("sysctl -n machdep.cpu.brand_string",
@@ -209,7 +206,7 @@ else:
'to be installed - easily done through the Homebrew package ' +
'manager (http://brew.sh). Note: gcc with OpenMP support ' +
'is required.')
# Minimum supported macOS deployment target
MIN_MACOS_VERSION = '10.13'
try:
@@ -219,12 +216,14 @@ else:
pass
os.environ['MIN_SUPPORTED_MACOSX_DEPLOYMENT_TARGET'] = MIN_MACOS_VERSION
# Sometimes worth testing with '-fstrict-aliasing', '-fno-common'
compile_args = ['-O3', '-w', '-fopenmp', '-march=native',
'-mmacosx-version-min=' + MIN_MACOS_VERSION]
linker_args = ['-fopenmp', '-mmacosx-version-min=' + MIN_MACOS_VERSION]
compile_args = ['-O3',
'-w',
'-fopenmp',
'-march=native',
f'-mmacosx-version-min={MIN_MACOS_VERSION}']
linker_args = ['-fopenmp', f'-mmacosx-version-min={MIN_MACOS_VERSION}']
libraries=['gomp']
# Compiler options - Linux
elif sys.platform == 'linux':
compile_args = ['-O3', '-w', '-fopenmp', '-march=native']
linker_args = ['-fopenmp']
@@ -256,17 +255,17 @@ else:
# Parse long_description from README.rst file.
with open('README.rst','r') as fd:
long_description = fd.read()
setup(name='gprMax',
version=version,
author='Craig Warren, Antonis Giannopoulos, and John Hartley',
url='http://www.gprmax.com',
description='Electromagnetic Modelling Software based on the ' +
'Finite-Difference Time-Domain (FDTD) method',
description='Electromagnetic Modelling Software based on the '
+ 'Finite-Difference Time-Domain (FDTD) method',
long_description=long_description,
long_description_content_type="text/x-rst",
license='GPLv3+',
python_requires='>' + str(MIN_PYTHON_VERSION[0]) + '.' + str(MIN_PYTHON_VERSION[1]),
python_requires=f'>{str(MIN_PYTHON_VERSION[0])}.{str(MIN_PYTHON_VERSION[1])}',
install_requires=['colorama',
'cython',
'h5py',
@@ -289,4 +288,5 @@ else:
'Operating System :: POSIX :: Linux',
'Programming Language :: Cython',
'Programming Language :: Python :: 3',
'Topic :: Scientific/Engineering'])
'Topic :: Scientific/Engineering'],
)