Added a pre-commit config file and reformatted all the files accordingly by using it.

这个提交包含在:
Sai-Suraj-27
2023-06-26 16:09:39 +05:30
父节点 c71e87e34f
当前提交 f9dd7f2420
共有 155 个文件被更改,包括 11383 次插入8802 次删除

查看文件

@@ -18,8 +18,11 @@ logger = logging.getLogger(__name__)
# Parse command line arguments
parser = argparse.ArgumentParser(description='Calculate and store (in a Numpy file) field patterns from a simulation with receivers positioned in circles around an antenna.', usage='cd gprMax; python -m user_libs.AntennaPatterns.initial_save outputfile')
parser.add_argument('outputfile', help='name of gprMax output file including path')
parser = argparse.ArgumentParser(
description="Calculate and store (in a Numpy file) field patterns from a simulation with receivers positioned in circles around an antenna.",
usage="cd gprMax; python -m user_libs.AntennaPatterns.initial_save outputfile",
)
parser.add_argument("outputfile", help="name of gprMax output file including path")
args = parser.parse_args()
outputfile = args.outputfile
@@ -27,7 +30,7 @@ outputfile = args.outputfile
# User configurable parameters
# Pattern type (E or H)
type = 'H'
type = "H"
# Antenna (true if using full antenna model; false for a theoretical Hertzian dipole
antenna = True
@@ -55,35 +58,47 @@ traceno = np.s_[:] # All traces
# Critical angle and velocity
if epsr:
mr = 1
z1 = np.sqrt(mr / epsr) * config.sim_config.em_consts['z0']
v1 = config.sim_config.em_consts['c'] / np.sqrt(epsr)
thetac = np.round(np.arcsin(v1 / config.sim_config.em_consts['c']) * (180 / np.pi))
z1 = np.sqrt(mr / epsr) * config.sim_config.em_consts["z0"]
v1 = config.sim_config.em_consts["c"] / np.sqrt(epsr)
thetac = np.round(np.arcsin(v1 / config.sim_config.em_consts["c"]) * (180 / np.pi))
wavelength = v1 / f
# Print some useful information
logger.info('Centre frequency: {} GHz'.format(f / 1e9))
logger.info("Centre frequency: {} GHz".format(f / 1e9))
if epsr:
logger.info('Critical angle for Er {} is {} degrees'.format(epsr, thetac))
logger.info('Wavelength: {:.3f} m'.format(wavelength))
logger.info('Observation distance(s) from {:.3f} m ({:.1f} wavelengths) to {:.3f} m ({:.1f} wavelengths)'.format(radii[0], radii[0] / wavelength, radii[-1], radii[-1] / wavelength))
logger.info('Theoretical boundary between reactive & radiating near-field (0.62*sqrt((D^3/wavelength): {:.3f} m'.format(0.62 * np.sqrt((D**3) / wavelength)))
logger.info('Theoretical boundary between radiating near-field & far-field (2*D^2/wavelength): {:.3f} m'.format((2 * D**2) / wavelength))
logger.info("Critical angle for Er {} is {} degrees".format(epsr, thetac))
logger.info("Wavelength: {:.3f} m".format(wavelength))
logger.info(
"Observation distance(s) from {:.3f} m ({:.1f} wavelengths) to {:.3f} m ({:.1f} wavelengths)".format(
radii[0], radii[0] / wavelength, radii[-1], radii[-1] / wavelength
)
)
logger.info(
"Theoretical boundary between reactive & radiating near-field (0.62*sqrt((D^3/wavelength): {:.3f} m".format(
0.62 * np.sqrt((D**3) / wavelength)
)
)
logger.info(
"Theoretical boundary between radiating near-field & far-field (2*D^2/wavelength): {:.3f} m".format(
(2 * D**2) / wavelength
)
)
# Load text file with coordinates of pattern origin
origin = np.loadtxt(os.path.splitext(outputfile)[0] + '_rxsorigin.txt')
origin = np.loadtxt(os.path.splitext(outputfile)[0] + "_rxsorigin.txt")
# Load output file and read some header information
f = h5py.File(outputfile, 'r')
iterations = f.attrs['Iterations']
dt = f.attrs['dt']
nrx = f.attrs['nrx']
f = h5py.File(outputfile, "r")
iterations = f.attrs["Iterations"]
dt = f.attrs["dt"]
nrx = f.attrs["nrx"]
if antenna:
nrx = nrx - 1 # Ignore first receiver point with full antenna model
start = 2
else:
start = 1
time = np.arange(0, dt * iterations, dt)
time = time / 1E-9
time = time / 1e-9
fs = 1 / dt # Sampling frequency
# Initialise arrays to store fields
@@ -105,15 +120,15 @@ Hthetasum = np.zeros(len(theta), dtype=np.float32)
patternsave = np.zeros((len(radii), len(theta)), dtype=np.float32)
for rx in range(0, nrx):
path = '/rxs/rx' + str(rx + start) + '/'
position = f[path].attrs['Position'][:]
path = "/rxs/rx" + str(rx + start) + "/"
position = f[path].attrs["Position"][:]
coords[rx, :] = position - origin
Ex[:, rx] = f[path + 'Ex'][:]
Ey[:, rx] = f[path + 'Ey'][:]
Ez[:, rx] = f[path + 'Ez'][:]
Hx[:, rx] = f[path + 'Hx'][:]
Hy[:, rx] = f[path + 'Hy'][:]
Hz[:, rx] = f[path + 'Hz'][:]
Ex[:, rx] = f[path + "Ex"][:]
Ey[:, rx] = f[path + "Ey"][:]
Ez[:, rx] = f[path + "Ez"][:]
Hx[:, rx] = f[path + "Hx"][:]
Hy[:, rx] = f[path + "Hy"][:]
Hz[:, rx] = f[path + "Hz"][:]
f.close()
# Plot traces for sanity checking
@@ -141,14 +156,23 @@ for radius in range(0, len(radii)):
# Observation points
for pt in range(rxstart, rxstart + len(theta)):
# Cartesian to spherical coordinate transform coefficients from (Kraus,1991,Electromagnetics,p.34)
r1 = coords[pt, 0] / np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2 + coords[pt, 2]**2)
r2 = coords[pt, 1] / np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2 + coords[pt, 2]**2)
r3 = coords[pt, 2] / np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2 + coords[pt, 2]**2)
theta1 = (coords[pt, 0] * coords[pt, 2]) / (np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2) * np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2 + coords[pt, 2]**2))
theta2 = (coords[pt, 1] * coords[pt, 2]) / (np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2) * np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2 + coords[pt, 2]**2))
theta3 = -(np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2) / np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2 + coords[pt, 2]**2))
phi1 = -(coords[pt, 1] / np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2))
phi2 = coords[pt, 0] / np.sqrt(coords[pt, 0]**2 + coords[pt, 1]**2)
r1 = coords[pt, 0] / np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
r2 = coords[pt, 1] / np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
r3 = coords[pt, 2] / np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
theta1 = (coords[pt, 0] * coords[pt, 2]) / (
np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2)
* np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
)
theta2 = (coords[pt, 1] * coords[pt, 2]) / (
np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2)
* np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
)
theta3 = -(
np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2)
/ np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
)
phi1 = -(coords[pt, 1] / np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2))
phi2 = coords[pt, 0] / np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2)
phi3 = 0
# Fields in spherical coordinates
@@ -161,22 +185,22 @@ for radius in range(0, len(radii)):
# Calculate metric for time-domain field pattern values
if impscaling and coords[pt, 2] < 0:
Ethetasum[index] = np.sum(Etheta[:, index]**2) / z1
Hthetasum[index] = np.sum(Htheta[:, index]**2) / z1
Ethetasum[index] = np.sum(Etheta[:, index] ** 2) / z1
Hthetasum[index] = np.sum(Htheta[:, index] ** 2) / z1
else:
Ethetasum[index] = np.sum(Etheta[:, index]**2) / config.sim_config.em_consts['z0']
Hthetasum[index] = np.sum(Htheta[:, index]**2) / config.sim_config.em_consts['z0']
Ethetasum[index] = np.sum(Etheta[:, index] ** 2) / config.sim_config.em_consts["z0"]
Hthetasum[index] = np.sum(Htheta[:, index] ** 2) / config.sim_config.em_consts["z0"]
index += 1
if type == 'H':
if type == "H":
# Flip H-plane patterns as rx points are written CCW but always plotted CW
patternsave[radius, :] = Hthetasum[::-1]
elif type == 'E':
elif type == "E":
patternsave[radius, :] = Ethetasum
rxstart += len(theta)
# Save pattern to numpy file
np.save(os.path.splitext(outputfile)[0], patternsave)
logger.info('Written Numpy file: {}.npy'.format(os.path.splitext(outputfile)[0]))
logger.info("Written Numpy file: {}.npy".format(os.path.splitext(outputfile)[0]))

查看文件

