Docstrings updates

这个提交包含在:
Craig Warren
2022-11-26 16:52:36 +00:00
父节点 e77a4b01f5
当前提交 1a8a65960b
共有 4 个文件被更改,包括 132 次插入81 次删除

查看文件

@@ -0,0 +1,18 @@
Toolboxes is a sub-package where useful Python modules contributed by users are stored.
********
Plotting
********
Information
===========
This package is intended to provide some basic scripts to get started with plotting outputs from simulations.
Package contents
================
* ``plot_antenna_params.py`` plots antenna parameters - incident, reflected and total voltages and currents; s11, (s21) and input impedance from an output file containing a transmission line source.
* ``plot_Ascan.py`` 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.
* ``plot_Bscan.py`` plots a B-scan (multiple A-scans) image.
* ``plot_source_wave.py`` plot built-in waveforms that can be used for sources.

查看文件

@@ -30,7 +30,7 @@ logger = logging.getLogger(__name__)
def mpl_plot(filename, outputdata, dt, rxnumber, rxcomponent, save=False): def mpl_plot(filename, outputdata, dt, rxnumber, rxcomponent, save=False):
"""Creates a plot (with matplotlib) of the B-scan. """Creates a plot of the B-scan.
Args: Args:
filename: string of filename (including path) of output file. filename: string of filename (including path) of output file.
@@ -101,28 +101,19 @@ if __name__ == "__main__":
logger.exception(f'No receivers found in {args.outputfile}') logger.exception(f'No receivers found in {args.outputfile}')
raise ValueError raise ValueError
rxsgather = []
for rx in range(1, nrx + 1): for rx in range(1, nrx + 1):
outputdata, dt = get_output_data(args.outputfile, rx, args.rx_component) outputdata, dt = get_output_data(args.outputfile, rx, args.rx_component)
print(outputdata.shape)
if args.gather: if args.gather:
rxsgather.append(outputdata) if rx == 1:
rxsgather = outputdata
rxsgather = np.column_stack((rxsgather, outputdata))
else: else:
plthandle = mpl_plot(args.outputfile, outputdata, dt, rx, plthandle = mpl_plot(args.outputfile, outputdata, dt, rx,
args.rx_component, save=args.save) args.rx_component, save=args.save)
# Plot all receivers from single output file together if required # Plot all receivers from single output file together if required
if args.gather: if args.gather:
rxsgather = np.array(rxsgather).transpose()
plthandle = mpl_plot(args.outputfile, rxsgather, dt, rx, plthandle = mpl_plot(args.outputfile, rxsgather, dt, rx,
args.rx_component, save=args.save) args.rx_component, save=args.save)
if args.save: plthandle.show()
# Save a PDF of the figure
plthandle.savefig(args.outputfile[:-3] + '.pdf', dpi=None,
format='pdf', bbox_inches='tight', pad_inches=0.1)
# # Save a PNG of the figure
# plthandle.savefig(args.outputfile[:-3] + '.png', dpi=150,
# format='png', bbox_inches='tight', pad_inches=0.1)
else:
plthandle.show()

查看文件

