你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 23:14:03 +08:00
changes
这个提交包含在:
@@ -1,164 +1,164 @@
|
|||||||
"""Class for add_grass command."""
|
"""Class for add_grass command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..utilities import round_value
|
from ..utilities import round_value
|
||||||
from ..materials import Material
|
from ..materials import Material
|
||||||
from ..fractals import FractalSurface
|
from ..fractals import FractalSurface
|
||||||
from ..fractals import Grass
|
from ..fractals import Grass
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class AddGrass(UserObjectGeometry):
|
class AddGrass(UserObjectGeometry):
|
||||||
"""User class for Grass command."""
|
"""User class for Grass command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 12
|
self.order = 12
|
||||||
self.hash = '#add_grass'
|
self.hash = '#add_grass'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
"""Add Grass to fractal box."""
|
"""Add Grass to fractal box."""
|
||||||
try:
|
try:
|
||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
fractal_box_id = self.kwargs['fractal_box_id']
|
fractal_box_id = self.kwargs['fractal_box_id']
|
||||||
frac_dim = self.kwargs['frac_dim']
|
frac_dim = self.kwargs['frac_dim']
|
||||||
limits = self.kwargs['limits']
|
limits = self.kwargs['limits']
|
||||||
n_blades = self.kwargs['n_blades']
|
n_blades = self.kwargs['n_blades']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' requires at least eleven parameters')
|
raise CmdInputError(self.__str__() + ' requires at least eleven parameters')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
seed = self.kwargs['seed']
|
seed = self.kwargs['seed']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
seed = None
|
seed = None
|
||||||
|
|
||||||
# grab the correct fractal volume
|
# grab the correct fractal volume
|
||||||
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
|
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
|
||||||
if volumes:
|
if volumes:
|
||||||
volume = volumes[0]
|
volume = volumes[0]
|
||||||
else:
|
else:
|
||||||
raise CmdInputError(self.__str__() + ' Cant find FractalBox {}'.format(fractal_box_id))
|
raise CmdInputError(self.__str__() + ' Cant find FractalBox {}'.format(fractal_box_id))
|
||||||
|
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
xs, ys, zs = p1
|
xs, ys, zs = p1
|
||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
if frac_dim < 0:
|
if frac_dim < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal dimension')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal dimension')
|
||||||
if limits[0] < 0 or limits[1] < 0:
|
if limits[0] < 0 or limits[1] < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the minimum and maximum heights for grass blades')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the minimum and maximum heights for grass blades')
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
if xs == xf:
|
if xs == xf:
|
||||||
if ys == yf or zs == zf:
|
if ys == yf or zs == zf:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
if xs != volume.xs and xs != volume.xf:
|
if xs != volume.xs and xs != volume.xf:
|
||||||
raise CmdInputError(self.__str__() + ' must specify external surfaces on a fractal box')
|
raise CmdInputError(self.__str__() + ' must specify external surfaces on a fractal box')
|
||||||
fractalrange = (round_value(limits[0] / grid.dx), round_value(limits[1] / grid.dx))
|
fractalrange = (round_value(limits[0] / grid.dx), round_value(limits[1] / grid.dx))
|
||||||
# xminus surface
|
# xminus surface
|
||||||
if xs == volume.xs:
|
if xs == volume.xs:
|
||||||
raise CmdInputError(self.__str__() + ' grass can only be specified on surfaces in the positive axis direction')
|
raise CmdInputError(self.__str__() + ' grass can only be specified on surfaces in the positive axis direction')
|
||||||
# xplus surface
|
# xplus surface
|
||||||
elif xf == volume.xf:
|
elif xf == volume.xf:
|
||||||
if fractalrange[1] > grid.nx:
|
if fractalrange[1] > grid.nx:
|
||||||
raise CmdInputError(self.__str__() + ' cannot apply grass to fractal box as it would exceed the domain size in the x direction')
|
raise CmdInputError(self.__str__() + ' cannot apply grass to fractal box as it would exceed the domain size in the x direction')
|
||||||
requestedsurface = 'xplus'
|
requestedsurface = 'xplus'
|
||||||
|
|
||||||
elif ys == yf:
|
elif ys == yf:
|
||||||
if xs == xf or zs == zf:
|
if xs == xf or zs == zf:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
if ys != volume.ys and ys != volume.yf:
|
if ys != volume.ys and ys != volume.yf:
|
||||||
raise CmdInputError(self.__str__() + ' must specify external surfaces on a fractal box')
|
raise CmdInputError(self.__str__() + ' must specify external surfaces on a fractal box')
|
||||||
fractalrange = (round_value(limits[0] / grid.dy), round_value(limits[1] / grid.dy))
|
fractalrange = (round_value(limits[0] / grid.dy), round_value(limits[1] / grid.dy))
|
||||||
# yminus surface
|
# yminus surface
|
||||||
if ys == volume.ys:
|
if ys == volume.ys:
|
||||||
raise CmdInputError(self.__str__() + ' grass can only be specified on surfaces in the positive axis direction')
|
raise CmdInputError(self.__str__() + ' grass can only be specified on surfaces in the positive axis direction')
|
||||||
# yplus surface
|
# yplus surface
|
||||||
elif yf == volume.yf:
|
elif yf == volume.yf:
|
||||||
if fractalrange[1] > grid.ny:
|
if fractalrange[1] > grid.ny:
|
||||||
raise CmdInputError(self.__str__() + ' cannot apply grass to fractal box as it would exceed the domain size in the y direction')
|
raise CmdInputError(self.__str__() + ' cannot apply grass to fractal box as it would exceed the domain size in the y direction')
|
||||||
requestedsurface = 'yplus'
|
requestedsurface = 'yplus'
|
||||||
|
|
||||||
elif zs == zf:
|
elif zs == zf:
|
||||||
if xs == xf or ys == yf:
|
if xs == xf or ys == yf:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
if zs != volume.zs and zs != volume.zf:
|
if zs != volume.zs and zs != volume.zf:
|
||||||
raise CmdInputError(self.__str__() + ' must specify external surfaces on a fractal box')
|
raise CmdInputError(self.__str__() + ' must specify external surfaces on a fractal box')
|
||||||
fractalrange = (round_value(limits[0] / grid.dz), round_value(limits[1] / grid.dz))
|
fractalrange = (round_value(limits[0] / grid.dz), round_value(limits[1] / grid.dz))
|
||||||
# zminus surface
|
# zminus surface
|
||||||
if zs == volume.zs:
|
if zs == volume.zs:
|
||||||
raise CmdInputError(self.__str__() + ' grass can only be specified on surfaces in the positive axis direction')
|
raise CmdInputError(self.__str__() + ' grass can only be specified on surfaces in the positive axis direction')
|
||||||
# zplus surface
|
# zplus surface
|
||||||
elif zf == volume.zf:
|
elif zf == volume.zf:
|
||||||
if fractalrange[1] > grid.nz:
|
if fractalrange[1] > grid.nz:
|
||||||
raise CmdInputError(self.__str__() + ' cannot apply grass to fractal box as it would exceed the domain size in the z direction')
|
raise CmdInputError(self.__str__() + ' cannot apply grass to fractal box as it would exceed the domain size in the z direction')
|
||||||
requestedsurface = 'zplus'
|
requestedsurface = 'zplus'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
|
|
||||||
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim)
|
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim)
|
||||||
surface.ID = 'grass'
|
surface.ID = 'grass'
|
||||||
surface.surfaceID = requestedsurface
|
surface.surfaceID = requestedsurface
|
||||||
surface.seed = seed
|
surface.seed = seed
|
||||||
|
|
||||||
# Set the fractal range to scale the fractal distribution between zero and one
|
# Set the fractal range to scale the fractal distribution between zero and one
|
||||||
surface.fractalrange = (0, 1)
|
surface.fractalrange = (0, 1)
|
||||||
surface.operatingonID = volume.ID
|
surface.operatingonID = volume.ID
|
||||||
surface.generate_fractal_surface(grid)
|
surface.generate_fractal_surface(grid)
|
||||||
if n_blades > surface.fractalsurface.shape[0] * surface.fractalsurface.shape[1]:
|
if n_blades > surface.fractalsurface.shape[0] * surface.fractalsurface.shape[1]:
|
||||||
raise CmdInputError(self.__str__() + ' the specified surface is not large enough for the number of grass blades/roots specified')
|
raise CmdInputError(self.__str__() + ' the specified surface is not large enough for the number of grass blades/roots specified')
|
||||||
|
|
||||||
# Scale the distribution so that the summation is equal to one, i.e. a probability distribution
|
# Scale the distribution so that the summation is equal to one, i.e. a probability distribution
|
||||||
surface.fractalsurface = surface.fractalsurface / np.sum(surface.fractalsurface)
|
surface.fractalsurface = surface.fractalsurface / np.sum(surface.fractalsurface)
|
||||||
|
|
||||||
# Set location of grass blades using probability distribution
|
# Set location of grass blades using probability distribution
|
||||||
# Create 1D vector of probability values from the 2D surface
|
# Create 1D vector of probability values from the 2D surface
|
||||||
probability1D = np.cumsum(np.ravel(surface.fractalsurface))
|
probability1D = np.cumsum(np.ravel(surface.fractalsurface))
|
||||||
|
|
||||||
# Create random numbers between zero and one for the number of blades of grass
|
# Create random numbers between zero and one for the number of blades of grass
|
||||||
R = np.random.RandomState(surface.seed)
|
R = np.random.RandomState(surface.seed)
|
||||||
A = R.random_sample(n_blades)
|
A = R.random_sample(n_blades)
|
||||||
|
|
||||||
# Locate the random numbers in the bins created by the 1D vector of probability values, and convert the 1D index back into a x, y index for the original surface.
|
# Locate the random numbers in the bins created by the 1D vector of probability values, and convert the 1D index back into a x, y index for the original surface.
|
||||||
bladesindex = np.unravel_index(np.digitize(A, probability1D), (surface.fractalsurface.shape[0], surface.fractalsurface.shape[1]))
|
bladesindex = np.unravel_index(np.digitize(A, probability1D), (surface.fractalsurface.shape[0], surface.fractalsurface.shape[1]))
|
||||||
|
|
||||||
# Set the fractal range to minimum and maximum heights of the grass blades
|
# Set the fractal range to minimum and maximum heights of the grass blades
|
||||||
surface.fractalrange = fractalrange
|
surface.fractalrange = fractalrange
|
||||||
|
|
||||||
# Set the fractal surface using the pre-calculated spatial distribution and a random height
|
# Set the fractal surface using the pre-calculated spatial distribution and a random height
|
||||||
surface.fractalsurface = np.zeros((surface.fractalsurface.shape[0], surface.fractalsurface.shape[1]))
|
surface.fractalsurface = np.zeros((surface.fractalsurface.shape[0], surface.fractalsurface.shape[1]))
|
||||||
for i in range(len(bladesindex[0])):
|
for i in range(len(bladesindex[0])):
|
||||||
surface.fractalsurface[bladesindex[0][i], bladesindex[1][i]] = R.randint(surface.fractalrange[0], surface.fractalrange[1], size=1)
|
surface.fractalsurface[bladesindex[0][i], bladesindex[1][i]] = R.randint(surface.fractalrange[0], surface.fractalrange[1], size=1)
|
||||||
|
|
||||||
# Create grass geometry parameters
|
# Create grass geometry parameters
|
||||||
g = Grass(n_blades)
|
g = Grass(n_blades)
|
||||||
g.seed = surface.seed
|
g.seed = surface.seed
|
||||||
surface.grass.append(g)
|
surface.grass.append(g)
|
||||||
|
|
||||||
# Check to see if grass has been already defined as a material
|
# Check to see if grass has been already defined as a material
|
||||||
if not any(x.ID == 'grass' for x in grid.materials):
|
if not any(x.ID == 'grass' for x in grid.materials):
|
||||||
m = Material(len(grid.materials), 'grass')
|
m = Material(len(grid.materials), 'grass')
|
||||||
m.averagable = False
|
m.averagable = False
|
||||||
m.type = 'builtin, debye'
|
m.type = 'builtin, debye'
|
||||||
m.er = Material.grasseri
|
m.er = Material.grasseri
|
||||||
m.deltaer.append(Material.grassdeltaer)
|
m.deltaer.append(Material.grassdeltaer)
|
||||||
m.tau.append(Material.grasstau)
|
m.tau.append(Material.grasstau)
|
||||||
grid.materials.append(m)
|
grid.materials.append(m)
|
||||||
if Material.maxpoles == 0:
|
if Material.maxpoles == 0:
|
||||||
Material.maxpoles = 1
|
Material.maxpoles = 1
|
||||||
|
|
||||||
# Check if time step for model is suitable for using grass
|
# Check if time step for model is suitable for using grass
|
||||||
grass = next((x for x in grid.materials if x.ID == 'grass'))
|
grass = next((x for x in grid.materials if x.ID == 'grass'))
|
||||||
testgrass = next((x for x in grass.tau if x < grid.dt), None)
|
testgrass = next((x for x in grass.tau if x < grid.dt), None)
|
||||||
if testgrass:
|
if testgrass:
|
||||||
raise CmdInputError(self.__str__() + ' requires the time step for the model to be less than the relaxation time required to model grass.')
|
raise CmdInputError(self.__str__() + ' requires the time step for the model to be less than the relaxation time required to model grass.')
|
||||||
|
|
||||||
volume.fractalsurfaces.append(surface)
|
volume.fractalsurfaces.append(surface)
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
tqdm.write('{} blades of grass on surface from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m with fractal dimension {:g}, fractal seeding {}, and range {:g}m to {:g}m, added to {}.'.format(n_blades, xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, surface.dimension, surface.seed, limits[0], limits[1], surface.operatingonID))
|
tqdm.write('{} blades of grass on surface from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m with fractal dimension {:g}, fractal seeding {}, and range {:g}m to {:g}m, added to {}.'.format(n_blades, xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, surface.dimension, surface.seed, limits[0], limits[1], surface.operatingonID))
|
||||||
|
@@ -1,127 +1,127 @@
|
|||||||
"""Class for surface roughness command."""
|
"""Class for surface roughness command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..fractals import FractalSurface
|
from ..fractals import FractalSurface
|
||||||
from ..utilities import round_value
|
from ..utilities import round_value
|
||||||
import gprMax.config as config
|
import gprMax.config as config
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class AddSurfaceRoughness(UserObjectGeometry):
|
class AddSurfaceRoughness(UserObjectGeometry):
|
||||||
"""User class for edge command."""
|
"""User class for edge command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 10
|
self.order = 10
|
||||||
self.hash = '#add_surface_roughness'
|
self.hash = '#add_surface_roughness'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
frac_dim = self.kwargs['frac_dim']
|
frac_dim = self.kwargs['frac_dim']
|
||||||
weighting = np.array(self.kwargs['weighting'], dtype=np.float64)
|
weighting = np.array(self.kwargs['weighting'], dtype=np.float64)
|
||||||
limits = np.array(self.kwargs['limits'])
|
limits = np.array(self.kwargs['limits'])
|
||||||
fractal_box_id = self.kwargs['fractal_box_id']
|
fractal_box_id = self.kwargs['fractal_box_id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' Incorrect parameters')
|
raise CmdInputError(self.__str__() + ' Incorrect parameters')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
seed = self.kwargs['seed']
|
seed = self.kwargs['seed']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
seed = None
|
seed = None
|
||||||
|
|
||||||
# grab the correct fractal volume
|
# grab the correct fractal volume
|
||||||
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
|
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
|
||||||
if volumes:
|
if volumes:
|
||||||
volume = volumes[0]
|
volume = volumes[0]
|
||||||
else:
|
else:
|
||||||
raise CmdInputError(self.__str__() + ' Cant find FractalBox {}'.format(fractal_box_id))
|
raise CmdInputError(self.__str__() + ' Cant find FractalBox {}'.format(fractal_box_id))
|
||||||
|
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
xs, ys, zs = p1
|
xs, ys, zs = p1
|
||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
if frac_dim < 0:
|
if frac_dim < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal dimension')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal dimension')
|
||||||
if weighting[0] < 0:
|
if weighting[0] < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal weighting in the first direction of the surface')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal weighting in the first direction of the surface')
|
||||||
if weighting[1] < 0:
|
if weighting[1] < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal weighting in the second direction of the surface')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal weighting in the second direction of the surface')
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
if xs == xf:
|
if xs == xf:
|
||||||
if ys == yf or zs == zf:
|
if ys == yf or zs == zf:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
if xs != volume.xs and xs != volume.xf:
|
if xs != volume.xs and xs != volume.xf:
|
||||||
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
||||||
fractalrange = (round_value(limits[0] / grid.dx), round_value(limits[1] / grid.dx))
|
fractalrange = (round_value(limits[0] / grid.dx), round_value(limits[1] / grid.dx))
|
||||||
# xminus surface
|
# xminus surface
|
||||||
if xs == volume.xs:
|
if xs == volume.xs:
|
||||||
if fractalrange[0] < 0 or fractalrange[1] > volume.xf:
|
if fractalrange[0] < 0 or fractalrange[1] > volume.xf:
|
||||||
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the upper coordinates of the fractal box or the domain in the x direction')
|
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the upper coordinates of the fractal box or the domain in the x direction')
|
||||||
requestedsurface = 'xminus'
|
requestedsurface = 'xminus'
|
||||||
# xplus surface
|
# xplus surface
|
||||||
elif xf == volume.xf:
|
elif xf == volume.xf:
|
||||||
if fractalrange[0] < volume.xs or fractalrange[1] > grid.nx:
|
if fractalrange[0] < volume.xs or fractalrange[1] > grid.nx:
|
||||||
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the lower coordinates of the fractal box or the domain in the x direction')
|
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the lower coordinates of the fractal box or the domain in the x direction')
|
||||||
requestedsurface = 'xplus'
|
requestedsurface = 'xplus'
|
||||||
|
|
||||||
elif ys == yf:
|
elif ys == yf:
|
||||||
if xs == xf or zs == zf:
|
if xs == xf or zs == zf:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
if ys != volume.ys and ys != volume.yf:
|
if ys != volume.ys and ys != volume.yf:
|
||||||
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
||||||
fractalrange = (round_value(limits[0] / grid.dy), round_value(limits[1] / grid.dy))
|
fractalrange = (round_value(limits[0] / grid.dy), round_value(limits[1] / grid.dy))
|
||||||
# yminus surface
|
# yminus surface
|
||||||
if ys == volume.ys:
|
if ys == volume.ys:
|
||||||
if fractalrange[0] < 0 or fractalrange[1] > volume.yf:
|
if fractalrange[0] < 0 or fractalrange[1] > volume.yf:
|
||||||
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the upper coordinates of the fractal box or the domain in the y direction')
|
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the upper coordinates of the fractal box or the domain in the y direction')
|
||||||
requestedsurface = 'yminus'
|
requestedsurface = 'yminus'
|
||||||
# yplus surface
|
# yplus surface
|
||||||
elif yf == volume.yf:
|
elif yf == volume.yf:
|
||||||
if fractalrange[0] < volume.ys or fractalrange[1] > grid.ny:
|
if fractalrange[0] < volume.ys or fractalrange[1] > grid.ny:
|
||||||
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the lower coordinates of the fractal box or the domain in the y direction')
|
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the lower coordinates of the fractal box or the domain in the y direction')
|
||||||
requestedsurface = 'yplus'
|
requestedsurface = 'yplus'
|
||||||
|
|
||||||
elif zs == zf:
|
elif zs == zf:
|
||||||
if xs == xf or ys == yf:
|
if xs == xf or ys == yf:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
if zs != volume.zs and zs != volume.zf:
|
if zs != volume.zs and zs != volume.zf:
|
||||||
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
||||||
fractalrange = (round_value(limits[0] / grid.dz), round_value(limits[1] / grid.dz))
|
fractalrange = (round_value(limits[0] / grid.dz), round_value(limits[1] / grid.dz))
|
||||||
# zminus surface
|
# zminus surface
|
||||||
if zs == volume.zs:
|
if zs == volume.zs:
|
||||||
if fractalrange[0] < 0 or fractalrange[1] > volume.zf:
|
if fractalrange[0] < 0 or fractalrange[1] > volume.zf:
|
||||||
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the upper coordinates of the fractal box or the domain in the x direction')
|
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the upper coordinates of the fractal box or the domain in the x direction')
|
||||||
requestedsurface = 'zminus'
|
requestedsurface = 'zminus'
|
||||||
# zplus surface
|
# zplus surface
|
||||||
elif zf == volume.zf:
|
elif zf == volume.zf:
|
||||||
if fractalrange[0] < volume.zs or fractalrange[1] > grid.nz:
|
if fractalrange[0] < volume.zs or fractalrange[1] > grid.nz:
|
||||||
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the lower coordinates of the fractal box or the domain in the z direction')
|
raise CmdInputError(self.__str__() + ' cannot apply fractal surface to fractal box as it would exceed either the lower coordinates of the fractal box or the domain in the z direction')
|
||||||
requestedsurface = 'zplus'
|
requestedsurface = 'zplus'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
|
|
||||||
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim)
|
surface = FractalSurface(xs, xf, ys, yf, zs, zf, frac_dim)
|
||||||
surface.surfaceID = requestedsurface
|
surface.surfaceID = requestedsurface
|
||||||
surface.fractalrange = fractalrange
|
surface.fractalrange = fractalrange
|
||||||
surface.operatingonID = volume.ID
|
surface.operatingonID = volume.ID
|
||||||
surface.seed = seed
|
surface.seed = seed
|
||||||
surface.weighting = weighting
|
surface.weighting = weighting
|
||||||
|
|
||||||
# List of existing surfaces IDs
|
# List of existing surfaces IDs
|
||||||
existingsurfaceIDs = [x.surfaceID for x in volume.fractalsurfaces]
|
existingsurfaceIDs = [x.surfaceID for x in volume.fractalsurfaces]
|
||||||
if surface.surfaceID in existingsurfaceIDs:
|
if surface.surfaceID in existingsurfaceIDs:
|
||||||
raise CmdInputError(self.__str__() + ' has already been used on the {} surface'.format(surface.surfaceID))
|
raise CmdInputError(self.__str__() + ' has already been used on the {} surface'.format(surface.surfaceID))
|
||||||
|
|
||||||
surface.generate_fractal_surface(grid)
|
surface.generate_fractal_surface(grid)
|
||||||
volume.fractalsurfaces.append(surface)
|
volume.fractalsurfaces.append(surface)
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
tqdm.write('Fractal surface from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m with fractal dimension {:g}, fractal weightings {:g}, {:g}, fractal seeding {}, and range {:g}m to {:g}m, added to {}.'.format(xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, surface.dimension, surface.weighting[0], surface.weighting[1], surface.seed, limits[0], limits[1], surface.operatingonID))
|
tqdm.write('Fractal surface from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m with fractal dimension {:g}, fractal weightings {:g}, {:g}, fractal seeding {}, and range {:g}m to {:g}m, added to {}.'.format(xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, surface.dimension, surface.weighting[0], surface.weighting[1], surface.seed, limits[0], limits[1], surface.operatingonID))
|
||||||
|
@@ -1,118 +1,118 @@
|
|||||||
"""Class for surface water command."""
|
"""Class for surface water command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..utilities import round_value
|
from ..utilities import round_value
|
||||||
from ..materials import Material
|
from ..materials import Material
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
|
||||||
class AddSurfaceWater(UserObjectGeometry):
|
class AddSurfaceWater(UserObjectGeometry):
|
||||||
"""User class for edge command."""
|
"""User class for edge command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 11
|
self.order = 11
|
||||||
self.hash = '#add_surface_water'
|
self.hash = '#add_surface_water'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
""""Create surface water on fractal box."""
|
""""Create surface water on fractal box."""
|
||||||
try:
|
try:
|
||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
fractal_box_id = self.kwargs['fractal_box_id']
|
fractal_box_id = self.kwargs['fractal_box_id']
|
||||||
depth = self.kwargs['depth']
|
depth = self.kwargs['depth']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' requires exactly eight parameters')
|
raise CmdInputError(self.__str__() + ' requires exactly eight parameters')
|
||||||
|
|
||||||
# grab the correct fractal volume
|
# grab the correct fractal volume
|
||||||
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
|
volumes = [volume for volume in grid.fractalvolumes if volume.ID == fractal_box_id]
|
||||||
if volumes:
|
if volumes:
|
||||||
volume = volumes[0]
|
volume = volumes[0]
|
||||||
else:
|
else:
|
||||||
raise CmdInputError(self.__str__() + ' Cant find FractalBox {}'.format(fractal_box_id))
|
raise CmdInputError(self.__str__() + ' Cant find FractalBox {}'.format(fractal_box_id))
|
||||||
|
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
xs, ys, zs = p1
|
xs, ys, zs = p1
|
||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
if depth <= 0:
|
if depth <= 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the depth of water')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the depth of water')
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
if xs == xf:
|
if xs == xf:
|
||||||
if ys == yf or zs == zf:
|
if ys == yf or zs == zf:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
if xs != volume.xs and xs != volume.xf:
|
if xs != volume.xs and xs != volume.xf:
|
||||||
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
||||||
# xminus surface
|
# xminus surface
|
||||||
if xs == volume.xs:
|
if xs == volume.xs:
|
||||||
requestedsurface = 'xminus'
|
requestedsurface = 'xminus'
|
||||||
# xplus surface
|
# xplus surface
|
||||||
elif xf == volume.xf:
|
elif xf == volume.xf:
|
||||||
requestedsurface = 'xplus'
|
requestedsurface = 'xplus'
|
||||||
filldepthcells = round_value(depth / grid.dx)
|
filldepthcells = round_value(depth / grid.dx)
|
||||||
filldepth = filldepthcells * grid.dx
|
filldepth = filldepthcells * grid.dx
|
||||||
|
|
||||||
elif ys == yf:
|
elif ys == yf:
|
||||||
if xs == xf or zs == zf:
|
if xs == xf or zs == zf:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
if ys != volume.ys and ys != volume.yf:
|
if ys != volume.ys and ys != volume.yf:
|
||||||
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
||||||
# yminus surface
|
# yminus surface
|
||||||
if ys == volume.ys:
|
if ys == volume.ys:
|
||||||
requestedsurface = 'yminus'
|
requestedsurface = 'yminus'
|
||||||
# yplus surface
|
# yplus surface
|
||||||
elif yf == volume.yf:
|
elif yf == volume.yf:
|
||||||
requestedsurface = 'yplus'
|
requestedsurface = 'yplus'
|
||||||
filldepthcells = round_value(depth / grid.dy)
|
filldepthcells = round_value(depth / grid.dy)
|
||||||
filldepth = filldepthcells * grid.dy
|
filldepth = filldepthcells * grid.dy
|
||||||
|
|
||||||
elif zs == zf:
|
elif zs == zf:
|
||||||
if xs == xf or ys == yf:
|
if xs == xf or ys == yf:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
if zs != volume.zs and zs != volume.zf:
|
if zs != volume.zs and zs != volume.zf:
|
||||||
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
raise CmdInputError(self.__str__() + ' can only be used on the external surfaces of a fractal box')
|
||||||
# zminus surface
|
# zminus surface
|
||||||
if zs == volume.zs:
|
if zs == volume.zs:
|
||||||
requestedsurface = 'zminus'
|
requestedsurface = 'zminus'
|
||||||
# zplus surface
|
# zplus surface
|
||||||
elif zf == volume.zf:
|
elif zf == volume.zf:
|
||||||
requestedsurface = 'zplus'
|
requestedsurface = 'zplus'
|
||||||
filldepthcells = round_value(depth / grid.dz)
|
filldepthcells = round_value(depth / grid.dz)
|
||||||
filldepth = filldepthcells * grid.dz
|
filldepth = filldepthcells * grid.dz
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
raise CmdInputError(self.__str__() + ' dimensions are not specified correctly')
|
||||||
|
|
||||||
surface = next((x for x in volume.fractalsurfaces if x.surfaceID == requestedsurface), None)
|
surface = next((x for x in volume.fractalsurfaces if x.surfaceID == requestedsurface), None)
|
||||||
if not surface:
|
if not surface:
|
||||||
raise CmdInputError(self.__str__() + ' specified surface {} does not have a rough surface applied'.format(requestedsurface))
|
raise CmdInputError(self.__str__() + ' specified surface {} does not have a rough surface applied'.format(requestedsurface))
|
||||||
|
|
||||||
surface.filldepth = filldepthcells
|
surface.filldepth = filldepthcells
|
||||||
|
|
||||||
# Check that requested fill depth falls within range of surface roughness
|
# Check that requested fill depth falls within range of surface roughness
|
||||||
if surface.filldepth < surface.fractalrange[0] or surface.filldepth > surface.fractalrange[1]:
|
if surface.filldepth < surface.fractalrange[0] or surface.filldepth > surface.fractalrange[1]:
|
||||||
raise CmdInputError(self.__str__() + ' requires a value for the depth of water that lies with the range of the requested surface roughness')
|
raise CmdInputError(self.__str__() + ' requires a value for the depth of water that lies with the range of the requested surface roughness')
|
||||||
|
|
||||||
# Check to see if water has been already defined as a material
|
# Check to see if water has been already defined as a material
|
||||||
if not any(x.ID == 'water' for x in grid.materials):
|
if not any(x.ID == 'water' for x in grid.materials):
|
||||||
m = Material(len(grid.materials), 'water')
|
m = Material(len(grid.materials), 'water')
|
||||||
m.averagable = False
|
m.averagable = False
|
||||||
m.type = 'builtin, debye'
|
m.type = 'builtin, debye'
|
||||||
m.er = Material.watereri
|
m.er = Material.watereri
|
||||||
m.deltaer.append(Material.waterdeltaer)
|
m.deltaer.append(Material.waterdeltaer)
|
||||||
m.tau.append(Material.watertau)
|
m.tau.append(Material.watertau)
|
||||||
grid.materials.append(m)
|
grid.materials.append(m)
|
||||||
if Material.maxpoles == 0:
|
if Material.maxpoles == 0:
|
||||||
Material.maxpoles = 1
|
Material.maxpoles = 1
|
||||||
|
|
||||||
# Check if time step for model is suitable for using water
|
# Check if time step for model is suitable for using water
|
||||||
water = next((x for x in grid.materials if x.ID == 'water'))
|
water = next((x for x in grid.materials if x.ID == 'water'))
|
||||||
testwater = next((x for x in water.tau if x < grid.dt), None)
|
testwater = next((x for x in water.tau if x < grid.dt), None)
|
||||||
if testwater:
|
if testwater:
|
||||||
raise CmdInputError(self.__str__() + ' requires the time step for the model to be less than the relaxation time required to model water.')
|
raise CmdInputError(self.__str__() + ' requires the time step for the model to be less than the relaxation time required to model water.')
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
tqdm.write('Water on surface from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m with depth {:g}m, added to {}.'.format(xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, filldepth, surface.operatingonID))
|
tqdm.write('Water on surface from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m with depth {:g}m, added to {}.'.format(xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, filldepth, surface.operatingonID))
|
||||||
|
@@ -1,93 +1,93 @@
|
|||||||
"""Class for triangle command."""
|
"""Class for triangle command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..materials import Material
|
from ..materials import Material
|
||||||
from ..cython.geometry_primitives import build_box
|
from ..cython.geometry_primitives import build_box
|
||||||
import gprMax.config as config
|
import gprMax.config as config
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class Box(UserObjectGeometry):
|
class Box(UserObjectGeometry):
|
||||||
"""User class for edge command."""
|
"""User class for edge command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 5
|
self.order = 5
|
||||||
self.hash = '#box'
|
self.hash = '#box'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
try:
|
try:
|
||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' Please specify two points.')
|
raise CmdInputError(self.__str__() + ' Please specify two points.')
|
||||||
# check materials have been specified
|
# check materials have been specified
|
||||||
# isotropic case
|
# isotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = [self.kwargs['material_id']]
|
materialsrequested = [self.kwargs['material_id']]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# Anisotropic case
|
# Anisotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
||||||
|
|
||||||
# check averaging
|
# check averaging
|
||||||
try:
|
try:
|
||||||
# go with user specified averaging
|
# go with user specified averaging
|
||||||
averagebox = self.kwargs['averaging']
|
averagebox = self.kwargs['averaging']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# if they havent specfied - go with the grid default
|
# if they havent specfied - go with the grid default
|
||||||
averagebox = grid.averagevolumeobjects
|
averagebox = grid.averagevolumeobjects
|
||||||
|
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
xs, ys, zs = p1
|
xs, ys, zs = p1
|
||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
notfound = [x for x in materialsrequested if x not in materials]
|
||||||
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
||||||
|
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(materials) == 1:
|
if len(materials) == 1:
|
||||||
averaging = materials[0].averagable and averagebox
|
averaging = materials[0].averagable and averagebox
|
||||||
numID = numIDx = numIDy = numIDz = materials[0].numID
|
numID = numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(materials) == 3:
|
elif len(materials) == 3:
|
||||||
averaging = False
|
averaging = False
|
||||||
numIDx = materials[0].numID
|
numIDx = materials[0].numID
|
||||||
numIDy = materials[1].numID
|
numIDy = materials[1].numID
|
||||||
numIDz = materials[2].numID
|
numIDz = materials[2].numID
|
||||||
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
|
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
|
||||||
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
||||||
if averagedmaterial:
|
if averagedmaterial:
|
||||||
numID = averagedmaterial.numID
|
numID = averagedmaterial.numID
|
||||||
else:
|
else:
|
||||||
numID = len(grid.materials)
|
numID = len(grid.materials)
|
||||||
m = Material(numID, requiredID)
|
m = Material(numID, requiredID)
|
||||||
m.type = 'dielectric-smoothed'
|
m.type = 'dielectric-smoothed'
|
||||||
# Create dielectric-smoothed constituents for material
|
# Create dielectric-smoothed constituents for material
|
||||||
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
|
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
|
||||||
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
|
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
|
||||||
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
||||||
m.sm = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
m.sm = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
||||||
|
|
||||||
# Append the new material object to the materials list
|
# Append the new material object to the materials list
|
||||||
grid.materials.append(m)
|
grid.materials.append(m)
|
||||||
|
|
||||||
build_box(xs, xf, ys, yf, zs, zf, numID, numIDx, numIDy, numIDz, averaging, grid.solid, grid.rigidE, grid.rigidH, grid.ID)
|
build_box(xs, xf, ys, yf, zs, zf, numID, numIDx, numIDy, numIDz, averaging, grid.solid, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
if averaging:
|
if averaging:
|
||||||
dielectricsmoothing = 'on'
|
dielectricsmoothing = 'on'
|
||||||
else:
|
else:
|
||||||
dielectricsmoothing = 'off'
|
dielectricsmoothing = 'off'
|
||||||
tqdm.write('Box from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m of material(s) {} created, dielectric smoothing is {}.'.format(xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, ', '.join(materialsrequested), dielectricsmoothing))
|
tqdm.write('Box from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m of material(s) {} created, dielectric smoothing is {}.'.format(xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, ', '.join(materialsrequested), dielectricsmoothing))
|
||||||
|
@@ -1,52 +1,52 @@
|
|||||||
from jinja2 import Environment, PackageLoader, select_autoescape
|
from jinja2 import Environment, PackageLoader, select_autoescape
|
||||||
env = Environment(
|
env = Environment(
|
||||||
loader=PackageLoader(__name__, 'templates'),
|
loader=PackageLoader(__name__, 'templates'),
|
||||||
)
|
)
|
||||||
|
|
||||||
template = env.get_template('fields_updates_dispersive_template')
|
template = env.get_template('fields_updates_dispersive_template')
|
||||||
|
|
||||||
r = template.render(
|
r = template.render(
|
||||||
functions=[
|
functions=[
|
||||||
# name, double, real
|
# name, double, real
|
||||||
{
|
{
|
||||||
'name_a': 'update_electric_dispersive_multipole_A_double_real',
|
'name_a': 'update_electric_dispersive_multipole_A_double_real',
|
||||||
'name_b': 'update_electric_dispersive_multipole_B_double_real',
|
'name_b': 'update_electric_dispersive_multipole_B_double_real',
|
||||||
'name_a_1': 'update_electric_dispersive_1pole_A_double_real',
|
'name_a_1': 'update_electric_dispersive_1pole_A_double_real',
|
||||||
'name_b_1': 'update_electric_dispersive_1pole_B_double_real',
|
'name_b_1': 'update_electric_dispersive_1pole_B_double_real',
|
||||||
'field_type': 'double',
|
'field_type': 'double',
|
||||||
'dispersive_type': 'double'
|
'dispersive_type': 'double'
|
||||||
},
|
},
|
||||||
# name, float, real
|
# name, float, real
|
||||||
{
|
{
|
||||||
'name_a': 'update_electric_dispersive_multipole_A_float_real',
|
'name_a': 'update_electric_dispersive_multipole_A_float_real',
|
||||||
'name_b': 'update_electric_dispersive_multipole_B_float_real',
|
'name_b': 'update_electric_dispersive_multipole_B_float_real',
|
||||||
'name_a_1': 'update_electric_dispersive_1pole_A_float_real',
|
'name_a_1': 'update_electric_dispersive_1pole_A_float_real',
|
||||||
'name_b_1': 'update_electric_dispersive_1pole_B_float_real',
|
'name_b_1': 'update_electric_dispersive_1pole_B_float_real',
|
||||||
'field_type': 'float',
|
'field_type': 'float',
|
||||||
'dispersive_type': 'float'
|
'dispersive_type': 'float'
|
||||||
},
|
},
|
||||||
# name, double, complex
|
# name, double, complex
|
||||||
{
|
{
|
||||||
'name_a': 'update_electric_dispersive_multipole_A_double_complex',
|
'name_a': 'update_electric_dispersive_multipole_A_double_complex',
|
||||||
'name_b': 'update_electric_dispersive_multipole_B_double_complex',
|
'name_b': 'update_electric_dispersive_multipole_B_double_complex',
|
||||||
'name_a_1': 'update_electric_dispersive_1pole_A_double_complex',
|
'name_a_1': 'update_electric_dispersive_1pole_A_double_complex',
|
||||||
'name_b_1': 'update_electric_dispersive_1pole_B_double_complex',
|
'name_b_1': 'update_electric_dispersive_1pole_B_double_complex',
|
||||||
'field_type': 'double',
|
'field_type': 'double',
|
||||||
'dispersive_type': 'double complex',
|
'dispersive_type': 'double complex',
|
||||||
'real_part': 'creal'
|
'real_part': 'creal'
|
||||||
},
|
},
|
||||||
# name, float, complex
|
# name, float, complex
|
||||||
{
|
{
|
||||||
'name_a': 'update_electric_dispersive_multipole_A_float_complex',
|
'name_a': 'update_electric_dispersive_multipole_A_float_complex',
|
||||||
'name_b': 'update_electric_dispersive_multipole_B_float_complex',
|
'name_b': 'update_electric_dispersive_multipole_B_float_complex',
|
||||||
'name_a_1': 'update_electric_dispersive_1pole_A_float_complex',
|
'name_a_1': 'update_electric_dispersive_1pole_A_float_complex',
|
||||||
'name_b_1': 'update_electric_dispersive_1pole_B_float_complex',
|
'name_b_1': 'update_electric_dispersive_1pole_B_float_complex',
|
||||||
'field_type': 'float',
|
'field_type': 'float',
|
||||||
'dispersive_type': 'float complex',
|
'dispersive_type': 'float complex',
|
||||||
'real_part': 'crealf'
|
'real_part': 'crealf'
|
||||||
}]
|
}]
|
||||||
)
|
)
|
||||||
|
|
||||||
f = open('cython/dispersive_updates_test.pyx', 'w')
|
f = open('cython/dispersive_updates_test.pyx', 'w')
|
||||||
f.write(r)
|
f.write(r)
|
||||||
f.close()
|
f.close()
|
||||||
|
@@ -1,98 +1,98 @@
|
|||||||
"""Class for cylinder command."""
|
"""Class for cylinder command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..materials import Material
|
from ..materials import Material
|
||||||
from ..cython.geometry_primitives import build_cylinder
|
from ..cython.geometry_primitives import build_cylinder
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import gprMax.config as config
|
import gprMax.config as config
|
||||||
|
|
||||||
|
|
||||||
class Cylinder(UserObjectGeometry):
|
class Cylinder(UserObjectGeometry):
|
||||||
"""User class for edge command."""
|
"""User class for edge command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 6
|
self.order = 6
|
||||||
self.hash = '#cylinder'
|
self.hash = '#cylinder'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
r = self.kwargs['r']
|
r = self.kwargs['r']
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' Please specify 2 points and a radius')
|
raise CmdInputError(self.__str__() + ' Please specify 2 points and a radius')
|
||||||
|
|
||||||
# check averaging
|
# check averaging
|
||||||
try:
|
try:
|
||||||
# go with user specified averaging
|
# go with user specified averaging
|
||||||
averagecylinder = self.kwargs['averaging']
|
averagecylinder = self.kwargs['averaging']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# if they havent specfied - go with the grid default
|
# if they havent specfied - go with the grid default
|
||||||
averagecylinder = grid.averagevolumeobjects
|
averagecylinder = grid.averagevolumeobjects
|
||||||
|
|
||||||
# check materials have been specified
|
# check materials have been specified
|
||||||
# isotropic case
|
# isotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = [self.kwargs['material_id']]
|
materialsrequested = [self.kwargs['material_id']]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# Anisotropic case
|
# Anisotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
||||||
|
|
||||||
x1, y1, z1 = uip.round_to_grid(p1)
|
x1, y1, z1 = uip.round_to_grid(p1)
|
||||||
x2, y2, z2 = uip.round_to_grid(p2)
|
x2, y2, z2 = uip.round_to_grid(p2)
|
||||||
|
|
||||||
if r <= 0:
|
if r <= 0:
|
||||||
raise CmdInputError(self.__str__() + ' the radius {:g} should be a positive value.'.format(r))
|
raise CmdInputError(self.__str__() + ' the radius {:g} should be a positive value.'.format(r))
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
notfound = [x for x in materialsrequested if x not in materials]
|
||||||
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
||||||
|
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(materials) == 1:
|
if len(materials) == 1:
|
||||||
averaging = materials[0].averagable and averagecylinder
|
averaging = materials[0].averagable and averagecylinder
|
||||||
numID = numIDx = numIDy = numIDz = materials[0].numID
|
numID = numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(materials) == 3:
|
elif len(materials) == 3:
|
||||||
averaging = False
|
averaging = False
|
||||||
numIDx = materials[0].numID
|
numIDx = materials[0].numID
|
||||||
numIDy = materials[1].numID
|
numIDy = materials[1].numID
|
||||||
numIDz = materials[2].numID
|
numIDz = materials[2].numID
|
||||||
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
|
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
|
||||||
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
||||||
if averagedmaterial:
|
if averagedmaterial:
|
||||||
numID = averagedmaterial.numID
|
numID = averagedmaterial.numID
|
||||||
else:
|
else:
|
||||||
numID = len(grid.materials)
|
numID = len(grid.materials)
|
||||||
m = Material(numID, requiredID)
|
m = Material(numID, requiredID)
|
||||||
m.type = 'dielectric-smoothed'
|
m.type = 'dielectric-smoothed'
|
||||||
# Create dielectric-smoothed constituents for material
|
# Create dielectric-smoothed constituents for material
|
||||||
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
|
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
|
||||||
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
|
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
|
||||||
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
||||||
m.sm = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
m.sm = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
||||||
|
|
||||||
# Append the new material object to the materials list
|
# Append the new material object to the materials list
|
||||||
grid.materials.append(m)
|
grid.materials.append(m)
|
||||||
|
|
||||||
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)
|
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)
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
if averaging:
|
if averaging:
|
||||||
dielectricsmoothing = 'on'
|
dielectricsmoothing = 'on'
|
||||||
else:
|
else:
|
||||||
dielectricsmoothing = 'off'
|
dielectricsmoothing = 'off'
|
||||||
tqdm.write('Cylinder with face centres {:g}m, {:g}m, {:g}m and {:g}m, {:g}m, {:g}m, with radius {:g}m, of material(s) {} created, dielectric smoothing is {}.'.format(x1, y1, z1, x2, y2, z2, r, ', '.join(materialsrequested), dielectricsmoothing))
|
tqdm.write('Cylinder with face centres {:g}m, {:g}m, {:g}m and {:g}m, {:g}m, {:g}m, with radius {:g}m, of material(s) {} created, dielectric smoothing is {}.'.format(x1, y1, z1, x2, y2, z2, r, ', '.join(materialsrequested), dielectricsmoothing))
|
||||||
|
@@ -1,137 +1,137 @@
|
|||||||
"""Class for cylinder command."""
|
"""Class for cylinder command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..materials import Material
|
from ..materials import Material
|
||||||
from ..cython.geometry_primitives import build_cylindrical_sector
|
from ..cython.geometry_primitives import build_cylindrical_sector
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class CylindricalSector(UserObjectGeometry):
|
class CylindricalSector(UserObjectGeometry):
|
||||||
"""User class for edge command."""
|
"""User class for edge command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 7
|
self.order = 7
|
||||||
self.hash = '#cylindrical_sector'
|
self.hash = '#cylindrical_sector'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
normal = self.kwargs['normal'].lower()
|
normal = self.kwargs['normal'].lower()
|
||||||
ctr1 = self.kwargs['ctr1']
|
ctr1 = self.kwargs['ctr1']
|
||||||
ctr2 = self.kwargs['ctr2']
|
ctr2 = self.kwargs['ctr2']
|
||||||
extent1 = self.kwargs['extent1']
|
extent1 = self.kwargs['extent1']
|
||||||
extent2 = self.kwargs['extent2']
|
extent2 = self.kwargs['extent2']
|
||||||
start = self.kwargs['start']
|
start = self.kwargs['start']
|
||||||
end = self.kwargs['end']
|
end = self.kwargs['end']
|
||||||
r = self.kwargs['r']
|
r = self.kwargs['r']
|
||||||
thickness = extent2 - extent1
|
thickness = extent2 - extent1
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__())
|
raise CmdInputError(self.__str__())
|
||||||
|
|
||||||
# check averaging
|
# check averaging
|
||||||
try:
|
try:
|
||||||
# go with user specified averaging
|
# go with user specified averaging
|
||||||
averagecylindricalsector = self.kwargs['averaging']
|
averagecylindricalsector = self.kwargs['averaging']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# if they havent specfied - go with the grid default
|
# if they havent specfied - go with the grid default
|
||||||
averagecylindricalsector = grid.averagevolumeobjects
|
averagecylindricalsector = grid.averagevolumeobjects
|
||||||
|
|
||||||
# check materials have been specified
|
# check materials have been specified
|
||||||
# isotropic case
|
# isotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = [self.kwargs['material_id']]
|
materialsrequested = [self.kwargs['material_id']]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# Anisotropic case
|
# Anisotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
||||||
|
|
||||||
sectorstartangle = 2 * np.pi * (start / 360)
|
sectorstartangle = 2 * np.pi * (start / 360)
|
||||||
sectorangle = 2 * np.pi * (end / 360)
|
sectorangle = 2 * np.pi * (end / 360)
|
||||||
|
|
||||||
if normal != 'x' and normal != 'y' and normal != 'z':
|
if normal != 'x' and normal != 'y' and normal != 'z':
|
||||||
raise CmdInputError(self.__str__() + ' the normal direction must be either x, y or z.')
|
raise CmdInputError(self.__str__() + ' the normal direction must be either x, y or z.')
|
||||||
if r <= 0:
|
if r <= 0:
|
||||||
raise CmdInputError(self.__str__() + ' the radius {:g} should be a positive value.'.format(r))
|
raise CmdInputError(self.__str__() + ' the radius {:g} should be a positive value.'.format(r))
|
||||||
if sectorstartangle < 0 or sectorangle <= 0:
|
if sectorstartangle < 0 or sectorangle <= 0:
|
||||||
raise CmdInputError(self.__str__() + ' the starting angle and sector angle should be a positive values.')
|
raise CmdInputError(self.__str__() + ' the starting angle and sector angle should be a positive values.')
|
||||||
if sectorstartangle >= 2 * np.pi or sectorangle >= 2 * np.pi:
|
if sectorstartangle >= 2 * np.pi or sectorangle >= 2 * np.pi:
|
||||||
raise CmdInputError(self.__str__() + ' the starting angle and sector angle must be less than 360 degrees.')
|
raise CmdInputError(self.__str__() + ' the starting angle and sector angle must be less than 360 degrees.')
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
notfound = [x for x in materialsrequested if x not in materials]
|
||||||
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
||||||
|
|
||||||
if thickness > 0:
|
if thickness > 0:
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(materials) == 1:
|
if len(materials) == 1:
|
||||||
averaging = materials[0].averagable and averagecylindricalsector
|
averaging = materials[0].averagable and averagecylindricalsector
|
||||||
numID = numIDx = numIDy = numIDz = materials[0].numID
|
numID = numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(materials) == 3:
|
elif len(materials) == 3:
|
||||||
averaging = False
|
averaging = False
|
||||||
numIDx = materials[0].numID
|
numIDx = materials[0].numID
|
||||||
numIDy = materials[1].numID
|
numIDy = materials[1].numID
|
||||||
numIDz = materials[2].numID
|
numIDz = materials[2].numID
|
||||||
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
|
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
|
||||||
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
||||||
if averagedmaterial:
|
if averagedmaterial:
|
||||||
numID = averagedmaterial.numID
|
numID = averagedmaterial.numID
|
||||||
else:
|
else:
|
||||||
numID = len(grid.materials)
|
numID = len(grid.materials)
|
||||||
m = Material(numID, requiredID)
|
m = Material(numID, requiredID)
|
||||||
m.type = 'dielectric-smoothed'
|
m.type = 'dielectric-smoothed'
|
||||||
# Create dielectric-smoothed constituents for material
|
# Create dielectric-smoothed constituents for material
|
||||||
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
|
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
|
||||||
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
|
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
|
||||||
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
||||||
m.sm = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
m.sm = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
||||||
|
|
||||||
# Append the new material object to the materials list
|
# Append the new material object to the materials list
|
||||||
grid.materials.append(m)
|
grid.materials.append(m)
|
||||||
else:
|
else:
|
||||||
averaging = False
|
averaging = False
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(materials) == 1:
|
if len(materials) == 1:
|
||||||
numID = numIDx = numIDy = numIDz = materials[0].numID
|
numID = numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(materials) == 3:
|
elif len(materials) == 3:
|
||||||
# numID requires a value but it will not be used
|
# numID requires a value but it will not be used
|
||||||
numID = None
|
numID = None
|
||||||
numIDx = materials[0].numID
|
numIDx = materials[0].numID
|
||||||
numIDy = materials[1].numID
|
numIDy = materials[1].numID
|
||||||
numIDz = materials[2].numID
|
numIDz = materials[2].numID
|
||||||
|
|
||||||
# yz-plane cylindrical sector
|
# yz-plane cylindrical sector
|
||||||
if normal == 'x':
|
if normal == 'x':
|
||||||
level, ctr1, ctr2 = uip.round_to_grid((extent1, ctr1, ctr2))
|
level, ctr1, ctr2 = uip.round_to_grid((extent1, ctr1, ctr2))
|
||||||
|
|
||||||
# xz-plane cylindrical sector
|
# xz-plane cylindrical sector
|
||||||
elif normal == 'y':
|
elif normal == 'y':
|
||||||
ctr1, level, ctr2 = uip.round_to_grid((ctr1, extent1, ctr2))
|
ctr1, level, ctr2 = uip.round_to_grid((ctr1, extent1, ctr2))
|
||||||
|
|
||||||
# xy-plane cylindrical sector
|
# xy-plane cylindrical sector
|
||||||
elif normal == 'z':
|
elif normal == 'z':
|
||||||
ctr1, ctr2, level = uip.round_to_grid((ctr1, ctr2, extent1))
|
ctr1, ctr2, level = uip.round_to_grid((ctr1, ctr2, extent1))
|
||||||
|
|
||||||
build_cylindrical_sector(ctr1, ctr2, level, sectorstartangle, sectorangle, r, normal, thickness, grid.dx, grid.dy, grid.dz, numID, numIDx, numIDy, numIDz, averaging, grid.solid, grid.rigidE, grid.rigidH, grid.ID)
|
build_cylindrical_sector(ctr1, ctr2, level, sectorstartangle, sectorangle, r, normal, thickness, grid.dx, grid.dy, grid.dz, numID, numIDx, numIDy, numIDz, averaging, grid.solid, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
if thickness > 0:
|
if thickness > 0:
|
||||||
if averaging:
|
if averaging:
|
||||||
dielectricsmoothing = 'on'
|
dielectricsmoothing = 'on'
|
||||||
else:
|
else:
|
||||||
dielectricsmoothing = 'off'
|
dielectricsmoothing = 'off'
|
||||||
tqdm.write('Cylindrical sector with centre {:g}m, {:g}m, radius {:g}m, starting angle {:.1f} degrees, sector angle {:.1f} degrees, thickness {:g}m, of material(s) {} created, dielectric smoothing is {}.'.format(ctr1, ctr2, r, (sectorstartangle / (2 * np.pi)) * 360, (sectorangle / (2 * np.pi)) * 360, thickness, ', '.join(materialsrequested), dielectricsmoothing))
|
tqdm.write('Cylindrical sector with centre {:g}m, {:g}m, radius {:g}m, starting angle {:.1f} degrees, sector angle {:.1f} degrees, thickness {:g}m, of material(s) {} created, dielectric smoothing is {}.'.format(ctr1, ctr2, r, (sectorstartangle / (2 * np.pi)) * 360, (sectorangle / (2 * np.pi)) * 360, thickness, ', '.join(materialsrequested), dielectricsmoothing))
|
||||||
else:
|
else:
|
||||||
tqdm.write('Cylindrical sector with centre {:g}m, {:g}m, radius {:g}m, starting angle {:.1f} degrees, sector angle {:.1f} degrees, of material(s) {} created.'.format(ctr1, ctr2, r, (sectorstartangle / (2 * np.pi)) * 360, (sectorangle / (2 * np.pi)) * 360, ', '.join(materialsrequested)))
|
tqdm.write('Cylindrical sector with centre {:g}m, {:g}m, radius {:g}m, starting angle {:.1f} degrees, sector angle {:.1f} degrees, of material(s) {} created.'.format(ctr1, ctr2, r, (sectorstartangle / (2 * np.pi)) * 360, (sectorangle / (2 * np.pi)) * 360, ', '.join(materialsrequested)))
|
||||||
|
@@ -1,64 +1,64 @@
|
|||||||
"""Class for edge command."""
|
"""Class for edge command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..cython.geometry_primitives import build_edge_x
|
from ..cython.geometry_primitives import build_edge_x
|
||||||
from ..cython.geometry_primitives import build_edge_y
|
from ..cython.geometry_primitives import build_edge_y
|
||||||
from ..cython.geometry_primitives import build_edge_z
|
from ..cython.geometry_primitives import build_edge_z
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
|
||||||
class Edge(UserObjectGeometry):
|
class Edge(UserObjectGeometry):
|
||||||
"""User class for edge command."""
|
"""User class for edge command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 2
|
self.order = 2
|
||||||
self.hash = '#edge'
|
self.hash = '#edge'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
"""Create edge and add it to the grid."""
|
"""Create edge and add it to the grid."""
|
||||||
try:
|
try:
|
||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
material_id = self.kwargs['material_id']
|
material_id = self.kwargs['material_id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' requires exactly 3 parameters')
|
raise CmdInputError(self.__str__() + ' requires exactly 3 parameters')
|
||||||
|
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
xs, ys, zs = p1
|
xs, ys, zs = p1
|
||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
material = next((x for x in grid.materials if x.ID == material_id), None)
|
material = next((x for x in grid.materials if x.ID == material_id), None)
|
||||||
|
|
||||||
if not material:
|
if not material:
|
||||||
raise CmdInputError('Material with ID {} does not exist'.format(material_id))
|
raise CmdInputError('Material with ID {} does not exist'.format(material_id))
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
# x-orientated wire
|
# x-orientated wire
|
||||||
if xs != xf:
|
if xs != xf:
|
||||||
if ys != yf or zs != zf:
|
if ys != yf or zs != zf:
|
||||||
raise CmdInputError(self.__str__() + ' the edge is not specified correctly')
|
raise CmdInputError(self.__str__() + ' the edge is not specified correctly')
|
||||||
else:
|
else:
|
||||||
for i in range(xs, xf):
|
for i in range(xs, xf):
|
||||||
build_edge_x(i, ys, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
build_edge_x(i, ys, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
# y-orientated wire
|
# y-orientated wire
|
||||||
elif ys != yf:
|
elif ys != yf:
|
||||||
if xs != xf or zs != zf:
|
if xs != xf or zs != zf:
|
||||||
raise CmdInputError(self.__str__() + ' the edge is not specified correctly')
|
raise CmdInputError(self.__str__() + ' the edge is not specified correctly')
|
||||||
else:
|
else:
|
||||||
for j in range(ys, yf):
|
for j in range(ys, yf):
|
||||||
build_edge_y(xs, j, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
build_edge_y(xs, j, zs, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
# z-orientated wire
|
# z-orientated wire
|
||||||
elif zs != zf:
|
elif zs != zf:
|
||||||
if xs != xf or ys != yf:
|
if xs != xf or ys != yf:
|
||||||
raise CmdInputError(self.__str__() + ' the edge is not specified correctly')
|
raise CmdInputError(self.__str__() + ' the edge is not specified correctly')
|
||||||
else:
|
else:
|
||||||
for k in range(zs, zf):
|
for k in range(zs, zf):
|
||||||
build_edge_z(xs, ys, k, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
build_edge_z(xs, ys, k, material.numID, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
tqdm.write('Edge from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m of material {} created.'.format(xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, material_id))
|
tqdm.write('Edge from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m of material {} created.'.format(xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, material_id))
|
||||||
|
@@ -1,93 +1,93 @@
|
|||||||
"""Class for surface roughness command."""
|
"""Class for surface roughness command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..fractals import FractalVolume
|
from ..fractals import FractalVolume
|
||||||
import gprMax.config as config
|
import gprMax.config as config
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class FractalBox(UserObjectGeometry):
|
class FractalBox(UserObjectGeometry):
|
||||||
"""User class for edge command."""
|
"""User class for edge command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 9
|
self.order = 9
|
||||||
self.hash = '#fractal_box'
|
self.hash = '#fractal_box'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
try:
|
try:
|
||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
frac_dim = self.kwargs['frac_dim']
|
frac_dim = self.kwargs['frac_dim']
|
||||||
weighting = np.array(self.kwargs['weighting'])
|
weighting = np.array(self.kwargs['weighting'])
|
||||||
n_materials = self.kwargs['n_materials']
|
n_materials = self.kwargs['n_materials']
|
||||||
mixing_model_id = self.kwargs['mixing_model_id']
|
mixing_model_id = self.kwargs['mixing_model_id']
|
||||||
ID = self.kwargs['id']
|
ID = self.kwargs['id']
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' Incorrect parameters')
|
raise CmdInputError(self.__str__() + ' Incorrect parameters')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
seed = self.kwargs['seed']
|
seed = self.kwargs['seed']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
seed = None
|
seed = None
|
||||||
|
|
||||||
# Default is no dielectric smoothing for a fractal box
|
# Default is no dielectric smoothing for a fractal box
|
||||||
averagefractalbox = False
|
averagefractalbox = False
|
||||||
|
|
||||||
# check averaging
|
# check averaging
|
||||||
try:
|
try:
|
||||||
# go with user specified averaging
|
# go with user specified averaging
|
||||||
averagefractalbox = self.kwargs['averaging']
|
averagefractalbox = self.kwargs['averaging']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# if they havent specfied - go with the grid default
|
# if they havent specfied - go with the grid default
|
||||||
averagefractalbox = False
|
averagefractalbox = False
|
||||||
|
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
xs, ys, zs = p1
|
xs, ys, zs = p1
|
||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
if frac_dim < 0:
|
if frac_dim < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal dimension')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal dimension')
|
||||||
if weighting[0] < 0:
|
if weighting[0] < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal weighting in the x direction')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal weighting in the x direction')
|
||||||
if weighting[1] < 0:
|
if weighting[1] < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal weighting in the y direction')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal weighting in the y direction')
|
||||||
if weighting[2] < 0:
|
if weighting[2] < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal weighting in the z direction')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the fractal weighting in the z direction')
|
||||||
if n_materials < 0:
|
if n_materials < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for the number of bins')
|
raise CmdInputError(self.__str__() + ' requires a positive value for the number of bins')
|
||||||
|
|
||||||
# Find materials to use to build fractal volume, either from mixing models or normal materials
|
# Find materials to use to build fractal volume, either from mixing models or normal materials
|
||||||
mixingmodel = next((x for x in grid.mixingmodels if x.ID == mixing_model_id), None)
|
mixingmodel = next((x for x in grid.mixingmodels if x.ID == mixing_model_id), None)
|
||||||
material = next((x for x in grid.materials if x.ID == mixing_model_id), None)
|
material = next((x for x in grid.materials if x.ID == mixing_model_id), None)
|
||||||
nbins = n_materials
|
nbins = n_materials
|
||||||
|
|
||||||
if mixingmodel:
|
if mixingmodel:
|
||||||
if nbins == 1:
|
if nbins == 1:
|
||||||
raise CmdInputError(self.__str__() + ' must be used with more than one material from the mixing model.')
|
raise CmdInputError(self.__str__() + ' must be used with more than one material from the mixing model.')
|
||||||
# Create materials from mixing model as number of bins now known from fractal_box command
|
# Create materials from mixing model as number of bins now known from fractal_box command
|
||||||
mixingmodel.calculate_debye_properties(nbins, grid)
|
mixingmodel.calculate_debye_properties(nbins, grid)
|
||||||
elif not material:
|
elif not material:
|
||||||
raise CmdInputError(self.__str__() + ' mixing model or material with ID {} does not exist'.format(mixing_model_id))
|
raise CmdInputError(self.__str__() + ' mixing model or material with ID {} does not exist'.format(mixing_model_id))
|
||||||
|
|
||||||
volume = FractalVolume(xs, xf, ys, yf, zs, zf, frac_dim)
|
volume = FractalVolume(xs, xf, ys, yf, zs, zf, frac_dim)
|
||||||
volume.ID = ID
|
volume.ID = ID
|
||||||
volume.operatingonID = mixing_model_id
|
volume.operatingonID = mixing_model_id
|
||||||
volume.nbins = nbins
|
volume.nbins = nbins
|
||||||
volume.seed = seed
|
volume.seed = seed
|
||||||
volume.weighting = weighting
|
volume.weighting = weighting
|
||||||
volume.averaging = averagefractalbox
|
volume.averaging = averagefractalbox
|
||||||
volume.mixingmodel = mixingmodel
|
volume.mixingmodel = mixingmodel
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
if volume.averaging:
|
if volume.averaging:
|
||||||
dielectricsmoothing = 'on'
|
dielectricsmoothing = 'on'
|
||||||
else:
|
else:
|
||||||
dielectricsmoothing = 'off'
|
dielectricsmoothing = 'off'
|
||||||
tqdm.write('Fractal box {} from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m with {}, fractal dimension {:g}, fractal weightings {:g}, {:g}, {:g}, fractal seeding {}, with {} material(s) created, dielectric smoothing is {}.'.format(volume.ID, xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, volume.operatingonID, volume.dimension, volume.weighting[0], volume.weighting[1], volume.weighting[2], volume.seed, volume.nbins, dielectricsmoothing))
|
tqdm.write('Fractal box {} from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m with {}, fractal dimension {:g}, fractal weightings {:g}, {:g}, {:g}, fractal seeding {}, with {} material(s) created, dielectric smoothing is {}.'.format(volume.ID, xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, volume.operatingonID, volume.dimension, volume.weighting[0], volume.weighting[1], volume.weighting[2], volume.seed, volume.nbins, dielectricsmoothing))
|
||||||
|
|
||||||
grid.fractalvolumes.append(volume)
|
grid.fractalvolumes.append(volume)
|
||||||
|
@@ -1,112 +1,112 @@
|
|||||||
"""Class for edge command."""
|
"""Class for edge command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..cython.geometry_primitives import build_face_yz
|
from ..cython.geometry_primitives import build_face_yz
|
||||||
from ..cython.geometry_primitives import build_face_xz
|
from ..cython.geometry_primitives import build_face_xz
|
||||||
from ..cython.geometry_primitives import build_face_xy
|
from ..cython.geometry_primitives import build_face_xy
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
|
||||||
class Plate(UserObjectGeometry):
|
class Plate(UserObjectGeometry):
|
||||||
"""User class for edge command."""
|
"""User class for edge command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 3
|
self.order = 3
|
||||||
self.hash = '#plate'
|
self.hash = '#plate'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
p2 = self.kwargs['p2']
|
p2 = self.kwargs['p2']
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' 2 points must be specified')
|
raise CmdInputError(self.__str__() + ' 2 points must be specified')
|
||||||
|
|
||||||
# isotropic
|
# isotropic
|
||||||
try:
|
try:
|
||||||
materialsrequested = [self.kwargs['material_id']]
|
materialsrequested = [self.kwargs['material_id']]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# Anisotropic case
|
# Anisotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
||||||
|
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
xs, ys, zs = p1
|
xs, ys, zs = p1
|
||||||
xf, yf, zf = p2
|
xf, yf, zf = p2
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
if xs == xf:
|
if xs == xf:
|
||||||
if ys == yf or zs == zf:
|
if ys == yf or zs == zf:
|
||||||
raise CmdInputError(self.__str__() + ' the plate is not specified correctly')
|
raise CmdInputError(self.__str__() + ' the plate is not specified correctly')
|
||||||
|
|
||||||
elif ys == yf:
|
elif ys == yf:
|
||||||
if xs == xf or zs == zf:
|
if xs == xf or zs == zf:
|
||||||
raise CmdInputError(self.__str__() + ' the plate is not specified correctly')
|
raise CmdInputError(self.__str__() + ' the plate is not specified correctly')
|
||||||
|
|
||||||
elif zs == zf:
|
elif zs == zf:
|
||||||
if xs == xf or ys == yf:
|
if xs == xf or ys == yf:
|
||||||
raise CmdInputError(self.__str__() + ' the plate is not specified correctly')
|
raise CmdInputError(self.__str__() + ' the plate is not specified correctly')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise CmdInputError(self.__str__() + ' the plate is not specified correctly')
|
raise CmdInputError(self.__str__() + ' the plate is not specified correctly')
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
notfound = [x for x in materialsrequested if x not in materials]
|
||||||
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
||||||
|
|
||||||
# yz-plane plate
|
# yz-plane plate
|
||||||
if xs == xf:
|
if xs == xf:
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(materials) == 1:
|
if len(materials) == 1:
|
||||||
numIDx = numIDy = numIDz = materials[0].numID
|
numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(materials) == 2:
|
elif len(materials) == 2:
|
||||||
numIDy = materials[0].numID
|
numIDy = materials[0].numID
|
||||||
numIDz = materials[1].numID
|
numIDz = materials[1].numID
|
||||||
|
|
||||||
for j in range(ys, yf):
|
for j in range(ys, yf):
|
||||||
for k in range(zs, zf):
|
for k in range(zs, zf):
|
||||||
build_face_yz(xs, j, k, numIDy, numIDz, grid.rigidE, grid.rigidH, grid.ID)
|
build_face_yz(xs, j, k, numIDy, numIDz, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
# xz-plane plate
|
# xz-plane plate
|
||||||
elif ys == yf:
|
elif ys == yf:
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(materials) == 1:
|
if len(materials) == 1:
|
||||||
numIDx = numIDy = numIDz = materials[0].numID
|
numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(materials) == 2:
|
elif len(materials) == 2:
|
||||||
numIDx = materials[0].numID
|
numIDx = materials[0].numID
|
||||||
numIDz = materials[1].numID
|
numIDz = materials[1].numID
|
||||||
|
|
||||||
for i in range(xs, xf):
|
for i in range(xs, xf):
|
||||||
for k in range(zs, zf):
|
for k in range(zs, zf):
|
||||||
build_face_xz(i, ys, k, numIDx, numIDz, grid.rigidE, grid.rigidH, grid.ID)
|
build_face_xz(i, ys, k, numIDx, numIDz, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
# xy-plane plate
|
# xy-plane plate
|
||||||
elif zs == zf:
|
elif zs == zf:
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(materials) == 1:
|
if len(materials) == 1:
|
||||||
numIDx = numIDy = numIDz = materials[0].numID
|
numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(materials) == 2:
|
elif len(materials) == 2:
|
||||||
numIDx = materials[0].numID
|
numIDx = materials[0].numID
|
||||||
numIDy = materials[1].numID
|
numIDy = materials[1].numID
|
||||||
|
|
||||||
for i in range(xs, xf):
|
for i in range(xs, xf):
|
||||||
for j in range(ys, yf):
|
for j in range(ys, yf):
|
||||||
build_face_xy(i, j, zs, numIDx, numIDy, grid.rigidE, grid.rigidH, grid.ID)
|
build_face_xy(i, j, zs, numIDx, numIDy, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
tqdm.write('Plate from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m of material(s) {} created.'.format(xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, ', '.join(materialsrequested)))
|
tqdm.write('Plate from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m of material(s) {} created.'.format(xs * grid.dx, ys * grid.dy, zs * grid.dz, xf * grid.dx, yf * grid.dy, zf * grid.dz, ', '.join(materialsrequested)))
|
||||||
|
@@ -1,91 +1,91 @@
|
|||||||
"""Class for sphere command."""
|
"""Class for sphere command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..materials import Material
|
from ..materials import Material
|
||||||
from ..cython.geometry_primitives import build_sphere
|
from ..cython.geometry_primitives import build_sphere
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class Sphere(UserObjectGeometry):
|
class Sphere(UserObjectGeometry):
|
||||||
"""User class for edge command."""
|
"""User class for edge command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 8
|
self.order = 8
|
||||||
self.hash = '#sphere'
|
self.hash = '#sphere'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
try:
|
try:
|
||||||
p1 = self.kwargs['p1']
|
p1 = self.kwargs['p1']
|
||||||
r = self.kwargs['r']
|
r = self.kwargs['r']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' Please specify a point and a radius.')
|
raise CmdInputError(self.__str__() + ' Please specify a point and a radius.')
|
||||||
|
|
||||||
# check averaging
|
# check averaging
|
||||||
try:
|
try:
|
||||||
# go with user specified averaging
|
# go with user specified averaging
|
||||||
averagesphere = self.kwargs['averaging']
|
averagesphere = self.kwargs['averaging']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# if they havent specfied - go with the grid default
|
# if they havent specfied - go with the grid default
|
||||||
averagesphere = grid.averagevolumeobjects
|
averagesphere = grid.averagevolumeobjects
|
||||||
|
|
||||||
# check materials have been specified
|
# check materials have been specified
|
||||||
# isotropic case
|
# isotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = [self.kwargs['material_id']]
|
materialsrequested = [self.kwargs['material_id']]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# Anisotropic case
|
# Anisotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
||||||
|
|
||||||
# Centre of sphere
|
# Centre of sphere
|
||||||
xc, yc, zc = uip.round_to_grid(p1)
|
xc, yc, zc = uip.round_to_grid(p1)
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
notfound = [x for x in materialsrequested if x not in materials]
|
||||||
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
||||||
|
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(materials) == 1:
|
if len(materials) == 1:
|
||||||
averaging = materials[0].averagable and averagesphere
|
averaging = materials[0].averagable and averagesphere
|
||||||
numID = numIDx = numIDy = numIDz = materials[0].numID
|
numID = numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(materials) == 3:
|
elif len(materials) == 3:
|
||||||
averaging = False
|
averaging = False
|
||||||
numIDx = materials[0].numID
|
numIDx = materials[0].numID
|
||||||
numIDy = materials[1].numID
|
numIDy = materials[1].numID
|
||||||
numIDz = materials[2].numID
|
numIDz = materials[2].numID
|
||||||
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
|
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
|
||||||
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
||||||
if averagedmaterial:
|
if averagedmaterial:
|
||||||
numID = averagedmaterial.numID
|
numID = averagedmaterial.numID
|
||||||
else:
|
else:
|
||||||
numID = len(grid.materials)
|
numID = len(grid.materials)
|
||||||
m = Material(numID, requiredID)
|
m = Material(numID, requiredID)
|
||||||
m.type = 'dielectric-smoothed'
|
m.type = 'dielectric-smoothed'
|
||||||
# Create dielectric-smoothed constituents for material
|
# Create dielectric-smoothed constituents for material
|
||||||
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
|
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
|
||||||
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
|
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
|
||||||
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
||||||
m.sm = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
m.sm = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
||||||
|
|
||||||
# Append the new material object to the materials list
|
# Append the new material object to the materials list
|
||||||
grid.materials.append(m)
|
grid.materials.append(m)
|
||||||
|
|
||||||
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)
|
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)
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
if averaging:
|
if averaging:
|
||||||
dielectricsmoothing = 'on'
|
dielectricsmoothing = 'on'
|
||||||
else:
|
else:
|
||||||
dielectricsmoothing = 'off'
|
dielectricsmoothing = 'off'
|
||||||
tqdm.write('Sphere with centre {:g}m, {:g}m, {:g}m, radius {:g}m, of material(s) {} created, dielectric smoothing is {}.'.format(xc * grid.dx, yc * grid.dy, zc * grid.dz, r, ', '.join(materialsrequested), dielectricsmoothing))
|
tqdm.write('Sphere with centre {:g}m, {:g}m, {:g}m, radius {:g}m, of material(s) {} created, dielectric smoothing is {}.'.format(xc * grid.dx, yc * grid.dy, zc * grid.dz, r, ', '.join(materialsrequested), dielectricsmoothing))
|
||||||
|
@@ -1,132 +1,132 @@
|
|||||||
"""Class for triangle command."""
|
"""Class for triangle command."""
|
||||||
from .cmds_geometry import UserObjectGeometry
|
from .cmds_geometry import UserObjectGeometry
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..materials import Material
|
from ..materials import Material
|
||||||
from ..cython.geometry_primitives import build_triangle
|
from ..cython.geometry_primitives import build_triangle
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class Triangle(UserObjectGeometry):
|
class Triangle(UserObjectGeometry):
|
||||||
"""User class for edge command."""
|
"""User class for edge command."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.order = 4
|
self.order = 4
|
||||||
self.hash = '#triangle'
|
self.hash = '#triangle'
|
||||||
|
|
||||||
def create(self, grid, uip):
|
def create(self, grid, uip):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
up1 = self.kwargs['p1']
|
up1 = self.kwargs['p1']
|
||||||
up2 = self.kwargs['p2']
|
up2 = self.kwargs['p2']
|
||||||
up3 = self.kwargs['p3']
|
up3 = self.kwargs['p3']
|
||||||
thickness = self.kwargs['thickness']
|
thickness = self.kwargs['thickness']
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.params_str() + ' Specify 3 points and a thickness')
|
raise CmdInputError(self.params_str() + ' Specify 3 points and a thickness')
|
||||||
|
|
||||||
# check averaging
|
# check averaging
|
||||||
try:
|
try:
|
||||||
# go with user specified averaging
|
# go with user specified averaging
|
||||||
averagetriangularprism = self.kwargs['averaging']
|
averagetriangularprism = self.kwargs['averaging']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# if they havent specfied - go with the grid default
|
# if they havent specfied - go with the grid default
|
||||||
averagetriangularprism = grid.averagevolumeobjects
|
averagetriangularprism = grid.averagevolumeobjects
|
||||||
|
|
||||||
# check materials have been specified
|
# check materials have been specified
|
||||||
# isotropic case
|
# isotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = [self.kwargs['material_id']]
|
materialsrequested = [self.kwargs['material_id']]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# Anisotropic case
|
# Anisotropic case
|
||||||
try:
|
try:
|
||||||
materialsrequested = self.kwargs['material_ids']
|
materialsrequested = self.kwargs['material_ids']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
raise CmdInputError(self.__str__() + ' No materials have been specified')
|
||||||
|
|
||||||
# Check whether points are valid against grid
|
# Check whether points are valid against grid
|
||||||
uip.check_tri_points(up1, up2, up3, object)
|
uip.check_tri_points(up1, up2, up3, object)
|
||||||
# Convert points to metres
|
# Convert points to metres
|
||||||
x1, y1, z1 = uip.round_to_grid(up1)
|
x1, y1, z1 = uip.round_to_grid(up1)
|
||||||
x2, y2, z2 = uip.round_to_grid(up2)
|
x2, y2, z2 = uip.round_to_grid(up2)
|
||||||
x3, y3, z3 = uip.round_to_grid(up3)
|
x3, y3, z3 = uip.round_to_grid(up3)
|
||||||
|
|
||||||
if thickness < 0:
|
if thickness < 0:
|
||||||
raise CmdInputError(self.__str__() + ' requires a positive value for thickness')
|
raise CmdInputError(self.__str__() + ' requires a positive value for thickness')
|
||||||
|
|
||||||
# Check for valid orientations
|
# Check for valid orientations
|
||||||
# yz-plane triangle
|
# yz-plane triangle
|
||||||
if x1 == x2 and x2 == x3:
|
if x1 == x2 and x2 == x3:
|
||||||
normal = 'x'
|
normal = 'x'
|
||||||
# xz-plane triangle
|
# xz-plane triangle
|
||||||
elif y1 == y2 and y2 == y3:
|
elif y1 == y2 and y2 == y3:
|
||||||
normal = 'y'
|
normal = 'y'
|
||||||
# xy-plane triangle
|
# xy-plane triangle
|
||||||
elif z1 == z2 and z2 == z3:
|
elif z1 == z2 and z2 == z3:
|
||||||
normal = 'z'
|
normal = 'z'
|
||||||
else:
|
else:
|
||||||
raise CmdInputError(self.__str__() + ' the triangle is not specified correctly')
|
raise CmdInputError(self.__str__() + ' the triangle is not specified correctly')
|
||||||
|
|
||||||
# Look up requested materials in existing list of material instances
|
# Look up requested materials in existing list of material instances
|
||||||
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
materials = [y for x in materialsrequested for y in grid.materials if y.ID == x]
|
||||||
|
|
||||||
if len(materials) != len(materialsrequested):
|
if len(materials) != len(materialsrequested):
|
||||||
notfound = [x for x in materialsrequested if x not in materials]
|
notfound = [x for x in materialsrequested if x not in materials]
|
||||||
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
raise CmdInputError(self.__str__() + ' material(s) {} do not exist'.format(notfound))
|
||||||
|
|
||||||
if thickness > 0:
|
if thickness > 0:
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(materials) == 1:
|
if len(materials) == 1:
|
||||||
averaging = materials[0].averagable and averagetriangularprism
|
averaging = materials[0].averagable and averagetriangularprism
|
||||||
numID = numIDx = numIDy = numIDz = materials[0].numID
|
numID = numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(materials) == 3:
|
elif len(materials) == 3:
|
||||||
averaging = False
|
averaging = False
|
||||||
numIDx = materials[0].numID
|
numIDx = materials[0].numID
|
||||||
numIDy = materials[1].numID
|
numIDy = materials[1].numID
|
||||||
numIDz = materials[2].numID
|
numIDz = materials[2].numID
|
||||||
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
|
requiredID = materials[0].ID + '+' + materials[1].ID + '+' + materials[2].ID
|
||||||
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
averagedmaterial = [x for x in grid.materials if x.ID == requiredID]
|
||||||
if averagedmaterial:
|
if averagedmaterial:
|
||||||
numID = averagedmaterial.numID
|
numID = averagedmaterial.numID
|
||||||
else:
|
else:
|
||||||
numID = len(grid.materials)
|
numID = len(grid.materials)
|
||||||
m = Material(numID, requiredID)
|
m = Material(numID, requiredID)
|
||||||
m.type = 'dielectric-smoothed'
|
m.type = 'dielectric-smoothed'
|
||||||
# Create dielectric-smoothed constituents for material
|
# Create dielectric-smoothed constituents for material
|
||||||
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
|
m.er = np.mean((materials[0].er, materials[1].er, materials[2].er), axis=0)
|
||||||
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
|
m.se = np.mean((materials[0].se, materials[1].se, materials[2].se), axis=0)
|
||||||
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
m.mr = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
||||||
m.sm = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
m.sm = np.mean((materials[0].mr, materials[1].mr, materials[2].mr), axis=0)
|
||||||
|
|
||||||
# Append the new material object to the materials list
|
# Append the new material object to the materials list
|
||||||
grid.materials.append(m)
|
grid.materials.append(m)
|
||||||
else:
|
else:
|
||||||
averaging = False
|
averaging = False
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(materials) == 1:
|
if len(materials) == 1:
|
||||||
numID = numIDx = numIDy = numIDz = materials[0].numID
|
numID = numIDx = numIDy = numIDz = materials[0].numID
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(materials) == 3:
|
elif len(materials) == 3:
|
||||||
# numID requires a value but it will not be used
|
# numID requires a value but it will not be used
|
||||||
numID = None
|
numID = None
|
||||||
numIDx = materials[0].numID
|
numIDx = materials[0].numID
|
||||||
numIDy = materials[1].numID
|
numIDy = materials[1].numID
|
||||||
numIDz = materials[2].numID
|
numIDz = materials[2].numID
|
||||||
|
|
||||||
build_triangle(x1, y1, z1, x2, y2, z2, x3, y3, z3, normal, thickness, grid.dx, grid.dy, grid.dz, numID, numIDx, numIDy, numIDz, averaging, grid.solid, grid.rigidE, grid.rigidH, grid.ID)
|
build_triangle(x1, y1, z1, x2, y2, z2, x3, y3, z3, normal, thickness, grid.dx, grid.dy, grid.dz, numID, numIDx, numIDy, numIDz, averaging, grid.solid, grid.rigidE, grid.rigidH, grid.ID)
|
||||||
|
|
||||||
if config.is_messages():
|
if config.is_messages():
|
||||||
if thickness > 0:
|
if thickness > 0:
|
||||||
if averaging:
|
if averaging:
|
||||||
dielectricsmoothing = 'on'
|
dielectricsmoothing = 'on'
|
||||||
else:
|
else:
|
||||||
dielectricsmoothing = 'off'
|
dielectricsmoothing = 'off'
|
||||||
tqdm.write('Triangle with coordinates {:g}m {:g}m {:g}m, {:g}m {:g}m {:g}m, {:g}m {:g}m {:g}m and thickness {:g}m of material(s) {} created, dielectric smoothing is {}.'.format(x1, y1, z1, x2, y2, z2, x3, y3, z3, thickness, ', '.join(materialsrequested), dielectricsmoothing))
|
tqdm.write('Triangle with coordinates {:g}m {:g}m {:g}m, {:g}m {:g}m {:g}m, {:g}m {:g}m {:g}m and thickness {:g}m of material(s) {} created, dielectric smoothing is {}.'.format(x1, y1, z1, x2, y2, z2, x3, y3, z3, thickness, ', '.join(materialsrequested), dielectricsmoothing))
|
||||||
else:
|
else:
|
||||||
tqdm.write('Triangle with coordinates {:g}m {:g}m {:g}m, {:g}m {:g}m {:g}m, {:g}m {:g}m {:g}m of material(s) {} created.'.format(x1, y1, z1, x2, y2, z2, x3, y3, z3, ', '.join(materialsrequested)))
|
tqdm.write('Triangle with coordinates {:g}m {:g}m {:g}m, {:g}m {:g}m {:g}m, {:g}m {:g}m {:g}m of material(s) {} created.'.format(x1, y1, z1, x2, y2, z2, x3, y3, z3, ', '.join(materialsrequested)))
|
||||||
|
文件差异内容过多而无法显示
加载差异
文件差异内容过多而无法显示
加载差异
534
gprMax/config.py
534
gprMax/config.py
@@ -1,267 +1,267 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import cython
|
import cython
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from scipy.constants import c
|
from scipy.constants import c
|
||||||
from scipy.constants import mu_0 as m0
|
from scipy.constants import mu_0 as m0
|
||||||
from scipy.constants import epsilon_0 as e0
|
from scipy.constants import epsilon_0 as e0
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from .utilities import get_terminal_width
|
from .utilities import get_terminal_width
|
||||||
from .utilities import get_host_info
|
from .utilities import get_host_info
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from colorama import init
|
from colorama import init
|
||||||
from colorama import Fore
|
from colorama import Fore
|
||||||
from colorama import Style
|
from colorama import Style
|
||||||
init()
|
init()
|
||||||
|
|
||||||
|
|
||||||
# Impedance of free space (Ohms)
|
# Impedance of free space (Ohms)
|
||||||
z0 = np.sqrt(m0 / e0)
|
z0 = np.sqrt(m0 / e0)
|
||||||
|
|
||||||
# General setting for the simulation
|
# General setting for the simulation
|
||||||
# inputfilepath: path to inputfile location
|
# inputfilepath: path to inputfile location
|
||||||
# outputfilepath: path to outputfile location
|
# outputfilepath: path to outputfile location
|
||||||
# messages: whether to print all messages as output to stdout or not
|
# messages: whether to print all messages as output to stdout or not
|
||||||
# progressbars: whether to show progress bars on stdoout or not
|
# progressbars: whether to show progress bars on stdoout or not
|
||||||
# mode: 2D TMx, 2D TMy, 2D TMz, or 3D
|
# mode: 2D TMx, 2D TMy, 2D TMz, or 3D
|
||||||
# cpu, cuda, opencl: solver type
|
# cpu, cuda, opencl: solver type
|
||||||
# autotranslate: auto translate objects with main grid coordinates
|
# autotranslate: auto translate objects with main grid coordinates
|
||||||
# to their equivalent local grid coordinate within the subgrid. If this option is off
|
# 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.
|
# users must specify sub-grid object point within the global subgrid space.
|
||||||
general = {'inputfilepath': 'gprMax', 'outputfilepath': 'gprMax', 'messages': True,
|
general = {'inputfilepath': 'gprMax', 'outputfilepath': 'gprMax', 'messages': True,
|
||||||
'progressbars': True, 'mode': '3D', 'cpu': True, 'cuda': False, 'opencl': False, 'autotranslate': False}
|
'progressbars': True, 'mode': '3D', 'cpu': True, 'cuda': False, 'opencl': False, 'autotranslate': False}
|
||||||
|
|
||||||
|
|
||||||
def is_messages():
|
def is_messages():
|
||||||
"""Function to return messages."""
|
"""Function to return messages."""
|
||||||
return general['messages']
|
return general['messages']
|
||||||
|
|
||||||
|
|
||||||
# Store information about host machine
|
# Store information about host machine
|
||||||
hostinfo = get_host_info()
|
hostinfo = get_host_info()
|
||||||
|
|
||||||
# Store information for CUDA solver type
|
# Store information for CUDA solver type
|
||||||
# gpus: information about any GPUs as a list of GPU objects
|
# gpus: information about any GPUs as a list of GPU objects
|
||||||
# snapsgpu2cpu: copy snapshot data from GPU to CPU during simulation
|
# snapsgpu2cpu: copy snapshot data from GPU to CPU during simulation
|
||||||
# N.B. This will happen if the requested snapshots are too large to fit
|
# 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
|
# on the memory of the GPU. If True this will slow performance significantly
|
||||||
cuda = {'gpus': None, 'snapsgpu2cpu': False}
|
cuda = {'gpus': None, 'snapsgpu2cpu': False}
|
||||||
|
|
||||||
# Numerical dispersion analysis parameters
|
# Numerical dispersion analysis parameters
|
||||||
# highestfreqthres: threshold (dB) down from maximum power (0dB) of main frequency used
|
# highestfreqthres: threshold (dB) down from maximum power (0dB) of main frequency used
|
||||||
# to calculate highest frequency for numerical dispersion analysis
|
# to calculate highest frequency for numerical dispersion analysis
|
||||||
# maxnumericaldisp: maximum allowable percentage physical phase-velocity phase error
|
# maxnumericaldisp: maximum allowable percentage physical phase-velocity phase error
|
||||||
# mingridsampling: minimum grid sampling of smallest wavelength for physical wave propagation
|
# mingridsampling: minimum grid sampling of smallest wavelength for physical wave propagation
|
||||||
numdispersion = {'highestfreqthres': 40, 'maxnumericaldisp': 2, 'mingridsampling': 3}
|
numdispersion = {'highestfreqthres': 40, 'maxnumericaldisp': 2, 'mingridsampling': 3}
|
||||||
|
|
||||||
# Materials
|
# Materials
|
||||||
# maxpoles: Maximum number of dispersive material poles in a model
|
# maxpoles: Maximum number of dispersive material poles in a model
|
||||||
materials = {'maxpoles': 0, 'dispersivedtype': None, 'dispersiveCdtype': None}
|
materials = {'maxpoles': 0, 'dispersivedtype': None, 'dispersiveCdtype': None}
|
||||||
|
|
||||||
# Data types
|
# Data types
|
||||||
# Solid and ID arrays use 32-bit integers (0 to 4294967295)
|
# 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)
|
# Rigid arrays use 8-bit integers (the smallest available type to store true/false)
|
||||||
# Fractal and dispersive coefficient arrays use complex numbers (complex)
|
# Fractal and dispersive coefficient arrays use complex numbers (complex)
|
||||||
# which are represented as two floats
|
# which are represented as two floats
|
||||||
# Main field arrays use floats (float_or_double) and complex numbers (complex)
|
# Main field arrays use floats (float_or_double) and complex numbers (complex)
|
||||||
# Precision of float_or_double and complex: single or double for numpy and C (CUDA) arrays
|
# Precision of float_or_double and complex: single or double for numpy and C (CUDA) arrays
|
||||||
precision = 'double'
|
precision = 'double'
|
||||||
|
|
||||||
if precision == 'single':
|
if precision == 'single':
|
||||||
dtypes = {'float_or_double': np.float32, 'complex': np.complex64,
|
dtypes = {'float_or_double': np.float32, 'complex': np.complex64,
|
||||||
'cython_float_or_double': cython.float, 'cython_complex': cython.floatcomplex,
|
'cython_float_or_double': cython.float, 'cython_complex': cython.floatcomplex,
|
||||||
'C_float_or_double': 'float', 'C_complex': 'pycuda::complex<float>'}
|
'C_float_or_double': 'float', 'C_complex': 'pycuda::complex<float>'}
|
||||||
elif precision == 'double':
|
elif precision == 'double':
|
||||||
dtypes = {'float_or_double': np.float64, 'complex': np.complex128,
|
dtypes = {'float_or_double': np.float64, 'complex': np.complex128,
|
||||||
'cython_float_or_double': cython.double, 'cython_complex': cython.doublecomplex,
|
'cython_float_or_double': cython.double, 'cython_complex': cython.doublecomplex,
|
||||||
'C_float_or_double': 'double', 'C_complex': 'pycuda::complex<double>'}
|
'C_float_or_double': 'double', 'C_complex': 'pycuda::complex<double>'}
|
||||||
|
|
||||||
|
|
||||||
class ModelConfig():
|
class ModelConfig():
|
||||||
|
|
||||||
def __init__(self, sim_config, i):
|
def __init__(self, sim_config, i):
|
||||||
self.sim_config = sim_config
|
self.sim_config = sim_config
|
||||||
self.reuse_geometry = False
|
self.reuse_geometry = False
|
||||||
|
|
||||||
# current model number (indexed from 0)
|
# current model number (indexed from 0)
|
||||||
self.i = i
|
self.i = i
|
||||||
|
|
||||||
parts = self.sim_config.output_file_path.parts
|
parts = self.sim_config.output_file_path.parts
|
||||||
|
|
||||||
if not sim_config.single_model:
|
if not sim_config.single_model:
|
||||||
# 1 indexed
|
# 1 indexed
|
||||||
self.appendmodelnumber = str(self.i + 1)
|
self.appendmodelnumber = str(self.i + 1)
|
||||||
else:
|
else:
|
||||||
self.appendmodelnumber = ''
|
self.appendmodelnumber = ''
|
||||||
|
|
||||||
# outputfilepath for specific model
|
# outputfilepath for specific model
|
||||||
self.output_file_path = Path(*parts[:-2], parts[-1] + self.appendmodelnumber)
|
self.output_file_path = Path(*parts[:-2], parts[-1] + self.appendmodelnumber)
|
||||||
self.output_file_path_ext = self.output_file_path.with_suffix('.out')
|
self.output_file_path_ext = self.output_file_path.with_suffix('.out')
|
||||||
|
|
||||||
# make a snapshot directory
|
# make a snapshot directory
|
||||||
stem = parts[-1] + '_snaps' + self.appendmodelnumber
|
stem = parts[-1] + '_snaps' + self.appendmodelnumber
|
||||||
self.snapshot_dir = Path(*parts[:-2], stem)
|
self.snapshot_dir = Path(*parts[:-2], stem)
|
||||||
|
|
||||||
inputfilestr_f = '\n--- Model {}/{}, input file: {}'
|
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, self.sim_config.model_end, self.sim_config.input_file_path)
|
||||||
# string to print at start of each model run
|
# string to print at start of each model run
|
||||||
self.next_model = Fore.GREEN + '{} {}\n'.format(self.inputfilestr, '-' * (get_terminal_width() - 1 - len(self.inputfilestr))) + Style.RESET_ALL
|
self.next_model = Fore.GREEN + '{} {}\n'.format(self.inputfilestr, '-' * (get_terminal_width() - 1 - len(self.inputfilestr))) + Style.RESET_ALL
|
||||||
|
|
||||||
# Add the current model run to namespace that can be accessed by
|
# Add the current model run to namespace that can be accessed by
|
||||||
# user in any Python code blocks in input file
|
# user in any Python code blocks in input file
|
||||||
#self.usernamespace['current_model_run'] = self.i + 1
|
#self.usernamespace['current_model_run'] = self.i + 1
|
||||||
|
|
||||||
def get_scene(self):
|
def get_scene(self):
|
||||||
if self.sim_config.scenes:
|
if self.sim_config.scenes:
|
||||||
return self.sim_config.scenes[self.i]
|
return self.sim_config.scenes[self.i]
|
||||||
else: return None
|
else: return None
|
||||||
|
|
||||||
def get_usernamespace(self):
|
def get_usernamespace(self):
|
||||||
return {'c': c,
|
return {'c': c,
|
||||||
'e0': e0,
|
'e0': e0,
|
||||||
'm0': m0,
|
'm0': m0,
|
||||||
'z0': z0,
|
'z0': z0,
|
||||||
'number_model_runs': self.sim_config.model_end + 1,
|
'number_model_runs': self.sim_config.model_end + 1,
|
||||||
'current_model_run': self.i + 1,
|
'current_model_run': self.i + 1,
|
||||||
'inputfile': self.sim_config.input_file_path.resolve()}
|
'inputfile': self.sim_config.input_file_path.resolve()}
|
||||||
|
|
||||||
|
|
||||||
class SimulationConfig:
|
class SimulationConfig:
|
||||||
|
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
"""Adapter for args into Simulation level configuration"""
|
"""Adapter for args into Simulation level configuration"""
|
||||||
|
|
||||||
# adapt the arg properties to link smoothly with MPIRunner(), CPURunner() etc..
|
# adapt the arg properties to link smoothly with MPIRunner(), CPURunner() etc..
|
||||||
|
|
||||||
# args.inputfile
|
# args.inputfile
|
||||||
# args.n
|
# args.n
|
||||||
# args.task
|
# args.task
|
||||||
# args.restart
|
# args.restart
|
||||||
# args.mpi
|
# args.mpi
|
||||||
# args.mpi_no_spawn
|
# args.mpi_no_spawn
|
||||||
# args.mpicomm
|
# args.mpicomm
|
||||||
# args.gpu
|
# args.gpu
|
||||||
# args.benchmark
|
# args.benchmark
|
||||||
# args.geometry_only
|
# args.geometry_only
|
||||||
# args.geometry_fixed
|
# args.geometry_fixed
|
||||||
# args.write_processed
|
# args.write_processed
|
||||||
|
|
||||||
self.args = args
|
self.args = args
|
||||||
self.n_models = args.n
|
self.n_models = args.n
|
||||||
self.inputfile = args.inputfile
|
self.inputfile = args.inputfile
|
||||||
self.gpu = args.gpu
|
self.gpu = args.gpu
|
||||||
self.mpi = args.mpi
|
self.mpi = args.mpi
|
||||||
self.mpi_no_spawn = args.mpi_no_spawn
|
self.mpi_no_spawn = args.mpi_no_spawn
|
||||||
self.general = {}
|
self.general = {}
|
||||||
self.general['messages'] = general['messages']
|
self.general['messages'] = general['messages']
|
||||||
self.geometry_fixed = args.geometry_fixed
|
self.geometry_fixed = args.geometry_fixed
|
||||||
self.geometry_only = args.geometry_only
|
self.geometry_only = args.geometry_only
|
||||||
self.write_processed = args.write_processed
|
self.write_processed = args.write_processed
|
||||||
|
|
||||||
# subgrid parameter may not exist if user uses CLI api
|
# subgrid parameter may not exist if user uses CLI api
|
||||||
try:
|
try:
|
||||||
self.subgrid = args.subgrid
|
self.subgrid = args.subgrid
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# this must be CLI user. No subgrids are available
|
# this must be CLI user. No subgrids are available
|
||||||
self.subgrid = False
|
self.subgrid = False
|
||||||
|
|
||||||
# scenes parameter may not exist if user uses CLI api
|
# scenes parameter may not exist if user uses CLI api
|
||||||
try:
|
try:
|
||||||
self.scenes = args.scenes
|
self.scenes = args.scenes
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self.scenes = []
|
self.scenes = []
|
||||||
|
|
||||||
# set more complex parameters
|
# set more complex parameters
|
||||||
self.set_input_file_path()
|
self.set_input_file_path()
|
||||||
self.set_output_file_path()
|
self.set_output_file_path()
|
||||||
self.set_model_start_end()
|
self.set_model_start_end()
|
||||||
self.set_single_model()
|
self.set_single_model()
|
||||||
|
|
||||||
def set_single_model(self):
|
def set_single_model(self):
|
||||||
if self.model_start == 0 and self.model_end == 1:
|
if self.model_start == 0 and self.model_end == 1:
|
||||||
self.single_model = True
|
self.single_model = True
|
||||||
else:
|
else:
|
||||||
self.single_model = False
|
self.single_model = False
|
||||||
|
|
||||||
# for example
|
# for example
|
||||||
def set_model_start_end(self):
|
def set_model_start_end(self):
|
||||||
|
|
||||||
# set range for number of models to run (internally 0 index)
|
# set range for number of models to run (internally 0 index)
|
||||||
if self.args.task:
|
if self.args.task:
|
||||||
# Job array feeds args.n number of single tasks
|
# Job array feeds args.n number of single tasks
|
||||||
modelstart = self.args.task - 1
|
modelstart = self.args.task - 1
|
||||||
modelend = self.args.task
|
modelend = self.args.task
|
||||||
elif self.args.restart:
|
elif self.args.restart:
|
||||||
modelstart = self.args.restart - 1
|
modelstart = self.args.restart - 1
|
||||||
modelend = modelstart + self.args.n - 1
|
modelend = modelstart + self.args.n - 1
|
||||||
else:
|
else:
|
||||||
modelstart = 0
|
modelstart = 0
|
||||||
modelend = modelstart + self.args.n
|
modelend = modelstart + self.args.n
|
||||||
|
|
||||||
self.model_start = modelstart
|
self.model_start = modelstart
|
||||||
self.model_end = modelend
|
self.model_end = modelend
|
||||||
|
|
||||||
def set_precision(self):
|
def set_precision(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def set_input_file_path(self):
|
def set_input_file_path(self):
|
||||||
"""Function to set to inputfile path"""
|
"""Function to set to inputfile path"""
|
||||||
|
|
||||||
# if the API is in use an id for the simulation must be provided.
|
# if the API is in use an id for the simulation must be provided.
|
||||||
if self.args.inputfile is None:
|
if self.args.inputfile is None:
|
||||||
self.input_file_path = Path(self.args.outputfile)
|
self.input_file_path = Path(self.args.outputfile)
|
||||||
else:
|
else:
|
||||||
self.input_file_path = Path(self.args.inputfile)
|
self.input_file_path = Path(self.args.inputfile)
|
||||||
|
|
||||||
def set_output_file_path(self):
|
def set_output_file_path(self):
|
||||||
# output file can be provided by the user. if they havent provided None
|
# output file can be provided by the user. if they havent provided None
|
||||||
# use the inputfilefile path instead
|
# use the inputfilefile path instead
|
||||||
try:
|
try:
|
||||||
self.output_file_path = Path(self.args.outputfile)
|
self.output_file_path = Path(self.args.outputfile)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self.output_file_path = Path(self.args.inputfile)
|
self.output_file_path = Path(self.args.inputfile)
|
||||||
|
|
||||||
|
|
||||||
class SimulationConfigMPI(SimulationConfig):
|
class SimulationConfigMPI(SimulationConfig):
|
||||||
|
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
super().__init__(args)
|
super().__init__(args)
|
||||||
|
|
||||||
def set_model_start_end(self):
|
def set_model_start_end(self):
|
||||||
# Set range for number of models to run
|
# Set range for number of models to run
|
||||||
self.model_start = self.args.restart if self.args.restart else 1
|
self.model_start = self.args.restart if self.args.restart else 1
|
||||||
self.model_end = self.modelstart + self.args.n
|
self.model_end = self.modelstart + self.args.n
|
||||||
|
|
||||||
|
|
||||||
def create_simulation_config(args):
|
def create_simulation_config(args):
|
||||||
|
|
||||||
if not args.mpi and not args.mpi_no_spawn:
|
if not args.mpi and not args.mpi_no_spawn:
|
||||||
sc = SimulationConfig(args)
|
sc = SimulationConfig(args)
|
||||||
elif args.mpi:
|
elif args.mpi:
|
||||||
sc = SimulationConfigMPI(args)
|
sc = SimulationConfigMPI(args)
|
||||||
return sc
|
return sc
|
||||||
|
|
||||||
|
|
||||||
def create_model_config(sim_config, i):
|
def create_model_config(sim_config, i):
|
||||||
mc = ModelConfig(sim_config, i)
|
mc = ModelConfig(sim_config, i)
|
||||||
return mc
|
return mc
|
||||||
|
@@ -1,119 +1,119 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
from .utilities import get_terminal_width
|
from .utilities import get_terminal_width
|
||||||
from .utilities import timer
|
from .utilities import timer
|
||||||
from .model_build_run import ModelBuildRun
|
from .model_build_run import ModelBuildRun
|
||||||
import datetime
|
import datetime
|
||||||
from .config import create_model_config
|
from .config import create_model_config
|
||||||
from .solvers import create_solver
|
from .solvers import create_solver
|
||||||
from .solvers import create_G
|
from .solvers import create_G
|
||||||
|
|
||||||
|
|
||||||
class Context():
|
class Context():
|
||||||
|
|
||||||
def __init__(self, sim_config):
|
def __init__(self, sim_config):
|
||||||
"""Context for the model to run in. Sub-class this with contexts
|
"""Context for the model to run in. Sub-class this with contexts
|
||||||
i.e. an MPI context.
|
i.e. an MPI context.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sim_config (SimConfig): Simulation level configuration object.
|
sim_config (SimConfig): Simulation level configuration object.
|
||||||
solver (Solver): FDTD general solver object.
|
solver (Solver): FDTD general solver object.
|
||||||
"""
|
"""
|
||||||
self.sim_config = sim_config
|
self.sim_config = sim_config
|
||||||
self.model_range = range(sim_config.model_start,
|
self.model_range = range(sim_config.model_start,
|
||||||
sim_config.model_end)
|
sim_config.model_end)
|
||||||
self.tsimend = 0
|
self.tsimend = 0
|
||||||
self.tsimstart = 1
|
self.tsimstart = 1
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Function to run the simulation in the correct context."""
|
"""Function to run the simulation in the correct context."""
|
||||||
self.tsimstart = timer()
|
self.tsimstart = timer()
|
||||||
self._run()
|
self._run()
|
||||||
self.tsimend = timer()
|
self.tsimend = timer()
|
||||||
|
|
||||||
def print_time_report(self):
|
def print_time_report(self):
|
||||||
"""Function to print the total simulation time based on context."""
|
"""Function to print the total simulation time based on context."""
|
||||||
s = self.make_time_report(sim_time)
|
s = self.make_time_report(sim_time)
|
||||||
print(s)
|
print(s)
|
||||||
|
|
||||||
def make_time_report(self):
|
def make_time_report(self):
|
||||||
"""Function to generate a string for the total simulation time bas"""
|
"""Function to generate a string for the total simulation time bas"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NoMPIContext(Context):
|
class NoMPIContext(Context):
|
||||||
|
|
||||||
def _run(self):
|
def _run(self):
|
||||||
"""Specialise how the models are farmed out."""
|
"""Specialise how the models are farmed out."""
|
||||||
|
|
||||||
for i in self.model_range:
|
for i in self.model_range:
|
||||||
model_config = create_model_config(self.sim_config, i)
|
model_config = create_model_config(self.sim_config, i)
|
||||||
|
|
||||||
# always create a solver for the first model
|
# always create a solver for the first model
|
||||||
# the next model to run only gets a new solver if the
|
# the next model to run only gets a new solver if the
|
||||||
# geometry is not re used.
|
# geometry is not re used.
|
||||||
if i != 0 and self.sim_config.geometry_fixed:
|
if i != 0 and self.sim_config.geometry_fixed:
|
||||||
model_config.reuse_geometry = True
|
model_config.reuse_geometry = True
|
||||||
else:
|
else:
|
||||||
G = create_G(self.sim_config)
|
G = create_G(self.sim_config)
|
||||||
|
|
||||||
model = ModelBuildRun(G, self.sim_config, model_config)
|
model = ModelBuildRun(G, self.sim_config, model_config)
|
||||||
model.build()
|
model.build()
|
||||||
|
|
||||||
solver = create_solver(G, self.sim_config)
|
solver = create_solver(G, self.sim_config)
|
||||||
|
|
||||||
if not self.sim_config.geometry_only:
|
if not self.sim_config.geometry_only:
|
||||||
model.run_model(solver)
|
model.run_model(solver)
|
||||||
|
|
||||||
def make_time_report(self):
|
def make_time_report(self):
|
||||||
"""Function to specialise the time reporting for the standard Simulation
|
"""Function to specialise the time reporting for the standard Simulation
|
||||||
context."""
|
context."""
|
||||||
sim_time = datetime.timedelta(seconds=self.tsimend - self.tsimstart)
|
sim_time = datetime.timedelta(seconds=self.tsimend - self.tsimstart)
|
||||||
s = '\n=== Simulation on {} completed in [HH:MM:SS]: {}'
|
s = '\n=== Simulation on {} completed in [HH:MM:SS]: {}'
|
||||||
s = s.format(self.simconfig.hostinfo['hostname'], sim_time)
|
s = s.format(self.simconfig.hostinfo['hostname'], sim_time)
|
||||||
return '{} {}\n'.format(s, '=' * (get_terminal_width() - 1 - len(s)))
|
return '{} {}\n'.format(s, '=' * (get_terminal_width() - 1 - len(s)))
|
||||||
|
|
||||||
|
|
||||||
class MPIContext(Context):
|
class MPIContext(Context):
|
||||||
|
|
||||||
def _run(self):
|
def _run(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def make_time_report(self):
|
def make_time_report(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MPINoSpawnContext(Context):
|
class MPINoSpawnContext(Context):
|
||||||
|
|
||||||
def _run(self):
|
def _run(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def make_time_report(self):
|
def make_time_report(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def create_context(sim_config):
|
def create_context(sim_config):
|
||||||
"""Create a context in which to run the simulation. i.e MPI."""
|
"""Create a context in which to run the simulation. i.e MPI."""
|
||||||
if sim_config.mpi_no_spawn:
|
if sim_config.mpi_no_spawn:
|
||||||
context = MPIContext(sim_config)
|
context = MPIContext(sim_config)
|
||||||
elif sim_config.mpi:
|
elif sim_config.mpi:
|
||||||
context = MPINoSpawnContext(sim_config)
|
context = MPINoSpawnContext(sim_config)
|
||||||
else:
|
else:
|
||||||
context = NoMPIContext(sim_config)
|
context = NoMPIContext(sim_config)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
@@ -1,281 +1,281 @@
|
|||||||
# Copyright (C) 2015-2017: The University of Edinburgh
|
# Copyright (C) 2015-2017: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
import numpy as np
|
import numpy as np
|
||||||
cimport numpy as np
|
cimport numpy as np
|
||||||
from cython.parallel import prange
|
from cython.parallel import prange
|
||||||
|
|
||||||
cpdef void cython_update_electric_os(
|
cpdef void cython_update_electric_os(
|
||||||
np.float64_t[:, :] updatecoeffsE,
|
np.float64_t[:, :] updatecoeffsE,
|
||||||
np.uint32_t[:, :, :, :] ID,
|
np.uint32_t[:, :, :, :] ID,
|
||||||
int face,
|
int face,
|
||||||
int l_l,
|
int l_l,
|
||||||
int l_u,
|
int l_u,
|
||||||
int m_l,
|
int m_l,
|
||||||
int m_u,
|
int m_u,
|
||||||
size_t n_l,
|
size_t n_l,
|
||||||
size_t n_u,
|
size_t n_u,
|
||||||
int nwn,
|
int nwn,
|
||||||
size_t lookup_id,
|
size_t lookup_id,
|
||||||
np.float64_t[:, :, :] field,
|
np.float64_t[:, :, :] field,
|
||||||
np.float64_t[:, :, :] inc_field,
|
np.float64_t[:, :, :] inc_field,
|
||||||
size_t co,
|
size_t co,
|
||||||
int sign_n,
|
int sign_n,
|
||||||
int sign_f,
|
int sign_f,
|
||||||
int mid,
|
int mid,
|
||||||
int r,
|
int r,
|
||||||
int s,
|
int s,
|
||||||
int nb,
|
int nb,
|
||||||
int nthreads
|
int nthreads
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
|
|
||||||
subgrid: (Subgrid)
|
subgrid: (Subgrid)
|
||||||
n: (String) the normal to the face to update
|
n: (String) the normal to the face to update
|
||||||
nwn: (Int) number of working cell in the normal direction
|
nwn: (Int) number of working cell in the normal direction
|
||||||
to the face
|
to the face
|
||||||
lookup_id: (Int) id of the H component we wish to update at
|
lookup_id: (Int) id of the H component we wish to update at
|
||||||
each node
|
each node
|
||||||
field: (Numpy array) main grid field to be updated
|
field: (Numpy array) main grid field to be updated
|
||||||
inc_field: (Numpy array) incident sub_grid field
|
inc_field: (Numpy array) incident sub_grid field
|
||||||
co: (Int) Coefficient used by gprMax update equations which
|
co: (Int) Coefficient used by gprMax update equations which
|
||||||
is specific to the field component being updated.
|
is specific to the field component being updated.
|
||||||
sign_n: (Int) 1 or -1 sign of the incident field on the near face.
|
sign_n: (Int) 1 or -1 sign of the incident field on the near face.
|
||||||
sign_f: (Int) 1 or -1 sign of the incident field on the far face.
|
sign_f: (Int) 1 or -1 sign of the incident field on the far face.
|
||||||
mid: (Bool) is the H node midway along the lower edge?
|
mid: (Bool) is the H node midway along the lower edge?
|
||||||
r = self.ratio
|
r = self.ratio
|
||||||
s = self.is_os_sep
|
s = self.is_os_sep
|
||||||
nb = self.n_boundary_cells
|
nb = self.n_boundary_cells
|
||||||
"""
|
"""
|
||||||
# Comments here as as per left and right face
|
# Comments here as as per left and right face
|
||||||
|
|
||||||
cdef Py_ssize_t l, m, l_s, m_s, n_s_l, n_s_r, material_e_l, material_e_r, i0, j0, k0, i1, j1, k1, i2, j2, k2, i3, j3, k3
|
cdef Py_ssize_t l, m, l_s, m_s, n_s_l, n_s_r, material_e_l, material_e_r, i0, j0, k0, i1, j1, k1, i2, j2, k2, i3, j3, k3
|
||||||
cdef int os
|
cdef int os
|
||||||
cdef double inc_n, inc_f
|
cdef double inc_n, inc_f
|
||||||
|
|
||||||
# surface normal index for the subgrid near face h nodes (left i index)
|
# surface normal index for the subgrid near face h nodes (left i index)
|
||||||
n_s_l = nb - s * r - r + r // 2
|
n_s_l = nb - s * r - r + r // 2
|
||||||
# surface normal index for the subgrid far face h nodes (right i index)
|
# surface normal index for the subgrid far face h nodes (right i index)
|
||||||
n_s_r = nb + nwn + s * r + r // 2
|
n_s_r = nb + nwn + s * r + r // 2
|
||||||
# OS at the left face
|
# OS at the left face
|
||||||
os = nb - r * s
|
os = nb - r * s
|
||||||
|
|
||||||
# Iterate over a slice of the main grid using dummy indices
|
# Iterate over a slice of the main grid using dummy indices
|
||||||
for l in prange(l_l, l_u, nogil=True, schedule='static', num_threads=nthreads):
|
for l in prange(l_l, l_u, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
|
|
||||||
# Calculate the subgrid j component of the H nodes
|
# Calculate the subgrid j component of the H nodes
|
||||||
# i.e. Hz node of the left or right face
|
# i.e. Hz node of the left or right face
|
||||||
if mid == 1:
|
if mid == 1:
|
||||||
l_s = os + (l - l_l) * r + r // 2
|
l_s = os + (l - l_l) * r + r // 2
|
||||||
# i.e. the Hy node of the left or right face
|
# i.e. the Hy node of the left or right face
|
||||||
else:
|
else:
|
||||||
l_s = os + (l - l_l) * r
|
l_s = os + (l - l_l) * r
|
||||||
|
|
||||||
for m in range(m_l, m_u):
|
for m in range(m_l, m_u):
|
||||||
|
|
||||||
# Calculate the subgrid k component of the H nodes
|
# Calculate the subgrid k component of the H nodes
|
||||||
if mid == 1:
|
if mid == 1:
|
||||||
m_s = os + (m - m_l) * r
|
m_s = os + (m - m_l) * r
|
||||||
else:
|
else:
|
||||||
m_s = os + (m - m_l) * r + r // 2
|
m_s = os + (m - m_l) * r + r // 2
|
||||||
|
|
||||||
# left and right
|
# left and right
|
||||||
if face == 2:
|
if face == 2:
|
||||||
# main grid index
|
# main grid index
|
||||||
i0, j0, k0 = n_l, l, m
|
i0, j0, k0 = n_l, l, m
|
||||||
# equivalent subgrid index
|
# equivalent subgrid index
|
||||||
i1, j1, k1 = n_s_l, l_s, m_s
|
i1, j1, k1 = n_s_l, l_s, m_s
|
||||||
i2, j2, k2 = n_u, l, m
|
i2, j2, k2 = n_u, l, m
|
||||||
i3, j3, k3 = n_s_r, l_s, m_s
|
i3, j3, k3 = n_s_r, l_s, m_s
|
||||||
# front and back
|
# front and back
|
||||||
if face == 3:
|
if face == 3:
|
||||||
i0, j0, k0 = l, n_l, m
|
i0, j0, k0 = l, n_l, m
|
||||||
i1, j1, k1 = l_s, n_s_l, m_s
|
i1, j1, k1 = l_s, n_s_l, m_s
|
||||||
i2, j2, k2 = l, n_u, m
|
i2, j2, k2 = l, n_u, m
|
||||||
i3, j3, k3 = l_s, n_s_r, m_s
|
i3, j3, k3 = l_s, n_s_r, m_s
|
||||||
# top bottom
|
# top bottom
|
||||||
if face == 1:
|
if face == 1:
|
||||||
i0, j0, k0 = l, m, n_l
|
i0, j0, k0 = l, m, n_l
|
||||||
i1, j1, k1 = l_s, m_s, n_s_l
|
i1, j1, k1 = l_s, m_s, n_s_l
|
||||||
i2, j2, k2 = l, m, n_u
|
i2, j2, k2 = l, m, n_u
|
||||||
i3, j3, k3 = l_s, m_s, n_s_r
|
i3, j3, k3 = l_s, m_s, n_s_r
|
||||||
# Update the left face
|
# Update the left face
|
||||||
|
|
||||||
# Get the material at main grid index
|
# Get the material at main grid index
|
||||||
material_e_l = ID[lookup_id, i0, j0, k0]
|
material_e_l = ID[lookup_id, i0, j0, k0]
|
||||||
# Get the associated indident field from the subgrid
|
# Get the associated indident field from the subgrid
|
||||||
inc_n = inc_field[i1, j1, k1] * sign_n
|
inc_n = inc_field[i1, j1, k1] * sign_n
|
||||||
# Update the main grid E field with the corrected H field
|
# Update the main grid E field with the corrected H field
|
||||||
field[i0, j0, k0] += updatecoeffsE[material_e_l, co] * inc_n
|
field[i0, j0, k0] += updatecoeffsE[material_e_l, co] * inc_n
|
||||||
|
|
||||||
# Update the right face
|
# Update the right face
|
||||||
material_e_r = ID[lookup_id, i2, j2, k2]
|
material_e_r = ID[lookup_id, i2, j2, k2]
|
||||||
inc_f = inc_field[i3, j3, k3] * sign_f
|
inc_f = inc_field[i3, j3, k3] * sign_f
|
||||||
field[i2, j2, k2] += updatecoeffsE[material_e_r, co] * inc_f
|
field[i2, j2, k2] += updatecoeffsE[material_e_r, co] * inc_f
|
||||||
|
|
||||||
cpdef void cython_update_magnetic_os(
|
cpdef void cython_update_magnetic_os(
|
||||||
np.float64_t[:, :] updatecoeffsH,
|
np.float64_t[:, :] updatecoeffsH,
|
||||||
np.uint32_t[:, :, :, :] ID,
|
np.uint32_t[:, :, :, :] ID,
|
||||||
int face,
|
int face,
|
||||||
int l_l,
|
int l_l,
|
||||||
int l_u,
|
int l_u,
|
||||||
int m_l,
|
int m_l,
|
||||||
int m_u,
|
int m_u,
|
||||||
size_t n_l,
|
size_t n_l,
|
||||||
size_t n_u,
|
size_t n_u,
|
||||||
int nwn,
|
int nwn,
|
||||||
size_t lookup_id,
|
size_t lookup_id,
|
||||||
np.float64_t[:, :, :] field,
|
np.float64_t[:, :, :] field,
|
||||||
np.float64_t[:, :, :] inc_field,
|
np.float64_t[:, :, :] inc_field,
|
||||||
size_t co,
|
size_t co,
|
||||||
int sign_n,
|
int sign_n,
|
||||||
int sign_f,
|
int sign_f,
|
||||||
int mid,
|
int mid,
|
||||||
int r,
|
int r,
|
||||||
int s,
|
int s,
|
||||||
int nb,
|
int nb,
|
||||||
int nthreads
|
int nthreads
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
int r ratio,
|
int r ratio,
|
||||||
int s is_os_sep,
|
int s is_os_sep,
|
||||||
int nb n_boundary_cells
|
int nb n_boundary_cells
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cdef Py_ssize_t l, m, l_s, m_s, n_s_l, n_s_r, material_e_l, material_e_r, i0, j0, k0, i1, j1, k1, i2, j2, k2, i3, j3, k3
|
cdef Py_ssize_t l, m, l_s, m_s, n_s_l, n_s_r, material_e_l, material_e_r, i0, j0, k0, i1, j1, k1, i2, j2, k2, i3, j3, k3
|
||||||
cdef int os
|
cdef int os
|
||||||
cdef double inc_n, inc_f
|
cdef double inc_n, inc_f
|
||||||
|
|
||||||
# i index (normal to os) for the subgrid near face e node
|
# i index (normal to os) for the subgrid near face e node
|
||||||
n_s_l = nb - r * s
|
n_s_l = nb - r * s
|
||||||
# Normal index for the subgrid far face e node
|
# Normal index for the subgrid far face e node
|
||||||
n_s_r = nb + nwn + s * r
|
n_s_r = nb + nwn + s * r
|
||||||
|
|
||||||
# os inner index for the sub grid
|
# os inner index for the sub grid
|
||||||
os = nb - r * s
|
os = nb - r * s
|
||||||
|
|
||||||
for l in prange(l_l, l_u, nogil=True, schedule='static', num_threads=nthreads):
|
for l in prange(l_l, l_u, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
|
|
||||||
# y coord of the Ex field component
|
# y coord of the Ex field component
|
||||||
if mid == 1:
|
if mid == 1:
|
||||||
l_s = os + (l - l_l) * r + r // 2
|
l_s = os + (l - l_l) * r + r // 2
|
||||||
# y coord of the Ez field component
|
# y coord of the Ez field component
|
||||||
else:
|
else:
|
||||||
l_s = os + (l - l_l) * r
|
l_s = os + (l - l_l) * r
|
||||||
|
|
||||||
for m in range(m_l, m_u):
|
for m in range(m_l, m_u):
|
||||||
|
|
||||||
# z coordinate of the Ex node in the subgrid
|
# z coordinate of the Ex node in the subgrid
|
||||||
if mid == 1:
|
if mid == 1:
|
||||||
m_s = os + (m - m_l) * r
|
m_s = os + (m - m_l) * r
|
||||||
else:
|
else:
|
||||||
m_s = os + (m - m_l) * r + r // 2
|
m_s = os + (m - m_l) * r + r // 2
|
||||||
|
|
||||||
# associate the given indices with their i, j, k values
|
# associate the given indices with their i, j, k values
|
||||||
|
|
||||||
# left and right
|
# left and right
|
||||||
if face == 2:
|
if face == 2:
|
||||||
# main grid index
|
# main grid index
|
||||||
i0, j0, k0 = n_l, l, m
|
i0, j0, k0 = n_l, l, m
|
||||||
# equivalent subgrid index
|
# equivalent subgrid index
|
||||||
i1, j1, k1 = n_s_l, l_s, m_s
|
i1, j1, k1 = n_s_l, l_s, m_s
|
||||||
i2, j2, k2 = n_u, l, m
|
i2, j2, k2 = n_u, l, m
|
||||||
i3, j3, k3 = n_s_r, l_s, m_s
|
i3, j3, k3 = n_s_r, l_s, m_s
|
||||||
# front and back
|
# front and back
|
||||||
if face == 3:
|
if face == 3:
|
||||||
i0, j0, k0 = l, n_l, m
|
i0, j0, k0 = l, n_l, m
|
||||||
i1, j1, k1 = l_s, n_s_l, m_s
|
i1, j1, k1 = l_s, n_s_l, m_s
|
||||||
i2, j2, k2 = l, n_u, m
|
i2, j2, k2 = l, n_u, m
|
||||||
i3, j3, k3 = l_s, n_s_r, m_s
|
i3, j3, k3 = l_s, n_s_r, m_s
|
||||||
# top bottom
|
# top bottom
|
||||||
if face == 1:
|
if face == 1:
|
||||||
i0, j0, k0 = l, m, n_l
|
i0, j0, k0 = l, m, n_l
|
||||||
i1, j1, k1 = l_s, m_s, n_s_l
|
i1, j1, k1 = l_s, m_s, n_s_l
|
||||||
i2, j2, k2 = l, m, n_u
|
i2, j2, k2 = l, m, n_u
|
||||||
i3, j3, k3 = l_s, m_s, n_s_r
|
i3, j3, k3 = l_s, m_s, n_s_r
|
||||||
|
|
||||||
material_e_l = ID[lookup_id, i0, j0, k0]
|
material_e_l = ID[lookup_id, i0, j0, k0]
|
||||||
inc_n = inc_field[i1, j1, k1] * sign_n
|
inc_n = inc_field[i1, j1, k1] * sign_n
|
||||||
|
|
||||||
# make sure these are the correct grid
|
# make sure these are the correct grid
|
||||||
field[i0, j0, k0] += updatecoeffsH[material_e_l, co] * inc_n
|
field[i0, j0, k0] += updatecoeffsH[material_e_l, co] * inc_n
|
||||||
|
|
||||||
# Far face
|
# Far face
|
||||||
material_e_r = ID[lookup_id, i2, j2, k2]
|
material_e_r = ID[lookup_id, i2, j2, k2]
|
||||||
inc_f = inc_field[i3, j3, k3] * sign_f
|
inc_f = inc_field[i3, j3, k3] * sign_f
|
||||||
field[i2, j2, k2] += updatecoeffsH[material_e_r, co] * inc_f
|
field[i2, j2, k2] += updatecoeffsH[material_e_r, co] * inc_f
|
||||||
|
|
||||||
cpdef void cython_update_is(
|
cpdef void cython_update_is(
|
||||||
int nwx,
|
int nwx,
|
||||||
int nwy,
|
int nwy,
|
||||||
int nwz,
|
int nwz,
|
||||||
np.float64_t[:, :] updatecoeffsE,
|
np.float64_t[:, :] updatecoeffsE,
|
||||||
np.uint32_t[:, :, :, :] ID,
|
np.uint32_t[:, :, :, :] ID,
|
||||||
int n,
|
int n,
|
||||||
int offset,
|
int offset,
|
||||||
int nwl,
|
int nwl,
|
||||||
int nwm,
|
int nwm,
|
||||||
int nwn,
|
int nwn,
|
||||||
int face,
|
int face,
|
||||||
np.float64_t[:, :, :] field,
|
np.float64_t[:, :, :] field,
|
||||||
np.float64_t[:, :] inc_field_l,
|
np.float64_t[:, :] inc_field_l,
|
||||||
np.float64_t[:, :] inc_field_u,
|
np.float64_t[:, :] inc_field_u,
|
||||||
Py_ssize_t lookup_id,
|
Py_ssize_t lookup_id,
|
||||||
int sign_l,
|
int sign_l,
|
||||||
int sign_u,
|
int sign_u,
|
||||||
Py_ssize_t co,
|
Py_ssize_t co,
|
||||||
int nthreads
|
int nthreads
|
||||||
):
|
):
|
||||||
|
|
||||||
cdef Py_ssize_t l, m, i1, j1, k1, i2, j2, k2, field_material_l, field_material_u, inc_i, inc_j
|
cdef Py_ssize_t l, m, i1, j1, k1, i2, j2, k2, field_material_l, field_material_u, inc_i, inc_j
|
||||||
cdef double inc_l, inc_u, f_l, f_u
|
cdef double inc_l, inc_u, f_l, f_u
|
||||||
# for inner faces H nodes are 1 cell before n boundary cells
|
# for inner faces H nodes are 1 cell before n boundary cells
|
||||||
cdef int n_o = n + offset
|
cdef int n_o = n + offset
|
||||||
|
|
||||||
for l in prange(n, nwl + n, nogil=True, schedule='static', num_threads=nthreads):
|
for l in prange(n, nwl + n, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for m in range(n, nwm + n):
|
for m in range(n, nwm + n):
|
||||||
|
|
||||||
# bottom and top
|
# bottom and top
|
||||||
if face == 1:
|
if face == 1:
|
||||||
i1, j1, k1 = l, m, n_o
|
i1, j1, k1 = l, m, n_o
|
||||||
i2, j2, k2 = l, m, n + nwz
|
i2, j2, k2 = l, m, n + nwz
|
||||||
# left and right
|
# left and right
|
||||||
if face == 2:
|
if face == 2:
|
||||||
i1, j1, k1 = n_o, l, m
|
i1, j1, k1 = n_o, l, m
|
||||||
i2, j2, k2 = n + nwx, l, m
|
i2, j2, k2 = n + nwx, l, m
|
||||||
# front and back
|
# front and back
|
||||||
if face == 3:
|
if face == 3:
|
||||||
i1, j1, k1 = l, n_o, m
|
i1, j1, k1 = l, n_o, m
|
||||||
i2, j2, k2 = l, n + nwy, m
|
i2, j2, k2 = l, n + nwy, m
|
||||||
|
|
||||||
inc_i = l - n
|
inc_i = l - n
|
||||||
inc_j = m - n
|
inc_j = m - n
|
||||||
|
|
||||||
field_material_l = ID[lookup_id, i1, j1, k1]
|
field_material_l = ID[lookup_id, i1, j1, k1]
|
||||||
inc_l = inc_field_l[inc_i, inc_j]
|
inc_l = inc_field_l[inc_i, inc_j]
|
||||||
# Additional field at i, j, k
|
# Additional field at i, j, k
|
||||||
f_l = updatecoeffsE[field_material_l, co] * inc_l * sign_l
|
f_l = updatecoeffsE[field_material_l, co] * inc_l * sign_l
|
||||||
# Set the new value
|
# Set the new value
|
||||||
field[i1, j1, k1] += f_l
|
field[i1, j1, k1] += f_l
|
||||||
|
|
||||||
field_material_u = ID[lookup_id, i2, j2, k2]
|
field_material_u = ID[lookup_id, i2, j2, k2]
|
||||||
inc_u = inc_field_u[inc_i, inc_j]
|
inc_u = inc_field_u[inc_i, inc_j]
|
||||||
# Additional field at i, j, k
|
# Additional field at i, j, k
|
||||||
f_u = updatecoeffsE[field_material_u, co] * inc_u * sign_u
|
f_u = updatecoeffsE[field_material_u, co] * inc_u * sign_u
|
||||||
# Set the new value
|
# Set the new value
|
||||||
field[i2, j2, k2] += f_u
|
field[i2, j2, k2] += f_u
|
||||||
|
@@ -1,48 +1,48 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from colorama import init
|
from colorama import init
|
||||||
from colorama import Fore
|
from colorama import Fore
|
||||||
|
|
||||||
init()
|
init()
|
||||||
|
|
||||||
sys.tracebacklimit = None
|
sys.tracebacklimit = None
|
||||||
|
|
||||||
|
|
||||||
class GeneralError(ValueError):
|
class GeneralError(ValueError):
|
||||||
"""Handles general errors. Subclasses the ValueError class."""
|
"""Handles general errors. Subclasses the ValueError class."""
|
||||||
|
|
||||||
def __init__(self, message, *args):
|
def __init__(self, message, *args):
|
||||||
|
|
||||||
self.message = message
|
self.message = message
|
||||||
super(GeneralError, self).__init__(message, *args)
|
super(GeneralError, self).__init__(message, *args)
|
||||||
print(Fore.RED)
|
print(Fore.RED)
|
||||||
|
|
||||||
|
|
||||||
class CmdInputError(ValueError):
|
class CmdInputError(ValueError):
|
||||||
"""Handles errors in user specified commands. Subclasses the ValueError
|
"""Handles errors in user specified commands. Subclasses the ValueError
|
||||||
class.
|
class.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, message, *args):
|
def __init__(self, message, *args):
|
||||||
|
|
||||||
self.message = message
|
self.message = message
|
||||||
super(CmdInputError, self).__init__(message, *args)
|
super(CmdInputError, self).__init__(message, *args)
|
||||||
print(Fore.RED)
|
print(Fore.RED)
|
||||||
|
@@ -1,202 +1,202 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from string import Template
|
from string import Template
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import h5py
|
import h5py
|
||||||
|
|
||||||
from ._version import __version__
|
from ._version import __version__
|
||||||
|
|
||||||
|
|
||||||
def store_outputs(G):
|
def store_outputs(G):
|
||||||
"""Stores field component values for every receiver and transmission line.
|
"""Stores field component values for every receiver and transmission line.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
iteration (int): Current iteration number.
|
iteration (int): Current iteration number.
|
||||||
Ex, Ey, Ez, Hx, Hy, Hz (memory view): Current electric and magnetic
|
Ex, Ey, Ez, Hx, Hy, Hz (memory view): Current electric and magnetic
|
||||||
field values.
|
field values.
|
||||||
G (class): Grid class instance - holds essential parameters describing
|
G (class): Grid class instance - holds essential parameters describing
|
||||||
the model.
|
the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
iteration = G.iteration
|
iteration = G.iteration
|
||||||
#import pdb; pdb.set_trace()
|
#import pdb; pdb.set_trace()
|
||||||
|
|
||||||
Ex, Ey, Ez, Hx, Hy, Hz = G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz
|
Ex, Ey, Ez, Hx, Hy, Hz = G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz
|
||||||
for rx in G.rxs:
|
for rx in G.rxs:
|
||||||
for output in rx.outputs:
|
for output in rx.outputs:
|
||||||
# Store electric or magnetic field components
|
# Store electric or magnetic field components
|
||||||
if 'I' not in output:
|
if 'I' not in output:
|
||||||
field = locals()[output]
|
field = locals()[output]
|
||||||
rx.outputs[output][iteration] = field[rx.xcoord, rx.ycoord, rx.zcoord]
|
rx.outputs[output][iteration] = field[rx.xcoord, rx.ycoord, rx.zcoord]
|
||||||
# Store current component
|
# Store current component
|
||||||
else:
|
else:
|
||||||
func = globals()[output]
|
func = globals()[output]
|
||||||
rx.outputs[output][iteration] = func(rx.xcoord, rx.ycoord, rx.zcoord,
|
rx.outputs[output][iteration] = func(rx.xcoord, rx.ycoord, rx.zcoord,
|
||||||
Hx, Hy, Hz, G)
|
Hx, Hy, Hz, G)
|
||||||
|
|
||||||
for tl in G.transmissionlines:
|
for tl in G.transmissionlines:
|
||||||
tl.Vtotal[iteration] = tl.voltage[tl.antpos]
|
tl.Vtotal[iteration] = tl.voltage[tl.antpos]
|
||||||
tl.Itotal[iteration] = tl.current[tl.antpos]
|
tl.Itotal[iteration] = tl.current[tl.antpos]
|
||||||
|
|
||||||
|
|
||||||
kernel_template_store_outputs = Template("""
|
kernel_template_store_outputs = Template("""
|
||||||
|
|
||||||
// Macros for converting subscripts to linear index:
|
// Macros for converting subscripts to linear index:
|
||||||
#define INDEX2D_RXCOORDS(m, n) (m)*($NY_RXCOORDS)+(n)
|
#define INDEX2D_RXCOORDS(m, n) (m)*($NY_RXCOORDS)+(n)
|
||||||
#define INDEX3D_RXS(i, j, k) (i)*($NY_RXS)*($NZ_RXS)+(j)*($NZ_RXS)+(k)
|
#define INDEX3D_RXS(i, j, k) (i)*($NY_RXS)*($NZ_RXS)+(j)*($NZ_RXS)+(k)
|
||||||
#define INDEX3D_FIELDS(i, j, k) (i)*($NY_FIELDS)*($NZ_FIELDS)+(j)*($NZ_FIELDS)+(k)
|
#define INDEX3D_FIELDS(i, j, k) (i)*($NY_FIELDS)*($NZ_FIELDS)+(j)*($NZ_FIELDS)+(k)
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
// Stores field component values for every receiver //
|
// Stores field component values for every receiver //
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
|
|
||||||
__global__ void store_outputs(int NRX, int iteration, const int* __restrict__ rxcoords, $REAL *rxs, const $REAL* __restrict__ Ex, const $REAL* __restrict__ Ey, const $REAL* __restrict__ Ez, const $REAL* __restrict__ Hx, const $REAL* __restrict__ Hy, const $REAL* __restrict__ Hz) {
|
__global__ void store_outputs(int NRX, int iteration, const int* __restrict__ rxcoords, $REAL *rxs, const $REAL* __restrict__ Ex, const $REAL* __restrict__ Ey, const $REAL* __restrict__ Ez, const $REAL* __restrict__ Hx, const $REAL* __restrict__ Hy, const $REAL* __restrict__ Hz) {
|
||||||
|
|
||||||
// This function stores field component values for every receiver in the model.
|
// This function stores field component values for every receiver in the model.
|
||||||
//
|
//
|
||||||
// Args:
|
// Args:
|
||||||
// NRX: Total number of receivers in the model
|
// NRX: Total number of receivers in the model
|
||||||
// rxs: Array to store field components for receivers - rows are field components; columns are iterations; pages are receivers
|
// rxs: Array to store field components for receivers - rows are field components; columns are iterations; pages are receivers
|
||||||
// E, H: Access to field component arrays
|
// E, H: Access to field component arrays
|
||||||
|
|
||||||
// Obtain the linear index corresponding to the current thread and use for each receiver
|
// Obtain the linear index corresponding to the current thread and use for each receiver
|
||||||
int rx = blockIdx.x * blockDim.x + threadIdx.x;
|
int rx = blockIdx.x * blockDim.x + threadIdx.x;
|
||||||
|
|
||||||
int i, j, k;
|
int i, j, k;
|
||||||
|
|
||||||
if (rx < NRX) {
|
if (rx < NRX) {
|
||||||
i = rxcoords[INDEX2D_RXCOORDS(rx,0)];
|
i = rxcoords[INDEX2D_RXCOORDS(rx,0)];
|
||||||
j = rxcoords[INDEX2D_RXCOORDS(rx,1)];
|
j = rxcoords[INDEX2D_RXCOORDS(rx,1)];
|
||||||
k = rxcoords[INDEX2D_RXCOORDS(rx,2)];
|
k = rxcoords[INDEX2D_RXCOORDS(rx,2)];
|
||||||
rxs[INDEX3D_RXS(0,iteration,rx)] = Ex[INDEX3D_FIELDS(i,j,k)];
|
rxs[INDEX3D_RXS(0,iteration,rx)] = Ex[INDEX3D_FIELDS(i,j,k)];
|
||||||
rxs[INDEX3D_RXS(1,iteration,rx)] = Ey[INDEX3D_FIELDS(i,j,k)];
|
rxs[INDEX3D_RXS(1,iteration,rx)] = Ey[INDEX3D_FIELDS(i,j,k)];
|
||||||
rxs[INDEX3D_RXS(2,iteration,rx)] = Ez[INDEX3D_FIELDS(i,j,k)];
|
rxs[INDEX3D_RXS(2,iteration,rx)] = Ez[INDEX3D_FIELDS(i,j,k)];
|
||||||
rxs[INDEX3D_RXS(3,iteration,rx)] = Hx[INDEX3D_FIELDS(i,j,k)];
|
rxs[INDEX3D_RXS(3,iteration,rx)] = Hx[INDEX3D_FIELDS(i,j,k)];
|
||||||
rxs[INDEX3D_RXS(4,iteration,rx)] = Hy[INDEX3D_FIELDS(i,j,k)];
|
rxs[INDEX3D_RXS(4,iteration,rx)] = Hy[INDEX3D_FIELDS(i,j,k)];
|
||||||
rxs[INDEX3D_RXS(5,iteration,rx)] = Hz[INDEX3D_FIELDS(i,j,k)];
|
rxs[INDEX3D_RXS(5,iteration,rx)] = Hz[INDEX3D_FIELDS(i,j,k)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
def write_hdf5_outputfile(outputfile, G):
|
def write_hdf5_outputfile(outputfile, G):
|
||||||
write_hdf5_main_grid_outputfile(outputfile, G)
|
write_hdf5_main_grid_outputfile(outputfile, G)
|
||||||
write_hdf5_sub_grid_outputfile(outputfile, G)
|
write_hdf5_sub_grid_outputfile(outputfile, G)
|
||||||
|
|
||||||
|
|
||||||
def write_hdf5_main_grid_outputfile(outputfile, G):
|
def write_hdf5_main_grid_outputfile(outputfile, G):
|
||||||
"""Write an output file in HDF5 format.
|
"""Write an output file in HDF5 format.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
outputfile (str): Name of the output file.
|
outputfile (str): Name of the output file.
|
||||||
Ex, Ey, Ez, Hx, Hy, Hz (memory view): Current electric and magnetic field values.
|
Ex, Ey, Ez, Hx, Hy, Hz (memory view): Current electric and magnetic field values.
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
write_data(outputfile, G)
|
write_data(outputfile, G)
|
||||||
|
|
||||||
|
|
||||||
def write_hdf5_sub_grid_outputfile(outputfile, G):
|
def write_hdf5_sub_grid_outputfile(outputfile, G):
|
||||||
"""Write an output file in HDF5 format.
|
"""Write an output file in HDF5 format.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
outputfile (str): Name of the output file.
|
outputfile (str): Name of the output file.
|
||||||
Ex, Ey, Ez, Hx, Hy, Hz (memory view): Current electric and magnetic field values.
|
Ex, Ey, Ez, Hx, Hy, Hz (memory view): Current electric and magnetic field values.
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
stem = outputfile.stem
|
stem = outputfile.stem
|
||||||
suffix = outputfile.suffix
|
suffix = outputfile.suffix
|
||||||
parent = outputfile.parent
|
parent = outputfile.parent
|
||||||
|
|
||||||
for sg in G.subgrids:
|
for sg in G.subgrids:
|
||||||
|
|
||||||
# create an outputfile for each subgrid
|
# create an outputfile for each subgrid
|
||||||
fp = stem + '_' + sg.name + suffix
|
fp = stem + '_' + sg.name + suffix
|
||||||
fp = parent / Path(fp)
|
fp = parent / Path(fp)
|
||||||
|
|
||||||
f = write_data(fp, sg)
|
f = write_data(fp, sg)
|
||||||
|
|
||||||
# write some additional meta data about the subgrid
|
# write some additional meta data about the subgrid
|
||||||
f.attrs['is_os_sep'] = sg.is_os_sep
|
f.attrs['is_os_sep'] = sg.is_os_sep
|
||||||
f.attrs['pml_separation'] = sg.pml_separation
|
f.attrs['pml_separation'] = sg.pml_separation
|
||||||
f.attrs['subgrid_pml_thickness'] = sg.pmlthickness['x0']
|
f.attrs['subgrid_pml_thickness'] = sg.pmlthickness['x0']
|
||||||
f.attrs['filter'] = sg.filter
|
f.attrs['filter'] = sg.filter
|
||||||
f.attrs['ratio'] = sg.ratio
|
f.attrs['ratio'] = sg.ratio
|
||||||
f.attrs['interpolation'] = sg.interpolation
|
f.attrs['interpolation'] = sg.interpolation
|
||||||
|
|
||||||
|
|
||||||
def write_data(outputfile, G):
|
def write_data(outputfile, G):
|
||||||
"""Write an output file in HDF5 format.
|
"""Write an output file in HDF5 format.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
outputfile (str): Name of the output file.
|
outputfile (str): Name of the output file.
|
||||||
Ex, Ey, Ez, Hx, Hy, Hz (memory view): Current electric and magnetic
|
Ex, Ey, Ez, Hx, Hy, Hz (memory view): Current electric and magnetic
|
||||||
field values.
|
field values.
|
||||||
G (class): Grid class instance - holds essential parameters describing
|
G (class): Grid class instance - holds essential parameters describing
|
||||||
the model.
|
the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
f = h5py.File(outputfile, 'w')
|
f = h5py.File(outputfile, 'w')
|
||||||
f.attrs['gprMax'] = __version__
|
f.attrs['gprMax'] = __version__
|
||||||
f.attrs['Title'] = G.title
|
f.attrs['Title'] = G.title
|
||||||
f.attrs['Iterations'] = G.iterations
|
f.attrs['Iterations'] = G.iterations
|
||||||
f.attrs['nx_ny_nz'] = (G.nx, G.ny, G.nz)
|
f.attrs['nx_ny_nz'] = (G.nx, G.ny, G.nz)
|
||||||
f.attrs['dx_dy_dz'] = (G.dx, G.dy, G.dz)
|
f.attrs['dx_dy_dz'] = (G.dx, G.dy, G.dz)
|
||||||
f.attrs['dt'] = G.dt
|
f.attrs['dt'] = G.dt
|
||||||
nsrc = len(G.voltagesources + G.hertziandipoles + G.magneticdipoles + G.transmissionlines)
|
nsrc = len(G.voltagesources + G.hertziandipoles + G.magneticdipoles + G.transmissionlines)
|
||||||
f.attrs['nsrc'] = nsrc
|
f.attrs['nsrc'] = nsrc
|
||||||
f.attrs['nrx'] = len(G.rxs)
|
f.attrs['nrx'] = len(G.rxs)
|
||||||
f.attrs['srcsteps'] = G.srcsteps
|
f.attrs['srcsteps'] = G.srcsteps
|
||||||
f.attrs['rxsteps'] = G.rxsteps
|
f.attrs['rxsteps'] = G.rxsteps
|
||||||
|
|
||||||
# Create group for sources (except transmission lines); add type and positional data attributes
|
# Create group for sources (except transmission lines); add type and positional data attributes
|
||||||
srclist = G.voltagesources + G.hertziandipoles + G.magneticdipoles
|
srclist = G.voltagesources + G.hertziandipoles + G.magneticdipoles
|
||||||
for srcindex, src in enumerate(srclist):
|
for srcindex, src in enumerate(srclist):
|
||||||
grp = f.create_group('/srcs/src' + str(srcindex + 1))
|
grp = f.create_group('/srcs/src' + str(srcindex + 1))
|
||||||
grp.attrs['Type'] = type(src).__name__
|
grp.attrs['Type'] = type(src).__name__
|
||||||
grp.attrs['Position'] = (src.xcoord * G.dx, src.ycoord * G.dy, src.zcoord * G.dz)
|
grp.attrs['Position'] = (src.xcoord * G.dx, src.ycoord * G.dy, src.zcoord * G.dz)
|
||||||
|
|
||||||
# Create group for transmission lines; add positional data, line resistance and
|
# Create group for transmission lines; add positional data, line resistance and
|
||||||
# line discretisation attributes; write arrays for line voltages and currents
|
# line discretisation attributes; write arrays for line voltages and currents
|
||||||
for tlindex, tl in enumerate(G.transmissionlines):
|
for tlindex, tl in enumerate(G.transmissionlines):
|
||||||
grp = f.create_group('/tls/tl' + str(tlindex + 1))
|
grp = f.create_group('/tls/tl' + str(tlindex + 1))
|
||||||
grp.attrs['Position'] = (tl.xcoord * G.dx, tl.ycoord * G.dy, tl.zcoord * G.dz)
|
grp.attrs['Position'] = (tl.xcoord * G.dx, tl.ycoord * G.dy, tl.zcoord * G.dz)
|
||||||
grp.attrs['Resistance'] = tl.resistance
|
grp.attrs['Resistance'] = tl.resistance
|
||||||
grp.attrs['dl'] = tl.dl
|
grp.attrs['dl'] = tl.dl
|
||||||
# Save incident voltage and current
|
# Save incident voltage and current
|
||||||
grp['Vinc'] = tl.Vinc
|
grp['Vinc'] = tl.Vinc
|
||||||
grp['Iinc'] = tl.Iinc
|
grp['Iinc'] = tl.Iinc
|
||||||
# Save total voltage and current
|
# Save total voltage and current
|
||||||
f['/tls/tl' + str(tlindex + 1) + '/Vtotal'] = tl.Vtotal
|
f['/tls/tl' + str(tlindex + 1) + '/Vtotal'] = tl.Vtotal
|
||||||
f['/tls/tl' + str(tlindex + 1) + '/Itotal'] = tl.Itotal
|
f['/tls/tl' + str(tlindex + 1) + '/Itotal'] = tl.Itotal
|
||||||
|
|
||||||
# Create group, add positional data and write field component arrays for receivers
|
# Create group, add positional data and write field component arrays for receivers
|
||||||
for rxindex, rx in enumerate(G.rxs):
|
for rxindex, rx in enumerate(G.rxs):
|
||||||
grp = f.create_group('/rxs/rx' + str(rxindex + 1))
|
grp = f.create_group('/rxs/rx' + str(rxindex + 1))
|
||||||
if rx.ID:
|
if rx.ID:
|
||||||
grp.attrs['Name'] = rx.ID
|
grp.attrs['Name'] = rx.ID
|
||||||
grp.attrs['Position'] = (rx.xcoord * G.dx, rx.ycoord * G.dy, rx.zcoord * G.dz)
|
grp.attrs['Position'] = (rx.xcoord * G.dx, rx.ycoord * G.dy, rx.zcoord * G.dz)
|
||||||
|
|
||||||
for output in rx.outputs:
|
for output in rx.outputs:
|
||||||
f['/rxs/rx' + str(rxindex + 1) + '/' + output] = rx.outputs[output]
|
f['/rxs/rx' + str(rxindex + 1) + '/' + output] = rx.outputs[output]
|
||||||
|
|
||||||
return f
|
return f
|
||||||
|
188
gprMax/gprMax.py
188
gprMax/gprMax.py
@@ -1,94 +1,94 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from .config import create_simulation_config
|
from .config import create_simulation_config
|
||||||
from .contexts import create_context
|
from .contexts import create_context
|
||||||
from .solvers import create_solver
|
from .solvers import create_solver
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
def api(
|
def api(
|
||||||
scenes=None,
|
scenes=None,
|
||||||
id=None,
|
id=None,
|
||||||
inputfile=None,
|
inputfile=None,
|
||||||
outputfile=None,
|
outputfile=None,
|
||||||
n=1,
|
n=1,
|
||||||
task=None,
|
task=None,
|
||||||
restart=None,
|
restart=None,
|
||||||
mpi=False,
|
mpi=False,
|
||||||
mpi_no_spawn=False,
|
mpi_no_spawn=False,
|
||||||
mpicomm=None,
|
mpicomm=None,
|
||||||
gpu=None,
|
gpu=None,
|
||||||
subgrid=None,
|
subgrid=None,
|
||||||
benchmark=False,
|
benchmark=False,
|
||||||
geometry_only=False,
|
geometry_only=False,
|
||||||
geometry_fixed=False,
|
geometry_fixed=False,
|
||||||
write_processed=False,
|
write_processed=False,
|
||||||
):
|
):
|
||||||
"""If installed as a module this is the entry point."""
|
"""If installed as a module this is the entry point."""
|
||||||
|
|
||||||
class ImportArguments:
|
class ImportArguments:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
args = ImportArguments()
|
args = ImportArguments()
|
||||||
|
|
||||||
args.scenes = scenes
|
args.scenes = scenes
|
||||||
args.inputfile = inputfile
|
args.inputfile = inputfile
|
||||||
args.outputfile = outputfile
|
args.outputfile = outputfile
|
||||||
args.n = n
|
args.n = n
|
||||||
args.task = task
|
args.task = task
|
||||||
args.restart = restart
|
args.restart = restart
|
||||||
args.mpi = mpi
|
args.mpi = mpi
|
||||||
args.mpi_no_spawn = mpi_no_spawn
|
args.mpi_no_spawn = mpi_no_spawn
|
||||||
args.mpicomm = mpicomm
|
args.mpicomm = mpicomm
|
||||||
args.gpu = gpu
|
args.gpu = gpu
|
||||||
args.subgrid=subgrid
|
args.subgrid=subgrid
|
||||||
args.benchmark = benchmark
|
args.benchmark = benchmark
|
||||||
args.geometry_only = geometry_only
|
args.geometry_only = geometry_only
|
||||||
args.geometry_fixed = geometry_fixed
|
args.geometry_fixed = geometry_fixed
|
||||||
args.write_processed = write_processed
|
args.write_processed = write_processed
|
||||||
|
|
||||||
run_main(args)
|
run_main(args)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""This is the main function for gprMax."""
|
"""This is the main function for gprMax."""
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse command line arguments
|
||||||
parser = argparse.ArgumentParser(prog='gprMax', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
parser = argparse.ArgumentParser(prog='gprMax', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
parser.add_argument('inputfile', help='path to, and name of inputfile or file object')
|
parser.add_argument('inputfile', help='path to, and name of inputfile or file object')
|
||||||
parser.add_argument('-n', default=1, type=int, help='number of times to run the input file, e.g. to create a B-scan')
|
parser.add_argument('-n', default=1, type=int, help='number of times to run the input file, e.g. to create a B-scan')
|
||||||
parser.add_argument('-task', type=int, help='task identifier (model number) for job array on Open Grid Scheduler/Grid Engine (http://gridscheduler.sourceforge.net/index.html)')
|
parser.add_argument('-task', type=int, help='task identifier (model number) for job array on Open Grid Scheduler/Grid Engine (http://gridscheduler.sourceforge.net/index.html)')
|
||||||
parser.add_argument('-restart', type=int, help='model number to restart from, e.g. when creating B-scan')
|
parser.add_argument('-restart', type=int, help='model number to restart from, e.g. when creating B-scan')
|
||||||
parser.add_argument('-mpi', type=int, help='number of MPI tasks, i.e. master + workers')
|
parser.add_argument('-mpi', type=int, help='number of MPI tasks, i.e. master + workers')
|
||||||
parser.add_argument('--mpi-no-spawn', action='store_true', default=False, help='flag to use MPI without spawn mechanism')
|
parser.add_argument('--mpi-no-spawn', action='store_true', default=False, help='flag to use MPI without spawn mechanism')
|
||||||
parser.add_argument('--mpi-worker', action='store_true', default=False, help=argparse.SUPPRESS)
|
parser.add_argument('--mpi-worker', action='store_true', default=False, help=argparse.SUPPRESS)
|
||||||
parser.add_argument('-gpu', type=int, action='append', nargs='*', help='flag to use Nvidia GPU or option to give list of device ID(s)')
|
parser.add_argument('-gpu', type=int, action='append', nargs='*', help='flag to use Nvidia GPU or option to give list of device ID(s)')
|
||||||
parser.add_argument('-benchmark', action='store_true', default=False, help='flag to switch on benchmarking mode')
|
parser.add_argument('-benchmark', action='store_true', default=False, help='flag to switch on benchmarking mode')
|
||||||
parser.add_argument('--geometry-only', action='store_true', default=False, help='flag to only build model and produce geometry file(s)')
|
parser.add_argument('--geometry-only', action='store_true', default=False, help='flag to only build model and produce geometry file(s)')
|
||||||
parser.add_argument('--geometry-fixed', action='store_true', default=False, help='flag to not reprocess model geometry, e.g. for B-scans where the geometry is fixed')
|
parser.add_argument('--geometry-fixed', action='store_true', default=False, help='flag to not reprocess model geometry, e.g. for B-scans where the geometry is fixed')
|
||||||
parser.add_argument('--write-processed', action='store_true', default=False, help='flag to write an input file after any Python code and include commands in the original input file have been processed')
|
parser.add_argument('--write-processed', action='store_true', default=False, help='flag to write an input file after any Python code and include commands in the original input file have been processed')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
run_main(args)
|
run_main(args)
|
||||||
|
|
||||||
def run_main(args):
|
def run_main(args):
|
||||||
|
|
||||||
sim_config = create_simulation_config(args)
|
sim_config = create_simulation_config(args)
|
||||||
context = create_context(sim_config)
|
context = create_context(sim_config)
|
||||||
context.run()
|
context.run()
|
||||||
|
1002
gprMax/grid.py
1002
gprMax/grid.py
文件差异内容过多而无法显示
加载差异
@@ -1,318 +1,318 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from .utilities import get_terminal_width
|
from .utilities import get_terminal_width
|
||||||
|
|
||||||
from .cmds_geometry.geometry_objects_read import GeometryObjectsRead
|
from .cmds_geometry.geometry_objects_read import GeometryObjectsRead
|
||||||
from .cmds_geometry.edge import Edge
|
from .cmds_geometry.edge import Edge
|
||||||
from .cmds_geometry.plate import Plate
|
from .cmds_geometry.plate import Plate
|
||||||
from .cmds_geometry.triangle import Triangle
|
from .cmds_geometry.triangle import Triangle
|
||||||
from .cmds_geometry.box import Box
|
from .cmds_geometry.box import Box
|
||||||
from .cmds_geometry.cylinder import Cylinder
|
from .cmds_geometry.cylinder import Cylinder
|
||||||
from .cmds_geometry.cylindrical_sector import CylindricalSector
|
from .cmds_geometry.cylindrical_sector import CylindricalSector
|
||||||
from .cmds_geometry.fractal_box import FractalBox
|
from .cmds_geometry.fractal_box import FractalBox
|
||||||
from .cmds_geometry.sphere import Sphere
|
from .cmds_geometry.sphere import Sphere
|
||||||
from .cmds_geometry.add_surface_roughness import AddSurfaceRoughness
|
from .cmds_geometry.add_surface_roughness import AddSurfaceRoughness
|
||||||
from .cmds_geometry.add_surface_water import AddSurfaceWater
|
from .cmds_geometry.add_surface_water import AddSurfaceWater
|
||||||
from .cmds_geometry.add_grass import AddGrass
|
from .cmds_geometry.add_grass import AddGrass
|
||||||
|
|
||||||
from .utilities import round_value
|
from .utilities import round_value
|
||||||
|
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
def process_geometrycmds(geometry):
|
def process_geometrycmds(geometry):
|
||||||
"""
|
"""
|
||||||
This function checks the validity of command parameters, creates instances
|
This function checks the validity of command parameters, creates instances
|
||||||
of classes of parameters, and calls functions to directly set arrays
|
of classes of parameters, and calls functions to directly set arrays
|
||||||
solid, rigid and ID.
|
solid, rigid and ID.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
geometry (list): Geometry commands in the model
|
geometry (list): Geometry commands in the model
|
||||||
"""
|
"""
|
||||||
|
|
||||||
scene_objects = []
|
scene_objects = []
|
||||||
|
|
||||||
# Disable progress bar if on Windows as it does not update properly
|
# Disable progress bar if on Windows as it does not update properly
|
||||||
# when messages are printed
|
# when messages are printed
|
||||||
#if sys.platform == 'win32':
|
#if sys.platform == 'win32':
|
||||||
# tqdmdisable = True
|
# tqdmdisable = True
|
||||||
#else:
|
#else:
|
||||||
# tqdmdisable = G.tqdmdisable
|
# tqdmdisable = G.tqdmdisable
|
||||||
|
|
||||||
tqdmdisable = False
|
tqdmdisable = False
|
||||||
|
|
||||||
for object in tqdm(geometry, desc='Processing geometry related cmds', unit='cmds', ncols=get_terminal_width() - 1, file=sys.stdout, disable=tqdmdisable):
|
for object in tqdm(geometry, desc='Processing geometry related cmds', unit='cmds', ncols=get_terminal_width() - 1, file=sys.stdout, disable=tqdmdisable):
|
||||||
tmp = object.split()
|
tmp = object.split()
|
||||||
|
|
||||||
if tmp[0] == '#geometry_objects_read:':
|
if tmp[0] == '#geometry_objects_read:':
|
||||||
if len(tmp) != 6:
|
if len(tmp) != 6:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires exactly five parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires exactly five parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||||
|
|
||||||
gor = GeometryObjectsRead(p1=p1, geofile=tmp[4], matfile=tmp[5])
|
gor = GeometryObjectsRead(p1=p1, geofile=tmp[4], matfile=tmp[5])
|
||||||
scene_objects.append(gor)
|
scene_objects.append(gor)
|
||||||
|
|
||||||
elif tmp[0] == '#edge:':
|
elif tmp[0] == '#edge:':
|
||||||
if len(tmp) != 8:
|
if len(tmp) != 8:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires exactly seven parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires exactly seven parameters')
|
||||||
|
|
||||||
edge = Edge(p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])),
|
edge = Edge(p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])),
|
||||||
p2=(float(tmp[4]), float(tmp[5]), float(tmp[6])),
|
p2=(float(tmp[4]), float(tmp[5]), float(tmp[6])),
|
||||||
material_id=tmp[7])
|
material_id=tmp[7])
|
||||||
|
|
||||||
scene_objects.append(edge)
|
scene_objects.append(edge)
|
||||||
|
|
||||||
elif tmp[0] == '#plate:':
|
elif tmp[0] == '#plate:':
|
||||||
if len(tmp) < 8:
|
if len(tmp) < 8:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least seven parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least seven parameters')
|
||||||
|
|
||||||
# Isotropic case
|
# Isotropic case
|
||||||
if len(tmp) == 8:
|
if len(tmp) == 8:
|
||||||
plate = Plate(p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])),
|
plate = Plate(p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])),
|
||||||
p2=(float(tmp[4]), float(tmp[5]), float(tmp[6])),
|
p2=(float(tmp[4]), float(tmp[5]), float(tmp[6])),
|
||||||
material_id=tmp[7])
|
material_id=tmp[7])
|
||||||
|
|
||||||
# Anisotropic case
|
# Anisotropic case
|
||||||
elif len(tmp) == 9:
|
elif len(tmp) == 9:
|
||||||
plate = Plate(p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])),
|
plate = Plate(p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])),
|
||||||
p2=(float(tmp[4]), float(tmp[5]), float(tmp[6])),
|
p2=(float(tmp[4]), float(tmp[5]), float(tmp[6])),
|
||||||
material_ids=tmp[7:])
|
material_ids=tmp[7:])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
||||||
|
|
||||||
scene_objects.append(plate)
|
scene_objects.append(plate)
|
||||||
|
|
||||||
elif tmp[0] == '#triangle:':
|
elif tmp[0] == '#triangle:':
|
||||||
if len(tmp) < 12:
|
if len(tmp) < 12:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least eleven parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least eleven parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||||
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
||||||
p3 = (float(tmp[7]), float(tmp[8]), float(tmp[9]))
|
p3 = (float(tmp[7]), float(tmp[8]), float(tmp[9]))
|
||||||
thickness = float(tmp[10])
|
thickness = float(tmp[10])
|
||||||
|
|
||||||
# Isotropic case with no user specified averaging
|
# Isotropic case with no user specified averaging
|
||||||
if len(tmp) == 12:
|
if len(tmp) == 12:
|
||||||
triangle = Triangle(p1=p1, p2=p2, p3=p3, thickness=thickness, material_id=tmp[11])
|
triangle = Triangle(p1=p1, p2=p2, p3=p3, thickness=thickness, material_id=tmp[11])
|
||||||
|
|
||||||
# Isotropic case with user specified averaging
|
# Isotropic case with user specified averaging
|
||||||
elif len(tmp) == 13:
|
elif len(tmp) == 13:
|
||||||
triangle = Triangle(p1=p1, p2=p2, p3=p3, thickness=thickness, material_id=tmp[11], averaging=tmp[12].lower())
|
triangle = Triangle(p1=p1, p2=p2, p3=p3, thickness=thickness, material_id=tmp[11], averaging=tmp[12].lower())
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(tmp) == 14:
|
elif len(tmp) == 14:
|
||||||
triangle = Triangle(p1=p1, p2=p2, p3=p3, thickness=thickness, material_ids=tmp[11:])
|
triangle = Triangle(p1=p1, p2=p2, p3=p3, thickness=thickness, material_ids=tmp[11:])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
||||||
|
|
||||||
scene_objects.append(triangle)
|
scene_objects.append(triangle)
|
||||||
|
|
||||||
elif tmp[0] == '#box:':
|
elif tmp[0] == '#box:':
|
||||||
if len(tmp) < 8:
|
if len(tmp) < 8:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least seven parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least seven parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||||
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
||||||
|
|
||||||
# Isotropic case with no user specified averaging
|
# Isotropic case with no user specified averaging
|
||||||
if len(tmp) == 8:
|
if len(tmp) == 8:
|
||||||
box = Box(p1=p1, p2=p2, material_id=tmp[7])
|
box = Box(p1=p1, p2=p2, material_id=tmp[7])
|
||||||
|
|
||||||
# Isotropic case with user specified averaging
|
# Isotropic case with user specified averaging
|
||||||
elif len(tmp) == 9:
|
elif len(tmp) == 9:
|
||||||
box = Box(p1=p1, p2=p2, material_id=tmp[7], averaging=tmp[8])
|
box = Box(p1=p1, p2=p2, material_id=tmp[7], averaging=tmp[8])
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(tmp) == 10:
|
elif len(tmp) == 10:
|
||||||
box = Box(p1=p1, p2=p2, material_ids=tmp[7:])
|
box = Box(p1=p1, p2=p2, material_ids=tmp[7:])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
||||||
|
|
||||||
scene_objects.append(box)
|
scene_objects.append(box)
|
||||||
|
|
||||||
elif tmp[0] == '#cylinder:':
|
elif tmp[0] == '#cylinder:':
|
||||||
if len(tmp) < 9:
|
if len(tmp) < 9:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least eight parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least eight parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||||
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
||||||
r = float(tmp[7])
|
r = float(tmp[7])
|
||||||
|
|
||||||
# Isotropic case with no user specified averaging
|
# Isotropic case with no user specified averaging
|
||||||
if len(tmp) == 9:
|
if len(tmp) == 9:
|
||||||
cylinder = Cylinder(p1=p1, p2=p2, r=r, material_id=tmp[8])
|
cylinder = Cylinder(p1=p1, p2=p2, r=r, material_id=tmp[8])
|
||||||
|
|
||||||
# Isotropic case with user specified averaging
|
# Isotropic case with user specified averaging
|
||||||
elif len(tmp) == 10:
|
elif len(tmp) == 10:
|
||||||
cylinder = Cylinder(p1=p1, p2=p2, r=r, material_id=tmp[8], averaging=tmp[9])
|
cylinder = Cylinder(p1=p1, p2=p2, r=r, material_id=tmp[8], averaging=tmp[9])
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(tmp) == 11:
|
elif len(tmp) == 11:
|
||||||
cylinder = Cylinder(p1=p1, p2=p2, r=r, material_ids=tmp[8:])
|
cylinder = Cylinder(p1=p1, p2=p2, r=r, material_ids=tmp[8:])
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
||||||
|
|
||||||
scene_objects.append(cylinder)
|
scene_objects.append(cylinder)
|
||||||
|
|
||||||
elif tmp[0] == '#cylindrical_sector:':
|
elif tmp[0] == '#cylindrical_sector:':
|
||||||
if len(tmp) < 10:
|
if len(tmp) < 10:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least nine parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least nine parameters')
|
||||||
|
|
||||||
normal = tmp[1].lower()
|
normal = tmp[1].lower()
|
||||||
ctr1 = float(tmp[2])
|
ctr1 = float(tmp[2])
|
||||||
ctr2 = float(tmp[3])
|
ctr2 = float(tmp[3])
|
||||||
extent1 = float(tmp[4])
|
extent1 = float(tmp[4])
|
||||||
extent2 = float(tmp[5])
|
extent2 = float(tmp[5])
|
||||||
r = float(tmp[6])
|
r = float(tmp[6])
|
||||||
start = float(tmp[7])
|
start = float(tmp[7])
|
||||||
end = float(tmp[8])
|
end = float(tmp[8])
|
||||||
|
|
||||||
# Isotropic case with no user specified averaging
|
# Isotropic case with no user specified averaging
|
||||||
if len(tmp) == 10:
|
if len(tmp) == 10:
|
||||||
CylindricalSector(normal=normal, ctl1=ctl1, ctl2=ctl2, extent1=extent1, extent2=extent2, r=r, start=start, end=end, msterial_id=tmp[9])
|
CylindricalSector(normal=normal, ctl1=ctl1, ctl2=ctl2, extent1=extent1, extent2=extent2, r=r, start=start, end=end, msterial_id=tmp[9])
|
||||||
|
|
||||||
# Isotropic case with user specified averaging
|
# Isotropic case with user specified averaging
|
||||||
elif len(tmp) == 11:
|
elif len(tmp) == 11:
|
||||||
CylindricalSector(normal=normal, ctl1=ctl1, ctl2=ctl2, extent1=extent1, extent2=extent2, r=r, start=start, end=end, averaging=tmp[10], material_id=tmp[9])
|
CylindricalSector(normal=normal, ctl1=ctl1, ctl2=ctl2, extent1=extent1, extent2=extent2, r=r, start=start, end=end, averaging=tmp[10], material_id=tmp[9])
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(tmp) == 12:
|
elif len(tmp) == 12:
|
||||||
CylindricalSector(normal=normal, ctl1=ctl1, ctl2=ctl2, extent1=extent1, extent2=extent2, r=r, start=start, end=end, material_ids=tmp[9:])
|
CylindricalSector(normal=normal, ctl1=ctl1, ctl2=ctl2, extent1=extent1, extent2=extent2, r=r, start=start, end=end, material_ids=tmp[9:])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
||||||
|
|
||||||
scene_objects.append(cylindrical_sector)
|
scene_objects.append(cylindrical_sector)
|
||||||
|
|
||||||
elif tmp[0] == '#sphere:':
|
elif tmp[0] == '#sphere:':
|
||||||
if len(tmp) < 6:
|
if len(tmp) < 6:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||||
r = float(tmp[4])
|
r = float(tmp[4])
|
||||||
|
|
||||||
# Isotropic case with no user specified averaging
|
# Isotropic case with no user specified averaging
|
||||||
if len(tmp) == 6:
|
if len(tmp) == 6:
|
||||||
sphere = Sphere(p1=p1, r=r, material_id=tmp[5])
|
sphere = Sphere(p1=p1, r=r, material_id=tmp[5])
|
||||||
|
|
||||||
# Isotropic case with user specified averaging
|
# Isotropic case with user specified averaging
|
||||||
elif len(tmp) == 7:
|
elif len(tmp) == 7:
|
||||||
sphere = Sphere(p1=p1, r=r, material_id=tmp[5], averaging=tmp[6])
|
sphere = Sphere(p1=p1, r=r, material_id=tmp[5], averaging=tmp[6])
|
||||||
|
|
||||||
# Uniaxial anisotropic case
|
# Uniaxial anisotropic case
|
||||||
elif len(tmp) == 8:
|
elif len(tmp) == 8:
|
||||||
sphere = Sphere(p1=p1, r=r, material_id=tmp[5:])
|
sphere = Sphere(p1=p1, r=r, material_id=tmp[5:])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
||||||
|
|
||||||
scene_objects.append(sphere)
|
scene_objects.append(sphere)
|
||||||
|
|
||||||
elif tmp[0] == '#fractal_box:':
|
elif tmp[0] == '#fractal_box:':
|
||||||
# Default is no dielectric smoothing for a fractal box
|
# Default is no dielectric smoothing for a fractal box
|
||||||
|
|
||||||
if len(tmp) < 14:
|
if len(tmp) < 14:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least thirteen parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least thirteen parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||||
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
||||||
frac_dim = float(tmp[7])
|
frac_dim = float(tmp[7])
|
||||||
weighting = np.array([float(tmp[8]), float(tmp[9]), float(tmp[10])])
|
weighting = np.array([float(tmp[8]), float(tmp[9]), float(tmp[10])])
|
||||||
n_materials = round_value(tmp[11])
|
n_materials = round_value(tmp[11])
|
||||||
mixing_model_id = tmp[12]
|
mixing_model_id = tmp[12]
|
||||||
ID = tmp[13]
|
ID = tmp[13]
|
||||||
# without seed
|
# without seed
|
||||||
if len(tmp) == 14:
|
if len(tmp) == 14:
|
||||||
fb = FractalBox(p1=p1, p2=p2, frac_dim=frac_dim, weighting=weighting, mixing_model_id=mixing_model_id, id=ID, n_materials=n_materials)
|
fb = FractalBox(p1=p1, p2=p2, frac_dim=frac_dim, weighting=weighting, mixing_model_id=mixing_model_id, id=ID, n_materials=n_materials)
|
||||||
# with seed
|
# with seed
|
||||||
elif len(tmp) == 15:
|
elif len(tmp) == 15:
|
||||||
fb = FractalBox(p1=p1, p2=p2, frac_dim=frac_dim, weighting=weighting, mixing_model_id=mixing_model_id, id=ID, n_materials=n_materials, seed=tmp[14])
|
fb = FractalBox(p1=p1, p2=p2, frac_dim=frac_dim, weighting=weighting, mixing_model_id=mixing_model_id, id=ID, n_materials=n_materials, seed=tmp[14])
|
||||||
# user specified averaging
|
# user specified averaging
|
||||||
elif len(tmp) == 16:
|
elif len(tmp) == 16:
|
||||||
fb = FractalBox(p1=p1, p2=p2, frac_dim=frac_dim, weighting=weighting, mixing_model_id=mixing_model_id, id=ID, n_materials=n_materials, seed=tmp[14], averaging=tmp[15].lower())
|
fb = FractalBox(p1=p1, p2=p2, frac_dim=frac_dim, weighting=weighting, mixing_model_id=mixing_model_id, id=ID, n_materials=n_materials, seed=tmp[14], averaging=tmp[15].lower())
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
||||||
|
|
||||||
scene_objects.append(fb)
|
scene_objects.append(fb)
|
||||||
|
|
||||||
# Search and process any modifiers for the fractal box
|
# Search and process any modifiers for the fractal box
|
||||||
for object in geometry:
|
for object in geometry:
|
||||||
tmp = object.split()
|
tmp = object.split()
|
||||||
|
|
||||||
if tmp[0] == '#add_surface_roughness:':
|
if tmp[0] == '#add_surface_roughness:':
|
||||||
if len(tmp) < 13:
|
if len(tmp) < 13:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least twelve parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least twelve parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||||
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
||||||
frac_dim = float(tmp[7])
|
frac_dim = float(tmp[7])
|
||||||
weighting = np.array([float(tmp[8]), float(tmp[9])])
|
weighting = np.array([float(tmp[8]), float(tmp[9])])
|
||||||
limits = [float(tmp[10]), float(tmp[11])]
|
limits = [float(tmp[10]), float(tmp[11])]
|
||||||
fractal_box_id = tmp[12]
|
fractal_box_id = tmp[12]
|
||||||
|
|
||||||
# No seed
|
# No seed
|
||||||
if len(tmp) == 13:
|
if len(tmp) == 13:
|
||||||
asr = AddSurfaceRoughness(p1=p1, p2=p2, frac_dim=frac_dim, weighting=weighting, limits=limits, fractal_box_id=fractal_box_id)
|
asr = AddSurfaceRoughness(p1=p1, p2=p2, frac_dim=frac_dim, weighting=weighting, limits=limits, fractal_box_id=fractal_box_id)
|
||||||
elif len(tmp) == 14:
|
elif len(tmp) == 14:
|
||||||
asr = AddSurfaceRoughness(p1=p1, p2=p2, frac_dim=frac_dim, weighting=weighting, limits=limits, fractal_box_id=fractal_box_id, seed=int(tmp[13]))
|
asr = AddSurfaceRoughness(p1=p1, p2=p2, frac_dim=frac_dim, weighting=weighting, limits=limits, fractal_box_id=fractal_box_id, seed=int(tmp[13]))
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
||||||
|
|
||||||
scene_objects.append(asr)
|
scene_objects.append(asr)
|
||||||
|
|
||||||
if tmp[0] == '#add_surface_water:':
|
if tmp[0] == '#add_surface_water:':
|
||||||
if len(tmp) != 9:
|
if len(tmp) != 9:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires exactly eight parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires exactly eight parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||||
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
||||||
depth = float(tmp[7])
|
depth = float(tmp[7])
|
||||||
fractal_box_id = tmp[8]
|
fractal_box_id = tmp[8]
|
||||||
|
|
||||||
asf = AddSurfaceWater(p1=p1, p2=p2, depth=depth, fractal_box_id=fractal_box_id)
|
asf = AddSurfaceWater(p1=p1, p2=p2, depth=depth, fractal_box_id=fractal_box_id)
|
||||||
scene_objects.append(asf)
|
scene_objects.append(asf)
|
||||||
|
|
||||||
if tmp[0] == '#add_grass:':
|
if tmp[0] == '#add_grass:':
|
||||||
if len(tmp) < 12:
|
if len(tmp) < 12:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least eleven parameters')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' requires at least eleven parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
p1 = (float(tmp[1]), float(tmp[2]), float(tmp[3]))
|
||||||
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
p2 = (float(tmp[4]), float(tmp[5]), float(tmp[6]))
|
||||||
frac_dim = float(tmp[7])
|
frac_dim = float(tmp[7])
|
||||||
limits = [float(tmp[8]), float(tmp[9])]
|
limits = [float(tmp[8]), float(tmp[9])]
|
||||||
n_blades = int(tmp[10])
|
n_blades = int(tmp[10])
|
||||||
fractal_box_id = tmp[11]
|
fractal_box_id = tmp[11]
|
||||||
|
|
||||||
# no seed
|
# no seed
|
||||||
if len(tmp) == 12:
|
if len(tmp) == 12:
|
||||||
grass = AddGrass(p1=p1, p2=p2, frac_dim=frac_dim, limits=limits, n_blades=n_blades, fractal_box_id=fractal_box_id)
|
grass = AddGrass(p1=p1, p2=p2, frac_dim=frac_dim, limits=limits, n_blades=n_blades, fractal_box_id=fractal_box_id)
|
||||||
elif len(tmp) == 13:
|
elif len(tmp) == 13:
|
||||||
grass = AddGrass(p1=p1, p2=p2, frac_dim=frac_dim, limits=limits, n_blades=n_blades, fractal_box_id=fractal_box_id, seed=int(tmp[12]))
|
grass = AddGrass(p1=p1, p2=p2, frac_dim=frac_dim, limits=limits, n_blades=n_blades, fractal_box_id=fractal_box_id, seed=int(tmp[12]))
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
raise CmdInputError("'" + ' '.join(tmp) + "'" + ' too many parameters have been given')
|
||||||
scene_objects.append(grass)
|
scene_objects.append(grass)
|
||||||
|
|
||||||
return scene_objects
|
return scene_objects
|
||||||
|
@@ -1,338 +1,338 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
# Copyright (C) 2015-2018: The University of Edinburgh
|
# Copyright (C) 2015-2018: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
from .exceptions import CmdInputError
|
from .exceptions import CmdInputError
|
||||||
from .cmds_multiple import Waveform
|
from .cmds_multiple import Waveform
|
||||||
from .cmds_multiple import VoltageSource
|
from .cmds_multiple import VoltageSource
|
||||||
from .cmds_multiple import HertzianDipole
|
from .cmds_multiple import HertzianDipole
|
||||||
from .cmds_multiple import MagneticDipole
|
from .cmds_multiple import MagneticDipole
|
||||||
from .cmds_multiple import TransmissionLine
|
from .cmds_multiple import TransmissionLine
|
||||||
from .cmds_multiple import Material
|
from .cmds_multiple import Material
|
||||||
from .cmds_multiple import Snapshot
|
from .cmds_multiple import Snapshot
|
||||||
from .cmds_multiple import AddDebyeDispersion
|
from .cmds_multiple import AddDebyeDispersion
|
||||||
from .cmds_multiple import AddLorentzDispersion
|
from .cmds_multiple import AddLorentzDispersion
|
||||||
from .cmds_multiple import AddDrudeDispersion
|
from .cmds_multiple import AddDrudeDispersion
|
||||||
from .cmds_multiple import SoilPeplinski
|
from .cmds_multiple import SoilPeplinski
|
||||||
from .cmds_multiple import GeometryView
|
from .cmds_multiple import GeometryView
|
||||||
from .cmds_multiple import GeometryObjectsWrite
|
from .cmds_multiple import GeometryObjectsWrite
|
||||||
from .cmds_multiple import PMLCFS
|
from .cmds_multiple import PMLCFS
|
||||||
from .cmds_multiple import Rx
|
from .cmds_multiple import Rx
|
||||||
|
|
||||||
|
|
||||||
def process_multicmds(multicmds):
|
def process_multicmds(multicmds):
|
||||||
"""
|
"""
|
||||||
Checks the validity of command parameters and creates instances of
|
Checks the validity of command parameters and creates instances of
|
||||||
classes of parameters.
|
classes of parameters.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
multicmds (dict): Commands that can have multiple instances in the model.
|
multicmds (dict): Commands that can have multiple instances in the model.
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
scene_objects = []
|
scene_objects = []
|
||||||
|
|
||||||
# Waveform definitions
|
# Waveform definitions
|
||||||
cmdname = '#waveform'
|
cmdname = '#waveform'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) != 4:
|
if len(tmp) != 4:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly four parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly four parameters')
|
||||||
|
|
||||||
waveform = Waveform(wave_type=tmp[0], amp=float(tmp[1]), freq=float(tmp[2]), id=tmp[3])
|
waveform = Waveform(wave_type=tmp[0], amp=float(tmp[1]), freq=float(tmp[2]), id=tmp[3])
|
||||||
scene_objects.append(waveform)
|
scene_objects.append(waveform)
|
||||||
|
|
||||||
# Voltage source
|
# Voltage source
|
||||||
cmdname = '#voltage_source'
|
cmdname = '#voltage_source'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) == 6:
|
if len(tmp) == 6:
|
||||||
voltage_source = VoltageSource(polarisation=tmp[0].lower(), p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), resistance=float(tmp[4]), waveform_id=tmp[5])
|
voltage_source = VoltageSource(polarisation=tmp[0].lower(), p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), resistance=float(tmp[4]), waveform_id=tmp[5])
|
||||||
elif len(tmp) == 8:
|
elif len(tmp) == 8:
|
||||||
voltage_source = VoltageSource(polarisation=tmp[0].lower(), p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), resistance=float(tmp[4]), waveform_id=tmp[5], start=float(tmp[6]), end=float(tmp[7]))
|
voltage_source = VoltageSource(polarisation=tmp[0].lower(), p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), resistance=float(tmp[4]), waveform_id=tmp[5], start=float(tmp[6]), end=float(tmp[7]))
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least six parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least six parameters')
|
||||||
|
|
||||||
scene_objects.append(voltage_source)
|
scene_objects.append(voltage_source)
|
||||||
|
|
||||||
# Hertzian dipole
|
# Hertzian dipole
|
||||||
cmdname = '#hertzian_dipole'
|
cmdname = '#hertzian_dipole'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) < 5:
|
if len(tmp) < 5:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
||||||
if len(tmp) == 5:
|
if len(tmp) == 5:
|
||||||
hertzian_dipole = HertzianDipole(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), waveform_id=tmp[4])
|
hertzian_dipole = HertzianDipole(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), waveform_id=tmp[4])
|
||||||
elif len(tmp) == 7:
|
elif len(tmp) == 7:
|
||||||
hertzian_dipole = HertzianDipole(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), waveform_id=tmp[4], start=float(tmp[5]), end=float(tmp[6]))
|
hertzian_dipole = HertzianDipole(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), waveform_id=tmp[4], start=float(tmp[5]), end=float(tmp[6]))
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' too many parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' too many parameters')
|
||||||
|
|
||||||
scene_objects.append(hertzian_dipole)
|
scene_objects.append(hertzian_dipole)
|
||||||
|
|
||||||
# Magnetic dipole
|
# Magnetic dipole
|
||||||
cmdname = '#magnetic_dipole'
|
cmdname = '#magnetic_dipole'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) < 5:
|
if len(tmp) < 5:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
||||||
if len(tmp) == 5:
|
if len(tmp) == 5:
|
||||||
magnetic_dipole = MagneticDipole(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), waveform_id=tmp[4])
|
magnetic_dipole = MagneticDipole(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), waveform_id=tmp[4])
|
||||||
elif len(tmp) == 7:
|
elif len(tmp) == 7:
|
||||||
magnetic_dipole = MagneticDipole(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), waveform_id=tmp[4], start=float(tmp[5]), end=float(tmp[6]))
|
magnetic_dipole = MagneticDipole(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), waveform_id=tmp[4], start=float(tmp[5]), end=float(tmp[6]))
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' too many parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' too many parameters')
|
||||||
|
|
||||||
scene_objects.append(magnetic_dipole)
|
scene_objects.append(magnetic_dipole)
|
||||||
|
|
||||||
# Transmission line
|
# Transmission line
|
||||||
cmdname = '#transmission_line'
|
cmdname = '#transmission_line'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) < 6:
|
if len(tmp) < 6:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least six parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least six parameters')
|
||||||
|
|
||||||
if len(tmp) == 6:
|
if len(tmp) == 6:
|
||||||
tl = TransmissionLine(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), resistance=float(tmp[4]), waveform_id=tmp[5])
|
tl = TransmissionLine(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), resistance=float(tmp[4]), waveform_id=tmp[5])
|
||||||
elif len(tmp) == 8:
|
elif len(tmp) == 8:
|
||||||
tl = TransmissionLine(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), resistance=float(tmp[4]), waveform_id=tmp[5], start=tmp[6], end=tmp[7])
|
tl = TransmissionLine(polarisation=tmp[0], p1=(float(tmp[1]), float(tmp[2]), float(tmp[3])), resistance=float(tmp[4]), waveform_id=tmp[5], start=tmp[6], end=tmp[7])
|
||||||
else:
|
else:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' too many parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' too many parameters')
|
||||||
|
|
||||||
scene_objects.append(tl)
|
scene_objects.append(tl)
|
||||||
|
|
||||||
# Receiver
|
# Receiver
|
||||||
cmdname = '#rx'
|
cmdname = '#rx'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) != 3 and len(tmp) < 5:
|
if len(tmp) != 3 and len(tmp) < 5:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' has an incorrect number of parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' has an incorrect number of parameters')
|
||||||
if len(tmp) == 3:
|
if len(tmp) == 3:
|
||||||
rx = Rx(p1=(float(tmp[0]), float(tmp[1]), float(tmp[2])))
|
rx = Rx(p1=(float(tmp[0]), float(tmp[1]), float(tmp[2])))
|
||||||
else:
|
else:
|
||||||
rx = Rx(p1=(float(tmp[0]), float(tmp[1]), float(tmp[2])), id=tmp[3], outputs=tmp[4:])
|
rx = Rx(p1=(float(tmp[0]), float(tmp[1]), float(tmp[2])), id=tmp[3], outputs=tmp[4:])
|
||||||
scene_objects.append(rx)
|
scene_objects.append(rx)
|
||||||
|
|
||||||
# Receiver array
|
# Receiver array
|
||||||
cmdname = '#rx_array'
|
cmdname = '#rx_array'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) != 9:
|
if len(tmp) != 9:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly nine parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly nine parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[0], float(tmp[1]), float[tmp[2]]))
|
p1 = (float(tmp[0], float(tmp[1]), float[tmp[2]]))
|
||||||
p2 = (float(tmp[3], float(tmp[4]), float[tmp[5]]))
|
p2 = (float(tmp[3], float(tmp[4]), float[tmp[5]]))
|
||||||
dl = (float(tmp[6], float(tmp[7]), float[tmp[8]]))
|
dl = (float(tmp[6], float(tmp[7]), float[tmp[8]]))
|
||||||
|
|
||||||
rx_array = RxArray(p1=p1, p2=p2, dl=dl)
|
rx_array = RxArray(p1=p1, p2=p2, dl=dl)
|
||||||
scene_objects.append(rx_array)
|
scene_objects.append(rx_array)
|
||||||
|
|
||||||
# Snapshot
|
# Snapshot
|
||||||
cmdname = '#snapshot'
|
cmdname = '#snapshot'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) != 11:
|
if len(tmp) != 11:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly eleven parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly eleven parameters')
|
||||||
|
|
||||||
p1 = (float(tmp[0], float(tmp[1]), float[tmp[2]]))
|
p1 = (float(tmp[0], float(tmp[1]), float[tmp[2]]))
|
||||||
p2 = (float(tmp[3], float(tmp[4]), float[tmp[5]]))
|
p2 = (float(tmp[3], float(tmp[4]), float[tmp[5]]))
|
||||||
dl = (float(tmp[6], float(tmp[7]), float[tmp[8]]))
|
dl = (float(tmp[6], float(tmp[7]), float[tmp[8]]))
|
||||||
filename = tmp[10]
|
filename = tmp[10]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
iterations = int(tmp[9])
|
iterations = int(tmp[9])
|
||||||
snapshot = Snapshot(p1=p1, p2=p2, dl=dl, iterations=iterations, filename=filename)
|
snapshot = Snapshot(p1=p1, p2=p2, dl=dl, iterations=iterations, filename=filename)
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
time = float(tmp[9])
|
time = float(tmp[9])
|
||||||
snapshot = Snapshot(p1=p1, p2=p2, dl=dl, time=time, filename=filename)
|
snapshot = Snapshot(p1=p1, p2=p2, dl=dl, time=time, filename=filename)
|
||||||
|
|
||||||
scene_objects.append(snapshot)
|
scene_objects.append(snapshot)
|
||||||
|
|
||||||
# Materials
|
# Materials
|
||||||
cmdname = '#material'
|
cmdname = '#material'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) != 5:
|
if len(tmp) != 5:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly five parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly five parameters')
|
||||||
|
|
||||||
material = Material(er=float(tmp[0]), se=float(tmp[1]), mr=float(tmp[2]), sm=float(tmp[3]), id=tmp[4])
|
material = Material(er=float(tmp[0]), se=float(tmp[1]), mr=float(tmp[2]), sm=float(tmp[3]), id=tmp[4])
|
||||||
scene_objects.append(material)
|
scene_objects.append(material)
|
||||||
|
|
||||||
cmdname = '#add_dispersion_debye'
|
cmdname = '#add_dispersion_debye'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
|
|
||||||
if len(tmp) < 4:
|
if len(tmp) < 4:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least four parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least four parameters')
|
||||||
|
|
||||||
poles = int(tmp[0])
|
poles = int(tmp[0])
|
||||||
er_delta = []
|
er_delta = []
|
||||||
tau = []
|
tau = []
|
||||||
material_ids = tmp[(2 * poles) + 1:len(tmp)]
|
material_ids = tmp[(2 * poles) + 1:len(tmp)]
|
||||||
|
|
||||||
for pole in range(1, 2 * poles, 2):
|
for pole in range(1, 2 * poles, 2):
|
||||||
er_delta.append(float(tmp[pole]))
|
er_delta.append(float(tmp[pole]))
|
||||||
tau.append(float(tmp[pole + 1]))
|
tau.append(float(tmp[pole + 1]))
|
||||||
|
|
||||||
debye_dispersion = AddDebyeDispersion(pole=poles, er_delta=er_delta, tau=tau, material_ids=material_ids)
|
debye_dispersion = AddDebyeDispersion(pole=poles, er_delta=er_delta, tau=tau, material_ids=material_ids)
|
||||||
scene_objects.append(debye_dispersion)
|
scene_objects.append(debye_dispersion)
|
||||||
|
|
||||||
cmdname = '#add_dispersion_lorentz'
|
cmdname = '#add_dispersion_lorentz'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
|
|
||||||
if len(tmp) < 5:
|
if len(tmp) < 5:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
||||||
|
|
||||||
poles = int(tmp[0])
|
poles = int(tmp[0])
|
||||||
material_ids = tmp[(3 * poles) + 1:len(tmp)]
|
material_ids = tmp[(3 * poles) + 1:len(tmp)]
|
||||||
er_delta = []
|
er_delta = []
|
||||||
tau = []
|
tau = []
|
||||||
alpha = []
|
alpha = []
|
||||||
|
|
||||||
for pole in range(1, 3 * poles, 3):
|
for pole in range(1, 3 * poles, 3):
|
||||||
er_delta.append(float(tmp[pole]))
|
er_delta.append(float(tmp[pole]))
|
||||||
tau.append(float(tmp[pole + 1]))
|
tau.append(float(tmp[pole + 1]))
|
||||||
alpha.append(float(tmp[pole + 2]))
|
alpha.append(float(tmp[pole + 2]))
|
||||||
|
|
||||||
lorentz_dispersion = AddLorentzDispersion(poles=poles, material_ids=material_ids, er_delta=er_delta, tau=tau, alpha=alpha)
|
lorentz_dispersion = AddLorentzDispersion(poles=poles, material_ids=material_ids, er_delta=er_delta, tau=tau, alpha=alpha)
|
||||||
scene_objects.append(lorentz_dispersion)
|
scene_objects.append(lorentz_dispersion)
|
||||||
|
|
||||||
cmdname = '#add_dispersion_drude'
|
cmdname = '#add_dispersion_drude'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
|
|
||||||
if len(tmp) < 5:
|
if len(tmp) < 5:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters')
|
||||||
|
|
||||||
poles = int(tmp[0])
|
poles = int(tmp[0])
|
||||||
material_ids = tmp[(3 * poles) + 1:len(tmp)]
|
material_ids = tmp[(3 * poles) + 1:len(tmp)]
|
||||||
tau = []
|
tau = []
|
||||||
alpha = []
|
alpha = []
|
||||||
|
|
||||||
for pole in range(1, 2 * poles, 2):
|
for pole in range(1, 2 * poles, 2):
|
||||||
tau.append(float(tmp[pole]))
|
tau.append(float(tmp[pole]))
|
||||||
alpha.append(float(tmp[pole + 1]))
|
alpha.append(float(tmp[pole + 1]))
|
||||||
|
|
||||||
drude_dispersion = AddDrudeDispersion(poles=poles, material_ids=material_ids, tau=tau, alpha=alpha)
|
drude_dispersion = AddDrudeDispersion(poles=poles, material_ids=material_ids, tau=tau, alpha=alpha)
|
||||||
scene_objects.append(drude_dispersion)
|
scene_objects.append(drude_dispersion)
|
||||||
|
|
||||||
cmdname = '#soil_peplinski'
|
cmdname = '#soil_peplinski'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
|
|
||||||
if len(tmp) != 7:
|
if len(tmp) != 7:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at exactly seven parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at exactly seven parameters')
|
||||||
soil = SoilPeplinski(sand_fraction=float(tmp[0]),
|
soil = SoilPeplinski(sand_fraction=float(tmp[0]),
|
||||||
clay_fraction=float(tmp[1]),
|
clay_fraction=float(tmp[1]),
|
||||||
bulk_density=float(tmp[2]),
|
bulk_density=float(tmp[2]),
|
||||||
sand_density=float(tmp[3]),
|
sand_density=float(tmp[3]),
|
||||||
water_fraction_lower=float(tmp[4]),
|
water_fraction_lower=float(tmp[4]),
|
||||||
water_fraction_upper=float(tmp[5]),
|
water_fraction_upper=float(tmp[5]),
|
||||||
id=tmp[6])
|
id=tmp[6])
|
||||||
scene_objects.append(soil)
|
scene_objects.append(soil)
|
||||||
|
|
||||||
# Geometry views (creates VTK-based geometry files)
|
# Geometry views (creates VTK-based geometry files)
|
||||||
cmdname = '#geometry_view'
|
cmdname = '#geometry_view'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) != 11:
|
if len(tmp) != 11:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly eleven parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly eleven parameters')
|
||||||
|
|
||||||
p1 = float(tmp[0]), float(tmp[1]), float(tmp[2])
|
p1 = float(tmp[0]), float(tmp[1]), float(tmp[2])
|
||||||
p2 = float(tmp[3]), float(tmp[4]), float(tmp[5])
|
p2 = float(tmp[3]), float(tmp[4]), float(tmp[5])
|
||||||
dl = float(tmp[6]), float(tmp[7]), float(tmp[8])
|
dl = float(tmp[6]), float(tmp[7]), float(tmp[8])
|
||||||
|
|
||||||
geometry_view = GeometryView(p1=p1, p2=p2, dl=dl, filename=tmp[9], output_type=tmp[10])
|
geometry_view = GeometryView(p1=p1, p2=p2, dl=dl, filename=tmp[9], output_type=tmp[10])
|
||||||
|
|
||||||
scene_objects.append(geometry_view)
|
scene_objects.append(geometry_view)
|
||||||
|
|
||||||
# Geometry object(s) output
|
# Geometry object(s) output
|
||||||
cmdname = '#geometry_objects_write'
|
cmdname = '#geometry_objects_write'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) != 7:
|
if len(tmp) != 7:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly seven parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly seven parameters')
|
||||||
|
|
||||||
p1 = float(tmp[0]), float(tmp[1]), float(tmp[2])
|
p1 = float(tmp[0]), float(tmp[1]), float(tmp[2])
|
||||||
p2 = float(tmp[3]), float(tmp[4]), float(tmp[5])
|
p2 = float(tmp[3]), float(tmp[4]), float(tmp[5])
|
||||||
gow = GeometryObjectsWrite(p1=p1, p2=p2, filename=tmp[6])
|
gow = GeometryObjectsWrite(p1=p1, p2=p2, filename=tmp[6])
|
||||||
scene_objects.append(gow)
|
scene_objects.append(gow)
|
||||||
|
|
||||||
|
|
||||||
# Complex frequency shifted (CFS) PML parameter
|
# Complex frequency shifted (CFS) PML parameter
|
||||||
cmdname = '#pml_cfs'
|
cmdname = '#pml_cfs'
|
||||||
if multicmds[cmdname] is not None:
|
if multicmds[cmdname] is not None:
|
||||||
if len(multicmds[cmdname]) > 2:
|
if len(multicmds[cmdname]) > 2:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' can only be used up to two times, for up to a 2nd order PML')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' can only be used up to two times, for up to a 2nd order PML')
|
||||||
for cmdinstance in multicmds[cmdname]:
|
for cmdinstance in multicmds[cmdname]:
|
||||||
tmp = cmdinstance.split()
|
tmp = cmdinstance.split()
|
||||||
if len(tmp) != 12:
|
if len(tmp) != 12:
|
||||||
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly twelve parameters')
|
raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly twelve parameters')
|
||||||
|
|
||||||
pml_cfs = PMLCFS(alphascalingprofile=tmp[0],
|
pml_cfs = PMLCFS(alphascalingprofile=tmp[0],
|
||||||
alphascalingdirection=tmp[1],
|
alphascalingdirection=tmp[1],
|
||||||
alphamin=tmp[2],
|
alphamin=tmp[2],
|
||||||
alphamax=tmp[3],
|
alphamax=tmp[3],
|
||||||
kappascalingprofile=tmp[4],
|
kappascalingprofile=tmp[4],
|
||||||
kappascalingdirection=tmp[5],
|
kappascalingdirection=tmp[5],
|
||||||
kappamin=tmp[6],
|
kappamin=tmp[6],
|
||||||
kappamax=tmp[7],
|
kappamax=tmp[7],
|
||||||
sigmascalingprofile=tmp[8],
|
sigmascalingprofile=tmp[8],
|
||||||
sigmascalingdirection=tmp[9],
|
sigmascalingdirection=tmp[9],
|
||||||
sigmamin=tmp[10],
|
sigmamin=tmp[10],
|
||||||
sigmamax=tmp[11])
|
sigmamax=tmp[11])
|
||||||
|
|
||||||
scene_objects.append(pml_cfs)
|
scene_objects.append(pml_cfs)
|
||||||
|
|
||||||
return scene_objects
|
return scene_objects
|
||||||
|
|
||||||
def process_subgrid_hsg(cmdinstance):
|
def process_subgrid_hsg(cmdinstance):
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
@@ -1,364 +1,364 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
import itertools
|
import itertools
|
||||||
import os
|
import os
|
||||||
import psutil
|
import psutil
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from colorama import init
|
from colorama import init
|
||||||
from colorama import Fore
|
from colorama import Fore
|
||||||
from colorama import Style
|
from colorama import Style
|
||||||
init()
|
init()
|
||||||
import cython
|
import cython
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from terminaltables import SingleTable
|
from terminaltables import SingleTable
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import gprMax.config as config
|
import gprMax.config as config
|
||||||
from .cuda.fields_updates import kernel_template_fields
|
from .cuda.fields_updates import kernel_template_fields
|
||||||
from .cuda.snapshots import kernel_template_store_snapshot
|
from .cuda.snapshots import kernel_template_store_snapshot
|
||||||
from .cuda.source_updates import kernel_template_sources
|
from .cuda.source_updates import kernel_template_sources
|
||||||
from .cython.yee_cell_build import build_electric_components
|
from .cython.yee_cell_build import build_electric_components
|
||||||
from .cython.yee_cell_build import build_magnetic_components
|
from .cython.yee_cell_build import build_magnetic_components
|
||||||
from .exceptions import GeneralError
|
from .exceptions import GeneralError
|
||||||
from .fields_outputs import kernel_template_store_outputs
|
from .fields_outputs import kernel_template_store_outputs
|
||||||
from .fields_outputs import write_hdf5_outputfile
|
from .fields_outputs import write_hdf5_outputfile
|
||||||
from .grid import FDTDGrid
|
from .grid import FDTDGrid
|
||||||
from .grid import dispersion_analysis
|
from .grid import dispersion_analysis
|
||||||
from .input_cmds_geometry import process_geometrycmds
|
from .input_cmds_geometry import process_geometrycmds
|
||||||
from .input_cmds_file import process_python_include_code
|
from .input_cmds_file import process_python_include_code
|
||||||
from .input_cmds_file import write_processed_file
|
from .input_cmds_file import write_processed_file
|
||||||
from .input_cmds_file import check_cmd_names
|
from .input_cmds_file import check_cmd_names
|
||||||
from .input_cmds_file import parse_hash_commands
|
from .input_cmds_file import parse_hash_commands
|
||||||
from .input_cmds_singleuse import process_singlecmds
|
from .input_cmds_singleuse import process_singlecmds
|
||||||
from .input_cmds_multiuse import process_multicmds
|
from .input_cmds_multiuse import process_multicmds
|
||||||
from .materials import Material
|
from .materials import Material
|
||||||
from .materials import process_materials
|
from .materials import process_materials
|
||||||
from .pml import CFS
|
from .pml import CFS
|
||||||
from .pml import PML
|
from .pml import PML
|
||||||
from .pml import build_pml
|
from .pml import build_pml
|
||||||
from .pml import pml_information
|
from .pml import pml_information
|
||||||
from .receivers import gpu_initialise_rx_arrays
|
from .receivers import gpu_initialise_rx_arrays
|
||||||
from .receivers import gpu_get_rx_array
|
from .receivers import gpu_get_rx_array
|
||||||
from .receivers import Rx
|
from .receivers import Rx
|
||||||
from .snapshots import Snapshot
|
from .snapshots import Snapshot
|
||||||
from .snapshots import gpu_initialise_snapshot_array
|
from .snapshots import gpu_initialise_snapshot_array
|
||||||
from .snapshots import gpu_get_snapshot_array
|
from .snapshots import gpu_get_snapshot_array
|
||||||
from .sources import gpu_initialise_src_arrays
|
from .sources import gpu_initialise_src_arrays
|
||||||
from .utilities import get_terminal_width
|
from .utilities import get_terminal_width
|
||||||
from .utilities import human_size
|
from .utilities import human_size
|
||||||
from .utilities import open_path_file
|
from .utilities import open_path_file
|
||||||
from .utilities import round32
|
from .utilities import round32
|
||||||
from .utilities import timer
|
from .utilities import timer
|
||||||
from .utilities import Printer
|
from .utilities import Printer
|
||||||
from .scene import Scene
|
from .scene import Scene
|
||||||
from .solvers import create_solver
|
from .solvers import create_solver
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ModelBuildRun:
|
class ModelBuildRun:
|
||||||
|
|
||||||
def __init__(self, G, sim_config, model_config):
|
def __init__(self, G, sim_config, model_config):
|
||||||
self.G = G
|
self.G = G
|
||||||
self.sim_config = sim_config
|
self.sim_config = sim_config
|
||||||
self.model_config = model_config
|
self.model_config = model_config
|
||||||
self.printer = Printer(config)
|
self.printer = Printer(config)
|
||||||
# Monitor memory usage
|
# Monitor memory usage
|
||||||
self.p = None
|
self.p = None
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
"""Runs a model - processes the input file; builds the Yee cells; calculates update coefficients; runs main FDTD loop.
|
"""Runs a model - processes the input file; builds the Yee cells; calculates update coefficients; runs main FDTD loop.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
args (dict): Namespace with command line arguments
|
args (dict): Namespace with command line arguments
|
||||||
currentmodelrun (int): Current model run number.
|
currentmodelrun (int): Current model run number.
|
||||||
modelend (int): Number of last model to run.
|
modelend (int): Number of last model to run.
|
||||||
numbermodelruns (int): Total number of model runs.
|
numbermodelruns (int): Total number of model runs.
|
||||||
inputfile (object): File object for the input file.
|
inputfile (object): File object for the input file.
|
||||||
usernamespace (dict): Namespace that can be accessed by user
|
usernamespace (dict): Namespace that can be accessed by user
|
||||||
in any Python code blocks in input file.
|
in any Python code blocks in input file.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tsolve (int): Length of time (seconds) of main FDTD calculations
|
tsolve (int): Length of time (seconds) of main FDTD calculations
|
||||||
"""
|
"""
|
||||||
# Monitor memory usage
|
# Monitor memory usage
|
||||||
self.p = psutil.Process()
|
self.p = psutil.Process()
|
||||||
|
|
||||||
# Normal model reading/building process; bypassed if geometry information to be reused
|
# Normal model reading/building process; bypassed if geometry information to be reused
|
||||||
if self.model_config.reuse_geometry:
|
if self.model_config.reuse_geometry:
|
||||||
self.reuse_geometry()
|
self.reuse_geometry()
|
||||||
else:
|
else:
|
||||||
self.build_geometry()
|
self.build_geometry()
|
||||||
|
|
||||||
G = self.G
|
G = self.G
|
||||||
|
|
||||||
# Adjust position of simple sources and receivers if required
|
# Adjust position of simple sources and receivers if required
|
||||||
if G.srcsteps[0] != 0 or G.srcsteps[1] != 0 or G.srcsteps[2] != 0:
|
if G.srcsteps[0] != 0 or G.srcsteps[1] != 0 or G.srcsteps[2] != 0:
|
||||||
for source in itertools.chain(G.hertziandipoles, G.magneticdipoles):
|
for source in itertools.chain(G.hertziandipoles, G.magneticdipoles):
|
||||||
if currentmodelrun == 1:
|
if currentmodelrun == 1:
|
||||||
if source.xcoord + G.srcsteps[0] * modelend < 0 or source.xcoord + G.srcsteps[0] * modelend > G.nx or source.ycoord + G.srcsteps[1] * modelend < 0 or source.ycoord + G.srcsteps[1] * modelend > G.ny or source.zcoord + G.srcsteps[2] * modelend < 0 or source.zcoord + G.srcsteps[2] * modelend > G.nz:
|
if source.xcoord + G.srcsteps[0] * modelend < 0 or source.xcoord + G.srcsteps[0] * modelend > G.nx or source.ycoord + G.srcsteps[1] * modelend < 0 or source.ycoord + G.srcsteps[1] * modelend > G.ny or source.zcoord + G.srcsteps[2] * modelend < 0 or source.zcoord + G.srcsteps[2] * modelend > G.nz:
|
||||||
raise GeneralError('Source(s) will be stepped to a position outside the domain.')
|
raise GeneralError('Source(s) will be stepped to a position outside the domain.')
|
||||||
source.xcoord = source.xcoordorigin + (currentmodelrun - 1) * G.srcsteps[0]
|
source.xcoord = source.xcoordorigin + (currentmodelrun - 1) * G.srcsteps[0]
|
||||||
source.ycoord = source.ycoordorigin + (currentmodelrun - 1) * G.srcsteps[1]
|
source.ycoord = source.ycoordorigin + (currentmodelrun - 1) * G.srcsteps[1]
|
||||||
source.zcoord = source.zcoordorigin + (currentmodelrun - 1) * G.srcsteps[2]
|
source.zcoord = source.zcoordorigin + (currentmodelrun - 1) * G.srcsteps[2]
|
||||||
if G.rxsteps[0] != 0 or G.rxsteps[1] != 0 or G.rxsteps[2] != 0:
|
if G.rxsteps[0] != 0 or G.rxsteps[1] != 0 or G.rxsteps[2] != 0:
|
||||||
for receiver in G.rxs:
|
for receiver in G.rxs:
|
||||||
if currentmodelrun == 1:
|
if currentmodelrun == 1:
|
||||||
if receiver.xcoord + G.rxsteps[0] * modelend < 0 or receiver.xcoord + G.rxsteps[0] * modelend > G.nx or receiver.ycoord + G.rxsteps[1] * modelend < 0 or receiver.ycoord + G.rxsteps[1] * modelend > G.ny or receiver.zcoord + G.rxsteps[2] * modelend < 0 or receiver.zcoord + G.rxsteps[2] * modelend > G.nz:
|
if receiver.xcoord + G.rxsteps[0] * modelend < 0 or receiver.xcoord + G.rxsteps[0] * modelend > G.nx or receiver.ycoord + G.rxsteps[1] * modelend < 0 or receiver.ycoord + G.rxsteps[1] * modelend > G.ny or receiver.zcoord + G.rxsteps[2] * modelend < 0 or receiver.zcoord + G.rxsteps[2] * modelend > G.nz:
|
||||||
raise GeneralError('Receiver(s) will be stepped to a position outside the domain.')
|
raise GeneralError('Receiver(s) will be stepped to a position outside the domain.')
|
||||||
receiver.xcoord = receiver.xcoordorigin + (currentmodelrun - 1) * G.rxsteps[0]
|
receiver.xcoord = receiver.xcoordorigin + (currentmodelrun - 1) * G.rxsteps[0]
|
||||||
receiver.ycoord = receiver.ycoordorigin + (currentmodelrun - 1) * G.rxsteps[1]
|
receiver.ycoord = receiver.ycoordorigin + (currentmodelrun - 1) * G.rxsteps[1]
|
||||||
receiver.zcoord = receiver.zcoordorigin + (currentmodelrun - 1) * G.rxsteps[2]
|
receiver.zcoord = receiver.zcoordorigin + (currentmodelrun - 1) * G.rxsteps[2]
|
||||||
|
|
||||||
# Write files for any geometry views and geometry object outputs
|
# 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():
|
if not (G.geometryviews or G.geometryobjectswrite) and self.sim_config.geometry_only and config.is_messages():
|
||||||
print(Fore.RED + '\nWARNING: No geometry views or geometry objects to output found.' + Style.RESET_ALL)
|
print(Fore.RED + '\nWARNING: No geometry views or geometry objects to output found.' + Style.RESET_ALL)
|
||||||
if config.is_messages(): print()
|
if config.is_messages(): print()
|
||||||
for i, geometryview in enumerate(G.geometryviews):
|
for i, geometryview in enumerate(G.geometryviews):
|
||||||
geometryview.set_filename(self.model_config.appendmodelnumber)
|
geometryview.set_filename(self.model_config.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'])
|
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)
|
geometryview.write_vtk(G, pbar)
|
||||||
pbar.close()
|
pbar.close()
|
||||||
for i, geometryobject in enumerate(G.geometryobjectswrite):
|
for i, geometryobject in enumerate(G.geometryobjectswrite):
|
||||||
pbar = tqdm(total=geometryobject.datawritesize, unit='byte', unit_scale=True, desc='Writing geometry object file {}/{}, {}'.format(i + 1, len(G.geometryobjectswrite), os.path.split(geometryobject.filename)[1]), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars'])
|
pbar = tqdm(total=geometryobject.datawritesize, unit='byte', unit_scale=True, desc='Writing geometry object file {}/{}, {}'.format(i + 1, len(G.geometryobjectswrite), os.path.split(geometryobject.filename)[1]), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars'])
|
||||||
geometryobject.write_hdf5(G, pbar)
|
geometryobject.write_hdf5(G, pbar)
|
||||||
pbar.close()
|
pbar.close()
|
||||||
|
|
||||||
# If only writing geometry information
|
# If only writing geometry information
|
||||||
if self.sim_config.geometry_only:
|
if self.sim_config.geometry_only:
|
||||||
tsolve = 0
|
tsolve = 0
|
||||||
|
|
||||||
def build_geometry(self):
|
def build_geometry(self):
|
||||||
model_config = self.model_config
|
model_config = self.model_config
|
||||||
sim_config = self.sim_config
|
sim_config = self.sim_config
|
||||||
|
|
||||||
G = self.G
|
G = self.G
|
||||||
|
|
||||||
printer = Printer(config)
|
printer = Printer(config)
|
||||||
printer.print(model_config.next_model)
|
printer.print(model_config.next_model)
|
||||||
|
|
||||||
scene = self.build_scene()
|
scene = self.build_scene()
|
||||||
|
|
||||||
# combine available grids
|
# combine available grids
|
||||||
grids = [G] + G.subgrids
|
grids = [G] + G.subgrids
|
||||||
gridbuilders = [GridBuilder(grid, self.printer) for grid in grids]
|
gridbuilders = [GridBuilder(grid, self.printer) for grid in grids]
|
||||||
|
|
||||||
for gb in gridbuilders:
|
for gb in gridbuilders:
|
||||||
gb.printer.print(pml_information(gb.grid))
|
gb.printer.print(pml_information(gb.grid))
|
||||||
gb.build_pmls()
|
gb.build_pmls()
|
||||||
gb.build_components()
|
gb.build_components()
|
||||||
gb.tm_grid_update()
|
gb.tm_grid_update()
|
||||||
gb.update_voltage_source_materials()
|
gb.update_voltage_source_materials()
|
||||||
gb.grid.initialise_std_update_coeff_arrays()
|
gb.grid.initialise_std_update_coeff_arrays()
|
||||||
|
|
||||||
# Set datatype for dispersive arrays if there are any dispersive materials.
|
# Set datatype for dispersive arrays if there are any dispersive materials.
|
||||||
if config.materials['maxpoles'] != 0:
|
if config.materials['maxpoles'] != 0:
|
||||||
drudelorentz = any([m for m in G.materials if 'drude' in m.type or 'lorentz' in m.type])
|
drudelorentz = any([m for m in G.materials if 'drude' in m.type or 'lorentz' in m.type])
|
||||||
if drudelorentz:
|
if drudelorentz:
|
||||||
config.materials['dispersivedtype'] = config.dtypes['complex']
|
config.materials['dispersivedtype'] = config.dtypes['complex']
|
||||||
config.materials['dispersiveCdtype'] = config.dtypes['C_complex']
|
config.materials['dispersiveCdtype'] = config.dtypes['C_complex']
|
||||||
else:
|
else:
|
||||||
config.materials['dispersivedtype'] = config.dtypes['float_or_double']
|
config.materials['dispersivedtype'] = config.dtypes['float_or_double']
|
||||||
config.materials['dispersiveCdtype'] = config.dtypes['C_float_or_double']
|
config.materials['dispersiveCdtype'] = config.dtypes['C_float_or_double']
|
||||||
|
|
||||||
# Update estimated memory (RAM) usage
|
# Update estimated memory (RAM) usage
|
||||||
G.memoryusage += int(3 * config.materials['maxpoles'] * (G.nx + 1) * (G.ny + 1) * (G.nz + 1) * np.dtype(config.materials['dispersivedtype']).itemsize)
|
G.memoryusage += int(3 * config.materials['maxpoles'] * (G.nx + 1) * (G.ny + 1) * (G.nz + 1) * np.dtype(config.materials['dispersivedtype']).itemsize)
|
||||||
G.memory_check()
|
G.memory_check()
|
||||||
printer.print('\nMemory (RAM) required - updated (dispersive): ~{}\n'.format(human_size(G.memoryusage)))
|
printer.print('\nMemory (RAM) required - updated (dispersive): ~{}\n'.format(human_size(G.memoryusage)))
|
||||||
|
|
||||||
for gb in gridbuilders:
|
for gb in gridbuilders:
|
||||||
gb.grid.initialise_dispersive_arrays(config.materials['dispersivedtype'])
|
gb.grid.initialise_dispersive_arrays(config.materials['dispersivedtype'])
|
||||||
|
|
||||||
# Check there is sufficient memory to store any snapshots
|
# Check there is sufficient memory to store any snapshots
|
||||||
if G.snapshots:
|
if G.snapshots:
|
||||||
snapsmemsize = 0
|
snapsmemsize = 0
|
||||||
for snap in G.snapshots:
|
for snap in G.snapshots:
|
||||||
# 2 x required to account for electric and magnetic fields
|
# 2 x required to account for electric and magnetic fields
|
||||||
snapsmemsize += (2 * snap.datasizefield)
|
snapsmemsize += (2 * snap.datasizefield)
|
||||||
G.memoryusage += int(snapsmemsize)
|
G.memoryusage += int(snapsmemsize)
|
||||||
G.memory_check(snapsmemsize=int(snapsmemsize))
|
G.memory_check(snapsmemsize=int(snapsmemsize))
|
||||||
|
|
||||||
printer.print('\nMemory (RAM) required - updated (snapshots): ~{}\n'.format(human_size(G.memoryusage)))
|
printer.print('\nMemory (RAM) required - updated (snapshots): ~{}\n'.format(human_size(G.memoryusage)))
|
||||||
|
|
||||||
for gb in gridbuilders:
|
for gb in gridbuilders:
|
||||||
gb.build_materials()
|
gb.build_materials()
|
||||||
|
|
||||||
# Check to see if numerical dispersion might be a problem
|
# Check to see if numerical dispersion might be a problem
|
||||||
results = dispersion_analysis(G)
|
results = dispersion_analysis(G)
|
||||||
if results['error']:
|
if results['error']:
|
||||||
printer.print(Fore.RED + "\nWARNING: Numerical dispersion analysis not carried out as {}".format(results['error']) + Style.RESET_ALL)
|
printer.print(Fore.RED + "\nWARNING: Numerical dispersion analysis not carried out as {}".format(results['error']) + Style.RESET_ALL)
|
||||||
elif results['N'] < config.numdispersion['mingridsampling']:
|
elif results['N'] < config.numdispersion['mingridsampling']:
|
||||||
raise GeneralError("Non-physical wave propagation: Material '{}' has wavelength sampled by {} cells, less than required minimum for physical wave propagation. Maximum significant frequency estimated as {:g}Hz".format(results['material'].ID, results['N'], results['maxfreq']))
|
raise GeneralError("Non-physical wave propagation: Material '{}' has wavelength sampled by {} cells, less than required minimum for physical wave propagation. Maximum significant frequency estimated as {:g}Hz".format(results['material'].ID, results['N'], results['maxfreq']))
|
||||||
elif results['deltavp'] and np.abs(results['deltavp']) > config.numdispersion['maxnumericaldisp']:
|
elif results['deltavp'] and np.abs(results['deltavp']) > config.numdispersion['maxnumericaldisp']:
|
||||||
printer.print(Fore.RED + "\nWARNING: Potentially significant numerical dispersion. Estimated largest physical phase-velocity error is {:.2f}% in material '{}' whose wavelength sampled by {} cells. Maximum significant frequency estimated as {:g}Hz".format(results['deltavp'], results['material'].ID, results['N'], results['maxfreq']) + Style.RESET_ALL)
|
printer.print(Fore.RED + "\nWARNING: Potentially significant numerical dispersion. Estimated largest physical phase-velocity error is {:.2f}% in material '{}' whose wavelength sampled by {} cells. Maximum significant frequency estimated as {:g}Hz".format(results['deltavp'], results['material'].ID, results['N'], results['maxfreq']) + Style.RESET_ALL)
|
||||||
elif results['deltavp']:
|
elif results['deltavp']:
|
||||||
printer.print("\nNumerical dispersion analysis: estimated largest physical phase-velocity error is {:.2f}% in material '{}' whose wavelength sampled by {} cells. Maximum significant frequency estimated as {:g}Hz".format(results['deltavp'], results['material'].ID, results['N'], results['maxfreq']))
|
printer.print("\nNumerical dispersion analysis: estimated largest physical phase-velocity error is {:.2f}% in material '{}' whose wavelength sampled by {} cells. Maximum significant frequency estimated as {:g}Hz".format(results['deltavp'], results['material'].ID, results['N'], results['maxfreq']))
|
||||||
|
|
||||||
|
|
||||||
def reuse_geometry(self):
|
def reuse_geometry(self):
|
||||||
G = self.G
|
G = self.G
|
||||||
inputfilestr = '\n--- Model {}/{}, input file (not re-processed, i.e. geometry fixed): {}'.format(self.model_config.appendmodelnumber, self.sim_config.model_end, self.sim_config.input_file_path)
|
inputfilestr = '\n--- Model {}/{}, input file (not re-processed, i.e. geometry fixed): {}'.format(self.model_config.appendmodelnumber, self.sim_config.model_end, self.sim_config.input_file_path)
|
||||||
self.printer.print(Fore.GREEN + '{} {}\n'.format(self.model_config.inputfilestr, '-' * (get_terminal_width() - 1 - len(inputfilestr))) + Style.RESET_ALL)
|
self.printer.print(Fore.GREEN + '{} {}\n'.format(self.model_config.inputfilestr, '-' * (get_terminal_width() - 1 - len(inputfilestr))) + Style.RESET_ALL)
|
||||||
for grid in [G] + G.subgrids:
|
for grid in [G] + G.subgrids:
|
||||||
grid.reset_fields()
|
grid.reset_fields()
|
||||||
|
|
||||||
def build_scene(self):
|
def build_scene(self):
|
||||||
G = self.G
|
G = self.G
|
||||||
# api for multiple scenes / model runs
|
# api for multiple scenes / model runs
|
||||||
scene = self.model_config.get_scene()
|
scene = self.model_config.get_scene()
|
||||||
|
|
||||||
# if there is no scene - process the hash commands instead
|
# if there is no scene - process the hash commands instead
|
||||||
if not scene:
|
if not scene:
|
||||||
scene = Scene()
|
scene = Scene()
|
||||||
# parse the input file into user objects and add them to the 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(self.model_config, G, scene)
|
||||||
|
|
||||||
# Creates the internal simulation objects.
|
# Creates the internal simulation objects.
|
||||||
scene.create_internal_objects(G)
|
scene.create_internal_objects(G)
|
||||||
return scene
|
return scene
|
||||||
|
|
||||||
def create_output_directory(self):
|
def create_output_directory(self):
|
||||||
|
|
||||||
if self.G.outputdirectory:
|
if self.G.outputdirectory:
|
||||||
# Check and set output directory and filename
|
# Check and set output directory and filename
|
||||||
try:
|
try:
|
||||||
os.mkdir(self.G.outputdirectory)
|
os.mkdir(self.G.outputdirectory)
|
||||||
self.printer.print('\nCreated output directory: {}'.format(self.G.outputdirectory))
|
self.printer.print('\nCreated output directory: {}'.format(self.G.outputdirectory))
|
||||||
except FileExistsError:
|
except FileExistsError:
|
||||||
pass
|
pass
|
||||||
# modify the output path (hack)
|
# modify the output path (hack)
|
||||||
self.model_config.output_file_path_ext = Path(self.G.outputdirectory, self.model_config.output_file_path_ext)
|
self.model_config.output_file_path_ext = Path(self.G.outputdirectory, self.model_config.output_file_path_ext)
|
||||||
|
|
||||||
|
|
||||||
def run_model(self, solver):
|
def run_model(self, solver):
|
||||||
|
|
||||||
G = self.G
|
G = self.G
|
||||||
|
|
||||||
self.create_output_directory()
|
self.create_output_directory()
|
||||||
self.printer.print('\nOutput file: {}\n'.format(self.model_config.output_file_path_ext))
|
self.printer.print('\nOutput file: {}\n'.format(self.model_config.output_file_path_ext))
|
||||||
|
|
||||||
tsolve = self.solve(solver)
|
tsolve = self.solve(solver)
|
||||||
|
|
||||||
# Write an output file in HDF5 format
|
# Write an output file in HDF5 format
|
||||||
write_hdf5_outputfile(self.model_config.output_file_path_ext, G)
|
write_hdf5_outputfile(self.model_config.output_file_path_ext, G)
|
||||||
|
|
||||||
# Write any snapshots to file
|
# Write any snapshots to file
|
||||||
if G.snapshots:
|
if G.snapshots:
|
||||||
# Create directory and construct filename from user-supplied name and model run number
|
# Create directory and construct filename from user-supplied name and model run number
|
||||||
snapshotdir = self.model_config.snapshot_dir
|
snapshotdir = self.model_config.snapshot_dir
|
||||||
if not os.path.exists(snapshotdir):
|
if not os.path.exists(snapshotdir):
|
||||||
os.mkdir(snapshotdir)
|
os.mkdir(snapshotdir)
|
||||||
|
|
||||||
self.printer.print()
|
self.printer.print()
|
||||||
for i, snap in enumerate(G.snapshots):
|
for i, snap in enumerate(G.snapshots):
|
||||||
snap.filename = snapshotdir + snap.basefilename + '.vti'
|
snap.filename = snapshotdir + snap.basefilename + '.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'])
|
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)
|
snap.write_vtk_imagedata(pbar, G)
|
||||||
pbar.close()
|
pbar.close()
|
||||||
self.printer.print()
|
self.printer.print()
|
||||||
|
|
||||||
memGPU = ''
|
memGPU = ''
|
||||||
if config.cuda['gpus']:
|
if config.cuda['gpus']:
|
||||||
memGPU = ' host + ~{} GPU'.format(human_size(self.solver.get_memsolve()))
|
memGPU = ' host + ~{} GPU'.format(human_size(self.solver.get_memsolve()))
|
||||||
|
|
||||||
self.printer.print('\nMemory (RAM) used: ~{}{}'.format(human_size(self.p.memory_full_info().uss), memGPU))
|
self.printer.print('\nMemory (RAM) used: ~{}{}'.format(human_size(self.p.memory_full_info().uss), memGPU))
|
||||||
self.printer.print('Solving time [HH:MM:SS]: {}'.format(datetime.timedelta(seconds=tsolve)))
|
self.printer.print('Solving time [HH:MM:SS]: {}'.format(datetime.timedelta(seconds=tsolve)))
|
||||||
|
|
||||||
return tsolve
|
return tsolve
|
||||||
|
|
||||||
def solve(self, solver):
|
def solve(self, solver):
|
||||||
"""
|
"""
|
||||||
Solving using FDTD method on CPU. Parallelised using Cython (OpenMP) for
|
Solving using FDTD method on CPU. Parallelised using Cython (OpenMP) for
|
||||||
electric and magnetic field updates, and PML updates.
|
electric and magnetic field updates, and PML updates.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
currentmodelrun (int): Current model run number.
|
currentmodelrun (int): Current model run number.
|
||||||
modelend (int): Number of last model to run.
|
modelend (int): Number of last model to run.
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tsolve (float): Time taken to execute solving (seconds)
|
tsolve (float): Time taken to execute solving (seconds)
|
||||||
"""
|
"""
|
||||||
G = self.G
|
G = self.G
|
||||||
|
|
||||||
if config.is_messages():
|
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(self.model_config
|
||||||
.i + 1) + '/' + str(self.sim_config.model_end), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars'])
|
.i + 1) + '/' + str(self.sim_config.model_end), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars'])
|
||||||
else:
|
else:
|
||||||
iterator = range(0, G.iterations)
|
iterator = range(0, G.iterations)
|
||||||
|
|
||||||
tsolve = solver.solve(iterator)
|
tsolve = solver.solve(iterator)
|
||||||
|
|
||||||
return tsolve
|
return tsolve
|
||||||
|
|
||||||
|
|
||||||
class GridBuilder:
|
class GridBuilder:
|
||||||
def __init__(self, grid, printer):
|
def __init__(self, grid, printer):
|
||||||
self.grid = grid
|
self.grid = grid
|
||||||
self.printer = printer
|
self.printer = printer
|
||||||
|
|
||||||
def build_pmls(self):
|
def build_pmls(self):
|
||||||
|
|
||||||
grid = self.grid
|
grid = self.grid
|
||||||
# build the PMLS
|
# 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.general['progressbars'])
|
||||||
|
|
||||||
for pml_id, thickness in grid.pmlthickness.items():
|
for pml_id, thickness in grid.pmlthickness.items():
|
||||||
build_pml(grid, pml_id, thickness)
|
build_pml(grid, pml_id, thickness)
|
||||||
pbar.update()
|
pbar.update()
|
||||||
pbar.close()
|
pbar.close()
|
||||||
|
|
||||||
def build_components(self):
|
def build_components(self):
|
||||||
# Build the model, i.e. set the material properties (ID) for every edge
|
# Build the model, i.e. set the material properties (ID) for every edge
|
||||||
# of every Yee cell
|
# of every Yee cell
|
||||||
self.printer.print('')
|
self.printer.print('')
|
||||||
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.general['progressbars'])
|
||||||
build_electric_components(self.grid.solid, self.grid.rigidE, self.grid.ID, self.grid)
|
build_electric_components(self.grid.solid, self.grid.rigidE, self.grid.ID, self.grid)
|
||||||
pbar.update()
|
pbar.update()
|
||||||
build_magnetic_components(self.grid.solid, self.grid.rigidH, self.grid.ID, self.grid)
|
build_magnetic_components(self.grid.solid, self.grid.rigidH, self.grid.ID, self.grid)
|
||||||
pbar.update()
|
pbar.update()
|
||||||
pbar.close()
|
pbar.close()
|
||||||
|
|
||||||
def tm_grid_update(self):
|
def tm_grid_update(self):
|
||||||
if '2D TMx' == config.general['mode']:
|
if '2D TMx' == config.general['mode']:
|
||||||
self.grid.tmx()
|
self.grid.tmx()
|
||||||
elif '2D TMy' == config.general['mode']:
|
elif '2D TMy' == config.general['mode']:
|
||||||
self.grid.tmy()
|
self.grid.tmy()
|
||||||
elif '2D TMz' == config.general['mode']:
|
elif '2D TMz' == config.general['mode']:
|
||||||
self.grid.tmz()
|
self.grid.tmz()
|
||||||
|
|
||||||
def update_voltage_source_materials(self):
|
def update_voltage_source_materials(self):
|
||||||
# Process any voltage sources (that have resistance) to create a new
|
# Process any voltage sources (that have resistance) to create a new
|
||||||
# material at the source location
|
# material at the source location
|
||||||
for voltagesource in self.grid.voltagesources:
|
for voltagesource in self.grid.voltagesources:
|
||||||
voltagesource.create_material(self.grid)
|
voltagesource.create_material(self.grid)
|
||||||
|
|
||||||
def build_materials(self):
|
def build_materials(self):
|
||||||
# Process complete list of materials - calculate update coefficients,
|
# 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
|
||||||
materialsdata = process_materials(self.grid)
|
materialsdata = process_materials(self.grid)
|
||||||
materialstable = SingleTable(materialsdata)
|
materialstable = SingleTable(materialsdata)
|
||||||
materialstable.outer_border = False
|
materialstable.outer_border = False
|
||||||
materialstable.justify_columns[0] = 'right'
|
materialstable.justify_columns[0] = 'right'
|
||||||
|
|
||||||
self.printer.print('\n{} Grid Materials:'.format(self.grid.name))
|
self.printer.print('\n{} Grid Materials:'.format(self.grid.name))
|
||||||
self.printer.print(materialstable.table)
|
self.printer.print(materialstable.table)
|
||||||
|
242
gprMax/scene.py
242
gprMax/scene.py
@@ -1,121 +1,121 @@
|
|||||||
from .user_inputs import create_user_input_points
|
from .user_inputs import create_user_input_points
|
||||||
from .materials import create_built_in_materials
|
from .materials import create_built_in_materials
|
||||||
from .cmds_single_use import UserObjectSingle
|
from .cmds_single_use import UserObjectSingle
|
||||||
from .cmds_single_use import DomainSingle
|
from .cmds_single_use import DomainSingle
|
||||||
from .cmds_single_use import Discretisation
|
from .cmds_single_use import Discretisation
|
||||||
from .cmds_single_use import TimeWindow
|
from .cmds_single_use import TimeWindow
|
||||||
from .cmds_multiple import UserObjectMulti
|
from .cmds_multiple import UserObjectMulti
|
||||||
from .subgrids.user_objects import SubGridBase as SubGridUserBase
|
from .subgrids.user_objects import SubGridBase as SubGridUserBase
|
||||||
from .cmds_geometry.cmds_geometry import UserObjectGeometry
|
from .cmds_geometry.cmds_geometry import UserObjectGeometry
|
||||||
from .exceptions import CmdInputError
|
from .exceptions import CmdInputError
|
||||||
from .cmds_geometry.fractal_box_builder import FractalBoxBuilder
|
from .cmds_geometry.fractal_box_builder import FractalBoxBuilder
|
||||||
from .utilities import human_size
|
from .utilities import human_size
|
||||||
|
|
||||||
|
|
||||||
class Scene:
|
class Scene:
|
||||||
|
|
||||||
"""Scene stores all of the user created objects
|
"""Scene stores all of the user created objects
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.multiple_cmds = []
|
self.multiple_cmds = []
|
||||||
self.single_cmds = []
|
self.single_cmds = []
|
||||||
self.geometry_cmds = []
|
self.geometry_cmds = []
|
||||||
self.essential_cmds = [DomainSingle, TimeWindow, Discretisation]
|
self.essential_cmds = [DomainSingle, TimeWindow, Discretisation]
|
||||||
|
|
||||||
# fractal box commands have an additional nonuser object which
|
# fractal box commands have an additional nonuser object which
|
||||||
# process modifications
|
# process modifications
|
||||||
fbb = FractalBoxBuilder()
|
fbb = FractalBoxBuilder()
|
||||||
self.add(fbb)
|
self.add(fbb)
|
||||||
|
|
||||||
def add(self, node):
|
def add(self, node):
|
||||||
if isinstance(node, UserObjectMulti):
|
if isinstance(node, UserObjectMulti):
|
||||||
self.multiple_cmds.append(node)
|
self.multiple_cmds.append(node)
|
||||||
elif isinstance(node, UserObjectGeometry):
|
elif isinstance(node, UserObjectGeometry):
|
||||||
self.geometry_cmds.append(node)
|
self.geometry_cmds.append(node)
|
||||||
elif isinstance(node, UserObjectSingle):
|
elif isinstance(node, UserObjectSingle):
|
||||||
self.single_cmds.append(node)
|
self.single_cmds.append(node)
|
||||||
else:
|
else:
|
||||||
raise Exception('This Object is Unknown to gprMax')
|
raise Exception('This Object is Unknown to gprMax')
|
||||||
|
|
||||||
def process_subgrid_commands(self, subgrids):
|
def process_subgrid_commands(self, subgrids):
|
||||||
|
|
||||||
# check for subgrid user objects
|
# check for subgrid user objects
|
||||||
def func(obj):
|
def func(obj):
|
||||||
if isinstance(obj, SubGridUserBase):
|
if isinstance(obj, SubGridUserBase):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# subgrid user objects
|
# subgrid user objects
|
||||||
subgrid_cmds = list(filter(func, self.multiple_cmds))
|
subgrid_cmds = list(filter(func, self.multiple_cmds))
|
||||||
|
|
||||||
# iterate through the user command objects under the subgrid user object
|
# iterate through the user command objects under the subgrid user object
|
||||||
for sg_cmd in subgrid_cmds:
|
for sg_cmd in subgrid_cmds:
|
||||||
# when the subgrid is created its reference is attached to its user
|
# when the subgrid is created its reference is attached to its user
|
||||||
# object. this reference allows the multi and geo user objects
|
# object. this reference allows the multi and geo user objects
|
||||||
# to build in the correct subgrid.
|
# to build in the correct subgrid.
|
||||||
sg = sg_cmd.subgrid
|
sg = sg_cmd.subgrid
|
||||||
self.process_cmds(sg_cmd.children_multiple, sg)
|
self.process_cmds(sg_cmd.children_multiple, sg)
|
||||||
self.process_cmds(sg_cmd.children_geometry, sg)
|
self.process_cmds(sg_cmd.children_geometry, sg)
|
||||||
|
|
||||||
def process_cmds(self, commands, grid):
|
def process_cmds(self, commands, grid):
|
||||||
cmds_sorted = sorted(commands, key=lambda cmd: cmd.order)
|
cmds_sorted = sorted(commands, key=lambda cmd: cmd.order)
|
||||||
for obj in cmds_sorted:
|
for obj in cmds_sorted:
|
||||||
# in the first level all objects belong to the main grid
|
# in the first level all objects belong to the main grid
|
||||||
uip = create_user_input_points(grid)
|
uip = create_user_input_points(grid)
|
||||||
# Create an instance to check the geometry points provided by the
|
# Create an instance to check the geometry points provided by the
|
||||||
# user. The way the point are checked depends on which grid the
|
# user. The way the point are checked depends on which grid the
|
||||||
# points belong to.
|
# points belong to.
|
||||||
obj.create(grid, uip)
|
obj.create(grid, uip)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def process_singlecmds(self, G):
|
def process_singlecmds(self, G):
|
||||||
|
|
||||||
# check for duplicate commands and warn user if they exist
|
# check for duplicate commands and warn user if they exist
|
||||||
cmds_unique = list(set(self.single_cmds))
|
cmds_unique = list(set(self.single_cmds))
|
||||||
if len(cmds_unique) != len(self.single_cmds):
|
if len(cmds_unique) != len(self.single_cmds):
|
||||||
raise CmdInputError('Duplicate Single Commands exist in the input.')
|
raise CmdInputError('Duplicate Single Commands exist in the input.')
|
||||||
|
|
||||||
# check essential cmds and warn user if missing
|
# check essential cmds and warn user if missing
|
||||||
for cmd_type in self.essential_cmds:
|
for cmd_type in self.essential_cmds:
|
||||||
d = any([isinstance(cmd, cmd_type) for cmd in cmds_unique])
|
d = any([isinstance(cmd, cmd_type) for cmd in cmds_unique])
|
||||||
if not d:
|
if not d:
|
||||||
raise CmdInputError('Your input file is missing essential commands required to run a model. Essential commands are: Domain, Discretisation, Time Window')
|
raise CmdInputError('Your input file is missing essential commands required to run a model. Essential commands are: Domain, Discretisation, Time Window')
|
||||||
|
|
||||||
self.process_cmds(cmds_unique, G)
|
self.process_cmds(cmds_unique, G)
|
||||||
|
|
||||||
|
|
||||||
def create_internal_objects(self, G):
|
def create_internal_objects(self, G):
|
||||||
|
|
||||||
# gprMax API presents the user with UserObjects in order to build
|
# gprMax API presents the user with UserObjects in order to build
|
||||||
# the internal Rx(), Cylinder() etc... objects. This function
|
# the internal Rx(), Cylinder() etc... objects. This function
|
||||||
# essentially calls the UserObject.create() function in the correct
|
# essentially calls the UserObject.create() function in the correct
|
||||||
# way
|
# way
|
||||||
|
|
||||||
# Traverse all the user objects in the correct order and create them.
|
# Traverse all the user objects in the correct order and create them.
|
||||||
create_built_in_materials(G)
|
create_built_in_materials(G)
|
||||||
|
|
||||||
# process commands that can onlyhave a single instance
|
# process commands that can onlyhave a single instance
|
||||||
self.process_singlecmds(G)
|
self.process_singlecmds(G)
|
||||||
|
|
||||||
# Process main grid multiple commands
|
# Process main grid multiple commands
|
||||||
self.process_cmds(self.multiple_cmds, G)
|
self.process_cmds(self.multiple_cmds, G)
|
||||||
|
|
||||||
# Estimate and check memory (RAM) usage
|
# Estimate and check memory (RAM) usage
|
||||||
G.memory_check()
|
G.memory_check()
|
||||||
#snapshot_memory_check(G)
|
#snapshot_memory_check(G)
|
||||||
|
|
||||||
# Initialise an array for volumetric material IDs (solid), boolean
|
# Initialise an array for volumetric material IDs (solid), boolean
|
||||||
# arrays for specifying materials not to be averaged (rigid),
|
# arrays for specifying materials not to be averaged (rigid),
|
||||||
# an array for cell edge IDs (ID)
|
# an array for cell edge IDs (ID)
|
||||||
G.initialise_grids()
|
G.initialise_grids()
|
||||||
|
|
||||||
# Process the main grid geometry commands
|
# Process the main grid geometry commands
|
||||||
self.process_cmds(self.geometry_cmds, G)
|
self.process_cmds(self.geometry_cmds, G)
|
||||||
|
|
||||||
# Process all the commands for the subgrid
|
# Process all the commands for the subgrid
|
||||||
self.process_subgrid_commands(G.subgrids)
|
self.process_subgrid_commands(G.subgrids)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
@@ -1,93 +1,96 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
from gprMax.updates import CPUUpdates
|
from gprMax.updates import CPUUpdates
|
||||||
from gprMax.updates import GPUUpdates
|
from gprMax.updates import GPUUpdates
|
||||||
from gprMax.utilities import timer
|
from .subgrids.updates import create_updates as create_subgrid_updates
|
||||||
from .grid import FDTDGrid
|
from gprMax.utilities import timer
|
||||||
from .grid import GPUGrid
|
from .grid import FDTDGrid
|
||||||
import gprMax.config as config
|
from .grid import GPUGrid
|
||||||
from .subgrids.solver import create_updates as create_subgrid_updates
|
import gprMax.config as config
|
||||||
from .subgrids.solver import SubGridSolver
|
|
||||||
|
|
||||||
|
def create_G(sim_config):
|
||||||
def create_G(sim_config):
|
"""Returns the configured solver."""
|
||||||
"""Returns the configured solver."""
|
if sim_config.gpu:
|
||||||
if sim_config.gpu:
|
G = GPUGrid()
|
||||||
G = GPUGrid()
|
elif sim_config.subgrid:
|
||||||
elif sim_config.subgrid:
|
G = FDTDGrid()
|
||||||
G = FDTDGrid()
|
else:
|
||||||
else:
|
G = FDTDGrid()
|
||||||
G = FDTDGrid()
|
|
||||||
|
return G
|
||||||
return G
|
|
||||||
|
|
||||||
|
def create_solver(G, sim_config):
|
||||||
def create_solver(G, sim_config):
|
"""Returns the configured solver."""
|
||||||
"""Returns the configured solver."""
|
if sim_config.gpu:
|
||||||
if sim_config.gpu:
|
updates = GPUUpdates(G)
|
||||||
updates = GPUUpdates(G)
|
solver = Solver(updates)
|
||||||
solver = Solver(updates)
|
elif sim_config.subgrid:
|
||||||
elif sim_config.subgrid:
|
updates = create_subgrid_updates(G)
|
||||||
updates = create_subgrid_updates(G)
|
solver = Solver(updates, hsg=True)
|
||||||
solver = SubGridSolver(G, updates)
|
else:
|
||||||
else:
|
updates = CPUUpdates(G)
|
||||||
updates = CPUUpdates(G)
|
solver = Solver(updates)
|
||||||
solver = Solver(updates)
|
# a large range of function exist to advance the time step for dispersive
|
||||||
# a large range of function exist to advance the time step for dispersive
|
# materials. The correct function is set here based on the
|
||||||
# materials. The correct function is set here based on the
|
# the required numerical precision and dispersive material type.
|
||||||
# the required numerical precision and dispersive material type.
|
props = updates.adapt_dispersive_config(config)
|
||||||
props = updates.adapt_dispersive_config(config)
|
updates.set_dispersive_updates(props)
|
||||||
updates.set_dispersive_updates(props)
|
return solver
|
||||||
return solver
|
|
||||||
|
|
||||||
|
|
||||||
|
class Solver:
|
||||||
class Solver:
|
|
||||||
|
"""Generic solver for Update objects"""
|
||||||
"""Generic solver for Update objects"""
|
|
||||||
|
def __init__(self, updates, hsg=False):
|
||||||
def __init__(self, updates):
|
"""Context for the model to run in. Sub-class this with contexts
|
||||||
"""Context for the model to run in. Sub-class this with contexts
|
i.e. an MPI context.
|
||||||
i.e. an MPI context.
|
|
||||||
|
Args:
|
||||||
Args:
|
updates (Updates): updates contains methods to run FDTD algorithm
|
||||||
updates (Updates): updates contains methods to run FDTD algorithm
|
iterator (iterator): can be range() or tqdm()
|
||||||
iterator (iterator): can be range() or tqdm()
|
"""
|
||||||
"""
|
self.updates = updates
|
||||||
self.updates = updates
|
self.hsg = hsg
|
||||||
|
|
||||||
def get_G(self):
|
def get_G(self):
|
||||||
return self.updates.G
|
return self.updates.G
|
||||||
|
|
||||||
def solve(self, iterator):
|
def solve(self, iterator):
|
||||||
"""Time step the FDTD model."""
|
"""Time step the FDTD model."""
|
||||||
tsolvestart = timer()
|
tsolvestart = timer()
|
||||||
for iteration in iterator:
|
for iteration in iterator:
|
||||||
self.updates.grid.iteration = iteration
|
self.updates.store_outputs()
|
||||||
self.updates.store_outputs()
|
self.updates.store_snapshots(iteration)
|
||||||
self.updates.store_snapshots(iteration)
|
self.updates.update_magnetic()
|
||||||
self.updates.update_magnetic()
|
self.updates.update_magnetic_pml()
|
||||||
self.updates.update_magnetic_pml()
|
self.updates.update_magnetic_sources()
|
||||||
self.updates.update_magnetic_sources(iteration)
|
if self.hsg:
|
||||||
self.updates.update_electric_a()
|
self.updates.hsg_2()
|
||||||
self.updates.update_electric_pml()
|
self.updates.update_electric_a()
|
||||||
self.updates.update_electric_sources(iteration)
|
self.updates.update_electric_pml()
|
||||||
self.updates.update_electric_b()
|
self.updates.update_electric_sources()
|
||||||
|
if self.hsg:
|
||||||
tsolve = timer() - tsolvestart
|
self.updates.hsg_1()
|
||||||
return tsolve
|
self.updates.update_electric_b()
|
||||||
|
|
||||||
|
tsolve = timer() - tsolvestart
|
||||||
|
return tsolve
|
||||||
|
@@ -1,413 +1,413 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import gprMax.config as config
|
import gprMax.config as config
|
||||||
from .grid import Ix
|
from .grid import Ix
|
||||||
from .grid import Iy
|
from .grid import Iy
|
||||||
from .grid import Iz
|
from .grid import Iz
|
||||||
from .utilities import round_value
|
from .utilities import round_value
|
||||||
|
|
||||||
|
|
||||||
class Source(object):
|
class Source(object):
|
||||||
"""Super-class which describes a generic source."""
|
"""Super-class which describes a generic source."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.ID = None
|
self.ID = None
|
||||||
self.polarisation = None
|
self.polarisation = None
|
||||||
self.xcoord = None
|
self.xcoord = None
|
||||||
self.ycoord = None
|
self.ycoord = None
|
||||||
self.zcoord = None
|
self.zcoord = None
|
||||||
self.xcoordorigin = None
|
self.xcoordorigin = None
|
||||||
self.ycoordorigin = None
|
self.ycoordorigin = None
|
||||||
self.zcoordorigin = None
|
self.zcoordorigin = None
|
||||||
self.start = None
|
self.start = None
|
||||||
self.stop = None
|
self.stop = None
|
||||||
self.waveformID = None
|
self.waveformID = None
|
||||||
|
|
||||||
def calculate_waveform_values(self, G):
|
def calculate_waveform_values(self, G):
|
||||||
"""Calculates all waveform values for source for duration of simulation.
|
"""Calculates all waveform values for source for duration of simulation.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
# Waveform values for electric sources - calculated half a timestep later
|
# Waveform values for electric sources - calculated half a timestep later
|
||||||
self.waveformvaluesJ = np.zeros((G.iterations), dtype=config.dtypes['float_or_double'])
|
self.waveformvaluesJ = np.zeros((G.iterations), dtype=config.dtypes['float_or_double'])
|
||||||
|
|
||||||
# Waveform values for magnetic sources
|
# Waveform values for magnetic sources
|
||||||
self.waveformvaluesM = np.zeros((G.iterations), dtype=config.dtypes['float_or_double'])
|
self.waveformvaluesM = np.zeros((G.iterations), dtype=config.dtypes['float_or_double'])
|
||||||
|
|
||||||
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
|
waveform = next(x for x in G.waveforms if x.ID == self.waveformID)
|
||||||
|
|
||||||
for iteration in range(G.iterations):
|
for iteration in range(G.iterations):
|
||||||
time = G.dt * iteration
|
time = G.dt * iteration
|
||||||
if time >= self.start and time <= self.stop:
|
if time >= self.start and time <= self.stop:
|
||||||
# Set the time of the waveform evaluation to account for any delay in the start
|
# Set the time of the waveform evaluation to account for any delay in the start
|
||||||
time -= self.start
|
time -= self.start
|
||||||
self.waveformvaluesJ[iteration] = waveform.calculate_value(time + 0.5 * G.dt, G.dt)
|
self.waveformvaluesJ[iteration] = waveform.calculate_value(time + 0.5 * G.dt, G.dt)
|
||||||
self.waveformvaluesM[iteration] = waveform.calculate_value(time, G.dt)
|
self.waveformvaluesM[iteration] = waveform.calculate_value(time, G.dt)
|
||||||
|
|
||||||
|
|
||||||
class VoltageSource(Source):
|
class VoltageSource(Source):
|
||||||
"""
|
"""
|
||||||
A voltage source can be a hard source if it's resistance is zero, i.e. the
|
A voltage source can be a hard source if it's resistance is zero, i.e. the
|
||||||
time variation of the specified electric field component is prescribed.
|
time variation of the specified electric field component is prescribed.
|
||||||
If it's resistance is non-zero it behaves as a resistive voltage source.
|
If it's resistance is non-zero it behaves as a resistive voltage source.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.resistance = None
|
self.resistance = None
|
||||||
|
|
||||||
def update_electric(self, iteration, updatecoeffsE, ID, Ex, Ey, Ez, G):
|
def update_electric(self, iteration, updatecoeffsE, ID, Ex, Ey, Ez, G):
|
||||||
"""Updates electric field values for a voltage source.
|
"""Updates electric field values for a voltage source.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
iteration (int): Current iteration (timestep).
|
iteration (int): Current iteration (timestep).
|
||||||
updatecoeffsE (memory view): numpy array of electric field update coefficients.
|
updatecoeffsE (memory view): numpy array of electric field update coefficients.
|
||||||
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
||||||
Ex, Ey, Ez (memory view): numpy array of electric field values.
|
Ex, Ey, Ez (memory view): numpy array of electric field values.
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if iteration * G.dt >= self.start and iteration * G.dt <= self.stop:
|
if iteration * G.dt >= self.start and iteration * G.dt <= self.stop:
|
||||||
i = self.xcoord
|
i = self.xcoord
|
||||||
j = self.ycoord
|
j = self.ycoord
|
||||||
k = self.zcoord
|
k = self.zcoord
|
||||||
componentID = 'E' + self.polarisation
|
componentID = 'E' + self.polarisation
|
||||||
|
|
||||||
if self.polarisation == 'x':
|
if self.polarisation == 'x':
|
||||||
if self.resistance != 0:
|
if self.resistance != 0:
|
||||||
Ex[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * (1 / (self.resistance * G.dy * G.dz))
|
Ex[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * (1 / (self.resistance * G.dy * G.dz))
|
||||||
else:
|
else:
|
||||||
Ex[i, j, k] = -1 * self.waveformvaluesJ[iteration] / G.dx
|
Ex[i, j, k] = -1 * self.waveformvaluesJ[iteration] / G.dx
|
||||||
|
|
||||||
elif self.polarisation == 'y':
|
elif self.polarisation == 'y':
|
||||||
if self.resistance != 0:
|
if self.resistance != 0:
|
||||||
Ey[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * (1 / (self.resistance * G.dx * G.dz))
|
Ey[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * (1 / (self.resistance * G.dx * G.dz))
|
||||||
else:
|
else:
|
||||||
Ey[i, j, k] = -1 * self.waveformvaluesJ[iteration] / G.dy
|
Ey[i, j, k] = -1 * self.waveformvaluesJ[iteration] / G.dy
|
||||||
|
|
||||||
elif self.polarisation == 'z':
|
elif self.polarisation == 'z':
|
||||||
if self.resistance != 0:
|
if self.resistance != 0:
|
||||||
Ez[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * (1 / (self.resistance * G.dx * G.dy))
|
Ez[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * (1 / (self.resistance * G.dx * G.dy))
|
||||||
else:
|
else:
|
||||||
Ez[i, j, k] = -1 * self.waveformvaluesJ[iteration] / G.dz
|
Ez[i, j, k] = -1 * self.waveformvaluesJ[iteration] / G.dz
|
||||||
|
|
||||||
def create_material(self, G):
|
def create_material(self, G):
|
||||||
"""Create a new material at the voltage source location that adds the
|
"""Create a new material at the voltage source location that adds the
|
||||||
voltage source conductivity to the underlying parameters.
|
voltage source conductivity to the underlying parameters.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.resistance != 0:
|
if self.resistance != 0:
|
||||||
i = self.xcoord
|
i = self.xcoord
|
||||||
j = self.ycoord
|
j = self.ycoord
|
||||||
k = self.zcoord
|
k = self.zcoord
|
||||||
|
|
||||||
componentID = 'E' + self.polarisation
|
componentID = 'E' + self.polarisation
|
||||||
requirednumID = G.ID[G.IDlookup[componentID], i, j, k]
|
requirednumID = G.ID[G.IDlookup[componentID], i, j, k]
|
||||||
material = next(x for x in G.materials if x.numID == requirednumID)
|
material = next(x for x in G.materials if x.numID == requirednumID)
|
||||||
newmaterial = deepcopy(material)
|
newmaterial = deepcopy(material)
|
||||||
newmaterial.ID = material.ID + '+' + self.ID
|
newmaterial.ID = material.ID + '+' + self.ID
|
||||||
newmaterial.numID = len(G.materials)
|
newmaterial.numID = len(G.materials)
|
||||||
newmaterial.averagable = False
|
newmaterial.averagable = False
|
||||||
newmaterial.type += ',\nvoltage-source'
|
newmaterial.type += ',\nvoltage-source'
|
||||||
|
|
||||||
# Add conductivity of voltage source to underlying conductivity
|
# Add conductivity of voltage source to underlying conductivity
|
||||||
if self.polarisation == 'x':
|
if self.polarisation == 'x':
|
||||||
newmaterial.se += G.dx / (self.resistance * G.dy * G.dz)
|
newmaterial.se += G.dx / (self.resistance * G.dy * G.dz)
|
||||||
elif self.polarisation == 'y':
|
elif self.polarisation == 'y':
|
||||||
newmaterial.se += G.dy / (self.resistance * G.dx * G.dz)
|
newmaterial.se += G.dy / (self.resistance * G.dx * G.dz)
|
||||||
elif self.polarisation == 'z':
|
elif self.polarisation == 'z':
|
||||||
newmaterial.se += G.dz / (self.resistance * G.dx * G.dy)
|
newmaterial.se += G.dz / (self.resistance * G.dx * G.dy)
|
||||||
|
|
||||||
G.ID[G.IDlookup[componentID], i, j, k] = newmaterial.numID
|
G.ID[G.IDlookup[componentID], i, j, k] = newmaterial.numID
|
||||||
G.materials.append(newmaterial)
|
G.materials.append(newmaterial)
|
||||||
|
|
||||||
|
|
||||||
class HertzianDipole(Source):
|
class HertzianDipole(Source):
|
||||||
"""A Hertzian dipole is an additive source (electric current density)."""
|
"""A Hertzian dipole is an additive source (electric current density)."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.dl = None
|
self.dl = None
|
||||||
|
|
||||||
def update_electric(self, iteration, updatecoeffsE, ID, Ex, Ey, Ez, G):
|
def update_electric(self, iteration, updatecoeffsE, ID, Ex, Ey, Ez, G):
|
||||||
"""Updates electric field values for a Hertzian dipole.
|
"""Updates electric field values for a Hertzian dipole.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
iteration (int): Current iteration (timestep).
|
iteration (int): Current iteration (timestep).
|
||||||
updatecoeffsE (memory view): numpy array of electric field update coefficients.
|
updatecoeffsE (memory view): numpy array of electric field update coefficients.
|
||||||
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
||||||
Ex, Ey, Ez (memory view): numpy array of electric field values.
|
Ex, Ey, Ez (memory view): numpy array of electric field values.
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if iteration * G.dt >= self.start and iteration * G.dt <= self.stop:
|
if iteration * G.dt >= self.start and iteration * G.dt <= self.stop:
|
||||||
i = self.xcoord
|
i = self.xcoord
|
||||||
j = self.ycoord
|
j = self.ycoord
|
||||||
k = self.zcoord
|
k = self.zcoord
|
||||||
componentID = 'E' + self.polarisation
|
componentID = 'E' + self.polarisation
|
||||||
if self.polarisation == 'x':
|
if self.polarisation == 'x':
|
||||||
Ex[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * self.dl * (1 / (G.dx * G.dy * G.dz))
|
Ex[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * self.dl * (1 / (G.dx * G.dy * G.dz))
|
||||||
|
|
||||||
elif self.polarisation == 'y':
|
elif self.polarisation == 'y':
|
||||||
Ey[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * self.dl * (1 / (G.dx * G.dy * G.dz))
|
Ey[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * self.dl * (1 / (G.dx * G.dy * G.dz))
|
||||||
|
|
||||||
elif self.polarisation == 'z':
|
elif self.polarisation == 'z':
|
||||||
Ez[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * self.dl * (1 / (G.dx * G.dy * G.dz))
|
Ez[i, j, k] -= updatecoeffsE[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesJ[iteration] * self.dl * (1 / (G.dx * G.dy * G.dz))
|
||||||
|
|
||||||
|
|
||||||
class MagneticDipole(Source):
|
class MagneticDipole(Source):
|
||||||
"""A magnetic dipole is an additive source (magnetic current density)."""
|
"""A magnetic dipole is an additive source (magnetic current density)."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def update_magnetic(self, iteration, updatecoeffsH, ID, Hx, Hy, Hz, G):
|
def update_magnetic(self, iteration, updatecoeffsH, ID, Hx, Hy, Hz, G):
|
||||||
"""Updates magnetic field values for a magnetic dipole.
|
"""Updates magnetic field values for a magnetic dipole.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
iteration (int): Current iteration (timestep).
|
iteration (int): Current iteration (timestep).
|
||||||
updatecoeffsH (memory view): numpy array of magnetic field update coefficients.
|
updatecoeffsH (memory view): numpy array of magnetic field update coefficients.
|
||||||
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
||||||
Hx, Hy, Hz (memory view): numpy array of magnetic field values.
|
Hx, Hy, Hz (memory view): numpy array of magnetic field values.
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if iteration * G.dt >= self.start and iteration * G.dt <= self.stop:
|
if iteration * G.dt >= self.start and iteration * G.dt <= self.stop:
|
||||||
i = self.xcoord
|
i = self.xcoord
|
||||||
j = self.ycoord
|
j = self.ycoord
|
||||||
k = self.zcoord
|
k = self.zcoord
|
||||||
componentID = 'H' + self.polarisation
|
componentID = 'H' + self.polarisation
|
||||||
|
|
||||||
if self.polarisation == 'x':
|
if self.polarisation == 'x':
|
||||||
Hx[i, j, k] -= updatecoeffsH[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesM[iteration] * (1 / (G.dx * G.dy * G.dz))
|
Hx[i, j, k] -= updatecoeffsH[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesM[iteration] * (1 / (G.dx * G.dy * G.dz))
|
||||||
|
|
||||||
elif self.polarisation == 'y':
|
elif self.polarisation == 'y':
|
||||||
Hy[i, j, k] -= updatecoeffsH[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesM[iteration] * (1 / (G.dx * G.dy * G.dz))
|
Hy[i, j, k] -= updatecoeffsH[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesM[iteration] * (1 / (G.dx * G.dy * G.dz))
|
||||||
|
|
||||||
elif self.polarisation == 'z':
|
elif self.polarisation == 'z':
|
||||||
Hz[i, j, k] -= updatecoeffsH[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesM[iteration] * (1 / (G.dx * G.dy * G.dz))
|
Hz[i, j, k] -= updatecoeffsH[ID[G.IDlookup[componentID], i, j, k], 4] * self.waveformvaluesM[iteration] * (1 / (G.dx * G.dy * G.dz))
|
||||||
|
|
||||||
|
|
||||||
def gpu_initialise_src_arrays(sources, G):
|
def gpu_initialise_src_arrays(sources, G):
|
||||||
"""Initialise arrays on GPU for source coordinates/polarisation, other source information, and source waveform values.
|
"""Initialise arrays on GPU for source coordinates/polarisation, other source information, and source waveform values.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources (list): List of sources of one class, e.g. HertzianDipoles.
|
sources (list): List of sources of one class, e.g. HertzianDipoles.
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
srcinfo1_gpu (int): numpy array of source cell coordinates and polarisation information.
|
srcinfo1_gpu (int): numpy array of source cell coordinates and polarisation information.
|
||||||
srcinfo2_gpu (float): numpy array of other source information, e.g. length, resistance etc...
|
srcinfo2_gpu (float): numpy array of other source information, e.g. length, resistance etc...
|
||||||
srcwaves_gpu (float): numpy array of source waveform values.
|
srcwaves_gpu (float): numpy array of source waveform values.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import pycuda.gpuarray as gpuarray
|
import pycuda.gpuarray as gpuarray
|
||||||
|
|
||||||
srcinfo1 = np.zeros((len(sources), 4), dtype=np.int32)
|
srcinfo1 = np.zeros((len(sources), 4), dtype=np.int32)
|
||||||
srcinfo2 = np.zeros((len(sources)), dtype=config.dtypes['float_or_double'])
|
srcinfo2 = np.zeros((len(sources)), dtype=config.dtypes['float_or_double'])
|
||||||
srcwaves = np.zeros((len(sources), G.iterations), dtype=config.dtypes['float_or_double'])
|
srcwaves = np.zeros((len(sources), G.iterations), dtype=config.dtypes['float_or_double'])
|
||||||
for i, src in enumerate(sources):
|
for i, src in enumerate(sources):
|
||||||
srcinfo1[i, 0] = src.xcoord
|
srcinfo1[i, 0] = src.xcoord
|
||||||
srcinfo1[i, 1] = src.ycoord
|
srcinfo1[i, 1] = src.ycoord
|
||||||
srcinfo1[i, 2] = src.zcoord
|
srcinfo1[i, 2] = src.zcoord
|
||||||
|
|
||||||
if src.polarisation == 'x':
|
if src.polarisation == 'x':
|
||||||
srcinfo1[i, 3] = 0
|
srcinfo1[i, 3] = 0
|
||||||
elif src.polarisation == 'y':
|
elif src.polarisation == 'y':
|
||||||
srcinfo1[i, 3] = 1
|
srcinfo1[i, 3] = 1
|
||||||
elif src.polarisation == 'z':
|
elif src.polarisation == 'z':
|
||||||
srcinfo1[i, 3] = 2
|
srcinfo1[i, 3] = 2
|
||||||
|
|
||||||
if src.__class__.__name__ == 'HertzianDipole':
|
if src.__class__.__name__ == 'HertzianDipole':
|
||||||
srcinfo2[i] = src.dl
|
srcinfo2[i] = src.dl
|
||||||
srcwaves[i, :] = src.waveformvaluesJ
|
srcwaves[i, :] = src.waveformvaluesJ
|
||||||
elif src.__class__.__name__ == 'VoltageSource':
|
elif src.__class__.__name__ == 'VoltageSource':
|
||||||
srcinfo2[i] = src.resistance
|
srcinfo2[i] = src.resistance
|
||||||
srcwaves[i, :] = src.waveformvaluesJ
|
srcwaves[i, :] = src.waveformvaluesJ
|
||||||
elif src.__class__.__name__ == 'MagneticDipole':
|
elif src.__class__.__name__ == 'MagneticDipole':
|
||||||
srcwaves[i, :] = src.waveformvaluesM
|
srcwaves[i, :] = src.waveformvaluesM
|
||||||
|
|
||||||
srcinfo1_gpu = gpuarray.to_gpu(srcinfo1)
|
srcinfo1_gpu = gpuarray.to_gpu(srcinfo1)
|
||||||
srcinfo2_gpu = gpuarray.to_gpu(srcinfo2)
|
srcinfo2_gpu = gpuarray.to_gpu(srcinfo2)
|
||||||
srcwaves_gpu = gpuarray.to_gpu(srcwaves)
|
srcwaves_gpu = gpuarray.to_gpu(srcwaves)
|
||||||
|
|
||||||
return srcinfo1_gpu, srcinfo2_gpu, srcwaves_gpu
|
return srcinfo1_gpu, srcinfo2_gpu, srcwaves_gpu
|
||||||
|
|
||||||
|
|
||||||
class TransmissionLine(Source):
|
class TransmissionLine(Source):
|
||||||
"""A transmission line source is a one-dimensional transmission line
|
"""A transmission line source is a one-dimensional transmission line
|
||||||
which is attached virtually to a grid cell.
|
which is attached virtually to a grid cell.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, G):
|
def __init__(self, G):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.resistance = None
|
self.resistance = None
|
||||||
|
|
||||||
# Coefficients for ABC termination of end of the transmission line
|
# Coefficients for ABC termination of end of the transmission line
|
||||||
self.abcv0 = 0
|
self.abcv0 = 0
|
||||||
self.abcv1 = 0
|
self.abcv1 = 0
|
||||||
|
|
||||||
# Spatial step of transmission line (N.B if the magic time step is
|
# Spatial step of transmission line (N.B if the magic time step is
|
||||||
# used it results in instabilities for certain impedances)
|
# used it results in instabilities for certain impedances)
|
||||||
self.dl = np.sqrt(3) * config.c * G.dt
|
self.dl = np.sqrt(3) * config.c * G.dt
|
||||||
|
|
||||||
# Number of cells in the transmission line (initially a long line to
|
# Number of cells in the transmission line (initially a long line to
|
||||||
# calculate incident voltage and current); consider putting ABCs/PML at end
|
# calculate incident voltage and current); consider putting ABCs/PML at end
|
||||||
self.nl = round_value(0.667 * G.iterations)
|
self.nl = round_value(0.667 * G.iterations)
|
||||||
|
|
||||||
# Cell position of the one-way injector excitation in the transmission line
|
# Cell position of the one-way injector excitation in the transmission line
|
||||||
self.srcpos = 5
|
self.srcpos = 5
|
||||||
|
|
||||||
# Cell position of where line connects to antenna/main grid
|
# Cell position of where line connects to antenna/main grid
|
||||||
self.antpos = 10
|
self.antpos = 10
|
||||||
|
|
||||||
self.voltage = np.zeros(self.nl, dtype=config.dtypes['float_or_double'])
|
self.voltage = np.zeros(self.nl, dtype=config.dtypes['float_or_double'])
|
||||||
self.current = np.zeros(self.nl, dtype=config.dtypes['float_or_double'])
|
self.current = np.zeros(self.nl, dtype=config.dtypes['float_or_double'])
|
||||||
self.Vinc = np.zeros(G.iterations, dtype=config.dtypes['float_or_double'])
|
self.Vinc = np.zeros(G.iterations, dtype=config.dtypes['float_or_double'])
|
||||||
self.Iinc = np.zeros(G.iterations, dtype=config.dtypes['float_or_double'])
|
self.Iinc = np.zeros(G.iterations, dtype=config.dtypes['float_or_double'])
|
||||||
self.Vtotal = np.zeros(G.iterations, dtype=config.dtypes['float_or_double'])
|
self.Vtotal = np.zeros(G.iterations, dtype=config.dtypes['float_or_double'])
|
||||||
self.Itotal = np.zeros(G.iterations, dtype=config.dtypes['float_or_double'])
|
self.Itotal = np.zeros(G.iterations, dtype=config.dtypes['float_or_double'])
|
||||||
|
|
||||||
def calculate_incident_V_I(self, G):
|
def calculate_incident_V_I(self, G):
|
||||||
"""Calculates the incident voltage and current with a long length
|
"""Calculates the incident voltage and current with a long length
|
||||||
transmission line not connected to the main grid from: http://dx.doi.org/10.1002/mop.10415
|
transmission line not connected to the main grid from: http://dx.doi.org/10.1002/mop.10415
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for iteration in range(G.iterations):
|
for iteration in range(G.iterations):
|
||||||
self.Iinc[iteration] = self.current[self.antpos]
|
self.Iinc[iteration] = self.current[self.antpos]
|
||||||
self.Vinc[iteration] = self.voltage[self.antpos]
|
self.Vinc[iteration] = self.voltage[self.antpos]
|
||||||
self.update_current(iteration, G)
|
self.update_current(iteration, G)
|
||||||
self.update_voltage(iteration, G)
|
self.update_voltage(iteration, G)
|
||||||
|
|
||||||
# Shorten number of cells in the transmission line before use with main grid
|
# Shorten number of cells in the transmission line before use with main grid
|
||||||
self.nl = self.antpos + 1
|
self.nl = self.antpos + 1
|
||||||
|
|
||||||
def update_abc(self, G):
|
def update_abc(self, G):
|
||||||
"""Updates absorbing boundary condition at end of the transmission line.
|
"""Updates absorbing boundary condition at end of the transmission line.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
h = (config.c * G.dt - self.dl) / (config.c * G.dt + self.dl)
|
h = (config.c * G.dt - self.dl) / (config.c * G.dt + self.dl)
|
||||||
|
|
||||||
self.voltage[0] = h * (self.voltage[1] - self.abcv0) + self.abcv1
|
self.voltage[0] = h * (self.voltage[1] - self.abcv0) + self.abcv1
|
||||||
self.abcv0 = self.voltage[0]
|
self.abcv0 = self.voltage[0]
|
||||||
self.abcv1 = self.voltage[1]
|
self.abcv1 = self.voltage[1]
|
||||||
|
|
||||||
def update_voltage(self, iteration, G):
|
def update_voltage(self, iteration, G):
|
||||||
"""Updates voltage values along the transmission line.
|
"""Updates voltage values along the transmission line.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
iteration (int): Current iteration (timestep).
|
iteration (int): Current iteration (timestep).
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Update all the voltage values along the line
|
# Update all the voltage values along the line
|
||||||
self.voltage[1:self.nl] -= self.resistance * (config.c * G.dt / self.dl) * (self.current[1:self.nl] - self.current[0:self.nl - 1])
|
self.voltage[1:self.nl] -= self.resistance * (config.c * G.dt / self.dl) * (self.current[1:self.nl] - self.current[0:self.nl - 1])
|
||||||
|
|
||||||
# Update the voltage at the position of the one-way injector excitation
|
# Update the voltage at the position of the one-way injector excitation
|
||||||
self.voltage[self.srcpos] += (config.c * G.dt / self.dl) * self.waveformvaluesJ[iteration]
|
self.voltage[self.srcpos] += (config.c * G.dt / self.dl) * self.waveformvaluesJ[iteration]
|
||||||
|
|
||||||
# Update ABC before updating current
|
# Update ABC before updating current
|
||||||
self.update_abc(G)
|
self.update_abc(G)
|
||||||
|
|
||||||
def update_current(self, iteration, G):
|
def update_current(self, iteration, G):
|
||||||
"""Updates current values along the transmission line.
|
"""Updates current values along the transmission line.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
iteration (int): Current iteration (timestep).
|
iteration (int): Current iteration (timestep).
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Update all the current values along the line
|
# Update all the current values along the line
|
||||||
self.current[0:self.nl - 1] -= (1 / self.resistance) * (config.c * G.dt / self.dl) * (self.voltage[1:self.nl] - self.voltage[0:self.nl - 1])
|
self.current[0:self.nl - 1] -= (1 / self.resistance) * (config.c * G.dt / self.dl) * (self.voltage[1:self.nl] - self.voltage[0:self.nl - 1])
|
||||||
|
|
||||||
# Update the current one cell before the position of the one-way injector excitation
|
# Update the current one cell before the position of the one-way injector excitation
|
||||||
self.current[self.srcpos - 1] += (1 / self.resistance) * (config.c * G.dt / self.dl) * self.waveformvaluesM[iteration]
|
self.current[self.srcpos - 1] += (1 / self.resistance) * (config.c * G.dt / self.dl) * self.waveformvaluesM[iteration]
|
||||||
|
|
||||||
def update_electric(self, iteration, updatecoeffsE, ID, Ex, Ey, Ez, G):
|
def update_electric(self, iteration, updatecoeffsE, ID, Ex, Ey, Ez, G):
|
||||||
"""Updates electric field value in the main grid from voltage value in the transmission line.
|
"""Updates electric field value in the main grid from voltage value in the transmission line.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
iteration (int): Current iteration (timestep).
|
iteration (int): Current iteration (timestep).
|
||||||
updatecoeffsE (memory view): numpy array of electric field update coefficients.
|
updatecoeffsE (memory view): numpy array of electric field update coefficients.
|
||||||
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
||||||
Ex, Ey, Ez (memory view): numpy array of electric field values.
|
Ex, Ey, Ez (memory view): numpy array of electric field values.
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if iteration * G.dt >= self.start and iteration * G.dt <= self.stop:
|
if iteration * G.dt >= self.start and iteration * G.dt <= self.stop:
|
||||||
i = self.xcoord
|
i = self.xcoord
|
||||||
j = self.ycoord
|
j = self.ycoord
|
||||||
k = self.zcoord
|
k = self.zcoord
|
||||||
|
|
||||||
self.update_voltage(iteration, G)
|
self.update_voltage(iteration, G)
|
||||||
|
|
||||||
if self.polarisation == 'x':
|
if self.polarisation == 'x':
|
||||||
Ex[i, j, k] = - self.voltage[self.antpos] / G.dx
|
Ex[i, j, k] = - self.voltage[self.antpos] / G.dx
|
||||||
|
|
||||||
elif self.polarisation == 'y':
|
elif self.polarisation == 'y':
|
||||||
Ey[i, j, k] = - self.voltage[self.antpos] / G.dy
|
Ey[i, j, k] = - self.voltage[self.antpos] / G.dy
|
||||||
|
|
||||||
elif self.polarisation == 'z':
|
elif self.polarisation == 'z':
|
||||||
Ez[i, j, k] = - self.voltage[self.antpos] / G.dz
|
Ez[i, j, k] = - self.voltage[self.antpos] / G.dz
|
||||||
|
|
||||||
def update_magnetic(self, iteration, updatecoeffsH, ID, Hx, Hy, Hz, G):
|
def update_magnetic(self, iteration, updatecoeffsH, ID, Hx, Hy, Hz, G):
|
||||||
"""Updates current value in transmission line from magnetic field values in the main grid.
|
"""Updates current value in transmission line from magnetic field values in the main grid.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
iteration (int): Current iteration (timestep).
|
iteration (int): Current iteration (timestep).
|
||||||
updatecoeffsH (memory view): numpy array of magnetic field update coefficients.
|
updatecoeffsH (memory view): numpy array of magnetic field update coefficients.
|
||||||
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
ID (memory view): numpy array of numeric IDs corresponding to materials in the model.
|
||||||
Hx, Hy, Hz (memory view): numpy array of magnetic field values.
|
Hx, Hy, Hz (memory view): numpy array of magnetic field values.
|
||||||
G (class): Grid class instance - holds essential parameters describing the model.
|
G (class): Grid class instance - holds essential parameters describing the model.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if iteration * G.dt >= self.start and iteration * G.dt <= self.stop:
|
if iteration * G.dt >= self.start and iteration * G.dt <= self.stop:
|
||||||
i = self.xcoord
|
i = self.xcoord
|
||||||
j = self.ycoord
|
j = self.ycoord
|
||||||
k = self.zcoord
|
k = self.zcoord
|
||||||
|
|
||||||
if self.polarisation == 'x':
|
if self.polarisation == 'x':
|
||||||
self.current[self.antpos] = Ix(i, j, k, G.Hx, G.Hy, G.Hz, G)
|
self.current[self.antpos] = Ix(i, j, k, G.Hx, G.Hy, G.Hz, G)
|
||||||
|
|
||||||
elif self.polarisation == 'y':
|
elif self.polarisation == 'y':
|
||||||
self.current[self.antpos] = Iy(i, j, k, G.Hx, G.Hy, G.Hz, G)
|
self.current[self.antpos] = Iy(i, j, k, G.Hx, G.Hy, G.Hz, G)
|
||||||
|
|
||||||
elif self.polarisation == 'z':
|
elif self.polarisation == 'z':
|
||||||
self.current[self.antpos] = Iz(i, j, k, G.Hx, G.Hy, G.Hz, G)
|
self.current[self.antpos] = Iz(i, j, k, G.Hx, G.Hy, G.Hz, G)
|
||||||
|
|
||||||
self.update_current(iteration, G)
|
self.update_current(iteration, G)
|
||||||
|
@@ -1,72 +1,72 @@
|
|||||||
from ..grid import FDTDGrid
|
from ..grid import FDTDGrid
|
||||||
|
|
||||||
from ..materials import Material
|
from ..materials import Material
|
||||||
|
|
||||||
from scipy.constants import mu_0
|
from scipy.constants import mu_0
|
||||||
from scipy.constants import epsilon_0
|
from scipy.constants import epsilon_0
|
||||||
from scipy.constants import c
|
from scipy.constants import c
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from colorama import init
|
from colorama import init
|
||||||
from colorama import Fore
|
from colorama import Fore
|
||||||
from colorama import Style
|
from colorama import Style
|
||||||
init()
|
init()
|
||||||
|
|
||||||
|
|
||||||
class SubGridBase(FDTDGrid):
|
class SubGridBase(FDTDGrid):
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.mode = '3D'
|
self.mode = '3D'
|
||||||
self.ratio = kwargs['ratio']
|
self.ratio = kwargs['ratio']
|
||||||
|
|
||||||
if self.ratio % 2 == 0:
|
if self.ratio % 2 == 0:
|
||||||
raise ValueError('Subgrid Error: Only odd ratios are supported')
|
raise ValueError('Subgrid Error: Only odd ratios are supported')
|
||||||
|
|
||||||
# Name of the grid
|
# Name of the grid
|
||||||
self.name = kwargs['ID']
|
self.name = kwargs['ID']
|
||||||
|
|
||||||
self.filter = kwargs['filter']
|
self.filter = kwargs['filter']
|
||||||
|
|
||||||
# Number of main grid cells between the IS and OS
|
# Number of main grid cells between the IS and OS
|
||||||
self.is_os_sep = kwargs['is_os_sep']
|
self.is_os_sep = kwargs['is_os_sep']
|
||||||
# Number of subgrid grid cells between the IS and OS
|
# Number of subgrid grid cells between the IS and OS
|
||||||
self.s_is_os_sep = self.is_os_sep * self.ratio
|
self.s_is_os_sep = self.is_os_sep * self.ratio
|
||||||
|
|
||||||
# Distance from OS to pml or the edge of the grid when pml is off
|
# Distance from OS to pml or the edge of the grid when pml is off
|
||||||
self.pml_separation = kwargs['pml_separation']
|
self.pml_separation = kwargs['pml_separation']
|
||||||
|
|
||||||
self.pmlthickness['x0'] = kwargs['subgrid_pml_thickness']
|
self.pmlthickness['x0'] = kwargs['subgrid_pml_thickness']
|
||||||
self.pmlthickness['y0'] = kwargs['subgrid_pml_thickness']
|
self.pmlthickness['y0'] = kwargs['subgrid_pml_thickness']
|
||||||
self.pmlthickness['z0'] = kwargs['subgrid_pml_thickness']
|
self.pmlthickness['z0'] = kwargs['subgrid_pml_thickness']
|
||||||
self.pmlthickness['xmax'] = kwargs['subgrid_pml_thickness']
|
self.pmlthickness['xmax'] = kwargs['subgrid_pml_thickness']
|
||||||
self.pmlthickness['ymax'] = kwargs['subgrid_pml_thickness']
|
self.pmlthickness['ymax'] = kwargs['subgrid_pml_thickness']
|
||||||
self.pmlthickness['zmax'] = kwargs['subgrid_pml_thickness']
|
self.pmlthickness['zmax'] = kwargs['subgrid_pml_thickness']
|
||||||
|
|
||||||
# Number of sub cells to extend the sub grid beyond the IS boundary
|
# Number of sub cells to extend the sub grid beyond the IS boundary
|
||||||
d_to_pml = self.s_is_os_sep + self.pml_separation
|
d_to_pml = self.s_is_os_sep + self.pml_separation
|
||||||
self.n_boundary_cells = d_to_pml + self.pmlthickness['x0']
|
self.n_boundary_cells = d_to_pml + self.pmlthickness['x0']
|
||||||
self.n_boundary_cells_x = d_to_pml + self.pmlthickness['x0']
|
self.n_boundary_cells_x = d_to_pml + self.pmlthickness['x0']
|
||||||
self.n_boundary_cells_y = d_to_pml + self.pmlthickness['y0']
|
self.n_boundary_cells_y = d_to_pml + self.pmlthickness['y0']
|
||||||
self.n_boundary_cells_z = d_to_pml + self.pmlthickness['z0']
|
self.n_boundary_cells_z = d_to_pml + self.pmlthickness['z0']
|
||||||
|
|
||||||
self.interpolation = kwargs['interpolation']
|
self.interpolation = kwargs['interpolation']
|
||||||
|
|
||||||
def calculate_dt(self):
|
def calculate_dt(self):
|
||||||
self.dt = (1 / (c * np.sqrt(
|
self.dt = (1 / (c * np.sqrt(
|
||||||
(1 / self.dx) * (1 / self.dx) +
|
(1 / self.dx) * (1 / self.dx) +
|
||||||
(1 / self.dy) * (1 / self.dy) +
|
(1 / self.dy) * (1 / self.dy) +
|
||||||
(1 / self.dz) * (1 / self.dz))))
|
(1 / self.dz) * (1 / self.dz))))
|
||||||
|
|
||||||
|
|
||||||
def main_grid_index_to_subgrid_index(self, i, j, k):
|
def main_grid_index_to_subgrid_index(self, i, j, k):
|
||||||
i_s = self.n_boundary_cells_x + (i - self.i0) * self.ratio
|
i_s = self.n_boundary_cells_x + (i - self.i0) * self.ratio
|
||||||
j_s = self.n_boundary_cells_y + (j - self.j0) * self.ratio
|
j_s = self.n_boundary_cells_y + (j - self.j0) * self.ratio
|
||||||
k_s = self.n_boundary_cells_z + (k - self.k0) * self.ratio
|
k_s = self.n_boundary_cells_z + (k - self.k0) * self.ratio
|
||||||
|
|
||||||
return (i_s, j_s, k_s)
|
return (i_s, j_s, k_s)
|
||||||
|
|
||||||
def initialise_geometry_arrays(self):
|
def initialise_geometry_arrays(self):
|
||||||
super().initialise_geometry_arrays()
|
super().initialise_geometry_arrays()
|
||||||
|
@@ -1,146 +1,146 @@
|
|||||||
from ..receivers import Rx
|
from ..receivers import Rx
|
||||||
|
|
||||||
|
|
||||||
class ReferenceRx(Rx):
|
class ReferenceRx(Rx):
|
||||||
"""Receiver that micks a receiver in coarse grid."""
|
"""Receiver that micks a receiver in coarse grid."""
|
||||||
|
|
||||||
"""We often want to compare an output in a fine reference solution with a
|
"""We often want to compare an output in a fine reference solution with a
|
||||||
the solution in the coarse grid of a subgridded solution. This receiver
|
the solution in the coarse grid of a subgridded solution. This receiver
|
||||||
moves the output points in the fine grid such that they are in the same
|
moves the output points in the fine grid such that they are in the same
|
||||||
position as the coarse grid.
|
position as the coarse grid.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def get_field(self, str_id, field):
|
def get_field(self, str_id, field):
|
||||||
"""Return the field value at the equivalent coarse yee cell.
|
"""Return the field value at the equivalent coarse yee cell.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
str_id : str
|
str_id : str
|
||||||
'Ex' etc...
|
'Ex' etc...
|
||||||
field : np array
|
field : np array
|
||||||
e.g. numpy array of grid.Ez
|
e.g. numpy array of grid.Ez
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
float
|
float
|
||||||
Field value
|
Field value
|
||||||
|
|
||||||
"""
|
"""
|
||||||
d = {
|
d = {
|
||||||
'Ex': self.get_Ex_from_field,
|
'Ex': self.get_Ex_from_field,
|
||||||
'Ey': self.get_Ey_from_field,
|
'Ey': self.get_Ey_from_field,
|
||||||
'Ez': self.get_Ez_from_field,
|
'Ez': self.get_Ez_from_field,
|
||||||
'Hx': self.get_Hx_from_field,
|
'Hx': self.get_Hx_from_field,
|
||||||
'Hy': self.get_Hy_from_field,
|
'Hy': self.get_Hy_from_field,
|
||||||
'Hz': self.get_Hz_from_field
|
'Hz': self.get_Hz_from_field
|
||||||
}
|
}
|
||||||
|
|
||||||
e = d[str_id](field)
|
e = d[str_id](field)
|
||||||
return e
|
return e
|
||||||
|
|
||||||
def get_Ex_from_field(self, Ex):
|
def get_Ex_from_field(self, Ex):
|
||||||
"""Return the Ex field value from the equivalent coarse yee cell.
|
"""Return the Ex field value from the equivalent coarse yee cell.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
Ex : 3d numpy array
|
Ex : 3d numpy array
|
||||||
e.g. grid.Ex
|
e.g. grid.Ex
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
float
|
float
|
||||||
Ex field value
|
Ex field value
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# offset = ratio // 2
|
# offset = ratio // 2
|
||||||
e = Ex[self.xcoord + self.offset, self.ycoord, self.zcoord]
|
e = Ex[self.xcoord + self.offset, self.ycoord, self.zcoord]
|
||||||
return e
|
return e
|
||||||
|
|
||||||
def get_Ey_from_field(self, Ey):
|
def get_Ey_from_field(self, Ey):
|
||||||
"""Return the Ey field value from the equivalent coarse yee cell.
|
"""Return the Ey field value from the equivalent coarse yee cell.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
Ex : 3d numpy array
|
Ex : 3d numpy array
|
||||||
e.g. grid.Ex
|
e.g. grid.Ex
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
float
|
float
|
||||||
Ey field value
|
Ey field value
|
||||||
|
|
||||||
"""
|
"""
|
||||||
e = Ey[self.xcoord, self.ycoord + self.offset, self.zcoord]
|
e = Ey[self.xcoord, self.ycoord + self.offset, self.zcoord]
|
||||||
return e
|
return e
|
||||||
|
|
||||||
def get_Ez_from_field(self, Ez):
|
def get_Ez_from_field(self, Ez):
|
||||||
"""Return the Ez field value from the equivalent coarse yee cell.
|
"""Return the Ez field value from the equivalent coarse yee cell.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
Ex : 3d numpy array
|
Ex : 3d numpy array
|
||||||
e.g. grid.Ez
|
e.g. grid.Ez
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
float
|
float
|
||||||
Ez field value
|
Ez field value
|
||||||
|
|
||||||
"""
|
"""
|
||||||
e = Ez[self.xcoord, self.ycoord, self.zcoord + self.offset]
|
e = Ez[self.xcoord, self.ycoord, self.zcoord + self.offset]
|
||||||
return e
|
return e
|
||||||
|
|
||||||
def get_Hx_from_field(self, Hx):
|
def get_Hx_from_field(self, Hx):
|
||||||
"""Return the Hx field value from the equivalent coarse yee cell.
|
"""Return the Hx field value from the equivalent coarse yee cell.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
Ex : 3d numpy array
|
Ex : 3d numpy array
|
||||||
e.g. grid.Hx
|
e.g. grid.Hx
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
float
|
float
|
||||||
Hx field value
|
Hx field value
|
||||||
|
|
||||||
"""
|
"""
|
||||||
e = Hx[self.xcoord, self.ycoord + self.offset, self.zcoord + self.offset]
|
e = Hx[self.xcoord, self.ycoord + self.offset, self.zcoord + self.offset]
|
||||||
return e
|
return e
|
||||||
|
|
||||||
def get_Hy_from_field(self, Hy):
|
def get_Hy_from_field(self, Hy):
|
||||||
"""Return the Hy field value from the equivalent coarse yee cell.
|
"""Return the Hy field value from the equivalent coarse yee cell.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
Ex : 3d numpy array
|
Ex : 3d numpy array
|
||||||
e.g. grid.Hx
|
e.g. grid.Hx
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
float
|
float
|
||||||
Hy field value
|
Hy field value
|
||||||
|
|
||||||
"""
|
"""
|
||||||
e = Hy[self.xcoord + self.offset, self.ycoord, self.zcoord + self.offset]
|
e = Hy[self.xcoord + self.offset, self.ycoord, self.zcoord + self.offset]
|
||||||
return e
|
return e
|
||||||
|
|
||||||
def get_Hz_from_field(self, Hz):
|
def get_Hz_from_field(self, Hz):
|
||||||
"""Return the Hz field value from the equivalent coarse yee cell.
|
"""Return the Hz field value from the equivalent coarse yee cell.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
Ex : 3d numpy array
|
Ex : 3d numpy array
|
||||||
e.g. grid.Hx
|
e.g. grid.Hx
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
float
|
float
|
||||||
Hz field value
|
Hz field value
|
||||||
|
|
||||||
"""
|
"""
|
||||||
e = Hz[self.xcoord + self.offset, self.ycoord + self.offset, self.zcoord]
|
e = Hz[self.xcoord + self.offset, self.ycoord + self.offset, self.zcoord]
|
||||||
return e
|
return e
|
||||||
|
文件差异内容过多而无法显示
加载差异
文件差异内容过多而无法显示
加载差异
@@ -1,148 +1,148 @@
|
|||||||
from .base import SubGridBase
|
from .base import SubGridBase
|
||||||
from ..cython.fields_updates_hsg import cython_update_is
|
from ..cython.fields_updates_hsg import cython_update_is
|
||||||
from ..cython.fields_updates_hsg import cython_update_magnetic_os
|
from ..cython.fields_updates_hsg import cython_update_magnetic_os
|
||||||
from ..cython.fields_updates_hsg import cython_update_electric_os
|
from ..cython.fields_updates_hsg import cython_update_electric_os
|
||||||
from ..utilities import human_size
|
from ..utilities import human_size
|
||||||
|
|
||||||
from colorama import init, Fore, Style
|
from colorama import init, Fore, Style
|
||||||
init()
|
init()
|
||||||
|
|
||||||
|
|
||||||
class SubGridHSG(SubGridBase):
|
class SubGridHSG(SubGridBase):
|
||||||
|
|
||||||
gridtype = '3DSUBGRID'
|
gridtype = '3DSUBGRID'
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.gridtype = SubGridHSG.gridtype
|
self.gridtype = SubGridHSG.gridtype
|
||||||
|
|
||||||
def update_magnetic_is(self, precursors):
|
def update_magnetic_is(self, precursors):
|
||||||
"""Update the subgrid nodes at the IS with the currents derived
|
"""Update the subgrid nodes at the IS with the currents derived
|
||||||
from the main grid.
|
from the main grid.
|
||||||
Args: nwl, nwm, nwn, face, field, inc_field, lookup_id, sign, mod, co
|
Args: nwl, nwm, nwn, face, field, inc_field, lookup_id, sign, mod, co
|
||||||
"""
|
"""
|
||||||
# Hz = c0Hz - c1Ey + c2Ex
|
# Hz = c0Hz - c1Ey + c2Ex
|
||||||
# Hy = c0Hy - c3Ex + c1Ez
|
# Hy = c0Hy - c3Ex + c1Ez
|
||||||
# Hx = c0Hx - c2Ez + c3Ey
|
# Hx = c0Hx - c2Ez + c3Ey
|
||||||
# bottom and top
|
# bottom and top
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwx, self.nwy + 1, self.nwz, 1, self.Hy, precursors.ex_bottom, precursors.ex_top, self.IDlookup['Hy'], 1, -1, 3, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwx, self.nwy + 1, self.nwz, 1, self.Hy, precursors.ex_bottom, precursors.ex_top, self.IDlookup['Hy'], 1, -1, 3, self.nthreads)
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwx + 1, self.nwy, self.nwz, 1, self.Hx, precursors.ey_bottom, precursors.ey_top, self.IDlookup['Hx'], -1, 1, 3, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwx + 1, self.nwy, self.nwz, 1, self.Hx, precursors.ey_bottom, precursors.ey_top, self.IDlookup['Hx'], -1, 1, 3, self.nthreads)
|
||||||
|
|
||||||
# left and right
|
# left and right
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwy, self.nwz + 1, self.nwx, 2, self.Hz, precursors.ey_left, precursors.ey_right, self.IDlookup['Hz'], 1, -1, 1, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwy, self.nwz + 1, self.nwx, 2, self.Hz, precursors.ey_left, precursors.ey_right, self.IDlookup['Hz'], 1, -1, 1, self.nthreads)
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwy + 1, self.nwz, self.nwx, 2, self.Hy, precursors.ez_left, precursors.ez_right, self.IDlookup['Hy'], -1, 1, 1, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwy + 1, self.nwz, self.nwx, 2, self.Hy, precursors.ez_left, precursors.ez_right, self.IDlookup['Hy'], -1, 1, 1, self.nthreads)
|
||||||
|
|
||||||
# front and back
|
# front and back
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwx, self.nwz + 1, self.nwy, 3, self.Hz, precursors.ex_front, precursors.ex_back, self.IDlookup['Hz'], -1, 1, 2, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwx, self.nwz + 1, self.nwy, 3, self.Hz, precursors.ex_front, precursors.ex_back, self.IDlookup['Hz'], -1, 1, 2, self.nthreads)
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwx + 1, self.nwz, self.nwy, 3, self.Hx, precursors.ez_front, precursors.ez_back, self.IDlookup['Hx'], 1, -1, 2, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsH, self.ID, self.n_boundary_cells, -1, self.nwx + 1, self.nwz, self.nwy, 3, self.Hx, precursors.ez_front, precursors.ez_back, self.IDlookup['Hx'], 1, -1, 2, self.nthreads)
|
||||||
|
|
||||||
def update_electric_is(self, precursors):
|
def update_electric_is(self, precursors):
|
||||||
# Args: nwl, nwm, nwn, face, field, inc_field, lookup_id, sign, mod, co
|
# Args: nwl, nwm, nwn, face, field, inc_field, lookup_id, sign, mod, co
|
||||||
|
|
||||||
# Ex = c0(Ex) + c2(dHz) - c3(dHy)
|
# Ex = c0(Ex) + c2(dHz) - c3(dHy)
|
||||||
# Ey = c0(Ey) + c3(dHx) - c1(dHz)
|
# Ey = c0(Ey) + c3(dHx) - c1(dHz)
|
||||||
# Ez = c0(Ez) + c1(dHy) - c2(dHx)
|
# Ez = c0(Ez) + c1(dHy) - c2(dHx)
|
||||||
|
|
||||||
# bottom and top
|
# bottom and top
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwx, self.nwy + 1, self.nwz, 1, self.Ex, precursors.hy_bottom, precursors.hy_top, self.IDlookup['Ex'], 1, -1, 3, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwx, self.nwy + 1, self.nwz, 1, self.Ex, precursors.hy_bottom, precursors.hy_top, self.IDlookup['Ex'], 1, -1, 3, self.nthreads)
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwx + 1, self.nwy, self.nwz, 1, self.Ey, precursors.hx_bottom, precursors.hx_top, self.IDlookup['Ey'], -1, 1, 3, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwx + 1, self.nwy, self.nwz, 1, self.Ey, precursors.hx_bottom, precursors.hx_top, self.IDlookup['Ey'], -1, 1, 3, self.nthreads)
|
||||||
|
|
||||||
# left and right
|
# left and right
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwy, self.nwz + 1, self.nwx, 2, self.Ey, precursors.hz_left, precursors.hz_right, self.IDlookup['Ey'], 1, -1, 1, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwy, self.nwz + 1, self.nwx, 2, self.Ey, precursors.hz_left, precursors.hz_right, self.IDlookup['Ey'], 1, -1, 1, self.nthreads)
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwy + 1, self.nwz, self.nwx, 2, self.Ez, precursors.hy_left, precursors.hy_right, self.IDlookup['Ez'], -1, 1, 1, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwy + 1, self.nwz, self.nwx, 2, self.Ez, precursors.hy_left, precursors.hy_right, self.IDlookup['Ez'], -1, 1, 1, self.nthreads)
|
||||||
|
|
||||||
# front and back
|
# front and back
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwx, self.nwz + 1, self.nwy, 3, self.Ex, precursors.hz_front, precursors.hz_back, self.IDlookup['Ex'], -1, 1, 2, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwx, self.nwz + 1, self.nwy, 3, self.Ex, precursors.hz_front, precursors.hz_back, self.IDlookup['Ex'], -1, 1, 2, self.nthreads)
|
||||||
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwx + 1, self.nwz, self.nwy, 3, self.Ez, precursors.hx_front, precursors.hx_back, self.IDlookup['Ez'], 1, -1, 2, self.nthreads)
|
cython_update_is(self.nwx, self.nwy, self.nwz, self.updatecoeffsE, self.ID, self.n_boundary_cells, 0, self.nwx + 1, self.nwz, self.nwy, 3, self.Ez, precursors.hx_front, precursors.hx_back, self.IDlookup['Ez'], 1, -1, 2, self.nthreads)
|
||||||
|
|
||||||
def update_electric_os(self, main_grid):
|
def update_electric_os(self, main_grid):
|
||||||
i_l = self.i0 - self.is_os_sep
|
i_l = self.i0 - self.is_os_sep
|
||||||
i_u = self.i1 + self.is_os_sep
|
i_u = self.i1 + self.is_os_sep
|
||||||
j_l = self.j0 - self.is_os_sep
|
j_l = self.j0 - self.is_os_sep
|
||||||
j_u = self.j1 + self.is_os_sep
|
j_u = self.j1 + self.is_os_sep
|
||||||
k_l = self.k0 - self.is_os_sep
|
k_l = self.k0 - self.is_os_sep
|
||||||
k_u = self.k1 + self.is_os_sep
|
k_u = self.k1 + self.is_os_sep
|
||||||
|
|
||||||
# Args: sub_grid, normal, l_l, l_u, m_l, m_u, n_l, n_u, nwn, lookup_id, field, inc_field, co, sign_n, sign_f
|
# Args: sub_grid, normal, l_l, l_u, m_l, m_u, n_l, n_u, nwn, lookup_id, field, inc_field, co, sign_n, sign_f
|
||||||
|
|
||||||
# Form of FDTD update equations for E
|
# Form of FDTD update equations for E
|
||||||
# Ex = c0(Ex) + c2(dHz) - c3(dHy)
|
# Ex = c0(Ex) + c2(dHz) - c3(dHy)
|
||||||
# Ey = c0(Ey) + c3(dHx) - c1(dHz)
|
# Ey = c0(Ey) + c3(dHx) - c1(dHz)
|
||||||
# Ez = c0(Ez) + c1(dHy) - c2(dHx)
|
# Ez = c0(Ez) + c1(dHy) - c2(dHx)
|
||||||
|
|
||||||
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 3, i_l, i_u, k_l, k_u + 1, j_l, j_u, self.nwy, main_grid.IDlookup['Ex'], main_grid.Ex, self.Hz, 2, 1, -1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 3, i_l, i_u, k_l, k_u + 1, j_l, j_u, self.nwy, main_grid.IDlookup['Ex'], main_grid.Ex, self.Hz, 2, 1, -1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 3, i_l, i_u + 1, k_l, k_u, j_l, j_u, self.nwy, main_grid.IDlookup['Ez'], main_grid.Ez, self.Hx, 2, -1, 1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 3, i_l, i_u + 1, k_l, k_u, j_l, j_u, self.nwy, main_grid.IDlookup['Ez'], main_grid.Ez, self.Hx, 2, -1, 1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
|
|
||||||
# Left and Right
|
# Left and Right
|
||||||
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 2, j_l, j_u, k_l, k_u + 1, i_l, i_u, self.nwx, main_grid.IDlookup['Ey'], main_grid.Ey, self.Hz, 1, -1, 1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 2, j_l, j_u, k_l, k_u + 1, i_l, i_u, self.nwx, main_grid.IDlookup['Ey'], main_grid.Ey, self.Hz, 1, -1, 1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 2, j_l, j_u + 1, k_l, k_u, i_l, i_u, self.nwx, main_grid.IDlookup['Ez'], main_grid.Ez, self.Hy, 1, 1, -1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 2, j_l, j_u + 1, k_l, k_u, i_l, i_u, self.nwx, main_grid.IDlookup['Ez'], main_grid.Ez, self.Hy, 1, 1, -1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
|
|
||||||
# Bottom and Top
|
# Bottom and Top
|
||||||
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 1, i_l, i_u, j_l, j_u + 1, k_l, k_u, self.nwz, main_grid.IDlookup['Ex'], main_grid.Ex, self.Hy, 3, -1, 1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 1, i_l, i_u, j_l, j_u + 1, k_l, k_u, self.nwz, main_grid.IDlookup['Ex'], main_grid.Ex, self.Hy, 3, -1, 1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 1, i_l, i_u + 1, j_l, j_u, k_l, k_u, self.nwz, main_grid.IDlookup['Ey'], main_grid.Ey, self.Hx, 3, 1, -1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_electric_os(main_grid.updatecoeffsE, main_grid.ID, 1, i_l, i_u + 1, j_l, j_u, k_l, k_u, self.nwz, main_grid.IDlookup['Ey'], main_grid.Ey, self.Hx, 3, 1, -1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
|
|
||||||
def update_magnetic_os(self, main_grid):
|
def update_magnetic_os(self, main_grid):
|
||||||
|
|
||||||
i_l = self.i0 - self.is_os_sep
|
i_l = self.i0 - self.is_os_sep
|
||||||
i_u = self.i1 + self.is_os_sep
|
i_u = self.i1 + self.is_os_sep
|
||||||
j_l = self.j0 - self.is_os_sep
|
j_l = self.j0 - self.is_os_sep
|
||||||
j_u = self.j1 + self.is_os_sep
|
j_u = self.j1 + self.is_os_sep
|
||||||
k_l = self.k0 - self.is_os_sep
|
k_l = self.k0 - self.is_os_sep
|
||||||
k_u = self.k1 + self.is_os_sep
|
k_u = self.k1 + self.is_os_sep
|
||||||
|
|
||||||
# Form of FDTD update equations for H
|
# Form of FDTD update equations for H
|
||||||
# Hz = c0Hz - c1Ey + c2Ex
|
# Hz = c0Hz - c1Ey + c2Ex
|
||||||
# Hy = c0Hy - c3Ex + c1Ez
|
# Hy = c0Hy - c3Ex + c1Ez
|
||||||
# Hx = c0Hx - c2Ez + c3Ey
|
# Hx = c0Hx - c2Ez + c3Ey
|
||||||
|
|
||||||
# Args: sub_grid, normal, l_l, l_u, m_l, m_u, n_l, n_u, nwn, lookup_id, field, inc_field, co, sign_n, sign_f):
|
# Args: sub_grid, normal, l_l, l_u, m_l, m_u, n_l, n_u, nwn, lookup_id, field, inc_field, co, sign_n, sign_f):
|
||||||
|
|
||||||
# Front and back
|
# Front and back
|
||||||
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 3, i_l, i_u, k_l, k_u + 1, j_l - 1, j_u, self.nwy, main_grid.IDlookup['Hz'], main_grid.Hz, self.Ex, 2, 1, -1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 3, i_l, i_u, k_l, k_u + 1, j_l - 1, j_u, self.nwy, main_grid.IDlookup['Hz'], main_grid.Hz, self.Ex, 2, 1, -1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 3, i_l, i_u + 1, k_l, k_u, j_l - 1, j_u, self.nwy, main_grid.IDlookup['Hx'], main_grid.Hx, self.Ez, 2, -1, 1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 3, i_l, i_u + 1, k_l, k_u, j_l - 1, j_u, self.nwy, main_grid.IDlookup['Hx'], main_grid.Hx, self.Ez, 2, -1, 1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
|
|
||||||
# Left and Right
|
# Left and Right
|
||||||
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 2, j_l, j_u, k_l, k_u + 1, i_l - 1, i_u, self.nwx, main_grid.IDlookup['Hz'], main_grid.Hz, self.Ey, 1, -1, 1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 2, j_l, j_u, k_l, k_u + 1, i_l - 1, i_u, self.nwx, main_grid.IDlookup['Hz'], main_grid.Hz, self.Ey, 1, -1, 1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 2, j_l, j_u + 1, k_l, k_u, i_l - 1, i_u, self.nwx, main_grid.IDlookup['Hy'], main_grid.Hy, self.Ez, 1, 1, -1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 2, j_l, j_u + 1, k_l, k_u, i_l - 1, i_u, self.nwx, main_grid.IDlookup['Hy'], main_grid.Hy, self.Ez, 1, 1, -1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
|
|
||||||
# bottom and top
|
# bottom and top
|
||||||
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 1, i_l, i_u, j_l, j_u + 1, k_l - 1, k_u, self.nwz, main_grid.IDlookup['Hy'], main_grid.Hy, self.Ex, 3, -1, 1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 1, i_l, i_u, j_l, j_u + 1, k_l - 1, k_u, self.nwz, main_grid.IDlookup['Hy'], main_grid.Hy, self.Ex, 3, -1, 1, 1, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 1, i_l, i_u + 1, j_l, j_u, k_l - 1, k_u, self.nwz, main_grid.IDlookup['Hx'], main_grid.Hx, self.Ey, 3, 1, -1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
cython_update_magnetic_os(main_grid.updatecoeffsH, main_grid.ID, 1, i_l, i_u + 1, j_l, j_u, k_l - 1, k_u, self.nwz, main_grid.IDlookup['Hx'], main_grid.Hx, self.Ey, 3, 1, -1, 0, self.ratio, self.is_os_sep, self.n_boundary_cells, main_grid.nthreads)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
||||||
self.memory_estimate_basic()
|
self.memory_estimate_basic()
|
||||||
|
|
||||||
s = '\n'
|
s = '\n'
|
||||||
s += Fore.CYAN
|
s += Fore.CYAN
|
||||||
s += 'Sub Grid HSG\n'
|
s += 'Sub Grid HSG\n'
|
||||||
s += 'Name: {}\n'.format(self.name)
|
s += 'Name: {}\n'.format(self.name)
|
||||||
s += 'dx, dy, dz: {}m {}m {}m\n'.format(self.dx, self.dy, self.dz)
|
s += 'dx, dy, dz: {}m {}m {}m\n'.format(self.dx, self.dy, self.dz)
|
||||||
s += 'dt: {}s\n'.format(self.dt)
|
s += 'dt: {}s\n'.format(self.dt)
|
||||||
s += 'Memory Estimate: {}\n'.format(human_size(self.memoryusage))
|
s += 'Memory Estimate: {}\n'.format(human_size(self.memoryusage))
|
||||||
s += 'Position: ({}m, {}m, {}m), ({}m, {}m, {}m)\n'.format(self.x1,
|
s += 'Position: ({}m, {}m, {}m), ({}m, {}m, {}m)\n'.format(self.x1,
|
||||||
self.y1,
|
self.y1,
|
||||||
self.z1,
|
self.z1,
|
||||||
self.x2,
|
self.x2,
|
||||||
self.y2,
|
self.y2,
|
||||||
self.z2)
|
self.z2)
|
||||||
s += 'Main Grid Indices: lower left({}, {}, {}), upper right({}, {}, {})\n'.format(self.i0, self.j0, self.k0, self.i1, self.j1, self.k1)
|
s += 'Main Grid Indices: lower left({}, {}, {}), upper right({}, {}, {})\n'.format(self.i0, self.j0, self.k0, self.i1, self.j1, self.k1)
|
||||||
s += 'Total Cells: {} {} {}\n'.format(self.nx, self.ny, self.nz)
|
s += 'Total Cells: {} {} {}\n'.format(self.nx, self.ny, self.nz)
|
||||||
s += 'Working Region Cells: {} {} {}\n'.format(self.nwx,
|
s += 'Working Region Cells: {} {} {}\n'.format(self.nwx,
|
||||||
self.nwy,
|
self.nwy,
|
||||||
self.nwz)
|
self.nwz)
|
||||||
for h in self.hertziandipoles:
|
for h in self.hertziandipoles:
|
||||||
s += 'Hertizian dipole: {} {} {}\n'.format(h.xcoord,
|
s += 'Hertizian dipole: {} {} {}\n'.format(h.xcoord,
|
||||||
h.ycoord,
|
h.ycoord,
|
||||||
h.zcoord)
|
h.zcoord)
|
||||||
s += str([x for x in self.waveforms
|
s += str([x for x in self.waveforms
|
||||||
if x.ID == h.waveformID][0]) + '\n'
|
if x.ID == h.waveformID][0]) + '\n'
|
||||||
for r in self.rxs:
|
for r in self.rxs:
|
||||||
s += 'Receiver: {} {} {}\n'.format(r.xcoord, r.ycoord, r.zcoord)
|
s += 'Receiver: {} {} {}\n'.format(r.xcoord, r.ycoord, r.zcoord)
|
||||||
|
|
||||||
for tl in self.transmissionlines:
|
for tl in self.transmissionlines:
|
||||||
s += 'Transmission Line: {} {} {}\n'.format(tl.xcoord, tl.ycoord, tl.zcoord)
|
s += 'Transmission Line: {} {} {}\n'.format(tl.xcoord, tl.ycoord, tl.zcoord)
|
||||||
s += str([x for x in self.waveforms
|
s += str([x for x in self.waveforms
|
||||||
if x.ID == tl.waveformID][0]) + '\n'
|
if x.ID == tl.waveformID][0]) + '\n'
|
||||||
s += Style.RESET_ALL
|
s += Style.RESET_ALL
|
||||||
return s
|
return s
|
||||||
|
@@ -1,241 +1,167 @@
|
|||||||
from ..cython.fields_updates_normal import update_electric
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
from ..cython.fields_updates_normal import update_magnetic
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
from ..fields_outputs import store_outputs
|
#
|
||||||
from ..utilities import get_terminal_width
|
# This file is part of gprMax.
|
||||||
from ..exceptions import GeneralError
|
#
|
||||||
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
from .subgrid_hsg import SubGridHSG
|
# it under the terms of the GNU General Public License as published by
|
||||||
from .precursor_nodes import PrecursorNodes as PrecursorNodesHSG
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
from .precursor_nodes_filtered import PrecursorNodes as PrecursorNodesFilteredHSG
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
from tqdm import tqdm
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
from time import perf_counter
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
import os
|
# GNU General Public License for more details.
|
||||||
import sys
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
from ..updates import CPUUpdates
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
from ..cython.fields_updates_normal import update_electric
|
||||||
|
from ..cython.fields_updates_normal import update_magnetic
|
||||||
|
from ..fields_outputs import store_outputs
|
||||||
def create_updates(G):
|
from ..utilities import get_terminal_width
|
||||||
"""Return the solver for the given subgrids."""
|
from ..exceptions import GeneralError
|
||||||
updaters = []
|
|
||||||
|
from .subgrid_hsg import SubGridHSG
|
||||||
for sg in G.subgrids:
|
from .precursor_nodes import PrecursorNodes as PrecursorNodesHSG
|
||||||
print(sg)
|
from .precursor_nodes_filtered import PrecursorNodes as PrecursorNodesFilteredHSG
|
||||||
sg_type = type(sg)
|
|
||||||
if sg_type == SubGridHSG and sg.filter:
|
from tqdm import tqdm
|
||||||
precursors = PrecursorNodesFilteredHSG(G, sg)
|
from time import perf_counter
|
||||||
elif sg_type == SubGridHSG and not sg.filter:
|
|
||||||
precursors = PrecursorNodesHSG(G, sg)
|
import os
|
||||||
else:
|
import sys
|
||||||
raise GeneralError(str(sg) + ' is not a subgrid type')
|
|
||||||
|
from ..updates import CPUUpdates
|
||||||
sgu = SubgridUpdater(sg, precursors, G)
|
|
||||||
updaters.append(sgu)
|
def create_updates(G):
|
||||||
|
"""Return the solver for the given subgrids."""
|
||||||
updates = SubgridUpdates(G, updaters)
|
updaters = []
|
||||||
return updates
|
|
||||||
|
for sg in G.subgrids:
|
||||||
class SubgridUpdates(CPUUpdates):
|
print(sg)
|
||||||
|
sg_type = type(sg)
|
||||||
def __init__(self, G, updaters):
|
if sg_type == SubGridHSG and sg.filter:
|
||||||
super().__init__(G)
|
precursors = PrecursorNodesFilteredHSG(G, sg)
|
||||||
self.updaters = updaters
|
elif sg_type == SubGridHSG and not sg.filter:
|
||||||
|
precursors = PrecursorNodesHSG(G, sg)
|
||||||
def hsg_1(self):
|
else:
|
||||||
"""Method to update the subgrids over the first phase."""
|
raise GeneralError(str(sg) + ' is not a subgrid type')
|
||||||
for sg_updater in self.updaters:
|
|
||||||
sg_updater.hsg_1()
|
sgu = SubgridUpdater(sg, precursors, G)
|
||||||
|
updaters.append(sgu)
|
||||||
def hsg_2(self):
|
|
||||||
"""Method to update the subgrids over the second phase."""
|
updates = SubgridUpdates(G, updaters)
|
||||||
for sg_updater in self.updaters:
|
return updates
|
||||||
sg_updater.hsg_2()
|
|
||||||
|
class SubgridUpdates(CPUUpdates):
|
||||||
class SubGridSolver:
|
|
||||||
"""Solver for subgridding simulations."""
|
def __init__(self, G, updaters):
|
||||||
|
super().__init__(G)
|
||||||
"""Class to call the various update methods required for an HSG-Subgrid simulation.
|
self.updaters = updaters
|
||||||
Multiple subgrids can be updated by adding more subgrid_updater objects to the subgrid_updater
|
|
||||||
array.
|
def hsg_1(self):
|
||||||
"""
|
"""Method to update the subgrids over the first phase."""
|
||||||
|
for sg_updater in self.updaters:
|
||||||
def __init__(self, G, updates, hsg=True):
|
sg_updater.hsg_1()
|
||||||
"""
|
|
||||||
Args:
|
def hsg_2(self):
|
||||||
G (G): Grid class instance - holds essential parameters
|
"""Method to update the subgrids over the second phase."""
|
||||||
describing the model.
|
for sg_updater in self.updaters:
|
||||||
updates: (list): list of subgrid_updaters used for updating
|
sg_updater.hsg_2()
|
||||||
the subgrids
|
|
||||||
hsg (bool): HSG methods for subgrids will not be called if False.
|
|
||||||
"""
|
class SubgridUpdater(CPUUpdates):
|
||||||
self.G = G
|
"""Class to handle updating the electric and magnetic fields of an HSG
|
||||||
self.updates = updates
|
subgrid. The IS, OS, subgrid region and the electric/magnetic sources are updated
|
||||||
self.hsg = hsg
|
using the precursor regions.
|
||||||
|
"""
|
||||||
def store_snapshots(self):
|
|
||||||
"""Store any snapshots."""
|
def __init__(self, subgrid, precursors, G):
|
||||||
for snap in self.G.snapshots:
|
"""
|
||||||
if snap.time == self.G.iteration + 1:
|
Args:
|
||||||
snap.store(self.G)
|
subgrid (SubGrid3d): Subgrid to be updated
|
||||||
|
precursors (PrecursorNodes): Precursor nodes associated with
|
||||||
def solve(self, iterations):
|
the subgrid - contain interpolated fields
|
||||||
"""Run timestepping."""
|
G (class): Grid class instance - holds essential parameters
|
||||||
tsolvestart = perf_counter()
|
describing the model.
|
||||||
self.iterations = iterations
|
"""
|
||||||
# for time step in range(self.G.iterations):
|
super().__init__(subgrid)
|
||||||
|
self.precursors = precursors
|
||||||
# The main grid FDTD loop
|
self.G = G
|
||||||
for iteration in self.iterations:
|
self.source_iteration = 0
|
||||||
self.updates.grid.iteration = iteration
|
|
||||||
self.updates.store_outputs()
|
def hsg_1(self):
|
||||||
#self.updates.store_snapshots(iteration)
|
"""This is the first half of the subgrid update. Takes the time step
|
||||||
self.updates.update_magnetic()
|
up to the main grid magnetic update"""
|
||||||
self.updates.update_magnetic_pml()
|
G = self.G
|
||||||
self.updates.update_magnetic_sources(iteration)
|
sub_grid = self.grid
|
||||||
self.updates.hsg_2()
|
precursors = self.precursors
|
||||||
self.updates.update_electric_a()
|
|
||||||
self.updates.update_electric_pml()
|
precursors.update_electric()
|
||||||
self.updates.update_electric_sources(iteration)
|
|
||||||
self.updates.hsg_1()
|
upper_m = int(sub_grid.ratio / 2 - 0.5)
|
||||||
self.updates.update_electric_b()
|
|
||||||
|
for m in range(1, upper_m + 1):
|
||||||
# Keep track of the index. Required for saving output correctly
|
|
||||||
self.G.iteration = iteration
|
# STD update, interpolate inc. field in time, apply correction
|
||||||
|
self.store_outputs()
|
||||||
# Return the elapsed time
|
self.update_electric_a()
|
||||||
tsolve = perf_counter() - tsolvestart
|
self.update_electric_pml()
|
||||||
|
precursors.interpolate_magnetic_in_time(int(m + sub_grid.ratio / 2 - 0.5))
|
||||||
return tsolve
|
sub_grid.update_electric_is(precursors)
|
||||||
|
self.update_electric_b()
|
||||||
def write_snapshots(self, iteration):
|
|
||||||
# Write any snapshots to file
|
self.update_electric_sources()
|
||||||
for i, snap in enumerate(self.G.snapshots):
|
|
||||||
if snap.time == iteration + 1:
|
# STD update, interpolate inc. field in time, apply correction
|
||||||
snapiters = 36 * (((snap.xf - snap.xs) / snap.dx) * ((snap.yf - snap.ys) / snap.dy) * ((snap.zf - snap.zs) / snap.dz))
|
self.update_magnetic()
|
||||||
pbar = tqdm(total=snapiters, leave=False, unit='byte', unit_scale=True, desc=' Writing snapshot file {} of {}, {}'.format(i + 1, len(self.G.snapshots), os.path.split(snap.filename)[1]), ncols=get_terminal_width() - 1, file=sys.stdout, disable=self.G.tqdmdisable)
|
self.update_magnetic_pml()
|
||||||
|
precursors.interpolate_electric_in_time(m)
|
||||||
# Use this call to print out main grid and subgrids
|
sub_grid.update_magnetic_is(precursors)
|
||||||
snap.write_vtk_imagedata(self.G.Ex, self.G.Ey, self.G.Ez, self.G.Hx, self.G.Hy, self.G.Hz, self.G, pbar, sub_grids=self.G.subgrids)
|
self.update_magnetic_sources()
|
||||||
|
|
||||||
# Use this call to print out the standard grid without subgrid
|
self.store_outputs()
|
||||||
# snap.write_vtk_imagedata(self.G.Ex, self.G.Ey, self.G.Ez, self.G.Hx, self.G.Hy, self.G.Hz, self.G, pbar)
|
self.update_electric_a()
|
||||||
|
self.update_electric_pml()
|
||||||
# Use this call to print out only the subgrid - use in combination with commented code in .multi_cmds/snapshots.py
|
precursors.calc_exact_magnetic_in_time()
|
||||||
# snap.write_vtk_imagedata_fast(self.grid)
|
sub_grid.update_electric_is(precursors)
|
||||||
pbar.close()
|
self.update_electric_b()
|
||||||
|
self.update_electric_sources()
|
||||||
|
sub_grid.update_electric_os(G)
|
||||||
class SubgridUpdater(CPUUpdates):
|
|
||||||
"""Class to handle updating the electric and magnetic fields of an HSG
|
def hsg_2(self):
|
||||||
subgrid. The IS, OS, subgrid region and the electric/magnetic sources are updated
|
"""This is the first half of the subgrid update. Takes the time step
|
||||||
using the precursor regions.
|
up to the main grid electric update"""
|
||||||
"""
|
G = self.G
|
||||||
|
sub_grid = self.grid
|
||||||
def __init__(self, subgrid, precursors, G):
|
precursors = self.precursors
|
||||||
"""
|
|
||||||
Args:
|
precursors.update_magnetic()
|
||||||
subgrid (SubGrid3d): Subgrid to be updated
|
|
||||||
precursors (PrecursorNodes): Precursor nodes associated with
|
upper_m = int(sub_grid.ratio / 2 - 0.5)
|
||||||
the subgrid
|
|
||||||
G (class): Grid class instance - holds essential parameters
|
for m in range(1, upper_m + 1):
|
||||||
describing the model.
|
|
||||||
"""
|
self.update_magnetic()
|
||||||
super().__init__(subgrid)
|
self.update_magnetic_pml()
|
||||||
self.precursors = precursors
|
|
||||||
self.G = G
|
precursors.interpolate_electric_in_time(int(m + sub_grid.ratio / 2 - 0.5))
|
||||||
self.source_iteration = 0
|
sub_grid.update_magnetic_is(precursors)
|
||||||
|
self.update_magnetic_sources()
|
||||||
def hsg_1(self):
|
|
||||||
"""This is the first half of the subgrid update. Takes the time step
|
self.store_outputs()
|
||||||
up to the main grid magnetic update"""
|
self.update_electric_a()
|
||||||
G = self.G
|
self.update_electric_pml()
|
||||||
sub_grid = self.grid
|
|
||||||
precursors = self.precursors
|
precursors.interpolate_magnetic_in_time(m)
|
||||||
|
sub_grid.update_electric_is(precursors)
|
||||||
precursors.update_electric()
|
self.update_electric_b()
|
||||||
|
|
||||||
upper_m = int(sub_grid.ratio / 2 - 0.5)
|
self.update_electric_sources()
|
||||||
|
|
||||||
for m in range(1, upper_m + 1):
|
self.update_magnetic()
|
||||||
|
self.update_magnetic_pml()
|
||||||
# STD update, interpolate inc. field in time, apply correction
|
precursors.calc_exact_electric_in_time()
|
||||||
self.store_outputs()
|
sub_grid.update_magnetic_is(precursors)
|
||||||
self.update_electric_a()
|
self.update_magnetic_sources()
|
||||||
self.update_electric_pml()
|
sub_grid.update_magnetic_os(G)
|
||||||
precursors.interpolate_magnetic_in_time(int(m + sub_grid.ratio / 2 - 0.5))
|
|
||||||
sub_grid.update_electric_is(precursors)
|
|
||||||
self.update_electric_b()
|
|
||||||
|
|
||||||
self.update_sub_grid_electric_sources()
|
|
||||||
|
|
||||||
# STD update, interpolate inc. field in time, apply correction
|
|
||||||
self.update_magnetic()
|
|
||||||
self.update_magnetic_pml()
|
|
||||||
precursors.interpolate_electric_in_time(m)
|
|
||||||
sub_grid.update_magnetic_is(precursors)
|
|
||||||
self.update_sub_grid_magnetic_sources()
|
|
||||||
|
|
||||||
self.store_outputs()
|
|
||||||
self.update_electric_a()
|
|
||||||
self.update_electric_pml()
|
|
||||||
precursors.calc_exact_magnetic_in_time()
|
|
||||||
sub_grid.update_electric_is(precursors)
|
|
||||||
self.update_electric_b()
|
|
||||||
self.update_sub_grid_electric_sources()
|
|
||||||
sub_grid.update_electric_os(G)
|
|
||||||
|
|
||||||
def hsg_2(self):
|
|
||||||
"""This is the first half of the subgrid update. Takes the time step
|
|
||||||
up to the main grid electric update"""
|
|
||||||
G = self.G
|
|
||||||
sub_grid = self.grid
|
|
||||||
precursors = self.precursors
|
|
||||||
|
|
||||||
precursors.update_magnetic()
|
|
||||||
|
|
||||||
upper_m = int(sub_grid.ratio / 2 - 0.5)
|
|
||||||
|
|
||||||
for m in range(1, upper_m + 1):
|
|
||||||
|
|
||||||
self.update_magnetic()
|
|
||||||
self.update_magnetic_pml()
|
|
||||||
|
|
||||||
precursors.interpolate_electric_in_time(int(m + sub_grid.ratio / 2 - 0.5))
|
|
||||||
sub_grid.update_magnetic_is(precursors)
|
|
||||||
self.update_sub_grid_magnetic_sources()
|
|
||||||
|
|
||||||
self.store_outputs()
|
|
||||||
self.update_electric_a()
|
|
||||||
self.update_electric_pml()
|
|
||||||
|
|
||||||
precursors.interpolate_magnetic_in_time(m)
|
|
||||||
sub_grid.update_electric_is(precursors)
|
|
||||||
self.update_electric_b()
|
|
||||||
|
|
||||||
self.update_sub_grid_electric_sources()
|
|
||||||
|
|
||||||
self.update_magnetic()
|
|
||||||
self.update_magnetic_pml()
|
|
||||||
precursors.calc_exact_electric_in_time()
|
|
||||||
sub_grid.update_magnetic_is(precursors)
|
|
||||||
self.update_sub_grid_magnetic_sources()
|
|
||||||
sub_grid.update_magnetic_os(G)
|
|
||||||
|
|
||||||
def update_sub_grid_electric_sources(self):
|
|
||||||
"""Update any electric sources in the subgrid"""
|
|
||||||
sg = self.grid
|
|
||||||
for source in sg.voltagesources + sg.transmissionlines + sg.hertziandipoles:
|
|
||||||
source.update_electric(self.source_iteration, sg.updatecoeffsE, sg.ID,
|
|
||||||
sg.Ex, sg.Ey, sg.Ez, sg)
|
|
||||||
self.source_iteration += 1
|
|
||||||
self.grid.iteration = self.source_iteration
|
|
||||||
|
|
||||||
def update_sub_grid_magnetic_sources(self):
|
|
||||||
"""Update any magnetic sources in the subgrid"""
|
|
||||||
sg = self.grid
|
|
||||||
for source in sg.transmissionlines + sg.magneticdipoles:
|
|
||||||
source.update_magnetic(self.source_iteration, sg.updatecoeffsH, sg.ID,
|
|
||||||
sg.Hx, sg.Hy, sg.Hz, sg)
|
|
@@ -1,205 +1,195 @@
|
|||||||
from .subgrid_hsg import SubGridHSG as SubGridHSGUser
|
from .subgrid_hsg import SubGridHSG as SubGridHSGUser
|
||||||
from .multi import ReferenceRx as ReferenceRxUser
|
from .multi import ReferenceRx as ReferenceRxUser
|
||||||
from ..exceptions import CmdInputError
|
from ..exceptions import CmdInputError
|
||||||
from ..cmds_multiple import UserObjectMulti
|
from ..cmds_multiple import UserObjectMulti
|
||||||
from ..cmds_geometry.cmds_geometry import UserObjectGeometry
|
from ..cmds_geometry.cmds_geometry import UserObjectGeometry
|
||||||
from ..cmds_multiple import Rx
|
from ..cmds_multiple import Rx
|
||||||
from gprMax import config
|
from gprMax import config
|
||||||
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class SubGridBase(UserObjectMulti):
|
class SubGridBase(UserObjectMulti):
|
||||||
"""Class to allow UserObjectMulti and UserObjectGeometry to be nested in SubGrid type user objects."""
|
"""Class to allow UserObjectMulti and UserObjectGeometry to be nested in SubGrid type user objects."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Constructor."""
|
"""Constructor."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.children_multiple = []
|
self.children_multiple = []
|
||||||
self.children_geometry = []
|
self.children_geometry = []
|
||||||
|
|
||||||
def add(self, node):
|
def add(self, node):
|
||||||
"""Function to add other user objects. Geometry and multi only."""
|
"""Function to add other user objects. Geometry and multi only."""
|
||||||
if isinstance(node, UserObjectMulti):
|
if isinstance(node, UserObjectMulti):
|
||||||
self.children_multiple.append(node)
|
self.children_multiple.append(node)
|
||||||
elif isinstance(node, UserObjectGeometry):
|
elif isinstance(node, UserObjectGeometry):
|
||||||
self.children_geometry.append(node)
|
self.children_geometry.append(node)
|
||||||
else:
|
else:
|
||||||
raise Exception(str(node) + ' This Object can not be added to a sub grid')
|
raise Exception(str(node) + ' This Object can not be added to a sub grid')
|
||||||
|
|
||||||
def check_filters(self, grid):
|
def check_filters(self, grid):
|
||||||
"""Check the filter of other grids - Only allow filters all on or filters all off."""
|
"""Check the filter of other grids - Only allow filters all on or filters all off."""
|
||||||
if grid.subgrids:
|
if grid.subgrids:
|
||||||
f = grid.subgrids[0]
|
f = grid.subgrids[0]
|
||||||
if f != self.kwargs['filter']:
|
if f != self.kwargs['filter']:
|
||||||
raise CmdInputError(self.__str__() + "Filters should be on or off. Set Filter on or off for all subgrids")
|
raise CmdInputError(self.__str__() + "Filters should be on or off. Set Filter on or off for all subgrids")
|
||||||
|
|
||||||
def set_discretisation(self, sg, grid):
|
def set_discretisation(self, sg, grid):
|
||||||
"""Set the spatial discretisation."""
|
"""Set the spatial discretisation."""
|
||||||
sg.dx = grid.dx / sg.ratio
|
sg.dx = grid.dx / sg.ratio
|
||||||
sg.dy = grid.dy / sg.ratio
|
sg.dy = grid.dy / sg.ratio
|
||||||
sg.dz = grid.dz / sg.ratio
|
sg.dz = grid.dz / sg.ratio
|
||||||
sg.dl = np.array([sg.dx, sg.dy, sg.dz])
|
sg.dl = np.array([sg.dx, sg.dy, sg.dz])
|
||||||
|
|
||||||
def set_main_grid_indices(self, sg, grid, uip, p1, p2):
|
def set_main_grid_indices(self, sg, grid, uip, p1, p2):
|
||||||
"""Set subgrid indices related to main grid placement."""
|
"""Set subgrid indices related to main grid placement."""
|
||||||
# Main grid indices of the sub grid. These are dummy indices. They are
|
# location of the IS
|
||||||
# not user internal except for printing to the user
|
sg.i0, sg.j0, sg.k0 = p1
|
||||||
sg.i0_u, sg.j0_u, sg.k0_u = p1
|
sg.i1, sg.j1, sg.k1 = p2
|
||||||
sg.i1_u, sg.j1_u, sg.k1_u = p2
|
|
||||||
|
sg.x1, sg.y1, sg.z1 = uip.round_to_grid(p1)
|
||||||
# The actual sub gridded area (IS index) is 4 cells in
|
sg.x2, sg.y2, sg.z2 = uip.round_to_grid(p2)
|
||||||
sg.i0, sg.j0, sg.k0 = np.add([sg.i0_u, sg.j0_u, sg.k0_u], sg.is_os_sep)
|
|
||||||
sg.i1, sg.j1, sg.k1 = np.subtract([sg.i1_u, sg.j1_u, sg.k1_u], sg.is_os_sep)
|
def set_name(self, sg):
|
||||||
|
sg.name = self.kwargs['id']
|
||||||
# Main grid indices of the sub grid. These are dummy indices. They are
|
|
||||||
# not user internal except for printing to the user
|
def set_working_region_cells(self, sg):
|
||||||
sg.x1_u, sg.y1_u, sg.z1_u = uip.round_to_grid(p1)
|
"""Number of cells in each dimension for the working region."""
|
||||||
sg.x2_u, sg.y2_u, sg.z2_u = uip.round_to_grid(p2)
|
sg.nwx = (sg.i1 - sg.i0) * sg.ratio
|
||||||
|
sg.nwy = (sg.j1 - sg.j0) * sg.ratio
|
||||||
sg.x1, sg.y1, sg.z1 = np.add([sg.x1_u, sg.y1_u, sg.z1_u], sg.is_os_sep * sg.dx)
|
sg.nwz = (sg.k1 - sg.k0) * sg.ratio
|
||||||
sg.x2, sg.y2, sg.z2 = np.subtract([sg.x2_u, sg.y2_u, sg.z2_u], sg.is_os_sep * sg.dx)
|
|
||||||
|
def set_total_cells(self, sg):
|
||||||
def set_name(self, sg):
|
"""Number of cells in each dimension for the whole region."""
|
||||||
sg.name = self.kwargs['id']
|
sg.nx = 2 * sg.n_boundary_cells_x + sg.nwx
|
||||||
|
sg.ny = 2 * sg.n_boundary_cells_y + sg.nwy
|
||||||
def set_working_region_cells(self, sg):
|
sg.nz = 2 * sg.n_boundary_cells_z + sg.nwz
|
||||||
"""Number of cells in each dimension for the working region."""
|
|
||||||
sg.nwx = (sg.i1 - sg.i0) * sg.ratio
|
def set_iterations(self, sg, main):
|
||||||
sg.nwy = (sg.j1 - sg.j0) * sg.ratio
|
"""Set number of iterations that will take place in the subgrid."""
|
||||||
sg.nwz = (sg.k1 - sg.k0) * sg.ratio
|
sg.iterations = main.iterations * sg.ratio
|
||||||
|
|
||||||
def set_total_cells(self, sg):
|
def setup(self, sg, grid, uip):
|
||||||
"""Number of cells in each dimension for the whole region."""
|
""""Common setup to both all subgrid types."""
|
||||||
sg.nx = 2 * sg.n_boundary_cells_x + sg.nwx
|
p1 = self.kwargs['p1']
|
||||||
sg.ny = 2 * sg.n_boundary_cells_y + sg.nwy
|
p2 = self.kwargs['p2']
|
||||||
sg.nz = 2 * sg.n_boundary_cells_z + sg.nwz
|
|
||||||
|
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
||||||
def set_iterations(self, sg, main):
|
|
||||||
"""Set number of iterations that will take place in the subgrid."""
|
self.check_filters(grid)
|
||||||
sg.iterations = main.iterations * sg.ratio
|
|
||||||
|
self.set_discretisation(sg, grid)
|
||||||
def setup(self, sg, grid, uip):
|
|
||||||
""""Common setup to both all subgrid types."""
|
# Set the temporal discretisation
|
||||||
p1 = self.kwargs['p1']
|
sg.calculate_dt()
|
||||||
p2 = self.kwargs['p2']
|
|
||||||
|
# ensure stability
|
||||||
p1, p2 = uip.check_box_points(p1, p2, self.__str__())
|
sg.round_time_step()
|
||||||
|
|
||||||
self.check_filters(grid)
|
# set the indices related to the subgrids main grid placement
|
||||||
|
self.set_main_grid_indices(sg, grid, uip, p1, p2)
|
||||||
self.set_discretisation(sg, grid)
|
|
||||||
|
"""
|
||||||
# Set the temporal discretisation
|
try:
|
||||||
sg.calculate_dt()
|
uip.check_box_points([sg.i0, sg.j0, sg.k0],
|
||||||
|
[sg.i1, sg.j1, sg.k1], cmd_str)
|
||||||
# ensure stability
|
except CmdInputError:
|
||||||
sg.round_time_step()
|
es_f = 'The subgrid should extend at least {} cells'
|
||||||
|
es = es_f.format(sg.is_os_sep * 2)
|
||||||
# set the indices related to the subgrids main grid placement
|
raise CmdInputError(cmd_str, es)
|
||||||
self.set_main_grid_indices(sg, grid, uip, p1, p2)
|
"""
|
||||||
|
|
||||||
"""
|
self.set_working_region_cells(sg)
|
||||||
try:
|
self.set_total_cells(sg)
|
||||||
uip.check_box_points([sg.i0, sg.j0, sg.k0],
|
self.set_iterations(sg, grid)
|
||||||
[sg.i1, sg.j1, sg.k1], cmd_str)
|
self.set_name(sg)
|
||||||
except CmdInputError:
|
|
||||||
es_f = 'The subgrid should extend at least {} cells'
|
# Copy a reference for the main grid to the sub grid
|
||||||
es = es_f.format(sg.is_os_sep * 2)
|
sg.parent_grid = grid
|
||||||
raise CmdInputError(cmd_str, es)
|
|
||||||
"""
|
sg.timewindow = grid.timewindow
|
||||||
|
|
||||||
self.set_working_region_cells(sg)
|
# Copy a subgrid reference to self so that children.create(grid, uip) can access
|
||||||
self.set_total_cells(sg)
|
# the correct grid
|
||||||
self.set_iterations(sg, grid)
|
self.subgrid = sg
|
||||||
self.set_name(sg)
|
|
||||||
|
# Copy over built in materials
|
||||||
# Copy a reference for the main grid to the sub grid
|
sg.materials = [copy(m) for m in grid.materials if m.numID in range(0, grid.n_built_in_materials + 1)]
|
||||||
sg.parent_grid = grid
|
# use same number of threads
|
||||||
|
sg.nthreads = grid.nthreads
|
||||||
sg.timewindow = grid.timewindow
|
|
||||||
|
# Dont mix and match different subgrids
|
||||||
# Copy a subgrid reference to self so that children.create(grid, uip) can access
|
for sg_made in grid.subgrids:
|
||||||
# the correct grid
|
if type(sg) != type(sg_made):
|
||||||
self.subgrid = sg
|
raise CmdInputError(self.__str__() + ' Please only use one type of subgrid')
|
||||||
|
|
||||||
# Copy over built in materials
|
# Reference the sub grid under the main grid to which it belongs.
|
||||||
sg.materials = [copy(m) for m in grid.materials if m.numID in range(0, grid.n_built_in_materials + 1)]
|
grid.subgrids.append(sg)
|
||||||
# use same number of threads
|
|
||||||
sg.nthreads = grid.nthreads
|
|
||||||
|
class SubGridHSG(SubGridBase):
|
||||||
# Dont mix and match different subgrids
|
"""HSG User Object."""
|
||||||
for sg_made in grid.subgrids:
|
def __init__(self,
|
||||||
if type(sg) != type(sg_made):
|
p1=None,
|
||||||
raise CmdInputError(self.__str__() + ' Please only use one type of subgrid')
|
p2=None,
|
||||||
|
ratio=3,
|
||||||
# Reference the sub grid under the main grid to which it belongs.
|
ID='',
|
||||||
grid.subgrids.append(sg)
|
is_os_sep=3,
|
||||||
|
pml_separation=4,
|
||||||
|
subgrid_pml_thickness=6,
|
||||||
class SubGridHSG(SubGridBase):
|
interpolation='linear',
|
||||||
"""HSG User Object."""
|
loss_mechanism=False,
|
||||||
def __init__(self,
|
loss_factor=False,
|
||||||
p1=None,
|
filter=True,
|
||||||
p2=None,
|
**kwargs):
|
||||||
ratio=3,
|
"""Constructor."""
|
||||||
ID='',
|
|
||||||
is_os_sep=3,
|
pml_separation = ratio // 2 + 2
|
||||||
pml_separation=4,
|
|
||||||
subgrid_pml_thickness=6,
|
# copy over the optional parameters
|
||||||
interpolation='linear',
|
kwargs['p1'] = p1
|
||||||
loss_mechanism=False,
|
kwargs['p2'] = p2
|
||||||
loss_factor=False,
|
kwargs['ratio'] = ratio
|
||||||
filter=True,
|
kwargs['ID'] = ID
|
||||||
**kwargs):
|
kwargs['is_os_sep'] = is_os_sep
|
||||||
"""Constructor."""
|
kwargs['pml_separation'] = pml_separation
|
||||||
|
kwargs['subgrid_pml_thickness'] = subgrid_pml_thickness
|
||||||
pml_separation = ratio // 2 + 2
|
kwargs['interpolation'] = interpolation
|
||||||
|
kwargs['filter'] = filter
|
||||||
# copy over the optional parameters
|
kwargs['loss_mechanism'] = loss_mechanism
|
||||||
kwargs['p1'] = p1
|
kwargs['loss_factor'] = loss_factor
|
||||||
kwargs['p2'] = p2
|
|
||||||
kwargs['ratio'] = ratio
|
super().__init__(**kwargs)
|
||||||
kwargs['ID'] = ID
|
self.order = 18
|
||||||
kwargs['is_os_sep'] = is_os_sep
|
self.hash = '#subgrid_hsg'
|
||||||
kwargs['pml_separation'] = pml_separation
|
|
||||||
kwargs['subgrid_pml_thickness'] = subgrid_pml_thickness
|
def create(self, grid, uip):
|
||||||
kwargs['interpolation'] = interpolation
|
sg = SubGridHSGUser(**self.kwargs)
|
||||||
kwargs['filter'] = filter
|
self.setup(sg, grid, uip)
|
||||||
kwargs['loss_mechanism'] = loss_mechanism
|
if config.is_messages():
|
||||||
kwargs['loss_factor'] = loss_factor
|
print(sg)
|
||||||
|
return sg
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.order = 18
|
|
||||||
self.hash = '#subgrid_hsg'
|
|
||||||
|
class ReferenceRx(Rx):
|
||||||
def create(self, grid, uip):
|
"""ReferenceRx User Object."""
|
||||||
sg = SubGridHSGUser(**self.kwargs)
|
|
||||||
self.setup(sg, grid, uip)
|
def __init__(self, **kwargs):
|
||||||
if config.is_messages():
|
super().__init__(**kwargs)
|
||||||
print(sg)
|
self.hash = '#rx_reference'
|
||||||
return sg
|
self.constructor = ReferenceRxUser
|
||||||
|
|
||||||
|
def create(self, grid, uip):
|
||||||
|
|
||||||
class ReferenceRx(Rx):
|
r = super().create(grid, uip)
|
||||||
"""ReferenceRx User Object."""
|
|
||||||
|
try:
|
||||||
def __init__(self, **kwargs):
|
ratio = self.kwargs['ratio']
|
||||||
super().__init__(**kwargs)
|
r.ratio = ratio
|
||||||
self.hash = '#rx_reference'
|
r.offset = ratio // 2
|
||||||
self.constructor = ReferenceRxUser
|
|
||||||
|
except KeyError:
|
||||||
def create(self, grid, uip):
|
raise CmdInputError("'{}' has an no ratio parameter".format(self.__str__()))
|
||||||
|
|
||||||
r = super().create(grid, uip)
|
|
||||||
|
|
||||||
try:
|
|
||||||
ratio = self.kwargs['ratio']
|
|
||||||
r.ratio = ratio
|
|
||||||
r.offset = ratio // 2
|
|
||||||
|
|
||||||
except KeyError:
|
|
||||||
raise CmdInputError("'{}' has an no ratio parameter".format(self.__str__()))
|
|
||||||
|
@@ -1,314 +1,314 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
cimport numpy as np
|
cimport numpy as np
|
||||||
from cython.parallel import prange
|
from cython.parallel import prange
|
||||||
|
|
||||||
cdef extern from "complex.h" nogil:
|
cdef extern from "complex.h" nogil:
|
||||||
double creal(double complex z)
|
double creal(double complex z)
|
||||||
float crealf(float complex z)
|
float crealf(float complex z)
|
||||||
|
|
||||||
|
|
||||||
###############################################################
|
###############################################################
|
||||||
# Electric field updates - dispersive materials - multipole A #
|
# Electric field updates - dispersive materials - multipole A #
|
||||||
###############################################################
|
###############################################################
|
||||||
|
|
||||||
{% for item in functions %}
|
{% for item in functions %}
|
||||||
cpdef void {{ item.name_a }}(
|
cpdef void {{ item.name_a }}(
|
||||||
int nx,
|
int nx,
|
||||||
int ny,
|
int ny,
|
||||||
int nz,
|
int nz,
|
||||||
int nthreads,
|
int nthreads,
|
||||||
int maxpoles,
|
int maxpoles,
|
||||||
{{ item.field_type }}[:, ::1] updatecoeffsE,
|
{{ item.field_type }}[:, ::1] updatecoeffsE,
|
||||||
{{ item.dispersive_type }}[:, ::1] updatecoeffsdispersive,
|
{{ item.dispersive_type }}[:, ::1] updatecoeffsdispersive,
|
||||||
np.uint32_t[:, :, :, ::1] ID,
|
np.uint32_t[:, :, :, ::1] ID,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Tx,
|
{{ item.dispersive_type }}[:, :, :, ::1] Tx,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Ty,
|
{{ item.dispersive_type }}[:, :, :, ::1] Ty,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Tz,
|
{{ item.dispersive_type }}[:, :, :, ::1] Tz,
|
||||||
{{ item.field_type }}[:, :, ::1] Ex,
|
{{ item.field_type }}[:, :, ::1] Ex,
|
||||||
{{ item.field_type }}[:, :, ::1] Ey,
|
{{ item.field_type }}[:, :, ::1] Ey,
|
||||||
{{ item.field_type }}[:, :, ::1] Ez,
|
{{ item.field_type }}[:, :, ::1] Ez,
|
||||||
{{ item.field_type }}[:, :, ::1] Hx,
|
{{ item.field_type }}[:, :, ::1] Hx,
|
||||||
{{ item.field_type }}[:, :, ::1] Hy,
|
{{ item.field_type }}[:, :, ::1] Hy,
|
||||||
{{ item.field_type }}[:, :, ::1] Hz
|
{{ item.field_type }}[:, :, ::1] Hz
|
||||||
):
|
):
|
||||||
"""This function updates the electric field components when dispersive materials (with multiple poles) are present.
|
"""This function updates the electric field components when dispersive materials (with multiple poles) are present.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
nx, ny, nz (int): Grid size in cells
|
nx, ny, nz (int): Grid size in cells
|
||||||
nthreads (int): Number of threads to use
|
nthreads (int): Number of threads to use
|
||||||
maxpoles (int): Maximum number of poles
|
maxpoles (int): Maximum number of poles
|
||||||
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cdef Py_ssize_t i, j, k, pole
|
cdef Py_ssize_t i, j, k, pole
|
||||||
cdef int material
|
cdef int material
|
||||||
cdef float phi = 0
|
cdef float phi = 0
|
||||||
|
|
||||||
# Ex component
|
# Ex component
|
||||||
if ny != 1 or nz != 1:
|
if ny != 1 or nz != 1:
|
||||||
for i in prange(0, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(0, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(1, ny):
|
for j in range(1, ny):
|
||||||
for k in range(1, nz):
|
for k in range(1, nz):
|
||||||
material = ID[0, i, j, k]
|
material = ID[0, i, j, k]
|
||||||
phi = 0
|
phi = 0
|
||||||
for pole in range(maxpoles):
|
for pole in range(maxpoles):
|
||||||
{% if 'complex' in item.dispersive_type %}
|
{% if 'complex' in item.dispersive_type %}
|
||||||
phi = phi + {{ item.real_part }}(updatecoeffsdispersive[material, pole * 3]) * {{ item.real_part }}(Tx[pole, i, j, k])
|
phi = phi + {{ item.real_part }}(updatecoeffsdispersive[material, pole * 3]) * {{ item.real_part }}(Tx[pole, i, j, k])
|
||||||
{% else %}
|
{% else %}
|
||||||
phi = phi + updatecoeffsdispersive[material, pole * 3] * Tx[pole, i, j, k]
|
phi = phi + updatecoeffsdispersive[material, pole * 3] * Tx[pole, i, j, k]
|
||||||
{% endif %}
|
{% endif %}
|
||||||
Tx[pole, i, j, k] = updatecoeffsdispersive[material, 1 + (pole * 3)] * Tx[pole, i, j, k] + updatecoeffsdispersive[material, 2 + (pole * 3)] * Ex[i, j, k]
|
Tx[pole, i, j, k] = updatecoeffsdispersive[material, 1 + (pole * 3)] * Tx[pole, i, j, k] + updatecoeffsdispersive[material, 2 + (pole * 3)] * Ex[i, j, k]
|
||||||
Ex[i, j, k] = updatecoeffsE[material, 0] * Ex[i, j, k] + updatecoeffsE[material, 2] * (Hz[i, j, k] - Hz[i, j - 1, k]) - updatecoeffsE[material, 3] * (Hy[i, j, k] - Hy[i, j, k - 1]) - updatecoeffsE[material, 4] * phi
|
Ex[i, j, k] = updatecoeffsE[material, 0] * Ex[i, j, k] + updatecoeffsE[material, 2] * (Hz[i, j, k] - Hz[i, j - 1, k]) - updatecoeffsE[material, 3] * (Hy[i, j, k] - Hy[i, j, k - 1]) - updatecoeffsE[material, 4] * phi
|
||||||
|
|
||||||
# Ey component
|
# Ey component
|
||||||
if nx != 1 or nz != 1:
|
if nx != 1 or nz != 1:
|
||||||
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(0, ny):
|
for j in range(0, ny):
|
||||||
for k in range(1, nz):
|
for k in range(1, nz):
|
||||||
material = ID[1, i, j, k]
|
material = ID[1, i, j, k]
|
||||||
phi = 0
|
phi = 0
|
||||||
for pole in range(maxpoles):
|
for pole in range(maxpoles):
|
||||||
{% if 'complex' in item.dispersive_type %}
|
{% if 'complex' in item.dispersive_type %}
|
||||||
phi = phi + {{ item.real_part }}(updatecoeffsdispersive[material, pole * 3]) * {{ item.real_part }}(Ty[pole, i, j, k])
|
phi = phi + {{ item.real_part }}(updatecoeffsdispersive[material, pole * 3]) * {{ item.real_part }}(Ty[pole, i, j, k])
|
||||||
{% else %}
|
{% else %}
|
||||||
phi = phi + updatecoeffsdispersive[material, pole * 3] * Ty[pole, i, j, k]
|
phi = phi + updatecoeffsdispersive[material, pole * 3] * Ty[pole, i, j, k]
|
||||||
{% endif %}
|
{% endif %}
|
||||||
Ty[pole, i, j, k] = updatecoeffsdispersive[material, 1 + (pole * 3)] * Ty[pole, i, j, k] + updatecoeffsdispersive[material, 2 + (pole * 3)] * Ey[i, j, k]
|
Ty[pole, i, j, k] = updatecoeffsdispersive[material, 1 + (pole * 3)] * Ty[pole, i, j, k] + updatecoeffsdispersive[material, 2 + (pole * 3)] * Ey[i, j, k]
|
||||||
Ey[i, j, k] = updatecoeffsE[material, 0] * Ey[i, j, k] + updatecoeffsE[material, 3] * (Hx[i, j, k] - Hx[i, j, k - 1]) - updatecoeffsE[material, 1] * (Hz[i, j, k] - Hz[i - 1, j, k]) - updatecoeffsE[material, 4] * phi
|
Ey[i, j, k] = updatecoeffsE[material, 0] * Ey[i, j, k] + updatecoeffsE[material, 3] * (Hx[i, j, k] - Hx[i, j, k - 1]) - updatecoeffsE[material, 1] * (Hz[i, j, k] - Hz[i - 1, j, k]) - updatecoeffsE[material, 4] * phi
|
||||||
|
|
||||||
# Ez component
|
# Ez component
|
||||||
if nx != 1 or ny != 1:
|
if nx != 1 or ny != 1:
|
||||||
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(1, ny):
|
for j in range(1, ny):
|
||||||
for k in range(0, nz):
|
for k in range(0, nz):
|
||||||
material = ID[2, i, j, k]
|
material = ID[2, i, j, k]
|
||||||
phi = 0
|
phi = 0
|
||||||
for pole in range(maxpoles):
|
for pole in range(maxpoles):
|
||||||
{% if 'complex' in item.dispersive_type %}
|
{% if 'complex' in item.dispersive_type %}
|
||||||
phi = phi + {{ item.real_part }}(updatecoeffsdispersive[material, pole * 3]) * {{ item.real_part }}(Tz[pole, i, j, k])
|
phi = phi + {{ item.real_part }}(updatecoeffsdispersive[material, pole * 3]) * {{ item.real_part }}(Tz[pole, i, j, k])
|
||||||
{% else %}
|
{% else %}
|
||||||
phi = phi + updatecoeffsdispersive[material, pole * 3] * Tz[pole, i, j, k]
|
phi = phi + updatecoeffsdispersive[material, pole * 3] * Tz[pole, i, j, k]
|
||||||
{% endif %}
|
{% endif %}
|
||||||
Tz[pole, i, j, k] = updatecoeffsdispersive[material, 1 + (pole * 3)] * Tz[pole, i, j, k] + updatecoeffsdispersive[material, 2 + (pole * 3)] * Ez[i, j, k]
|
Tz[pole, i, j, k] = updatecoeffsdispersive[material, 1 + (pole * 3)] * Tz[pole, i, j, k] + updatecoeffsdispersive[material, 2 + (pole * 3)] * Ez[i, j, k]
|
||||||
Ez[i, j, k] = updatecoeffsE[material, 0] * Ez[i, j, k] + updatecoeffsE[material, 1] * (Hy[i, j, k] - Hy[i - 1, j, k]) - updatecoeffsE[material, 2] * (Hx[i, j, k] - Hx[i, j - 1, k]) - updatecoeffsE[material, 4] * phi
|
Ez[i, j, k] = updatecoeffsE[material, 0] * Ez[i, j, k] + updatecoeffsE[material, 1] * (Hy[i, j, k] - Hy[i - 1, j, k]) - updatecoeffsE[material, 2] * (Hx[i, j, k] - Hx[i, j - 1, k]) - updatecoeffsE[material, 4] * phi
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
###############################################################
|
###############################################################
|
||||||
# Electric field updates - dispersive materials - multipole B #
|
# Electric field updates - dispersive materials - multipole B #
|
||||||
###############################################################
|
###############################################################
|
||||||
|
|
||||||
{% for item in functions %}
|
{% for item in functions %}
|
||||||
cpdef void {{ item.name_b }}(
|
cpdef void {{ item.name_b }}(
|
||||||
int nx,
|
int nx,
|
||||||
int ny,
|
int ny,
|
||||||
int nz,
|
int nz,
|
||||||
int nthreads,
|
int nthreads,
|
||||||
int maxpoles,
|
int maxpoles,
|
||||||
{{ item.dispersive_type }}[:, ::1] updatecoeffsdispersive,
|
{{ item.dispersive_type }}[:, ::1] updatecoeffsdispersive,
|
||||||
np.uint32_t[:, :, :, ::1] ID,
|
np.uint32_t[:, :, :, ::1] ID,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Tx,
|
{{ item.dispersive_type }}[:, :, :, ::1] Tx,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Ty,
|
{{ item.dispersive_type }}[:, :, :, ::1] Ty,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Tz,
|
{{ item.dispersive_type }}[:, :, :, ::1] Tz,
|
||||||
{{ item.field_type }}[:, :, ::1] Ex,
|
{{ item.field_type }}[:, :, ::1] Ex,
|
||||||
{{ item.field_type }}[:, :, ::1] Ey,
|
{{ item.field_type }}[:, :, ::1] Ey,
|
||||||
{{ item.field_type }}[:, :, ::1] Ez
|
{{ item.field_type }}[:, :, ::1] Ez
|
||||||
):
|
):
|
||||||
"""This function updates a temporary dispersive material array when disperisive materials (with multiple poles) are present.
|
"""This function updates a temporary dispersive material array when disperisive materials (with multiple poles) are present.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
nx, ny, nz (int): Grid size in cells
|
nx, ny, nz (int): Grid size in cells
|
||||||
nthreads (int): Number of threads to use
|
nthreads (int): Number of threads to use
|
||||||
maxpoles (int): Maximum number of poles
|
maxpoles (int): Maximum number of poles
|
||||||
updatecoeffs, T, ID, E (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
updatecoeffs, T, ID, E (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cdef Py_ssize_t i, j, k, pole
|
cdef Py_ssize_t i, j, k, pole
|
||||||
cdef int material
|
cdef int material
|
||||||
|
|
||||||
# Ex component
|
# Ex component
|
||||||
if ny != 1 or nz != 1:
|
if ny != 1 or nz != 1:
|
||||||
for i in prange(0, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(0, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(1, ny):
|
for j in range(1, ny):
|
||||||
for k in range(1, nz):
|
for k in range(1, nz):
|
||||||
material = ID[0, i, j, k]
|
material = ID[0, i, j, k]
|
||||||
for pole in range(maxpoles):
|
for pole in range(maxpoles):
|
||||||
Tx[pole, i, j, k] = Tx[pole, i, j, k] - updatecoeffsdispersive[material, 2 + (pole * 3)] * Ex[i, j, k]
|
Tx[pole, i, j, k] = Tx[pole, i, j, k] - updatecoeffsdispersive[material, 2 + (pole * 3)] * Ex[i, j, k]
|
||||||
|
|
||||||
# Ey component
|
# Ey component
|
||||||
if nx != 1 or nz != 1:
|
if nx != 1 or nz != 1:
|
||||||
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(0, ny):
|
for j in range(0, ny):
|
||||||
for k in range(1, nz):
|
for k in range(1, nz):
|
||||||
material = ID[1, i, j, k]
|
material = ID[1, i, j, k]
|
||||||
for pole in range(maxpoles):
|
for pole in range(maxpoles):
|
||||||
Ty[pole, i, j, k] = Ty[pole, i, j, k] - updatecoeffsdispersive[material, 2 + (pole * 3)] * Ey[i, j, k]
|
Ty[pole, i, j, k] = Ty[pole, i, j, k] - updatecoeffsdispersive[material, 2 + (pole * 3)] * Ey[i, j, k]
|
||||||
|
|
||||||
# Ez component
|
# Ez component
|
||||||
if nx != 1 or ny != 1:
|
if nx != 1 or ny != 1:
|
||||||
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(1, ny):
|
for j in range(1, ny):
|
||||||
for k in range(0, nz):
|
for k in range(0, nz):
|
||||||
material = ID[2, i, j, k]
|
material = ID[2, i, j, k]
|
||||||
for pole in range(maxpoles):
|
for pole in range(maxpoles):
|
||||||
Tz[pole, i, j, k] = Tz[pole, i, j, k] - updatecoeffsdispersive[material, 2 + (pole * 3)] * Ez[i, j, k]
|
Tz[pole, i, j, k] = Tz[pole, i, j, k] - updatecoeffsdispersive[material, 2 + (pole * 3)] * Ez[i, j, k]
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
#################################################################
|
#################################################################
|
||||||
# Electric field updates - dispersive materials - single pole A #
|
# Electric field updates - dispersive materials - single pole A #
|
||||||
#################################################################
|
#################################################################
|
||||||
|
|
||||||
{% for item in functions %}
|
{% for item in functions %}
|
||||||
cpdef void {{ item.name_a_1 }}(
|
cpdef void {{ item.name_a_1 }}(
|
||||||
int nx,
|
int nx,
|
||||||
int ny,
|
int ny,
|
||||||
int nz,
|
int nz,
|
||||||
int nthreads,
|
int nthreads,
|
||||||
int maxpoles,
|
int maxpoles,
|
||||||
{{ item.field_type }}[:, ::1] updatecoeffsE,
|
{{ item.field_type }}[:, ::1] updatecoeffsE,
|
||||||
{{ item.dispersive_type }}[:, ::1] updatecoeffsdispersive,
|
{{ item.dispersive_type }}[:, ::1] updatecoeffsdispersive,
|
||||||
np.uint32_t[:, :, :, ::1] ID,
|
np.uint32_t[:, :, :, ::1] ID,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Tx,
|
{{ item.dispersive_type }}[:, :, :, ::1] Tx,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Ty,
|
{{ item.dispersive_type }}[:, :, :, ::1] Ty,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Tz,
|
{{ item.dispersive_type }}[:, :, :, ::1] Tz,
|
||||||
{{ item.field_type }}[:, :, ::1] Ex,
|
{{ item.field_type }}[:, :, ::1] Ex,
|
||||||
{{ item.field_type }}[:, :, ::1] Ey,
|
{{ item.field_type }}[:, :, ::1] Ey,
|
||||||
{{ item.field_type }}[:, :, ::1] Ez,
|
{{ item.field_type }}[:, :, ::1] Ez,
|
||||||
{{ item.field_type }}[:, :, ::1] Hx,
|
{{ item.field_type }}[:, :, ::1] Hx,
|
||||||
{{ item.field_type }}[:, :, ::1] Hy,
|
{{ item.field_type }}[:, :, ::1] Hy,
|
||||||
{{ item.field_type }}[:, :, ::1] Hz
|
{{ item.field_type }}[:, :, ::1] Hz
|
||||||
):
|
):
|
||||||
"""This function updates the electric field components when dispersive materials (with 1 pole) are present.
|
"""This function updates the electric field components when dispersive materials (with 1 pole) are present.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
nx, ny, nz (int): Grid size in cells
|
nx, ny, nz (int): Grid size in cells
|
||||||
nthreads (int): Number of threads to use
|
nthreads (int): Number of threads to use
|
||||||
maxpoles (int): Maximum number of poles
|
maxpoles (int): Maximum number of poles
|
||||||
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
updatecoeffs, T, ID, E, H (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cdef Py_ssize_t i, j, k
|
cdef Py_ssize_t i, j, k
|
||||||
cdef int material
|
cdef int material
|
||||||
cdef float phi = 0
|
cdef float phi = 0
|
||||||
|
|
||||||
# Ex component
|
# Ex component
|
||||||
if ny != 1 or nz != 1:
|
if ny != 1 or nz != 1:
|
||||||
for i in prange(0, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(0, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(1, ny):
|
for j in range(1, ny):
|
||||||
for k in range(1, nz):
|
for k in range(1, nz):
|
||||||
material = ID[0, i, j, k]
|
material = ID[0, i, j, k]
|
||||||
{% if 'complex' in item.dispersive_type %}
|
{% if 'complex' in item.dispersive_type %}
|
||||||
phi = {{ item.real_part }}(updatecoeffsdispersive[material, 0]) * {{ item.real_part }}(Tx[0, i, j, k])
|
phi = {{ item.real_part }}(updatecoeffsdispersive[material, 0]) * {{ item.real_part }}(Tx[0, i, j, k])
|
||||||
{% else %}
|
{% else %}
|
||||||
phi = updatecoeffsdispersive[material, 0] * Tx[0, i, j, k]
|
phi = updatecoeffsdispersive[material, 0] * Tx[0, i, j, k]
|
||||||
{% endif %}
|
{% endif %}
|
||||||
Tx[0, i, j, k] = updatecoeffsdispersive[material, 1] * Tx[0, i, j, k] + updatecoeffsdispersive[material, 2] * Ex[i, j, k]
|
Tx[0, i, j, k] = updatecoeffsdispersive[material, 1] * Tx[0, i, j, k] + updatecoeffsdispersive[material, 2] * Ex[i, j, k]
|
||||||
Ex[i, j, k] = updatecoeffsE[material, 0] * Ex[i, j, k] + updatecoeffsE[material, 2] * (Hz[i, j, k] - Hz[i, j - 1, k]) - updatecoeffsE[material, 3] * (Hy[i, j, k] - Hy[i, j, k - 1]) - updatecoeffsE[material, 4] * phi
|
Ex[i, j, k] = updatecoeffsE[material, 0] * Ex[i, j, k] + updatecoeffsE[material, 2] * (Hz[i, j, k] - Hz[i, j - 1, k]) - updatecoeffsE[material, 3] * (Hy[i, j, k] - Hy[i, j, k - 1]) - updatecoeffsE[material, 4] * phi
|
||||||
|
|
||||||
# Ey component
|
# Ey component
|
||||||
if nx != 1 or nz != 1:
|
if nx != 1 or nz != 1:
|
||||||
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(0, ny):
|
for j in range(0, ny):
|
||||||
for k in range(1, nz):
|
for k in range(1, nz):
|
||||||
material = ID[1, i, j, k]
|
material = ID[1, i, j, k]
|
||||||
{% if 'complex' in item.dispersive_type %}
|
{% if 'complex' in item.dispersive_type %}
|
||||||
phi = {{ item.real_part }}(updatecoeffsdispersive[material, 0]) * {{ item.real_part }}(Ty[0, i, j, k])
|
phi = {{ item.real_part }}(updatecoeffsdispersive[material, 0]) * {{ item.real_part }}(Ty[0, i, j, k])
|
||||||
{% else %}
|
{% else %}
|
||||||
phi = updatecoeffsdispersive[material, 0] * Ty[0, i, j, k]
|
phi = updatecoeffsdispersive[material, 0] * Ty[0, i, j, k]
|
||||||
{% endif %}
|
{% endif %}
|
||||||
Ty[0, i, j, k] = updatecoeffsdispersive[material, 1] * Ty[0, i, j, k] + updatecoeffsdispersive[material, 2] * Ey[i, j, k]
|
Ty[0, i, j, k] = updatecoeffsdispersive[material, 1] * Ty[0, i, j, k] + updatecoeffsdispersive[material, 2] * Ey[i, j, k]
|
||||||
Ey[i, j, k] = updatecoeffsE[material, 0] * Ey[i, j, k] + updatecoeffsE[material, 3] * (Hx[i, j, k] - Hx[i, j, k - 1]) - updatecoeffsE[material, 1] * (Hz[i, j, k] - Hz[i - 1, j, k]) - updatecoeffsE[material, 4] * phi
|
Ey[i, j, k] = updatecoeffsE[material, 0] * Ey[i, j, k] + updatecoeffsE[material, 3] * (Hx[i, j, k] - Hx[i, j, k - 1]) - updatecoeffsE[material, 1] * (Hz[i, j, k] - Hz[i - 1, j, k]) - updatecoeffsE[material, 4] * phi
|
||||||
|
|
||||||
# Ez component
|
# Ez component
|
||||||
if nx != 1 or ny != 1:
|
if nx != 1 or ny != 1:
|
||||||
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(1, ny):
|
for j in range(1, ny):
|
||||||
for k in range(0, nz):
|
for k in range(0, nz):
|
||||||
material = ID[2, i, j, k]
|
material = ID[2, i, j, k]
|
||||||
{% if 'complex' in item.dispersive_type %}
|
{% if 'complex' in item.dispersive_type %}
|
||||||
phi = {{ item.real_part }}(updatecoeffsdispersive[material, 0]) * {{ item.real_part }}(Tz[0, i, j, k])
|
phi = {{ item.real_part }}(updatecoeffsdispersive[material, 0]) * {{ item.real_part }}(Tz[0, i, j, k])
|
||||||
{% else %}
|
{% else %}
|
||||||
phi = updatecoeffsdispersive[material, 0] * Tz[0, i, j, k]
|
phi = updatecoeffsdispersive[material, 0] * Tz[0, i, j, k]
|
||||||
{% endif %}
|
{% endif %}
|
||||||
Tz[0, i, j, k] = updatecoeffsdispersive[material, 1] * Tz[0, i, j, k] + updatecoeffsdispersive[material, 2] * Ez[i, j, k]
|
Tz[0, i, j, k] = updatecoeffsdispersive[material, 1] * Tz[0, i, j, k] + updatecoeffsdispersive[material, 2] * Ez[i, j, k]
|
||||||
Ez[i, j, k] = updatecoeffsE[material, 0] * Ez[i, j, k] + updatecoeffsE[material, 1] * (Hy[i, j, k] - Hy[i - 1, j, k]) - updatecoeffsE[material, 2] * (Hx[i, j, k] - Hx[i, j - 1, k]) - updatecoeffsE[material, 4] * phi
|
Ez[i, j, k] = updatecoeffsE[material, 0] * Ez[i, j, k] + updatecoeffsE[material, 1] * (Hy[i, j, k] - Hy[i - 1, j, k]) - updatecoeffsE[material, 2] * (Hx[i, j, k] - Hx[i, j - 1, k]) - updatecoeffsE[material, 4] * phi
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
#################################################################
|
#################################################################
|
||||||
# Electric field updates - dispersive materials - single pole B #
|
# Electric field updates - dispersive materials - single pole B #
|
||||||
#################################################################
|
#################################################################
|
||||||
|
|
||||||
{% for item in functions %}
|
{% for item in functions %}
|
||||||
cpdef void {{ item.name_b_1 }}(
|
cpdef void {{ item.name_b_1 }}(
|
||||||
int nx,
|
int nx,
|
||||||
int ny,
|
int ny,
|
||||||
int nz,
|
int nz,
|
||||||
int nthreads,
|
int nthreads,
|
||||||
int maxpoles,
|
int maxpoles,
|
||||||
{{ item.dispersive_type }}[:, ::1] updatecoeffsdispersive,
|
{{ item.dispersive_type }}[:, ::1] updatecoeffsdispersive,
|
||||||
np.uint32_t[:, :, :, ::1] ID,
|
np.uint32_t[:, :, :, ::1] ID,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Tx,
|
{{ item.dispersive_type }}[:, :, :, ::1] Tx,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Ty,
|
{{ item.dispersive_type }}[:, :, :, ::1] Ty,
|
||||||
{{ item.dispersive_type }}[:, :, :, ::1] Tz,
|
{{ item.dispersive_type }}[:, :, :, ::1] Tz,
|
||||||
{{ item.field_type }}[:, :, ::1] Ex,
|
{{ item.field_type }}[:, :, ::1] Ex,
|
||||||
{{ item.field_type }}[:, :, ::1] Ey,
|
{{ item.field_type }}[:, :, ::1] Ey,
|
||||||
{{ item.field_type }}[:, :, ::1] Ez
|
{{ item.field_type }}[:, :, ::1] Ez
|
||||||
):
|
):
|
||||||
"""This function updates a temporary dispersive material array when disperisive materials (with 1 pole) are present.
|
"""This function updates a temporary dispersive material array when disperisive materials (with 1 pole) are present.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
nx, ny, nz (int): Grid size in cells
|
nx, ny, nz (int): Grid size in cells
|
||||||
nthreads (int): Number of threads to use
|
nthreads (int): Number of threads to use
|
||||||
maxpoles (int): Maximum number of poles
|
maxpoles (int): Maximum number of poles
|
||||||
updatecoeffs, T, ID, E (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
updatecoeffs, T, ID, E (memoryviews): Access to update coeffients, temporary, ID and field component arrays
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cdef Py_ssize_t i, j, k
|
cdef Py_ssize_t i, j, k
|
||||||
cdef int material
|
cdef int material
|
||||||
|
|
||||||
# Ex component
|
# Ex component
|
||||||
if ny != 1 or nz != 1:
|
if ny != 1 or nz != 1:
|
||||||
for i in prange(0, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(0, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(1, ny):
|
for j in range(1, ny):
|
||||||
for k in range(1, nz):
|
for k in range(1, nz):
|
||||||
material = ID[0, i, j, k]
|
material = ID[0, i, j, k]
|
||||||
Tx[0, i, j, k] = Tx[0, i, j, k] - updatecoeffsdispersive[material, 2] * Ex[i, j, k]
|
Tx[0, i, j, k] = Tx[0, i, j, k] - updatecoeffsdispersive[material, 2] * Ex[i, j, k]
|
||||||
|
|
||||||
# Ey component
|
# Ey component
|
||||||
if nx != 1 or nz != 1:
|
if nx != 1 or nz != 1:
|
||||||
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(0, ny):
|
for j in range(0, ny):
|
||||||
for k in range(1, nz):
|
for k in range(1, nz):
|
||||||
material = ID[1, i, j, k]
|
material = ID[1, i, j, k]
|
||||||
Ty[0, i, j, k] = Ty[0, i, j, k] - updatecoeffsdispersive[material, 2] * Ey[i, j, k]
|
Ty[0, i, j, k] = Ty[0, i, j, k] - updatecoeffsdispersive[material, 2] * Ey[i, j, k]
|
||||||
|
|
||||||
# Ez component
|
# Ez component
|
||||||
if nx != 1 or ny != 1:
|
if nx != 1 or ny != 1:
|
||||||
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
for i in prange(1, nx, nogil=True, schedule='static', num_threads=nthreads):
|
||||||
for j in range(1, ny):
|
for j in range(1, ny):
|
||||||
for k in range(0, nz):
|
for k in range(0, nz):
|
||||||
material = ID[2, i, j, k]
|
material = ID[2, i, j, k]
|
||||||
Tz[0, i, j, k] = Tz[0, i, j, k] - updatecoeffsdispersive[material, 2] * Ez[i, j, k]
|
Tz[0, i, j, k] = Tz[0, i, j, k] - updatecoeffsdispersive[material, 2] * Ez[i, j, k]
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@@ -1,185 +1,186 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from gprMax.fields_outputs import store_outputs
|
from gprMax.fields_outputs import store_outputs
|
||||||
import gprMax.config as config
|
import gprMax.config as config
|
||||||
from gprMax.cython.fields_updates_normal import update_electric
|
from gprMax.cython.fields_updates_normal import update_electric
|
||||||
from gprMax.cython.fields_updates_normal import update_magnetic
|
from gprMax.cython.fields_updates_normal import update_magnetic
|
||||||
|
|
||||||
|
|
||||||
class CPUUpdates:
|
class CPUUpdates:
|
||||||
|
|
||||||
def __init__(self, G):
|
def __init__(self, G):
|
||||||
self.grid = G
|
self.grid = G
|
||||||
self.dispersive_update_a = None
|
self.dispersive_update_a = None
|
||||||
self.dispersive_update_b = None
|
self.dispersive_update_b = None
|
||||||
|
|
||||||
def store_outputs(self):
|
def store_outputs(self):
|
||||||
# Store field component values for every receiver and transmission line
|
# Store field component values for every receiver and transmission line
|
||||||
store_outputs(self.grid)
|
store_outputs(self.grid)
|
||||||
|
|
||||||
def store_snapshots(self, iteration):
|
def store_snapshots(self, iteration):
|
||||||
# Store any snapshots
|
# Store any snapshots
|
||||||
for snap in self.grid.snapshots:
|
for snap in self.grid.snapshots:
|
||||||
if snap.time == iteration + 1:
|
if snap.time == iteration + 1:
|
||||||
snap.store(self.grid)
|
snap.store(self.grid)
|
||||||
|
|
||||||
def update_magnetic(self):
|
def update_magnetic(self):
|
||||||
# Update magnetic field components
|
# Update magnetic field components
|
||||||
update_magnetic(self.grid.nx,
|
update_magnetic(self.grid.nx,
|
||||||
self.grid.ny,
|
self.grid.ny,
|
||||||
self.grid.nz,
|
self.grid.nz,
|
||||||
config.hostinfo['ompthreads'],
|
config.hostinfo['ompthreads'],
|
||||||
self.grid.updatecoeffsH,
|
self.grid.updatecoeffsH,
|
||||||
self.grid.ID,
|
self.grid.ID,
|
||||||
self.grid.Ex,
|
self.grid.Ex,
|
||||||
self.grid.Ey,
|
self.grid.Ey,
|
||||||
self.grid.Ez,
|
self.grid.Ez,
|
||||||
self.grid.Hx,
|
self.grid.Hx,
|
||||||
self.grid.Hy,
|
self.grid.Hy,
|
||||||
self.grid.Hz)
|
self.grid.Hz)
|
||||||
|
|
||||||
def update_magnetic_pml(self):
|
def update_magnetic_pml(self):
|
||||||
# Update magnetic field components with the PML correction
|
# Update magnetic field components with the PML correction
|
||||||
for pml in self.grid.pmls:
|
for pml in self.grid.pmls:
|
||||||
pml.update_magnetic(self.grid)
|
pml.update_magnetic(self.grid)
|
||||||
|
|
||||||
def update_magnetic_sources(self, iteration):
|
def update_magnetic_sources(self):
|
||||||
# Update magnetic field components from sources
|
# Update magnetic field components from sources
|
||||||
for source in self.grid.transmissionlines + self.grid.magneticdipoles:
|
for source in self.grid.transmissionlines + self.grid.magneticdipoles:
|
||||||
source.update_magnetic(iteration,
|
source.update_magnetic(self.grid.iteration,
|
||||||
self.grid.updatecoeffsH,
|
self.grid.updatecoeffsH,
|
||||||
self.grid.ID,
|
self.grid.ID,
|
||||||
self.grid.Hx,
|
self.grid.Hx,
|
||||||
self.grid.Hy,
|
self.grid.Hy,
|
||||||
self.grid.Hz,
|
self.grid.Hz,
|
||||||
self.grid)
|
self.grid)
|
||||||
|
|
||||||
def update_electric_a(self):
|
def update_electric_a(self):
|
||||||
# Update electric field components
|
# Update electric field components
|
||||||
# All materials are non-dispersive so do standard update
|
# All materials are non-dispersive so do standard update
|
||||||
if config.materials['maxpoles'] == 0:
|
if config.materials['maxpoles'] == 0:
|
||||||
update_electric(self.grid.nx,
|
update_electric(self.grid.nx,
|
||||||
self.grid.ny,
|
self.grid.ny,
|
||||||
self.grid.nz,
|
self.grid.nz,
|
||||||
config.hostinfo['ompthreads'],
|
config.hostinfo['ompthreads'],
|
||||||
self.grid.updatecoeffsE,
|
self.grid.updatecoeffsE,
|
||||||
self.grid.ID,
|
self.grid.ID,
|
||||||
self.grid.Ex,
|
self.grid.Ex,
|
||||||
self.grid.Ey,
|
self.grid.Ey,
|
||||||
self.grid.Ez,
|
self.grid.Ez,
|
||||||
self.grid.Hx,
|
self.grid.Hx,
|
||||||
self.grid.Hy,
|
self.grid.Hy,
|
||||||
self.grid.Hz)
|
self.grid.Hz)
|
||||||
|
|
||||||
# If there are any dispersive materials do 1st part of dispersive update
|
# If there are any dispersive materials do 1st part of dispersive update
|
||||||
# (it is split into two parts as it requires present and updated electric field values).
|
# (it is split into two parts as it requires present and updated electric field values).
|
||||||
else:
|
else:
|
||||||
self.dispersive_update_a(self.grid.nx,
|
self.dispersive_update_a(self.grid.nx,
|
||||||
self.grid.ny,
|
self.grid.ny,
|
||||||
self.grid.nz,
|
self.grid.nz,
|
||||||
config.hostinfo['ompthreads'],
|
config.hostinfo['ompthreads'],
|
||||||
config.materials['maxpoles'],
|
config.materials['maxpoles'],
|
||||||
self.grid.updatecoeffsE,
|
self.grid.updatecoeffsE,
|
||||||
self.grid.updatecoeffsdispersive,
|
self.grid.updatecoeffsdispersive,
|
||||||
self.grid.ID,
|
self.grid.ID,
|
||||||
self.grid.Tx,
|
self.grid.Tx,
|
||||||
self.grid.Ty,
|
self.grid.Ty,
|
||||||
self.grid.Tz,
|
self.grid.Tz,
|
||||||
self.grid.Ex,
|
self.grid.Ex,
|
||||||
self.grid.Ey,
|
self.grid.Ey,
|
||||||
self.grid.Ez,
|
self.grid.Ez,
|
||||||
self.grid.Hx,
|
self.grid.Hx,
|
||||||
self.grid.Hy,
|
self.grid.Hy,
|
||||||
self.grid.Hz)
|
self.grid.Hz)
|
||||||
|
|
||||||
def update_electric_pml(self):
|
def update_electric_pml(self):
|
||||||
# Update electric field components with the PML correction
|
# Update electric field components with the PML correction
|
||||||
for pml in self.grid.pmls:
|
for pml in self.grid.pmls:
|
||||||
pml.update_electric(self.grid)
|
pml.update_electric(self.grid)
|
||||||
|
|
||||||
def update_electric_sources(self, iteration):
|
def update_electric_sources(self):
|
||||||
# Update electric field components from sources (update any Hertzian dipole sources last)
|
# Update electric field components from sources (update any Hertzian dipole sources last)
|
||||||
for source in self.grid.voltagesources + self.grid.transmissionlines + self.grid.hertziandipoles:
|
for source in self.grid.voltagesources + self.grid.transmissionlines + self.grid.hertziandipoles:
|
||||||
source.update_electric(iteration, self.grid.updatecoeffsE, self.grid.ID, self.grid.Ex, self.grid.Ey, self.grid.Ez, self.grid)
|
source.update_electric(self.grid.iteration, self.grid.updatecoeffsE, self.grid.ID, self.grid.Ex, self.grid.Ey, self.grid.Ez, self.grid)
|
||||||
|
self.grid.iteration += 1
|
||||||
def update_electric_b(self):
|
|
||||||
# If there are any dispersive materials do 2nd part of dispersive update
|
def update_electric_b(self):
|
||||||
# (it is split into two parts as it requires present and updated electric
|
# If there are any dispersive materials do 2nd part of dispersive update
|
||||||
# field values). Therefore it can only be completely updated after the
|
# (it is split into two parts as it requires present and updated electric
|
||||||
# electric field has been updated by the PML and source updates.
|
# field values). Therefore it can only be completely updated after the
|
||||||
if config.materials['maxpoles'] != 0:
|
# electric field has been updated by the PML and source updates.
|
||||||
self.dispersive_update_b(self.grid.nx,
|
if config.materials['maxpoles'] != 0:
|
||||||
self.grid.ny,
|
self.dispersive_update_b(self.grid.nx,
|
||||||
self.grid.nz,
|
self.grid.ny,
|
||||||
config.hostinfo['ompthreads'],
|
self.grid.nz,
|
||||||
config.materials['maxpoles'],
|
config.hostinfo['ompthreads'],
|
||||||
self.grid.updatecoeffsdispersive,
|
config.materials['maxpoles'],
|
||||||
self.grid.ID,
|
self.grid.updatecoeffsdispersive,
|
||||||
self.grid.Tx,
|
self.grid.ID,
|
||||||
self.grid.Ty,
|
self.grid.Tx,
|
||||||
self.grid.Tz,
|
self.grid.Ty,
|
||||||
self.grid.Ex,
|
self.grid.Tz,
|
||||||
self.grid.Ey,
|
self.grid.Ex,
|
||||||
self.grid.Ez)
|
self.grid.Ey,
|
||||||
|
self.grid.Ez)
|
||||||
def adapt_dispersive_config(self, config):
|
|
||||||
|
def adapt_dispersive_config(self, config):
|
||||||
if config.materials['maxpoles'] > 1:
|
|
||||||
poles = 'multi'
|
if config.materials['maxpoles'] > 1:
|
||||||
|
poles = 'multi'
|
||||||
else:
|
|
||||||
poles = '1'
|
else:
|
||||||
|
poles = '1'
|
||||||
if config.precision == 'single':
|
|
||||||
type = 'float'
|
if config.precision == 'single':
|
||||||
|
type = 'float'
|
||||||
else:
|
|
||||||
type = 'double'
|
else:
|
||||||
|
type = 'double'
|
||||||
if config.materials['dispersivedtype'] == config.dtypes['complex']:
|
|
||||||
dispersion = 'complex'
|
if config.materials['dispersivedtype'] == config.dtypes['complex']:
|
||||||
else:
|
dispersion = 'complex'
|
||||||
dispersion = 'real'
|
else:
|
||||||
|
dispersion = 'real'
|
||||||
class Props():
|
|
||||||
pass
|
class Props():
|
||||||
|
pass
|
||||||
props = Props()
|
|
||||||
props.poles = poles
|
props = Props()
|
||||||
props.precision = type
|
props.poles = poles
|
||||||
props.dispersion_type = dispersion
|
props.precision = type
|
||||||
|
props.dispersion_type = dispersion
|
||||||
return props
|
|
||||||
|
return props
|
||||||
def set_dispersive_updates(self, props):
|
|
||||||
"""Function to set dispersive update functions based on model."""
|
def set_dispersive_updates(self, props):
|
||||||
|
"""Function to set dispersive update functions based on model."""
|
||||||
update_f = 'update_electric_dispersive_{}pole_{}_{}_{}'
|
|
||||||
disp_a = update_f.format(props.poles, 'A', props.precision, props.dispersion_type)
|
update_f = 'update_electric_dispersive_{}pole_{}_{}_{}'
|
||||||
disp_b = update_f.format(props.poles, 'B', props.precision, props.dispersion_type)
|
disp_a = update_f.format(props.poles, 'A', props.precision, props.dispersion_type)
|
||||||
|
disp_b = update_f.format(props.poles, 'B', props.precision, props.dispersion_type)
|
||||||
disp_a_f = getattr(import_module('gprMax.cython.fields_updates_dispersive'), disp_a)
|
|
||||||
disp_b_f = getattr(import_module('gprMax.cython.fields_updates_dispersive'), disp_b)
|
disp_a_f = getattr(import_module('gprMax.cython.fields_updates_dispersive'), disp_a)
|
||||||
|
disp_b_f = getattr(import_module('gprMax.cython.fields_updates_dispersive'), disp_b)
|
||||||
self.dispersive_update_a = disp_a_f
|
|
||||||
self.dispersive_update_b = disp_b_f
|
self.dispersive_update_a = disp_a_f
|
||||||
|
self.dispersive_update_b = disp_b_f
|
||||||
|
|
||||||
class GPUUpdates:
|
|
||||||
pass
|
class GPUUpdates:
|
||||||
|
pass
|
||||||
|
@@ -1,430 +1,430 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
import codecs
|
import codecs
|
||||||
import decimal as d
|
import decimal as d
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import psutil
|
import psutil
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
from shutil import get_terminal_size
|
from shutil import get_terminal_size
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
|
|
||||||
from colorama import init
|
from colorama import init
|
||||||
from colorama import Fore
|
from colorama import Fore
|
||||||
from colorama import Style
|
from colorama import Style
|
||||||
init()
|
init()
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from .exceptions import GeneralError
|
from .exceptions import GeneralError
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_terminal_width():
|
def get_terminal_width():
|
||||||
"""Get/set width of terminal being used.
|
"""Get/set width of terminal being used.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
terminalwidth (int): Terminal width
|
terminalwidth (int): Terminal width
|
||||||
"""
|
"""
|
||||||
|
|
||||||
terminalwidth = get_terminal_size()[0]
|
terminalwidth = get_terminal_size()[0]
|
||||||
if terminalwidth == 0:
|
if terminalwidth == 0:
|
||||||
terminalwidth = 100
|
terminalwidth = 100
|
||||||
|
|
||||||
return terminalwidth
|
return terminalwidth
|
||||||
|
|
||||||
|
|
||||||
def logo(version):
|
def logo(version):
|
||||||
"""Print gprMax logo, version, and licencing/copyright information.
|
"""Print gprMax logo, version, and licencing/copyright information.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
version (str): Version number.
|
version (str): Version number.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
description = '\n=== Electromagnetic modelling software based on the Finite-Difference Time-Domain (FDTD) method'
|
description = '\n=== Electromagnetic modelling software based on the Finite-Difference Time-Domain (FDTD) method'
|
||||||
copyright = 'Copyright (C) 2015-2019: The University of Edinburgh'
|
copyright = 'Copyright (C) 2015-2019: The University of Edinburgh'
|
||||||
authors = 'Authors: Craig Warren and Antonis Giannopoulos'
|
authors = 'Authors: Craig Warren and Antonis Giannopoulos'
|
||||||
licenseinfo1 = '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.\n'
|
licenseinfo1 = '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.\n'
|
||||||
licenseinfo2 = '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.'
|
licenseinfo2 = '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.'
|
||||||
licenseinfo3 = 'You should have received a copy of the GNU General Public License along with gprMax. If not, see www.gnu.org/licenses.'
|
licenseinfo3 = 'You should have received a copy of the GNU General Public License along with gprMax. If not, see www.gnu.org/licenses.'
|
||||||
|
|
||||||
logo = """ www.gprmax.com __ __
|
logo = """ www.gprmax.com __ __
|
||||||
__ _ _ __ _ __| \/ | __ ___ __
|
__ _ _ __ _ __| \/ | __ ___ __
|
||||||
/ _` | '_ \| '__| |\/| |/ _` \ \/ /
|
/ _` | '_ \| '__| |\/| |/ _` \ \/ /
|
||||||
| (_| | |_) | | | | | | (_| |> <
|
| (_| | |_) | | | | | | (_| |> <
|
||||||
\__, | .__/|_| |_| |_|\__,_/_/\_\\
|
\__, | .__/|_| |_| |_|\__,_/_/\_\\
|
||||||
|___/|_|
|
|___/|_|
|
||||||
v""" + version
|
v""" + version
|
||||||
|
|
||||||
print('{} {}\n'.format(description, '=' * (get_terminal_width() - len(description) - 1)))
|
print('{} {}\n'.format(description, '=' * (get_terminal_width() - len(description) - 1)))
|
||||||
print(Fore.CYAN + '{}\n'.format(logo))
|
print(Fore.CYAN + '{}\n'.format(logo))
|
||||||
print(Style.RESET_ALL + textwrap.fill(copyright, width=get_terminal_width() - 1, initial_indent=' '))
|
print(Style.RESET_ALL + textwrap.fill(copyright, width=get_terminal_width() - 1, initial_indent=' '))
|
||||||
print(textwrap.fill(authors, width=get_terminal_width() - 1, initial_indent=' '))
|
print(textwrap.fill(authors, width=get_terminal_width() - 1, initial_indent=' '))
|
||||||
print()
|
print()
|
||||||
print(textwrap.fill(licenseinfo1, width=get_terminal_width() - 1, initial_indent=' ', subsequent_indent=' '))
|
print(textwrap.fill(licenseinfo1, width=get_terminal_width() - 1, initial_indent=' ', subsequent_indent=' '))
|
||||||
print(textwrap.fill(licenseinfo2, width=get_terminal_width() - 1, initial_indent=' ', subsequent_indent=' '))
|
print(textwrap.fill(licenseinfo2, width=get_terminal_width() - 1, initial_indent=' ', subsequent_indent=' '))
|
||||||
print(textwrap.fill(licenseinfo3, width=get_terminal_width() - 1, initial_indent=' ', subsequent_indent=' '))
|
print(textwrap.fill(licenseinfo3, width=get_terminal_width() - 1, initial_indent=' ', subsequent_indent=' '))
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def open_path_file(path_or_file):
|
def open_path_file(path_or_file):
|
||||||
"""Accepts either a path as a string or a file object and returns a 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:
|
Args:
|
||||||
path_or_file: path as a string or a file object.
|
path_or_file: path as a string or a file object.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
f (object): File object.
|
f (object): File object.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if isinstance(path_or_file, str):
|
if isinstance(path_or_file, str):
|
||||||
f = file_to_close = codecs.open(path_or_file, 'r', encoding='utf-8')
|
f = file_to_close = codecs.open(path_or_file, 'r', encoding='utf-8')
|
||||||
else:
|
else:
|
||||||
f = path_or_file
|
f = path_or_file
|
||||||
file_to_close = None
|
file_to_close = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yield f
|
yield f
|
||||||
finally:
|
finally:
|
||||||
if file_to_close:
|
if file_to_close:
|
||||||
file_to_close.close()
|
file_to_close.close()
|
||||||
|
|
||||||
|
|
||||||
def round_value(value, decimalplaces=0):
|
def round_value(value, decimalplaces=0):
|
||||||
"""Rounding function.
|
"""Rounding function.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
value (float): Number to round.
|
value (float): Number to round.
|
||||||
decimalplaces (int): Number of decimal places of float to represent rounded value.
|
decimalplaces (int): Number of decimal places of float to represent rounded value.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
rounded (int/float): Rounded value.
|
rounded (int/float): Rounded value.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Rounds to nearest integer (half values are rounded downwards)
|
# Rounds to nearest integer (half values are rounded downwards)
|
||||||
if decimalplaces == 0:
|
if decimalplaces == 0:
|
||||||
rounded = int(d.Decimal(value).quantize(d.Decimal('1'), rounding=d.ROUND_HALF_DOWN))
|
rounded = int(d.Decimal(value).quantize(d.Decimal('1'), rounding=d.ROUND_HALF_DOWN))
|
||||||
|
|
||||||
# Rounds down to nearest float represented by number of decimal places
|
# Rounds down to nearest float represented by number of decimal places
|
||||||
else:
|
else:
|
||||||
precision = '1.{places}'.format(places='0' * decimalplaces)
|
precision = '1.{places}'.format(places='0' * decimalplaces)
|
||||||
rounded = float(d.Decimal(value).quantize(d.Decimal(precision), rounding=d.ROUND_FLOOR))
|
rounded = float(d.Decimal(value).quantize(d.Decimal(precision), rounding=d.ROUND_FLOOR))
|
||||||
|
|
||||||
return rounded
|
return rounded
|
||||||
|
|
||||||
|
|
||||||
def round32(value):
|
def round32(value):
|
||||||
"""Rounds up to nearest multiple of 32."""
|
"""Rounds up to nearest multiple of 32."""
|
||||||
return int(32 * np.ceil(float(value) / 32))
|
return int(32 * np.ceil(float(value) / 32))
|
||||||
|
|
||||||
|
|
||||||
def fft_power(waveform, dt):
|
def fft_power(waveform, dt):
|
||||||
"""Calculate a FFT of the given waveform of amplitude values;
|
"""Calculate a FFT of the given waveform of amplitude values;
|
||||||
converted to decibels and shifted so that maximum power is 0dB
|
converted to decibels and shifted so that maximum power is 0dB
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
waveform (ndarray): time domain waveform
|
waveform (ndarray): time domain waveform
|
||||||
dt (float): time step
|
dt (float): time step
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
freqs (ndarray): frequency bins
|
freqs (ndarray): frequency bins
|
||||||
power (ndarray): power
|
power (ndarray): power
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Calculate magnitude of frequency spectra of waveform (ignore warning from taking a log of any zero values)
|
# Calculate magnitude of frequency spectra of waveform (ignore warning from taking a log of any zero values)
|
||||||
with np.errstate(divide='ignore'):
|
with np.errstate(divide='ignore'):
|
||||||
power = 10 * np.log10(np.abs(np.fft.fft(waveform))**2)
|
power = 10 * np.log10(np.abs(np.fft.fft(waveform))**2)
|
||||||
|
|
||||||
# Replace any NaNs or Infs from zero division
|
# Replace any NaNs or Infs from zero division
|
||||||
power[np.invert(np.isfinite(power))] = 0
|
power[np.invert(np.isfinite(power))] = 0
|
||||||
|
|
||||||
# Frequency bins
|
# Frequency bins
|
||||||
freqs = np.fft.fftfreq(power.size, d=dt)
|
freqs = np.fft.fftfreq(power.size, d=dt)
|
||||||
|
|
||||||
# Shift powers so that frequency with maximum power is at zero decibels
|
# Shift powers so that frequency with maximum power is at zero decibels
|
||||||
power -= np.amax(power)
|
power -= np.amax(power)
|
||||||
|
|
||||||
return freqs, power
|
return freqs, power
|
||||||
|
|
||||||
|
|
||||||
def human_size(size, a_kilobyte_is_1024_bytes=False):
|
def human_size(size, a_kilobyte_is_1024_bytes=False):
|
||||||
"""Convert a file size to human-readable form.
|
"""Convert a file size to human-readable form.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
size (int): file size in bytes.
|
size (int): file size in bytes.
|
||||||
a_kilobyte_is_1024_bytes (boolean) - true for multiples of 1024, false for multiples of 1000.
|
a_kilobyte_is_1024_bytes (boolean) - true for multiples of 1024, false for multiples of 1000.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Human-readable (string).
|
Human-readable (string).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
suffixes = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], 1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
|
suffixes = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], 1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
|
||||||
|
|
||||||
if size < 0:
|
if size < 0:
|
||||||
raise ValueError('Number must be non-negative.')
|
raise ValueError('Number must be non-negative.')
|
||||||
|
|
||||||
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
|
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
|
||||||
for suffix in suffixes[multiple]:
|
for suffix in suffixes[multiple]:
|
||||||
size /= multiple
|
size /= multiple
|
||||||
if size < multiple:
|
if size < multiple:
|
||||||
return '{:.3g}{}'.format(size, suffix)
|
return '{:.3g}{}'.format(size, suffix)
|
||||||
|
|
||||||
raise ValueError('Number is too large.')
|
raise ValueError('Number is too large.')
|
||||||
|
|
||||||
|
|
||||||
def get_host_info():
|
def get_host_info():
|
||||||
"""Get information about the machine, CPU, RAM, and OS.
|
"""Get information about the machine, CPU, RAM, and OS.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
hostinfo (dict): Manufacturer and model of machine; description of CPU
|
hostinfo (dict): Manufacturer and model of machine; description of CPU
|
||||||
type, speed, cores; RAM; name and version of operating system.
|
type, speed, cores; RAM; name and version of operating system.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Default to 'unknown' if any of the detection fails
|
# Default to 'unknown' if any of the detection fails
|
||||||
manufacturer = model = cpuID = sockets = threadspercore = 'unknown'
|
manufacturer = model = cpuID = sockets = threadspercore = 'unknown'
|
||||||
|
|
||||||
# Windows
|
# Windows
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
# Manufacturer/model
|
# Manufacturer/model
|
||||||
try:
|
try:
|
||||||
manufacturer = subprocess.check_output("wmic csproduct get vendor", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
manufacturer = subprocess.check_output("wmic csproduct get vendor", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||||
manufacturer = manufacturer.split('\n')
|
manufacturer = manufacturer.split('\n')
|
||||||
if len(manufacturer) > 1:
|
if len(manufacturer) > 1:
|
||||||
manufacturer = manufacturer[1]
|
manufacturer = manufacturer[1]
|
||||||
else:
|
else:
|
||||||
manufacturer = manufacturer[0]
|
manufacturer = manufacturer[0]
|
||||||
model = subprocess.check_output("wmic computersystem get model", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
model = subprocess.check_output("wmic computersystem get model", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||||
model = model.split('\n')
|
model = model.split('\n')
|
||||||
if len(model) > 1:
|
if len(model) > 1:
|
||||||
model = model[1]
|
model = model[1]
|
||||||
else:
|
else:
|
||||||
model = model[0]
|
model = model[0]
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
pass
|
pass
|
||||||
machineID = manufacturer + ' ' + model
|
machineID = manufacturer + ' ' + model
|
||||||
|
|
||||||
# CPU information
|
# CPU information
|
||||||
try:
|
try:
|
||||||
allcpuinfo = subprocess.check_output("wmic cpu get Name", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
allcpuinfo = subprocess.check_output("wmic cpu get Name", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||||
allcpuinfo = allcpuinfo.split('\n')
|
allcpuinfo = allcpuinfo.split('\n')
|
||||||
sockets = 0
|
sockets = 0
|
||||||
for line in allcpuinfo:
|
for line in allcpuinfo:
|
||||||
if 'CPU' in line:
|
if 'CPU' in line:
|
||||||
cpuID = line.strip()
|
cpuID = line.strip()
|
||||||
sockets += 1
|
sockets += 1
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Hyperthreading
|
# Hyperthreading
|
||||||
if psutil.cpu_count(logical=False) != psutil.cpu_count(logical=True):
|
if psutil.cpu_count(logical=False) != psutil.cpu_count(logical=True):
|
||||||
hyperthreading = True
|
hyperthreading = True
|
||||||
else:
|
else:
|
||||||
hyperthreading = False
|
hyperthreading = False
|
||||||
|
|
||||||
# OS version
|
# OS version
|
||||||
if platform.machine().endswith('64'):
|
if platform.machine().endswith('64'):
|
||||||
osbit = ' (64-bit)'
|
osbit = ' (64-bit)'
|
||||||
else:
|
else:
|
||||||
osbit = ' (32-bit)'
|
osbit = ' (32-bit)'
|
||||||
osversion = 'Windows ' + platform.release() + osbit
|
osversion = 'Windows ' + platform.release() + osbit
|
||||||
|
|
||||||
# Mac OS X/macOS
|
# Mac OS X/macOS
|
||||||
elif sys.platform == 'darwin':
|
elif sys.platform == 'darwin':
|
||||||
# Manufacturer/model
|
# Manufacturer/model
|
||||||
manufacturer = 'Apple'
|
manufacturer = 'Apple'
|
||||||
try:
|
try:
|
||||||
model = subprocess.check_output("sysctl -n hw.model", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
model = subprocess.check_output("sysctl -n hw.model", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
pass
|
pass
|
||||||
machineID = manufacturer + ' ' + model
|
machineID = manufacturer + ' ' + model
|
||||||
|
|
||||||
# CPU information
|
# CPU information
|
||||||
try:
|
try:
|
||||||
sockets = subprocess.check_output("sysctl -n hw.packages", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
sockets = subprocess.check_output("sysctl -n hw.packages", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||||
sockets = int(sockets)
|
sockets = int(sockets)
|
||||||
cpuID = subprocess.check_output("sysctl -n machdep.cpu.brand_string", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
cpuID = subprocess.check_output("sysctl -n machdep.cpu.brand_string", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||||
cpuID = ' '.join(cpuID.split())
|
cpuID = ' '.join(cpuID.split())
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Hyperthreading
|
# Hyperthreading
|
||||||
if psutil.cpu_count(logical=False) != psutil.cpu_count(logical=True):
|
if psutil.cpu_count(logical=False) != psutil.cpu_count(logical=True):
|
||||||
hyperthreading = True
|
hyperthreading = True
|
||||||
else:
|
else:
|
||||||
hyperthreading = False
|
hyperthreading = False
|
||||||
|
|
||||||
# OS version
|
# OS version
|
||||||
if int(platform.mac_ver()[0].split('.')[1]) < 12:
|
if int(platform.mac_ver()[0].split('.')[1]) < 12:
|
||||||
osversion = 'Mac OS X (' + platform.mac_ver()[0] + ')'
|
osversion = 'Mac OS X (' + platform.mac_ver()[0] + ')'
|
||||||
else:
|
else:
|
||||||
osversion = 'macOS (' + platform.mac_ver()[0] + ')'
|
osversion = 'macOS (' + platform.mac_ver()[0] + ')'
|
||||||
|
|
||||||
# Linux
|
# Linux
|
||||||
elif sys.platform == 'linux':
|
elif sys.platform == 'linux':
|
||||||
# Manufacturer/model
|
# Manufacturer/model
|
||||||
try:
|
try:
|
||||||
manufacturer = subprocess.check_output("cat /sys/class/dmi/id/sys_vendor", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
manufacturer = subprocess.check_output("cat /sys/class/dmi/id/sys_vendor", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||||
model = subprocess.check_output("cat /sys/class/dmi/id/product_name", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
model = subprocess.check_output("cat /sys/class/dmi/id/product_name", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
pass
|
pass
|
||||||
machineID = manufacturer + ' ' + model
|
machineID = manufacturer + ' ' + model
|
||||||
|
|
||||||
# CPU information
|
# CPU information
|
||||||
try:
|
try:
|
||||||
cpuIDinfo = subprocess.check_output("cat /proc/cpuinfo", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
cpuIDinfo = subprocess.check_output("cat /proc/cpuinfo", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||||
for line in cpuIDinfo.split('\n'):
|
for line in cpuIDinfo.split('\n'):
|
||||||
if re.search('model name', line):
|
if re.search('model name', line):
|
||||||
cpuID = re.sub('.*model name.*:', '', line, 1).strip()
|
cpuID = re.sub('.*model name.*:', '', line, 1).strip()
|
||||||
allcpuinfo = subprocess.check_output("lscpu", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
allcpuinfo = subprocess.check_output("lscpu", shell=True, stderr=subprocess.STDOUT).decode('utf-8').strip()
|
||||||
for line in allcpuinfo.split('\n'):
|
for line in allcpuinfo.split('\n'):
|
||||||
if 'Socket(s)' in line:
|
if 'Socket(s)' in line:
|
||||||
sockets = int(line.strip()[-1])
|
sockets = int(line.strip()[-1])
|
||||||
if 'Thread(s) per core' in line:
|
if 'Thread(s) per core' in line:
|
||||||
threadspercore = int(line.strip()[-1])
|
threadspercore = int(line.strip()[-1])
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Hyperthreading
|
# Hyperthreading
|
||||||
if threadspercore == 2:
|
if threadspercore == 2:
|
||||||
hyperthreading = True
|
hyperthreading = True
|
||||||
else:
|
else:
|
||||||
hyperthreading = False
|
hyperthreading = False
|
||||||
|
|
||||||
# OS version
|
# OS version
|
||||||
osrelease = subprocess.check_output("cat /proc/sys/kernel/osrelease", shell=True).decode('utf-8').strip()
|
osrelease = subprocess.check_output("cat /proc/sys/kernel/osrelease", shell=True).decode('utf-8').strip()
|
||||||
osversion = 'Linux (' + osrelease + ', ' + platform.linux_distribution()[0] + ')'
|
osversion = 'Linux (' + osrelease + ', ' + platform.linux_distribution()[0] + ')'
|
||||||
|
|
||||||
# Dictionary of host information
|
# Dictionary of host information
|
||||||
hostinfo = {}
|
hostinfo = {}
|
||||||
hostinfo['hostname'] = platform.node()
|
hostinfo['hostname'] = platform.node()
|
||||||
hostinfo['machineID'] = machineID.strip()
|
hostinfo['machineID'] = machineID.strip()
|
||||||
hostinfo['sockets'] = sockets
|
hostinfo['sockets'] = sockets
|
||||||
hostinfo['cpuID'] = cpuID
|
hostinfo['cpuID'] = cpuID
|
||||||
hostinfo['osversion'] = osversion
|
hostinfo['osversion'] = osversion
|
||||||
hostinfo['hyperthreading'] = hyperthreading
|
hostinfo['hyperthreading'] = hyperthreading
|
||||||
hostinfo['logicalcores'] = psutil.cpu_count()
|
hostinfo['logicalcores'] = psutil.cpu_count()
|
||||||
try:
|
try:
|
||||||
# Get number of physical CPU cores, i.e. avoid hyperthreading with OpenMP
|
# Get number of physical CPU cores, i.e. avoid hyperthreading with OpenMP
|
||||||
hostinfo['physicalcores'] = psutil.cpu_count(logical=False)
|
hostinfo['physicalcores'] = psutil.cpu_count(logical=False)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
hostinfo['physicalcores'] = hostinfo['logicalcores']
|
hostinfo['physicalcores'] = hostinfo['logicalcores']
|
||||||
# Handle case where cpu_count returns None on some machines
|
# Handle case where cpu_count returns None on some machines
|
||||||
if not hostinfo['physicalcores']:
|
if not hostinfo['physicalcores']:
|
||||||
hostinfo['physicalcores'] = hostinfo['logicalcores']
|
hostinfo['physicalcores'] = hostinfo['logicalcores']
|
||||||
hostinfo['ram'] = psutil.virtual_memory().total
|
hostinfo['ram'] = psutil.virtual_memory().total
|
||||||
hostinfo['ompthreads'] = 1
|
hostinfo['ompthreads'] = 1
|
||||||
|
|
||||||
return hostinfo
|
return hostinfo
|
||||||
|
|
||||||
|
|
||||||
class GPU(object):
|
class GPU(object):
|
||||||
"""GPU information."""
|
"""GPU information."""
|
||||||
|
|
||||||
def __init__(self, deviceID):
|
def __init__(self, deviceID):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
deviceID (int): Device ID for GPU.
|
deviceID (int): Device ID for GPU.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.deviceID = deviceID
|
self.deviceID = deviceID
|
||||||
self.name = None
|
self.name = None
|
||||||
self.pcibusID = None
|
self.pcibusID = None
|
||||||
self.constmem = None
|
self.constmem = None
|
||||||
self.totalmem = None
|
self.totalmem = None
|
||||||
# Threads per block for main field updates
|
# Threads per block for main field updates
|
||||||
self.tpb = (256, 1, 1)
|
self.tpb = (256, 1, 1)
|
||||||
# Blocks per grid for main field updates (set in grid.py)
|
# Blocks per grid for main field updates (set in grid.py)
|
||||||
self.bpg = None
|
self.bpg = None
|
||||||
|
|
||||||
def get_gpu_info(self, drv):
|
def get_gpu_info(self, drv):
|
||||||
"""Set information about GPU.
|
"""Set information about GPU.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
drv (object): PyCuda driver.
|
drv (object): PyCuda driver.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.name = drv.Device(self.deviceID).name()
|
self.name = drv.Device(self.deviceID).name()
|
||||||
self.pcibusID = drv.Device(self.deviceID).pci_bus_id()
|
self.pcibusID = drv.Device(self.deviceID).pci_bus_id()
|
||||||
self.constmem = drv.Device(self.deviceID).total_constant_memory
|
self.constmem = drv.Device(self.deviceID).total_constant_memory
|
||||||
self.totalmem = drv.Device(self.deviceID).total_memory()
|
self.totalmem = drv.Device(self.deviceID).total_memory()
|
||||||
|
|
||||||
|
|
||||||
def detect_check_gpus(deviceIDs):
|
def detect_check_gpus(deviceIDs):
|
||||||
"""Get information about Nvidia GPU(s).
|
"""Get information about Nvidia GPU(s).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
deviceIDs (list): List of integers of device IDs.
|
deviceIDs (list): List of integers of device IDs.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
gpus (list): Detected GPU(s) object(s).
|
gpus (list): Detected GPU(s) object(s).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pycuda.driver as drv
|
import pycuda.driver as drv
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise ImportError('To use gprMax in GPU mode the pycuda package must be installed, and you must have a NVIDIA CUDA-Enabled GPU (https://developer.nvidia.com/cuda-gpus).')
|
raise ImportError('To use gprMax in GPU mode the pycuda package must be installed, and you must have a NVIDIA CUDA-Enabled GPU (https://developer.nvidia.com/cuda-gpus).')
|
||||||
drv.init()
|
drv.init()
|
||||||
|
|
||||||
# Check and list any CUDA-Enabled GPUs
|
# Check and list any CUDA-Enabled GPUs
|
||||||
if drv.Device.count() == 0:
|
if drv.Device.count() == 0:
|
||||||
raise GeneralError('No NVIDIA CUDA-Enabled GPUs detected (https://developer.nvidia.com/cuda-gpus)')
|
raise GeneralError('No NVIDIA CUDA-Enabled GPUs detected (https://developer.nvidia.com/cuda-gpus)')
|
||||||
elif 'CUDA_VISIBLE_DEVICES' in os.environ:
|
elif 'CUDA_VISIBLE_DEVICES' in os.environ:
|
||||||
deviceIDsavail = os.environ.get('CUDA_VISIBLE_DEVICES')
|
deviceIDsavail = os.environ.get('CUDA_VISIBLE_DEVICES')
|
||||||
deviceIDsavail = [int(s) for s in deviceIDsavail.split(',')]
|
deviceIDsavail = [int(s) for s in deviceIDsavail.split(',')]
|
||||||
else:
|
else:
|
||||||
deviceIDsavail = range(drv.Device.count())
|
deviceIDsavail = range(drv.Device.count())
|
||||||
|
|
||||||
# If no device ID is given use default of 0
|
# If no device ID is given use default of 0
|
||||||
if not deviceIDs:
|
if not deviceIDs:
|
||||||
deviceIDs = [0]
|
deviceIDs = [0]
|
||||||
|
|
||||||
# Check if requested device ID(s) exist
|
# Check if requested device ID(s) exist
|
||||||
for ID in deviceIDs:
|
for ID in deviceIDs:
|
||||||
if ID not in deviceIDsavail:
|
if ID not in deviceIDsavail:
|
||||||
raise GeneralError('GPU with device ID {} does not exist'.format(ID))
|
raise GeneralError('GPU with device ID {} does not exist'.format(ID))
|
||||||
|
|
||||||
# Gather information about selected/detected GPUs
|
# Gather information about selected/detected GPUs
|
||||||
gpus = []
|
gpus = []
|
||||||
allgpustext = []
|
allgpustext = []
|
||||||
for ID in deviceIDsavail:
|
for ID in deviceIDsavail:
|
||||||
gpu = GPU(deviceID=ID)
|
gpu = GPU(deviceID=ID)
|
||||||
gpu.get_gpu_info(drv)
|
gpu.get_gpu_info(drv)
|
||||||
if ID in deviceIDs:
|
if ID in deviceIDs:
|
||||||
gpus.append(gpu)
|
gpus.append(gpu)
|
||||||
allgpustext.append('{} - {}, {}'.format(gpu.deviceID, gpu.name, human_size(gpu.totalmem, a_kilobyte_is_1024_bytes=True)))
|
allgpustext.append('{} - {}, {}'.format(gpu.deviceID, gpu.name, human_size(gpu.totalmem, a_kilobyte_is_1024_bytes=True)))
|
||||||
|
|
||||||
return gpus, allgpustext
|
return gpus, allgpustext
|
||||||
|
|
||||||
|
|
||||||
def timer():
|
def timer():
|
||||||
"""Function to return the current process wide time in fractional seconds."""
|
"""Function to return the current process wide time in fractional seconds."""
|
||||||
return perf_counter()
|
return perf_counter()
|
||||||
|
|
||||||
class Printer():
|
class Printer():
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.printing = config.is_messages()
|
self.printing = config.is_messages()
|
||||||
|
|
||||||
def print(self, str):
|
def print(self, str):
|
||||||
if self.printing:
|
if self.printing:
|
||||||
print(str)
|
print(str)
|
||||||
|
540
setup.py
540
setup.py
@@ -1,270 +1,270 @@
|
|||||||
# Copyright (C) 2015-2019: The University of Edinburgh
|
# Copyright (C) 2015-2019: The University of Edinburgh
|
||||||
# Authors: Craig Warren and Antonis Giannopoulos
|
# Authors: Craig Warren and Antonis Giannopoulos
|
||||||
#
|
#
|
||||||
# This file is part of gprMax.
|
# This file is part of gprMax.
|
||||||
#
|
#
|
||||||
# gprMax is free software: you can redistribute it and/or modify
|
# gprMax is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# gprMax is distributed in the hope that it will be useful,
|
# gprMax is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from setuptools import setup, Extension
|
from setuptools import setup, Extension
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
from distutils.extension import Extension
|
from distutils.extension import Extension
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import numpy as np
|
import numpy as np
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise ImportError('gprMax requires the NumPy package.')
|
raise ImportError('gprMax requires the NumPy package.')
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from jinja2 import Environment, PackageLoader, select_autoescape
|
from jinja2 import Environment, PackageLoader, select_autoescape
|
||||||
|
|
||||||
|
|
||||||
def build_dispersive_material_templates():
|
def build_dispersive_material_templates():
|
||||||
"""
|
"""
|
||||||
Function to generate Cython .pyx files for dispersive media update.
|
Function to generate Cython .pyx files for dispersive media update.
|
||||||
Jinja2 templates are used to render the various dispersive update functions.
|
Jinja2 templates are used to render the various dispersive update functions.
|
||||||
"""
|
"""
|
||||||
env = Environment(
|
env = Environment(
|
||||||
loader=PackageLoader(__name__, 'gprMax/templates'),
|
loader=PackageLoader(__name__, 'gprMax/templates'),
|
||||||
)
|
)
|
||||||
|
|
||||||
template = env.get_template('fields_updates_dispersive_template')
|
template = env.get_template('fields_updates_dispersive_template')
|
||||||
|
|
||||||
# Render dispersive template for different types
|
# Render dispersive template for different types
|
||||||
r = template.render(
|
r = template.render(
|
||||||
functions=[
|
functions=[
|
||||||
# templates for Double precision and dispersive materials with
|
# templates for Double precision and dispersive materials with
|
||||||
# real susceptibility functions
|
# real susceptibility functions
|
||||||
{
|
{
|
||||||
'name_a': 'update_electric_dispersive_multipole_A_double_real',
|
'name_a': 'update_electric_dispersive_multipole_A_double_real',
|
||||||
'name_b': 'update_electric_dispersive_multipole_B_double_real',
|
'name_b': 'update_electric_dispersive_multipole_B_double_real',
|
||||||
'name_a_1': 'update_electric_dispersive_1pole_A_double_real',
|
'name_a_1': 'update_electric_dispersive_1pole_A_double_real',
|
||||||
'name_b_1': 'update_electric_dispersive_1pole_B_double_real',
|
'name_b_1': 'update_electric_dispersive_1pole_B_double_real',
|
||||||
'field_type': 'double',
|
'field_type': 'double',
|
||||||
'dispersive_type': 'double'
|
'dispersive_type': 'double'
|
||||||
},
|
},
|
||||||
# templates for Float precision and dispersive materials with
|
# templates for Float precision and dispersive materials with
|
||||||
# real susceptibility functions
|
# real susceptibility functions
|
||||||
{
|
{
|
||||||
'name_a': 'update_electric_dispersive_multipole_A_float_real',
|
'name_a': 'update_electric_dispersive_multipole_A_float_real',
|
||||||
'name_b': 'update_electric_dispersive_multipole_B_float_real',
|
'name_b': 'update_electric_dispersive_multipole_B_float_real',
|
||||||
'name_a_1': 'update_electric_dispersive_1pole_A_float_real',
|
'name_a_1': 'update_electric_dispersive_1pole_A_float_real',
|
||||||
'name_b_1': 'update_electric_dispersive_1pole_B_float_real',
|
'name_b_1': 'update_electric_dispersive_1pole_B_float_real',
|
||||||
'field_type': 'float',
|
'field_type': 'float',
|
||||||
'dispersive_type': 'float'
|
'dispersive_type': 'float'
|
||||||
},
|
},
|
||||||
# templates for Double precision and dispersive materials with
|
# templates for Double precision and dispersive materials with
|
||||||
# complex susceptibility functions
|
# complex susceptibility functions
|
||||||
{
|
{
|
||||||
'name_a': 'update_electric_dispersive_multipole_A_double_complex',
|
'name_a': 'update_electric_dispersive_multipole_A_double_complex',
|
||||||
'name_b': 'update_electric_dispersive_multipole_B_double_complex',
|
'name_b': 'update_electric_dispersive_multipole_B_double_complex',
|
||||||
'name_a_1': 'update_electric_dispersive_1pole_A_double_complex',
|
'name_a_1': 'update_electric_dispersive_1pole_A_double_complex',
|
||||||
'name_b_1': 'update_electric_dispersive_1pole_B_double_complex',
|
'name_b_1': 'update_electric_dispersive_1pole_B_double_complex',
|
||||||
'field_type': 'double',
|
'field_type': 'double',
|
||||||
'dispersive_type': 'double complex',
|
'dispersive_type': 'double complex',
|
||||||
# c function to take real part of complex double type
|
# c function to take real part of complex double type
|
||||||
'real_part': 'creal'
|
'real_part': 'creal'
|
||||||
},
|
},
|
||||||
# templates for Float precision and dispersive materials with
|
# templates for Float precision and dispersive materials with
|
||||||
# complex susceptibility functions
|
# complex susceptibility functions
|
||||||
{
|
{
|
||||||
'name_a': 'update_electric_dispersive_multipole_A_float_complex',
|
'name_a': 'update_electric_dispersive_multipole_A_float_complex',
|
||||||
'name_b': 'update_electric_dispersive_multipole_B_float_complex',
|
'name_b': 'update_electric_dispersive_multipole_B_float_complex',
|
||||||
'name_a_1': 'update_electric_dispersive_1pole_A_float_complex',
|
'name_a_1': 'update_electric_dispersive_1pole_A_float_complex',
|
||||||
'name_b_1': 'update_electric_dispersive_1pole_B_float_complex',
|
'name_b_1': 'update_electric_dispersive_1pole_B_float_complex',
|
||||||
'field_type': 'float',
|
'field_type': 'float',
|
||||||
'dispersive_type': 'float complex',
|
'dispersive_type': 'float complex',
|
||||||
# c function to take real part of complex double type
|
# c function to take real part of complex double type
|
||||||
'real_part': 'crealf'
|
'real_part': 'crealf'
|
||||||
}]
|
}]
|
||||||
)
|
)
|
||||||
|
|
||||||
with open('gprMax/cython/fields_updates_dispersive.pyx', 'w') as f:
|
with open('gprMax/cython/fields_updates_dispersive.pyx', 'w') as f:
|
||||||
f.write(r)
|
f.write(r)
|
||||||
|
|
||||||
# Generate Cython file for dispersive materials update functions
|
# Generate Cython file for dispersive materials update functions
|
||||||
build_dispersive_material_templates()
|
build_dispersive_material_templates()
|
||||||
|
|
||||||
# Importing _version__.py before building can cause issues.
|
# Importing _version__.py before building can cause issues.
|
||||||
with open('gprMax/_version.py', 'r') as fd:
|
with open('gprMax/_version.py', 'r') as fd:
|
||||||
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
|
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
|
||||||
fd.read(), re.MULTILINE).group(1)
|
fd.read(), re.MULTILINE).group(1)
|
||||||
|
|
||||||
# Parse package name from init file. Importing __init__.py / gprMax will break as gprMax depends on compiled .pyx files.
|
# Parse package name from init file. Importing __init__.py / gprMax will break as gprMax depends on compiled .pyx files.
|
||||||
with open('gprMax/__init__.py', 'r') as fd:
|
with open('gprMax/__init__.py', 'r') as fd:
|
||||||
packagename = re.search(r'^__name__\s*=\s*[\'"]([^\'"]*)[\'"]',
|
packagename = re.search(r'^__name__\s*=\s*[\'"]([^\'"]*)[\'"]',
|
||||||
fd.read(), re.MULTILINE).group(1)
|
fd.read(), re.MULTILINE).group(1)
|
||||||
|
|
||||||
packages = [packagename, 'tests', 'tools', 'user_libs']
|
packages = [packagename, 'tests', 'tools', 'user_libs']
|
||||||
|
|
||||||
# Parse long_description from README.rst file.
|
# Parse long_description from README.rst file.
|
||||||
with open('README.rst','r') as fd:
|
with open('README.rst','r') as fd:
|
||||||
long_description = fd.read()
|
long_description = fd.read()
|
||||||
|
|
||||||
# Python version
|
# Python version
|
||||||
if sys.version_info[:2] < (3, 6):
|
if sys.version_info[:2] < (3, 6):
|
||||||
sys.exit('\nExited: Requires Python 3.6 or newer!\n')
|
sys.exit('\nExited: Requires Python 3.6 or newer!\n')
|
||||||
|
|
||||||
# Process 'build' command line argument
|
# Process 'build' command line argument
|
||||||
if 'build' in sys.argv:
|
if 'build' in sys.argv:
|
||||||
print("Running 'build_ext --inplace'")
|
print("Running 'build_ext --inplace'")
|
||||||
sys.argv.remove('build')
|
sys.argv.remove('build')
|
||||||
sys.argv.append('build_ext')
|
sys.argv.append('build_ext')
|
||||||
sys.argv.append('--inplace')
|
sys.argv.append('--inplace')
|
||||||
|
|
||||||
# Process '--no-cython' command line argument - either Cythonize or just compile the .c files
|
# Process '--no-cython' command line argument - either Cythonize or just compile the .c files
|
||||||
if '--no-cython' in sys.argv:
|
if '--no-cython' in sys.argv:
|
||||||
USE_CYTHON = False
|
USE_CYTHON = False
|
||||||
sys.argv.remove('--no-cython')
|
sys.argv.remove('--no-cython')
|
||||||
else:
|
else:
|
||||||
USE_CYTHON = True
|
USE_CYTHON = True
|
||||||
|
|
||||||
# Build a list of all the files that need to be Cythonized looking in gprMax directory
|
# Build a list of all the files that need to be Cythonized looking in gprMax directory
|
||||||
cythonfiles = []
|
cythonfiles = []
|
||||||
for root, dirs, files in os.walk(os.path.join(os.getcwd(), packagename), topdown=True):
|
for root, dirs, files in os.walk(os.path.join(os.getcwd(), packagename), topdown=True):
|
||||||
for file in files:
|
for file in files:
|
||||||
if file.endswith('.pyx'):
|
if file.endswith('.pyx'):
|
||||||
cythonfiles.append(os.path.relpath(os.path.join(root, file)))
|
cythonfiles.append(os.path.relpath(os.path.join(root, file)))
|
||||||
|
|
||||||
# Process 'cleanall' command line argument - cleanup Cython files
|
# Process 'cleanall' command line argument - cleanup Cython files
|
||||||
if 'cleanall' in sys.argv:
|
if 'cleanall' in sys.argv:
|
||||||
USE_CYTHON = False
|
USE_CYTHON = False
|
||||||
for file in cythonfiles:
|
for file in cythonfiles:
|
||||||
filebase = os.path.splitext(file)[0]
|
filebase = os.path.splitext(file)[0]
|
||||||
# Remove Cython C files
|
# Remove Cython C files
|
||||||
if os.path.isfile(filebase + '.c'):
|
if os.path.isfile(filebase + '.c'):
|
||||||
try:
|
try:
|
||||||
os.remove(filebase + '.c')
|
os.remove(filebase + '.c')
|
||||||
print('Removed: {}'.format(filebase + '.c'))
|
print('Removed: {}'.format(filebase + '.c'))
|
||||||
except OSError:
|
except OSError:
|
||||||
print('Could not remove: {}'.format(filebase + '.c'))
|
print('Could not remove: {}'.format(filebase + '.c'))
|
||||||
# Remove compiled Cython modules
|
# Remove compiled Cython modules
|
||||||
libfile = glob.glob(os.path.join(os.getcwd(), os.path.splitext(file)[0]) + '*.pyd') + glob.glob(os.path.join(os.getcwd(), os.path.splitext(file)[0]) + '*.so')
|
libfile = glob.glob(os.path.join(os.getcwd(), os.path.splitext(file)[0]) + '*.pyd') + glob.glob(os.path.join(os.getcwd(), os.path.splitext(file)[0]) + '*.so')
|
||||||
if libfile:
|
if libfile:
|
||||||
libfile = libfile[0]
|
libfile = libfile[0]
|
||||||
try:
|
try:
|
||||||
os.remove(libfile)
|
os.remove(libfile)
|
||||||
print('Removed: {}'.format(os.path.abspath(libfile)))
|
print('Removed: {}'.format(os.path.abspath(libfile)))
|
||||||
except OSError:
|
except OSError:
|
||||||
print('Could not remove: {}'.format(os.path.abspath(libfile)))
|
print('Could not remove: {}'.format(os.path.abspath(libfile)))
|
||||||
# Remove build, dist, egg and __pycache__ directories
|
# Remove build, dist, egg and __pycache__ directories
|
||||||
shutil.rmtree(os.path.join(os.getcwd(), 'build'), ignore_errors=True)
|
shutil.rmtree(os.path.join(os.getcwd(), 'build'), ignore_errors=True)
|
||||||
shutil.rmtree(os.path.join(os.getcwd(), 'dist'), ignore_errors=True)
|
shutil.rmtree(os.path.join(os.getcwd(), 'dist'), ignore_errors=True)
|
||||||
shutil.rmtree(os.path.join(os.getcwd(), 'gprMax.egg-info'), ignore_errors=True)
|
shutil.rmtree(os.path.join(os.getcwd(), 'gprMax.egg-info'), ignore_errors=True)
|
||||||
for p in pathlib.Path(os.getcwd()).rglob('__pycache__'):
|
for p in pathlib.Path(os.getcwd()).rglob('__pycache__'):
|
||||||
shutil.rmtree(p, ignore_errors=True)
|
shutil.rmtree(p, ignore_errors=True)
|
||||||
print('Removed: {}'.format(p))
|
print('Removed: {}'.format(p))
|
||||||
# Now do a normal clean
|
# Now do a normal clean
|
||||||
sys.argv[1] = 'clean' # this is what distutils understands
|
sys.argv[1] = 'clean' # this is what distutils understands
|
||||||
|
|
||||||
# Set compiler options
|
# Set compiler options
|
||||||
# Windows
|
# Windows
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
compile_args = ['/O2', '/openmp', '/w'] # No static linking as no static version of OpenMP library; /w disables warnings
|
compile_args = ['/O2', '/openmp', '/w'] # No static linking as no static version of OpenMP library; /w disables warnings
|
||||||
linker_args = []
|
linker_args = []
|
||||||
extra_objects = []
|
extra_objects = []
|
||||||
# macOS - needs gcc (usually via HomeBrew) because the default compiler LLVM (clang) does not support OpenMP
|
# macOS - needs gcc (usually via HomeBrew) because the default compiler LLVM (clang) does not support OpenMP
|
||||||
# - with gcc -fopenmp option implies -pthread
|
# - with gcc -fopenmp option implies -pthread
|
||||||
elif sys.platform == 'darwin':
|
elif sys.platform == 'darwin':
|
||||||
gccpath = glob.glob('/usr/local/bin/gcc-[4-9]*')
|
gccpath = glob.glob('/usr/local/bin/gcc-[4-9]*')
|
||||||
if gccpath:
|
if gccpath:
|
||||||
# Use newest gcc found
|
# Use newest gcc found
|
||||||
os.environ['CC'] = gccpath[-1].split(os.sep)[-1]
|
os.environ['CC'] = gccpath[-1].split(os.sep)[-1]
|
||||||
rpath = '/usr/local/opt/gcc/lib/gcc/' + gccpath[-1].split(os.sep)[-1][-1] + '/'
|
rpath = '/usr/local/opt/gcc/lib/gcc/' + gccpath[-1].split(os.sep)[-1][-1] + '/'
|
||||||
else:
|
else:
|
||||||
raise('Cannot find gcc 4-9 in /usr/local/bin. gprMax requires gcc to be installed - easily done through the Homebrew package manager (http://brew.sh). Note: gcc with OpenMP support is required.')
|
raise('Cannot find gcc 4-9 in /usr/local/bin. gprMax requires gcc to be installed - easily done through the Homebrew package manager (http://brew.sh). Note: gcc with OpenMP support is required.')
|
||||||
compile_args = ['-O3', '-w', '-fopenmp', '-march=native'] # Sometimes worth testing with '-fstrict-aliasing', '-fno-common'
|
compile_args = ['-O3', '-w', '-fopenmp', '-march=native'] # Sometimes worth testing with '-fstrict-aliasing', '-fno-common'
|
||||||
linker_args = ['-fopenmp', '-Wl,-rpath,' + rpath]
|
linker_args = ['-fopenmp', '-Wl,-rpath,' + rpath]
|
||||||
extra_objects = []
|
extra_objects = []
|
||||||
# Linux
|
# Linux
|
||||||
elif sys.platform == 'linux':
|
elif sys.platform == 'linux':
|
||||||
compile_args = ['-O3', '-w', '-fopenmp', '-march=native']
|
compile_args = ['-O3', '-w', '-fopenmp', '-march=native']
|
||||||
linker_args = ['-fopenmp']
|
linker_args = ['-fopenmp']
|
||||||
extra_objects = []
|
extra_objects = []
|
||||||
|
|
||||||
# Build a list of all the extensions
|
# Build a list of all the extensions
|
||||||
extensions = []
|
extensions = []
|
||||||
for file in cythonfiles:
|
for file in cythonfiles:
|
||||||
tmp = os.path.splitext(file)
|
tmp = os.path.splitext(file)
|
||||||
if USE_CYTHON:
|
if USE_CYTHON:
|
||||||
fileext = tmp[1]
|
fileext = tmp[1]
|
||||||
else:
|
else:
|
||||||
fileext = '.c'
|
fileext = '.c'
|
||||||
extension = Extension(tmp[0].replace(os.sep, '.'),
|
extension = Extension(tmp[0].replace(os.sep, '.'),
|
||||||
[tmp[0] + fileext],
|
[tmp[0] + fileext],
|
||||||
language='c',
|
language='c',
|
||||||
include_dirs=[np.get_include()],
|
include_dirs=[np.get_include()],
|
||||||
extra_compile_args=compile_args,
|
extra_compile_args=compile_args,
|
||||||
extra_link_args=linker_args,
|
extra_link_args=linker_args,
|
||||||
extra_objects=extra_objects)
|
extra_objects=extra_objects)
|
||||||
extensions.append(extension)
|
extensions.append(extension)
|
||||||
|
|
||||||
# Cythonize (build .c files)
|
# Cythonize (build .c files)
|
||||||
if USE_CYTHON:
|
if USE_CYTHON:
|
||||||
from Cython.Build import cythonize
|
from Cython.Build import cythonize
|
||||||
extensions = cythonize(extensions,
|
extensions = cythonize(extensions,
|
||||||
compiler_directives={
|
compiler_directives={
|
||||||
'boundscheck': False,
|
'boundscheck': False,
|
||||||
'wraparound': False,
|
'wraparound': False,
|
||||||
'initializedcheck': False,
|
'initializedcheck': False,
|
||||||
'embedsignature': True,
|
'embedsignature': True,
|
||||||
'language_level': 3
|
'language_level': 3
|
||||||
},
|
},
|
||||||
annotate=False)
|
annotate=False)
|
||||||
|
|
||||||
# SetupTools Required to make package
|
# SetupTools Required to make package
|
||||||
import setuptools
|
import setuptools
|
||||||
|
|
||||||
setup(name=packagename,
|
setup(name=packagename,
|
||||||
version=version,
|
version=version,
|
||||||
author='Craig Warren and Antonis Giannopoulos',
|
author='Craig Warren and Antonis Giannopoulos',
|
||||||
url='http://www.gprmax.com',
|
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=long_description,
|
||||||
long_description_content_type="text/x-rst",
|
long_description_content_type="text/x-rst",
|
||||||
license='GPLv3+',
|
license='GPLv3+',
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Environment :: Console',
|
'Environment :: Console',
|
||||||
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
|
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
|
||||||
'Operating System :: MacOS',
|
'Operating System :: MacOS',
|
||||||
'Operating System :: Microsoft :: Windows',
|
'Operating System :: Microsoft :: Windows',
|
||||||
'Operating System :: POSIX :: Linux',
|
'Operating System :: POSIX :: Linux',
|
||||||
'Programming Language :: Cython',
|
'Programming Language :: Cython',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Topic :: Scientific/Engineering'
|
'Topic :: Scientific/Engineering'
|
||||||
],
|
],
|
||||||
#requirements
|
#requirements
|
||||||
python_requires=">3.6",
|
python_requires=">3.6",
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"colorama",
|
"colorama",
|
||||||
"cython",
|
"cython",
|
||||||
"h5py",
|
"h5py",
|
||||||
"jupyter",
|
"jupyter",
|
||||||
"matplotlib",
|
"matplotlib",
|
||||||
"numpy",
|
"numpy",
|
||||||
"psutil",
|
"psutil",
|
||||||
"scipy",
|
"scipy",
|
||||||
"terminaltables",
|
"terminaltables",
|
||||||
"tqdm",
|
"tqdm",
|
||||||
],
|
],
|
||||||
ext_modules=extensions,
|
ext_modules=extensions,
|
||||||
packages=packages,
|
packages=packages,
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
include_dirs=[np.get_include()])
|
include_dirs=[np.get_include()])
|
||||||
|
在新工单中引用
屏蔽一个用户