@@ -17,8 +17,11 @@ logger = logging.getLogger(__name__)
# Parse command line arguments
parser = argparse.ArgumentParser(description='Plot field patterns from a simulation with receivers positioned in circles around an antenna. This module should be used after the field pattern data has been processed and stored using the initial_save.py module.', usage='cd gprMax; python -m user_libs.AntennaPatterns.plot_fields numpyfile')
parser.add_argument('numpyfile', help='name of numpy file including path')
parser = argparse.ArgumentParser(
description="Plot field patterns from a simulation with receivers positioned in circles around an antenna. This module should be used after the field pattern data has been processed and stored using the initial_save.py module.",
usage="cd gprMax; python -m user_libs.AntennaPatterns.plot_fields numpyfile",
)
parser.add_argument("numpyfile", help="name of numpy file including path")
# parser.add_argument('hertzian', help='name of numpy file including path')
args = parser.parse_args()
patterns = np.load(args.numpyfile)
@@ -28,7 +31,7 @@ patterns = np.load(args.numpyfile)
# User configurable parameters
# Pattern type (E or H)
type = 'H'
type = "H"
# Relative permittivity of half-space for homogeneous materials (set to None for inhomogeneous)
epsr = 5
@@ -52,33 +55,45 @@ step = 12
# Critical angle and velocity
if epsr:
mr = 1
z1 = np.sqrt(mr / epsr) * config.sim_config.em_consts['z0']
v1 = config.sim_config.em_consts['c'] / np.sqrt(epsr)
thetac = np.round(np.rad2deg(np.arcsin(v1 / config.sim_config.em_consts['c'])))
z1 = np.sqrt(mr / epsr) * config.sim_config.em_consts["z0"]
v1 = config.sim_config.em_consts["c"] / np.sqrt(epsr)
thetac = np.round(np.rad2deg(np.arcsin(v1 / config.sim_config.em_consts["c"])))
wavelength = v1 / f
# Print some useful information
logger.info('Centre frequency: {} GHz'.format(f / 1e9))
logger.info("Centre frequency: {} GHz".format(f / 1e9))
if epsr:
logger.info('Critical angle for Er {} is {} degrees'.format(epsr, thetac))
logger.info('Wavelength: {:.3f} m'.format(wavelength))
logger.info('Observation distance(s) from {:.3f} m ({:.1f} wavelengths) to {:.3f} m ({:.1f} wavelengths)'.format(radii[0], radii[0] / wavelength, radii[-1], radii[-1] / wavelength))
logger.info('Theoretical boundary between reactive & radiating near-field (0.62*sqrt((D^3/wavelength): {:.3f} m'.format(0.62 * np.sqrt((D**3) / wavelength)))
logger.info('Theoretical boundary between radiating near-field & far-field (2*D^2/wavelength): {:.3f} m'.format((2 * D**2) / wavelength))
logger.info("Critical angle for Er {} is {} degrees".format(epsr, thetac))
logger.info("Wavelength: {:.3f} m".format(wavelength))
logger.info(
"Observation distance(s) from {:.3f} m ({:.1f} wavelengths) to {:.3f} m ({:.1f} wavelengths)".format(
radii[0], radii[0] / wavelength, radii[-1], radii[-1] / wavelength
)
)
logger.info(
"Theoretical boundary between reactive & radiating near-field (0.62*sqrt((D^3/wavelength): {:.3f} m".format(
0.62 * np.sqrt((D**3) / wavelength)
)
)
logger.info(
"Theoretical boundary between radiating near-field & far-field (2*D^2/wavelength): {:.3f} m".format(
(2 * D**2) / wavelength
)
)
# Setup figure
fig = plt.figure(num=args.numpyfile, figsize=(8, 8), facecolor='w', edgecolor='w')
fig = plt.figure(num=args.numpyfile, figsize=(8, 8), facecolor="w", edgecolor="w")
ax = plt.subplot(111, polar=True)
cmap = plt.cm.get_cmap('rainbow')
ax.set_prop_cycle('color', [cmap(i) for i in np.linspace(0, 1, len(radii))])
cmap = plt.cm.get_cmap("rainbow")
ax.set_prop_cycle("color", [cmap(i) for i in np.linspace(0, 1, len(radii))])
# Critical angle window and air/subsurface interface lines
if epsr:
ax.plot([0, np.deg2rad(180 - thetac)], [min, 0], color='0.7', lw=2)
ax.plot([0, np.deg2rad(180 + thetac)], [min, 0], color='0.7', lw=2)
ax.plot([np.deg2rad(270), np.deg2rad(90)], [0, 0], color='0.7', lw=2)
ax.annotate('Air', xy=(np.deg2rad(270), 0), xytext=(8, 8), textcoords='offset points')
ax.annotate('Ground', xy=(np.deg2rad(270), 0), xytext=(8, -15), textcoords='offset points')
ax.plot([0, np.deg2rad(180 - thetac)], [min, 0], color="0.7", lw=2)
ax.plot([0, np.deg2rad(180 + thetac)], [min, 0], color="0.7", lw=2)
ax.plot([np.deg2rad(270), np.deg2rad(90)], [0, 0], color="0.7", lw=2)
ax.annotate("Air", xy=(np.deg2rad(270), 0), xytext=(8, 8), textcoords="offset points")
ax.annotate("Ground", xy=(np.deg2rad(270), 0), xytext=(8, -15), textcoords="offset points")
# Plot patterns
for patt in range(0, len(radii)):
@@ -86,12 +101,12 @@ for patt in range(0, len(radii)):
pattplot = pattplot / np.max(np.max(patterns)) # Normalise, based on set of patterns
# Calculate power (ignore warning from taking a log of any zero values)
with np.errstate(divide='ignore'):
with np.errstate(divide="ignore"):
power = 10 * np.log10(pattplot)
# Replace any NaNs or Infs from zero division
power[np.invert(np.isfinite(power))] = 0
ax.plot(theta, power, label='{:.2f}m'.format(radii[patt]), marker='.', ms=6, lw=1.5)
ax.plot(theta, power, label="{:.2f}m".format(radii[patt]), marker=".", ms=6, lw=1.5)
# Add Hertzian dipole plot
# hertzplot1 = np.append(hertzian[0, :], hertzian[0, 0]) # Append start value to close circle
@@ -102,8 +117,8 @@ for patt in range(0, len(radii)):
# ax.plot(theta, 10 * np.log10(hertzplot2), label='Inf. dipole, 0.58m', color='black', ls='--', lw=3)
# Theta axis options
ax.set_theta_zero_location('N')
ax.set_theta_direction('clockwise')
ax.set_theta_zero_location("N")
ax.set_theta_direction("clockwise")
ax.set_thetagrids(np.arange(0, 360, 30))
# Radial axis options
@@ -111,19 +126,21 @@ ax.set_rmax(0)
ax.set_rlabel_position(45)
ax.set_yticks(np.arange(min, step, step))
yticks = ax.get_yticks().tolist()
yticks[-1] = '0 dB'
yticks[-1] = "0 dB"
ax.set_yticklabels(yticks)
# Grid and legend
ax.grid(True)
handles, existlabels = ax.get_legend_handles_labels()
leg = ax.legend([handles[0], handles[-1]], [existlabels[0], existlabels[-1]], ncol=2, loc=(0.27, -0.12), frameon=False) # Plot just first and last legend entries
leg = ax.legend(
[handles[0], handles[-1]], [existlabels[0], existlabels[-1]], ncol=2, loc=(0.27, -0.12), frameon=False
) # Plot just first and last legend entries
# leg = ax.legend([handles[0], handles[-3], handles[-2], handles[-1]], [existlabels[0], existlabels[-3], existlabels[-2], existlabels[-1]], ncol=4, loc=(-0.13,-0.12), frameon=False)
[legobj.set_linewidth(2) for legobj in leg.legendHandles]
# Save a pdf of the plot
savename = os.path.splitext(args.numpyfile)[0] + '.pdf'
fig.savefig(savename, dpi=None, format='pdf', bbox_inches='tight', pad_inches=0.1)
savename = os.path.splitext(args.numpyfile)[0] + ".pdf"
fig.savefig(savename, dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
# savename = os.path.splitext(args.numpyfile)[0] + '.png'
# fig.savefig(savename, dpi=150, format='png', bbox_inches='tight', pad_inches=0.1)

查看文件

@@ -8,22 +8,24 @@ logger = logging.getLogger(__name__)
# Parse command line arguments
parser = argparse.ArgumentParser(description='Writes a HDF5 file of AustinMan or AustinWoman head only.', usage='python head_only_hdf5 filename')
parser.add_argument('filename', help='name and path to (HDF5) file containing AustinMan or AustinWoman model')
parser = argparse.ArgumentParser(
description="Writes a HDF5 file of AustinMan or AustinWoman head only.", usage="python head_only_hdf5 filename"
)
parser.add_argument("filename", help="name and path to (HDF5) file containing AustinMan or AustinWoman model")
args = parser.parse_args()
# Read full body HDF5 file
f = h5py.File(args.filename, 'r')
dx_dy_dz = f.attrs['dx_dy_dz']
data = f['/data'][:, :, :]
f = h5py.File(args.filename, "r")
dx_dy_dz = f.attrs["dx_dy_dz"]
data = f["/data"][:, :, :]
# Define head as last 1/8 of total body height
nzhead = 7 * int(data.shape[2] / 8)
logger.info(f'Dimensions of head model: {data.shape[0]:g} x {data.shape[1]:g} x {data.shape[2] - nzhead:g} cells')
logger.info(f"Dimensions of head model: {data.shape[0]:g} x {data.shape[1]:g} x {data.shape[2] - nzhead:g} cells")
# Write HDF5 file
headfile = os.path.splitext(args.filename)[0] + '_head.h5'
f = h5py.File(headfile, 'w')
f.attrs['dx_dy_dz'] = dx_dy_dz
f['/data'] = data[:, :, nzhead:data.shape[2]]
headfile = os.path.splitext(args.filename)[0] + "_head.h5"
f = h5py.File(headfile, "w")
f.attrs["dx_dy_dz"] = dx_dy_dz
f["/data"] = data[:, :, nzhead : data.shape[2]]

查看文件

@@ -19,7 +19,7 @@ from optimization import DA_DLS, DE_DLS, PSO_DLS
class Relaxation(object):
""" Create Relaxation function object for complex material.
"""Create Relaxation function object for complex material.
:param sigma: The conductivity (Siemens/metre).
:type sigma: float, non-optional
@@ -52,13 +52,20 @@ class Relaxation(object):
:type optimizer_options: dict, optional, default: empty dict
"""
def __init__(self, sigma, mu, mu_sigma,
material_name, f_n=50,
number_of_debye_poles=-1,
plot=True, save=False,
optimizer=PSO_DLS,
optimizer_options={}):
self.name = 'Relaxation function'
def __init__(
self,
sigma,
mu,
mu_sigma,
material_name,
f_n=50,
number_of_debye_poles=-1,
plot=True,
save=False,
optimizer=PSO_DLS,
optimizer_options={},
):
self.name = "Relaxation function"
self.params = {}
self.number_of_debye_poles = number_of_debye_poles
self.f_n = f_n
@@ -71,7 +78,7 @@ class Relaxation(object):
self.optimizer = optimizer(**optimizer_options)
def set_freq(self, f_min, f_max, f_n=50):
""" Interpolate frequency vector using n equally logarithmicaly spaced frequencies.
"""Interpolate frequency vector using n equally logarithmicaly spaced frequencies.
Args:
f_min (float): First bound of the frequency range
@@ -84,19 +91,17 @@ class Relaxation(object):
f_min and f_max must satisfied f_min < f_max
"""
if abs(f_min - f_max) > 1e12:
warnings.warn(f'The chosen range is realy big. '
f'Consider setting greater number of points '
f'on the frequency grid!')
self.freq = np.logspace(np.log10(f_min),
np.log10(f_max),
int(f_n))
warnings.warn(
f"The chosen range is realy big. "
f"Consider setting greater number of points "
f"on the frequency grid!"
)
self.freq = np.logspace(np.log10(f_min), np.log10(f_max), int(f_n))
def check_inputs(self):
""" Check the validity of the inputs. """
"""Check the validity of the inputs."""
try:
d = [float(i) for i in
[self.number_of_debye_poles,
self.sigma, self.mu, self.mu_sigma]]
d = [float(i) for i in [self.number_of_debye_poles, self.sigma, self.mu, self.mu_sigma]]
except ValueError:
sys.exit("The inputs should be numeric.")
if not isinstance(self.number_of_debye_poles, int):
@@ -105,7 +110,7 @@ class Relaxation(object):
sys.exit("The inputs should be positive.")
def calculation(self):
""" Approximate the given relaxation function
"""Approximate the given relaxation function
(Havriliak-Negami function, Crim, Jonscher) or based on raw data.
"""
raise NotImplementedError()
@@ -116,17 +121,16 @@ class Relaxation(object):
Returns:
s (str): Info about chosen function and its parameters.
"""
print(f"Approximating {self.name}"
f" using {self.number_of_debye_poles} Debye poles")
print(f"Approximating {self.name}" f" using {self.number_of_debye_poles} Debye poles")
print(f"{self.name} parameters: ")
s = ''
s = ""
for k, v in self.params.items():
s += f"{k:10s} = {v}\n"
print(s)
return f'{self.name}:\n{s}'
return f"{self.name}:\n{s}"
def optimize(self):
""" Calling the main optimisation module with defined lower and upper boundaries of search.
"""Calling the main optimisation module with defined lower and upper boundaries of search.
Returns:
tau (ndarray): The optimised relaxation times.
@@ -138,21 +142,19 @@ class Relaxation(object):
for given frequency points.
"""
# Define the lower and upper boundaries of search
lb = np.full(self.number_of_debye_poles,
-np.log10(np.max(self.freq)) - 3)
ub = np.full(self.number_of_debye_poles,
-np.log10(np.min(self.freq)) + 3)
lb = np.full(self.number_of_debye_poles, -np.log10(np.max(self.freq)) - 3)
ub = np.full(self.number_of_debye_poles, -np.log10(np.min(self.freq)) + 3)
# Call optimizer to minimize the cost function
tau, weights, ee, rl, im = self.optimizer.fit(func=self.optimizer.cost_function,
lb=lb, ub=ub,
funckwargs={'rl': self.rl,
'im': self.im,
'freq': self.freq}
)
tau, weights, ee, rl, im = self.optimizer.fit(
func=self.optimizer.cost_function,
lb=lb,
ub=ub,
funckwargs={"rl": self.rl, "im": self.im, "freq": self.freq},
)
return tau, weights, ee, rl, im
def run(self):
""" Solve the problem described by the given relaxation function
"""Solve the problem described by the given relaxation function
(Havriliak-Negami function, Crim, Jonscher)
or data given from a text file.
@@ -173,9 +175,7 @@ class Relaxation(object):
self.rl, self.im = q.real, q.imag
if self.number_of_debye_poles == -1:
print("\n#########",
"Try to automaticaly fit number of Debye poles, up to 20!",
"##########\n", sep="")
print("\n#########", "Try to automaticaly fit number of Debye poles, up to 20!", "##########\n", sep="")
error = np.infty # artificial best error starting value
self.number_of_debye_poles = 1
iteration = 1
@@ -198,9 +198,7 @@ class Relaxation(object):
# Print the results in gprMax format style
properties = self.print_output(tau, weights, ee)
print(f'The average fractional error for:\n'
f'- real part: {err_real}\n'
f'- imaginary part: {err_imag}\n')
print(f"The average fractional error for:\n" f"- real part: {err_real}\n" f"- imaginary part: {err_imag}\n")
if self.save:
self.save_result(properties)
# Plot the actual and the approximate dielectric properties
@@ -209,7 +207,7 @@ class Relaxation(object):
return err_real + err_imag, properties
def print_output(self, tau, weights, ee):
""" Print out the resulting Debye parameters in a gprMax format.
"""Print out the resulting Debye parameters in a gprMax format.
Args:
tau (ndarray): The best known position form optimization module
@@ -225,28 +223,25 @@ class Relaxation(object):
print(f" |{'e_inf':^14s}|{'De':^14s}|{'log(tau_0)':^25s}|")
print("_" * 65)
for i in range(0, len(tau)):
print("Debye {0:}|{1:^14.5f}|{2:^14.5f}|{3:^25.5f}|"
.format(i + 1, ee/len(tau), weights[i],
tau[i]))
print("Debye {0:}|{1:^14.5f}|{2:^14.5f}|{3:^25.5f}|".format(i + 1, ee / len(tau), weights[i], tau[i]))
print("_" * 65)
# Print the Debye expnasion in a gprMax format
material_prop = []
material_prop.append("#material: {} {} {} {} {}\n".format(ee, self.sigma,
self.mu,
self.mu_sigma,
self.material_name))
material_prop.append(
"#material: {} {} {} {} {}\n".format(ee, self.sigma, self.mu, self.mu_sigma, self.material_name)
)
print(material_prop[0], end="")
dispersion_prop = "#add_dispersion_debye: {}".format(len(tau))
for i in range(len(tau)):
dispersion_prop += " {} {}".format(weights[i], 10**tau[i])
dispersion_prop += " {} {}".format(weights[i], 10 ** tau[i])
dispersion_prop += " {}".format(self.material_name)
print(dispersion_prop)
material_prop.append(dispersion_prop + '\n')
material_prop.append(dispersion_prop + "\n")
return material_prop
def plot_result(self, rl_exp, im_exp):
""" Plot the actual and the approximated electric permittivity,
"""Plot the actual and the approximated electric permittivity,
along with relative error for real and imaginary parts
using a semilogarithm X axes.
@@ -261,14 +256,10 @@ class Relaxation(object):
gs = gridspec.GridSpec(2, 1)
ax = fig.add_subplot(gs[0])
ax.grid(b=True, which="major", linewidth=0.2, linestyle="--")
ax.semilogx(self.freq * 1e-6, rl_exp, "b-", linewidth=2.0,
label="Debye Expansion: Real part")
ax.semilogx(self.freq * 1e-6, -im_exp, "k-", linewidth=2.0,
label="Debye Expansion: Imaginary part")
ax.semilogx(self.freq * 1e-6, self.rl, "r.",
linewidth=2.0, label=f"{self.name}: Real part")
ax.semilogx(self.freq * 1e-6, -self.im, "g.", linewidth=2.0,
label=f"{self.name}: Imaginary part")
ax.semilogx(self.freq * 1e-6, rl_exp, "b-", linewidth=2.0, label="Debye Expansion: Real part")
ax.semilogx(self.freq * 1e-6, -im_exp, "k-", linewidth=2.0, label="Debye Expansion: Imaginary part")
ax.semilogx(self.freq * 1e-6, self.rl, "r.", linewidth=2.0, label=f"{self.name}: Real part")
ax.semilogx(self.freq * 1e-6, -self.im, "g.", linewidth=2.0, label=f"{self.name}: Imaginary part")
ax.set_ylim([-1, np.max(np.concatenate([self.rl, -self.im])) + 1])
ax.legend()
ax.set_xlabel("Frequency (MHz)")
@@ -276,17 +267,15 @@ class Relaxation(object):
ax = fig.add_subplot(gs[1])
ax.grid(b=True, which="major", linewidth=0.2, linestyle="--")
ax.semilogx(self.freq * 1e-6, (rl_exp - self.rl)/(self.rl + 1), "b-", linewidth=2.0,
label="Real part")
ax.semilogx(self.freq * 1e-6, (-im_exp + self.im)/(self.im + 1), "k-", linewidth=2.0,
label="Imaginary part")
ax.semilogx(self.freq * 1e-6, (rl_exp - self.rl) / (self.rl + 1), "b-", linewidth=2.0, label="Real part")
ax.semilogx(self.freq * 1e-6, (-im_exp + self.im) / (self.im + 1), "k-", linewidth=2.0, label="Imaginary part")
ax.legend()
ax.set_xlabel("Frequency (MHz)")
ax.set_ylabel("Relative approximation error")
plt.show()
def error(self, rl_exp, im_exp):
""" Calculate the average fractional error separately for
"""Calculate the average fractional error separately for
relative permittivity (real part) and conductivity (imaginary part)
Args:
@@ -300,13 +289,13 @@ class Relaxation(object):
avg_err_imag (float): average fractional error
for conductivity (imaginary part)
"""
avg_err_real = np.sum(np.abs((rl_exp - self.rl)/(self.rl + 1)) * 100)/len(rl_exp)
avg_err_imag = np.sum(np.abs((-im_exp + self.im)/(self.im + 1)) * 100)/len(im_exp)
avg_err_real = np.sum(np.abs((rl_exp - self.rl) / (self.rl + 1)) * 100) / len(rl_exp)
avg_err_imag = np.sum(np.abs((-im_exp + self.im) / (self.im + 1)) * 100) / len(im_exp)
return avg_err_real, avg_err_imag
@staticmethod
def save_result(output, fdir="../materials"):
""" Save the resulting Debye parameters in a gprMax format.
"""Save the resulting Debye parameters in a gprMax format.
Args:
output (list(str)): Material and resulting Debye parameters
@@ -316,17 +305,13 @@ class Relaxation(object):
if fdir != "../materials" and os.path.isdir(fdir):
file_path = os.path.join(fdir, "my_materials.txt")
elif os.path.isdir("../materials"):
file_path = os.path.join("../materials",
"my_materials.txt")
file_path = os.path.join("../materials", "my_materials.txt")
elif os.path.isdir("materials"):
file_path = os.path.join("materials",
"my_materials.txt")
file_path = os.path.join("materials", "my_materials.txt")
elif os.path.isdir("user_libs/materials"):
file_path = os.path.join("user_libs", "materials",
"my_materials.txt")
file_path = os.path.join("user_libs", "materials", "my_materials.txt")
else:
sys.exit("Cannot save material properties "
f"in {os.path.join(fdir, 'my_materials.txt')}!")
sys.exit("Cannot save material properties " f"in {os.path.join(fdir, 'my_materials.txt')}!")
fileH = open(file_path, "a")
fileH.write(f"## {output[0].split(' ')[-1]}")
fileH.writelines(output)
@@ -336,7 +321,7 @@ class Relaxation(object):
class HavriliakNegami(Relaxation):
""" Approximate a given Havriliak-Negami function
"""Approximate a given Havriliak-Negami function
Havriliak-Negami function = ε_∞ + Δ‎ε / (1 + (2πfjτ)**α)**β,
where f is the frequency in Hz.
@@ -362,20 +347,40 @@ class HavriliakNegami(Relaxation):
:param tau_0: Real positive float number, tau_0 is the relaxation time.
:type tau_0: float
"""
def __init__(self, f_min, f_max,
alpha, beta, e_inf, de, tau_0,
sigma, mu, mu_sigma, material_name,
number_of_debye_poles=-1, f_n=50,
plot=False, save=False,
optimizer=PSO_DLS,
optimizer_options={}):
super(HavriliakNegami, self).__init__(sigma=sigma, mu=mu, mu_sigma=mu_sigma,
material_name=material_name, f_n=f_n,
number_of_debye_poles=number_of_debye_poles,
plot=plot, save=save,
optimizer=optimizer,
optimizer_options=optimizer_options)
self.name = 'Havriliak-Negami function'
def __init__(
self,
f_min,
f_max,
alpha,
beta,
e_inf,
de,
tau_0,
sigma,
mu,
mu_sigma,
material_name,
number_of_debye_poles=-1,
f_n=50,
plot=False,
save=False,
optimizer=PSO_DLS,
optimizer_options={},
):
super(HavriliakNegami, self).__init__(
sigma=sigma,
mu=mu,
mu_sigma=mu_sigma,
material_name=material_name,
f_n=f_n,
number_of_debye_poles=number_of_debye_poles,
plot=plot,
save=save,
optimizer=optimizer,
optimizer_options=optimizer_options,
)
self.name = "Havriliak-Negami function"
# Place the lower frequency bound at f_min and the upper frequency bound at f_max
if f_min > f_max:
self.f_min, self.f_max = f_max, f_min
@@ -384,12 +389,18 @@ class HavriliakNegami(Relaxation):
# Choosing n frequencies logarithmicaly equally spaced between the bounds given
self.set_freq(self.f_min, self.f_max, self.f_n)
self.e_inf, self.alpha, self.beta, self.de, self.tau_0 = e_inf, alpha, beta, de, tau_0
self.params = {'f_min': self.f_min, 'f_max': self.f_max,
'eps_inf': self.e_inf, 'Delta_eps': self.de, 'tau_0': self.tau_0,
'alpha': self.alpha, 'beta': self.beta}
self.params = {
"f_min": self.f_min,
"f_max": self.f_max,
"eps_inf": self.e_inf,
"Delta_eps": self.de,
"tau_0": self.tau_0,
"alpha": self.alpha,
"beta": self.beta,
}
def check_inputs(self):
""" Check the validity of the Havriliak Negami model's inputs. """
"""Check the validity of the Havriliak Negami model's inputs."""
super(HavriliakNegami, self).check_inputs()
try:
d = [float(i) for i in self.params.values()]
@@ -406,15 +417,12 @@ class HavriliakNegami(Relaxation):
def calculation(self):
"""Calculates the Havriliak-Negami function for
the given parameters."""
return self.e_inf + self.de / (
1 + (1j * 2 * np.pi *
self.freq * self.tau_0)**self.alpha
)**self.beta
the given parameters."""
return self.e_inf + self.de / (1 + (1j * 2 * np.pi * self.freq * self.tau_0) ** self.alpha) ** self.beta
class Jonscher(Relaxation):
""" Approximate a given Jonsher function
"""Approximate a given Jonsher function
Jonscher function = ε_∞ - ap * (-1j * 2πf / omegap)**n_p,
where f is the frequency in Hz
@@ -433,20 +441,39 @@ class Jonscher(Relaxation):
:params n_p: Jonscher parameter, 0 < n_p < 1.
:type n_p: float, non-optional
"""
def __init__(self, f_min, f_max,
e_inf, a_p, omega_p, n_p,
sigma, mu, mu_sigma,
material_name, number_of_debye_poles=-1,
f_n=50, plot=False, save=False,
optimizer=PSO_DLS,
optimizer_options={}):
super(Jonscher, self).__init__(sigma=sigma, mu=mu, mu_sigma=mu_sigma,
material_name=material_name, f_n=f_n,
number_of_debye_poles=number_of_debye_poles,
plot=plot, save=save,
optimizer=optimizer,
optimizer_options=optimizer_options)
self.name = 'Jonsher function'
def __init__(
self,
f_min,
f_max,
e_inf,
a_p,
omega_p,
n_p,
sigma,
mu,
mu_sigma,
material_name,
number_of_debye_poles=-1,
f_n=50,
plot=False,
save=False,
optimizer=PSO_DLS,
optimizer_options={},
):
super(Jonscher, self).__init__(
sigma=sigma,
mu=mu,
mu_sigma=mu_sigma,
material_name=material_name,
f_n=f_n,
number_of_debye_poles=number_of_debye_poles,
plot=plot,
save=save,
optimizer=optimizer,
optimizer_options=optimizer_options,
)
self.name = "Jonsher function"
# Place the lower frequency bound at f_min and the upper frequency bound at f_max
if f_min > f_max:
self.f_min, self.f_max = f_max, f_min
@@ -455,12 +482,17 @@ class Jonscher(Relaxation):
# Choosing n frequencies logarithmicaly equally spaced between the bounds given
self.set_freq(self.f_min, self.f_max, self.f_n)
self.e_inf, self.a_p, self.omega_p, self.n_p = e_inf, a_p, omega_p, n_p
self.params = {'f_min': self.f_min, 'f_max': self.f_max,
'eps_inf': self.e_inf, 'n_p': self.n_p,
'omega_p': self.omega_p, 'a_p': self.a_p}
self.params = {
"f_min": self.f_min,
"f_max": self.f_max,
"eps_inf": self.e_inf,
"n_p": self.n_p,
"omega_p": self.omega_p,
"a_p": self.a_p,
}
def check_inputs(self):
""" Check the validity of the inputs. """
"""Check the validity of the inputs."""
super(Jonscher, self).check_inputs()
try:
d = [float(i) for i in self.params.values()]
@@ -475,13 +507,13 @@ class Jonscher(Relaxation):
def calculation(self):
"""Calculates the Q function for the given parameters"""
return self.e_inf + (self.a_p * (2 * np.pi *
self.freq / self.omega_p)**(self.n_p-1)) * (
1 - 1j / np.tan(self.n_p * np.pi/2))
return self.e_inf + (self.a_p * (2 * np.pi * self.freq / self.omega_p) ** (self.n_p - 1)) * (
1 - 1j / np.tan(self.n_p * np.pi / 2)
)
class Crim(Relaxation):
""" Approximate a given CRIM function
"""Approximate a given CRIM function
CRIM = (Σ frac_i * (ε_∞_i + Δε_i/(1 + 2πfj*τ_i))^a)^(1/a)
:param f_min: First bound of the frequency range
@@ -498,20 +530,37 @@ class Crim(Relaxation):
:type materials: ndarray, non-optional
"""
def __init__(self, f_min, f_max, a, volumetric_fractions,
materials, sigma, mu, mu_sigma, material_name,
number_of_debye_poles=-1, f_n=50,
plot=False, save=False,
optimizer=PSO_DLS,
optimizer_options={}):
super(Crim, self).__init__(sigma=sigma, mu=mu, mu_sigma=mu_sigma,
material_name=material_name, f_n=f_n,
number_of_debye_poles=number_of_debye_poles,
plot=plot, save=save,
optimizer=optimizer,
optimizer_options=optimizer_options)
self.name = 'CRIM function'
def __init__(
self,
f_min,
f_max,
a,
volumetric_fractions,
materials,
sigma,
mu,
mu_sigma,
material_name,
number_of_debye_poles=-1,
f_n=50,
plot=False,
save=False,
optimizer=PSO_DLS,
optimizer_options={},
):
super(Crim, self).__init__(
sigma=sigma,
mu=mu,
mu_sigma=mu_sigma,
material_name=material_name,
f_n=f_n,
number_of_debye_poles=number_of_debye_poles,
plot=plot,
save=save,
optimizer=optimizer,
optimizer_options=optimizer_options,
)
self.name = "CRIM function"
# Place the lower frequency bound at f_min and the upper frequency bound at f_max
if f_min > f_max:
self.f_min, self.f_max = f_max, f_min
@@ -522,16 +571,19 @@ class Crim(Relaxation):
self.a = a
self.volumetric_fractions = np.array(volumetric_fractions)
self.materials = np.array(materials)
self.params = {'f_min': self.f_min, 'f_max': self.f_max,
'a': self.a, 'volumetric_fractions': self.volumetric_fractions,
'materials': self.materials}
self.params = {
"f_min": self.f_min,
"f_max": self.f_max,
"a": self.a,
"volumetric_fractions": self.volumetric_fractions,
"materials": self.materials,
}
def check_inputs(self):
""" Check the validity of the inputs. """
"""Check the validity of the inputs."""
super(Crim, self).check_inputs()
try:
d = [float(i) for i in
[self.f_min, self.f_max, self.a]]
d = [float(i) for i in [self.f_min, self.f_max, self.a]]
except ValueError:
sys.exit("The inputs should be numeric.")
if (np.array(d) < 0).sum() != 0:
@@ -557,12 +609,11 @@ class Crim(Relaxation):
sys.exit("Error: The summation of volumetric volumes should be equal to 1")
def print_info(self):
""" Print information about chosen approximation settings """
print(f"Approximating Complex Refractive Index Model (CRIM)"
f" using {self.number_of_debye_poles} Debye poles")
"""Print information about chosen approximation settings"""
print(f"Approximating Complex Refractive Index Model (CRIM)" f" using {self.number_of_debye_poles} Debye poles")
print("CRIM parameters: ")
for i in range(len(self.volumetric_fractions)):
print("Material {}.:".format(i+1))
print("Material {}.:".format(i + 1))
print("---------------------------------")
print(f"{'Vol. fraction':>27s} = {self.volumetric_fractions[i]}")
print(f"{'e_inf':>27s} = {self.materials[i][0]}")
@@ -571,16 +622,27 @@ class Crim(Relaxation):
def calculation(self):
"""Calculates the Crim function for the given parameters"""
return np.sum(np.repeat(self.volumetric_fractions, len(self.freq)
).reshape((-1, len(self.materials)))*(
self.materials[:, 0] + self.materials[:, 1] / (
1 + 1j * 2 * np.pi * np.repeat(self.freq, len(self.materials)
).reshape((-1, len(self.materials))) * self.materials[:, 2]))**self.a,
axis=1)**(1 / self.a)
return np.sum(
np.repeat(self.volumetric_fractions, len(self.freq)).reshape((-1, len(self.materials)))
* (
self.materials[:, 0]
+ self.materials[:, 1]
/ (
1
+ 1j
* 2
* np.pi
* np.repeat(self.freq, len(self.materials)).reshape((-1, len(self.materials)))
* self.materials[:, 2]
)
)
** self.a,
axis=1,
) ** (1 / self.a)
class Rawdata(Relaxation):
""" Interpolate data given from a text file.
"""Interpolate data given from a text file.
:param filename: text file which contains three columns:
frequency (Hz),Real,Imaginary (separated by comma).
@@ -588,113 +650,147 @@ class Rawdata(Relaxation):
:param delimiter: separator for three data columns
:type delimiter: str, optional (Deafult: ',')
"""
def __init__(self, filename,
sigma, mu, mu_sigma,
material_name, number_of_debye_poles=-1,
f_n=50, delimiter=',',
plot=False, save=False,
optimizer=PSO_DLS,
optimizer_options={}):
super(Rawdata, self).__init__(sigma=sigma, mu=mu, mu_sigma=mu_sigma,
material_name=material_name, f_n=f_n,
number_of_debye_poles=number_of_debye_poles,
plot=plot, save=save,
optimizer=optimizer,
optimizer_options=optimizer_options)
def __init__(
self,
filename,
sigma,
mu,
mu_sigma,
material_name,
number_of_debye_poles=-1,
f_n=50,
delimiter=",",
plot=False,
save=False,
optimizer=PSO_DLS,
optimizer_options={},
):
super(Rawdata, self).__init__(
sigma=sigma,
mu=mu,
mu_sigma=mu_sigma,
material_name=material_name,
f_n=f_n,
number_of_debye_poles=number_of_debye_poles,
plot=plot,
save=save,
optimizer=optimizer,
optimizer_options=optimizer_options,
)
self.delimiter = delimiter
self.filename = Path(filename).absolute()
self.params = {'filename': self.filename}
self.params = {"filename": self.filename}
def check_inputs(self):
""" Check the validity of the inputs. """
"""Check the validity of the inputs."""
super(Rawdata, self).check_inputs()
if not os.path.isfile(self.filename):
sys.exit("File doesn't exists!")
def calculation(self):
""" Interpolate real and imaginary part from data.
"""Interpolate real and imaginary part from data.
Column framework of the input file three columns comma-separated
Frequency(Hz),Real,Imaginary
"""
# Read the file
with open(self.filename) as f:
try:
array = np.array(
[[float(x) for x in line.split(self.delimiter)] for line in f]
)
array = np.array([[float(x) for x in line.split(self.delimiter)] for line in f])
except ValueError:
sys.exit("Error: The inputs should be numeric")
self.set_freq(min(array[:, 0]), max(array[:, 0]), self.f_n)
rl_interp = scipy.interpolate.interp1d(array[:, 0], array[:, 1],
fill_value="extrapolate")
im_interp = scipy.interpolate.interp1d(array[:, 0], array[:, 2],
fill_value="extrapolate")
rl_interp = scipy.interpolate.interp1d(array[:, 0], array[:, 1], fill_value="extrapolate")
im_interp = scipy.interpolate.interp1d(array[:, 0], array[:, 2], fill_value="extrapolate")
return rl_interp(self.freq) - 1j * im_interp(self.freq)
if __name__ == "__main__":
# Kelley et al. parameters
setup = HavriliakNegami(f_min=1e7, f_max=1e11,
alpha=0.91, beta=0.45,
e_inf=2.7, de=8.6-2.7, tau_0=9.4e-10,
sigma=0, mu=0, mu_sigma=0,
material_name="Kelley", f_n=100,
number_of_debye_poles=6,
plot=True, save=False,
optimizer_options={'swarmsize': 30,
'maxiter': 100,
'omega': 0.5,
'phip': 1.4,
'phig': 1.4,
'minstep': 1e-8,
'minfun': 1e-8,
'seed': 111,
'pflag': True})
setup = HavriliakNegami(
f_min=1e7,
f_max=1e11,
alpha=0.91,
beta=0.45,
e_inf=2.7,
de=8.6 - 2.7,
tau_0=9.4e-10,
sigma=0,
mu=0,
mu_sigma=0,
material_name="Kelley",
f_n=100,
number_of_debye_poles=6,
plot=True,
save=False,
optimizer_options={
"swarmsize": 30,
"maxiter": 100,
"omega": 0.5,
"phip": 1.4,
"phig": 1.4,
"minstep": 1e-8,
"minfun": 1e-8,
"seed": 111,
"pflag": True,
},
)
setup.run()
setup = HavriliakNegami(f_min=1e7, f_max=1e11,
alpha=0.91, beta=0.45,
e_inf=2.7, de=8.6-2.7, tau_0=9.4e-10,
sigma=0, mu=0, mu_sigma=0,
material_name="Kelley", f_n=100,
number_of_debye_poles=6,
plot=True, save=False,
optimizer=DA_DLS,
optimizer_options={'seed': 111})
setup = HavriliakNegami(
f_min=1e7,
f_max=1e11,
alpha=0.91,
beta=0.45,
e_inf=2.7,
de=8.6 - 2.7,
tau_0=9.4e-10,
sigma=0,
mu=0,
mu_sigma=0,
material_name="Kelley",
f_n=100,
number_of_debye_poles=6,
plot=True,
save=False,
optimizer=DA_DLS,
optimizer_options={"seed": 111},
)
setup.run()
setup = HavriliakNegami(f_min=1e7, f_max=1e11,
alpha=0.91, beta=0.45,
e_inf=2.7, de=8.6-2.7, tau_0=9.4e-10,
sigma=0, mu=0, mu_sigma=0,
material_name="Kelley", f_n=100,
number_of_debye_poles=6,
plot=True, save=False,
optimizer=DE_DLS,
optimizer_options={'seed': 111})
setup = HavriliakNegami(
f_min=1e7,
f_max=1e11,
alpha=0.91,
beta=0.45,
e_inf=2.7,
de=8.6 - 2.7,
tau_0=9.4e-10,
sigma=0,
mu=0,
mu_sigma=0,
material_name="Kelley",
f_n=100,
number_of_debye_poles=6,
plot=True,
save=False,
optimizer=DE_DLS,
optimizer_options={"seed": 111},
)
setup.run()
# Testing setup
setup = Rawdata("examples/Test.txt", 0.1, 1, 0.1, "M1",
number_of_debye_poles=3, plot=True,
optimizer_options={'seed': 111})
setup = Rawdata(
"examples/Test.txt", 0.1, 1, 0.1, "M1", number_of_debye_poles=3, plot=True, optimizer_options={"seed": 111}
)
setup.run()
np.random.seed(111)
setup = HavriliakNegami(1e12, 1e-3, 0.5, 1, 10, 5,
1e-6, 0.1, 1, 0, "M2",
number_of_debye_poles=6,
plot=True)
setup = HavriliakNegami(1e12, 1e-3, 0.5, 1, 10, 5, 1e-6, 0.1, 1, 0, "M2", number_of_debye_poles=6, plot=True)
setup.run()
setup = Jonscher(1e6, 1e-5, 50, 1, 1e5, 0.7,
0.1, 1, 0.1, "M3",
number_of_debye_poles=4,
plot=True)
setup = Jonscher(1e6, 1e-5, 50, 1, 1e5, 0.7, 0.1, 1, 0.1, "M3", number_of_debye_poles=4, plot=True)
setup.run()
f = np.array([0.5, 0.5])
material1 = [3, 25, 1e6]
material2 = [3, 0, 1e3]
materials = np.array([material1, material2])
setup = Crim(1*1e-1, 1e-9, 0.5, f, materials, 0.1,
1, 0, "M4", number_of_debye_poles=2,
plot=True)
setup = Crim(1 * 1e-1, 1e-9, 0.5, f, materials, 0.1, 1, 0, "M4", number_of_debye_poles=2, plot=True)
setup.run()

查看文件

@@ -23,7 +23,7 @@ The generic form of dispersive media is
\epsilon(\omega) = \epsilon^{'}(\omega) - j\epsilon^{''}(\omega),
where :math:`\omega` is the angular frequency, :math:`\epsilon^{'}` and :math:`\epsilon^{''}` are the real and imaginary parts of the permittivity respectively.
where :math:`\omega` is the angular frequency, :math:`\epsilon^{'}` and :math:`\epsilon^{''}` are the real and imaginary parts of the permittivity respectively.
This package provides scripts and tools which can be used to fit a multi-Debye expansion to dielectric data, defined as
@@ -144,7 +144,7 @@ The ``CRIM`` class has the following structure:
.. code-block:: none
CRIM(f_min, f_max, a, volumetric_fractions,
materials, sigma, mu, mu_sigma, material_name,
materials, sigma, mu, mu_sigma, material_name,
number_of_debye_poles=-1, f_n=50,
plot=False, save=True,
optimizer=PSO_DLS,
@@ -245,4 +245,4 @@ The following code shows a basic example of how to use the Havriliak-Negami func
'seed': 111,
'pflag': True})
# run optimization
setup.run()
setup.run()

查看文件

@@ -468,4 +468,4 @@
},
"nbformat": 4,
"nbformat_minor": 5
}
}

查看文件

@@ -1,28 +1,41 @@
# I. Giannakis, A. Giannopoulos and N. Davidson,
# "Incorporating dispersive electrical properties in FDTD GPR models
# using a general Cole-Cole dispersion function,"
# using a general Cole-Cole dispersion function,"
# 2012 14th International Conference on Ground Penetrating Radar (GPR), 2012, pp. 232-236
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
from Debye_Fit import HavriliakNegami
if __name__ == "__main__":
# set Havrilak-Negami function with initial parameters
setup = HavriliakNegami(f_min=1e4, f_max=1e11,
alpha=0.3, beta=1,
e_inf=3.4, de=2.7, tau_0=.8e-10,
sigma=0.45e-3, mu=1, mu_sigma=0,
material_name="dry_sand", f_n=100,
plot=True, save=False,
optimizer_options={'swarmsize':30,
'maxiter':100,
'omega':0.5,
'phip':1.4,
'phig':1.4,
'minstep':1e-8,
'minfun':1e-8,
'seed': 111,
'pflag': True})
setup = HavriliakNegami(
f_min=1e4,
f_max=1e11,
alpha=0.3,
beta=1,
e_inf=3.4,
de=2.7,
tau_0=0.8e-10,
sigma=0.45e-3,
mu=1,
mu_sigma=0,
material_name="dry_sand",
f_n=100,
plot=True,
save=False,
optimizer_options={
"swarmsize": 30,
"maxiter": 100,
"omega": 0.5,
"phip": 1.4,
"phig": 1.4,
"minstep": 1e-8,
"minfun": 1e-8,
"seed": 111,
"pflag": True,
},
)
### Dry Sand in case of 3, 5
# and automatically set number of Debye poles (-1)
for number_of_debye_poles in [3, 5, -1]:
@@ -31,12 +44,12 @@ if __name__ == "__main__":
### Moist sand
# set Havrilak-Negami function parameters
setup.material_name="moist_sand"
setup.material_name = "moist_sand"
setup.alpha = 0.25
setup.beta = 1
setup.e_inf = 5.6
setup.de = 3.3
setup.tau_0 = 1.1e-10,
setup.tau_0 = (1.1e-10,)
setup.sigma = 2e-3
# calculate for different number of Debye poles
for number_of_debye_poles in [3, 5, -1]:

查看文件

@@ -768,4 +768,4 @@
},
"nbformat": 4,
"nbformat_minor": 5
}
}

查看文件

@@ -22,6 +22,7 @@ class Optimizer(object):
unsigned integers (Default: None).
:type seed: int, NoneType, optional
"""
def __init__(self, maxiter=1000, seed=None):
self.maxiter = maxiter
self.seed = seed
@@ -58,12 +59,11 @@ class Optimizer(object):
# find the weights using a calc_weights method
if self.calc_weights is None:
raise NotImplementedError()
_, _, weights, ee, rl_exp, im_exp = \
self.calc_weights(tau, **funckwargs)
_, _, weights, ee, rl_exp, im_exp = self.calc_weights(tau, **funckwargs)
return tau, weights, ee, rl_exp, im_exp
def calc_relaxation_times(self):
""" Optimisation method that tries to find an optimal set
"""Optimisation method that tries to find an optimal set
of relaxation times that minimise the error
between the actual and the approximated electric permittivity.
"""
@@ -93,7 +93,7 @@ class Optimizer(object):
class PSO_DLS(Optimizer):
""" Create hybrid Particle Swarm-Damped Least Squares optimisation
"""Create hybrid Particle Swarm-Damped Least Squares optimisation
object with predefined parameters.
:param swarmsize: The number of particles in the swarm (Default: 40).
@@ -119,11 +119,10 @@ class PSO_DLS(Optimizer):
value during optimization process (Default: False).
:type pflag: bool, optional
"""
def __init__(self, swarmsize=40, maxiter=50,
omega=0.9, phip=0.9, phig=0.9,
minstep=1e-8, minfun=1e-8,
pflag=False, seed=None):
def __init__(
self, swarmsize=40, maxiter=50, omega=0.9, phip=0.9, phig=0.9, minstep=1e-8, minfun=1e-8, pflag=False, seed=None
):
super(PSO_DLS, self).__init__(maxiter, seed)
self.swarmsize = swarmsize
self.omega = omega
@@ -156,13 +155,11 @@ class PSO_DLS(Optimizer):
"""
np.random.seed(self.seed)
# check input parameters
assert len(lb) == len(ub), \
'Lower- and upper-bounds must be the same length'
assert hasattr(func, '__call__'), 'Invalid function handle'
assert len(lb) == len(ub), "Lower- and upper-bounds must be the same length"
assert hasattr(func, "__call__"), "Invalid function handle"
lb = np.array(lb)
ub = np.array(ub)
assert np.all(ub > lb), \
'All upper-bound values must be greater than lower-bound values'
assert np.all(ub > lb), "All upper-bound values must be greater than lower-bound values"
vhigh = np.abs(ub - lb)
vlow = -vhigh
@@ -200,14 +197,16 @@ class PSO_DLS(Optimizer):
v[i, :] = vlow + np.random.rand(d) * (vhigh - vlow)
# Iterate until termination criterion met
for it in tqdm(range(self.maxiter), desc='Debye fitting'):
for it in tqdm(range(self.maxiter), desc="Debye fitting"):
rp = np.random.uniform(size=(self.swarmsize, d))
rg = np.random.uniform(size=(self.swarmsize, d))
for i in range(self.swarmsize):
# Update the particle's velocity
v[i, :] = self.omega * v[i, :] + self.phip * rp[i, :] * \
(p[i, :] - x[i, :]) + \
self.phig * rg[i, :] * (g - x[i, :])
v[i, :] = (
self.omega * v[i, :]
+ self.phip * rp[i, :] * (p[i, :] - x[i, :])
+ self.phig * rg[i, :] * (g - x[i, :])
)
# Update the particle's position,
# correcting lower and upper bound
# violations, then update the objective function value
@@ -227,12 +226,10 @@ class PSO_DLS(Optimizer):
tmp = x[i, :].copy()
stepsize = np.sqrt(np.sum((g - tmp) ** 2))
if np.abs(fg - fx) <= self.minfun:
print(f'Stopping search: Swarm best objective '
f'change less than {self.minfun}')
print(f"Stopping search: Swarm best objective " f"change less than {self.minfun}")
return tmp, fx
elif stepsize <= self.minstep:
print(f'Stopping search: Swarm best position '
f'change less than {self.minstep}')
print(f"Stopping search: Swarm best position " f"change less than {self.minstep}")
return tmp, fx
else:
g = tmp.copy()
@@ -261,11 +258,9 @@ class PSO_DLS(Optimizer):
# it clears an axes
plt.cla()
plt.plot(x, y, "b-", linewidth=1.0)
plt.ylim(min(y) - 0.1 * min(y),
max(y) + 0.1 * max(y))
plt.ylim(min(y) - 0.1 * min(y), max(y) + 0.1 * max(y))
plt.xlim(min(x) - 0.1, max(x) + 0.1)
plt.grid(b=True, which="major", color="k",
linewidth=0.2, linestyle="--")
plt.grid(b=True, which="major", color="k", linewidth=0.2, linestyle="--")
plt.suptitle("Debye fitting process")
plt.xlabel("Iteration")
plt.ylabel("Average Error")
@@ -273,17 +268,27 @@ class PSO_DLS(Optimizer):
class DA_DLS(Optimizer):
""" Create Dual Annealing object with predefined parameters.
"""Create Dual Annealing object with predefined parameters.
The current class is a modified edition of the scipy.optimize
package which can be found at:
https://docs.scipy.org/doc/scipy/reference/generated/
scipy.optimize.dual_annealing.html#scipy.optimize.dual_annealing
"""
def __init__(self, maxiter=1000,
local_search_options={}, initial_temp=5230.0,
restart_temp_ratio=2e-05, visit=2.62, accept=-5.0,
maxfun=1e7, no_local_search=False,
callback=None, x0=None, seed=None):
def __init__(
self,
maxiter=1000,
local_search_options={},
initial_temp=5230.0,
restart_temp_ratio=2e-05,
visit=2.62,
accept=-5.0,
maxfun=1e7,
no_local_search=False,
callback=None,
x0=None,
seed=None,
):
super(DA_DLS, self).__init__(maxiter, seed)
self.local_search_options = local_search_options
self.initial_temp = initial_temp
@@ -330,7 +335,8 @@ class DA_DLS(Optimizer):
maxfun=self.maxfun,
no_local_search=self.no_local_search,
callback=self.callback,
x0=self.x0)
x0=self.x0,
)
print(result.message)
return result.x, result.fun
@@ -344,12 +350,25 @@ class DE_DLS(Optimizer):
https://docs.scipy.org/doc/scipy/reference/generated/
scipy.optimize.differential_evolution.html#scipy.optimize.differential_evolution
"""
def __init__(self, maxiter=1000,
strategy='best1bin', popsize=15, tol=0.01, mutation=(0.5, 1),
recombination=0.7, callback=None, disp=False, polish=True,
init='latinhypercube', atol=0,
updating='immediate', workers=1,
constraints=(), seed=None):
def __init__(
self,
maxiter=1000,
strategy="best1bin",
popsize=15,
tol=0.01,
mutation=(0.5, 1),
recombination=0.7,
callback=None,
disp=False,
polish=True,
init="latinhypercube",
atol=0,
updating="immediate",
workers=1,
constraints=(),
seed=None,
):
super(DE_DLS, self).__init__(maxiter, seed)
self.strategy = strategy
self.popsize = popsize
@@ -403,7 +422,8 @@ class DE_DLS(Optimizer):
atol=self.atol,
updating=self.updating,
workers=self.workers,
constraints=self.constraints)
constraints=self.constraints,
)
print(result.message)
return result.x, result.fun
@@ -446,17 +466,15 @@ def DLS(logt, rl, im, freq):
# Here they are transformed back t0=10**logt
tt = 10**logt
# y = Ax, here the A matrix for the real and the imaginary part is builded
d = 1 / (1 + 1j * 2 * np.pi * np.repeat(
freq, len(tt)).reshape((-1, len(tt))) * tt)
d = 1 / (1 + 1j * 2 * np.pi * np.repeat(freq, len(tt)).reshape((-1, len(tt))) * tt)
# Adding dumping (Levenberg–Marquardt algorithm)
# Solving the overdetermined system y=Ax
x = np.abs(np.linalg.lstsq(d.imag, im, rcond=None)[0])
# x - absolute damped least-squares solution
rp, ip = np.matmul(d.real, x[np.newaxis].T).T[0], np.matmul(
d.imag, x[np.newaxis].T).T[0]
cost_i = np.sum(np.abs(ip-im))/len(im)
rp, ip = np.matmul(d.real, x[np.newaxis].T).T[0], np.matmul(d.imag, x[np.newaxis].T).T[0]
cost_i = np.sum(np.abs(ip - im)) / len(im)
ee = np.mean(rl - rp)
if ee < 1:
ee = 1
cost_r = np.sum(np.abs(rp + ee - rl))/len(im)
cost_r = np.sum(np.abs(rp + ee - rl)) / len(im)
return cost_i, cost_r, x, ee, rp, ip

查看文件

@@ -12,7 +12,7 @@ Supported methods:
Methods
^^^^^^^
1. __constructor__ - is called in all child classes.
1. __constructor__ - is called in all child classes.
It takes the following arguments:
- `maxiter`: maximum number of iterations for the optimizer,

文件差异内容过多而无法显示 加载差异

查看文件

@@ -26,7 +26,7 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
centre of the antenna in the x-y plane and the
bottom of the antenna skid in the z direction.
resolution (float): Spatial resolution for the antenna model.
kwargs (dict): Optional variables, e.g. can be fed from an optimisation
kwargs (dict): Optional variables, e.g. can be fed from an optimisation
process.
Returns:
@@ -50,10 +50,10 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
# If using parameters from an optimisation
try:
kwargs
excitationfreq = kwargs['excitationfreq']
sourceresistance = kwargs['sourceresistance']
absorberEr = kwargs['absorberEr']
absorbersig = kwargs['absorbersig']
excitationfreq = kwargs["excitationfreq"]
sourceresistance = kwargs["sourceresistance"]
absorberEr = kwargs["absorberEr"]
absorbersig = kwargs["absorbersig"]
# Otherwise choose pre-set optimised parameters
except:
@@ -84,7 +84,7 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
bowtieheight = 0.024
tx = x + 0.062, y + 0.052, z + skidthickness
else:
logger.exception('This antenna module can only be used with a spatial resolution of 1mm or 2mm')
logger.exception("This antenna module can only be used with a spatial resolution of 1mm or 2mm")
raise ValueError
# SMD resistors - 3 on each Tx & Rx bowtie arm
@@ -100,382 +100,573 @@ def antenna_like_MALA_1200(x, y, z, resolution=0.001, **kwargs):
rxsiglower = ((1 / rxrescelllower) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor
# Material definitions
absorber = gprMax.Material(er=absorberEr, se=absorbersig, mr=1, sm=0, id='absorber')
pcb = gprMax.Material(er=3, se=0, mr=1, sm=0, id='pcb')
hdpe = gprMax.Material(er=2.35, se=0, mr=1, sm=0, id='hdpe')
polypropylene = gprMax.Material(er=2.26, se=0, mr=1, sm=0, id='polypropylene')
txreslower = gprMax.Material(er=3, se=txsiglower, mr=1, sm=0, id='txreslower')
txresupper = gprMax.Material(er=3, se=txsigupper, mr=1, sm=0, id='txresupper')
rxreslower = gprMax.Material(er=3, se=rxsiglower, mr=1, sm=0, id='rxreslower')
rxresupper = gprMax.Material(er=3, se=rxsigupper, mr=1, sm=0, id='rxresupper')
scene_objects.extend((absorber, pcb, hdpe, polypropylene, txreslower, txresupper,
rxreslower, rxresupper))
absorber = gprMax.Material(er=absorberEr, se=absorbersig, mr=1, sm=0, id="absorber")
pcb = gprMax.Material(er=3, se=0, mr=1, sm=0, id="pcb")
hdpe = gprMax.Material(er=2.35, se=0, mr=1, sm=0, id="hdpe")
polypropylene = gprMax.Material(er=2.26, se=0, mr=1, sm=0, id="polypropylene")
txreslower = gprMax.Material(er=3, se=txsiglower, mr=1, sm=0, id="txreslower")
txresupper = gprMax.Material(er=3, se=txsigupper, mr=1, sm=0, id="txresupper")
rxreslower = gprMax.Material(er=3, se=rxsiglower, mr=1, sm=0, id="rxreslower")
rxresupper = gprMax.Material(er=3, se=rxsigupper, mr=1, sm=0, id="rxresupper")
scene_objects.extend((absorber, pcb, hdpe, polypropylene, txreslower, txresupper, rxreslower, rxresupper))
# Antenna geometry
# Shield - metallic enclosure
b1 = gprMax.Box(p1=(x, y, z + skidthickness),
p2=(x + casesize[0], y + casesize[1], z + skidthickness + casesize[2]),
material_id='pec')
b2 = gprMax.Box(p1=(x + 0.020, y + casethickness, z + skidthickness),
p2=(x + 0.100, y + casesize[1] - casethickness,
z + skidthickness + casethickness), material_id='free_space')
b3 = gprMax.Box(p1=(x + 0.100, y + casethickness, z + skidthickness),
p2=(x + casesize[0] - casethickness, y + casesize[1] - casethickness,
z + skidthickness + casethickness), material_id='free_space')
b1 = gprMax.Box(
p1=(x, y, z + skidthickness),
p2=(x + casesize[0], y + casesize[1], z + skidthickness + casesize[2]),
material_id="pec",
)
b2 = gprMax.Box(
p1=(x + 0.020, y + casethickness, z + skidthickness),
p2=(x + 0.100, y + casesize[1] - casethickness, z + skidthickness + casethickness),
material_id="free_space",
)
b3 = gprMax.Box(
p1=(x + 0.100, y + casethickness, z + skidthickness),
p2=(x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + casethickness),
material_id="free_space",
)
# Absorber material
b4 = gprMax.Box(p1=(x + 0.020, y + casethickness, z + skidthickness),
p2=(x + 0.100, y + casesize[1] - casethickness,
z + skidthickness + casesize[2] - casethickness),
material_id='absorber')
b5 = gprMax.Box(p1=(x + 0.100, y + casethickness, z + skidthickness),
p2=(x + casesize[0] - casethickness, y + casesize[1] - casethickness,
z + skidthickness + casesize[2] - casethickness),
material_id='absorber')
b4 = gprMax.Box(
p1=(x + 0.020, y + casethickness, z + skidthickness),
p2=(x + 0.100, y + casesize[1] - casethickness, z + skidthickness + casesize[2] - casethickness),
material_id="absorber",
)
b5 = gprMax.Box(
p1=(x + 0.100, y + casethickness, z + skidthickness),
p2=(
x + casesize[0] - casethickness,
y + casesize[1] - casethickness,
z + skidthickness + casesize[2] - casethickness,
),
material_id="absorber",
)
scene_objects.extend((b1, b2, b3, b4, b5))
# Shield - cylindrical sections
c1 = gprMax.Cylinder(p1=(x + 0.055, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.055, y + casesize[1] - 0.008,
z + skidthickness + casesize[2] - casethickness),
r=0.008, material_id='pec')
c2 = gprMax.Cylinder(p1=(x + 0.055, y + 0.008, z + skidthickness),
p2=(x + 0.055, y + 0.008,
z + skidthickness + casesize[2] - casethickness),
r=0.008, material_id='pec')
c3 = gprMax.Cylinder(p1=(x + 0.147, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.147, y + casesize[1] - 0.008,
z + skidthickness + casesize[2] - casethickness),
r=0.008, material_id='pec')
c4 = gprMax.Cylinder(p1=(x + 0.147, y + 0.008, z + skidthickness),
p2=(x + 0.147, y + 0.008,
z + skidthickness + casesize[2] - casethickness),
r=0.008, material_id='pec')
c5 = gprMax.Cylinder(p1=(x + 0.055, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.055, y + casesize[1] - 0.008,
z + skidthickness + casesize[2] - casethickness),
r=0.007, material_id='free_space')
c6 = gprMax.Cylinder(p1=(x + 0.055, y + 0.008, z + skidthickness),
p2=(x + 0.055, y + 0.008,
z + skidthickness + casesize[2] - casethickness),
r=0.007, material_id='free_space')
c7 = gprMax.Cylinder(p1=(x + 0.147, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.147, y + casesize[1] - 0.008,
z + skidthickness + casesize[2] - casethickness),
r=0.007, material_id='free_space')
c8 = gprMax.Cylinder(p1=(x + 0.147, y + 0.008, z + skidthickness),
p2=(x + 0.147, y + 0.008,
z + skidthickness + casesize[2] - casethickness),
r=0.007, material_id='free_space')
b6 = gprMax.Box(p1=(x + 0.054, y + casesize[1] - 0.016, z + skidthickness),
p2=(x + 0.056, y + casesize[1] - 0.014,
z + skidthickness + casesize[2] - casethickness),
material_id='free_space')
b7 = gprMax.Box(p1=(x + 0.054, y + 0.014, z + skidthickness),
p2=(x + 0.056, y + 0.016,
z + skidthickness + casesize[2] - casethickness),
material_id='free_space')
b8 = gprMax.Box(p1=(x + 0.146, y + casesize[1] - 0.016, z + skidthickness),
p2=(x + 0.148, y + casesize[1] - 0.014,
z + skidthickness + casesize[2] - casethickness),
material_id='free_space')
b9 = gprMax.Box(p1=(x + 0.146, y + 0.014, z + skidthickness),
p2=(x + 0.148, y + 0.016,
z + skidthickness + casesize[2] - casethickness),
material_id='free_space')
c1 = gprMax.Cylinder(
p1=(x + 0.055, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.055, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness),
r=0.008,
material_id="pec",
)
c2 = gprMax.Cylinder(
p1=(x + 0.055, y + 0.008, z + skidthickness),
p2=(x + 0.055, y + 0.008, z + skidthickness + casesize[2] - casethickness),
r=0.008,
material_id="pec",
)
c3 = gprMax.Cylinder(
p1=(x + 0.147, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.147, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness),
r=0.008,
material_id="pec",
)
c4 = gprMax.Cylinder(
p1=(x + 0.147, y + 0.008, z + skidthickness),
p2=(x + 0.147, y + 0.008, z + skidthickness + casesize[2] - casethickness),
r=0.008,
material_id="pec",
)
c5 = gprMax.Cylinder(
p1=(x + 0.055, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.055, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness),
r=0.007,
material_id="free_space",
)
c6 = gprMax.Cylinder(
p1=(x + 0.055, y + 0.008, z + skidthickness),
p2=(x + 0.055, y + 0.008, z + skidthickness + casesize[2] - casethickness),
r=0.007,
material_id="free_space",
)
c7 = gprMax.Cylinder(
p1=(x + 0.147, y + casesize[1] - 0.008, z + skidthickness),
p2=(x + 0.147, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness),
r=0.007,
material_id="free_space",
)
c8 = gprMax.Cylinder(
p1=(x + 0.147, y + 0.008, z + skidthickness),
p2=(x + 0.147, y + 0.008, z + skidthickness + casesize[2] - casethickness),
r=0.007,
material_id="free_space",
)
b6 = gprMax.Box(
p1=(x + 0.054, y + casesize[1] - 0.016, z + skidthickness),
p2=(x + 0.056, y + casesize[1] - 0.014, z + skidthickness + casesize[2] - casethickness),
material_id="free_space",
)
b7 = gprMax.Box(
p1=(x + 0.054, y + 0.014, z + skidthickness),
p2=(x + 0.056, y + 0.016, z + skidthickness + casesize[2] - casethickness),
material_id="free_space",
)
b8 = gprMax.Box(
p1=(x + 0.146, y + casesize[1] - 0.016, z + skidthickness),
p2=(x + 0.148, y + casesize[1] - 0.014, z + skidthickness + casesize[2] - casethickness),
material_id="free_space",
)
b9 = gprMax.Box(
p1=(x + 0.146, y + 0.014, z + skidthickness),
p2=(x + 0.148, y + 0.016, z + skidthickness + casesize[2] - casethickness),
material_id="free_space",
)
scene_objects.extend((c1, c2, c3, c4, c5, c6, c7, c8, b6, b7, b8, b9))
# PCB
b10 = gprMax.Box(p1=(x + 0.020, y + 0.018, z + skidthickness),
p2=(x + casesize[0] - casethickness, y + casesize[1] - 0.018,
z + skidthickness + pcbthickness), material_id='pcb')
b10 = gprMax.Box(
p1=(x + 0.020, y + 0.018, z + skidthickness),
p2=(x + casesize[0] - casethickness, y + casesize[1] - 0.018, z + skidthickness + pcbthickness),
material_id="pcb",
)
# Shield - Tx & Rx cavities
b11 = gprMax.Box(p1=(x + 0.032, y + 0.022, z + skidthickness),
p2=(x + 0.032 + cavitysize[0], y + 0.022 + cavitysize[1],
z + skidthickness + cavitysize[2]), material_id='pec')
b12 = gprMax.Box(p1=(x + 0.032 + cavitythickness, y + 0.022 + cavitythickness,
z + skidthickness), p2=(x + 0.032 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
z + skidthickness + cavitysize[2]), material_id='absorber')
b13 = gprMax.Box(p1=(x + 0.108, y + 0.022, z + skidthickness),
p2=(x + 0.108 + cavitysize[0], y + 0.022 + cavitysize[1],
z + skidthickness + cavitysize[2]), material_id='pec')
b14 = gprMax.Box(p1=(x + 0.108 + cavitythickness, y + 0.022 + cavitythickness,
z + skidthickness), p2=(x + 0.108 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
z + skidthickness + cavitysize[2]), material_id='free_space')
b11 = gprMax.Box(
p1=(x + 0.032, y + 0.022, z + skidthickness),
p2=(x + 0.032 + cavitysize[0], y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2]),
material_id="pec",
)
b12 = gprMax.Box(
p1=(x + 0.032 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness),
p2=(
x + 0.032 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
z + skidthickness + cavitysize[2],
),
material_id="absorber",
)
b13 = gprMax.Box(
p1=(x + 0.108, y + 0.022, z + skidthickness),
p2=(x + 0.108 + cavitysize[0], y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2]),
material_id="pec",
)
b14 = gprMax.Box(
p1=(x + 0.108 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness),
p2=(
x + 0.108 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
z + skidthickness + cavitysize[2],
),
material_id="free_space",
)
# Shield - Tx & Rx cavities - joining strips
b15 = gprMax.Box(p1=(x + 0.032 + cavitysize[0], y + 0.022 + cavitysize[1] - 0.006,
z + skidthickness + cavitysize[2] - casethickness),
p2=(x + 0.108, y + 0.022 + cavitysize[1],
z + skidthickness + cavitysize[2]), material_id='pec')
b16 = gprMax.Box(p1=(x + 0.032 + cavitysize[0], y + 0.022,
z + skidthickness + cavitysize[2] - casethickness),
p2=(x + 0.108, y + 0.022 + 0.006,
z + skidthickness + cavitysize[2]), material_id='pec')
b15 = gprMax.Box(
p1=(
x + 0.032 + cavitysize[0],
y + 0.022 + cavitysize[1] - 0.006,
z + skidthickness + cavitysize[2] - casethickness,
),
p2=(x + 0.108, y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2]),
material_id="pec",
)
b16 = gprMax.Box(
p1=(x + 0.032 + cavitysize[0], y + 0.022, z + skidthickness + cavitysize[2] - casethickness),
p2=(x + 0.108, y + 0.022 + 0.006, z + skidthickness + cavitysize[2]),
material_id="pec",
)
# PCB - replace bits chopped by TX & Rx cavities
b17 = gprMax.Box(p1=(x + 0.032 + cavitythickness, y + 0.022 + cavitythickness,
z + skidthickness), p2=(x + 0.032 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
z + skidthickness + pcbthickness), material_id='pcb')
b18 = gprMax.Box(p1=(x + 0.108 + cavitythickness, y + 0.022 + cavitythickness,
z + skidthickness), p2=(x + 0.108 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
z + skidthickness + pcbthickness), material_id='pcb')
b17 = gprMax.Box(
p1=(x + 0.032 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness),
p2=(
x + 0.032 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
z + skidthickness + pcbthickness,
),
material_id="pcb",
)
b18 = gprMax.Box(
p1=(x + 0.108 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness),
p2=(
x + 0.108 + cavitysize[0] - cavitythickness,
y + 0.022 + cavitysize[1] - cavitythickness,
z + skidthickness + pcbthickness,
),
material_id="pcb",
)
scene_objects.extend((b10, b11, b12, b13, b14, b15, b16, b17, b18))
# PCB components
# Tx bowtie
if resolution == 0.001:
t1 = gprMax.Triangle(p1=(tx[0], tx[1] - 0.001, tx[2]),
p2=(tx[0] - 0.026, tx[1] - bowtieheight - 0.001, tx[2]),
p3=(tx[0] + 0.026, tx[1] - bowtieheight - 0.001, tx[2]),
thickness=0, material_id='pec')
e1 = gprMax.Edge(p1=(tx[0], tx[1] - 0.001, tx[2]),
p2=(tx[0], tx[1], tx[2]), material_id='pec')
t2 = gprMax.Triangle(p1=(tx[0], tx[1] + 0.002, tx[2]),
p2=(tx[0] - 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
p3=(tx[0] + 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
thickness=0, material_id='pec')
e2 = gprMax.Edge(p1=(tx[0], tx[1] + 0.001, tx[2]),
p2=(tx[0], tx[1] + 0.002, tx[2]), material_id='pec')
t1 = gprMax.Triangle(
p1=(tx[0], tx[1] - 0.001, tx[2]),
p2=(tx[0] - 0.026, tx[1] - bowtieheight - 0.001, tx[2]),
p3=(tx[0] + 0.026, tx[1] - bowtieheight - 0.001, tx[2]),
thickness=0,
material_id="pec",
)
e1 = gprMax.Edge(p1=(tx[0], tx[1] - 0.001, tx[2]), p2=(tx[0], tx[1], tx[2]), material_id="pec")
t2 = gprMax.Triangle(
p1=(tx[0], tx[1] + 0.002, tx[2]),
p2=(tx[0] - 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
p3=(tx[0] + 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
thickness=0,
material_id="pec",
)
e2 = gprMax.Edge(p1=(tx[0], tx[1] + 0.001, tx[2]), p2=(tx[0], tx[1] + 0.002, tx[2]), material_id="pec")
scene_objects.extend((t1, t2, e1, e2))
elif resolution == 0.002:
t1 = gprMax.Triangle(p1=(tx[0], tx[1], tx[2]),
p2=(tx[0] - 0.026, tx[1] - bowtieheight, tx[2]),
p3=(tx[0] + 0.026, tx[1] - bowtieheight, tx[2]),
thickness=0, material_id='pec')
t2 = gprMax.Triangle(p1=(tx[0], tx[1] + 0.002, tx[2]),
p2=(tx[0] - 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
p3=(tx[0] + 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
thickness=0, material_id='pec')
t1 = gprMax.Triangle(
p1=(tx[0], tx[1], tx[2]),
p2=(tx[0] - 0.026, tx[1] - bowtieheight, tx[2]),
p3=(tx[0] + 0.026, tx[1] - bowtieheight, tx[2]),
thickness=0,
material_id="pec",
)
t2 = gprMax.Triangle(
p1=(tx[0], tx[1] + 0.002, tx[2]),
p2=(tx[0] - 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
p3=(tx[0] + 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
thickness=0,
material_id="pec",
)
scene_objects.extend((t1, t2))
# Rx bowtie
if resolution == 0.001:
t3 = gprMax.Triangle(p1=(tx[0] + 0.076, tx[1] - 0.001, tx[2]),
p2=(tx[0] + 0.076 - 0.026, tx[1] - bowtieheight - 0.001, tx[2]),
p3=(tx[0] + 0.076 + 0.026, tx[1] - bowtieheight - 0.001, tx[2]),
thickness=0, material_id='pec')
e3 = gprMax.Edge(p1=(tx[0] + 0.076, tx[1] - 0.001, tx[2]),
p2=(tx[0] + 0.076, tx[1], tx[2]), material_id='pec')
t4 = gprMax.Triangle(p1=(tx[0] + 0.076, tx[1] + 0.002, tx[2]),
p2=(tx[0] + 0.076 - 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
p3=(tx[0] + 0.076 + 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
thickness=0, material_id='pec')
e4 = gprMax.Edge(p1=(tx[0] + 0.076, tx[1] + 0.001, tx[2]),
p2=(tx[0] + 0.076, tx[1] + 0.002, tx[2]), material_id='pec')
t3 = gprMax.Triangle(
p1=(tx[0] + 0.076, tx[1] - 0.001, tx[2]),
p2=(tx[0] + 0.076 - 0.026, tx[1] - bowtieheight - 0.001, tx[2]),
p3=(tx[0] + 0.076 + 0.026, tx[1] - bowtieheight - 0.001, tx[2]),
thickness=0,
material_id="pec",
)
e3 = gprMax.Edge(p1=(tx[0] + 0.076, tx[1] - 0.001, tx[2]), p2=(tx[0] + 0.076, tx[1], tx[2]), material_id="pec")
t4 = gprMax.Triangle(
p1=(tx[0] + 0.076, tx[1] + 0.002, tx[2]),
p2=(tx[0] + 0.076 - 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
p3=(tx[0] + 0.076 + 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
thickness=0,
material_id="pec",
)
e4 = gprMax.Edge(
p1=(tx[0] + 0.076, tx[1] + 0.001, tx[2]), p2=(tx[0] + 0.076, tx[1] + 0.002, tx[2]), material_id="pec"
)
scene_objects.extend((t3, e3, t4, e4))
elif resolution == 0.002:
t3 = gprMax.Triangle(p1=(tx[0] + 0.076, tx[1], tx[2]),
p2=(tx[0] + 0.076 - 0.026, tx[1] - bowtieheight, tx[2]),
p3=(tx[0] + 0.076 + 0.026, tx[1] - bowtieheight, tx[2]),
thickness=0, material_id='pec')
t4 = gprMax.Triangle(p1=(tx[0] + 0.076, tx[1] + 0.002, tx[2]),
p2=(tx[0] + 0.076 - 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
p3=(tx[0] + 0.076 + 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
thickness=0, material_id='pec')
t3 = gprMax.Triangle(
p1=(tx[0] + 0.076, tx[1], tx[2]),
p2=(tx[0] + 0.076 - 0.026, tx[1] - bowtieheight, tx[2]),
p3=(tx[0] + 0.076 + 0.026, tx[1] - bowtieheight, tx[2]),
thickness=0,
material_id="pec",
)
t4 = gprMax.Triangle(
p1=(tx[0] + 0.076, tx[1] + 0.002, tx[2]),
p2=(tx[0] + 0.076 - 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
p3=(tx[0] + 0.076 + 0.026, tx[1] + bowtieheight + 0.002, tx[2]),
thickness=0,
material_id="pec",
)
scene_objects.extend((t3, t4))
# Tx surface mount resistors (lower y coordinate)
if resolution == 0.001:
e5 = gprMax.Edge(p1=(tx[0] - 0.023, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023, tx[1] - bowtieheight - dy, tx[2]),
material_id='txreslower')
e6 = gprMax.Edge(p1=(tx[0] - 0.023 + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + dx, tx[1] - bowtieheight - dy, tx[2]),
material_id='txreslower')
e7 = gprMax.Edge(p1=(tx[0], tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0], tx[1] - bowtieheight - dy, tx[2]),
material_id='txreslower')
e8 = gprMax.Edge(p1=(tx[0] + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + dx, tx[1] - bowtieheight - dy, tx[2]),
material_id='txreslower')
e9 = gprMax.Edge(p1=(tx[0] + 0.022, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.022, tx[1] - bowtieheight - dy, tx[2]),
material_id='txreslower')
e10 = gprMax.Edge(p1=(tx[0] + 0.022 + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.022 + dx, tx[1] - bowtieheight - dy, tx[2]),
material_id='txreslower')
e5 = gprMax.Edge(
p1=(tx[0] - 0.023, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023, tx[1] - bowtieheight - dy, tx[2]),
material_id="txreslower",
)
e6 = gprMax.Edge(
p1=(tx[0] - 0.023 + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + dx, tx[1] - bowtieheight - dy, tx[2]),
material_id="txreslower",
)
e7 = gprMax.Edge(
p1=(tx[0], tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0], tx[1] - bowtieheight - dy, tx[2]),
material_id="txreslower",
)
e8 = gprMax.Edge(
p1=(tx[0] + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + dx, tx[1] - bowtieheight - dy, tx[2]),
material_id="txreslower",
)
e9 = gprMax.Edge(
p1=(tx[0] + 0.022, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.022, tx[1] - bowtieheight - dy, tx[2]),
material_id="txreslower",
)
e10 = gprMax.Edge(
p1=(tx[0] + 0.022 + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.022 + dx, tx[1] - bowtieheight - dy, tx[2]),
material_id="txreslower",
)
scene_objects.extend((e5, e6, e7, e8, e9, e10))
elif resolution == 0.002:
e5 = gprMax.Edge(p1=(tx[0] - 0.023, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023, tx[1] - bowtieheight, tx[2]),
material_id='txreslower')
e6 = gprMax.Edge(p1=(tx[0] - 0.023 + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + dx, tx[1] - bowtieheight, tx[2]),
material_id='txreslower')
e7 = gprMax.Edge(p1=(tx[0], tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0], tx[1] - bowtieheight, tx[2]),
material_id='txreslower')
e8 = gprMax.Edge(p1=(tx[0] + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + dx, tx[1] - bowtieheight, tx[2]),
material_id='txreslower')
e9 = gprMax.Edge(p1=(tx[0] + 0.020, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.020, tx[1] - bowtieheight, tx[2]),
material_id='txreslower')
e10 = gprMax.Edge(p1=(tx[0] + 0.020 + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.020 + dx, tx[1] - bowtieheight, tx[2]),
material_id='txreslower')
e5 = gprMax.Edge(
p1=(tx[0] - 0.023, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023, tx[1] - bowtieheight, tx[2]),
material_id="txreslower",
)
e6 = gprMax.Edge(
p1=(tx[0] - 0.023 + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + dx, tx[1] - bowtieheight, tx[2]),
material_id="txreslower",
)
e7 = gprMax.Edge(
p1=(tx[0], tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0], tx[1] - bowtieheight, tx[2]),
material_id="txreslower",
)
e8 = gprMax.Edge(
p1=(tx[0] + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + dx, tx[1] - bowtieheight, tx[2]),
material_id="txreslower",
)
e9 = gprMax.Edge(
p1=(tx[0] + 0.020, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.020, tx[1] - bowtieheight, tx[2]),
material_id="txreslower",
)
e10 = gprMax.Edge(
p1=(tx[0] + 0.020 + dx, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.020 + dx, tx[1] - bowtieheight, tx[2]),
material_id="txreslower",
)
scene_objects.extend((e5, e6, e7, e8, e9, e10))
# Tx surface mount resistors (upper y coordinate)
if resolution == 0.001:
e11 = gprMax.Edge(p1=(tx[0] - 0.023, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e12 = gprMax.Edge(p1=(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e13 = gprMax.Edge(p1=(tx[0], tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0], tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e14 = gprMax.Edge(p1=(tx[0] + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e15 = gprMax.Edge(p1=(tx[0] + 0.022, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.022, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e16 = gprMax.Edge(p1=(tx[0] + 0.022 + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.022 + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e11 = gprMax.Edge(
p1=(tx[0] - 0.023, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
e12 = gprMax.Edge(
p1=(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
e13 = gprMax.Edge(
p1=(tx[0], tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0], tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
e14 = gprMax.Edge(
p1=(tx[0] + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
e15 = gprMax.Edge(
p1=(tx[0] + 0.022, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.022, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
e16 = gprMax.Edge(
p1=(tx[0] + 0.022 + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.022 + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
scene_objects.extend((e11, e12, e13, e14, e15, e16))
elif resolution == 0.002:
e11 = gprMax.Edge(p1=(tx[0] - 0.023, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e12 = gprMax.Edge(p1=(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e13 = gprMax.Edge(p1=(tx[0], tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0], tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e14 = gprMax.Edge(p1=(tx[0] + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e15 = gprMax.Edge(p1=(tx[0] + 0.020, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.020, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e16 = gprMax.Edge(p1=(tx[0] + 0.020 + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.020 + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='txresupper')
e11 = gprMax.Edge(
p1=(tx[0] - 0.023, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
e12 = gprMax.Edge(
p1=(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
e13 = gprMax.Edge(
p1=(tx[0], tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0], tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
e14 = gprMax.Edge(
p1=(tx[0] + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
e15 = gprMax.Edge(
p1=(tx[0] + 0.020, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.020, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
e16 = gprMax.Edge(
p1=(tx[0] + 0.020 + dx, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.020 + dx, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="txresupper",
)
scene_objects.extend((e11, e12, e13, e14, e15, e16))
# Rx surface mount resistors (lower y coordinate)
if resolution == 0.001:
e17 = gprMax.Edge(p1=(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id='rxreslower')
e18 = gprMax.Edge(p1=(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id='rxreslower')
e19 = gprMax.Edge(p1=(tx[0] + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id='rxreslower')
e20 = gprMax.Edge(p1=(tx[0] + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + dx + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id='rxreslower')
e21 = gprMax.Edge(p1=(tx[0] + 0.022 + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.022 + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id='rxreslower')
e22 = gprMax.Edge(p1=(tx[0] + 0.022 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.022 + dx + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id='rxreslower')
e17 = gprMax.Edge(
p1=(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id="rxreslower",
)
e18 = gprMax.Edge(
p1=(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id="rxreslower",
)
e19 = gprMax.Edge(
p1=(tx[0] + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id="rxreslower",
)
e20 = gprMax.Edge(
p1=(tx[0] + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + dx + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id="rxreslower",
)
e21 = gprMax.Edge(
p1=(tx[0] + 0.022 + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.022 + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id="rxreslower",
)
e22 = gprMax.Edge(
p1=(tx[0] + 0.022 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.022 + dx + 0.076, tx[1] - bowtieheight - dy, tx[2]),
material_id="rxreslower",
)
scene_objects.extend((e17, e18, e19, e20, e21, e22))
elif resolution == 0.002:
e17 = gprMax.Edge(p1=(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight, tx[2]),
material_id='rxreslower')
e18 = gprMax.Edge(p1=(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight, tx[2]),
material_id='rxreslower')
e19 = gprMax.Edge(p1=(tx[0] + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.076, tx[1] - bowtieheight, tx[2]),
material_id='rxreslower')
e20 = gprMax.Edge(p1=(tx[0] + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + dx + 0.076, tx[1] - bowtieheight, tx[2]),
material_id='rxreslower')
e21 = gprMax.Edge(p1=(tx[0] + 0.020 + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.020 + 0.076, tx[1] - bowtieheight, tx[2]),
material_id='rxreslower')
e22 = gprMax.Edge(p1=(tx[0] + 0.020 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.020 + dx + 0.076, tx[1] - bowtieheight, tx[2]),
material_id='rxreslower')
e17 = gprMax.Edge(
p1=(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight, tx[2]),
material_id="rxreslower",
)
e18 = gprMax.Edge(
p1=(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight, tx[2]),
material_id="rxreslower",
)
e19 = gprMax.Edge(
p1=(tx[0] + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.076, tx[1] - bowtieheight, tx[2]),
material_id="rxreslower",
)
e20 = gprMax.Edge(
p1=(tx[0] + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + dx + 0.076, tx[1] - bowtieheight, tx[2]),
material_id="rxreslower",
)
e21 = gprMax.Edge(
p1=(tx[0] + 0.020 + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.020 + 0.076, tx[1] - bowtieheight, tx[2]),
material_id="rxreslower",
)
e22 = gprMax.Edge(
p1=(tx[0] + 0.020 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2]),
p2=(tx[0] + 0.020 + dx + 0.076, tx[1] - bowtieheight, tx[2]),
material_id="rxreslower",
)
scene_objects.extend((e17, e18, e19, e20, e21, e22))
# Rx surface mount resistors (upper y coordinate)
if resolution == 0.001:
e23 = gprMax.Edge(p1=(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e24 = gprMax.Edge(p1=(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e25 = gprMax.Edge(p1=(tx[0] + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e26 = gprMax.Edge(p1=(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e27 = gprMax.Edge(p1=(tx[0] + 0.022 + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.022 + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e28 = gprMax.Edge(p1=(tx[0] + 0.022 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.022 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e23 = gprMax.Edge(
p1=(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
e24 = gprMax.Edge(
p1=(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
e25 = gprMax.Edge(
p1=(tx[0] + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
e26 = gprMax.Edge(
p1=(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
e27 = gprMax.Edge(
p1=(tx[0] + 0.022 + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.022 + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
e28 = gprMax.Edge(
p1=(tx[0] + 0.022 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.022 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
scene_objects.extend((e23, e24, e25, e26, e27, e28))
elif resolution == 0.002:
e23 = gprMax.Edge(p1=(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e24 = gprMax.Edge(p1=(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e25 = gprMax.Edge(p1=(tx[0] + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e26 = gprMax.Edge(p1=(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e27 = gprMax.Edge(p1=(tx[0] + 0.020 + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.020 + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e28 = gprMax.Edge(p1=(tx[0] + 0.020 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.020 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id='rxresupper')
e23 = gprMax.Edge(
p1=(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
e24 = gprMax.Edge(
p1=(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
e25 = gprMax.Edge(
p1=(tx[0] + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
e26 = gprMax.Edge(
p1=(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
e27 = gprMax.Edge(
p1=(tx[0] + 0.020 + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.020 + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
e28 = gprMax.Edge(
p1=(tx[0] + 0.020 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2]),
p2=(tx[0] + 0.020 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2]),
material_id="rxresupper",
)
scene_objects.extend((e23, e24, e25, e26, e27, e28))
# Skid
b19 = gprMax.Box(p1=(x, y, z), p2=(x + casesize[0], y + casesize[1],
z + polypropylenethickness), material_id='polypropylene')
b20 = gprMax.Box(p1=(x, y, z + polypropylenethickness),
p2=(x + casesize[0], y + casesize[1],
z + polypropylenethickness + hdpethickness),
material_id='hdpe')
b19 = gprMax.Box(
p1=(x, y, z), p2=(x + casesize[0], y + casesize[1], z + polypropylenethickness), material_id="polypropylene"
)
b20 = gprMax.Box(
p1=(x, y, z + polypropylenethickness),
p2=(x + casesize[0], y + casesize[1], z + polypropylenethickness + hdpethickness),
material_id="hdpe",
)
scene_objects.extend((b19, b20))
# Excitation
w2 = gprMax.Waveform(wave_type='gaussian', amp=1, freq=excitationfreq, id='my_gaussian')
w2 = gprMax.Waveform(wave_type="gaussian", amp=1, freq=excitationfreq, id="my_gaussian")
scene_objects.append(w2)
vs1 = gprMax.VoltageSource(polarisation='y', p1=(tx[0], tx[1], tx[2]),
resistance=sourceresistance, waveform_id='my_gaussian')
vs1 = gprMax.VoltageSource(
polarisation="y", p1=(tx[0], tx[1], tx[2]), resistance=sourceresistance, waveform_id="my_gaussian"
)
scene_objects.append(vs1)
# Output point - receiver bowtie
r1 = gprMax.Rx(p1=(tx[0] + 0.076, tx[1], tx[2]), id='rxbowtie', outputs='Ey')
r1 = gprMax.Rx(p1=(tx[0] + 0.076, tx[1], tx[2]), id="rxbowtie", outputs="Ey")
scene_objects.append(r1)
# Geometry views
gv1 = gprMax.GeometryView(p1=(x - dx, y - dy, z - dz), p2=(x + casesize[0] + dx,
y + casesize[1] + dy, z + skidthickness + casesize[2] + dz),
dl=(dx, dy, dz), filename='antenna_like_MALA_1200',
output_type='n')
gv2 = gprMax.GeometryView(p1=(x, y, z), p2=(x + casesize[0], y + casesize[1], z + 0.010),
dl=(dx, dy, dz), filename='antenna_like_MALA_1200_pcb',
output_type='f')
gv1 = gprMax.GeometryView(
p1=(x - dx, y - dy, z - dz),
p2=(x + casesize[0] + dx, y + casesize[1] + dy, z + skidthickness + casesize[2] + dz),
dl=(dx, dy, dz),
filename="antenna_like_MALA_1200",
output_type="n",
)
gv2 = gprMax.GeometryView(
p1=(x, y, z),
p2=(x + casesize[0], y + casesize[1], z + 0.010),
dl=(dx, dy, dz),
filename="antenna_like_MALA_1200_pcb",
output_type="f",
)
# scene_objects.extend((gv1, gv2))
return scene_objects

查看文件

@@ -53,11 +53,11 @@ To include an antenna model similar to a GSSI 1.5 GHz antenna at a location 0.12
from toolboxes.GPRAntennaModels.GSSI import antenna_like_GSSI_1500
scene = gprMax.Scene()
# Import antenna model and add to model
dl = 0.002
ant_pos = (0.125, 0.094, 0.100)
gssi_objects = antenna_like_GSSI_1500(ant_pos[0], ant_pos[1], ant_pos[2],
gssi_objects = antenna_like_GSSI_1500(ant_pos[0], ant_pos[1], ant_pos[2],
resolution=dl)
for obj in gssi_objects:
# Rotate antenna model if desired

查看文件

@@ -253,7 +253,7 @@ where :math:`dt` is the temporal resolution (timestep) of the model.
Example of the ``impulse`` waveform - time domain.
.. note::
* The impulse waveform should be used with care!
* The impulse response of a model, i.e. when the source in the model is excited using the impulse waveform, is not likely to be useful when viewed in isolation.
* The impulse waveform should be used with care!
* The impulse response of a model, i.e. when the source in the model is excited using the impulse waveform, is not likely to be useful when viewed in isolation.
* However, the impulse response of a model can be convolved with different inputs (waveforms) to provide valid outputs without having to run a separate model for each different input (waveform).
* The impulse response of the model can only be legitimately convolved with inputs (waveforms) that respect the limits of numerical dispersion in the original model, i.e. if a waveform contains frequencies that will not propagate correctly (due to numerical dispersion) in the original model, then the convolution of the waveform with the impulse response will not be valid.
* The impulse response of the model can only be legitimately convolved with inputs (waveforms) that respect the limits of numerical dispersion in the original model, i.e. if a waveform contains frequencies that will not propagate correctly (due to numerical dispersion) in the original model, then the convolution of the waveform with the impulse response will not be valid.

查看文件

@@ -48,55 +48,53 @@ def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False, save=False):
file = Path(filename)
# Open output file and read iterations
f = h5py.File(file, 'r')
f = h5py.File(file, "r")
# Paths to grid(s) to traverse for outputs
paths = ['/']
paths = ["/"]
# Check if any subgrids and add path(s)
is_subgrids = "/subgrids" in f
if is_subgrids:
paths = paths + ['/subgrids/' + path + '/' for path in f['/subgrids'].keys()]
paths = paths + ["/subgrids/" + path + "/" for path in f["/subgrids"].keys()]
# Get number of receivers in grid(s)
nrxs = []
for path in paths:
if f[path].attrs['nrx'] > 0:
nrxs.append(f[path].attrs['nrx'])
if f[path].attrs["nrx"] > 0:
nrxs.append(f[path].attrs["nrx"])
else:
paths.remove(path)
# Check there are any receivers
if not paths:
logger.exception(f'No receivers found in {file}')
logger.exception(f"No receivers found in {file}")
raise ValueError
# Loop through all grids
for path in paths:
iterations = f[path].attrs['Iterations']
nrx = f[path].attrs['nrx']
dt = f[path].attrs['dt']
iterations = f[path].attrs["Iterations"]
nrx = f[path].attrs["nrx"]
dt = f[path].attrs["dt"]
time = np.linspace(0, (iterations - 1) * dt, num=iterations)
# Check for single output component when doing a FFT
if fft:
if not len(outputs) == 1:
logger.exception('A single output must be specified when using ' +
'the -fft option')
logger.exception("A single output must be specified when using " + "the -fft option")
raise ValueError
# New plot for each receiver
for rx in range(1, nrx + 1):
rxpath = path + 'rxs/rx' + str(rx) + '/'
rxpath = path + "rxs/rx" + str(rx) + "/"
availableoutputs = list(f[rxpath].keys())
# If only a single output is required, create one subplot
if len(outputs) == 1:
# Check for polarity of output and if requested output is in file
if outputs[0][-1] == '-':
if outputs[0][-1] == "-":
polarity = -1
outputtext = '-' + outputs[0][0:-1]
outputtext = "-" + outputs[0][0:-1]
output = outputs[0][0:-1]
else:
polarity = 1
@@ -104,9 +102,11 @@ def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False, save=False):
output = outputs[0]
if output not in availableoutputs:
logger.exception(f"{output} output requested to plot, but " +
f"the available output for receiver 1 is " +
f"{', '.join(availableoutputs)}")
logger.exception(
f"{output} output requested to plot, but "
+ f"the available output for receiver 1 is "
+ f"{', '.join(availableoutputs)}"
)
raise ValueError
outputdata = f[rxpath + output][:] * polarity
@@ -118,7 +118,7 @@ def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False, save=False):
freqmaxpower = np.where(np.isclose(power, 0))[0][0]
# Set plotting range to -60dB from maximum power or 4 times
# frequency at maximum power
# frequency at maximum power
try:
pltrange = np.where(power[freqmaxpower:] < -60)[0][0] + freqmaxpower + 1
except:
@@ -127,82 +127,91 @@ def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False, save=False):
pltrange = np.s_[0:pltrange]
# Plot time history of output component
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2,
num=rxpath + ' - ' + f[rxpath].attrs['Name'],
figsize=(20, 10), facecolor='w',
edgecolor='w')
line1 = ax1.plot(time, outputdata, 'r', lw=2, label=outputtext)
ax1.set_xlabel('Time [s]')
ax1.set_ylabel(outputtext + ' field strength [V/m]')
fig, (ax1, ax2) = plt.subplots(
nrows=1,
ncols=2,
num=rxpath + " - " + f[rxpath].attrs["Name"],
figsize=(20, 10),
facecolor="w",
edgecolor="w",
)
line1 = ax1.plot(time, outputdata, "r", lw=2, label=outputtext)
ax1.set_xlabel("Time [s]")
ax1.set_ylabel(outputtext + " field strength [V/m]")
ax1.set_xlim([0, np.amax(time)])
ax1.grid(which='both', axis='both', linestyle='-.')
ax1.grid(which="both", axis="both", linestyle="-.")
# Plot frequency spectra
markerline, stemlines, baseline = ax2.stem(freqs[pltrange],
power[pltrange], '-.',
use_line_collection=True)
plt.setp(baseline, 'linewidth', 0)
plt.setp(stemlines, 'color', 'r')
plt.setp(markerline, 'markerfacecolor', 'r', 'markeredgecolor', 'r')
line2 = ax2.plot(freqs[pltrange], power[pltrange], 'r', lw=2)
ax2.set_xlabel('Frequency [Hz]')
ax2.set_ylabel('Power [dB]')
ax2.grid(which='both', axis='both', linestyle='-.')
markerline, stemlines, baseline = ax2.stem(
freqs[pltrange], power[pltrange], "-.", use_line_collection=True
)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "r")
plt.setp(markerline, "markerfacecolor", "r", "markeredgecolor", "r")
line2 = ax2.plot(freqs[pltrange], power[pltrange], "r", lw=2)
ax2.set_xlabel("Frequency [Hz]")
ax2.set_ylabel("Power [dB]")
ax2.grid(which="both", axis="both", linestyle="-.")
# Change colours and labels for magnetic field components
# Change colours and labels for magnetic field components
# or currents
if 'H' in outputs[0]:
plt.setp(line1, color='g')
plt.setp(line2, color='g')
plt.setp(ax1, ylabel=outputtext + ' field strength [A/m]')
plt.setp(stemlines, 'color', 'g')
plt.setp(markerline, 'markerfacecolor', 'g',
'markeredgecolor', 'g')
elif 'I' in outputs[0]:
plt.setp(line1, color='b')
plt.setp(line2, color='b')
plt.setp(ax1, ylabel=outputtext + ' current [A]')
plt.setp(stemlines, 'color', 'b')
plt.setp(markerline, 'markerfacecolor', 'b',
'markeredgecolor', 'b')
if "H" in outputs[0]:
plt.setp(line1, color="g")
plt.setp(line2, color="g")
plt.setp(ax1, ylabel=outputtext + " field strength [A/m]")
plt.setp(stemlines, "color", "g")
plt.setp(markerline, "markerfacecolor", "g", "markeredgecolor", "g")
elif "I" in outputs[0]:
plt.setp(line1, color="b")
plt.setp(line2, color="b")
plt.setp(ax1, ylabel=outputtext + " current [A]")
plt.setp(stemlines, "color", "b")
plt.setp(markerline, "markerfacecolor", "b", "markeredgecolor", "b")
plt.show()
# Plotting if no FFT required
else:
fig, ax = plt.subplots(subplot_kw=dict(xlabel='Time [s]',
ylabel=outputtext + ' field strength [V/m]'),
num=rxpath + ' - ' + f[rxpath].attrs['Name'],
figsize=(20, 10), facecolor='w', edgecolor='w')
line = ax.plot(time, outputdata, 'r', lw=2, label=outputtext)
fig, ax = plt.subplots(
subplot_kw=dict(xlabel="Time [s]", ylabel=outputtext + " field strength [V/m]"),
num=rxpath + " - " + f[rxpath].attrs["Name"],
figsize=(20, 10),
facecolor="w",
edgecolor="w",
)
line = ax.plot(time, outputdata, "r", lw=2, label=outputtext)
ax.set_xlim([0, np.amax(time)])
# ax.set_ylim([-15, 20])
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
if 'H' in output:
plt.setp(line, color='g')
plt.setp(ax, ylabel=outputtext + ', field strength [A/m]')
elif 'I' in output:
plt.setp(line, color='b')
plt.setp(ax, ylabel=outputtext + ', current [A]')
if "H" in output:
plt.setp(line, color="g")
plt.setp(ax, ylabel=outputtext + ", field strength [A/m]")
elif "I" in output:
plt.setp(line, color="b")
plt.setp(ax, ylabel=outputtext + ", current [A]")
# If multiple outputs required, create all nine subplots and
# If multiple outputs required, create all nine subplots and
# populate only the specified ones
else:
fig, ax = plt.subplots(subplot_kw=dict(xlabel='Time [s]'),
num=rxpath + ' - ' + f[rxpath].attrs['Name'],
figsize=(20, 10), facecolor='w', edgecolor='w')
fig, ax = plt.subplots(
subplot_kw=dict(xlabel="Time [s]"),
num=rxpath + " - " + f[rxpath].attrs["Name"],
figsize=(20, 10),
facecolor="w",
edgecolor="w",
)
if len(outputs) == 9:
gs = gridspec.GridSpec(3, 3, hspace=0.3, wspace=0.3)
else:
gs = gridspec.GridSpec(3, 2, hspace=0.3, wspace=0.3)
for output in outputs:
# Check for polarity of output and if requested output
# Check for polarity of output and if requested output
# is in file
if output[-1] == 'm':
if output[-1] == "m":
polarity = -1
outputtext = '-' + output[0:-1]
outputtext = "-" + output[0:-1]
output = output[0:-1]
else:
polarity = 1
@@ -210,93 +219,115 @@ def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False, save=False):
# Check if requested output is in file
if output not in availableoutputs:
logger.exception(f"Output(s) requested to plot: " +
f"{', '.join(outputs)}, but available output(s) " +
f"for receiver {rx} in the file: " +
f"{', '.join(availableoutputs)}")
logger.exception(
f"Output(s) requested to plot: "
+ f"{', '.join(outputs)}, but available output(s) "
+ f"for receiver {rx} in the file: "
+ f"{', '.join(availableoutputs)}"
)
raise ValueError
outputdata = f[rxpath + output][:] * polarity
if output == 'Ex':
if output == "Ex":
ax = plt.subplot(gs[0, 0])
ax.plot(time, outputdata, 'r', lw=2, label=outputtext)
ax.set_ylabel(outputtext + ', field strength [V/m]')
ax.plot(time, outputdata, "r", lw=2, label=outputtext)
ax.set_ylabel(outputtext + ", field strength [V/m]")
# ax.set_ylim([-15, 20])
elif output == 'Ey':
elif output == "Ey":
ax = plt.subplot(gs[1, 0])
ax.plot(time, outputdata, 'r', lw=2, label=outputtext)
ax.set_ylabel(outputtext + ', field strength [V/m]')
ax.plot(time, outputdata, "r", lw=2, label=outputtext)
ax.set_ylabel(outputtext + ", field strength [V/m]")
# ax.set_ylim([-15, 20])
elif output == 'Ez':
elif output == "Ez":
ax = plt.subplot(gs[2, 0])
ax.plot(time, outputdata, 'r', lw=2, label=outputtext)
ax.set_ylabel(outputtext + ', field strength [V/m]')
ax.plot(time, outputdata, "r", lw=2, label=outputtext)
ax.set_ylabel(outputtext + ", field strength [V/m]")
# ax.set_ylim([-15, 20])
elif output == 'Hx':
elif output == "Hx":
ax = plt.subplot(gs[0, 1])
ax.plot(time, outputdata, 'g', lw=2, label=outputtext)
ax.set_ylabel(outputtext + ', field strength [A/m]')
ax.plot(time, outputdata, "g", lw=2, label=outputtext)
ax.set_ylabel(outputtext + ", field strength [A/m]")
# ax.set_ylim([-0.03, 0.03])
elif output == 'Hy':
elif output == "Hy":
ax = plt.subplot(gs[1, 1])
ax.plot(time, outputdata, 'g', lw=2, label=outputtext)
ax.set_ylabel(outputtext + ', field strength [A/m]')
ax.plot(time, outputdata, "g", lw=2, label=outputtext)
ax.set_ylabel(outputtext + ", field strength [A/m]")
# ax.set_ylim([-0.03, 0.03])
elif output == 'Hz':
elif output == "Hz":
ax = plt.subplot(gs[2, 1])
ax.plot(time, outputdata, 'g', lw=2, label=outputtext)
ax.set_ylabel(outputtext + ', field strength [A/m]')
ax.plot(time, outputdata, "g", lw=2, label=outputtext)
ax.set_ylabel(outputtext + ", field strength [A/m]")
# ax.set_ylim([-0.03, 0.03])
elif output == 'Ix':
elif output == "Ix":
ax = plt.subplot(gs[0, 2])
ax.plot(time, outputdata, 'b', lw=2, label=outputtext)
ax.set_ylabel(outputtext + ', current [A]')
elif output == 'Iy':
ax.plot(time, outputdata, "b", lw=2, label=outputtext)
ax.set_ylabel(outputtext + ", current [A]")
elif output == "Iy":
ax = plt.subplot(gs[1, 2])
ax.plot(time, outputdata, 'b', lw=2, label=outputtext)
ax.set_ylabel(outputtext + ', current [A]')
elif output == 'Iz':
ax.plot(time, outputdata, "b", lw=2, label=outputtext)
ax.set_ylabel(outputtext + ", current [A]")
elif output == "Iz":
ax = plt.subplot(gs[2, 2])
ax.plot(time, outputdata, 'b', lw=2, label=outputtext)
ax.set_ylabel(outputtext + ', current [A]')
ax.plot(time, outputdata, "b", lw=2, label=outputtext)
ax.set_ylabel(outputtext + ", current [A]")
for ax in fig.axes:
ax.set_xlim([0, np.amax(time)])
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
f.close()
if save:
# Save a PDF of the figure
fig.savefig(filename[:-3] + '.pdf', dpi=None, format='pdf',
bbox_inches='tight', pad_inches=0.1)
fig.savefig(filename[:-3] + ".pdf", dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
# Save a PNG of the figure
# fig.savefig(filename[:-3] + '.png', dpi=150, format='png',
# fig.savefig(filename[:-3] + '.png', dpi=150, format='png',
# bbox_inches='tight', pad_inches=0.1)
return plt
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Plots electric and magnetic fields and ' +
'currents from all receiver points in the given output file. ' +
'Each receiver point is plotted in a new figure window.',
usage='cd gprMax; python -m toolboxes.Plotting.plot_Ascan outputfile')
parser.add_argument('outputfile', help='name of output file including path')
parser.add_argument('--outputs', help='outputs to be plotted',
default=Rx.defaultoutputs,
choices=['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz',
'Ix', 'Iy', 'Iz', 'Ex-', 'Ey-', 'Ez-',
'Hx-', 'Hy-', 'Hz-', 'Ix-', 'Iy-', 'Iz-'],
nargs='+')
parser.add_argument('-fft', action='store_true', default=False,
help='plot FFT (single output must be specified)')
parser.add_argument('-save', action='store_true', default=False,
help='save plot directly to file, i.e. do not display')
parser = argparse.ArgumentParser(
description="Plots electric and magnetic fields and "
+ "currents from all receiver points in the given output file. "
+ "Each receiver point is plotted in a new figure window.",
usage="cd gprMax; python -m toolboxes.Plotting.plot_Ascan outputfile",
)
parser.add_argument("outputfile", help="name of output file including path")
parser.add_argument(
"--outputs",
help="outputs to be plotted",
default=Rx.defaultoutputs,
choices=[
"Ex",
"Ey",
"Ez",
"Hx",
"Hy",
"Hz",
"Ix",
"Iy",
"Iz",
"Ex-",
"Ey-",
"Ez-",
"Hx-",
"Hy-",
"Hz-",
"Ix-",
"Iy-",
"Iz-",
],
nargs="+",
)
parser.add_argument("-fft", action="store_true", default=False, help="plot FFT (single output must be specified)")
parser.add_argument(
"-save", action="store_true", default=False, help="save plot directly to file, i.e. do not display"
)
args = parser.parse_args()
plthandle = mpl_plot(args.outputfile, args.outputs, fft=args.fft, save=args.save)
plthandle.show()
plthandle.show()

查看文件

@@ -46,59 +46,69 @@ def mpl_plot(filename, outputdata, dt, rxnumber, rxcomponent, save=False):
file = Path(filename)
fig = plt.figure(num=file.stem + ' - rx' + str(rxnumber), figsize=(20, 10),
facecolor='w', edgecolor='w')
plt.imshow(outputdata, extent=[0, outputdata.shape[1], outputdata.shape[0] * dt, 0],
interpolation='nearest', aspect='auto', cmap='seismic',
vmin=-np.amax(np.abs(outputdata)), vmax=np.amax(np.abs(outputdata)))
plt.xlabel('Trace number')
plt.ylabel('Time [s]')
fig = plt.figure(num=file.stem + " - rx" + str(rxnumber), figsize=(20, 10), facecolor="w", edgecolor="w")
plt.imshow(
outputdata,
extent=[0, outputdata.shape[1], outputdata.shape[0] * dt, 0],
interpolation="nearest",
aspect="auto",
cmap="seismic",
vmin=-np.amax(np.abs(outputdata)),
vmax=np.amax(np.abs(outputdata)),
)
plt.xlabel("Trace number")
plt.ylabel("Time [s]")
# Grid properties
ax = fig.gca()
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
cb = plt.colorbar()
if 'E' in rxcomponent:
cb.set_label('Field strength [V/m]')
elif 'H' in rxcomponent:
cb.set_label('Field strength [A/m]')
elif 'I' in rxcomponent:
cb.set_label('Current [A]')
if "E" in rxcomponent:
cb.set_label("Field strength [V/m]")
elif "H" in rxcomponent:
cb.set_label("Field strength [A/m]")
elif "I" in rxcomponent:
cb.set_label("Current [A]")
if save:
# Save a PDF of the figure
fig.savefig(filename[:-3] + '.pdf', dpi=None, format='pdf',
bbox_inches='tight', pad_inches=0.1)
fig.savefig(filename[:-3] + ".pdf", dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
# Save a PNG of the figure
# fig.savefig(filename[:-3] + '.png', dpi=150, format='png',
# fig.savefig(filename[:-3] + '.png', dpi=150, format='png',
# bbox_inches='tight', pad_inches=0.1)
return plt
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Plots a B-scan image.',
usage='cd gprMax; python -m toolboxes.Plotting.plot_Bscan outputfile output')
parser.add_argument('outputfile', help='name of output file including path')
parser.add_argument('rx_component', help='name of output component to be plotted',
choices=['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz', 'Ix', 'Iy', 'Iz'])
parser.add_argument('-gather', action='store_true', default=False,
help='gather together all receiver outputs in file')
parser.add_argument('-save', action='store_true', default=False,
help='save plot directly to file, i.e. do not display')
parser = argparse.ArgumentParser(
description="Plots a B-scan image.",
usage="cd gprMax; python -m toolboxes.Plotting.plot_Bscan outputfile output",
)
parser.add_argument("outputfile", help="name of output file including path")
parser.add_argument(
"rx_component",
help="name of output component to be plotted",
choices=["Ex", "Ey", "Ez", "Hx", "Hy", "Hz", "Ix", "Iy", "Iz"],
)
parser.add_argument(
"-gather", action="store_true", default=False, help="gather together all receiver outputs in file"
)
parser.add_argument(
"-save", action="store_true", default=False, help="save plot directly to file, i.e. do not display"
)
args = parser.parse_args()
# Open output file and read number of outputs (receivers)
f = h5py.File(args.outputfile, 'r')
nrx = f.attrs['nrx']
f = h5py.File(args.outputfile, "r")
nrx = f.attrs["nrx"]
f.close()
# Check there are any receivers
if nrx == 0:
logger.exception(f'No receivers found in {args.outputfile}')
logger.exception(f"No receivers found in {args.outputfile}")
raise ValueError
for rx in range(1, nrx + 1):
@@ -108,12 +118,10 @@ if __name__ == "__main__":
rxsgather = outputdata
rxsgather = np.column_stack((rxsgather, outputdata))
else:
plthandle = mpl_plot(args.outputfile, outputdata, dt, rx,
args.rx_component, save=args.save)
plthandle = mpl_plot(args.outputfile, outputdata, dt, rx, args.rx_component, save=args.save)
# Plot all receivers from single output file together if required
if args.gather:
plthandle = mpl_plot(args.outputfile, rxsgather, dt, rx,
args.rx_component, save=args.save)
plthandle = mpl_plot(args.outputfile, rxsgather, dt, rx, args.rx_component, save=args.save)
plthandle.show()

查看文件

@@ -45,65 +45,67 @@ def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=N
# Open output file and read some attributes
file = Path(filename)
f = h5py.File(file, 'r')
dxdydz = f.attrs['dx_dy_dz']
dt = f.attrs['dt']
iterations = f.attrs['Iterations']
f = h5py.File(file, "r")
dxdydz = f.attrs["dx_dy_dz"]
dt = f.attrs["dt"]
iterations = f.attrs["Iterations"]
# Calculate time array and frequency bin spacing
time = np.linspace(0, (iterations - 1) * dt, num=iterations)
df = 1 / np.amax(time)
logger.info(f'Time window: {np.amax(time):g} s ({iterations} iterations)')
logger.info(f'Time step: {dt:g} s')
logger.info(f'Frequency bin spacing: {df:g} Hz')
logger.info(f"Time window: {np.amax(time):g} s ({iterations} iterations)")
logger.info(f"Time step: {dt:g} s")
logger.info(f"Frequency bin spacing: {df:g} Hz")
# Read/calculate voltages and currents from transmitter antenna
tltxpath = '/tls/tl' + str(tltxnumber) + '/'
tltxpath = "/tls/tl" + str(tltxnumber) + "/"
# Incident voltages/currents
Vinc = f[tltxpath + 'Vinc'][:]
Iinc = f[tltxpath + 'Iinc'][:]
Vinc = f[tltxpath + "Vinc"][:]
Iinc = f[tltxpath + "Iinc"][:]
# Total (incident + reflected) voltages/currents
Vtotal = f[tltxpath + 'Vtotal'][:]
Itotal = f[tltxpath + 'Itotal'][:]
Vtotal = f[tltxpath + "Vtotal"][:]
Itotal = f[tltxpath + "Itotal"][:]
# Reflected voltages/currents
Vref = Vtotal - Vinc
Iref = Itotal - Iinc
# If a receiver antenna is used (with a transmission line or receiver),
# If a receiver antenna is used (with a transmission line or receiver),
# get received voltage for s21
if tlrxnumber:
tlrxpath = '/tls/tl' + str(tlrxnumber) + '/'
Vrec = f[tlrxpath + 'Vtotal'][:]
tlrxpath = "/tls/tl" + str(tlrxnumber) + "/"
Vrec = f[tlrxpath + "Vtotal"][:]
elif rxnumber:
rxpath = '/rxs/rx' + str(rxnumber) + '/'
rxpath = "/rxs/rx" + str(rxnumber) + "/"
availableoutputs = list(f[rxpath].keys())
if rxcomponent not in availableoutputs:
logger.exception(f"{rxcomponent} output requested, but the available " +
f"output for receiver {rxnumber} is " +
f"{', '.join(availableoutputs)}")
logger.exception(
f"{rxcomponent} output requested, but the available "
+ f"output for receiver {rxnumber} is "
+ f"{', '.join(availableoutputs)}"
)
raise ValueError
rxpath += rxcomponent
# Received voltage
if rxcomponent == 'Ex':
if rxcomponent == "Ex":
Vrec = f[rxpath][:] * -1 * dxdydz[0]
elif rxcomponent == 'Ey':
elif rxcomponent == "Ey":
Vrec = f[rxpath][:] * -1 * dxdydz[1]
elif rxcomponent == 'Ez':
elif rxcomponent == "Ez":
Vrec = f[rxpath][:] * -1 * dxdydz[2]
f.close()
# Frequency bins
freqs = np.fft.fftfreq(Vinc.size, d=dt)
# Delay correction - current lags voltage, so delay voltage to match
# Delay correction - current lags voltage, so delay voltage to match
# current timestep
delaycorrection = np.exp(1j * 2 * np.pi * freqs * (dt / 2))
@@ -119,7 +121,7 @@ def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=N
yin = np.fft.fft(Itotal) / (np.fft.fft(Vtotal) * delaycorrection)
# Convert to decibels (ignore warning from taking a log of any zero values)
with np.errstate(divide='ignore'):
with np.errstate(divide="ignore"):
Vincp = 20 * np.log10(np.abs((np.fft.fft(Vinc) * delaycorrection)))
Iincp = 20 * np.log10(np.abs(np.fft.fft(Iinc)))
Vrefp = 20 * np.log10(np.abs((np.fft.fft(Vref) * delaycorrection)))
@@ -138,23 +140,56 @@ def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=N
s11[np.invert(np.isfinite(s11))] = 0
# Create dictionary of antenna parameters
antennaparams = {'time': time, 'freqs': freqs, 'Vinc': Vinc, 'Vincp': Vincp,
'Iinc': Iinc, 'Iincp': Iincp, 'Vref': Vref, 'Vrefp': Vrefp,
'Iref': Iref, 'Irefp': Irefp, 'Vtotal': Vtotal,
'Vtotalp': Vtotalp, 'Itotal': Itotal, 'Itotalp': Itotalp,
's11': s11, 'zin': zin, 'yin': yin}
antennaparams = {
"time": time,
"freqs": freqs,
"Vinc": Vinc,
"Vincp": Vincp,
"Iinc": Iinc,
"Iincp": Iincp,
"Vref": Vref,
"Vrefp": Vrefp,
"Iref": Iref,
"Irefp": Irefp,
"Vtotal": Vtotal,
"Vtotalp": Vtotalp,
"Itotal": Itotal,
"Itotalp": Itotalp,
"s11": s11,
"zin": zin,
"yin": yin,
}
if tlrxnumber or rxnumber:
with np.errstate(divide='ignore'): # Ignore warning from taking a log of any zero values
with np.errstate(divide="ignore"): # Ignore warning from taking a log of any zero values
s21 = 20 * np.log10(s21)
s21[np.invert(np.isfinite(s21))] = 0
antennaparams['s21'] = s21
antennaparams["s21"] = s21
return antennaparams
def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp,
Iref, Irefp, Vtotal, Vtotalp, Itotal, Itotalp, s11, zin, yin,
s21=None, save=False):
def mpl_plot(
filename,
time,
freqs,
Vinc,
Vincp,
Iinc,
Iincp,
Vref,
Vrefp,
Iref,
Irefp,
Vtotal,
Vtotalp,
Itotal,
Itotalp,
s11,
zin,
yin,
s21=None,
save=False,
):
"""Plots antenna parameters - incident, reflected and total voltages and
currents; s11, (s21) and input impedance.
@@ -162,14 +197,14 @@ def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp,
filename: string of filename (including path) of output file.
time: array of simulation time.
freq: array of frequencies for FFTs.
Vinc, Vincp, Iinc, Iincp: arrays of time and frequency domain
representations of incident voltage and
Vinc, Vincp, Iinc, Iincp: arrays of time and frequency domain
representations of incident voltage and
current.
Vref, Vrefp, Iref, Irefp: arrays of time and frequency domain
representations of reflected voltage and
Vref, Vrefp, Iref, Irefp: arrays of time and frequency domain
representations of reflected voltage and
current.
Vtotal, Vtotalp, Itotal, Itotalp: arrays of time and frequency domain
representations of total voltage and
Vtotal, Vtotalp, Itotal, Itotalp: arrays of time and frequency domain
representations of total voltage and
current.
s11, s21: array(s) of s11 and, optionally, s21 parameters.
zin, yin: arrays of input impedance and input admittance parameters.
@@ -189,105 +224,103 @@ def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp,
# Print some useful values from s11, and input impedance
s11minfreq = np.where(s11[pltrange] == np.amin(s11[pltrange]))[0][0]
logger.info(f's11 minimum: {np.amin(s11[pltrange]):g} dB at ' +
f'{freqs[s11minfreq + pltrangemin]:g} Hz')
logger.info(f'At {freqs[s11minfreq + pltrangemin]:g} Hz...')
logger.info(f'Input impedance: {np.abs(zin[s11minfreq + pltrangemin]):.1f}' +
f'{zin[s11minfreq + pltrangemin].imag:+.1f}j Ohms')
logger.info(f"s11 minimum: {np.amin(s11[pltrange]):g} dB at " + f"{freqs[s11minfreq + pltrangemin]:g} Hz")
logger.info(f"At {freqs[s11minfreq + pltrangemin]:g} Hz...")
logger.info(
f"Input impedance: {np.abs(zin[s11minfreq + pltrangemin]):.1f}"
+ f"{zin[s11minfreq + pltrangemin].imag:+.1f}j Ohms"
)
# logger.info(f'Input admittance (mag): {np.abs(yin[s11minfreq + pltrangemin]):g} S')
# logger.info(f'Input admittance (phase): {np.angle(yin[s11minfreq + pltrangemin], deg=True):.1f} deg')
# Figure 1
# Plot incident voltage
fig1, ax = plt.subplots(num='Transmitter transmission line parameters',
figsize=(20, 12), facecolor='w', edgecolor='w')
fig1, ax = plt.subplots(
num="Transmitter transmission line parameters", figsize=(20, 12), facecolor="w", edgecolor="w"
)
gs1 = gridspec.GridSpec(4, 2, hspace=0.7)
ax = plt.subplot(gs1[0, 0])
ax.plot(time, Vinc, 'r', lw=2, label='Vinc')
ax.set_title('Incident voltage')
ax.set_xlabel('Time [s]')
ax.set_ylabel('Voltage [V]')
ax.plot(time, Vinc, "r", lw=2, label="Vinc")
ax.set_title("Incident voltage")
ax.set_xlabel("Time [s]")
ax.set_ylabel("Voltage [V]")
ax.set_xlim([0, np.amax(time)])
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
# Plot frequency spectra of incident voltage
ax = plt.subplot(gs1[0, 1])
markerline, stemlines, baseline = ax.stem(freqs[pltrange], Vincp[pltrange],
'-.', use_line_collection=True)
plt.setp(baseline, 'linewidth', 0)
plt.setp(stemlines, 'color', 'r')
plt.setp(markerline, 'markerfacecolor', 'r', 'markeredgecolor', 'r')
ax.plot(freqs[pltrange], Vincp[pltrange], 'r', lw=2)
ax.set_title('Incident voltage')
ax.set_xlabel('Frequency [Hz]')
ax.set_ylabel('Power [dB]')
ax.grid(which='both', axis='both', linestyle='-.')
markerline, stemlines, baseline = ax.stem(freqs[pltrange], Vincp[pltrange], "-.", use_line_collection=True)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "r")
plt.setp(markerline, "markerfacecolor", "r", "markeredgecolor", "r")
ax.plot(freqs[pltrange], Vincp[pltrange], "r", lw=2)
ax.set_title("Incident voltage")
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Power [dB]")
ax.grid(which="both", axis="both", linestyle="-.")
# Plot incident current
ax = plt.subplot(gs1[1, 0])
ax.plot(time, Iinc, 'b', lw=2, label='Vinc')
ax.set_title('Incident current')
ax.set_xlabel('Time [s]')
ax.set_ylabel('Current [A]')
ax.plot(time, Iinc, "b", lw=2, label="Vinc")
ax.set_title("Incident current")
ax.set_xlabel("Time [s]")
ax.set_ylabel("Current [A]")
ax.set_xlim([0, np.amax(time)])
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
# Plot frequency spectra of incident current
ax = plt.subplot(gs1[1, 1])
markerline, stemlines, baseline = ax.stem(freqs[pltrange], Iincp[pltrange],
'-.', use_line_collection=True)
plt.setp(baseline, 'linewidth', 0)
plt.setp(stemlines, 'color', 'b')
plt.setp(markerline, 'markerfacecolor', 'b', 'markeredgecolor', 'b')
ax.plot(freqs[pltrange], Iincp[pltrange], 'b', lw=2)
ax.set_title('Incident current')
ax.set_xlabel('Frequency [Hz]')
ax.set_ylabel('Power [dB]')
ax.grid(which='both', axis='both', linestyle='-.')
markerline, stemlines, baseline = ax.stem(freqs[pltrange], Iincp[pltrange], "-.", use_line_collection=True)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "b")
plt.setp(markerline, "markerfacecolor", "b", "markeredgecolor", "b")
ax.plot(freqs[pltrange], Iincp[pltrange], "b", lw=2)
ax.set_title("Incident current")
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Power [dB]")
ax.grid(which="both", axis="both", linestyle="-.")
# Plot total voltage
ax = plt.subplot(gs1[2, 0])
ax.plot(time, Vtotal, 'r', lw=2, label='Vinc')
ax.set_title('Total (incident + reflected) voltage')
ax.set_xlabel('Time [s]')
ax.set_ylabel('Voltage [V]')
ax.plot(time, Vtotal, "r", lw=2, label="Vinc")
ax.set_title("Total (incident + reflected) voltage")
ax.set_xlabel("Time [s]")
ax.set_ylabel("Voltage [V]")
ax.set_xlim([0, np.amax(time)])
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
# Plot frequency spectra of total voltage
ax = plt.subplot(gs1[2, 1])
markerline, stemlines, baseline = ax.stem(freqs[pltrange], Vtotalp[pltrange],
'-.', use_line_collection=True)
plt.setp(baseline, 'linewidth', 0)
plt.setp(stemlines, 'color', 'r')
plt.setp(markerline, 'markerfacecolor', 'r', 'markeredgecolor', 'r')
ax.plot(freqs[pltrange], Vtotalp[pltrange], 'r', lw=2)
ax.set_title('Total (incident + reflected) voltage')
ax.set_xlabel('Frequency [Hz]')
ax.set_ylabel('Power [dB]')
ax.grid(which='both', axis='both', linestyle='-.')
markerline, stemlines, baseline = ax.stem(freqs[pltrange], Vtotalp[pltrange], "-.", use_line_collection=True)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "r")
plt.setp(markerline, "markerfacecolor", "r", "markeredgecolor", "r")
ax.plot(freqs[pltrange], Vtotalp[pltrange], "r", lw=2)
ax.set_title("Total (incident + reflected) voltage")
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Power [dB]")
ax.grid(which="both", axis="both", linestyle="-.")
# Plot total current
ax = plt.subplot(gs1[3, 0])
ax.plot(time, Itotal, 'b', lw=2, label='Vinc')
ax.set_title('Total (incident + reflected) current')
ax.set_xlabel('Time [s]')
ax.set_ylabel('Current [A]')
ax.plot(time, Itotal, "b", lw=2, label="Vinc")
ax.set_title("Total (incident + reflected) current")
ax.set_xlabel("Time [s]")
ax.set_ylabel("Current [A]")
ax.set_xlim([0, np.amax(time)])
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
# Plot frequency spectra of total current
ax = plt.subplot(gs1[3, 1])
markerline, stemlines, baseline = ax.stem(freqs[pltrange], Itotalp[pltrange],
'-.', use_line_collection=True)
plt.setp(baseline, 'linewidth', 0)
plt.setp(stemlines, 'color', 'b')
plt.setp(markerline, 'markerfacecolor', 'b', 'markeredgecolor', 'b')
ax.plot(freqs[pltrange], Itotalp[pltrange], 'b', lw=2)
ax.set_title('Total (incident + reflected) current')
ax.set_xlabel('Frequency [Hz]')
ax.set_ylabel('Power [dB]')
ax.grid(which='both', axis='both', linestyle='-.')
markerline, stemlines, baseline = ax.stem(freqs[pltrange], Itotalp[pltrange], "-.", use_line_collection=True)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "b")
plt.setp(markerline, "markerfacecolor", "b", "markeredgecolor", "b")
ax.plot(freqs[pltrange], Itotalp[pltrange], "b", lw=2)
ax.set_title("Total (incident + reflected) current")
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Power [dB]")
ax.grid(which="both", axis="both", linestyle="-.")
# Plot reflected (reflected) voltage
# ax = plt.subplot(gs1[4, 0])
@@ -335,69 +368,64 @@ def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp,
# Figure 2
# Plot frequency spectra of s11
fig2, ax = plt.subplots(num='Antenna parameters', figsize=(20, 12),
facecolor='w', edgecolor='w')
fig2, ax = plt.subplots(num="Antenna parameters", figsize=(20, 12), facecolor="w", edgecolor="w")
gs2 = gridspec.GridSpec(2, 2, hspace=0.3)
ax = plt.subplot(gs2[0, 0])
markerline, stemlines, baseline = ax.stem(freqs[pltrange], s11[pltrange],
'-.', use_line_collection=True)
plt.setp(baseline, 'linewidth', 0)
plt.setp(stemlines, 'color', 'g')
plt.setp(markerline, 'markerfacecolor', 'g', 'markeredgecolor', 'g')
ax.plot(freqs[pltrange], s11[pltrange], 'g', lw=2)
ax.set_title('s11')
ax.set_xlabel('Frequency [Hz]')
ax.set_ylabel('Power [dB]')
markerline, stemlines, baseline = ax.stem(freqs[pltrange], s11[pltrange], "-.", use_line_collection=True)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "g")
plt.setp(markerline, "markerfacecolor", "g", "markeredgecolor", "g")
ax.plot(freqs[pltrange], s11[pltrange], "g", lw=2)
ax.set_title("s11")
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Power [dB]")
# ax.set_xlim([0, 5e9])
# ax.set_ylim([-25, 0])
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
# Plot frequency spectra of s21
if s21 is not None:
ax = plt.subplot(gs2[0, 1])
markerline, stemlines, baseline = ax.stem(freqs[pltrange], s21[pltrange],
'-.', use_line_collection=True)
plt.setp(baseline, 'linewidth', 0)
plt.setp(stemlines, 'color', 'g')
plt.setp(markerline, 'markerfacecolor', 'g', 'markeredgecolor', 'g')
ax.plot(freqs[pltrange], s21[pltrange], 'g', lw=2)
ax.set_title('s21')
ax.set_xlabel('Frequency [Hz]')
ax.set_ylabel('Power [dB]')
markerline, stemlines, baseline = ax.stem(freqs[pltrange], s21[pltrange], "-.", use_line_collection=True)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "g")
plt.setp(markerline, "markerfacecolor", "g", "markeredgecolor", "g")
ax.plot(freqs[pltrange], s21[pltrange], "g", lw=2)
ax.set_title("s21")
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Power [dB]")
# ax.set_xlim([0.88e9, 1.02e9])
# ax.set_ylim([-25, 50])
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
# Plot input resistance (real part of impedance)
ax = plt.subplot(gs2[1, 0])
markerline, stemlines, baseline = ax.stem(freqs[pltrange], zin[pltrange].real,
'-.', use_line_collection=True)
plt.setp(baseline, 'linewidth', 0)
plt.setp(stemlines, 'color', 'g')
plt.setp(markerline, 'markerfacecolor', 'g', 'markeredgecolor', 'g')
ax.plot(freqs[pltrange], zin[pltrange].real, 'g', lw=2)
ax.set_title('Input impedance (resistive)')
ax.set_xlabel('Frequency [Hz]')
ax.set_ylabel('Resistance [Ohms]')
markerline, stemlines, baseline = ax.stem(freqs[pltrange], zin[pltrange].real, "-.", use_line_collection=True)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "g")
plt.setp(markerline, "markerfacecolor", "g", "markeredgecolor", "g")
ax.plot(freqs[pltrange], zin[pltrange].real, "g", lw=2)
ax.set_title("Input impedance (resistive)")
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Resistance [Ohms]")
# ax.set_xlim([0.88e9, 1.02e9])
ax.set_ylim(bottom=0)
# ax.set_ylim([0, 300])
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
# Plot input reactance (imaginery part of impedance)
ax = plt.subplot(gs2[1, 1])
markerline, stemlines, baseline = ax.stem(freqs[pltrange], zin[pltrange].imag,
'-.', use_line_collection=True)
plt.setp(baseline, 'linewidth', 0)
plt.setp(stemlines, 'color', 'g')
plt.setp(markerline, 'markerfacecolor', 'g', 'markeredgecolor', 'g')
ax.plot(freqs[pltrange], zin[pltrange].imag, 'g', lw=2)
ax.set_title('Input impedance (reactive)')
ax.set_xlabel('Frequency [Hz]')
ax.set_ylabel('Reactance [Ohms]')
markerline, stemlines, baseline = ax.stem(freqs[pltrange], zin[pltrange].imag, "-.", use_line_collection=True)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "g")
plt.setp(markerline, "markerfacecolor", "g", "markeredgecolor", "g")
ax.plot(freqs[pltrange], zin[pltrange].imag, "g", lw=2)
ax.set_title("Input impedance (reactive)")
ax.set_xlabel("Frequency [Hz]")
ax.set_ylabel("Reactance [Ohms]")
# ax.set_xlim([0.88e9, 1.02e9])
# ax.set_ylim([-300, 300])
ax.grid(which='both', axis='both', linestyle='-.')
ax.grid(which="both", axis="both", linestyle="-.")
# Plot input admittance (magnitude)
# ax = plt.subplot(gs2[2, 0])
@@ -430,49 +458,49 @@ def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp,
# ax.grid(which='both', axis='both', linestyle='-.')
if save:
savename1 = filename.stem + '_tl_params'
savename1 = filename.stem + "_tl_params"
savename1 = filename.parent / savename1
savename2 = filename.stem + '_ant_params'
savename2 = filename.stem + "_ant_params"
savename2 = filename.parent / savename2
# Save a PDF of the figure
fig1.savefig(savename1.with_suffix('.pdf'), dpi=None, format='pdf',
bbox_inches='tight', pad_inches=0.1)
fig2.savefig(savename2.with_suffix('.pdf'), dpi=None, format='pdf',
bbox_inches='tight', pad_inches=0.1)
fig1.savefig(savename1.with_suffix(".pdf"), dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
fig2.savefig(savename2.with_suffix(".pdf"), dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
# Save a PNG of the figure
# fig1.savefig(savename1.with_suffix('.png'), dpi=150, format='png',
# fig1.savefig(savename1.with_suffix('.png'), dpi=150, format='png',
# bbox_inches='tight', pad_inches=0.1)
# fig2.savefig(savename2.with_suffix('.png'), dpi=150, format='png',
# fig2.savefig(savename2.with_suffix('.png'), dpi=150, format='png',
# bbox_inches='tight', pad_inches=0.1)
return plt
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Plots antenna parameters - ' +
'incident, reflected and total voltages ' +
'and currents; s11, (s21) and input impedance ' +
'from an output file containing a transmission ' +
'line source.',
usage='cd gprMax; python -m toolboxes.Plotting.plot_antenna_params outputfile')
parser.add_argument('outputfile', help='name of output file including path')
parser.add_argument('--tltx-num', default=1, type=int,
help='transmitter antenna - transmission line number')
parser.add_argument('--tlrx-num', type=int,
help='receiver antenna - transmission line number')
parser.add_argument('--rx-num', type=int,
help='receiver antenna - output number')
parser.add_argument('--rx-component', type=str,
help='receiver antenna - output electric field component',
choices=['Ex', 'Ey', 'Ez'])
parser.add_argument('-save', action='store_true', default=False,
help='save plot directly to file, i.e. do not display')
parser = argparse.ArgumentParser(
description="Plots antenna parameters - "
+ "incident, reflected and total voltages "
+ "and currents; s11, (s21) and input impedance "
+ "from an output file containing a transmission "
+ "line source.",
usage="cd gprMax; python -m toolboxes.Plotting.plot_antenna_params outputfile",
)
parser.add_argument("outputfile", help="name of output file including path")
parser.add_argument("--tltx-num", default=1, type=int, help="transmitter antenna - transmission line number")
parser.add_argument("--tlrx-num", type=int, help="receiver antenna - transmission line number")
parser.add_argument("--rx-num", type=int, help="receiver antenna - output number")
parser.add_argument(
"--rx-component",
type=str,
help="receiver antenna - output electric field component",
choices=["Ex", "Ey", "Ez"],
)
parser.add_argument(
"-save", action="store_true", default=False, help="save plot directly to file, i.e. do not display"
)
args = parser.parse_args()
antennaparams = calculate_antenna_params(args.outputfile, args.tltx_num,
args.tlrx_num, args.rx_num,
args.rx_component)
antennaparams = calculate_antenna_params(
args.outputfile, args.tltx_num, args.tlrx_num, args.rx_num, args.rx_component
)
plthandle = mpl_plot(args.outputfile, **antennaparams, save=args.save)
plthandle.show()

查看文件

@@ -25,7 +25,7 @@ import numpy as np
from gprMax.utilities.utilities import fft_power, round_value
from gprMax.waveforms import Waveform
logging.basicConfig(format='%(message)s', level=logging.INFO)
logging.basicConfig(format="%(message)s", level=logging.INFO)
def check_timewindow(timewindow, dt):
@@ -53,7 +53,7 @@ def check_timewindow(timewindow, dt):
if timewindow > 0:
iterations = round_value((timewindow / dt)) + 1
else:
logging.exception('Time window must have a value greater than zero')
logging.exception("Time window must have a value greater than zero")
raise ValueError
return timewindow, iterations
@@ -76,36 +76,41 @@ def mpl_plot(w, timewindow, dt, iterations, fft=False, save=False):
time = np.linspace(0, (iterations - 1) * dt, num=iterations)
waveform = np.zeros(len(time))
timeiter = np.nditer(time, flags=['c_index'])
timeiter = np.nditer(time, flags=["c_index"])
while not timeiter.finished:
waveform[timeiter.index] = w.calculate_value(timeiter[0], dt)
timeiter.iternext()
logging.info('Waveform characteristics...')
logging.info(f'Type: {w.type}')
logging.info(f'Maximum (absolute) amplitude: {np.max(np.abs(waveform)):g}')
logging.info("Waveform characteristics...")
logging.info(f"Type: {w.type}")
logging.info(f"Maximum (absolute) amplitude: {np.max(np.abs(waveform)):g}")
if w.freq and not w.type == 'gaussian' and not w.type == 'impulse':
logging.info(f'Centre frequency: {w.freq:g} Hz')
if w.freq and not w.type == "gaussian" and not w.type == "impulse":
logging.info(f"Centre frequency: {w.freq:g} Hz")
if (w.type == 'gaussian' or w.type == 'gaussiandot' or w.type == 'gaussiandotnorm'
or w.type == 'gaussianprime' or w.type == 'gaussiandoubleprime'):
if (
w.type == "gaussian"
or w.type == "gaussiandot"
or w.type == "gaussiandotnorm"
or w.type == "gaussianprime"
or w.type == "gaussiandoubleprime"
):
delay = 1 / w.freq
logging.info(f'Time to centre of pulse: {delay:g} s')
elif w.type == 'gaussiandotdot' or w.type == 'gaussiandotdotnorm' or w.type == 'ricker':
logging.info(f"Time to centre of pulse: {delay:g} s")
elif w.type == "gaussiandotdot" or w.type == "gaussiandotdotnorm" or w.type == "ricker":
delay = np.sqrt(2) / w.freq
logging.info(f'Time to centre of pulse: {delay:g} s')
logging.info(f"Time to centre of pulse: {delay:g} s")
logging.info(f'Time window: {timewindow:g} s ({iterations} iterations)')
logging.info(f'Time step: {dt:g} s')
logging.info(f"Time window: {timewindow:g} s ({iterations} iterations)")
logging.info(f"Time step: {dt:g} s")
if fft:
# FFT
freqs, power = fft_power(waveform, dt)
# Set plotting range to 4 times frequency at max power of waveform or
# 4 times the centre frequency
# 4 times the centre frequency
freqmaxpower = np.where(np.isclose(power, 0))[0][0]
if freqs[freqmaxpower] > w.freq:
pltrange = np.where(freqs > 4 * freqs[freqmaxpower])[0][0]
@@ -113,73 +118,66 @@ def mpl_plot(w, timewindow, dt, iterations, fft=False, save=False):
pltrange = np.where(freqs > 4 * w.freq)[0][0]
pltrange = np.s_[0:pltrange]
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, num=w.type,
figsize=(20, 10), facecolor='w',
edgecolor='w')
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, num=w.type, figsize=(20, 10), facecolor="w", edgecolor="w")
# Plot waveform
ax1.plot(time, waveform, 'r', lw=2)
ax1.set_xlabel('Time [s]')
ax1.set_ylabel('Amplitude')
ax1.plot(time, waveform, "r", lw=2)
ax1.set_xlabel("Time [s]")
ax1.set_ylabel("Amplitude")
# Plot frequency spectra
markerline, stemlines, baseline = ax2.stem(freqs[pltrange], power[pltrange],
'-.', use_line_collection=True)
plt.setp(baseline, 'linewidth', 0)
plt.setp(stemlines, 'color', 'r')
plt.setp(markerline, 'markerfacecolor', 'r', 'markeredgecolor', 'r')
ax2.plot(freqs[pltrange], power[pltrange], 'r', lw=2)
ax2.set_xlabel('Frequency [Hz]')
ax2.set_ylabel('Power [dB]')
markerline, stemlines, baseline = ax2.stem(freqs[pltrange], power[pltrange], "-.", use_line_collection=True)
plt.setp(baseline, "linewidth", 0)
plt.setp(stemlines, "color", "r")
plt.setp(markerline, "markerfacecolor", "r", "markeredgecolor", "r")
ax2.plot(freqs[pltrange], power[pltrange], "r", lw=2)
ax2.set_xlabel("Frequency [Hz]")
ax2.set_ylabel("Power [dB]")
else:
fig, ax1 = plt.subplots(num=w.type, figsize=(10, 10), facecolor='w',
edgecolor='w')
fig, ax1 = plt.subplots(num=w.type, figsize=(10, 10), facecolor="w", edgecolor="w")
# Plot waveform
ax1.plot(time, waveform, 'r', lw=2)
ax1.set_xlabel('Time [s]')
ax1.set_ylabel('Amplitude')
ax1.plot(time, waveform, "r", lw=2)
ax1.set_xlabel("Time [s]")
ax1.set_ylabel("Amplitude")
# Turn on grid
[ax.grid(which='both', axis='both', linestyle='-.') for ax in fig.axes]
[ax.grid(which="both", axis="both", linestyle="-.") for ax in fig.axes]
if save:
savefile = Path(__file__).parent / w.type
# Save a PDF of the figure
fig.savefig(savefile.with_suffix('.pdf'), dpi=None, format='pdf',
bbox_inches='tight', pad_inches=0.1)
fig.savefig(savefile.with_suffix(".pdf"), dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
# Save a PNG of the figure
fig.savefig(savefile.with_suffix('.png'), dpi=150, format='png',
bbox_inches='tight', pad_inches=0.1)
fig.savefig(savefile.with_suffix(".png"), dpi=150, format="png", bbox_inches="tight", pad_inches=0.1)
return plt
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Plot built-in waveforms that can be used for sources.',
usage='cd gprMax; python -m toolboxes.Plotting.plot_source_wave type amp freq timewindow dt')
parser.add_argument('type', help='type of waveform', choices=Waveform.types)
parser.add_argument('amp', type=float, help='amplitude of waveform')
parser.add_argument('freq', type=float, help='centre frequency of waveform')
parser.add_argument('timewindow', help='time window to view waveform')
parser.add_argument('dt', type=float, help='time step to view waveform')
parser.add_argument('-fft', action='store_true', default=False,
help='plot FFT of waveform')
parser.add_argument('-save', action='store_true', default=False,
help='save plot directly to file, i.e. do not display')
parser = argparse.ArgumentParser(
description="Plot built-in waveforms that can be used for sources.",
usage="cd gprMax; python -m toolboxes.Plotting.plot_source_wave type amp freq timewindow dt",
)
parser.add_argument("type", help="type of waveform", choices=Waveform.types)
parser.add_argument("amp", type=float, help="amplitude of waveform")
parser.add_argument("freq", type=float, help="centre frequency of waveform")
parser.add_argument("timewindow", help="time window to view waveform")
parser.add_argument("dt", type=float, help="time step to view waveform")
parser.add_argument("-fft", action="store_true", default=False, help="plot FFT of waveform")
parser.add_argument(
"-save", action="store_true", default=False, help="save plot directly to file, i.e. do not display"
)
args = parser.parse_args()
# Check waveform parameters
if args.type.lower() not in Waveform.types:
logging.exception(f"The waveform must have one of the following types " +
f"{', '.join(Waveform.types)}")
logging.exception(f"The waveform must have one of the following types " + f"{', '.join(Waveform.types)}")
raise ValueError
if args.freq <= 0:
logging.exception('The waveform requires an excitation frequency value of ' +
'greater than zero')
logging.exception("The waveform requires an excitation frequency value of " + "greater than zero")
raise ValueError
# Create waveform instance
@@ -189,6 +187,5 @@ if __name__ == "__main__":
w.freq = args.freq
timewindow, iterations = check_timewindow(args.timewindow, args.dt)
plthandle = mpl_plot(w, timewindow, args.dt, iterations, fft=args.fft,
save=args.save)
plthandle = mpl_plot(w, timewindow, args.dt, iterations, fft=args.fft, save=args.save)
plthandle.show()

