你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 04:56:51 +08:00
Added a pre-commit config file and reformatted all the files accordingly by using it.
这个提交包含在:
@@ -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)
|
||||
|
在新工单中引用
屏蔽一个用户