你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 04:56:51 +08:00
Started implementing new config structure.
这个提交包含在:
@@ -194,8 +194,4 @@ class AddGrass(UserObjectGeometry):
|
||||
|
||||
volume.fractalsurfaces.append(surface)
|
||||
|
||||
log.info(f'{n_blades} blades of grass on surface from {xs * grid.dx:g}m, \
|
||||
{ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, \
|
||||
{yf * grid.dy:g}m, {zf * grid.dz:g}m with fractal dimension \
|
||||
{surface.dimension:g}, fractal seeding {surface.seed}, and range \
|
||||
{limits[0]:g}m to {limits[1]:g}m, added to {surface.operatingonID}.')
|
||||
log.info(f'{n_blades} blades of grass on surface from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m with fractal dimension {surface.dimension:g}, fractal seeding {surface.seed}, and range {limits[0]:g}m to {limits[1]:g}m, added to {surface.operatingonID}.')
|
||||
|
@@ -159,9 +159,4 @@ class AddSurfaceRoughness(UserObjectGeometry):
|
||||
surface.generate_fractal_surface(grid)
|
||||
volume.fractalsurfaces.append(surface)
|
||||
|
||||
log.info(f'Fractal surface from {xs * grid.dx:g}m, {ys * grid.dy:g}m, \
|
||||
{zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, \
|
||||
{zf * grid.dz:g}m with fractal dimension {surface.dimension:g}, \
|
||||
fractal weightings {surface.weighting[0]:g}, {surface.weighting[1]:g}, \
|
||||
fractal seeding {surface.seed}, and range {limits[0]:g}m to \
|
||||
{limits[1]:g}m, added to {surface.operatingonID}.')
|
||||
log.info(f'Fractal surface from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m with fractal dimension {surface.dimension:g}, fractal weightings {surface.weighting[0]:g}, {surface.weighting[1]:g}, fractal seeding {surface.seed}, and range {limits[0]:g}m to {limits[1]:g}m, added to {surface.operatingonID}.')
|
||||
|
@@ -143,7 +143,4 @@ class AddSurfaceWater(UserObjectGeometry):
|
||||
if testwater:
|
||||
raise CmdInputError(self.__str__() + ' requires the time step for the model to be less than the relaxation time required to model water.')
|
||||
|
||||
log.info(f'Water on surface from {xs * grid.dx:g}m, {ys * grid.dy:g}m, \
|
||||
{zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, \
|
||||
{zf * grid.dz:g}m with depth {filldepth:g}m, added to \
|
||||
{surface.operatingonID}.')
|
||||
log.info(f'Water on surface from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m with depth {filldepth:g}m, added to {surface.operatingonID}.')
|
||||
|
@@ -117,7 +117,4 @@ class Box(UserObjectGeometry):
|
||||
build_box(xs, xf, ys, yf, zs, zf, numID, numIDx, numIDy, numIDz, averaging, grid.solid, grid.rigidE, grid.rigidH, grid.ID)
|
||||
|
||||
dielectricsmoothing = 'on' if averaging else 'off'
|
||||
log.info(f"Box from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, \
|
||||
to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m of \
|
||||
material(s) {', '.join(materialsrequested)} created, dielectric \
|
||||
smoothing is {dielectricsmoothing}.")
|
||||
log.info(f"Box from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m of material(s) {', '.join(materialsrequested)} created, dielectric smoothing is {dielectricsmoothing}.")
|
||||
|
@@ -122,6 +122,4 @@ class Cylinder(UserObjectGeometry):
|
||||
build_cylinder(x1, y1, z1, x2, y2, z2, r, grid.dx, grid.dy, grid.dz, numID, numIDx, numIDy, numIDz, averaging, grid.solid, grid.rigidE, grid.rigidH, grid.ID)
|
||||
|
||||
dielectricsmoothing = 'on' if averaging else 'off'
|
||||
log.info(f"Cylinder with face centres {x1:g}m, {y1:g}m, {z1:g}m and {x2:g}m, \
|
||||
{y2:g}m, {z2:g}m, with radius {r:g}m, of material(s) {', '.join(materialsrequested)} \
|
||||
created, dielectric smoothing is {dielectricsmoothing}.")
|
||||
log.info(f"Cylinder with face centres {x1:g}m, {y1:g}m, {z1:g}m and {x2:g}m, {y2:g}m, {z2:g}m, with radius {r:g}m, of material(s) {', '.join(materialsrequested)} created, dielectric smoothing is {dielectricsmoothing}.")
|
||||
|
@@ -172,14 +172,6 @@ class CylindricalSector(UserObjectGeometry):
|
||||
|
||||
if thickness > 0:
|
||||
dielectricsmoothing = 'on' if averaging else 'off'
|
||||
log.info(f"Cylindrical sector with centre {ctr1:g}m, {ctr2:g}m, \
|
||||
radius {r:g}m, starting angle {(sectorstartangle / (2 * np.pi)) * 360:.1f} \
|
||||
degrees, sector angle {(sectorangle / (2 * np.pi)) * 360:.1f} \
|
||||
degrees, thickness {thickness:g}m, of material(s) \
|
||||
{', '.join(materialsrequested)} created, dielectric smoothing \
|
||||
is {dielectricsmoothing}.")
|
||||
log.info(f"Cylindrical sector with centre {ctr1:g}m, {ctr2:g}m, radius {r:g}m, starting angle {(sectorstartangle / (2 * np.pi)) * 360:.1f} degrees, sector angle {(sectorangle / (2 * np.pi)) * 360:.1f} degrees, thickness {thickness:g}m, of material(s) {', '.join(materialsrequested)} created, dielectric smoothing is {dielectricsmoothing}.")
|
||||
else:
|
||||
log.info(f"Cylindrical sector with centre {ctr1:g}m, {ctr2:g}m, \
|
||||
radius {r:g}m, starting angle {(sectorstartangle / (2 * np.pi)) * 360:.1f} \
|
||||
degrees, sector angle {(sectorangle / (2 * np.pi)) * 360:.1f} \
|
||||
degrees, of material(s) {', '.join(materialsrequested)} created.")
|
||||
log.info(f"Cylindrical sector with centre {ctr1:g}m, {ctr2:g}m, radius {r:g}m, starting angle {(sectorstartangle / (2 * np.pi)) * 360:.1f} degrees, sector angle {(sectorangle / (2 * np.pi)) * 360:.1f} degrees, of material(s) {', '.join(materialsrequested)} created.")
|
||||
|
@@ -87,6 +87,4 @@ class Edge(UserObjectGeometry):
|
||||
for k in range(zs, zf):
|
||||
build_edge_z(xs, ys, k, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
||||
|
||||
log.info(f'Edge from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, \
|
||||
to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m of \
|
||||
material {material_id} created.')
|
||||
log.info(f'Edge from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m of material {material_id} created.')
|
||||
|
@@ -122,11 +122,6 @@ class FractalBox(UserObjectGeometry):
|
||||
volume.mixingmodel = mixingmodel
|
||||
|
||||
dielectricsmoothing = 'on' if volume.averaging else 'off'
|
||||
log.info(f'Fractal box {volume.ID} from {xs * grid.dx:g}m, {ys * grid.dy:g}m, \
|
||||
{zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m \
|
||||
with {volume.operatingonID}, fractal dimension {volume.dimension:g}, fractal \
|
||||
weightings {volume.weighting[0]:g}, {volume.weighting[1]:g}, {volume.weighting[2]:g}, \
|
||||
fractal seeding {volume.seed}, with {volume.nbins} material(s) created, \
|
||||
dielectric smoothing is {dielectricsmoothing}.')
|
||||
log.info(f'Fractal box {volume.ID} from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m with {volume.operatingonID}, fractal dimension {volume.dimension:g}, fractal weightings {volume.weighting[0]:g}, {volume.weighting[1]:g}, {volume.weighting[2]:g}, fractal seeding {volume.seed}, with {volume.nbins} material(s) created, dielectric smoothing is {dielectricsmoothing}.')
|
||||
|
||||
grid.fractalvolumes.append(volume)
|
||||
|
@@ -18,14 +18,12 @@
|
||||
|
||||
import numpy as np
|
||||
|
||||
import gprMax.config as config
|
||||
from .cmds_geometry import UserObjectGeometry
|
||||
from ..config import dtypes
|
||||
from ..cython.geometry_primitives import build_voxels_from_array
|
||||
from ..cython.geometry_primitives import build_voxels_from_array_mask
|
||||
from ..exceptions import CmdInputError
|
||||
|
||||
floattype = dtypes['float_or_double']
|
||||
|
||||
|
||||
class FractalBoxBuilder(UserObjectGeometry):
|
||||
"""Internal class for fractal box modifications. This class should be used
|
||||
@@ -75,7 +73,7 @@ class FractalBoxBuilder(UserObjectGeometry):
|
||||
|
||||
# If there is only 1 bin then a normal material is being used, otherwise a mixing model
|
||||
if volume.nbins == 1:
|
||||
volume.fractalvolume = np.ones((volume.nx, volume.ny, volume.nz), dtype=floattype)
|
||||
volume.fractalvolume = np.ones((volume.nx, volume.ny, volume.nz), dtype=config.sim_config.dtype['float_or_double'])
|
||||
materialnumID = next(x.numID for x in grid.materials if x.ID == volume.operatingonID)
|
||||
volume.fractalvolume *= materialnumID
|
||||
else:
|
||||
|
@@ -107,6 +107,4 @@ class GeometryObjectsRead(UserObjectGeometry):
|
||||
except KeyError:
|
||||
averaging = False
|
||||
build_voxels_from_array(xs, ys, zs, numexistmaterials, averaging, data, G.solid, G.rigidE, G.rigidH, G.ID)
|
||||
log.info(f'Geometry objects from file (voxels only){ geofile} \
|
||||
inserted at {xs * G.dx:g}m, {ys * G.dy:g}m, {zs * G.dz:g}m, \
|
||||
with corresponding materials file {matfile}.')
|
||||
log.info(f'Geometry objects from file (voxels only){geofile} inserted at {xs * G.dx:g}m, {ys * G.dy:g}m, {zs * G.dz:g}m, with corresponding materials file {matfile}.')
|
||||
|
@@ -135,6 +135,4 @@ class Plate(UserObjectGeometry):
|
||||
for j in range(ys, yf):
|
||||
build_face_xy(i, j, zs, numIDx, numIDy, grid.rigidE, grid.rigidH, grid.ID)
|
||||
|
||||
log.info(f"Plate from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, \
|
||||
to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m of \
|
||||
material(s) {', '.join(materialsrequested)} created.")
|
||||
log.info(f"Plate from {xs * grid.dx:g}m, {ys * grid.dy:g}m, {zs * grid.dz:g}m, to {xf * grid.dx:g}m, {yf * grid.dy:g}m, {zf * grid.dz:g}m of material(s) {', '.join(materialsrequested)} created.")
|
||||
|
@@ -116,6 +116,4 @@ class Sphere(UserObjectGeometry):
|
||||
build_sphere(xc, yc, zc, r, grid.dx, grid.dy, grid.dz, numID, numIDx, numIDy, numIDz, averaging, grid.solid, grid.rigidE, grid.rigidH, grid.ID)
|
||||
|
||||
dielectricsmoothing = 'on' if averaging else 'off'
|
||||
log.info(f"Sphere with centre {xc * grid.dx:g}m, {yc * grid.dy:g}m, {zc * grid.dz:g}m, \
|
||||
radius {r:g}m, of material(s) {', '.join(materialsrequested)} \
|
||||
created, dielectric smoothing is {dielectricsmoothing}.")
|
||||
log.info(f"Sphere with centre {xc * grid.dx:g}m, {yc * grid.dy:g}m, {zc * grid.dz:g}m, radius {r:g}m, of material(s) {', '.join(materialsrequested)} created, dielectric smoothing is {dielectricsmoothing}.")
|
||||
|
@@ -157,11 +157,6 @@ class Triangle(UserObjectGeometry):
|
||||
|
||||
if thickness > 0:
|
||||
dielectricsmoothing = 'on' if averaging else 'off'
|
||||
log.info(f"Triangle with coordinates {x1:g}m {y1:g}m {z1:g}m, \
|
||||
{x2:g}m {y2:g}m {z2:g}m, {x3:g}m {y3:g}m {z3:g}m and thickness \
|
||||
{thickness:g}m of material(s) {', '.join(materialsrequested)} \
|
||||
created, dielectric smoothing is {dielectricsmoothing}.")
|
||||
log.info(f"Triangle with coordinates {x1:g}m {y1:g}m {z1:g}m, {x2:g}m {y2:g}m {z2:g}m, {x3:g}m {y3:g}m {z3:g}m and thickness {thickness:g}m of material(s) {', '.join(materialsrequested)} created, dielectric smoothing is {dielectricsmoothing}.")
|
||||
else:
|
||||
log.info(f"Triangle with coordinates {x1:g}m {y1:g}m {z1:g}m, \
|
||||
{x2:g}m {y2:g}m {z2:g}m, {x3:g}m {y3:g}m {z3:g}m of \
|
||||
material(s) {', '.join(materialsrequested)} created.")
|
||||
log.info(f"Triangle with coordinates {x1:g}m {y1:g}m {z1:g}m, {x2:g}m {y2:g}m {z2:g}m, {x3:g}m {y3:g}m {z3:g}m of material(s) {', '.join(materialsrequested)} created.")
|
||||
|
@@ -196,7 +196,7 @@ class VoltageSource(UserObjectMulti):
|
||||
|
||||
v.calculate_waveform_values(grid)
|
||||
|
||||
log.info('Voltage source with polarity {} at {:g}m, {:g}m, {:g}m, resistance {:.1f} Ohms,'.format(v.polarisation, v.xcoord * grid.dx, v.ycoord * grid.dy, v.zcoord * grid.dz, v.resistance) + startstop + 'using waveform {} created.'.format(v.waveformID))
|
||||
log.info(f'Voltage source with polarity {v.polarisation} at {v.xcoord * grid.dx:g}m, {v.ycoord * grid.dy:g}m, {v.zcoord * grid.dz:g}m, resistance {v.resistance:.1f} Ohms,' + startstop + f'using waveform {v.waveformID} created.')
|
||||
|
||||
grid.voltagesources.append(v)
|
||||
|
||||
@@ -524,7 +524,7 @@ class Rx(UserObjectMulti):
|
||||
except KeyError:
|
||||
r.ID = 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.dtypes['float_or_double'])
|
||||
r.outputs[key] = np.zeros(grid.iterations, dtype=config.sim_config.dtypes['float_or_double'])
|
||||
|
||||
log.info(f"Receiver at {r.xcoord * grid.dx:g}m, {r.ycoord * grid.dy:g}m, {r.zcoord * grid.dz:g}m with output component(s) {', '.join(r.outputs)} created.")
|
||||
|
||||
@@ -1189,3 +1189,4 @@ class SubgridHSG(UserObjectMulti):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
log.debug('Is this required?')
|
||||
|
@@ -122,7 +122,7 @@ class Domain(UserObjectSingle):
|
||||
G.nthreads = set_openmp_threads()
|
||||
log.info(f'Number of CPU (OpenMP) threads: {G.nthreads}')
|
||||
|
||||
if G.nthreads > config.hostinfo['physicalcores']:
|
||||
if G.nthreads > config.sim_config.hostinfo['physicalcores']:
|
||||
log.warning(Fore.RED + f"You have specified more threads ({G.nthreads}) \
|
||||
than available physical CPU cores ({config.hostinfo['physicalcores']}). \
|
||||
This may lead to degraded performance." + Style.RESET_ALL)
|
||||
@@ -231,7 +231,7 @@ class Messages(UserObjectSingle):
|
||||
try:
|
||||
s = '#messages: {}'.format(self.kwargs['yn'])
|
||||
except KeyError:
|
||||
log.info('messages problem')
|
||||
log.exception('messages problem')
|
||||
|
||||
def create(self, G, uip):
|
||||
try:
|
||||
@@ -266,8 +266,7 @@ class Title(UserObjectSingle):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if config.is_messages():
|
||||
log.info('Model title: {}'.format(G.title))
|
||||
log.info(f'Model title: {G.title}')
|
||||
|
||||
|
||||
class NumThreads(UserObjectSingle):
|
||||
@@ -302,15 +301,16 @@ class NumThreads(UserObjectSingle):
|
||||
G.nthreads = n
|
||||
os.environ['OMP_NUM_THREADS'] = str(G.nthreads)
|
||||
|
||||
if config.is_messages():
|
||||
log.info('Number of CPU (OpenMP) threads: {}'.format(G.nthreads))
|
||||
log.info(f'Number of CPU (OpenMP) threads: {G.nthreads}')
|
||||
if G.nthreads > config.hostinfo['physicalcores']:
|
||||
log.info(Fore.RED + 'WARNING: You have specified more threads ({}) than available physical CPU cores ({}). This may lead to degraded performance.'.format(G.nthreads, config.hostinfo['physicalcores']) + Style.RESET_ALL)
|
||||
log.warning(Fore.RED + f"You have specified more threads ({G.nthreads}) \
|
||||
than available physical CPU cores (\
|
||||
{config.sim_config.hostinfo['physicalcores']}). \
|
||||
This may lead to degraded performance." + Style.RESET_ALL)
|
||||
|
||||
# Print information about any GPU in use
|
||||
if config.is_messages():
|
||||
if G.gpu is not None:
|
||||
log.info('GPU solving using: {} - {}'.format(G.gpu.deviceID, G.gpu.name))
|
||||
if G.gpu is not None:
|
||||
log.info(f'GPU solving using: {G.gpu.deviceID} - {G.gpu.name}')
|
||||
|
||||
|
||||
class TimeStepStabilityFactor(UserObjectSingle):
|
||||
@@ -326,7 +326,7 @@ class TimeStepStabilityFactor(UserObjectSingle):
|
||||
|
||||
def __str__(self):
|
||||
try:
|
||||
return '#time_step_stability_factor: {}'.format(self.kwargs['f'])
|
||||
return f"#time_step_stability_factor: {self.kwargs['f']}"
|
||||
except KeyError:
|
||||
return '#time_step_stability_factor:'
|
||||
|
||||
@@ -339,8 +339,7 @@ class TimeStepStabilityFactor(UserObjectSingle):
|
||||
if f <= 0 or f > 1:
|
||||
raise CmdInputError(self.__str__() + ' requires the value of the time step stability factor to be between zero and one')
|
||||
G.dt = G.dt * f
|
||||
if config.is_messages():
|
||||
log.info('Time step (modified): {:g} secs'.format(G.dt))
|
||||
log.info(f'Time step (modified): {G.dt:g} secs')
|
||||
|
||||
|
||||
class PMLCells(UserObjectSingle):
|
||||
@@ -412,8 +411,9 @@ class SrcSteps(UserObjectSingle):
|
||||
except KeyError:
|
||||
raise CmdInputError('#src_steps: requires exactly three parameters')
|
||||
|
||||
if config.is_messages():
|
||||
log.info('Simple sources will step {:g}m, {:g}m, {:g}m for each model run.'.format(G.srcsteps[0] * G.dx, G.srcsteps[1] * G.dy, G.srcsteps[2] * G.dz))
|
||||
log.info(f'Simple sources will step {G.srcsteps[0] * G.dx:g}m, \
|
||||
{G.srcsteps[1] * G.dy:g}m, {G.srcsteps[2] * G.dz:g}m \
|
||||
for each model run.')
|
||||
|
||||
|
||||
class RxSteps(UserObjectSingle):
|
||||
@@ -433,8 +433,9 @@ class RxSteps(UserObjectSingle):
|
||||
except KeyError:
|
||||
raise CmdInputError('#rx_steps: requires exactly three parameters')
|
||||
|
||||
if config.is_messages():
|
||||
log.info('All receivers will step {:g}m, {:g}m, {:g}m for each model run.'.format(G.rxsteps[0] * G.dx, G.rxsteps[1] * G.dy, G.rxsteps[2] * G.dz))
|
||||
log.info(f'All receivers will step {G.rxsteps[0] * G.dx:g}m, \
|
||||
{G.rxsteps[1] * G.dy:g}m, {G.rxsteps[2] * G.dz:g}m \
|
||||
for each model run.')
|
||||
|
||||
|
||||
class ExcitationFile(UserObjectSingle):
|
||||
@@ -468,8 +469,7 @@ class ExcitationFile(UserObjectSingle):
|
||||
if not os.path.isfile(excitationfile):
|
||||
excitationfile = os.path.abspath(os.path.join(G.inputdirectory, excitationfile))
|
||||
|
||||
if config.is_messages():
|
||||
log.info('\nExcitation file: {}'.format(excitationfile))
|
||||
log.info(f'\nExcitation file: {excitationfile}')
|
||||
|
||||
# Get waveform names
|
||||
with open(excitationfile, 'r') as f:
|
||||
@@ -490,7 +490,7 @@ class ExcitationFile(UserObjectSingle):
|
||||
|
||||
for waveform in range(len(waveformIDs)):
|
||||
if any(x.ID == waveformIDs[waveform] for x in G.waveforms):
|
||||
raise CmdInputError('Waveform with ID {} already exists'.format(waveformIDs[waveform]))
|
||||
raise CmdInputError(f'Waveform with ID {waveformIDs[waveform]} already exists')
|
||||
w = Waveform()
|
||||
w.ID = waveformIDs[waveform]
|
||||
w.type = 'user'
|
||||
@@ -508,8 +508,9 @@ class ExcitationFile(UserObjectSingle):
|
||||
# Interpolate waveform values
|
||||
w.userfunc = interpolate.interp1d(waveformtime, singlewaveformvalues, **kwargs)
|
||||
|
||||
if config.is_messages():
|
||||
log.info('User waveform {} created using {} and, if required, interpolation parameters (kind: {}, fill value: {}).'.format(w.ID, timestr, kwargs['kind'], kwargs['fill_value']))
|
||||
log.info(f"User waveform {w.ID} created using {timestr} and, if \
|
||||
required, interpolation parameters (kind: {kwargs['kind']}, \
|
||||
fill value: {kwargs['fill_value']}).")
|
||||
|
||||
G.waveforms.append(w)
|
||||
|
||||
|
185
gprMax/config.py
185
gprMax/config.py
@@ -31,79 +31,23 @@ from scipy.constants import mu_0 as m0
|
||||
from .utilities import get_host_info
|
||||
from .utilities import get_terminal_width
|
||||
|
||||
# Single instance of SimConfig to hold simulation configuration parameters.
|
||||
sim_config = None
|
||||
|
||||
# General settings for the simulation
|
||||
# inputfilepath: path to inputfile location
|
||||
# outputfilepath: path to outputfile location
|
||||
# messages: whether to print all messages as output to stdout or not
|
||||
# progressbars: whether to show progress bars on stdoout or not
|
||||
# mode: 2D TMx, 2D TMy, 2D TMz, or 3D
|
||||
# cpu, cuda, opencl: solver type
|
||||
# precision: data type for electromagnetic field output (single/double)
|
||||
# autotranslate: auto translate objects with main grid coordinates
|
||||
# to their equivalent local grid coordinate within the subgrid. If this option is off
|
||||
# users must specify sub-grid object point within the global subgrid space.
|
||||
# z0: impedance of free space (Ohms)
|
||||
general = {'messages': True,
|
||||
'progressbars': True,
|
||||
'mode': '3D',
|
||||
'cpu': True,
|
||||
'cuda': False,
|
||||
'opencl': False,
|
||||
'precision': 'single',
|
||||
'autotranslate': False,
|
||||
'z0': np.sqrt(m0 / e0)}
|
||||
|
||||
def is_messages():
|
||||
"""Return messages."""
|
||||
return general['messages']
|
||||
|
||||
# Store information about host machine
|
||||
hostinfo = get_host_info()
|
||||
|
||||
# Store information for CUDA solver type
|
||||
# gpus: information about any GPUs as a list of GPU objects
|
||||
# snapsgpu2cpu: copy snapshot data from GPU to CPU during simulation
|
||||
# N.B. This will happen if the requested snapshots are too large to fit
|
||||
# on the memory of the GPU. If True this will slow performance significantly
|
||||
cuda = {'gpus': None, 'snapsgpu2cpu': False}
|
||||
|
||||
# Data type (precision) for electromagnetic field output
|
||||
# Solid and ID arrays use 32-bit integers (0 to 4294967295)
|
||||
# Rigid arrays use 8-bit integers (the smallest available type to store true/false)
|
||||
# Fractal arrays use complex numbers
|
||||
# Dispersive coefficient arrays use either float or complex numbers
|
||||
# Main field arrays use floats
|
||||
|
||||
if general['precision'] == 'single':
|
||||
dtypes = {'float_or_double': np.float32,
|
||||
'complex': np.complex64,
|
||||
'cython_float_or_double': cython.float,
|
||||
'cython_complex': cython.floatcomplex,
|
||||
'C_float_or_double': 'float',
|
||||
'C_complex': 'pycuda::complex<float>'}
|
||||
elif general['precision'] == 'double':
|
||||
dtypes = {'float_or_double': np.float64,
|
||||
'complex': np.complex128,
|
||||
'cython_float_or_double': cython.double,
|
||||
'cython_complex': cython.doublecomplex,
|
||||
'C_float_or_double': 'double',
|
||||
'C_complex': 'pycuda::complex<double>'}
|
||||
|
||||
# Instance of ModelConfig that hold model configuration parameters.
|
||||
model_configs = []
|
||||
|
||||
class ModelConfig:
|
||||
"""Configuration parameters for a model.
|
||||
N.B. Multiple models can exist within a simulation
|
||||
"""
|
||||
|
||||
def __init__(self, sim_config, i):
|
||||
def __init__(self, i):
|
||||
"""
|
||||
Args:
|
||||
sim_config (SimConfig): Simulation level configuration object.
|
||||
i (int): Current model number.
|
||||
"""
|
||||
|
||||
self.sim_config = sim_config
|
||||
self.i = i # Indexed from 0
|
||||
self.reuse_geometry = False
|
||||
|
||||
@@ -113,7 +57,7 @@ class ModelConfig:
|
||||
self.appendmodelnumber = ''
|
||||
|
||||
# Output file path for specific model
|
||||
parts = self.sim_config.output_file_path.with_suffix('').parts
|
||||
parts = sim_config.output_file_path.with_suffix('').parts
|
||||
self.output_file_path = Path(*parts[:-1], parts[-1] + self.appendmodelnumber)
|
||||
self.output_file_path_ext = self.output_file_path.with_suffix('.out')
|
||||
|
||||
@@ -122,7 +66,7 @@ class ModelConfig:
|
||||
|
||||
# String to print at start of each model run
|
||||
inputfilestr_f = '\n--- Model {}/{}, input file: {}'
|
||||
self.inputfilestr = inputfilestr_f.format(self.i + 1, self.sim_config.model_end, self.sim_config.input_file_path)
|
||||
self.inputfilestr = inputfilestr_f.format(self.i + 1, sim_config.model_end, sim_config.input_file_path)
|
||||
self.next_model = Fore.GREEN + '{} {}\n'.format(self.inputfilestr, '-' * (get_terminal_width() - 1 - len(self.inputfilestr))) + Style.RESET_ALL
|
||||
|
||||
# Numerical dispersion analysis parameters
|
||||
@@ -143,18 +87,18 @@ class ModelConfig:
|
||||
'dispersiveCdtype': None}
|
||||
|
||||
def get_scene(self):
|
||||
if self.sim_config.scenes:
|
||||
return self.sim_config.scenes[self.i]
|
||||
if sim_config.scenes:
|
||||
return sim_config.scenes[self.i]
|
||||
else: return None
|
||||
|
||||
def get_usernamespace(self):
|
||||
return {'c': c, # Speed of light in free space (m/s)
|
||||
'e0': e0, # Permittivity of free space (F/m)
|
||||
'm0': m0, # Permeability of free space (H/m)
|
||||
'z0': general['z0'], # Impedance of free space (Ohms)
|
||||
'number_model_runs': self.sim_config.model_end + 1,
|
||||
'z0': np.sqrt(m0 / e0), # Impedance of free space (Ohms)
|
||||
'number_model_runs': sim_config.model_end + 1,
|
||||
'current_model_run': self.i + 1,
|
||||
'inputfile': self.sim_config.input_file_path.resolve()}
|
||||
'inputfile': sim_config.input_file_path.resolve()}
|
||||
|
||||
|
||||
class SimulationConfig:
|
||||
@@ -169,10 +113,45 @@ class SimulationConfig:
|
||||
"""
|
||||
|
||||
self.args = args
|
||||
self.general = general
|
||||
self.hostinfo = hostinfo
|
||||
self.cuda = cuda
|
||||
self.dtypes = dtypes
|
||||
|
||||
# General settings for the simulation
|
||||
# inputfilepath: path to inputfile location
|
||||
# outputfilepath: path to outputfile location
|
||||
# messages: whether to print all messages as output to stdout or not
|
||||
# progressbars: whether to show progress bars on stdoout or not
|
||||
# mode: 2D TMx, 2D TMy, 2D TMz, or 3D
|
||||
# cpu, cuda, opencl: solver type
|
||||
# precision: data type for electromagnetic field output (single/double)
|
||||
# autotranslate: auto translate objects with main grid coordinates
|
||||
# to their equivalent local grid coordinate within the subgrid.
|
||||
# If this option is off users must specify sub-grid object point
|
||||
# within the global subgrid space.
|
||||
self.general = {'messages': True,
|
||||
'progressbars': True,
|
||||
'mode': '3D',
|
||||
'cpu': True,
|
||||
'cuda': False,
|
||||
'opencl': False,
|
||||
'precision': 'single',
|
||||
'autotranslate': False}
|
||||
|
||||
self.em_consts = {'c': c, # Speed of light in free space (m/s)
|
||||
'e0': e0, # Permittivity of free space (F/m)
|
||||
'm0': m0, # Permeability of free space (H/m)
|
||||
'z0': np.sqrt(m0 / e0)} # Impedance of free space (Ohms)
|
||||
|
||||
# Store information about host machine
|
||||
self.hostinfo = get_host_info()
|
||||
|
||||
# Store information for CUDA solver type
|
||||
# gpus: information about any GPUs as a list of GPU objects
|
||||
# snapsgpu2cpu: copy snapshot data from GPU to CPU during simulation
|
||||
# N.B. This will happen if the requested snapshots are too large to fit
|
||||
# on the memory of the GPU. If True this will slow performance significantly
|
||||
self.cuda = {'gpus': None, 'snapsgpu2cpu': False}
|
||||
|
||||
# Data type (precision) for electromagnetic field output
|
||||
self.dtypes = None
|
||||
|
||||
# Subgrid parameter may not exist if user enters via CLI
|
||||
try:
|
||||
@@ -187,11 +166,40 @@ class SimulationConfig:
|
||||
self.scenes = []
|
||||
|
||||
# Set more complex parameters
|
||||
self.set_precision()
|
||||
self.set_input_file_path()
|
||||
self.set_output_file_path()
|
||||
self.set_model_start_end()
|
||||
self.set_single_model()
|
||||
|
||||
def is_messages(self):
|
||||
return self.general['messages']
|
||||
|
||||
def set_precision(self):
|
||||
"""Data type (precision) for electromagnetic field output.
|
||||
|
||||
Solid and ID arrays use 32-bit integers (0 to 4294967295)
|
||||
Rigid arrays use 8-bit integers (the smallest available type to store true/false)
|
||||
Fractal arrays use complex numbers
|
||||
Dispersive coefficient arrays use either float or complex numbers
|
||||
Main field arrays use floats
|
||||
"""
|
||||
|
||||
if self.general['precision'] == 'single':
|
||||
self.dtypes = {'float_or_double': np.float32,
|
||||
'complex': np.complex64,
|
||||
'cython_float_or_double': cython.float,
|
||||
'cython_complex': cython.floatcomplex,
|
||||
'C_float_or_double': 'float',
|
||||
'C_complex': 'pycuda::complex<float>'}
|
||||
elif self.general['precision'] == 'double':
|
||||
self.dtypes = {'float_or_double': np.float64,
|
||||
'complex': np.complex128,
|
||||
'cython_float_or_double': cython.double,
|
||||
'cython_complex': cython.doublecomplex,
|
||||
'C_float_or_double': 'double',
|
||||
'C_complex': 'pycuda::complex<double>'}
|
||||
|
||||
def set_single_model(self):
|
||||
if self.model_start == 0 and self.model_end == 1:
|
||||
self.single_model = True
|
||||
@@ -242,36 +250,3 @@ class SimulationConfigMPI(SimulationConfig):
|
||||
# Set range for number of models to run
|
||||
self.model_start = self.args.restart if self.args.restart else 1
|
||||
self.model_end = self.modelstart + self.args.n
|
||||
|
||||
|
||||
def create_simulation_config(args):
|
||||
"""Create simulation level configuration object to hold simulation
|
||||
level parameters.
|
||||
|
||||
Args:
|
||||
args (Namespace): Arguments from either API or CLI.
|
||||
|
||||
Returns:
|
||||
sc (SimulationConfig): Simulation configuration object.
|
||||
"""
|
||||
|
||||
if not args.mpi and not args.mpi_no_spawn:
|
||||
sc = SimulationConfig(args)
|
||||
elif args.mpi:
|
||||
sc = SimulationConfigMPI(args)
|
||||
|
||||
return sc
|
||||
|
||||
|
||||
def create_model_config(sim_config, i):
|
||||
"""Create model level configuration object to hold model level
|
||||
parameters.
|
||||
|
||||
Args:
|
||||
sim_config (SimConfig): Simulation level configuration object.
|
||||
i (int): Current model number.
|
||||
"""
|
||||
|
||||
mc = ModelConfig(sim_config, i)
|
||||
|
||||
return mc
|
||||
|
47
gprMax/config_parser.py
可执行文件
47
gprMax/config_parser.py
可执行文件
@@ -0,0 +1,47 @@
|
||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||
# Authors: Craig Warren and Antonis Giannopoulos
|
||||
#
|
||||
# This file is part of gprMax.
|
||||
#
|
||||
# gprMax is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gprMax is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import gprMax.config as config
|
||||
|
||||
|
||||
def write_simulation_config(args):
|
||||
"""Write simulation level configuration parameters to config module. As
|
||||
there can only be one instance of the config module objects are always
|
||||
found via 'import gprMax.config'
|
||||
|
||||
Args:
|
||||
args (Namespace): Arguments from either API or CLI.
|
||||
"""
|
||||
|
||||
if args.mpi or args.mpi_no_spawn:
|
||||
config.sim_config = config.SimulationConfigMPI(args)
|
||||
else:
|
||||
config.sim_config = config.SimulationConfig(args)
|
||||
|
||||
|
||||
def write_model_config(i):
|
||||
"""Write model level configuration parameters to config module. As there can
|
||||
only be one instance of the config module objects are always found via
|
||||
'import gprMax.config'
|
||||
|
||||
Args:
|
||||
i (int): Model number.
|
||||
"""
|
||||
|
||||
model_config = config.ModelConfig(i)
|
||||
config.model_configs.append(model_config)
|
@@ -18,8 +18,9 @@
|
||||
|
||||
import datetime
|
||||
|
||||
import gprMax.config as config
|
||||
from ._version import __version__, codename
|
||||
from .config import create_model_config
|
||||
from .config_parser import write_model_config
|
||||
from .model_build_run import ModelBuildRun
|
||||
from .solvers import create_solver
|
||||
from .solvers import create_G
|
||||
@@ -33,14 +34,8 @@ class Context:
|
||||
e.g. an MPI context.
|
||||
"""
|
||||
|
||||
def __init__(self, sim_config):
|
||||
"""
|
||||
Args:
|
||||
sim_config (SimConfig): Simulation level configuration object.
|
||||
"""
|
||||
|
||||
self.sim_config = sim_config
|
||||
self.model_range = range(sim_config.model_start, sim_config.model_end)
|
||||
def __init__(self):
|
||||
self.model_range = range(config.sim_config.model_start, config.sim_config.model_end)
|
||||
self.tsimend = 0
|
||||
self.tsimstart = 1
|
||||
|
||||
@@ -70,29 +65,25 @@ class NoMPIContext(Context):
|
||||
is parallelised using either OpenMP (CPU) or CUDA (GPU).
|
||||
"""
|
||||
|
||||
def __init__(self, sim_config):
|
||||
super().__init__(sim_config)
|
||||
|
||||
def _run(self):
|
||||
"""Specialise how the models are farmed out."""
|
||||
|
||||
for i in self.model_range:
|
||||
model_config = create_model_config(self.sim_config, i)
|
||||
write_model_config(i)
|
||||
|
||||
# Always create a solver for the first model.
|
||||
# The next model to run only gets a new solver if the
|
||||
# geometry is not re-used.
|
||||
if i != 0 and self.sim_config.geometry_fixed:
|
||||
model_config.reuse_geometry = True
|
||||
if i != 0 and config.sim_config.args.geometry_fixed:
|
||||
config.model_config[i].reuse_geometry = True
|
||||
else:
|
||||
G = create_G(self.sim_config)
|
||||
G = create_G()
|
||||
|
||||
model = ModelBuildRun(G, self.sim_config, model_config)
|
||||
model = ModelBuildRun(i, G)
|
||||
model.build()
|
||||
solver = create_solver(G)
|
||||
|
||||
solver = create_solver(G, self.sim_config)
|
||||
|
||||
if not self.sim_config.geometry_only:
|
||||
if not config.sim_config.args.geometry_only:
|
||||
model.solve(solver)
|
||||
|
||||
def make_time_report(self):
|
||||
@@ -111,8 +102,8 @@ class MPIContext(Context):
|
||||
or CUDA (GPU).
|
||||
"""
|
||||
|
||||
def __init__(self, sim_config):
|
||||
super().__init__(sim_config)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
from mpi4py import MPI
|
||||
|
||||
def _run(self):
|
||||
@@ -124,8 +115,8 @@ class MPIContext(Context):
|
||||
|
||||
class MPINoSpawnContext(Context):
|
||||
|
||||
def __init__(self, sim_config):
|
||||
super().__init__(sim_config)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
from mpi4py import MPI
|
||||
|
||||
def _run(self):
|
||||
@@ -135,21 +126,18 @@ class MPINoSpawnContext(Context):
|
||||
pass
|
||||
|
||||
|
||||
def create_context(sim_config):
|
||||
def create_context():
|
||||
"""Create a context in which to run the simulation. i.e MPI.
|
||||
|
||||
Args:
|
||||
sim_config (SimConfig): Simulation level configuration object.
|
||||
|
||||
Returns:
|
||||
context (Context): Context for the model to run in.
|
||||
"""
|
||||
|
||||
if sim_config.args.mpi:
|
||||
context = MPIContext(sim_config)
|
||||
elif sim_config.args.mpi_no_spawn:
|
||||
context = MPINoSpawnContext(sim_config)
|
||||
if config.sim_config.args.mpi:
|
||||
context = MPIContext()
|
||||
elif config.sim_config.args.mpi_no_spawn:
|
||||
context = MPINoSpawnContext()
|
||||
else:
|
||||
context = NoMPIContext(sim_config)
|
||||
context = NoMPIContext()
|
||||
|
||||
return context
|
||||
|
@@ -19,7 +19,7 @@
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
from .config import create_simulation_config
|
||||
from .config_parser import write_simulation_config
|
||||
from .contexts import create_context
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
||||
@@ -137,7 +137,7 @@ def run_main(args):
|
||||
args (Namespace): arguments from either API or CLI.
|
||||
"""
|
||||
|
||||
sim_config = create_simulation_config(args)
|
||||
context = create_context(sim_config)
|
||||
write_simulation_config(args)
|
||||
context = create_context()
|
||||
context.run()
|
||||
context.print_time_report()
|
||||
|
@@ -24,7 +24,6 @@ from colorama import Fore
|
||||
from colorama import Style
|
||||
init()
|
||||
import numpy as np
|
||||
from scipy.constants import c
|
||||
|
||||
import gprMax.config as config
|
||||
from .exceptions import GeneralError
|
||||
@@ -147,12 +146,12 @@ class FDTDGrid:
|
||||
|
||||
def initialise_field_arrays(self):
|
||||
"""Initialise arrays for the electric and magnetic field components."""
|
||||
self.Ex = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.dtypes['float_or_double'])
|
||||
self.Ey = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.dtypes['float_or_double'])
|
||||
self.Ez = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.dtypes['float_or_double'])
|
||||
self.Hx = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.dtypes['float_or_double'])
|
||||
self.Hy = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.dtypes['float_or_double'])
|
||||
self.Hz = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.dtypes['float_or_double'])
|
||||
self.Ex = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.Ey = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.Ez = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.Hx = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.Hy = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.Hz = np.zeros((self.nx + 1, self.ny + 1, self.nz + 1), dtype=config.sim_config.dtypes['float_or_double'])
|
||||
|
||||
def initialise_grids(self):
|
||||
"""Initialise all grids."""
|
||||
@@ -162,8 +161,8 @@ class FDTDGrid:
|
||||
|
||||
def initialise_std_update_coeff_arrays(self):
|
||||
"""Initialise arrays for storing update coefficients."""
|
||||
self.updatecoeffsE = np.zeros((len(self.materials), 5), dtype=config.dtypes['float_or_double'])
|
||||
self.updatecoeffsH = np.zeros((len(self.materials), 5), dtype=config.dtypes['float_or_double'])
|
||||
self.updatecoeffsE = np.zeros((len(self.materials), 5), dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.updatecoeffsH = np.zeros((len(self.materials), 5), dtype=config.sim_config.dtypes['float_or_double'])
|
||||
|
||||
def initialise_dispersive_arrays(self, dtype):
|
||||
"""Initialise arrays for storing coefficients when there are dispersive materials present."""
|
||||
@@ -183,7 +182,7 @@ class FDTDGrid:
|
||||
rigidarrays = (12 + 6) * self.nx * self.ny * self.nz * np.dtype(np.int8).itemsize
|
||||
|
||||
# 6 x field arrays + 6 x ID arrays
|
||||
fieldarrays = (6 + 6) * (self.nx + 1) * (self.ny + 1) * (self.nz + 1) * np.dtype(config.dtypes['float_or_double']).itemsize
|
||||
fieldarrays = (6 + 6) * (self.nx + 1) * (self.ny + 1) * (self.nz + 1) * np.dtype(config.sim_config.dtypes['float_or_double']).itemsize
|
||||
|
||||
# PML arrays
|
||||
pmlarrays = 0
|
||||
@@ -211,7 +210,7 @@ class FDTDGrid:
|
||||
"""Check if the required amount of memory (RAM) is available to build
|
||||
and/or run model on the host.
|
||||
"""
|
||||
if self.memoryusage > config.hostinfo['ram']:
|
||||
if self.memoryusage > config.sim_config.hostinfo['ram']:
|
||||
raise GeneralError(f"Memory (RAM) required ~{human_size(self.memoryusage)} \
|
||||
exceeds {human_size(config.hostinfo['ram'], a_kilobyte_is_1024_bytes=True)} detected!\n")
|
||||
|
||||
@@ -256,7 +255,7 @@ class FDTDGrid:
|
||||
|
||||
def calculate_dt(self):
|
||||
"""Calculate time step at the CFL limit."""
|
||||
self.dt = (1 / (c * np.sqrt(
|
||||
self.dt = (1 / (config.sim_config.em_consts['c'] * np.sqrt(
|
||||
(1 / self.dx) * (1 / self.dx) +
|
||||
(1 / self.dy) * (1 / self.dy) +
|
||||
(1 / self.dz) * (1 / self.dz))))
|
||||
|
@@ -294,9 +294,7 @@ def parse_hash_commands(model_config, G, scene):
|
||||
scene (Scene): Scene object.
|
||||
"""
|
||||
|
||||
sim_config = model_config.sim_config
|
||||
|
||||
with open(sim_config.input_file_path) as inputfile:
|
||||
with open(config.sim_config.input_file_path) as inputfile:
|
||||
|
||||
usernamespace = model_config.get_usernamespace()
|
||||
|
||||
@@ -312,7 +310,7 @@ def parse_hash_commands(model_config, G, scene):
|
||||
|
||||
# Write a file containing the input commands after Python or include
|
||||
# file commands have been processed
|
||||
if sim_config.args.write_processed:
|
||||
if config.sim_config.args.write_processed:
|
||||
write_processed_file(processedlines, model_config.appendmodelnumber, G)
|
||||
|
||||
user_objs = get_user_objects(processedlines, check=True)
|
||||
|
@@ -67,8 +67,8 @@ class Material:
|
||||
G (FDTDGrid): Holds essential parameters describing a model.
|
||||
"""
|
||||
|
||||
EA = (config.e0 * self.er / G.dt) + 0.5 * self.se
|
||||
EB = (config.e0 * self.er / G.dt) - 0.5 * self.se
|
||||
EA = (config.sim_config.em_consts['e0'] * self.er / G.dt) + 0.5 * self.se
|
||||
EB = (config.sim_config.em_consts['e0'] * self.er / G.dt) - 0.5 * self.se
|
||||
|
||||
if self.ID == 'pec' or self.se == float('inf'):
|
||||
self.CA = 0
|
||||
@@ -100,7 +100,7 @@ class Material:
|
||||
|
||||
class DispersiveMaterial(Material):
|
||||
"""Class to describe materials with frequency dependent properties, e.g.
|
||||
Debye, Drude, Lorenz
|
||||
Debye, Drude, Lorenz.
|
||||
"""
|
||||
|
||||
# Properties of water from: http://dx.doi.org/10.1109/TGRS.2006.873208
|
||||
@@ -161,8 +161,10 @@ class DispersiveMaterial(Material):
|
||||
self.zt[x] = (self.w[x] / self.q[x]) * (1 - self.eqt[x]) / G.dt
|
||||
self.zt2[x] = (self.w[x] / self.q[x]) * (1 - self.eqt2[x])
|
||||
|
||||
EA = (config.e0 * self.er / G.dt) + 0.5 * self.se - (config.e0 / G.dt) * np.sum(self.zt2.real)
|
||||
EB = (config.e0 * self.er / G.dt) - 0.5 * self.se - (config.e0 / G.dt) * np.sum(self.zt2.real)
|
||||
EA = ((config.sim_config.em_consts['e0'] * self.er / G.dt) + 0.5 * self.se -
|
||||
(config.sim_config.em_consts['e0'] / G.dt) * np.sum(self.zt2.real))
|
||||
EB = ((config.sim_config.em_consts['e0'] * self.er / G.dt) - 0.5 * self.se -
|
||||
(config.sim_config.em_consts['e0'] / G.dt) * np.sum(self.zt2.real))
|
||||
|
||||
self.CA = EB / EA
|
||||
self.CBx = (1 / G.dx) * 1 / EA
|
||||
@@ -186,7 +188,7 @@ class DispersiveMaterial(Material):
|
||||
er = self.er
|
||||
|
||||
w = 2 * np.pi * freq
|
||||
er += self.se / (w * config.e0)
|
||||
er += self.se / (w * config.sim_config.em_consts['e0'])
|
||||
if 'debye' in self.type:
|
||||
for pole in range(self.poles):
|
||||
er += self.deltaer[pole] / (1 + 1j * w * self.tau[pole])
|
||||
@@ -205,7 +207,7 @@ class DispersiveMaterial(Material):
|
||||
|
||||
def process_materials(G):
|
||||
"""Process complete list of materials - calculate update coefficients,
|
||||
store in arrays, and build text list of materials/properties
|
||||
store in arrays, and build text list of materials/properties
|
||||
|
||||
Args:
|
||||
G (FDTDGrid): Holds essential parameters describing a model.
|
||||
@@ -236,8 +238,8 @@ def process_materials(G):
|
||||
if hasattr(material, 'poles'):
|
||||
z = 0
|
||||
for pole in range(config.materials['maxpoles']):
|
||||
G.updatecoeffsdispersive[material.numID, z:z + 3] = (config.e0
|
||||
* material.eqt2[pole], material.eqt[pole], material.zt[pole])
|
||||
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
|
||||
|
@@ -79,10 +79,9 @@ log = logging.getLogger(__name__)
|
||||
class ModelBuildRun:
|
||||
"""Builds and runs (solves) a model."""
|
||||
|
||||
def __init__(self, G, sim_config, model_config):
|
||||
def __init__(self, i, G):
|
||||
self.i = i
|
||||
self.G = G
|
||||
self.sim_config = sim_config
|
||||
self.model_config = model_config
|
||||
# Monitor memory usage
|
||||
self.p = None
|
||||
|
||||
@@ -93,37 +92,34 @@ class ModelBuildRun:
|
||||
self.p = psutil.Process()
|
||||
|
||||
# Normal model reading/building process; bypassed if geometry information to be reused
|
||||
if self.model_config.reuse_geometry:
|
||||
self.reuse_geometry()
|
||||
else:
|
||||
self.build_geometry()
|
||||
self.reuse_geometry() if config.model_configs[self.i].reuse_geometry else self.build_geometry()
|
||||
|
||||
G = self.G
|
||||
|
||||
# Adjust position of simple sources and receivers if required
|
||||
if G.srcsteps[0] != 0 or G.srcsteps[1] != 0 or G.srcsteps[2] != 0:
|
||||
for source in itertools.chain(G.hertziandipoles, G.magneticdipoles):
|
||||
if self.model_config.i == 0:
|
||||
if config.model_configs[self.i].i == 0:
|
||||
if source.xcoord + G.srcsteps[0] * self.sim_config.model_end < 0 or source.xcoord + G.srcsteps[0] * self.sim_config.model_end > G.nx or source.ycoord + G.srcsteps[1] * self.sim_config.model_end < 0 or source.ycoord + G.srcsteps[1] * self.sim_config.model_end > G.ny or source.zcoord + G.srcsteps[2] * self.sim_config.model_end < 0 or source.zcoord + G.srcsteps[2] * self.sim_config.model_end > G.nz:
|
||||
raise GeneralError('Source(s) will be stepped to a position outside the domain.')
|
||||
source.xcoord = source.xcoordorigin + (self.model_config.i) * G.srcsteps[0]
|
||||
source.ycoord = source.ycoordorigin + (self.model_config.i) * G.srcsteps[1]
|
||||
source.zcoord = source.zcoordorigin + (self.model_config.i) * G.srcsteps[2]
|
||||
source.xcoord = source.xcoordorigin + (config.model_configs[self.i].i) * G.srcsteps[0]
|
||||
source.ycoord = source.ycoordorigin + (config.model_configs[self.i].i) * G.srcsteps[1]
|
||||
source.zcoord = source.zcoordorigin + (config.model_configs[self.i].i) * G.srcsteps[2]
|
||||
if G.rxsteps[0] != 0 or G.rxsteps[1] != 0 or G.rxsteps[2] != 0:
|
||||
for receiver in G.rxs:
|
||||
if self.model_config.i == 0:
|
||||
if config.model_configs[self.i].i == 0:
|
||||
if receiver.xcoord + G.rxsteps[0] * self.sim_config.model_end < 0 or receiver.xcoord + G.rxsteps[0] * self.sim_config.model_end > G.nx or receiver.ycoord + G.rxsteps[1] * self.sim_config.model_end < 0 or receiver.ycoord + G.rxsteps[1] * self.sim_config.model_end > G.ny or receiver.zcoord + G.rxsteps[2] * self.sim_config.model_end < 0 or receiver.zcoord + G.rxsteps[2] * self.sim_config.model_end > G.nz:
|
||||
raise GeneralError('Receiver(s) will be stepped to a position outside the domain.')
|
||||
receiver.xcoord = receiver.xcoordorigin + (self.model_config.i) * G.rxsteps[0]
|
||||
receiver.ycoord = receiver.ycoordorigin + (self.model_config.i) * G.rxsteps[1]
|
||||
receiver.zcoord = receiver.zcoordorigin + (self.model_config.i) * G.rxsteps[2]
|
||||
receiver.xcoord = receiver.xcoordorigin + (config.model_configs[self.i].i) * G.rxsteps[0]
|
||||
receiver.ycoord = receiver.ycoordorigin + (config.model_configs[self.i].i) * G.rxsteps[1]
|
||||
receiver.zcoord = receiver.zcoordorigin + (config.model_configs[self.i].i) * G.rxsteps[2]
|
||||
|
||||
# Write files for any geometry views and geometry object outputs
|
||||
if not (G.geometryviews or G.geometryobjectswrite) and self.sim_config.geometry_only and config.is_messages():
|
||||
log.warning(Fore.RED + f'\nNo geometry views or geometry objects to output found.' + Style.RESET_ALL)
|
||||
if config.is_messages(): print()
|
||||
for i, geometryview in enumerate(G.geometryviews):
|
||||
geometryview.set_filename(self.model_config.appendmodelnumber)
|
||||
geometryview.set_filename(config.model_configs[self.i].appendmodelnumber)
|
||||
pbar = tqdm(total=geometryview.datawritesize, unit='byte', unit_scale=True, desc='Writing geometry view file {}/{}, {}'.format(i + 1, len(G.geometryviews), os.path.split(geometryview.filename)[1]), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars'])
|
||||
geometryview.write_vtk(G, pbar)
|
||||
pbar.close()
|
||||
@@ -138,20 +134,18 @@ class ModelBuildRun:
|
||||
# tsolve = 0
|
||||
|
||||
def build_geometry(self):
|
||||
model_config = self.model_config
|
||||
sim_config = self.sim_config
|
||||
G = self.G
|
||||
|
||||
log.info(model_config.next_model)
|
||||
log.info(config.model_configs[self.i].next_model)
|
||||
|
||||
scene = self.build_scene()
|
||||
|
||||
# Combine available grids
|
||||
grids = [G] + G.subgrids
|
||||
gridbuilders = [GridBuilder(grid, self.printer) for grid in grids]
|
||||
gridbuilders = [GridBuilder(grid) for grid in grids]
|
||||
|
||||
for gb in gridbuilders:
|
||||
gb.printer.print(pml_information(gb.grid))
|
||||
pml_information(gb.grid)
|
||||
gb.build_pmls()
|
||||
gb.build_components()
|
||||
gb.tm_grid_update()
|
||||
@@ -159,7 +153,7 @@ class ModelBuildRun:
|
||||
gb.grid.initialise_std_update_coeff_arrays()
|
||||
|
||||
# Set datatype for dispersive arrays if there are any dispersive materials.
|
||||
if self.model_config.materials['maxpoles'] != 0:
|
||||
if config.model_configs[self.i].materials['maxpoles'] != 0:
|
||||
drudelorentz = any([m for m in G.materials if 'drude' in m.type or 'lorentz' in m.type])
|
||||
if drudelorentz:
|
||||
config.materials['dispersivedtype'] = config.dtypes['complex']
|
||||
@@ -220,22 +214,22 @@ class ModelBuildRun:
|
||||
G = self.G
|
||||
# Reset iteration number
|
||||
G.iteration = 0
|
||||
self.model_config.inputfilestr = f'\n--- Model {self.model_config.appendmodelnumber}/{self.sim_config.model_end}, \
|
||||
config.model_configs[self.i].inputfilestr = f'\n--- Model {config.model_configs[self.i].appendmodelnumber}/{self.sim_config.model_end}, \
|
||||
input file (not re-processed, i.e. geometry fixed): {self.sim_config.input_file_path}'
|
||||
log.info(Fore.GREEN + f"{self.model_config.inputfilestr} {'-' * (get_terminal_width() - 1 - len(self.model_config.inputfilestr))}" + Style.RESET_ALL)
|
||||
log.info(Fore.GREEN + f"{config.model_configs[self.i].inputfilestr} {'-' * (get_terminal_width() - 1 - len(config.model_configs[self.i].inputfilestr))}" + Style.RESET_ALL)
|
||||
for grid in [G] + G.subgrids:
|
||||
grid.reset_fields()
|
||||
|
||||
def build_scene(self):
|
||||
G = self.G
|
||||
# API for multiple scenes / model runs
|
||||
scene = self.model_config.get_scene()
|
||||
scene = config.model_configs[self.i].get_scene()
|
||||
|
||||
# If there is no scene - process the hash commands instead
|
||||
if not scene:
|
||||
scene = Scene()
|
||||
# Parse the input file into user objects and add them to the scene
|
||||
scene = parse_hash_commands(self.model_config, G, scene)
|
||||
scene = parse_hash_commands(config.model_configs[self.i], G, scene)
|
||||
|
||||
# Creates the internal simulation objects.
|
||||
scene.create_internal_objects(G)
|
||||
@@ -251,7 +245,7 @@ class ModelBuildRun:
|
||||
except FileExistsError:
|
||||
pass
|
||||
# Modify the output path (hack)
|
||||
self.model_config.output_file_path_ext = Path(self.G.outputdirectory, self.model_config.output_file_path_ext)
|
||||
config.model_configs[self.i].output_file_path_ext = Path(self.G.outputdirectory, config.model_configs[self.i].output_file_path_ext)
|
||||
|
||||
def write_output_data(self):
|
||||
"""Write output data, i.e. field data for receivers and snapshots
|
||||
@@ -261,19 +255,19 @@ class ModelBuildRun:
|
||||
G = self.G
|
||||
|
||||
# Write an output file in HDF5 format
|
||||
write_hdf5_outputfile(self.model_config.output_file_path_ext, G)
|
||||
write_hdf5_outputfile(config.model_configs[self.i].output_file_path_ext, G)
|
||||
|
||||
# Write any snapshots to file
|
||||
if G.snapshots:
|
||||
# Create directory and construct filename from user-supplied name
|
||||
# and model run number
|
||||
snapshotdir = self.model_config.snapshot_dir
|
||||
snapshotdir = config.model_configs[self.i].snapshot_dir
|
||||
if not os.path.exists(snapshotdir):
|
||||
os.mkdir(snapshotdir)
|
||||
|
||||
log.info('')
|
||||
for i, snap in enumerate(G.snapshots):
|
||||
fn = snapshotdir / Path(self.model_config.output_file_path.stem + '_' + snap.basefilename)
|
||||
fn = snapshotdir / Path(config.model_configs[self.i].output_file_path.stem + '_' + snap.basefilename)
|
||||
snap.filename = fn.with_suffix('.vti')
|
||||
pbar = tqdm(total=snap.vtkdatawritesize, leave=True, unit='byte', unit_scale=True, desc='Writing snapshot file {} of {}, {}'.format(i + 1, len(G.snapshots), os.path.split(snap.filename)[1]), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars'])
|
||||
snap.write_vtk_imagedata(pbar, G)
|
||||
@@ -304,13 +298,13 @@ class ModelBuildRun:
|
||||
G = self.G
|
||||
|
||||
if config.is_messages():
|
||||
iterator = tqdm(range(G.iterations), desc='Running simulation, model ' + str(self.model_config
|
||||
iterator = tqdm(range(G.iterations), desc='Running simulation, model ' + str(config.model_configs[self.i]
|
||||
.i + 1) + '/' + str(self.sim_config.model_end), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars'])
|
||||
else:
|
||||
iterator = range(0, G.iterations)
|
||||
|
||||
self.create_output_directory()
|
||||
log.info(f'Output file: {self.model_config.output_file_path_ext}\n')
|
||||
log.info(f'Output file: {config.model_configs[self.i].output_file_path_ext}\n')
|
||||
|
||||
# Run solver
|
||||
tsolve = self.solve(solver)
|
||||
@@ -325,15 +319,14 @@ class ModelBuildRun:
|
||||
|
||||
|
||||
class GridBuilder:
|
||||
def __init__(self, grid, printer):
|
||||
def __init__(self, grid):
|
||||
self.grid = grid
|
||||
self.printer = printer
|
||||
|
||||
def build_pmls(self):
|
||||
grid = self.grid
|
||||
|
||||
# Build the PMLS
|
||||
pbar = tqdm(total=sum(1 for value in grid.pmlthickness.values() if value > 0), desc='Building {} Grid PML boundaries'.format(self.grid.name), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars'])
|
||||
pbar = tqdm(total=sum(1 for value in grid.pmlthickness.values() if value > 0), desc='Building {} Grid PML boundaries'.format(self.grid.name), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.sim_config.general['progressbars'])
|
||||
for pml_id, thickness in grid.pmlthickness.items():
|
||||
if thickness > 0:
|
||||
build_pml(grid, pml_id, thickness)
|
||||
@@ -344,7 +337,7 @@ class GridBuilder:
|
||||
# Build the model, i.e. set the material properties (ID) for every edge
|
||||
# of every Yee cell
|
||||
log.info('')
|
||||
pbar = tqdm(total=2, desc='Building {} Grid'.format(self.grid.name), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars'])
|
||||
pbar = tqdm(total=2, desc='Building {} Grid'.format(self.grid.name), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.sim_config.general['progressbars'])
|
||||
build_electric_components(self.grid.solid, self.grid.rigidE, self.grid.ID, self.grid)
|
||||
pbar.update()
|
||||
build_magnetic_components(self.grid.solid, self.grid.rigidH, self.grid.ID, self.grid)
|
||||
@@ -352,11 +345,11 @@ class GridBuilder:
|
||||
pbar.close()
|
||||
|
||||
def tm_grid_update(self):
|
||||
if '2D TMx' == config.general['mode']:
|
||||
if '2D TMx' == config.sim_config.general['mode']:
|
||||
self.grid.tmx()
|
||||
elif '2D TMy' == config.general['mode']:
|
||||
elif '2D TMy' == config.sim_config.general['mode']:
|
||||
self.grid.tmy()
|
||||
elif '2D TMz' == config.general['mode']:
|
||||
elif '2D TMz' == config.sim_config.general['mode']:
|
||||
self.grid.tmz()
|
||||
|
||||
def update_voltage_source_materials(self):
|
||||
|
@@ -80,7 +80,7 @@ class CFS:
|
||||
|
||||
# Calculation of the maximum value of sigma from http://dx.doi.org/10.1109/8.546249
|
||||
m = CFSParameter.scalingprofiles[self.sigma.scalingprofile]
|
||||
self.sigma.max = (0.8 * (m + 1)) / (config.general['z0'] * d * np.sqrt(er * mr))
|
||||
self.sigma.max = (0.8 * (m + 1)) / (config.sim_config.em_consts['z0'] * d * np.sqrt(er * mr))
|
||||
|
||||
def scaling_polynomial(self, order, Evalues, Hvalues):
|
||||
"""Applies the polynomial to be used for the scaling profile for
|
||||
@@ -123,8 +123,8 @@ class CFS:
|
||||
"""
|
||||
|
||||
# Extra cell of thickness added to allow correct scaling of electric and magnetic values
|
||||
Evalues = np.zeros(thickness + 1, dtype=config.dtypes['float_or_double'])
|
||||
Hvalues = np.zeros(thickness + 1, dtype=config.dtypes['float_or_double'])
|
||||
Evalues = np.zeros(thickness + 1, dtype=config.sim_config.dtypes['float_or_double'])
|
||||
Hvalues = np.zeros(thickness + 1, dtype=config.sim_config.dtypes['float_or_double'])
|
||||
|
||||
if parameter.scalingprofile == 'constant':
|
||||
Evalues += parameter.max
|
||||
@@ -215,31 +215,31 @@ class PML:
|
||||
|
||||
if self.direction[0] == 'x':
|
||||
self.EPhi1 = np.zeros((len(self.CFS), self.nx + 1, self.ny, self.nz + 1),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.EPhi2 = np.zeros((len(self.CFS), self.nx + 1, self.ny + 1, self.nz),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.HPhi1 = np.zeros((len(self.CFS), self.nx, self.ny + 1, self.nz),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.HPhi2 = np.zeros((len(self.CFS), self.nx, self.ny, self.nz + 1),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
elif self.direction[0] == 'y':
|
||||
self.EPhi1 = np.zeros((len(self.CFS), self.nx, self.ny + 1, self.nz + 1),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.EPhi2 = np.zeros((len(self.CFS), self.nx + 1, self.ny + 1, self.nz),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.HPhi1 = np.zeros((len(self.CFS), self.nx + 1, self.ny, self.nz),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.HPhi2 = np.zeros((len(self.CFS), self.nx, self.ny, self.nz + 1),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
elif self.direction[0] == 'z':
|
||||
self.EPhi1 = np.zeros((len(self.CFS), self.nx, self.ny + 1, self.nz + 1),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.EPhi2 = np.zeros((len(self.CFS), self.nx + 1, self.ny, self.nz + 1),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.HPhi1 = np.zeros((len(self.CFS), self.nx + 1, self.ny, self.nz),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.HPhi2 = np.zeros((len(self.CFS), self.nx, self.ny + 1, self.nz),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.sim_config.dtypes['float_or_double'])
|
||||
|
||||
def calculate_update_coeffs(self, er, mr, G):
|
||||
"""Calculates electric and magnetic update coefficients for the PML.
|
||||
@@ -251,21 +251,21 @@ class PML:
|
||||
"""
|
||||
|
||||
self.ERA = np.zeros((len(self.CFS), self.thickness),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.ERB = np.zeros((len(self.CFS), self.thickness),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.ERE = np.zeros((len(self.CFS), self.thickness),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.ERF = np.zeros((len(self.CFS), self.thickness),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.HRA = np.zeros((len(self.CFS), self.thickness),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.HRB = np.zeros((len(self.CFS), self.thickness),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.HRE = np.zeros((len(self.CFS), self.thickness),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
self.HRF = np.zeros((len(self.CFS), self.thickness),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
|
||||
for x, cfs in enumerate(self.CFS):
|
||||
if not cfs.sigma.max:
|
||||
@@ -277,33 +277,33 @@ class PML:
|
||||
# Define different parameters depending on PML formulation
|
||||
if G.pmlformulation == 'HORIPML':
|
||||
# HORIPML electric update coefficients
|
||||
tmp = (2 * config.e0 * Ekappa) + G.dt * (Ealpha * Ekappa + Esigma)
|
||||
self.ERA[x, :] = (2 * config.e0 + G.dt * Ealpha) / tmp
|
||||
self.ERB[x, :] = (2 * config.e0 * Ekappa) / tmp
|
||||
self.ERE[x, :] = ((2 * config.e0 * Ekappa) - G.dt
|
||||
tmp = (2 * config.sim_config.em_consts['e0'] * Ekappa) + G.dt * (Ealpha * Ekappa + Esigma)
|
||||
self.ERA[x, :] = (2 * config.sim_config.em_consts['e0'] + G.dt * Ealpha) / tmp
|
||||
self.ERB[x, :] = (2 * config.sim_config.em_consts['e0'] * Ekappa) / tmp
|
||||
self.ERE[x, :] = ((2 * config.sim_config.em_consts['e0'] * Ekappa) - G.dt
|
||||
* (Ealpha * Ekappa + Esigma)) / tmp
|
||||
self.ERF[x, :] = (2 * Esigma * G.dt) / (Ekappa * tmp)
|
||||
|
||||
# HORIPML magnetic update coefficients
|
||||
tmp = (2 * config.e0 * Hkappa) + G.dt * (Halpha * Hkappa + Hsigma)
|
||||
self.HRA[x, :] = (2 * config.e0 + G.dt * Halpha) / tmp
|
||||
self.HRB[x, :] = (2 * config.e0 * Hkappa) / tmp
|
||||
self.HRE[x, :] = ((2 * config.e0 * Hkappa) - G.dt
|
||||
tmp = (2 * config.sim_config.em_consts['e0'] * Hkappa) + G.dt * (Halpha * Hkappa + Hsigma)
|
||||
self.HRA[x, :] = (2 * config.sim_config.em_consts['e0'] + G.dt * Halpha) / tmp
|
||||
self.HRB[x, :] = (2 * config.sim_config.em_consts['e0'] * Hkappa) / tmp
|
||||
self.HRE[x, :] = ((2 * config.sim_config.em_consts['e0'] * Hkappa) - G.dt
|
||||
* (Halpha * Hkappa + Hsigma)) / tmp
|
||||
self.HRF[x, :] = (2 * Hsigma * G.dt) / (Hkappa * tmp)
|
||||
|
||||
elif G.pmlformulation == 'MRIPML':
|
||||
tmp = 2 * config.e0 + G.dt * Ealpha
|
||||
tmp = 2 * config.sim_config.em_consts['e0'] + G.dt * Ealpha
|
||||
self.ERA[x, :] = Ekappa + (G.dt * Esigma) / tmp
|
||||
self.ERB[x, :] = (2 * config.e0) / tmp
|
||||
self.ERE[x, :] = ((2 * config.e0) - G.dt * Ealpha) / tmp
|
||||
self.ERB[x, :] = (2 * config.sim_config.em_consts['e0']) / tmp
|
||||
self.ERE[x, :] = ((2 * config.sim_config.em_consts['e0']) - G.dt * Ealpha) / tmp
|
||||
self.ERF[x, :] = (2 * Esigma * G.dt) / tmp
|
||||
|
||||
# MRIPML magnetic update coefficients
|
||||
tmp = 2 * config.e0 + G.dt * Halpha
|
||||
tmp = 2 * config.sim_config.em_consts['e0'] + G.dt * Halpha
|
||||
self.HRA[x, :] = Hkappa + (G.dt * Hsigma) / tmp
|
||||
self.HRB[x, :] = (2 * config.e0) / tmp
|
||||
self.HRE[x, :] = ((2 * config.e0) - G.dt * Halpha) / tmp
|
||||
self.HRB[x, :] = (2 * config.sim_config.em_consts['e0']) / tmp
|
||||
self.HRE[x, :] = ((2 * config.sim_config.sim_config.em_consts['e0']) - G.dt * Halpha) / tmp
|
||||
self.HRF[x, :] = (2 * Hsigma * G.dt) / tmp
|
||||
|
||||
def update_electric(self, G):
|
||||
@@ -316,7 +316,7 @@ class PML:
|
||||
pmlmodule = 'gprMax.cython.pml_updates_electric_' + G.pmlformulation
|
||||
func = getattr(import_module(pmlmodule), 'order' + str(len(self.CFS)) + '_' + self.direction)
|
||||
func(self.xs, self.xf, self.ys, self.yf, self.zs, self.zf,
|
||||
config.hostinfo['ompthreads'], G.updatecoeffsE, G.ID,
|
||||
config.sim_config.hostinfo['ompthreads'], G.updatecoeffsE, G.ID,
|
||||
G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz, self.EPhi1, self.EPhi2,
|
||||
self.ERA, self.ERB, self.ERE, self.ERF, self.d)
|
||||
|
||||
@@ -330,7 +330,7 @@ class PML:
|
||||
pmlmodule = 'gprMax.cython.pml_updates_magnetic_' + G.pmlformulation
|
||||
func = getattr(import_module(pmlmodule), 'order' + str(len(self.CFS)) + '_' + self.direction)
|
||||
func(self.xs, self.xf, self.ys, self.yf, self.zs, self.zf,
|
||||
config.hostinfo['ompthreads'], G.updatecoeffsH, G.ID,
|
||||
config.sim_config.hostinfo['ompthreads'], G.updatecoeffsH, G.ID,
|
||||
G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz, self.HPhi1, self.HPhi2,
|
||||
self.HRA, self.HRB, self.HRE, self.HRF, self.d)
|
||||
|
||||
|
@@ -40,18 +40,9 @@ class Snapshot:
|
||||
bpg = None
|
||||
|
||||
# Set string for byte order
|
||||
if sys.byteorder == 'little':
|
||||
byteorder = 'LittleEndian'
|
||||
else:
|
||||
byteorder = 'BigEndian'
|
||||
byteorder = 'LittleEndian' if sys.byteorder == 'little' else 'BigEndian'
|
||||
|
||||
|
||||
# Set format text and string depending on float type
|
||||
if config.dtypes['float_or_double'] == np.float32:
|
||||
floatname = 'Float32'
|
||||
floatstring = 'f'
|
||||
elif config.dtypes['float_or_double'] == np.float64:
|
||||
floatname = 'Float64'
|
||||
floatstring = 'd'
|
||||
|
||||
def __init__(self, xs=None, ys=None, zs=None, xf=None, yf=None, zf=None,
|
||||
dx=None, dy=None, dz=None, time=None, filename=None):
|
||||
@@ -63,6 +54,14 @@ class Snapshot:
|
||||
filename (str): Filename to save to.
|
||||
"""
|
||||
|
||||
# Set format text and string depending on float type
|
||||
if config.sim_config.dtypes['float_or_double'] == np.float32:
|
||||
self.floatname = 'Float32'
|
||||
self.floatstring = 'f'
|
||||
elif config.sim_config.dtypes['float_or_double'] == np.float64:
|
||||
self.floatname = 'Float64'
|
||||
self.floatstring = 'd'
|
||||
|
||||
self.fieldoutputs = {'electric': True, 'magnetic': True}
|
||||
self.xs = xs
|
||||
self.ys = ys
|
||||
@@ -156,14 +155,14 @@ class Snapshot:
|
||||
|
||||
if self.fieldoutputs['electric'] and self.fieldoutputs['magnetic']:
|
||||
self.filehandle.write('<CellData Vectors="E-field H-field">\n'.encode('utf-8'))
|
||||
self.filehandle.write(f'<DataArray type="{Snapshot.floatname}" Name="E-field" NumberOfComponents="3" format="appended" offset="0" />\n'.encode('utf-8'))
|
||||
self.filehandle.write(f'<DataArray type="{Snapshot.floatname}" Name="H-field" NumberOfComponents="3" format="appended" offset="{hfield_offset}" />\n'.encode('utf-8'))
|
||||
self.filehandle.write(f'<DataArray type="{self.floatname}" Name="E-field" NumberOfComponents="3" format="appended" offset="0" />\n'.encode('utf-8'))
|
||||
self.filehandle.write(f'<DataArray type="{self.floatname}" Name="H-field" NumberOfComponents="3" format="appended" offset="{hfield_offset}" />\n'.encode('utf-8'))
|
||||
elif self.fieldoutputs['electric']:
|
||||
self.filehandle.write('<CellData Vectors="E-field">\n'.encode('utf-8'))
|
||||
self.filehandle.write(f'<DataArray type="{Snapshot.floatname}" Name="E-field" NumberOfComponents="3" format="appended" offset="0" />\n'.encode('utf-8'))
|
||||
self.filehandle.write(f'<DataArray type="{self.floatname}" Name="E-field" NumberOfComponents="3" format="appended" offset="0" />\n'.encode('utf-8'))
|
||||
elif self.fieldoutputs['magnetic']:
|
||||
self.filehandle.write('<CellData Vectors="H-field">\n'.encode('utf-8'))
|
||||
self.filehandle.write(f'<DataArray type="{Snapshot.floatname}" Name="H-field" NumberOfComponents="3" format="appended" offset="0" />\n'.encode('utf-8'))
|
||||
self.filehandle.write(f'<DataArray type="{self.floatname}" Name="H-field" NumberOfComponents="3" format="appended" offset="0" />\n'.encode('utf-8'))
|
||||
|
||||
self.filehandle.write('</CellData>\n</Piece>\n</ImageData>\n<AppendedData encoding="raw">\n_'.encode('utf-8'))
|
||||
|
||||
|
@@ -24,19 +24,16 @@ from .updates import CPUUpdates
|
||||
from .updates import CUDAUpdates
|
||||
|
||||
|
||||
def create_G(sim_config):
|
||||
def create_G():
|
||||
"""Create grid object according to solver.
|
||||
|
||||
Args:
|
||||
sim_config (SimConfig): Simulation level configuration object.
|
||||
|
||||
Returns:
|
||||
G (FDTDGrid): Holds essential parameters describing the model.
|
||||
"""
|
||||
|
||||
if sim_config.general['cuda']:
|
||||
if config.sim_config.general['cuda']:
|
||||
G = CUDAGrid()
|
||||
elif sim_config.subgrid:
|
||||
elif config.sim_config.subgrid:
|
||||
G = FDTDGrid()
|
||||
else:
|
||||
G = FDTDGrid()
|
||||
@@ -44,21 +41,20 @@ def create_G(sim_config):
|
||||
return G
|
||||
|
||||
|
||||
def create_solver(G, sim_config):
|
||||
def create_solver(G):
|
||||
"""Create configured solver object.
|
||||
|
||||
Args:
|
||||
G (FDTDGrid): Holds essential parameters describing the model.
|
||||
sim_config (SimConfig): simulation level configuration object.
|
||||
|
||||
Returns:
|
||||
solver (Solver): solver object.
|
||||
"""
|
||||
|
||||
if sim_config.gpu:
|
||||
if config.sim_config.gpu:
|
||||
updates = CUDAUpdates(G)
|
||||
solver = Solver(updates)
|
||||
elif sim_config.subgrid:
|
||||
elif config.sim_config.subgrid:
|
||||
updates = create_subgrid_updates(G)
|
||||
solver = Solver(updates, hsg=True)
|
||||
# A large range of different functions exist to advance the time step for
|
||||
|
@@ -51,11 +51,11 @@ class Source:
|
||||
"""
|
||||
# Waveform values for electric sources - calculated half a timestep later
|
||||
self.waveformvaluesJ = np.zeros((G.iterations),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
|
||||
# Waveform values for magnetic sources
|
||||
self.waveformvaluesM = np.zeros((G.iterations),
|
||||
dtype=config.dtypes['float_or_double'])
|
||||
dtype=config.sim_config.dtypes['float_or_double'])
|
||||
|
||||
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
|
||||
|
||||
|
@@ -36,6 +36,7 @@ from colorama import Style
|
||||
init()
|
||||
import numpy as np
|
||||
|
||||
import gprMax.config as config
|
||||
from .exceptions import GeneralError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -90,7 +91,7 @@ def logo(version):
|
||||
@contextmanager
|
||||
def open_path_file(path_or_file):
|
||||
"""Accepts either a path as a string or a file object and returns a file
|
||||
object (http://stackoverflow.com/a/6783680).
|
||||
object (http://stackoverflow.com/a/6783680).
|
||||
|
||||
Args:
|
||||
path_or_file: path as a string or a file object.
|
||||
@@ -361,7 +362,7 @@ def set_openmp_threads():
|
||||
# os.environ['OMP_DISPLAY_ENV'] = 'TRUE'
|
||||
|
||||
# Catch bug with Windows Subsystem for Linux (https://github.com/Microsoft/BashOnWindows/issues/785)
|
||||
if 'Microsoft' in config.hostinfo['osversion']:
|
||||
if 'Microsoft' in config.sim_config.hostinfo['osversion']:
|
||||
os.environ['KMP_AFFINITY'] = 'disabled'
|
||||
del os.environ['OMP_PLACES']
|
||||
del os.environ['OMP_PROC_BIND']
|
||||
@@ -370,8 +371,8 @@ def set_openmp_threads():
|
||||
nthreads = int(os.environ.get('OMP_NUM_THREADS'))
|
||||
else:
|
||||
# Set number of threads to number of physical CPU cores
|
||||
nthreads = config.hostinfo['physicalcores']
|
||||
os.environ['OMP_NUM_THREADS'] = str(G.nthreads)
|
||||
nthreads = config.sim_config.hostinfo['physicalcores']
|
||||
os.environ['OMP_NUM_THREADS'] = str(nthreads)
|
||||
|
||||
return nthreads
|
||||
|
||||
|
在新工单中引用
屏蔽一个用户