查看文件

@@ -9,7 +9,7 @@ Information
**Author/Contact**: Kartik Bansal (kartikbn21000@gmail.com)
This package provides the ability to directly model real objects without having to build their geometries manually using geometry primitives such as the ``#edge``, ``#plate``, ``#box`` etc.. commands. It specifically provides a tool to convert a `STL file <https://en.wikipedia.org/wiki/STL_(file_format)>`_, which can be produced by many CAD software packages, to a voxelised mesh (FDTD Yee cells) which is saved as a geometry file in HDF5 format suitable for directly importing into gprMax.
This package provides the ability to directly model real objects without having to build their geometries manually using geometry primitives such as the ``#edge``, ``#plate``, ``#box`` etc.. commands. It specifically provides a tool to convert a `STL file <https://en.wikipedia.org/wiki/STL_(file_format)>`_, which can be produced by many CAD software packages, to a voxelised mesh (FDTD Yee cells) which is saved as a geometry file in HDF5 format suitable for directly importing into gprMax.
This package was created as part of the `Google Summer of Code <https://summerofcode.withgoogle.com/>`_ programme 2021 which gprMax participated. The package uses the `stl-to-voxel <https://github.com/cpederkoff/stl-to-voxel>`_ Python library by Christian Pederkoff.
@@ -67,4 +67,4 @@ The following Python script (using our Python API) can be used to import the gen
.. figure:: ../../images_shared/stanford_bunny.png
:width: 600 px
FDTD geometry mesh showing the Stanford bunny
FDTD geometry mesh showing the Stanford bunny