@@ -33,14 +33,14 @@ def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=N
and currents; s11, (s21) and input impedance. and currents; s11, (s21) and input impedance.
Args: Args:
filename (string): Filename (including path) of output file. filename: string of filename (including path) of output file.
tltxnumber (int): Transmitter antenna - transmission line number tltxnumber: int for transmitter antenna - transmission line number
tlrxnumber (int): Receiver antenna - transmission line number tlrxnumber: int for receiver antenna - transmission line number
rxnumber (int): Receiver antenna - output number rxnumber: int for receiver antenna - output number
rxcomponent (str): Receiver antenna - output electric field component rxcomponent: in for receiver antenna - output electric field component
Returns: Returns:
antennaparams (dict): Antenna parameters. antennaparams: dict of antenna parameters.
""" """
# Open output file and read some attributes # Open output file and read some attributes
@@ -73,7 +73,8 @@ def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=N
Vref = Vtotal - Vinc Vref = Vtotal - Vinc
Iref = Itotal - Iinc Iref = Itotal - Iinc
# If a receiver antenna is used (with a transmission line or receiver), get received voltage for s21 # If a receiver antenna is used (with a transmission line or receiver),
# get received voltage for s21
if tlrxnumber: if tlrxnumber:
tlrxpath = '/tls/tl' + str(tlrxnumber) + '/' tlrxpath = '/tls/tl' + str(tlrxnumber) + '/'
Vrec = f[tlrxpath + 'Vtotal'][:] Vrec = f[tlrxpath + 'Vtotal'][:]
@@ -83,7 +84,9 @@ def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=N
availableoutputs = list(f[rxpath].keys()) availableoutputs = list(f[rxpath].keys())
if rxcomponent not in availableoutputs: if rxcomponent not in availableoutputs:
logger.exception(f"{rxcomponent} output requested, but the available output for receiver {rxnumber} is {', '.join(availableoutputs)}") logger.exception(f"{rxcomponent} output requested, but the available " +
f"output for receiver {rxnumber} is " +
f"{', '.join(availableoutputs)}")
raise ValueError raise ValueError
rxpath += rxcomponent rxpath += rxcomponent
@@ -100,7 +103,8 @@ def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=N
# Frequency bins # Frequency bins
freqs = np.fft.fftfreq(Vinc.size, d=dt) freqs = np.fft.fftfreq(Vinc.size, d=dt)
# Delay correction - current lags voltage, so delay voltage to match current timestep # Delay correction - current lags voltage, so delay voltage to match
# current timestep
delaycorrection = np.exp(1j * 2 * np.pi * freqs * (dt / 2)) delaycorrection = np.exp(1j * 2 * np.pi * freqs * (dt / 2))
# Calculate s11 and (optionally) s21 # Calculate s11 and (optionally) s21
@@ -134,9 +138,10 @@ def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=N
s11[np.invert(np.isfinite(s11))] = 0 s11[np.invert(np.isfinite(s11))] = 0
# Create dictionary of antenna parameters # Create dictionary of antenna parameters
antennaparams = {'time': time, 'freqs': freqs, 'Vinc': Vinc, 'Vincp': Vincp, 'Iinc': Iinc, 'Iincp': Iincp, antennaparams = {'time': time, 'freqs': freqs, 'Vinc': Vinc, 'Vincp': Vincp,
'Vref': Vref, 'Vrefp': Vrefp, 'Iref': Iref, 'Irefp': Irefp, 'Iinc': Iinc, 'Iincp': Iincp, 'Vref': Vref, 'Vrefp': Vrefp,
'Vtotal': Vtotal, 'Vtotalp': Vtotalp, 'Itotal': Itotal, 'Itotalp': Itotalp, 'Iref': Iref, 'Irefp': Irefp, 'Vtotal': Vtotal,
'Vtotalp': Vtotalp, 'Itotal': Itotal, 'Itotalp': Itotalp,
's11': s11, 'zin': zin, 'yin': yin} 's11': s11, 'zin': zin, 'yin': yin}
if tlrxnumber or rxnumber: 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
@@ -147,22 +152,31 @@ def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=N
return antennaparams 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): def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp,
"""Plots antenna parameters - incident, reflected and total volatges and 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. currents; s11, (s21) and input impedance.
Args: Args:
filename (string): Filename (including path) of output file. filename: string of filename (including path) of output file.
time (array): Simulation time. time: array of simulation time.
freq (array): Frequencies for FFTs. freq: array of frequencies for FFTs.
Vinc, Vincp, Iinc, Iincp (array): Time and frequency domain representations of incident voltage and current. Vinc, Vincp, Iinc, Iincp: arrays of time and frequency domain
Vref, Vrefp, Iref, Irefp (array): Time and frequency domain representations of reflected voltage and current. representations of incident voltage and
Vtotal, Vtotalp, Itotal, Itotalp (array): Time and frequency domain representations of total voltage and current. current.
s11, s21 (array): s11 and, optionally, s21 parameters. Vref, Vrefp, Iref, Irefp: arrays of time and frequency domain
zin, yin (array): Input impedance and input admittance parameters. representations of reflected voltage and
current.
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.
save: boolean flag to save plot to file.
Returns: Returns:
plt (object): matplotlib plot object. plt: matplotlib plot object.
""" """
# Set plotting range # Set plotting range
@@ -175,9 +189,11 @@ def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp, Iref,
# Print some useful values from s11, and input impedance # Print some useful values from s11, and input impedance
s11minfreq = np.where(s11[pltrange] == np.amin(s11[pltrange]))[0][0] s11minfreq = np.where(s11[pltrange] == np.amin(s11[pltrange]))[0][0]
logger.info(f's11 minimum: {np.amin(s11[pltrange]):g} dB at {freqs[s11minfreq + pltrangemin]:g} Hz') 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'At {freqs[s11minfreq + pltrangemin]:g} Hz...')
logger.info(f'Input impedance: {np.abs(zin[s11minfreq + pltrangemin]):.1f}{zin[s11minfreq + pltrangemin].imag:+.1f}j Ohms') 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 (mag): {np.abs(yin[s11minfreq + pltrangemin]):g} S')
# logger.info(f'Input admittance (phase): {np.angle(yin[s11minfreq + pltrangemin], deg=True):.1f} deg') # logger.info(f'Input admittance (phase): {np.angle(yin[s11minfreq + pltrangemin], deg=True):.1f} deg')
@@ -413,19 +429,21 @@ def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp, Iref,
# ax.set_ylim([-40, 100]) # ax.set_ylim([-40, 100])
# ax.grid(which='both', axis='both', linestyle='-.') # ax.grid(which='both', axis='both', linestyle='-.')
# Save a PDF/PNG of the figure if save:
savename1 = filename.stem + '_tl_params' savename1 = filename.stem + '_tl_params'
savename1 = filename.parent / savename1 savename1 = filename.parent / savename1
savename2 = filename.stem + '_ant_params' savename2 = filename.stem + '_ant_params'
savename2 = filename.parent / savename2 savename2 = filename.parent / savename2
# fig1.savefig(savename1.with_suffix('.png'), dpi=150, format='png', # Save a PDF of the figure
# bbox_inches='tight', pad_inches=0.1) fig1.savefig(savename1.with_suffix('.pdf'), dpi=None, format='pdf',
# fig2.savefig(savename2.with_suffix('.png'), dpi=150, format='png', bbox_inches='tight', pad_inches=0.1)
# bbox_inches='tight', pad_inches=0.1) fig2.savefig(savename2.with_suffix('.pdf'), dpi=None, format='pdf',
# fig1.savefig(savename1.with_suffix('.pdf'), dpi=None, format='pdf', bbox_inches='tight', pad_inches=0.1)
# bbox_inches='tight', pad_inches=0.1) # Save a PNG of the figure
# fig2.savefig(savename2.with_suffix('.pdf'), dpi=None, format='pdf', # fig1.savefig(savename1.with_suffix('.png'), dpi=150, format='png',
# bbox_inches='tight', pad_inches=0.1) # bbox_inches='tight', pad_inches=0.1)
# fig2.savefig(savename2.with_suffix('.png'), dpi=150, format='png',
# bbox_inches='tight', pad_inches=0.1)
return plt return plt
@@ -433,14 +451,28 @@ def mpl_plot(filename, time, freqs, Vinc, Vincp, Iinc, Iincp, Vref, Vrefp, Iref,
if __name__ == "__main__": if __name__ == "__main__":
# Parse command line arguments # Parse command line arguments
parser = argparse.ArgumentParser(description='Plots antenna parameters (s11, s21 parameters and input impedance) from an output file containing a transmission line source.', usage='cd gprMax; python -m tools.plot_antenna_params outputfile') 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('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('--tltx-num', default=1, type=int,
parser.add_argument('--tlrx-num', type=int, help='receiver antenna - transmission line number') help='transmitter antenna - transmission line number')
parser.add_argument('--rx-num', type=int, help='receiver antenna - output number') parser.add_argument('--tlrx-num', type=int,
parser.add_argument('--rx-component', type=str, help='receiver antenna - output electric field component', choices=['Ex', 'Ey', 'Ez']) 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() 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,
plthandle = mpl_plot(args.outputfile, **antennaparams) args.tlrx_num, args.rx_num,
args.rx_component)
plthandle = mpl_plot(args.outputfile, **antennaparams, save=args.save)
plthandle.show() plthandle.show()

查看文件

@@ -32,12 +32,12 @@ def check_timewindow(timewindow, dt):
"""Checks and sets time window and number of iterations. """Checks and sets time window and number of iterations.
Args: Args:
timewindow (float): Time window. timewindow: float of time window.
dt (float): Time discretisation. dt: flost of time discretisation.
Returns: Returns:
timewindow (float): Time window. timewindow: float of time window.
iterations (int): Number of interations. iterations: int of number of interations.
""" """
# Time window could be a string, float or int, so convert to string then check # Time window could be a string, float or int, so convert to string then check
@@ -59,18 +59,19 @@ def check_timewindow(timewindow, dt):
return timewindow, iterations return timewindow, iterations
def mpl_plot(w, timewindow, dt, iterations, fft=False): def mpl_plot(w, timewindow, dt, iterations, fft=False, save=False):
"""Plots waveform and prints useful information about its properties. """Plots waveform and prints useful information about its properties.
Args: Args:
w (class): Waveform class instance. w: Waveform class instance.
timewindow (float): Time window. timewindow: float of time window.
dt (float): Time discretisation. dt: float of time discretisation.
iterations (int): Number of iterations. iterations: int of number of iterations.
fft (boolean): Plot FFT switch. fft: boolean flag to plot FFT.
save: boolean flag to save plot to file.
Returns: Returns:
plt (object): matplotlib plot object. plt: matplotlib plot object.
""" """
time = np.linspace(0, (iterations - 1) * dt, num=iterations) time = np.linspace(0, (iterations - 1) * dt, num=iterations)
@@ -143,12 +144,14 @@ def mpl_plot(w, timewindow, dt, iterations, fft=False):
# Turn on grid # 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]
# Save a PDF/PNG of the figure if save:
savefile = Path(__file__).parent / w.type savefile = Path(__file__).parent / w.type
# fig.savefig(savefile.with_suffix('.pdf'), dpi=None, format='pdf', # Save a PDF of the figure
# bbox_inches='tight', pad_inches=0.1) fig.savefig(savefile.with_suffix('.pdf'), dpi=None, format='pdf',
# fig.savefig(savefile.with_suffix('.png'), dpi=150, format='png', bbox_inches='tight', pad_inches=0.1)
# 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)
return plt return plt
@@ -156,21 +159,27 @@ def mpl_plot(w, timewindow, dt, iterations, fft=False):
if __name__ == "__main__": if __name__ == "__main__":
# Parse command line arguments # Parse command line arguments
parser = argparse.ArgumentParser(description='Plot built-in waveforms that can be used for sources.', usage='cd gprMax; python -m tools.plot_source_wave type amp freq timewindow dt') 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('type', help='type of waveform', choices=Waveform.types)
parser.add_argument('amp', type=float, help='amplitude of waveform') parser.add_argument('amp', type=float, help='amplitude of waveform')
parser.add_argument('freq', type=float, help='centre frequency 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('timewindow', help='time window to view waveform')
parser.add_argument('dt', type=float, help='time step to view waveform') parser.add_argument('dt', type=float, help='time step to view waveform')
parser.add_argument('-fft', action='store_true', help='plot FFT of waveform', default=False) 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() args = parser.parse_args()
# Check waveform parameters # Check waveform parameters
if args.type.lower() not in Waveform.types: if args.type.lower() not in Waveform.types:
logger.exception(f"The waveform must have one of the following types {', '.join(Waveform.types)}") logger.exception(f"The waveform must have one of the following types " +
f"{', '.join(Waveform.types)}")
raise ValueError raise ValueError
if args.freq <= 0: if args.freq <= 0:
logger.exception('The waveform requires an excitation frequency value of greater than zero') logger.exception('The waveform requires an excitation frequency value of ' +
'greater than zero')
raise ValueError raise ValueError
# Create waveform instance # Create waveform instance
@@ -180,5 +189,6 @@ if __name__ == "__main__":
w.freq = args.freq w.freq = args.freq
timewindow, iterations = check_timewindow(args.timewindow, args.dt) timewindow, iterations = check_timewindow(args.timewindow, args.dt)
plthandle = mpl_plot(w, timewindow, args.dt, iterations, args.fft) plthandle = mpl_plot(w, timewindow, args.dt, iterations, fft=args.fft,
save=args.save)
plthandle.show() plthandle.show()