查看文件

@@ -7,12 +7,12 @@ from . import slice
def convert_meshes(meshes, discretization, parallel=True):
scale, shift, shape = slice.calculate_scale_shift(meshes, discretization)
vol = np.zeros(shape[::-1], dtype=np.int32)
for mesh_ind, org_mesh in enumerate(meshes):
slice.scale_and_shift_mesh(org_mesh, scale, shift)
cur_vol = slice.mesh_to_plane(org_mesh, shape, parallel)
vol[cur_vol] = mesh_ind + 1
return vol, scale, shift
@@ -22,12 +22,12 @@ def convert_file(input_file_path, discretization, pad=1, parallel=False):
def convert_files(input_file_paths, discretization, colors=[(0, 0, 0)], pad=1, parallel=False):
meshes = []
for input_file_path in input_file_paths:
mesh_obj = mesh.Mesh.from_file(input_file_path)
org_mesh = np.hstack((mesh_obj.v0[:, np.newaxis], mesh_obj.v1[:, np.newaxis], mesh_obj.v2[:, np.newaxis]))
meshes.append(org_mesh)
vol, scale, shift = convert_meshes(meshes, discretization, parallel)
vol = np.transpose(vol)
return vol

查看文件

@@ -15,7 +15,7 @@ z = 0.148
scene = gprMax.Scene()
title = gprMax.Title(name=fn.with_suffix('').name)
title = gprMax.Title(name=fn.with_suffix("").name)
domain = gprMax.Domain(p1=(x, y, z))
dxdydz = gprMax.Discretisation(p1=(dl, dl, dl))
time_window = gprMax.TimeWindow(time=10e-9)
@@ -25,13 +25,13 @@ scene.add(domain)
scene.add(dxdydz)
scene.add(time_window)
go = gprMax.GeometryObjectsRead(p1=(0.020, 0.020, 0.020), geofile='stl/Stanford_Bunny.h5', matfile= 'materials.txt')
go = gprMax.GeometryObjectsRead(p1=(0.020, 0.020, 0.020), geofile="stl/Stanford_Bunny.h5", matfile="materials.txt")
gv = gprMax.GeometryView(
p1=(0, 0, 0), p2=domain.props.p1, dl=(dl, dl, dl), filename=fn.with_suffix("").name, output_type="n"
)
gv = gprMax.GeometryView(p1=(0, 0, 0), p2=domain.props.p1,
dl=(dl, dl, dl), filename=fn.with_suffix('').name,
output_type='n')
scene.add(go)
scene.add(gv)
gprMax.run(scenes=[scene], geometry_only=True, outputfile=fn)
gprMax.run(scenes=[scene], geometry_only=True, outputfile=fn)

查看文件

@@ -1,4 +1,4 @@
#material: 3 0 1 0 sand
#material: 5 0.001 1 0 concrete
#material: 2.35 0 1 0 hdpe
#material: 3 0 1 0 pcb
#material: 3 0 1 0 pcb

查看文件

@@ -4,16 +4,16 @@ from functools import reduce
def lines_to_voxels(line_list, pixels):
current_line_indices = set()
x = 0
for (event_x, status, line_ind) in generate_line_events(line_list):
for event_x, status, line_ind in generate_line_events(line_list):
while event_x - x >= 0:
lines = reduce(lambda acc, cur: acc + [line_list[cur]], current_line_indices, [])
paint_y_axis(lines, pixels, x)
x += 1
if status == 'start':
if status == "start":
assert line_ind not in current_line_indices
current_line_indices.add(line_ind)
elif status == 'end':
elif status == "end":
assert line_ind in current_line_indices
current_line_indices.remove(line_ind)
@@ -23,14 +23,14 @@ def slope_intercept(p1, p2):
x2, y2 = p2[:2]
slope = (y2 - y1) / (x2 - x1)
intercept = y1 - slope * x1
return slope, intercept
def generate_y(p1, p2, x):
slope, intercept = slope_intercept(p1, p2)
y = slope * x + intercept
return y
@@ -41,7 +41,7 @@ def paint_y_axis(lines, pixels, x):
if len(target_ys) % 2:
distances = []
for i in range(len(target_ys) - 1):
distances.append(target_ys[i+1] - target_ys[i])
distances.append(target_ys[i + 1] - target_ys[i])
# https://stackoverflow.com/a/17952763
min_idx = -min((x, -i) for i, x in enumerate(distances))[1]
del target_ys[min_idx]
@@ -54,15 +54,15 @@ def paint_y_axis(lines, pixels, x):
pixels[target_y][x] = True
is_black = not is_black
yi = target_y
assert is_black is False, 'an error has occured at x%s' % x
assert is_black is False, "an error has occured at x%s" % x
def generate_line_events(line_list):
events = []
for i, line in enumerate(line_list):
first, second = sorted(line, key=lambda pt: pt[0])
events.append((first[0], 'start', i))
events.append((second[0], 'end', i))
events.append((first[0], "start", i))
events.append((second[0], "end", i))
return sorted(events, key=lambda tup: tup[0])

查看文件

@@ -27,13 +27,13 @@ def mesh_to_plane(mesh, bounding_box, parallel):
else:
pbar.update(1)
_, pixels = paint_z_plane(mesh_subset, z, bounding_box[1::-1])
vol[z]=pixels
vol[z] = pixels
z += 1
if status == 'start':
if status == "start":
assert tri_ind not in current_mesh_indices
current_mesh_indices.add(tri_ind)
elif status == 'end':
elif status == "end":
assert tri_ind in current_mesh_indices
current_mesh_indices.remove(tri_ind)
@@ -61,17 +61,17 @@ def paint_z_plane(mesh, height, plane_shape):
def linear_interpolation(p1, p2, distance):
'''
"""
:param p1: Point 1
:param p2: Point 2
:param distance: Between 0 and 1, Lower numbers return points closer to p1.
:return: A point on the line between p1 and p2
'''
return p1 * (1-distance) + p2 * distance
"""
return p1 * (1 - distance) + p2 * distance
def triangle_to_intersecting_lines(triangle, height, pixels, lines):
assert (len(triangle) == 3)
assert len(triangle) == 3
above = list(filter(lambda pt: pt[2] > height, triangle))
below = list(filter(lambda pt: pt[2] < height, triangle))
same = list(filter(lambda pt: pt[2] == height, triangle))
@@ -100,36 +100,36 @@ def triangle_to_intersecting_lines(triangle, height, pixels, lines):
def where_line_crosses_z(p1, p2, z):
if (p1[2] > p2[2]):
if p1[2] > p2[2]:
p1, p2 = p2, p1
# now p1 is below p2 in z
if p2[2] == p1[2]:
distance = 0
else:
distance = (z - p1[2]) / (p2[2] - p1[2])
return linear_interpolation(p1, p2, distance)
def calculate_scale_shift(meshes, discretization):
mesh_min = meshes[0].min(axis=(0, 1))
mesh_max = meshes[0].max(axis=(0, 1))
for mesh in meshes[1:]:
mesh_min = np.minimum(mesh_min, mesh.min(axis=(0, 1)))
mesh_max = np.maximum(mesh_max, mesh.max(axis=(0, 1)))
amplitude = mesh_max - mesh_min
#Standard Unit of STL is mm
vx=discretization[0]*1000
vy=discretization[1]*1000
vz=discretization[2]*1000
bx=int(amplitude[0]/vx)
by=int(amplitude[1]/vy)
bz=int(amplitude[2]/vz)
bounding_box = [bx+1, by+1, bz+1]
return max(1/vx,1/vy,1/vz), mesh_min, bounding_box
amplitude = mesh_max - mesh_min
# Standard Unit of STL is mm
vx = discretization[0] * 1000
vy = discretization[1] * 1000
vz = discretization[2] * 1000
bx = int(amplitude[0] / vx)
by = int(amplitude[1] / vy)
bz = int(amplitude[2] / vz)
bounding_box = [bx + 1, by + 1, bz + 1]
return max(1 / vx, 1 / vy, 1 / vz), mesh_min, bounding_box
def scale_and_shift_mesh(mesh, scale, shift):
@@ -142,7 +142,7 @@ def generate_tri_events(mesh):
events = []
for i, tri in enumerate(mesh):
bottom, middle, top = sorted(tri, key=lambda pt: pt[2])
events.append((bottom[2], 'start', i))
events.append((top[2], 'end', i))
events.append((bottom[2], "start", i))
events.append((top[2], "end", i))
return sorted(events, key=lambda tup: tup[0])

查看文件

@@ -7,33 +7,35 @@ import h5py
from .convert import convert_file
logger = logging.getLogger(__name__)
logging.basicConfig(format='%(message)s', level=logging.INFO)
logging.basicConfig(format="%(message)s", level=logging.INFO)
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Allows the user to convert a STL files to voxelized mesh.', usage='cd gprMax; python -m user_libs.STLtoVoxel.stltovoxel stlfilename matindex dx_dy_dz')
parser.add_argument('stlfilename', help='name of STL file to convert including path')
parser.add_argument('-matindex', type=int, required=True,
help='index of material to extract from STL file')
parser.add_argument('-dxdydz', nargs='+', type=float, required=True,
help='discretisation to use in voxelisation process')
parser = argparse.ArgumentParser(
description="Allows the user to convert a STL files to voxelized mesh.",
usage="cd gprMax; python -m user_libs.STLtoVoxel.stltovoxel stlfilename matindex dx_dy_dz",
)
parser.add_argument("stlfilename", help="name of STL file to convert including path")
parser.add_argument("-matindex", type=int, required=True, help="index of material to extract from STL file")
parser.add_argument(
"-dxdydz", nargs="+", type=float, required=True, help="discretisation to use in voxelisation process"
)
args = parser.parse_args()
filename_stl = Path(args.stlfilename)
dxdydz = tuple(args.dxdydz)
logger.info(f'\nConverting STL file: {filename_stl.name}')
logger.info(f"\nConverting STL file: {filename_stl.name}")
model_array = convert_file(filename_stl, dxdydz)
model_array[model_array==0] = -1
model_array[model_array==1] = args.matindex
logger.info(f'Number of voxels: {model_array.shape[0]} x {model_array.shape[1]} x {model_array.shape[2]}')
logger.info(f'Spatial discretisation: {dxdydz[0]} x {dxdydz[1]} x {dxdydz[2]}m')
# Write HDF5 file for gprMax using voxels
filename_hdf5 = filename_stl.with_suffix('.h5')
with h5py.File(filename_hdf5, 'w') as f:
f.create_dataset('data', data=model_array)
f.attrs['dx_dy_dz'] = (dxdydz[0], dxdydz[1], dxdydz[2])
model_array[model_array == 0] = -1
model_array[model_array == 1] = args.matindex
logger.info(f"Number of voxels: {model_array.shape[0]} x {model_array.shape[1]} x {model_array.shape[2]}")
logger.info(f"Spatial discretisation: {dxdydz[0]} x {dxdydz[1]} x {dxdydz[2]}m")
logger.info(f'Written geometry object file: {filename_hdf5.name}')
# Write HDF5 file for gprMax using voxels
filename_hdf5 = filename_stl.with_suffix(".h5")
with h5py.File(filename_hdf5, "w") as f:
f.create_dataset("data", data=model_array)
f.attrs["dx_dy_dz"] = (dxdydz[0], dxdydz[1], dxdydz[2])
logger.info(f"Written geometry object file: {filename_hdf5.name}")

查看文件

@@ -28,4 +28,4 @@ export OMP_NUM_THREADS=16
### Run gprMax with input file
cd $HOME/gprMax
python -m gprMax mymodel.in -n 10
python -m gprMax mymodel.in -n 10

查看文件

@@ -19,15 +19,25 @@
import json
import os
from paraview.simple import (AppendDatasets, Box, GetActiveSource,
GetActiveView, GetParaViewVersion, Hide,
OpenDataFile, RenameSource, RenderAllViews,
SetActiveSource, Show, Threshold)
from paraview.simple import (
AppendDatasets,
Box,
GetActiveSource,
GetActiveView,
GetParaViewVersion,
Hide,
OpenDataFile,
RenameSource,
RenderAllViews,
SetActiveSource,
Show,
Threshold,
)
def threshold_filt(input, lt, ut, scalars):
"""Create threshold filter according to Paraview version.
Args:
input (array): input data to threshold filter
lt, ut (int): lower and upper bounds of thresholding operation
@@ -42,7 +52,7 @@ def threshold_filt(input, lt, ut, scalars):
threshold = Threshold(Input=input)
threshold.Scalars = scalars
if pvv.major == 5 and pvv.minor < 10:
threshold.ThresholdRange = [lt, ut]
else:
@@ -62,76 +72,88 @@ def display_pmls(pmlthick, dx_dy_dz, nx_ny_nz):
nx_ny_dz (tuple): Domain size (cells)
"""
pml_names = ['x0', 'y0', 'z0', 'xmax', 'ymax', 'zmax']
pml_names = ["x0", "y0", "z0", "xmax", "ymax", "zmax"]
pmls = dict.fromkeys(pml_names, None)
SetActiveSource(pv_src)
if pmlthick[0] != 0:
x0 = Box(Center=[pmlthick[0] * dx_dy_dz[0] / 2,
nx_ny_nz[1] * dx_dy_dz[1] / 2,
nx_ny_nz[2] * dx_dy_dz[2] / 2],
XLength=pmlthick[0] * dx_dy_dz[0],
YLength=nx_ny_nz[1] * dx_dy_dz[1],
ZLength=nx_ny_nz[2] * dx_dy_dz[2])
pmls['x0'] = x0
x0 = Box(
Center=[pmlthick[0] * dx_dy_dz[0] / 2, nx_ny_nz[1] * dx_dy_dz[1] / 2, nx_ny_nz[2] * dx_dy_dz[2] / 2],
XLength=pmlthick[0] * dx_dy_dz[0],
YLength=nx_ny_nz[1] * dx_dy_dz[1],
ZLength=nx_ny_nz[2] * dx_dy_dz[2],
)
pmls["x0"] = x0
if pmlthick[3] != 0:
xmax = Box(Center=[dx_dy_dz[0] * (nx_ny_nz[0] - pmlthick[3] / 2),
nx_ny_nz[1] * dx_dy_dz[1] / 2,
nx_ny_nz[2] * dx_dy_dz[2] / 2],
XLength=pmlthick[3] * dx_dy_dz[0],
YLength=nx_ny_nz[1] * dx_dy_dz[1],
ZLength=nx_ny_nz[2] * dx_dy_dz[2])
pmls['xmax'] = xmax
xmax = Box(
Center=[
dx_dy_dz[0] * (nx_ny_nz[0] - pmlthick[3] / 2),
nx_ny_nz[1] * dx_dy_dz[1] / 2,
nx_ny_nz[2] * dx_dy_dz[2] / 2,
],
XLength=pmlthick[3] * dx_dy_dz[0],
YLength=nx_ny_nz[1] * dx_dy_dz[1],
ZLength=nx_ny_nz[2] * dx_dy_dz[2],
)
pmls["xmax"] = xmax
if pmlthick[1] != 0:
y0 = Box(Center=[nx_ny_nz[0] * dx_dy_dz[0] / 2,
pmlthick[1] * dx_dy_dz[1] / 2,
nx_ny_nz[2] * dx_dy_dz[2] / 2],
XLength=nx_ny_nz[0] * dx_dy_dz[0],
YLength=pmlthick[1] * dx_dy_dz[1],
ZLength=nx_ny_nz[2] * dx_dy_dz[2])
pmls['y0'] = y0
y0 = Box(
Center=[nx_ny_nz[0] * dx_dy_dz[0] / 2, pmlthick[1] * dx_dy_dz[1] / 2, nx_ny_nz[2] * dx_dy_dz[2] / 2],
XLength=nx_ny_nz[0] * dx_dy_dz[0],
YLength=pmlthick[1] * dx_dy_dz[1],
ZLength=nx_ny_nz[2] * dx_dy_dz[2],
)
pmls["y0"] = y0
if pmlthick[4] != 0:
ymax = Box(Center=[nx_ny_nz[0] * dx_dy_dz[0] / 2,
dx_dy_dz[1] * (nx_ny_nz[1] - pmlthick[4] / 2),
nx_ny_nz[2] * dx_dy_dz[2] / 2],
XLength=nx_ny_nz[0] * dx_dy_dz[0],
YLength=pmlthick[4] * dx_dy_dz[1],
ZLength=nx_ny_nz[2] * dx_dy_dz[2])
pmls['ymax'] = ymax
ymax = Box(
Center=[
nx_ny_nz[0] * dx_dy_dz[0] / 2,
dx_dy_dz[1] * (nx_ny_nz[1] - pmlthick[4] / 2),
nx_ny_nz[2] * dx_dy_dz[2] / 2,
],
XLength=nx_ny_nz[0] * dx_dy_dz[0],
YLength=pmlthick[4] * dx_dy_dz[1],
ZLength=nx_ny_nz[2] * dx_dy_dz[2],
)
pmls["ymax"] = ymax
if pmlthick[2] != 0:
z0 = Box(Center=[nx_ny_nz[0] * dx_dy_dz[0] / 2,
nx_ny_nz[1] * dx_dy_dz[1] / 2,
pmlthick[2] * dx_dy_dz[2] / 2],
XLength=nx_ny_nz[0] * dx_dy_dz[0],
YLength=nx_ny_nz[1] * dx_dy_dz[1],
ZLength=pmlthick[2] * dx_dy_dz[2])
pmls['z0'] = z0
z0 = Box(
Center=[nx_ny_nz[0] * dx_dy_dz[0] / 2, nx_ny_nz[1] * dx_dy_dz[1] / 2, pmlthick[2] * dx_dy_dz[2] / 2],
XLength=nx_ny_nz[0] * dx_dy_dz[0],
YLength=nx_ny_nz[1] * dx_dy_dz[1],
ZLength=pmlthick[2] * dx_dy_dz[2],
)
pmls["z0"] = z0
if pmlthick[5] != 0:
zmax = Box(Center=[nx_ny_nz[0] * dx_dy_dz[0] / 2,
nx_ny_nz[1] * dx_dy_dz[1] / 2,
dx_dy_dz[2] * (nx_ny_nz[2] - pmlthick[5] / 2)],
XLength=nx_ny_nz[0] * dx_dy_dz[0],
YLength=nx_ny_nz[1] * dx_dy_dz[1],
ZLength=pmlthick[5] * dx_dy_dz[2])
pmls['zmax'] = zmax
zmax = Box(
Center=[
nx_ny_nz[0] * dx_dy_dz[0] / 2,
nx_ny_nz[1] * dx_dy_dz[1] / 2,
dx_dy_dz[2] * (nx_ny_nz[2] - pmlthick[5] / 2),
],
XLength=nx_ny_nz[0] * dx_dy_dz[0],
YLength=nx_ny_nz[1] * dx_dy_dz[1],
ZLength=pmlthick[5] * dx_dy_dz[2],
)
pmls["zmax"] = zmax
# Name PML sources and set opacity
tmp = []
for pml in pmls:
if pmls[pml]:
RenameSource('PML - ' + pml, pmls[pml])
RenameSource("PML - " + pml, pmls[pml])
Hide(pmls[pml], pv_view)
tmp.append(pmls[pml])
# Create a group of PMLs to switch on/off easily
if tmp:
pml_gp = AppendDatasets(Input=tmp)
RenameSource('PML - All', pml_gp)
RenameSource("PML - All", pml_gp)
pml_view = Show(pml_gp)
pml_view.Opacity = 0.5
@@ -148,7 +170,7 @@ file = data.FileName
dirname = os.path.dirname(file[0])
# Read and display data from file, i.e. materials, sources, receivers, and PMLs
with open(file, 'rb') as f:
with open(file, "rb") as f:
# Comments () embedded in line 3 of file
f.readline()
f.readline()
@@ -157,14 +179,14 @@ with open(file, 'rb') as f:
c = c[5:-5]
# Model information
c = json.loads(c)
print('\ngprMax version: ' + c['gprMax_version'])
print(file)
print("\ngprMax version: " + c["gprMax_version"])
print(file)
################
# Display data #
################
pv_view = GetActiveView()
pv_view.AxesGrid.Visibility = 1 # Show Data Axes Grid
pv_view.AxesGrid.Visibility = 1 # Show Data Axes Grid
pv_data = OpenDataFile(file)
pv_disp = Show(pv_data, pv_view)
pv_src = GetActiveSource()
@@ -173,60 +195,64 @@ src_name = os.path.split(file)
RenameSource(src_name[1])
# Discretisation
dl = c['dx_dy_dz']
dl = c["dx_dy_dz"]
# Number of voxels
nl = c['nx_ny_nz']
nl = c["nx_ny_nz"]
# Materials
try:
for i, mat in enumerate(c['Materials']):
threshold = threshold_filt(pv_src, i, i, ['CELLS', 'Material'])
for i, mat in enumerate(c["Materials"]):
threshold = threshold_filt(pv_src, i, i, ["CELLS", "Material"])
RenameSource(mat, threshold)
# Show data in view, except for free_space
if i != 1:
thresholddisplay = Show(threshold, pv_view)
thresholddisplay.ColorArrayName = ['CELLS', 'Material']
thresholddisplay.ColorArrayName = ["CELLS", "Material"]
threshold.UpdatePipeline()
except KeyError:
print('No materials to load')
print("No materials to load")
# Display any sources
try:
for item in c['Sources']:
pos = item['position']
name = item['name']
src = Box(Center=[pos[0] + dl[0]/2,
pos[1] + dl[1]/2,
pos[2] + dl[2]/2],
XLength=dl[0], YLength=dl[1], ZLength=dl[2])
for item in c["Sources"]:
pos = item["position"]
name = item["name"]
src = Box(
Center=[pos[0] + dl[0] / 2, pos[1] + dl[1] / 2, pos[2] + dl[2] / 2],
XLength=dl[0],
YLength=dl[1],
ZLength=dl[2],
)
RenameSource(name, src)
Show(src)
except KeyError:
print('No sources to load')
print("No sources to load")
# Display any receivers
try:
for item in c['Receivers']:
pos = item['position']
name = item['name']
rx = Box(Center=[pos[0] + dl[0]/2,
pos[1] + dl[1]/2,
pos[2] + dl[2]/2],
XLength=dl[0], YLength=dl[1], ZLength=dl[2])
for item in c["Receivers"]:
pos = item["position"]
name = item["name"]
rx = Box(
Center=[pos[0] + dl[0] / 2, pos[1] + dl[1] / 2, pos[2] + dl[2] / 2],
XLength=dl[0],
YLength=dl[1],
ZLength=dl[2],
)
RenameSource(name, rx)
Show(rx)
except KeyError:
print('No receivers to load')
print("No receivers to load")
# Display any PMLs
try:
pt = c['PMLthickness']
pt = c["PMLthickness"]
display_pmls(pt, dl, nl)
except KeyError:
print('No PMLs to load')
print("No PMLs to load")
RenderAllViews()
# Reset view to fit data

查看文件

@@ -74,4 +74,4 @@ gprMax produces a separate output file for each trace (A-scan) in a B-scan. This
where:
* ``basefilename`` is the base name file of the output file series, e.g. for ``myoutput1.h5``, ``myoutput2.h5`` the base file name would be ``myoutput``
* ``remove-files`` is an optional argument (flag) that when given will remove the separate output files after the merge.
* ``remove-files`` is an optional argument (flag) that when given will remove the separate output files after the merge.

查看文件

@@ -39,7 +39,7 @@ class Cursor(object):
"""
self.im = im
self.materials = materials
plt.connect('button_press_event', self)
plt.connect("button_press_event", self)
def __call__(self, event):
"""
@@ -50,12 +50,19 @@ class Cursor(object):
x, y = event.xdata, event.ydata
if x is not None and y is not None:
pixel = self.im[int(y), int(x)]
pixel = np.floor(pixel * 255).astype(np.int16) # Convert pixel values from float (0-1) to integer (0-255)
pixel = np.floor(pixel * 255).astype(
np.int16
) # Convert pixel values from float (0-1) to integer (0-255)
match = pixel_match(materials, pixel)
if match is False:
logger.info('x, y: {} {} px; RGB: {}; material ID: {}'.format(int(x), int(y), pixel[:-1], len(self.materials)))
logger.info(
"x, y: {} {} px; RGB: {}; material ID: {}".format(
int(x), int(y), pixel[:-1], len(self.materials)
)
)
materials.append(pixel)
def pixel_match(pixellist, pixeltest):
"""Checks if the RGB(A) value of a pixel already exists in a list of pixel values.
@@ -75,31 +82,39 @@ def pixel_match(pixellist, pixeltest):
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Convert a PNG image to a HDF5 file that can be used to import geometry (#geometry_objects_read) into a 2D gprMax model. Colours from the image are selected which correspond to a list of materials that should be supplied in a separate text file.', usage='python convert_png2h5.py imagefile dx dy dz')
parser.add_argument('imagefile', help='name of image file including path')
parser.add_argument('dxdydz', type=float, action='append', nargs=3, help='spatial resolution of model, e.g. dx dy dz')
parser.add_argument('-zcells', default=1, type=int, help='number of cells for domain in z-direction (infinite direction)')
parser = argparse.ArgumentParser(
description="Convert a PNG image to a HDF5 file that can be used to import geometry (#geometry_objects_read) into a 2D gprMax model. Colours from the image are selected which correspond to a list of materials that should be supplied in a separate text file.",
usage="python convert_png2h5.py imagefile dx dy dz",
)
parser.add_argument("imagefile", help="name of image file including path")
parser.add_argument(
"dxdydz", type=float, action="append", nargs=3, help="spatial resolution of model, e.g. dx dy dz"
)
parser.add_argument(
"-zcells", default=1, type=int, help="number of cells for domain in z-direction (infinite direction)"
)
args = parser.parse_args()
# Open image file
im = mpimg.imread(args.imagefile)
# Store image data to use for creating geometry
imdata = np.rot90(im, k=3) # Rotate 90CW
imdata = np.floor(imdata * 255).astype(np.int16) # Convert pixel values from float (0-1) to integer (0-255)
imdata = np.rot90(im, k=3) # Rotate 90CW
imdata = np.floor(imdata * 255).astype(np.int16) # Convert pixel values from float (0-1) to integer (0-255)
logger.info('Reading PNG image file: {}'.format(os.path.split(args.imagefile)[1]))
logger.info(' 1. Select discrete material colours by clicking on parts of the image.\n 2. When all materials have been selected close the image.')
logger.info("Reading PNG image file: {}".format(os.path.split(args.imagefile)[1]))
logger.info(
" 1. Select discrete material colours by clicking on parts of the image.\n 2. When all materials have been selected close the image."
)
# List to hold selected RGB values from image
materials = []
# Plot image and record rgb values from mouse clicks
fig = plt.figure(num=os.path.split(args.imagefile)[1], facecolor='w', edgecolor='w')
im = np.flipud(im) # Flip image for viewing with origin in lower left
plt.imshow(im, interpolation='nearest', aspect='equal', origin='lower')
fig = plt.figure(num=os.path.split(args.imagefile)[1], facecolor="w", edgecolor="w")
im = np.flipud(im) # Flip image for viewing with origin in lower left
plt.imshow(im, interpolation="nearest", aspect="equal", origin="lower")
Cursor(im, materials)
plt.show()
@@ -107,23 +122,22 @@ if __name__ == "__main__":
dx_dy_dz = (args.dxdydz[0][0], args.dxdydz[0][1], args.dxdydz[0][2])
# Filename for geometry (HDF5) file
hdf5file = os.path.splitext(args.imagefile)[0] + '.h5'
hdf5file = os.path.splitext(args.imagefile)[0] + ".h5"
# Array to store geometry data (initialised as background, i.e. -1)
data = np.ones((imdata.shape[0], imdata.shape[1], args.zcells), dtype=np.int16) * -1
# Write geometry (HDF5) file
with h5py.File(hdf5file, 'w') as fout:
with h5py.File(hdf5file, "w") as fout:
# Add attribute with name 'dx_dy_dz' for spatial resolution
fout.attrs['dx_dy_dz'] = dx_dy_dz
fout.attrs["dx_dy_dz"] = dx_dy_dz
# Use a boolean mask to match selected pixel values with position in image
for i, material in enumerate(materials):
mask = np.all(imdata == material, axis=-1)
data[mask,:] = i
data[mask, :] = i
# Write data to file
fout.create_dataset('data', data=data)
fout.create_dataset("data", data=data)
logger.info('Written HDF5 file: {}'.format(os.path.split(hdf5file)[1]))
logger.info("Written HDF5 file: {}".format(os.path.split(hdf5file)[1]))

查看文件

@@ -20,30 +20,37 @@ import logging
import humanize
from gprMax.utilities.host_info import (detect_cuda_gpus, detect_opencl,
get_host_info, print_cuda_info,
print_opencl_info)
from gprMax.utilities.host_info import (
detect_cuda_gpus,
detect_opencl,
get_host_info,
print_cuda_info,
print_opencl_info,
)
from gprMax.utilities.utilities import get_terminal_width
logging.basicConfig(format='%(message)s', level=logging.INFO)
logging.basicConfig(format="%(message)s", level=logging.INFO)
# Host machine info.
hostinfo = get_host_info()
hyperthreadingstr = f", {hostinfo['logicalcores']} cores with Hyper-Threading" if hostinfo['hyperthreading'] else ''
hostname = (f"\n=== {hostinfo['hostname']}")
hyperthreadingstr = f", {hostinfo['logicalcores']} cores with Hyper-Threading" if hostinfo["hyperthreading"] else ""
hostname = f"\n=== {hostinfo['hostname']}"
logging.info(f"{hostname} {'=' * (get_terminal_width() - len(hostname) - 1)}")
logging.info(f"\n{'Mfr/model:':<12} {hostinfo['machineID']}")
logging.info(f"{'CPU:':<12} {hostinfo['sockets']} x {hostinfo['cpuID']} " +
f"({hostinfo['physicalcores']} cores{hyperthreadingstr})")
logging.info(
f"{'CPU:':<12} {hostinfo['sockets']} x {hostinfo['cpuID']} "
+ f"({hostinfo['physicalcores']} cores{hyperthreadingstr})"
)
logging.info(f"{'RAM:':<12} {humanize.naturalsize(hostinfo['ram'], True)}")
logging.info(f"{'OS/Version:':<12} {hostinfo['osversion']}")
# OpenMP
logging.info("\n\n=== OpenMP capabilities (gprMax will not use Hyper-Threading " +
"as there is no performance advantage)\n")
logging.info(
"\n\n=== OpenMP capabilities (gprMax will not use Hyper-Threading " + "as there is no performance advantage)\n"
)
logging.info(f"{'OpenMP threads: '} {hostinfo['physicalcores']}")
# CUDA
# CUDA
logging.info("\n\n=== CUDA capabilities\n")
gpus = detect_cuda_gpus()
if gpus:

查看文件

@@ -44,26 +44,28 @@ def get_output_data(filename, rxnumber, rxcomponent):
"""
# Open output file and read some attributes
with h5py.File(filename, 'r') as f:
nrx = f.attrs['nrx']
dt = f.attrs['dt']
with h5py.File(filename, "r") as f:
nrx = f.attrs["nrx"]
dt = f.attrs["dt"]
# Check there are any receivers
if nrx == 0:
logger.exception(f'No receivers found in {filename}')
logger.exception(f"No receivers found in {filename}")
raise ValueError
path = '/rxs/rx' + str(rxnumber) + '/'
path = "/rxs/rx" + str(rxnumber) + "/"
availableoutputs = list(f[path].keys())
# Check if requested output is in file
if rxcomponent not in availableoutputs:
logger.exception(f"{rxcomponent} output requested to plot, but the " +
f"available output for receiver 1 is " +
f"{', '.join(availableoutputs)}")
logger.exception(
f"{rxcomponent} output requested to plot, but the "
+ f"available output for receiver 1 is "
+ f"{', '.join(availableoutputs)}"
)
raise ValueError
outputdata = f[path + '/' + rxcomponent]
outputdata = f[path + "/" + rxcomponent]
outputdata = np.array(outputdata)
return outputdata, dt
@@ -78,43 +80,43 @@ def merge_files(outputfiles, removefiles=False):
removefiles: boolean flag to remove individual output files after merge.
"""
merged_outputfile = os.path.commonprefix(outputfiles) + '_merged.h5'
merged_outputfile = os.path.commonprefix(outputfiles) + "_merged.h5"
# Combined output file
fout = h5py.File(merged_outputfile, 'w')
fout = h5py.File(merged_outputfile, "w")
for i, outputfile in enumerate(outputfiles):
fin = h5py.File(outputfile, 'r')
nrx = fin.attrs['nrx']
fin = h5py.File(outputfile, "r")
nrx = fin.attrs["nrx"]
# Write properties for merged file on first iteration
if i == 0:
fout.attrs['gprMax'] = __version__
fout.attrs['Iterations'] = fin.attrs['Iterations']
fout.attrs['nx_ny_nz'] = fin.attrs['nx_ny_nz']
fout.attrs['dx_dy_dz'] = fin.attrs['dx_dy_dz']
fout.attrs['dt'] = fin.attrs['dt']
fout.attrs['nsrc'] = fin.attrs['nsrc']
fout.attrs['nrx'] = fin.attrs['nrx']
fout.attrs['srcsteps'] = fin.attrs['srcsteps']
fout.attrs['rxsteps'] = fin.attrs['rxsteps']
fout.attrs["gprMax"] = __version__
fout.attrs["Iterations"] = fin.attrs["Iterations"]
fout.attrs["nx_ny_nz"] = fin.attrs["nx_ny_nz"]
fout.attrs["dx_dy_dz"] = fin.attrs["dx_dy_dz"]
fout.attrs["dt"] = fin.attrs["dt"]
fout.attrs["nsrc"] = fin.attrs["nsrc"]
fout.attrs["nrx"] = fin.attrs["nrx"]
fout.attrs["srcsteps"] = fin.attrs["srcsteps"]
fout.attrs["rxsteps"] = fin.attrs["rxsteps"]
for rx in range(1, nrx + 1):
path = '/rxs/rx' + str(rx)
path = "/rxs/rx" + str(rx)
grp = fout.create_group(path)
availableoutputs = list(fin[path].keys())
for output in availableoutputs:
grp.create_dataset(output,
(fout.attrs['Iterations'], len(outputfiles)),
dtype=fin[path + '/' + output].dtype)
grp.create_dataset(
output, (fout.attrs["Iterations"], len(outputfiles)), dtype=fin[path + "/" + output].dtype
)
# For all receivers
for rx in range(1, nrx + 1):
path = '/rxs/rx' + str(rx) + '/'
path = "/rxs/rx" + str(rx) + "/"
availableoutputs = list(fin[path].keys())
# For all receiver outputs
for output in availableoutputs:
fout[path + '/' + output][:, i] = fin[path + '/' + output][:]
fout[path + "/" + output][:, i] = fin[path + "/" + output][:]
fin.close()
fout.close()
@@ -123,19 +125,22 @@ def merge_files(outputfiles, removefiles=False):
for outputfile in outputfiles:
os.remove(outputfile)
if __name__ == "__main__":
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Merges traces (A-scans) from multiple ' +
'output files into one new file, then ' +
'optionally removes the series of output files.',
usage='cd gprMax; python -m tools.outputfiles_merge basefilename')
parser.add_argument('basefilename', help='base name of output file series including path')
parser.add_argument('--remove-files', action='store_true', default=False,
help='flag to remove individual output files after merge')
parser = argparse.ArgumentParser(
description="Merges traces (A-scans) from multiple "
+ "output files into one new file, then "
+ "optionally removes the series of output files.",
usage="cd gprMax; python -m tools.outputfiles_merge basefilename",
)
parser.add_argument("basefilename", help="base name of output file series including path")
parser.add_argument(
"--remove-files", action="store_true", default=False, help="flag to remove individual output files after merge"
)
args = parser.parse_args()
files = glob.glob(args.basefilename + '*.h5')
outputfiles = [filename for filename in files if '_merged' not in filename]
files = glob.glob(args.basefilename + "*.h5")
outputfiles = [filename for filename in files if "_merged" not in filename]
outputfiles.sort(key=natural_keys)
merge_files(outputfiles, removefiles=args.remove_files)