def antenna_like_GSSI_1500(x, y, z, resolution=0.001): """Inserts a description of an antenna similar to the GSSI 1.5GHz antenna. Can be used with 1mm (default) or 2mm spatial resolution. The external dimensions of the antenna are 170mm x 108mm x 45mm. One output point is defined between the arms of the receiever bowtie. The bowties are aligned with the y axis so the output is the y component of the electric field. Args: x, y, z (float): Coordinates of a location in the model to insert the antenna. Coordinates are relative to the geometric 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. """ # Antenna geometry properties casesize = (0.170, 0.108, 0.043) casethickness = 0.002 shieldthickness = 0.002 foamsurroundthickness = 0.003 pcbthickness = 0.002 skidthickness = 0.004 bowtiebase = 0.022 bowtieheight = 0.014 patchheight = 0.015 excitationfreq = 1.5e9 # GHz # excitationfreq = 1.71e9 # Value from http://hdl.handle.net/1842/4074 sourceresistance = 50 # Ohms # sourceresistance = 4 # Value from http://hdl.handle.net/1842/4074 x = x - (casesize[0] / 2) y = y - (casesize[1] / 2) # Coordinates of source excitation point in antenna tx = x + 0.114, y + 0.053, z + skidthickness if resolution == 0.001: dx = 0.001 dy = 0.001 dz = 0.001 elif resolution == 0.002: dx = 0.002 dy = 0.002 dz = 0.002 foamsurroundthickness = 0.002 patchheight = 0.016 tx = x + 0.112, y + 0.052, z + skidthickness else: raise CmdInputError('This antenna module can only be used with a spatial discretisation of 1mm or 2mm') # Material definitions print('#material: 1.7 0.59 1.0 0.0 absorber') # print('#material: 1.58 0.428 1.0 0.0 absorber') # Value from http://hdl.handle.net/1842/4074 print('#material: 3.0 0.0 1.0 0.0 pcb') print('#material: 2.35 0.0 1.0 0.0 hdpe') # Antenna geometry # Plastic case print('#box: {} {} {} {} {} {} hdpe'.format(x, y, z + skidthickness, x + casesize[0], y + casesize[1], z + skidthickness + casesize[2])) print('#box: {} {} {} {} {} {} free_space'.format(x + casethickness, y + casethickness, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + casesize[2] - casethickness)) # Metallic enclosure print('#box: {} {} {} {} {} {} pec'.format(x + 0.025, y + casethickness, z + skidthickness, x + casesize[0] - 0.025, y + casesize[1] - casethickness, z + skidthickness + 0.027)) # Absorber material, and foam (modelled as PCB material) around edge of absorber print('#box: {} {} {} {} {} {} pcb'.format(x + 0.025 + shieldthickness, y + casethickness + shieldthickness, z + skidthickness, x + 0.025 + shieldthickness + 0.057, y + casesize[1] - casethickness - shieldthickness, z + skidthickness + 0.027 - shieldthickness - 0.001)) print('#box: {} {} {} {} {} {} absorber'.format(x + 0.025 + shieldthickness + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.025 + shieldthickness + 0.057 - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + 0.027 - shieldthickness)) print('#box: {} {} {} {} {} {} pcb'.format(x + 0.086, y + casethickness + shieldthickness, z + skidthickness, x + 0.086 + 0.057, y + casesize[1] - casethickness - shieldthickness, z + skidthickness + 0.027 - shieldthickness - 0.001)) print('#box: {} {} {} {} {} {} absorber'.format(x + 0.086 + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.086 + 0.057 - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + 0.027 - shieldthickness)) # PCB print('#box: {} {} {} {} {} {} pcb'.format(x + 0.025 + shieldthickness + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.086 - shieldthickness - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + pcbthickness)) print('#box: {} {} {} {} {} {} pcb'.format(x + 0.086 + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.086 + 0.057 - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + pcbthickness)) # PCB components if resolution == 0.001: # Rx & Tx bowties a = 0 b = 0 while b < 13: print('#plate: {} {} {} {} {} {} pec'.format(x + 0.045 + a*dx, y + 0.039 + b*dx, z + skidthickness, x + 0.065 - a*dx, y + 0.039 + b*dx + dy, z + skidthickness)) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.045 + a*dx, y + 0.067 - b*dx, z + skidthickness, x + 0.065 - a*dx, y + 0.067 - b*dx + dy, z + skidthickness)) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.104 + a*dx, y + 0.039 + b*dx, z + skidthickness, x + 0.124 - a*dx, y + 0.039 + b*dx + dy, z + skidthickness)) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.104 + a*dx, y + 0.067 - b*dx, z + skidthickness, x + 0.124 - a*dx, y + 0.067 - b*dx + dy, z + skidthickness)) b += 1 if a == 2 or a == 4 or a == 7: print('#plate: {} {} {} {} {} {} pec'.format(x + 0.045 + a*dx, y + 0.039 + b*dx, z + skidthickness, x + 0.065 - a*dx, y + 0.039 + b*dx + dy, z + skidthickness)) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.045 + a*dx, y + 0.067 - b*dx, z + skidthickness, x + 0.065 - a*dx, y + 0.067 - b*dx + dy, z + skidthickness)) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.104 + a*dx, y + 0.039 + b*dx, z + skidthickness, x + 0.124 - a*dx, y + 0.039 + b*dx + dy, z + skidthickness)) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.104 + a*dx, y + 0.067 - b*dx, z + skidthickness, x + 0.124 - a*dx, y + 0.067 - b*dx + dy, z + skidthickness)) b += 1 a += 1 # Rx extension section (upper y) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.044, y + 0.068, z + skidthickness, x + 0.044 + bowtiebase, y + 0.068 + patchheight, z + skidthickness)) # Tx extension section (upper y) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.103, y + 0.068, z + skidthickness, x + 0.103 + bowtiebase, y + 0.068 + patchheight, z + skidthickness)) # Edges that represent wire between bowtie halves in 1mm model print('#edge: {} {} {} {} {} {} pec'.format(tx[0] - 0.059, tx[1] - dy, tx[2], tx[0] - 0.059, tx[1], tx[2])) print('#edge: {} {} {} {} {} {} pec'.format(tx[0] - 0.059, tx[1] + dy, tx[2], tx[0] - 0.059, tx[1] + 0.002, tx[2])) print('#edge: {} {} {} {} {} {} pec'.format(tx[0], tx[1] - dy, tx[2], tx[0], tx[1], tx[2])) print('#edge: {} {} {} {} {} {} pec'.format(tx[0], tx[1] + dz, tx[2], tx[0], tx[1] + 0.002, tx[2])) elif resolution == 0.002: # Rx & Tx bowties for a in range(0,6): print('#plate: {} {} {} {} {} {} pec'.format(x + 0.044 + a*dx, y + 0.040 + a*dx, z + skidthickness, x + 0.066 - a*dx, y + 0.040 + a*dx + dy, z + skidthickness)) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.044 + a*dx, y + 0.064 - a*dx, z + skidthickness, x + 0.066 - a*dx, y + 0.064 - a*dx + dy, z + skidthickness)) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.103 + a*dx, y + 0.040 + a*dx, z + skidthickness, x + 0.125 - a*dx, y + 0.040 + a*dx + dy, z + skidthickness)) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.103 + a*dx, y + 0.064 - a*dx, z + skidthickness, x + 0.125 - a*dx, y + 0.064 - a*dx + dy, z + skidthickness)) # Rx extension section (upper y) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.044, y + 0.066, z + skidthickness, x + 0.044 + bowtiebase, y + 0.066 + patchheight, z + skidthickness)) # Tx extension section (upper y) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.103, y + 0.066, z + skidthickness, x + 0.103 + bowtiebase, y + 0.066 + patchheight, z + skidthickness)) # Rx extension section (lower y) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.044, y + 0.024, z + skidthickness, x + 0.044 + bowtiebase, y + 0.024 + patchheight, z + skidthickness)) # Tx extension section (lower y) print('#plate: {} {} {} {} {} {} pec'.format(x + 0.103, y + 0.024, z + skidthickness, x + 0.103 + bowtiebase, y + 0.024 + patchheight, z + skidthickness)) # Skid print('#box: {} {} {} {} {} {} hdpe'.format(x, y, z, x + casesize[0], y + casesize[1], z + skidthickness)) # Geometry views #print('#geometry_view: {} {} {} {} {} {} {} {} {} antenna_like_GSSI_1500 n'.format(x - dx, y - dy, z - dz, x + casesize[0] + dx, y + casesize[1] + dy, z + skidthickness + casesize[2] + dz, dx, dy, dz)) #print('#geometry_view: {} {} {} {} {} {} {} {} {} antenna_like_GSSI_1500_pcb f'.format(x, y, z, x + casesize[0], y + casesize[1], z + 0.010, dx, dy, dz)) # Excitation print('#waveform: gaussian 1.0 {} myGaussian'.format(excitationfreq)) print('#voltage_source: y {} {} {} {} myGaussian'.format(tx[0], tx[1], tx[2], sourceresistance)) # Output point - transmitter bowtie #print('#rx: {} {} {}'.format(tx[0], tx[1], tx[2])) # Output point - receiver bowtie print('#rx: {} {} {}'.format(tx[0] - 0.059, tx[1], tx[2]))
"""Plots a B-scan image.""" # Parse command line arguments parser = argparse.ArgumentParser(description='Plots a B-scan image.', usage='cd gprMax; python -m tools.plot_Bscan outputfile output') parser.add_argument('outputfile', help='name of output file including path') parser.add_argument('output', help='name of output component to be plotted (Ex, Ey, Ez, Hx, Hy, Hz, Ix, Iy or Iz)') args = parser.parse_args() # Open output file and read some attributes f = h5py.File(args.outputfile, 'r') nrx = f.attrs['nrx'] # Check there are any receivers if nrx == 0: raise CmdInputError('No receivers found in {}'.format(args.outputfile)) for rx in range(1, nrx + 1): path = '/rxs/rx' + str(rx) + '/' availableoutputs = list(f[path].keys()) # Check if requested output is in file if args.output not in availableoutputs: raise CmdInputError('{} output requested to plot, but the available output for receiver 1 is {}'.format(args.output, ', '.join(availableoutputs))) outputdata = f[path + '/' + args.output] # Check that there is more than one A-scan present if outputdata.shape[1] == 1: raise CmdInputError('{} contains only a single A-scan.'.format(args.outputfile))
def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False): """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. Args: filename (string): Filename (including path) of output file. outputs (list): List of field/current components to plot. fft (boolean): Plot FFT switch. Returns: plt (object): matplotlib plot object. """ # Open output file and read some attributes f = h5py.File(filename, 'r') nrx = f.attrs['nrx'] dt = f.attrs['dt'] iterations = f.attrs['Iterations'] time = np.linspace(0, (iterations - 1) * dt, num=iterations) # Check there are any receivers if nrx == 0: raise CmdInputError('No receivers found in {}'.format(filename)) # Check for single output component when doing a FFT if fft: if not len(outputs) == 1: raise CmdInputError('A single output must be specified when using the -fft option') # New plot for each receiver for rx in range(1, nrx + 1): path = '/rxs/rx' + str(rx) + '/' availableoutputs = list(f[path].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] == '-': polarity = -1 outputtext = '-' + outputs[0][0:-1] output = outputs[0][0:-1] else: polarity = 1 outputtext = outputs[0] output = outputs[0] if output not in availableoutputs: raise CmdInputError('{} output requested to plot, but the available output for receiver 1 is {}'.format(output, ', '.join(availableoutputs))) outputdata = f[path + output][:] * polarity # Plotting if FFT required if fft: # FFT freqs, power = fft_power(outputdata, dt) freqmaxpower = np.where(np.isclose(power, 0))[0][0] # Set plotting range to -60dB from maximum power or 4 times #Â frequency at maximum power try: pltrange = np.where(power[freqmaxpower:] < -60)[0][0] + freqmaxpower + 1 except: pltrange = freqmaxpower * 4 pltrange = np.s_[0:pltrange] # Plot time history of output component fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, num='rx' + str(rx), 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='-.') # Plot frequency spectra markerline, stemlines, baseline = ax2.stem(freqs[pltrange], power[pltrange], '-.') 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 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') 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='rx' + str(rx), 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='-.') 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 populate only the specified ones else: fig, ax = plt.subplots(subplot_kw=dict(xlabel='Time [s]'), num='rx' + str(rx), 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 is in file if output[-1] == 'm': polarity = -1 outputtext = '-' + output[0:-1] output = output[0:-1] else: polarity = 1 outputtext = output # Check if requested output is in file if output not in availableoutputs: raise CmdInputError('Output(s) requested to plot: {}, but available output(s) for receiver {} in the file: {}'.format(', '.join(outputs), rx, ', '.join(availableoutputs))) outputdata = f[path + output][:] * polarity 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.set_ylim([-15, 20]) 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.set_ylim([-15, 20]) 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.set_ylim([-15, 20]) 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.set_ylim([-0.03, 0.03]) 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.set_ylim([-0.03, 0.03]) 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.set_ylim([-0.03, 0.03]) 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 = plt.subplot(gs[1, 2]) 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]') for ax in fig.axes: ax.set_xlim([0, np.amax(time)]) ax.grid(which='both', axis='both', linestyle='-.') # Save a PDF/PNG of the figure # fig.savefig(os.path.splitext(os.path.abspath(filename))[0] + '_rx' + str(rx) + '.pdf', dpi=None, format='pdf', bbox_inches='tight', pad_inches=0.1) # fig.savefig(os.path.splitext(os.path.abspath(filename))[0] + '_rx' + str(rx) + '.png', dpi=150, format='png', bbox_inches='tight', pad_inches=0.1) return plt
def run_opt_sim(args, inputfile, usernamespace): """Run a simulation using Taguchi's optmisation process. Args: args (dict): Namespace with command line arguments inputfile (object): File object for the input file. usernamespace (dict): Namespace that can be accessed by user in any Python code blocks in input file. """ tsimstart = perf_counter() if args.n > 1: raise CmdInputError('When a Taguchi optimisation is being carried out the number of model runs argument is not required') inputfileparts = os.path.splitext(inputfile.name) # Default maximum number of iterations of optimisation to perform (used # if the stopping criterion is not achieved) maxiterations = 20 # Process Taguchi code blocks in the input file; pass in ordered # dictionary to hold parameters to optimise tmp = usernamespace.copy() tmp.update({'optparams': OrderedDict()}) taguchinamespace = taguchi_code_blocks(inputfile, tmp) # Extract dictionaries and variables containing initialisation parameters optparams = taguchinamespace['optparams'] fitness = taguchinamespace['fitness'] if 'maxiterations' in taguchinamespace: maxiterations = taguchinamespace['maxiterations'] # Store initial parameter ranges optparamsinit = list(optparams.items()) # Dictionary to hold history of optmised values of parameters optparamshist = OrderedDict((key, list()) for key in optparams) # Import specified fitness function fitness_metric = getattr(import_module('user_libs.optimisation_taguchi.fitness_functions'), fitness['name']) # Select OA OA, N, cols, k, s, t = construct_OA(optparams) taguchistr = '\n--- Taguchi optimisation' print('{} {}\n'.format(taguchistr, '-' * (get_terminal_width() - 1 - len(taguchistr)))) print('Orthogonal array: {:g} experiments per iteration, {:g} parameters ({:g} will be used), {:g} levels, and strength {:g}'.format(N, cols, k, s, t)) tmp = [(k, v) for k, v in optparams.items()] print('Parameters to optimise with ranges: {}'.format(str(tmp).strip('[]'))) print('Output name(s) from model: {}'.format(fitness['args']['outputs'])) print('Fitness function "{}" with stopping criterion {:g}'.format(fitness['name'], fitness['stop'])) print('Maximum iterations: {:g}'.format(maxiterations)) # Initialise arrays and lists to store parameters required throughout optimisation # Lower, central, and upper values for each parameter levels = np.zeros((s, k), dtype=floattype) # Optimal lower, central, or upper value for each parameter levelsopt = np.zeros(k, dtype=np.uint8) # Difference used to set values for levels levelsdiff = np.zeros(k, dtype=floattype) # History of fitness values from each confirmation experiment fitnessvalueshist = [] iteration = 0 while iteration < maxiterations: # Reset number of model runs to number of experiments args.n = N usernamespace['number_model_runs'] = N # Fitness values for each experiment fitnessvalues = [] # Set parameter ranges and define experiments optparams, levels, levelsdiff = calculate_ranges_experiments(optparams, optparamsinit, levels, levelsopt, levelsdiff, OA, N, k, s, iteration) # Run model for each experiment # Mixed mode MPI with OpenMP or CUDA - MPI task farm for models with # each model parallelised with OpenMP (CPU) or CUDA (GPU) if args.mpi: run_mpi_sim(args, inputfile, usernamespace, optparams) # Standard behaviour - models run serially with each model parallelised # with OpenMP (CPU) or CUDA (GPU) else: run_std_sim(args, inputfile, usernamespace, optparams) # Calculate fitness value for each experiment for experiment in range(1, N + 1): outputfile = inputfileparts[0] + str(experiment) + '.out' fitnessvalues.append(fitness_metric(outputfile, fitness['args'])) os.remove(outputfile) taguchistr = '\n--- Taguchi optimisation, iteration {}: {} initial experiments with fitness values {}.'.format(iteration + 1, N, fitnessvalues) print('{} {}\n'.format(taguchistr, '-' * (get_terminal_width() - 1 - len(taguchistr)))) # Calculate optimal levels from fitness values by building a response # table; update dictionary of parameters with optimal values optparams, levelsopt = calculate_optimal_levels(optparams, levels, levelsopt, fitnessvalues, OA, N, k) # Update dictionary with history of parameters with optimal values for key, value in optparams.items(): optparamshist[key].append(value[0]) # Run a confirmation experiment with optimal values args.n = 1 usernamespace['number_model_runs'] = 1 # Mixed mode MPI with OpenMP or CUDA - MPI task farm for models with # each model parallelised with OpenMP (CPU) or CUDA (GPU) if args.mpi: run_mpi_sim(args, inputfile, usernamespace, optparams) # Standard behaviour - models run serially with each model parallelised # with OpenMP (CPU) or CUDA (GPU) else: run_std_sim(args, inputfile, usernamespace, optparams) # Calculate fitness value for confirmation experiment outputfile = inputfileparts[0] + '.out' fitnessvalueshist.append(fitness_metric(outputfile, fitness['args'])) # Rename confirmation experiment output file so that it is retained for each iteraction os.rename(outputfile, os.path.splitext(outputfile)[0] + '_final' + str(iteration + 1) + '.out') taguchistr = '\n--- Taguchi optimisation, iteration {} completed. History of optimal parameter values {} and of fitness values {}'.format(iteration + 1, dict(optparamshist), fitnessvalueshist) print('{} {}\n'.format(taguchistr, '-' * (get_terminal_width() - 1 - len(taguchistr)))) iteration += 1 # Stop optimisation if stopping criterion has been reached if fitnessvalueshist[iteration - 1] > fitness['stop']: taguchistr = '\n--- Taguchi optimisation stopped as fitness criteria reached: {:g} > {:g}'.format(fitnessvalueshist[iteration - 1], fitness['stop']) print('{} {}\n'.format(taguchistr, '-' * (get_terminal_width() - 1 - len(taguchistr)))) break # Stop optimisation if successive fitness values are within a percentage threshold fitnessvaluesthres = 0.1 if iteration > 2: fitnessvaluesclose = (np.abs(fitnessvalueshist[iteration - 2] - fitnessvalueshist[iteration - 1]) / fitnessvalueshist[iteration - 1]) * 100 if fitnessvaluesclose < fitnessvaluesthres: taguchistr = '\n--- Taguchi optimisation stopped as successive fitness values within {}%'.format(fitnessvaluesthres) print('{} {}\n'.format(taguchistr, '-' * (get_terminal_width() - 1 - len(taguchistr)))) break tsimend = perf_counter() # Save optimisation parameters history and fitness values history to file opthistfile = inputfileparts[0] + '_hist.pickle' with open(opthistfile, 'wb') as f: pickle.dump(optparamshist, f) pickle.dump(fitnessvalueshist, f) pickle.dump(optparamsinit, f) taguchistr = '\n=== Taguchi optimisation completed in [HH:MM:SS]: {} after {} iteration(s)'.format(datetime.timedelta(seconds=int(tsimend - tsimstart)), iteration) print('{} {}\n'.format(taguchistr, '=' * (get_terminal_width() - 1 - len(taguchistr)))) print('History of optimal parameter values {} and of fitness values {}\n'.format(dict(optparamshist), fitnessvalueshist))
if not pmlcheck: cmd1 = '#abc_type: pml' cmd2 = '#pml_layers: 10' print("Commands '{}' and '{}' added.".format(cmd1, cmd2)) inputlines.append(cmd1) inputlines.append(cmd2) # Process materials for position, material in materials.items(): params = material.split() debye = next((debye for debye in debyes if debye.split()[-1] == params[5]), None) if debye: if len(debye.split()) > 5: raise CmdInputError( "Command '{}' cannot be used in the old version of gprMax as it only supports materials with a single Debye pole." .format(''.join(debye))) medium = '#medium: {} {} {} {} {} {} {}'.format( float(params[1]) + float(debye.split()[2]), params[1], float(debye.split()[3]), params[2], params[3], params[4], params[5]) print("Commands '{}' and '{}', replaced with '{}'".format( material, debye, medium)) else: medium = '#medium: {} 0 0 {} {} {} {}'.format(params[1], params[2], params[3], params[4], params[5]) print("Command '{}', replaced with '{}'".format(material, medium)) inputlines[position] = medium # Create #analysis block
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', help='plot FFT of waveform', default=False) args = parser.parse_args() # Check waveform parameters if args.type.lower() not in Waveform.types: raise CmdInputError( 'The waveform must have one of the following types {}'.format( ', '.join(Waveform.types))) if args.freq <= 0: raise CmdInputError( 'The waveform requires an excitation frequency value of greater than zero' ) # Create waveform instance w = Waveform() w.type = args.type w.amp = args.amp w.freq = args.freq timewindow, iterations = check_timewindow(args.timewindow, args.dt) plthandle = mpl_plot(w, timewindow, args.dt, iterations, args.fft) plthandle.show()
def antenna_like_GSSI_1500(x, y, z, resolution=0.001, rotate90=False): """Inserts a description of an antenna similar to the GSSI 1.5GHz antenna. Can be used with 1mm (default) or 2mm spatial resolution. The external dimensions of the antenna are 170x108x45mm. One output point is defined between the arms of the receiver bowtie. The bowties are aligned with the y axis so the output is the y component of the electric field (x component if the antenna is rotated 90 degrees). Args: x, y, z (float): Coordinates of a location in the model to insert the antenna. Coordinates are relative to the geometric 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. rotate90 (bool): Rotate model 90 degrees CCW in xy plane. """ # Antenna geometry properties casesize = (0.170, 0.108, 0.043) casethickness = 0.002 shieldthickness = 0.002 foamsurroundthickness = 0.003 pcbthickness = 0.002 skidthickness = 0.004 bowtiebase = 0.022 bowtieheight = 0.014 patchheight = 0.015 # Set origin for rotation to geometric centre of antenna in x-y plane if required, and set output component for receiver if rotate90: rotate90origin = (x, y) output = 'Ex' else: rotate90origin = () output = 'Ey' x = x - (casesize[0] / 2) y = y - (casesize[1] / 2) # Coordinates of source excitation point in antenna tx = x + 0.114, y + 0.053, z + skidthickness if resolution == 0.001: dx = 0.001 dy = 0.001 dz = 0.001 elif resolution == 0.002: dx = 0.002 dy = 0.002 dz = 0.002 foamsurroundthickness = 0.002 patchheight = 0.016 tx = x + 0.114, y + 0.052, z + skidthickness else: raise CmdInputError('This antenna module can only be used with a spatial discretisation of 1mm or 2mm') # Specify optimisation state of antenna model optstate = ['WarrenThesis', 'DebyeAbsorber', 'GiannakisPaper'] optstate = optstate[0] if optstate == 'WarrenThesis': # Original optimised values from http://hdl.handle.net/1842/4074 excitationfreq = 1.71e9 sourceresistance = 230 # Correction for old (< 123) GprMax3D bug (optimised to 4) rxres = 925 # Resistance at Rx bowtie material(1.58, 0.428, 1, 0, 'absorber1') material(3, 0, 1, 0, 'absorber2') # Foam modelled as PCB material material(3, 0, 1, 0, 'pcb') material(2.35, 0, 1, 0, 'hdpe') material(3, (1 / rxres) * (dy / (dx * dz)), 1, 0, 'rxres') elif optstate == 'DebyeAbsorber': #Â Same values as WarrenThesis but uses dispersive absorber properties for Eccosorb LS22 excitationfreq = 1.71e9 sourceresistance = 230 # Correction for old (< 123) GprMax3D bug (optimised to 4) rxres = 925 # Resistance at Rx bowtie material(1, 0, 1, 0, 'absorber1') print('#add_dispersion_debye: 3 3.7733 1.00723e-11 3.14418 1.55686e-10 20.2441 3.44129e-10 absorber1') # Eccosorb LS22 3-pole Debye model (https://bitbucket.org/uoyaeg/aegboxts/wiki/Home) material(3, 0, 1, 0, 'absorber2') # Foam modelled as PCB material material(3, 0, 1, 0, 'pcb') material(2.35, 0, 1, 0, 'hdpe') material(3, (1 / rxres) * (dy / (dx * dz)), 1, 0, 'rxres') elif optstate == 'GiannakisPaper': # Further optimised values from https://doi.org/10.1109/TGRS.2018.2869027 sourceresistance = 195 material(3.96, 0.31, 1, 0, 'absorber1') material(1.05, 1.01, 1, 0, 'absorber2') material(1.37, 0.0002, 1, 0, 'pcb') material(1.99, 0.013, 1, 0, 'hdpe') # Antenna geometry # Plastic case box(x, y, z + skidthickness, x + casesize[0], y + casesize[1], z + skidthickness + casesize[2], 'hdpe', rotate90origin=rotate90origin) box(x + casethickness, y + casethickness, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + casesize[2] - casethickness, 'free_space', rotate90origin=rotate90origin) # Metallic enclosure box(x + 0.025, y + casethickness, z + skidthickness, x + casesize[0] - 0.025, y + casesize[1] - casethickness, z + skidthickness + 0.027, 'pec', rotate90origin=rotate90origin) # Absorber material (absorber1) and foam (absorber2) around edge of absorber box(x + 0.025 + shieldthickness, y + casethickness + shieldthickness, z + skidthickness, x + 0.025 + shieldthickness + 0.057, y + casesize[1] - casethickness - shieldthickness, z + skidthickness + 0.027 - shieldthickness - 0.001, 'absorber2', rotate90origin=rotate90origin) box(x + 0.025 + shieldthickness + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.025 + shieldthickness + 0.057 - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + 0.027 - shieldthickness, 'absorber1', rotate90origin=rotate90origin) box(x + 0.086, y + casethickness + shieldthickness, z + skidthickness, x + 0.086 + 0.057, y + casesize[1] - casethickness - shieldthickness, z + skidthickness + 0.027 - shieldthickness - 0.001, 'absorber2', rotate90origin=rotate90origin) box(x + 0.086 + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.086 + 0.057 - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + 0.027 - shieldthickness, 'absorber1', rotate90origin=rotate90origin) # PCB box(x + 0.025 + shieldthickness + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.086 - shieldthickness - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) box(x + 0.086 + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.086 + 0.057 - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) # PCB components if resolution == 0.001: # Rx & Tx bowties a = 0 b = 0 while b < 13: plate(x + 0.045 + a * dx, y + 0.039 + b * dx, z + skidthickness, x + 0.065 - a * dx, y + 0.039 + b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.045 + a * dx, y + 0.067 - b * dx, z + skidthickness, x + 0.065 - a * dx, y + 0.067 - b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.104 + a * dx, y + 0.039 + b * dx, z + skidthickness, x + 0.124 - a * dx, y + 0.039 + b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.104 + a * dx, y + 0.067 - b * dx, z + skidthickness, x + 0.124 - a * dx, y + 0.067 - b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) b += 1 if a == 2 or a == 4 or a == 7: plate(x + 0.045 + a * dx, y + 0.039 + b * dx, z + skidthickness, x + 0.065 - a * dx, y + 0.039 + b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.045 + a * dx, y + 0.067 - b * dx, z + skidthickness, x + 0.065 - a * dx, y + 0.067 - b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.104 + a * dx, y + 0.039 + b * dx, z + skidthickness, x + 0.124 - a * dx, y + 0.039 + b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.104 + a * dx, y + 0.067 - b * dx, z + skidthickness, x + 0.124 - a * dx, y + 0.067 - b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) b += 1 a += 1 # Rx extension section (upper y) plate(x + 0.044, y + 0.068, z + skidthickness, x + 0.044 + bowtiebase, y + 0.068 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Tx extension section (upper y) plate(x + 0.103, y + 0.068, z + skidthickness, x + 0.103 + bowtiebase, y + 0.068 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Edges that represent wire between bowtie halves in 1mm model edge(tx[0] - 0.059, tx[1] - dy, tx[2], tx[0] - 0.059, tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0] - 0.059, tx[1] + dy, tx[2], tx[0] - 0.059, tx[1] + 0.002, tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] - dy, tx[2], tx[0], tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] + dz, tx[2], tx[0], tx[1] + 0.002, tx[2], 'pec', rotate90origin=rotate90origin) elif resolution == 0.002: # Rx & Tx bowties for a in range(0, 6): plate(x + 0.044 + a * dx, y + 0.040 + a * dx, z + skidthickness, x + 0.066 - a * dx, y + 0.040 + a * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.044 + a * dx, y + 0.064 - a * dx, z + skidthickness, x + 0.066 - a * dx, y + 0.064 - a * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.103 + a * dx, y + 0.040 + a * dx, z + skidthickness, x + 0.125 - a * dx, y + 0.040 + a * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.103 + a * dx, y + 0.064 - a * dx, z + skidthickness, x + 0.125 - a * dx, y + 0.064 - a * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Rx extension section (upper y) plate(x + 0.044, y + 0.066, z + skidthickness, x + 0.044 + bowtiebase, y + 0.066 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Tx extension section (upper y) plate(x + 0.103, y + 0.066, z + skidthickness, x + 0.103 + bowtiebase, y + 0.066 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Rx extension section (lower y) plate(x + 0.044, y + 0.024, z + skidthickness, x + 0.044 + bowtiebase, y + 0.024 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Tx extension section (lower y) plate(x + 0.103, y + 0.024, z + skidthickness, x + 0.103 + bowtiebase, y + 0.024 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Skid box(x, y, z, x + casesize[0], y + casesize[1], z + skidthickness, 'hdpe', rotate90origin=rotate90origin) # Geometry views # geometry_view(x - dx, y - dy, z - dz, x + casesize[0] + dx, y + casesize[1] + dy, z + skidthickness + casesize[2] + dz, dx, dy, dz, 'antenna_like_GSSI_1500') # geometry_view(x, y, z, x + casesize[0], y + casesize[1], z + 0.010, dx, dy, dz, 'antenna_like_GSSI_1500_pcb', type='f') # Excitation if optstate == 'WarrenThesis' or optstate == 'DebyeAbsorber': # Gaussian pulse print('#waveform: gaussian 1 {} myGaussian'.format(excitationfreq)) voltage_source('y', tx[0], tx[1], tx[2], sourceresistance, 'myGaussian', dxdy=(resolution, resolution), rotate90origin=rotate90origin) elif optstate == 'GiannakisPaper': # Optimised custom pulse print('#excitation_file: {} linear extrapolate'.format(os.path.join(userlibdir, 'GSSI1p5optpulse.txt'))) voltage_source('y', tx[0], tx[1], tx[2], sourceresistance, 'GSSI1p5optpulse', dxdy=(resolution, resolution), rotate90origin=rotate90origin) # Output point - receiver bowtie if resolution == 0.001: if optstate == 'WarrenThesis' or optstate == 'DebyeAbsorber': edge(tx[0] - 0.059, tx[1], tx[2], tx[0] - 0.059, tx[1] + dy, tx[2], 'rxres', rotate90origin=rotate90origin) rx(tx[0] - 0.059, tx[1], tx[2], identifier='rxbowtie', to_save=[output], polarisation='y', dxdy=(resolution, resolution), rotate90origin=rotate90origin) elif resolution == 0.002: if optstate == 'WarrenThesis' or optstate == 'DebyeAbsorber': edge(tx[0] - 0.060, tx[1], tx[2], tx[0] - 0.060, tx[1] + dy, tx[2], 'rxres', rotate90origin=rotate90origin) rx(tx[0] - 0.060, tx[1], tx[2], identifier='rxbowtie', to_save=[output], polarisation='y', dxdy=(resolution, resolution), rotate90origin=rotate90origin)
def calculate_antenna_params(filename, tltxnumber=1, tlrxnumber=None, rxnumber=None, rxcomponent=None): """Calculates antenna parameters - incident, reflected and total volatges and currents; s11, (s21) and input impedance. Args: filename (string): Filename (including path) of output file. tltxnumber (int): Transmitter antenna - transmission line number tlrxnumber (int): Receiver antenna - transmission line number rxnumber (int): Receiver antenna - output number rxcomponent (str): Receiver antenna - output electric field component Returns: antennaparams (dict): Antenna parameters. """ # Open output file and read some attributes f = h5py.File(filename, '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, 1, iterations) time *= (iterations * dt) df = 1 / np.amax(time) print('Time window: {:g} s ({} iterations)'.format(np.amax(time), iterations)) print('Time step: {:g} s'.format(dt)) print('Frequency bin spacing: {:g} Hz'.format(df)) # Read/calculate voltages and currents from transmitter antenna tltxpath = '/tls/tl' + str(tltxnumber) + '/' # Incident voltages/currents Vinc = f[tltxpath + 'Vinc'][:] Iinc = f[tltxpath + 'Iinc'][:] # Total (incident + reflected) voltages/currents 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), get received voltage for s21 if tlrxnumber: tlrxpath = '/tls/tl' + str(tlrxnumber) + '/' Vrec = f[tlrxpath + 'Vtotal'][:] elif rxnumber: rxpath = '/rxs/rx' + str(rxnumber) + '/' availableoutputs = list(f[rxpath].keys()) if rxcomponent not in availableoutputs: raise CmdInputError( '{} output requested, but the available output for receiver {} is {}' .format(rxcomponent, rxnumber, ', '.join(availableoutputs))) rxpath += rxcomponent # Received voltage if rxcomponent == 'Ex': Vrec = f[rxpath][:] * -1 * dxdydz[0] elif rxcomponent == 'Ey': Vrec = f[rxpath][:] * -1 * dxdydz[1] 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 current timestep delaycorrection = np.exp(1j * 2 * np.pi * freqs * (dt / 2)) # Calculate s11 and (optionally) s21 s11 = np.abs(np.fft.fft(Vref) / np.fft.fft(Vinc)) if tlrxnumber or rxnumber: s21 = np.abs(np.fft.fft(Vrec) / np.fft.fft(Vinc)) # Calculate input impedance zin = (np.fft.fft(Vtotal) * delaycorrection) / np.fft.fft(Itotal) # Calculate input admittance yin = np.fft.fft(Itotal) / (np.fft.fft(Vtotal) * delaycorrection) # Convert to decibels 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))) Irefp = 20 * np.log10(np.abs(np.fft.fft(Iref))) Vtotalp = 20 * np.log10(np.abs((np.fft.fft(Vtotal) * delaycorrection))) Itotalp = 20 * np.log10(np.abs(np.fft.fft(Itotal))) s11 = 20 * np.log10(s11) # 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 } if tlrxnumber or rxnumber: s21 = 20 * np.log10(s21) antennaparams['s21'] = s21 return antennaparams
usage='cd gprMax; python -m tools.plot_hdf5_Bscan outputfile field') parser.add_argument('outputfile', help='name of output file including path') parser.add_argument('field', help='name of field to be plotted, i.e. Ex, Ey, Ez') args = parser.parse_args() file = args.outputfile field = args.field path = '/rxs/rx1' f = h5py.File(file, 'r') data = f[path + '/' + field] # Check that there is more than one A-scan present if data.shape[1] == 1: raise CmdInputError('{} contains only a single A-scan.'.format(file)) # Plot B-scan image fig = plt.figure(num=file, figsize=(20, 10), facecolor='w', edgecolor='w') plt.imshow(data, extent=[0, data.shape[1], data.shape[0] * f.attrs['dt'], 0], interpolation='nearest', aspect='auto', cmap='seismic', vmin=-np.amax(np.abs(data)), vmax=np.amax(np.abs(data))) plt.xlabel('Trace number') plt.ylabel('Time [s]') plt.grid() cb = plt.colorbar() cb.set_label('Field strength [V/m]')
def run_opt_sim(args, numbermodelruns, inputfile, usernamespace): """Run a simulation using Taguchi's optmisation process. Args: args (dict): Namespace with command line arguments numbermodelruns (int): Total number of model runs. inputfile (str): Name of the input file to open. usernamespace (dict): Namespace that can be accessed by user in any Python code blocks in input file. """ if numbermodelruns > 1: raise CmdInputError( 'When a Taguchi optimisation is being carried out the number of model runs argument is not required' ) inputfileparts = os.path.splitext(inputfile) # Default maximum number of iterations of optimisation to perform (used if the stopping criterion is not achieved) maxiterations = 20 # Process Taguchi code blocks in the input file; pass in ordered dictionary to hold parameters to optimise tmp = usernamespace.copy() tmp.update({'optparams': OrderedDict()}) taguchinamespace = taguchi_code_blocks(inputfile, tmp) # Extract dictionaries and variables containing initialisation parameters optparams = taguchinamespace['optparams'] fitness = taguchinamespace['fitness'] if 'maxiterations' in taguchinamespace: maxiterations = taguchinamespace['maxiterations'] # Store initial parameter ranges optparamsinit = list(optparams.items()) # Dictionary to hold history of optmised values of parameters optparamshist = OrderedDict((key, list()) for key in optparams) # Import specified fitness function fitness_metric = getattr( importlib.import_module('user_libs.optimisation_taguchi_fitness'), fitness['name']) # Select OA OA, N, cols, k, s, t = construct_OA(optparams) print( '\n{}\n\nTaguchi optimisation: orthogonal array with {} experiments, {} parameters ({} used), {} levels, and strength {} will be used.' .format(68 * '*', N, cols, k, s, t)) # Initialise arrays and lists to store parameters required throughout optimisation # Lower, central, and upper values for each parameter levels = np.zeros((s, k), dtype=floattype) # Optimal lower, central, or upper value for each parameter levelsopt = np.zeros(k, dtype=floattype) # Difference used to set values for levels levelsdiff = np.zeros(k, dtype=floattype) # History of fitness values from each confirmation experiment fitnessvalueshist = [] iteration = 0 while iteration < maxiterations: # Reset number of model runs to number of experiments numbermodelruns = N usernamespace['number_model_runs'] = numbermodelruns # Fitness values for each experiment fitnessvalues = [] # Set parameter ranges and define experiments optparams, levels, levelsdiff = calculate_ranges_experiments( optparams, optparamsinit, levels, levelsopt, levelsdiff, OA, N, k, s, iteration) # Run model for each experiment if args.mpi: # Mixed mode MPI/OpenMP - MPI task farm for models with each model parallelised with OpenMP run_mpi_sim(args, numbermodelruns, inputfile, usernamespace, optparams) else: # Standard behaviour - models run serially with each model parallelised with OpenMP run_std_sim(args, numbermodelruns, inputfile, usernamespace, optparams) # Calculate fitness value for each experiment for experiment in range(1, numbermodelruns + 1): outputfile = inputfileparts[0] + str(experiment) + '.out' fitnessvalues.append(fitness_metric(outputfile, fitness['args'])) os.remove(outputfile) print( '\nTaguchi optimisation, iteration {}: {} initial experiments with fitness values {}.' .format(iteration + 1, numbermodelruns, fitnessvalues)) # Calculate optimal levels from fitness values by building a response table; update dictionary of parameters with optimal values optparams, levelsopt = calculate_optimal_levels( optparams, levels, levelsopt, fitnessvalues, OA, N, k) # Run a confirmation experiment with optimal values numbermodelruns = 1 usernamespace['number_model_runs'] = numbermodelruns run_std_sim(args, numbermodelruns, inputfile, usernamespace, optparams) # Calculate fitness value for confirmation experiment outputfile = inputfileparts[0] + '.out' fitnessvalueshist.append(fitness_metric(outputfile, fitness['args'])) # Rename confirmation experiment output file so that it is retained for each iteraction os.rename( outputfile, os.path.splitext(outputfile)[0] + '_final' + str(iteration + 1) + '.out') print( '\nTaguchi optimisation, iteration {} completed. History of optimal parameter values {} and of fitness values {}' .format(iteration + 1, dict(optparamshist), fitnessvalueshist, 68 * '*')) iteration += 1 # Stop optimisation if stopping criterion has been reached if fitnessvalueshist[iteration - 1] > fitness['stop']: print('\nTaguchi optimisation stopped as fitness criteria reached') break # Stop optimisation if successive fitness values are within a percentage threshold if iteration > 2: fitnessvaluesclose = (np.abs(fitnessvalueshist[iteration - 2] - fitnessvalueshist[iteration - 1]) / fitnessvalueshist[iteration - 1]) * 100 fitnessvaluesthres = 0.1 if fitnessvaluesclose < fitnessvaluesthres: print( '\nTaguchi optimisation stopped as successive fitness values within {}%' .format(fitnessvaluesthres)) break # Save optimisation parameters history and fitness values history to file opthistfile = inputfileparts[0] + '_hist' np.savez(opthistfile, dict(optparamshist), fitnessvalueshist) print( '\n{}\nTaguchi optimisation completed after {} iteration(s).\nHistory of optimal parameter values {} and of fitness values {}\n{}\n' .format(68 * '*', iteration, dict(optparamshist), fitnessvalueshist, 68 * '*')) # Plot the history of fitness values and each optimised parameter values for the optimisation plot_optimisation_history(fitnessvalueshist, optparamshist, optparamsinit)
def process_multicmds(multicmds, G): """Checks the validity of command parameters and creates instances of classes of parameters. Args: multicmds (dict): Commands that can have multiple instances in the model. G (class): Grid class instance - holds essential parameters describing the model. """ # Waveform definitions cmdname = '#waveform' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) != 4: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly four parameters') if tmp[0].lower() not in Waveform.types: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' must have one of the following types {}'.format(','.join(Waveform.types))) if float(tmp[2]) <= 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires an excitation frequency value of greater than zero') if any(x.ID == tmp[3] for x in G.waveforms): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' with ID {} already exists'.format(tmp[3])) w = Waveform() w.ID = tmp[3] w.type = tmp[0].lower() w.amp = float(tmp[1]) w.freq = float(tmp[2]) if G.messages: print('Waveform {} of type {} with amplitude {:g}, frequency {:g}Hz created.'.format(w.ID, w.type, w.amp, w.freq)) G.waveforms.append(w) # Voltage source cmdname = '#voltage_source' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) < 6: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least six parameters') # Check polarity & position parameters if tmp[0].lower() not in ('x', 'y', 'z'): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' polarisation must be x, y, or z') xcoord = round_value(float(tmp[1])/G.dx) ycoord = round_value(float(tmp[2])/G.dy) zcoord = round_value(float(tmp[3])/G.dz) resistance = float(tmp[4]) if xcoord < 0 or xcoord >= G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' x-coordinate is not within the model domain') if ycoord < 0 or ycoord >= G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' y-coordinate is not within the model domain') if zcoord < 0 or zcoord >= G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' z-coordinate is not within the model domain') if xcoord < G.pmlthickness[0] or xcoord > G.nx - G.pmlthickness[3] or ycoord < G.pmlthickness[1] or ycoord > G.ny - G.pmlthickness[4] or zcoord < G.pmlthickness[2] or zcoord > G.nz - G.pmlthickness[5]: print("WARNING: '" + cmdname + ': ' + ' '.join(tmp) + "'" + ' sources and receivers should not normally be positioned within the PML.') if resistance < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a source resistance of zero or greater') # Check if there is a waveformID in the waveforms list if not any(x.ID == tmp[5] for x in G.waveforms): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' there is no waveform with the identifier {}'.format(tmp[5])) v = VoltageSource() v.polarisation= tmp[0] v.xcoord = xcoord v.ycoord = ycoord v.zcoord = zcoord v.resistance = resistance v.waveformID = tmp[5] if len(tmp) > 6: # Check source start & source remove time parameters start = float(tmp[6]) stop = float(tmp[7]) if start < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' delay of the initiation of the source should not be less than zero') if stop < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time to remove the source should not be less than zero') if stop - start <= 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' duration of the source should not be zero or less') v.start = start if stop > G.timewindow: v.stop = G.timewindow startstop = ' start time {:g} secs, finish time {:g} secs '.format(v.start, v.stop) else: v.start = 0 v.stop = G.timewindow startstop = ' ' if G.messages: print('Voltage source with polarity {} at {:g}m, {:g}m, {:g}m, resistance {:.1f} Ohms,'.format(v.polarisation, v.xcoord * G.dx, v.ycoord * G.dy, v.zcoord * G.dz, v.resistance) + startstop + 'using waveform {} created.'.format(v.waveformID)) G.voltagesources.append(v) # Hertzian dipole cmdname = '#hertzian_dipole' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) < 5: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters') # Check polarity & position parameters if tmp[0].lower() not in ('x', 'y', 'z'): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' polarisation must be x, y, or z') xcoord = round_value(float(tmp[1])/G.dx) ycoord = round_value(float(tmp[2])/G.dy) zcoord = round_value(float(tmp[3])/G.dz) if xcoord < 0 or xcoord >= G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' x-coordinate is not within the model domain') if ycoord < 0 or ycoord >= G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' y-coordinate is not within the model domain') if zcoord < 0 or zcoord >= G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' z-coordinate is not within the model domain') if xcoord < G.pmlthickness[0] or xcoord > G.nx - G.pmlthickness[3] or ycoord < G.pmlthickness[1] or ycoord > G.ny - G.pmlthickness[4] or zcoord < G.pmlthickness[2] or zcoord > G.nz - G.pmlthickness[5]: print("WARNING: '" + cmdname + ': ' + ' '.join(tmp) + "'" + ' sources and receivers should not normally be positioned within the PML.') # Check if there is a waveformID in the waveforms list if not any(x.ID == tmp[4] for x in G.waveforms): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' there is no waveform with the identifier {}'.format(tmp[4])) h = HertzianDipole() h.polarisation = tmp[0] h.xcoord = xcoord h.ycoord = ycoord h.zcoord = zcoord h.waveformID = tmp[4] if len(tmp) > 5: # Check source start & source remove time parameters start = float(tmp[5]) stop = float(tmp[6]) if start < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' delay of the initiation of the source should not be less than zero') if stop < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time to remove the source should not be less than zero') if stop - start <= 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' duration of the source should not be zero or less') h.start = start if stop > G.timewindow: h.stop = G.timewindow startstop = ' start time {:g} secs, finish time {:g} secs '.format(h.start, h.stop) else: h.start = 0 h.stop = G.timewindow startstop = ' ' if G.messages: print('Hertzian dipole with polarity {} at {:g}m, {:g}m, {:g}m,'.format(h.polarisation, h.xcoord * G.dx, h.ycoord * G.dy, h.zcoord * G.dz) + startstop + 'using waveform {} created.'.format(h.waveformID)) G.hertziandipoles.append(h) # Magnetic dipole cmdname = '#magnetic_dipole' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) < 5: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters') # Check polarity & position parameters if tmp[0].lower() not in ('x', 'y', 'z'): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' polarisation must be x, y, or z') xcoord = round_value(float(tmp[1])/G.dx) ycoord = round_value(float(tmp[2])/G.dy) zcoord = round_value(float(tmp[3])/G.dz) if xcoord < 0 or xcoord >= G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' x-coordinate is not within the model domain') if ycoord < 0 or ycoord >= G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' y-coordinate is not within the model domain') if zcoord < 0 or zcoord >= G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' z-coordinate is not within the model domain') if xcoord < G.pmlthickness[0] or xcoord > G.nx - G.pmlthickness[3] or ycoord < G.pmlthickness[1] or ycoord > G.ny - G.pmlthickness[4] or zcoord < G.pmlthickness[2] or zcoord > G.nz - G.pmlthickness[5]: print("WARNING: '" + cmdname + ': ' + ' '.join(tmp) + "'" + ' sources and receivers should not normally be positioned within the PML.') # Check if there is a waveformID in the waveforms list if not any(x.ID == tmp[4] for x in G.waveforms): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' there is no waveform with the identifier {}'.format(tmp[4])) m = MagneticDipole() m.polarisation = tmp[0] m.xcoord = xcoord m.ycoord = ycoord m.zcoord = zcoord m.waveformID = tmp[4] if len(tmp) > 5: # Check source start & source remove time parameters start = float(tmp[5]) stop = float(tmp[6]) if start < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' delay of the initiation of the source should not be less than zero') if stop < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time to remove the source should not be less than zero') if stop - start <= 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' duration of the source should not be zero or less') m.start = start if stop > G.timewindow: m.stop = G.timewindow startstop = ' start time {:g} secs, finish time {:g} secs '.format(m.start, m.stop) else: m.start = 0 m.stop = G.timewindow startstop = ' ' if G.messages: print('Magnetic dipole with polarity {} at {:g}m, {:g}m, {:g}m,'.format(m.polarisation, m.xcoord * G.dx, m.ycoord * G.dy, m.zcoord * G.dz) + startstop + 'using waveform {} created.'.format(m.waveformID)) G.magneticdipoles.append(m) # Transmission line cmdname = '#transmission_line' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) < 6: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least six parameters') # Check polarity & position parameters if tmp[0].lower() not in ('x', 'y', 'z'): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' polarisation must be x, y, or z') xcoord = round_value(float(tmp[1])/G.dx) ycoord = round_value(float(tmp[2])/G.dy) zcoord = round_value(float(tmp[3])/G.dz) resistance = float(tmp[4]) if xcoord < 0 or xcoord >= G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' x-coordinate is not within the model domain') if ycoord < 0 or ycoord >= G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' y-coordinate is not within the model domain') if zcoord < 0 or zcoord >= G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' z-coordinate is not within the model domain') if xcoord < G.pmlthickness[0] or xcoord > G.nx - G.pmlthickness[3] or ycoord < G.pmlthickness[1] or ycoord > G.ny - G.pmlthickness[4] or zcoord < G.pmlthickness[2] or zcoord > G.nz - G.pmlthickness[5]: print("WARNING: '" + cmdname + ': ' + ' '.join(tmp) + "'" + ' sources and receivers should not normally be positioned within the PML.') if resistance <= 0 or resistance > z0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a resistance greater than zero and less than the impedance of free space, i.e. 376.73 Ohms') # Check if there is a waveformID in the waveforms list if not any(x.ID == tmp[5] for x in G.waveforms): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' there is no waveform with the identifier {}'.format(tmp[4])) t = TransmissionLine(G) t.polarisation = tmp[0] t.xcoord = xcoord t.ycoord = ycoord t.zcoord = zcoord t.resistance = resistance t.waveformID = tmp[5] t.calculate_incident_V_I(G) if len(tmp) > 6: # Check source start & source remove time parameters start = float(tmp[6]) stop = float(tmp[7]) if start < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' delay of the initiation of the source should not be less than zero') if stop < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time to remove the source should not be less than zero') if stop - start <= 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' duration of the source should not be zero or less') t.start = start if stop > G.timewindow: t.stop = G.timewindow startstop = ' start time {:g} secs, finish time {:g} secs '.format(t.start, t.stop) else: t.start = 0 t.stop = G.timewindow startstop = ' ' if G.messages: print('Transmission line with polarity {} at {:g}m, {:g}m, {:g}m, resistance {:.1f} Ohms,'.format(t.polarisation, t.xcoord * G.dx, t.ycoord * G.dy, t.zcoord * G.dz, t.resistance) + startstop + 'using waveform {} created.'.format(t.waveformID)) G.transmissionlines.append(t) # Receiver cmdname = '#rx' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) != 3 and len(tmp) < 5: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' has an incorrect number of parameters') # Check position parameters xcoord = round_value(float(tmp[0])/G.dx) ycoord = round_value(float(tmp[1])/G.dy) zcoord = round_value(float(tmp[2])/G.dz) if xcoord < 0 or xcoord >= G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' x-coordinate is not within the model domain') if ycoord < 0 or ycoord >= G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' y-coordinate is not within the model domain') if zcoord < 0 or zcoord >= G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' z-coordinate is not within the model domain') if xcoord < G.pmlthickness[0] or xcoord > G.nx - G.pmlthickness[3] or ycoord < G.pmlthickness[1] or ycoord > G.ny - G.pmlthickness[4] or zcoord < G.pmlthickness[2] or zcoord > G.nz - G.pmlthickness[5]: print("WARNING: '" + cmdname + ': ' + ' '.join(tmp) + "'" + ' sources and receivers should not normally be positioned within the PML.') r = Rx(xcoord=xcoord, ycoord=ycoord, zcoord=zcoord) # If no ID or outputs are specified, use default i.e Ex, Ey, Ez, Hx, Hy, Hz, Ix, Iy, Iz if len(tmp) == 3: r.outputs = Rx.availableoutputs[0:9] else: r.ID = tmp[3] # Check and add field output names for field in tmp[4::]: if field in Rx.availableoutputs: r.outputs.append(field) else: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' contains an output type that is not available') if G.messages: print('Receiver at {:g}m, {:g}m, {:g}m with output(s) {} created.'.format(r.xcoord * G.dx, r.ycoord * G.dy, r.zcoord * G.dz, ', '.join(r.outputs))) G.rxs.append(r) # Receiver box cmdname = '#rx_box' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) != 9: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly nine parameters') xs = round_value(float(tmp[0])/G.dx) xf = round_value(float(tmp[3])/G.dx) ys = round_value(float(tmp[1])/G.dy) yf = round_value(float(tmp[4])/G.dy) zs = round_value(float(tmp[2])/G.dz) zf = round_value(float(tmp[5])/G.dz) dx = round_value(float(tmp[6])/G.dx) dy = round_value(float(tmp[7])/G.dy) dz = round_value(float(tmp[8])/G.dz) if xs < 0 or xs >= G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower x-coordinate {:g}m is not within the model domain'.format(xs)) if xf < 0 or xf >= G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper x-coordinate {:g}m is not within the model domain'.format(xf)) if ys < 0 or ys >= G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower y-coordinate {:g}m is not within the model domain'.format(ys)) if yf < 0 or yf >= G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper y-coordinate {:g}m is not within the model domain'.format(yf)) if zs < 0 or zs >= G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower z-coordinate {:g}m is not within the model domain'.format(zs)) if zf < 0 or zf >= G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper z-coordinate {:g}m is not within the model domain'.format(zf)) if xcoord < G.pmlthickness[0] or xcoord > G.nx - G.pmlthickness[3] or ycoord < G.pmlthickness[1] or ycoord > G.ny - G.pmlthickness[4] or zcoord < G.pmlthickness[2] or zcoord > G.nz - G.pmlthickness[5]: print("WARNING: '" + cmdname + ': ' + ' '.join(tmp) + "'" + ' sources and receivers should not normally be positioned within the PML.') if xs >= xf or ys >= yf or zs >= zf: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower coordinates should be less than the upper coordinates') if dx < 0 or dy < 0 or dz < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than zero') if dx < G.dx or dy < G.dy or dz < G.dz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than the spatial discretisation') for x in range(xs, xf, dx): for y in range(ys, yf, dy): for z in range(zs, zf, dz): r = Rx(xcoord=x, ycoord=y, zcoord=z) G.rxs.append(r) if G.messages: print('Receiver box {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m with steps {:g}m, {:g}m, {:g} created.'.format(xs * G.dx, ys * G.dy, zs * G.dz, xf * G.dx, yf * G.dy, zf * G.dz, dx * G.dx, dy * G.dy, dz * G.dz)) # Snapshot cmdname = '#snapshot' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) != 11: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly eleven parameters') xs = round_value(float(tmp[0])/G.dx) xf = round_value(float(tmp[3])/G.dx) ys = round_value(float(tmp[1])/G.dy) yf = round_value(float(tmp[4])/G.dy) zs = round_value(float(tmp[2])/G.dz) zf = round_value(float(tmp[5])/G.dz) dx = round_value(float(tmp[6])/G.dx) dy = round_value(float(tmp[7])/G.dy) dz = round_value(float(tmp[8])/G.dz) # If real floating point value given if '.' in tmp[9] or 'e' in tmp[9]: if float(tmp[9]) > 0: time = round_value((float(tmp[9]) / G.dt)) + 1 else: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time value must be greater than zero') # If number of iterations given else: time = int(tmp[9]) if xs < 0 or xs > G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower x-coordinate {:g}m is not within the model domain'.format(xs * G.dx)) if xf < 0 or xf > G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper x-coordinate {:g}m is not within the model domain'.format(xf * G.dx)) if ys < 0 or ys > G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower y-coordinate {:g}m is not within the model domain'.format(ys * G.dy)) if yf < 0 or yf > G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper y-coordinate {:g}m is not within the model domain'.format(yf * G.dy)) if zs < 0 or zs > G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower z-coordinate {:g}m is not within the model domain'.format(zs * G.dz)) if zf < 0 or zf > G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper z-coordinate {:g}m is not within the model domain'.format(zf * G.dz)) if xs >= xf or ys >= yf or zs >= zf: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower coordinates should be less than the upper coordinates') if dx < 0 or dy < 0 or dz < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than zero') if dx < G.dx or dy < G.dy or dz < G.dz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than the spatial discretisation') if time <= 0 or time > G.iterations: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' time value is not valid') s = Snapshot(xs, ys, zs, xf, yf, zf, dx, dy, dz, time, tmp[10]) if G.messages: print('Snapshot from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m, discretisation {:g}m, {:g}m, {:g}m, at {:g} secs with filename {} created.'.format(xs * G.dx, ys * G.dy, zs * G.dz, xf * G.dx, yf * G.dy, zf * G.dz, dx * G.dx, dx * G.dy, dx * G.dz, s.time * G.dt, s.filename)) G.snapshots.append(s) # Materials # Create built-in materials m = Material(0, 'pec', G) m.average = False G.materials.append(m) m = Material(1, 'free_space', G) m.average = True G.materials.append(m) cmdname = '#material' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) != 5: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly five parameters') if float(tmp[0]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for static (DC) permittivity') if float(tmp[1]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for conductivity') if float(tmp[2]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for permeability') if float(tmp[3]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for magnetic conductivity') if any(x.ID == tmp[4] for x in G.materials): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' with ID {} already exists'.format(tmp[4])) # Create a new instance of the Material class material (start index after pec & free_space) m = Material(len(G.materials), tmp[4], G) m.er = float(tmp[0]) m.se = float(tmp[1]) m.mr = float(tmp[2]) m.sm = float(tmp[3]) if G.messages: print('Material {} with epsr={:g}, sig={:g} S/m; mur={:g}, sig*={:g} S/m created.'.format(m.ID, m.er, m.se, m.mr, m.sm)) # Append the new material object to the materials list G.materials.append(m) cmdname = '#add_dispersion_debye' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) < 4: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least four parameters') if int(tmp[0]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for number of poles') poles = int(tmp[0]) materialsrequested = tmp[(2 * poles) + 1:len(tmp)] # Look up requested materials in existing list of material instances materials = [y for x in materialsrequested for y in G.materials if y.ID == x] if len(materials) != len(materialsrequested): notfound = [x for x in materialsrequested if x not in materials] raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' material(s) {} do not exist'.format(notfound)) for material in materials: material.type = 'debye' material.poles = poles material.average = False for pole in range(1, 2 * poles, 2): if float(tmp[pole]) > 0 and float(tmp[pole + 1]) > G.dt: material.deltaer.append(float(tmp[pole])) material.tau.append(float(tmp[pole + 1])) else: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires positive values for the permittivity difference and relaxation times, and relaxation times that are greater than the time step for the model.') if material.poles > Material.maxpoles: Material.maxpoles = material.poles if G.messages: print('Debye-type disperion added to {} with delta_epsr={}, and tau={} secs created.'.format(material.ID, ','.join('%4.2f' % deltaer for deltaer in material.deltaer), ','.join('%4.3e' % tau for tau in material.tau))) cmdname = '#add_dispersion_lorentz' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) < 5: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters') if int(tmp[0]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for number of poles') poles = int(tmp[0]) materialsrequested = tmp[(3 * poles) + 1:len(tmp)] # Look up requested materials in existing list of material instances materials = [y for x in materialsrequested for y in G.materials if y.ID == x] if len(materials) != len(materialsrequested): notfound = [x for x in materialsrequested if x not in materials] raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' material(s) {} do not exist'.format(notfound)) for material in materials: material.type = 'lorentz' material.poles = poles material.average = False for pole in range(1, 3 * poles, 3): if float(tmp[pole]) > 0 and float(tmp[pole + 1]) > G.dt and float(tmp[pole + 2]) > G.dt: material.deltaer.append(float(tmp[pole])) material.tau.append(float(tmp[pole + 1])) material.alpha.append(float(tmp[pole + 2])) else: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires positive values for the permittivity difference and frequencies, and associated times that are greater than the time step for the model.') if material.poles > Material.maxpoles: Material.maxpoles = material.poles if G.messages: print('Lorentz-type disperion added to {} with delta_epsr={}, omega={} secs, and gamma={} created.'.format(material.ID, ','.join('%4.2f' % deltaer for deltaer in material.deltaer), ','.join('%4.3e' % tau for tau in material.tau), ','.join('%4.3e' % alpha for alpha in material.alpha))) cmdname = '#add_dispersion_drude' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) < 5: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at least five parameters') if int(tmp[0]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for number of poles') poles = int(tmp[0]) materialsrequested = tmp[(3 * poles) + 1:len(tmp)] # Look up requested materials in existing list of material instances materials = [y for x in materialsrequested for y in G.materials if y.ID == x] if len(materials) != len(materialsrequested): notfound = [x for x in materialsrequested if x not in materials] raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' material(s) {} do not exist'.format(notfound)) for material in materials: material.type = 'drude' material.poles = poles material.average = False for pole in range(1, 2 * poles, 2): if float(tmp[pole]) > 0 and float(tmp[pole + 1]) > G.dt: material.tau.append(float(tmp[pole ])) material.alpha.append(float(tmp[pole + 1])) else: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires positive values for the frequencies, and associated times that are greater than the time step for the model.') if material.poles > Material.maxpoles: Material.maxpoles = material.poles if G.messages: print('Drude-type disperion added to {} with omega={} secs, and gamma={} secs created.'.format(material.ID, ','.join('%4.3e' % tau for tau in material.tau), ','.join('%4.3e' % alpha for alpha in material.alpha))) cmdname = '#soil_peplinski' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) != 7: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires at exactly seven parameters') if float(tmp[0]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the sand fraction') if float(tmp[1]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the clay fraction') if float(tmp[2]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the bulk density') if float(tmp[3]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the sand particle density') if float(tmp[4]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the lower limit of the water volumetric fraction') if float(tmp[5]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires a positive value for the upper limit of the water volumetric fraction') if any(x.ID == tmp[6] for x in G.mixingmodels): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' with ID {} already exists'.format(tmp[6])) # Create a new instance of the Material class material (start index after pec & free_space) s = PeplinskiSoil(tmp[6], float(tmp[0]), float(tmp[1]), float(tmp[2]), float(tmp[3]), (float(tmp[4]), float(tmp[5]))) if G.messages: print('Mixing model (Peplinski) used to create {} with sand fraction {:g}, clay fraction {:g}, bulk density {:g}g/cm3, sand particle density {:g}g/cm3, and water volumetric fraction {:g} to {:g} created.'.format(s.ID, s.S, s.C, s.rb, s.rs, s.mu[0], s.mu[1])) # Append the new material object to the materials list G.mixingmodels.append(s) # Geometry views (creates VTK-based geometry files) cmdname = '#geometry_view' if multicmds[cmdname] != 'None': for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) != 11: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly eleven parameters') xs = round_value(float(tmp[0])/G.dx) xf = round_value(float(tmp[3])/G.dx) ys = round_value(float(tmp[1])/G.dy) yf = round_value(float(tmp[4])/G.dy) zs = round_value(float(tmp[2])/G.dz) zf = round_value(float(tmp[5])/G.dz) dx = round_value(float(tmp[6])/G.dx) dy = round_value(float(tmp[7])/G.dy) dz = round_value(float(tmp[8])/G.dz) if xs < 0 or xs > G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower x-coordinate {:g}m is not within the model domain'.format(xs * G.dx)) if xf < 0 or xf > G.nx: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper x-coordinate {:g}m is not within the model domain'.format(xf * G.dx)) if ys < 0 or ys > G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower y-coordinate {:g}m is not within the model domain'.format(ys * G.dy)) if yf < 0 or yf > G.ny: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper y-coordinate {:g}m is not within the model domain'.format(yf * G.dy)) if zs < 0 or zs > G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower z-coordinate {:g}m is not within the model domain'.format(zs * G.dz)) if zf < 0 or zf > G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the upper z-coordinate {:g}m is not within the model domain'.format(zf * G.dz)) if xs >= xf or ys >= yf or zs >= zf: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the lower coordinates should be less than the upper coordinates') if dx < 0 or dy < 0 or dz < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than zero') if dx > G.nx or dy > G.ny or dz > G.nz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should be less than the domain size') if dx < G.dx or dy < G.dy or dz < G.dz: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' the step size should not be less than the spatial discretisation') if tmp[10].lower() != 'n' and tmp[10].lower() != 'f': raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires type to be either n (normal) or f (fine)') g = GeometryView(xs, ys, zs, xf, yf, zf, dx, dy, dz, tmp[9], tmp[10].lower()) if G.messages: print('Geometry view from {:g}m, {:g}m, {:g}m, to {:g}m, {:g}m, {:g}m, discretisation {:g}m, {:g}m, {:g}m, filename {} created.'.format(xs * G.dx, ys * G.dy, zs * G.dz, xf * G.dx, yf * G.dy, zf * G.dz, dx * G.dx, dy * G.dy, dz * G.dz, g.filename)) # Append the new GeometryView object to the geometry views list G.geometryviews.append(g) # Complex frequency shifted (CFS) PML parameter cmdname = '#pml_cfs' if multicmds[cmdname] != 'None': if len(multicmds[cmdname]) > 2: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' can only be used up to two times, for up to a 2nd order PML') for cmdinstance in multicmds[cmdname]: tmp = cmdinstance.split() if len(tmp) != 12: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' requires exactly twelve parameters') if tmp[0] not in CFSParameter.scalingprofiles.keys() or tmp[4] not in CFSParameter.scalingprofiles.keys() or tmp[8] not in CFSParameter.scalingprofiles.keys(): raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' must have scaling type {}'.format(','.join(CFSParameter.scalingprofiles.keys()))) if tmp[1] not in CFSParameter.scalingdirections or tmp[5] not in CFSParameter.scalingdirections or tmp[9] not in CFSParameter.scalingdirections: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' must have scaling type {}'.format(','.join(CFSParameter.scalingprofiles.keys()))) if float(tmp[2]) < 0 or float(tmp[3]) < 0 or float(tmp[6]) < 0 or float(tmp[7]) < 0 or float(tmp[10]) < 0: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' minimum and maximum scaling values must be greater than zero') if float(tmp[6]) < 1: raise CmdInputError("'" + cmdname + ': ' + ' '.join(tmp) + "'" + ' minimum scaling value for kappa must be greater than zero') cfs = CFS() cfsalpha = CFSParameter() cfsalpha.ID = 'alpha' cfsalpha.scalingprofile = tmp[0] cfsalpha.scalingdirection = tmp[1] cfsalpha.min = float(tmp[2]) cfsalpha.max = float(tmp[3]) cfskappa = CFSParameter() cfskappa.ID = 'kappa' cfskappa.scalingprofile = tmp[4] cfskappa.scalingdirection = tmp[5] cfskappa.min = float(tmp[6]) cfskappa.max = float(tmp[7]) cfssigma = CFSParameter() cfssigma.ID = 'sigma' cfssigma.scalingprofile = tmp[8] cfssigma.scalingdirection = tmp[9] cfssigma.min = float(tmp[10]) if tmp[11] == 'None': cfssigma.max = None else: cfssigma.max = float(tmp[11]) cfs = CFS() cfs.alpha = cfsalpha cfs.kappa = cfskappa cfs.sigma = cfssigma if G.messages: print('PML CFS parameters: alpha (scaling: {}, scaling direction: {}, min: {:g}, max: {:g}), kappa (scaling: {}, scaling direction: {}, min: {:g}, max: {:g}), sigma (scaling: {}, scaling direction: {}, min: {:g}, max: {:g}) created.'.format(cfsalpha.scalingprofile, cfsalpha.scalingdirection, cfsalpha.min, cfsalpha.max, cfskappa.scalingprofile, cfskappa.scalingdirection, cfskappa.min, cfskappa.max, cfssigma.scalingprofile, cfssigma.scalingdirection, cfssigma.min, cfssigma.max)) G.cfs.append(cfs)
def process_singlecmds(singlecmds, multicmds, G): """Checks the validity of command parameters and creates instances of classes of parameters. Args: singlecmds (dict): Commands that can only occur once in the model. multicmds (dict): Commands that can have multiple instances in the model (required to pass to process_materials_file function). G (class): Grid class instance - holds essential parameters describing the model. """ # Check validity of command parameters in order needed # messages cmd = '#messages' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') if singlecmds[cmd].lower() == 'y': G.messages = True elif singlecmds[cmd].lower() == 'n': G.messages = False else: raise CmdInputError(cmd + ' requires input values of either y or n') # Title cmd = '#title' if singlecmds[cmd] != 'None': G.title = singlecmds[cmd] if G.messages: print('Model title: {}'.format(G.title)) # Number of processors to run on (OpenMP) cmd = '#num_threads' ompthreads = os.environ.get('OMP_NUM_THREADS') if singlecmds[cmd] != 'None': tmp = tuple(int(x) for x in singlecmds[cmd].split()) if len(tmp) != 1: raise CmdInputError( cmd + ' requires exactly one parameter to specify the number of threads to use' ) if tmp[0] < 1: raise CmdInputError( cmd + ' requires the value to be an integer not less than one') G.nthreads = tmp[0] elif ompthreads: G.nthreads = int(ompthreads) else: # Set number of threads to number of physical CPU cores, i.e. avoid hyperthreading with OpenMP G.nthreads = psutil.cpu_count(logical=False) if G.messages: print('Number of threads: {}'.format(G.nthreads)) # Spatial discretisation cmd = '#dx_dy_dz' tmp = [float(x) for x in singlecmds[cmd].split()] if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') if tmp[0] <= 0: raise CmdInputError( cmd + ' requires the x-direction spatial step to be greater than zero') if tmp[1] <= 0: raise CmdInputError( cmd + ' requires the y-direction spatial step to be greater than zero') if tmp[2] <= 0: raise CmdInputError( cmd + ' requires the z-direction spatial step to be greater than zero') G.dx = tmp[0] G.dy = tmp[1] G.dz = tmp[2] if G.messages: print('Spatial discretisation: {:g} x {:g} x {:g}m'.format( G.dx, G.dy, G.dz)) # Domain cmd = '#domain' tmp = [float(x) for x in singlecmds[cmd].split()] if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.nx = round_value(tmp[0] / G.dx) G.ny = round_value(tmp[1] / G.dy) G.nz = round_value(tmp[2] / G.dz) if G.nx == 0 or G.ny == 0 or G.nz == 0: raise CmdInputError(cmd + ' requires at least one cell in every dimension') if G.messages: print( 'Domain size: {:g} x {:g} x {:g}m ({:d} x {:d} x {:d} = {:g} cells)' .format(tmp[0], tmp[1], tmp[2], G.nx, G.ny, G.nz, (G.nx * G.ny * G.nz))) # Guesstimate at memory usage mem = (((G.nx + 1) * (G.ny + 1) * (G.nz + 1) * 13 * np.dtype(floattype).itemsize + (G.nx + 1) * (G.ny + 1) * (G.nz + 1) * 18) * 1.1) + 30e6 print('Memory (RAM) usage: ~{} required, {} available'.format( human_size(mem), human_size(psutil.virtual_memory().total))) # Time step CFL limit - use either 2D or 3D (default) cmd = '#time_step_limit_type' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') if singlecmds[cmd].lower() == '2d': if G.nx == 1: G.dt = 1 / (c * np.sqrt((1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz))) elif G.ny == 1: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dz) * (1 / G.dz))) elif G.nz == 1: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy))) else: raise CmdInputError( cmd + ' 2D CFL limit can only be used when one dimension of the domain is one cell' ) elif singlecmds[cmd].lower() == '3d': G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz))) else: raise CmdInputError(cmd + ' requires input values of either 2D or 3D') else: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz))) # Round down time step to nearest float with precision one less than hardware maximum. Avoids inadvertently exceeding the CFL due to binary representation of floating point number. G.dt = round_value(G.dt, decimalplaces=d.getcontext().prec - 1) if G.messages: print('Time step: {:g} secs'.format(G.dt)) # Time step stability factor cmd = '#time_step_stability_factor' if singlecmds[cmd] != 'None': tmp = tuple(float(x) for x in singlecmds[cmd].split()) if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') if tmp[0] <= 0 or tmp[0] > 1: raise CmdInputError( cmd + ' requires the value of the time step stability factor to be between zero and one' ) G.dt = G.dt * tmp[0] if G.messages: print('Time step (modified): {:g} secs'.format(G.dt)) # Time window cmd = '#time_window' tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError( cmd + ' requires exactly one parameter to specify the time window. Either in seconds or number of iterations.' ) tmp = tmp[0].lower() # If real floating point value given if '.' in tmp or 'e' in tmp: if float(tmp) > 0: G.timewindow = float(tmp) G.iterations = round_value((float(tmp) / G.dt)) + 1 else: raise CmdInputError(cmd + ' must have a value greater than zero') # If number of iterations given else: G.timewindow = (int(tmp) - 1) * G.dt G.iterations = int(tmp) if G.messages: print('Time window: {:g} secs ({} iterations)'.format( G.timewindow, G.iterations)) # PML cmd = '#pml_cells' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 1 and len(tmp) != 6: raise CmdInputError(cmd + ' requires either one or six parameters') if len(tmp) == 1: G.pmlthickness = (int(tmp[0]), int(tmp[0]), int(tmp[0]), int(tmp[0]), int(tmp[0]), int(tmp[0])) else: G.pmlthickness = (int(tmp[0]), int(tmp[1]), int(tmp[2]), int(tmp[3]), int(tmp[4]), int(tmp[5])) if 2 * G.pmlthickness[0] >= G.nx or 2 * G.pmlthickness[ 1] >= G.ny or 2 * G.pmlthickness[2] >= G.nz or 2 * G.pmlthickness[ 3] >= G.nx or 2 * G.pmlthickness[ 4] >= G.ny or 2 * G.pmlthickness[5] >= G.nz: raise CmdInputError(cmd + ' has too many cells for the domain size') # src_steps cmd = '#src_steps' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.srcstepx = round_value(float(tmp[0]) / G.dx) G.srcstepy = round_value(float(tmp[1]) / G.dy) G.srcstepz = round_value(float(tmp[2]) / G.dz) if G.messages: print( 'All sources will step {:g}m, {:g}m, {:g}m for each model run.' .format(G.srcstepx * G.dx, G.srcstepy * G.dy, G.srcstepz * G.dz)) # rx_steps cmd = '#rx_steps' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.rxstepx = round_value(float(tmp[0]) / G.dx) G.rxstepy = round_value(float(tmp[1]) / G.dy) G.rxstepz = round_value(float(tmp[2]) / G.dz) if G.messages: print( 'All receivers will step {:g}m, {:g}m, {:g}m for each model run.' .format(G.rxstepx * G.dx, G.rxstepy * G.dy, G.rxstepz * G.dz)) # Excitation file for user-defined source waveforms cmd = '#excitation_file' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') excitationfile = tmp[0] # See if file exists at specified path and if not try input file directory if not os.path.isfile(excitationfile): excitationfile = os.path.join(G.inputdirectory, excitationfile) # Get waveform names with open(excitationfile, 'r') as f: waveformIDs = f.readline().split() # Read all waveform values into an array waveformvalues = np.loadtxt(excitationfile, skiprows=1, dtype=floattype) for waveform in range(len(waveformIDs)): if any(x.ID == waveformIDs[waveform] for x in G.waveforms): raise CmdInputError( 'Waveform with ID {} already exists'.format( waveformIDs[waveform])) w = Waveform() w.ID = waveformIDs[waveform] w.type = 'user' if len(waveformvalues.shape) == 1: w.uservalues = waveformvalues[:] else: w.uservalues = waveformvalues[:, waveform] if G.messages: print('User waveform {} created.'.format(w.ID)) G.waveforms.append(w)
def antenna_like_MALA_1200(x, y, z, resolution=0.001): """Inserts a description of an antenna similar to the MALA 1.2GHz antenna. Can be used with 1mm (default) or 2mm spatial resolution. The external dimensions of the antenna are 184mm x 109mm x 46mm. One output point is defined between the arms of the receiever bowtie. The bowties are aligned with the y axis so the output is the y component of the electric field. Args: x, y, z (float): Coordinates of a location in the model to insert the antenna. Coordinates are relative to the geometric 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. """ # Antenna geometry properties casesize = (0.184, 0.109, 0.040) casethickness = 0.002 cavitysize = (0.062, 0.062, 0.037) cavitythickness = 0.001 pcbthickness = 0.002 polypropylenethickness = 0.003; hdpethickness = 0.003; skidthickness = 0.006 bowtieheight = 0.025 excitationfreq = 0.978e9 # GHz sourceresistance = 1000 # Ohms x = x - (casesize[0] / 2) y = y - (casesize[1] / 2) # Coordinates of source excitation point in antenna tx = x + 0.063, y + 0.052, z + skidthickness if resolution == 0.001: dx = 0.001 dy = 0.001 dz = 0.001 elif resolution == 0.002: dx = 0.002 dy = 0.002 dz = 0.002 cavitysize = (0.062, 0.062, 0.036) cavitythickness = 0.002 polypropylenethickness = 0.002; hdpethickness = 0.004; bowtieheight = 0.024 tx = x + 0.062, y + 0.052, z + skidthickness else: raise CmdInputError('This antenna module can only be used with a spatial resolution of 1mm or 2mm') # SMD resistors - 3 on each Tx & Rx bowtie arm txres = 470 # Ohms txrescellupper = txres / 3 # Resistor over 3 cells txsigupper = ((1 / txrescellupper) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor txrescelllower = txres / 4 # Resistor over 4 cells txsiglower = ((1 / txrescelllower) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor rxres = 150 # Ohms rxrescellupper = rxres / 3 # Resistor over 3 cells rxsigupper = ((1 / rxrescellupper) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor rxrescelllower = rxres / 4 # Resistor over 4 cells rxsiglower = ((1 / rxrescelllower) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor # Material definitions print('#material: 6.49 0.252 1.0 0.0 absorber') print('#material: 3.0 0.0 1.0 0.0 pcb') print('#material: 2.35 0.0 1.0 0.0 hdpe') print('#material: 2.26 0.0 1.0 0.0 polypropylene') print('#material: 3.0 {:.3f} 1.0 0.0 txreslower'.format(txsiglower)) print('#material: 3.0 {:.3f} 1.0 0.0 txresupper'.format(txsigupper)) print('#material: 3.0 {:.3f} 1.0 0.0 rxreslower'.format(rxsiglower)) print('#material: 3.0 {:.3f} 1.0 0.0 rxresupper'.format(rxsigupper)) # Antenna geometry # Shield - metallic enclosure print('#box: {} {} {} {} {} {} pec'.format(x, y, z + skidthickness, x + casesize[0], y + casesize[1], z + skidthickness + casesize[2])) print('#box: {} {} {} {} {} {} free_space'.format(x + 0.020, y + casethickness, z + skidthickness, x + 0.100, y + casesize[1] - casethickness, z + skidthickness + casethickness)) print('#box: {} {} {} {} {} {} free_space'.format(x + 0.100, y + casethickness, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + casethickness)) # Absorber material print('#box: {} {} {} {} {} {} absorber'.format(x + 0.020, y + casethickness, z + skidthickness, x + 0.100, y + casesize[1] - casethickness, z + skidthickness + casesize[2] - casethickness)) print('#box: {} {} {} {} {} {} absorber'.format(x + 0.100, y + casethickness, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + casesize[2] - casethickness)) # Shield - cylindrical sections print('#cylinder: {} {} {} {} {} {} {} pec'.format(x + 0.055, y + casesize[1] - 0.008, z + skidthickness, x + 0.055, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness, 0.008)) print('#cylinder: {} {} {} {} {} {} {} pec'.format(x + 0.055, y + 0.008, z + skidthickness, x + 0.055, y + 0.008, z + skidthickness + casesize[2] - casethickness, 0.008)) print('#cylinder: {} {} {} {} {} {} {} pec'.format(x + 0.147, y + casesize[1] - 0.008, z + skidthickness, x + 0.147, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness, 0.008)) print('#cylinder: {} {} {} {} {} {} {} pec'.format(x + 0.147, y + 0.008, z + skidthickness, x + 0.147, y + 0.008, z + skidthickness + casesize[2] - casethickness, 0.008)) print('#cylinder: {} {} {} {} {} {} {} free_space'.format(x + 0.055, y + casesize[1] - 0.008, z + skidthickness, x + 0.055, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness, 0.007)) print('#cylinder: {} {} {} {} {} {} {} free_space'.format(x + 0.055, y + 0.008, z + skidthickness, x + 0.055, y + 0.008, z + skidthickness + casesize[2] - casethickness, 0.007)) print('#cylinder: {} {} {} {} {} {} {} free_space'.format(x + 0.147, y + casesize[1] - 0.008, z + skidthickness, x + 0.147, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness, 0.007)) print('#cylinder: {} {} {} {} {} {} {} free_space'.format(x + 0.147, y + 0.008, z + skidthickness, x + 0.147, y + 0.008, z + skidthickness + casesize[2] - casethickness, 0.007)) print('#box: {} {} {} {} {} {} free_space'.format(x + 0.054, y + casesize[1] - 0.016, z + skidthickness, x + 0.056, y + casesize[1] - 0.014, z + skidthickness + casesize[2] - casethickness)) print('#box: {} {} {} {} {} {} free_space'.format(x + 0.054, y + 0.014, z + skidthickness, x + 0.056, y + 0.016, z + skidthickness + casesize[2] - casethickness)) print('#box: {} {} {} {} {} {} free_space'.format(x + 0.146, y + casesize[1] - 0.016, z + skidthickness, x + 0.148, y + casesize[1] - 0.014, z + skidthickness + casesize[2] - casethickness)) print('#box: {} {} {} {} {} {} free_space'.format(x + 0.146, y + 0.014, z + skidthickness, x + 0.148, y + 0.016, z + skidthickness + casesize[2] - casethickness)) # PCB print('#box: {} {} {} {} {} {} pcb'.format(x + 0.020, y + 0.018, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - 0.018, z + skidthickness + pcbthickness)) # Shield - Tx & Rx cavities print('#box: {} {} {} {} {} {} pec'.format(x + 0.032, y + 0.022, z + skidthickness, x + 0.032 + cavitysize[0], y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2])) print('#box: {} {} {} {} {} {} absorber'.format(x + 0.032 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness, x + 0.032 + cavitysize[0] - cavitythickness, y + 0.022 + cavitysize[1] - cavitythickness, z + skidthickness + cavitysize[2])) print('#box: {} {} {} {} {} {} pec'.format(x + 0.108, y + 0.022, z + skidthickness, x + 0.108 + cavitysize[0], y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2])) print('#box: {} {} {} {} {} {} free_space'.format(x + 0.108 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness, x + 0.108 + cavitysize[0] - cavitythickness, y + 0.022 + cavitysize[1] - cavitythickness, z + skidthickness + cavitysize[2])) # Shield - Tx & Rx cavities - joining strips print('#box: {} {} {} {} {} {} pec'.format(x + 0.032 + cavitysize[0], y + 0.022 + cavitysize[1] - 0.006, z + skidthickness + cavitysize[2] - casethickness, x + 0.108, y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2])) print('#box: {} {} {} {} {} {} pec'.format(x + 0.032 + cavitysize[0], y + 0.022, z + skidthickness + cavitysize[2] - casethickness, x + 0.108, y + 0.022 + 0.006, z + skidthickness + cavitysize[2])) # PCB - replace bits chopped by TX & Rx cavities print('#box: {} {} {} {} {} {} pcb'.format(x + 0.032 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness, x + 0.032 + cavitysize[0] - cavitythickness, y + 0.022 + cavitysize[1] - cavitythickness, z + skidthickness + pcbthickness)) print('#box: {} {} {} {} {} {} pcb'.format(x + 0.108 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness, x + 0.108 + cavitysize[0] - cavitythickness, y + 0.022 + cavitysize[1] - cavitythickness, z + skidthickness + pcbthickness)) # PCB components # Tx bowtie print('#triangle: {} {} {} {} {} {} {} {} {} 0 pec'.format(tx[0], tx[1] - 0.001, tx[2], tx[0] - 0.026, tx[1] - bowtieheight - 0.001, tx[2], tx[0] + 0.026, tx[1] - bowtieheight - 0.001, tx[2])) print('#edge: {} {} {} {} {} {} pec'.format(tx[0], tx[1] - 0.001, tx[2], tx[0], tx[1], tx[2])) print('#triangle: {} {} {} {} {} {} {} {} {} 0 pec'.format(tx[0], tx[1] + 0.002, tx[2], tx[0] - 0.026, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.026, tx[1] + bowtieheight + 0.002, tx[2])) print('#edge: {} {} {} {} {} {} pec'.format(tx[0], tx[1] + 0.001, tx[2], tx[0], tx[1] + 0.002, tx[2])) # Rx bowtie print('#triangle: {} {} {} {} {} {} {} {} {} 0 pec'.format(tx[0] + 0.076, tx[1] - 0.001, tx[2], tx[0] + 0.076 - 0.026, tx[1] - bowtieheight - 0.001, tx[2], tx[0] + 0.076 + 0.026, tx[1] - bowtieheight - 0.001, tx[2])) print('#edge: {} {} {} {} {} {} pec'.format(tx[0] + 0.076, tx[1] - 0.001, tx[2], tx[0] + 0.076, tx[1], tx[2])) print('#triangle: {} {} {} {} {} {} {} {} {} 0 pec'.format(tx[0] + 0.076, tx[1] + 0.002, tx[2], tx[0] + 0.076 - 0.026, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.076 + 0.026, tx[1] + bowtieheight + 0.002, tx[2])) print('#edge: {} {} {} {} {} {} pec'.format(tx[0] + 0.076, tx[1] + 0.001, tx[2], tx[0] + 0.076, tx[1] + 0.002, tx[2])) # Tx surface mount resistors (lower y coordinate) if resolution == 0.001: print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0] - 0.023, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023, tx[1] - bowtieheight - dy, tx[2])) print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0] - 0.023 + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + dx, tx[1] - bowtieheight - dy, tx[2])) print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0], tx[1] - bowtieheight - 0.004, tx[2], tx[0], tx[1] - bowtieheight - dy, tx[2])) print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0] + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + dx, tx[1] - bowtieheight - dy, tx[2])) print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0] + 0.022, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.022, tx[1] - bowtieheight - dy, tx[2])) print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0] + 0.022 + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.022 + dx, tx[1] - bowtieheight - dy, tx[2])) elif resolution == 0.002: print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0] - 0.023, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023, tx[1] - bowtieheight, tx[2])) print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0] - 0.023 + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + dx, tx[1] - bowtieheight, tx[2])) print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0], tx[1] - bowtieheight - 0.004, tx[2], tx[0], tx[1] - bowtieheight, tx[2])) print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0] + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + dx, tx[1] - bowtieheight, tx[2])) print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0] + 0.020, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.020, tx[1] - bowtieheight, tx[2])) print('#edge: {} {} {} {} {} {} txreslower'.format(tx[0] + 0.020 + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.020 + dx, tx[1] - bowtieheight, tx[2])) # Tx surface mount resistors (upper y coordinate) if resolution == 0.001: print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0] - 0.023, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0], tx[1] + bowtieheight + 0.002, tx[2], tx[0], tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0] + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + dx, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0] + 0.022, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.022, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0] + 0.022 + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.022 + dx, tx[1] + bowtieheight + 0.006, tx[2])) elif resolution == 0.002: print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0] - 0.023, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0], tx[1] + bowtieheight + 0.002, tx[2], tx[0], tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0] + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + dx, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0] + 0.020, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.020, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} txresupper'.format(tx[0] + 0.020 + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.020 + dx, tx[1] + bowtieheight + 0.006, tx[2])) # Rx surface mount resistors (lower y coordinate) if resolution == 0.001: print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - dy, tx[2])) print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - dy, tx[2])) print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.076, tx[1] - bowtieheight - dy, tx[2])) print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + dx + 0.076, tx[1] - bowtieheight - dy, tx[2])) print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] + 0.022 + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.022 + 0.076, tx[1] - bowtieheight - dy, tx[2])) print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] + 0.022 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.022 + dx + 0.076, tx[1] - bowtieheight - dy, tx[2])) elif resolution == 0.002: print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + 0.076, tx[1] - bowtieheight, tx[2])) print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight, tx[2])) print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.076, tx[1] - bowtieheight, tx[2])) print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + dx + 0.076, tx[1] - bowtieheight, tx[2])) print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] + 0.020 + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.020 + 0.076, tx[1] - bowtieheight, tx[2])) print('#edge: {} {} {} {} {} {} rxreslower'.format(tx[0] + 0.020 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.020 + dx + 0.076, tx[1] - bowtieheight, tx[2])) # Rx surface mount resistors (upper y coordinate) if resolution == 0.001: print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] + 0.022 + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.022 + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] + 0.022 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.022 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) elif resolution == 0.002: print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] + 0.020 + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.020 + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) print('#edge: {} {} {} {} {} {} rxresupper'.format(tx[0] + 0.020 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.020 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2])) # Skid print('#box: {} {} {} {} {} {} polypropylene'.format(x, y, z, x + casesize[0], y + casesize[1], z + polypropylenethickness)) print('#box: {} {} {} {} {} {} hdpe'.format(x, y, z + polypropylenethickness, x + casesize[0], y + casesize[1], z + polypropylenethickness + hdpethickness)) # Geometry views #print('#geometry_view: {} {} {} {} {} {} {} {} {} antenna_like_MALA_1200 n'.format(x - dx, y - dy, z - dz, x + casesize[0] + dx, y + casesize[1] + dy, z + casesize[2] + skidthickness + dz, dx, dy, dz)) #print('#geometry_view: {} {} {} {} {} {} {} {} {} antenna_like_MALA_1200_pcb f'.format(x, y, z, x + casesize[0], y + casesize[1], z + 0.010, dx, dy, dz)) # Excitation print('#waveform: gaussian 1.0 {} myGaussian'.format(excitationfreq)) print('#voltage_source: y {} {} {} {} myGaussian'.format(tx[0], tx[1], tx[2], sourceresistance)) # Output point - transmitter bowtie #print('#rx: {} {} {}'.format(tx[0], tx[1], tx[2])) # Output point - receiver bowtie print('#rx: {} {} {}'.format(tx[0] + 0.076, tx[1], tx[2]))
def check_cmd_names(processedlines, checkessential=True): """Checks the validity of commands, i.e. are they gprMax commands, and that all essential commands are present. Args: processedlines (list): Input commands after Python processing. checkessential (boolean): Perform check to see that all essential commands are present. Returns: singlecmds (dict): Commands that can only occur once in the model. multiplecmds (dict): Commands that can have multiple instances in the model. geometry (list): Geometry commands in the model. """ # Dictionaries of available commands # Essential commands neccessary to run a gprMax model essentialcmds = ['#domain', '#dx_dy_dz', '#time_window'] # Commands that there should only be one instance of in a model singlecmds = dict.fromkeys([ '#domain', '#dx_dy_dz', '#time_window', '#title', '#messages', '#num_threads', '#time_step_stability_factor', '#pml_cells', '#excitation_file', '#src_steps', '#rx_steps', '#taguchi', '#end_taguchi' ], 'None') # Commands that there can be multiple instances of in a model - these will be lists within the dictionary multiplecmds = { key: [] for key in [ '#geometry_view', '#geometry_objects_write', '#material', '#soil_peplinski', '#add_dispersion_debye', '#add_dispersion_lorentz', '#add_dispersion_drude', '#waveform', '#voltage_source', '#hertzian_dipole', '#magnetic_dipole', '#transmission_line', '#rx', '#rx_array', '#snapshot', '#pml_cfs' ] } # Geometry object building commands that there can be multiple instances of in a model - these will be lists within the dictionary geometrycmds = [ '#geometry_objects_read', '#edge', '#plate', '#triangle', '#box', '#sphere', '#cylinder', '#cylindrical_sector', '#fractal_box', '#add_surface_roughness', '#add_surface_water', '#add_grass' ] # List to store all geometry object commands in order from input file geometry = [] # Check if command names are valid, if essential commands are present, and add command parameters to appropriate dictionary values or lists countessentialcmds = 0 lindex = 0 while (lindex < len(processedlines)): cmd = processedlines[lindex].split(':') cmdname = cmd[0] cmdparams = cmd[1] # Check if there is space between command name and parameters, i.e. check first character of parameter string if ' ' not in cmdparams[0]: raise CmdInputError( 'There must be a space between the command name and parameters in ' + processedlines[lindex]) # Check if command name is valid if cmdname not in essentialcmds and cmdname not in singlecmds and cmdname not in multiplecmds and cmdname not in geometrycmds: raise CmdInputError( 'Your input file contains an invalid command: ' + cmdname) # Count essential commands if cmdname in essentialcmds: countessentialcmds += 1 # Assign command parameters as values to dictionary keys if cmdname in singlecmds: if singlecmds[cmdname] == 'None': singlecmds[cmdname] = cmd[1].strip(' \t\n') else: raise CmdInputError('You can only have instance of ' + cmdname + ' in your model') elif cmdname in multiplecmds: multiplecmds[cmdname].append(cmd[1].strip(' \t\n')) elif cmdname in geometrycmds: geometry.append(processedlines[lindex].strip(' \t\n')) lindex += 1 if checkessential: if (countessentialcmds < len(essentialcmds)): raise CmdInputError( 'Your input file is missing essential commands required to run a model. Essential commands are: ' + ', '.join(essentialcmds)) return singlecmds, multiplecmds, geometry
def antenna_like_GSSI_400(x, y, z, resolution=0.001, rotate90=False): """Inserts a description of an antenna similar to the GSSI 400MHz antenna. Can be used with 0.5mm, 1mm (default) or 2mm spatial resolution. The external dimensions of the antenna are 300x300x178mm. One output point is defined between the arms of the receiver bowtie. The bowties are aligned with the y axis so the output is the y component of the electric field. Args: x, y, z (float): Coordinates of a location in the model to insert the antenna. Coordinates are relative to the geometric 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. rotate90 (bool): Rotate model 90 degrees CCW in xy plane. """ # Antenna geometry properties casesize = (0.3, 0.3, 0.178) # original casethickness = 0.002 shieldthickness = 0.002 foamsurroundthickness = 0.003 pcbthickness = 0.002 bowtiebase = 0.06 bowtieheight = 0.06 # original 0.056 patchheight = 0.06 # original 0.056 metalboxheight = 0.089 metalmiddleplateheight = 0.11 # Set origin for rotation to geometric centre of antenna in x-y plane if required, and set output component for receiver if rotate90: rotate90origin = (x, y) output = 'Ex' else: rotate90origin = () output = 'Ey' smooth_dec = 'yes' # choose to use dielectric smoothing or not src_type = 'voltage_source' # # source type. "voltage_source" or "transmission_line" excitationfreq = 0.39239891e9 # GHz sourceresistance = 111.59927 # Ohms receiverresistance = sourceresistance # Ohms absorberEr = 1.1 absorbersig = 0.062034689 pcber = 2.35 hdper = 2.35 skidthickness = 0.01 x = x - (casesize[0] / 2) y = y - (casesize[1] / 2) # Coordinates of source excitation point in antenna tx = x + 0.01 + 0.005 + 0.056, y + casethickness + 0.005 + 0.143, z + skidthickness if resolution == 0.0005: dx = 0.0005 dy = 0.0005 dz = 0.0005 tx = x + 0.01 + 0.005 + 0.056, y + casethickness + 0.005 + 0.1435, z + skidthickness elif resolution == 0.001: dx = 0.001 dy = 0.001 dz = 0.001 elif resolution == 0.002: dx = 0.002 dy = 0.002 dz = 0.002 foamsurroundthickness = 0.002 metalboxheight = 0.088 tx = x + 0.01 + 0.004 + 0.056, y + casethickness + 0.005 + 0.143 - 0.002, z + skidthickness else: raise CmdInputError('This antenna module can only be used with a spatial discretisation of 0.5mm, 1mm, 2mm') # Material definitions material(absorberEr, absorbersig, 1, 0, 'absorber') material(pcber, 0, 1, 0, 'pcb') material(hdper, 0, 1, 0, 'hdpe') # Antenna geometry if smooth_dec == 'yes': # Plastic case box(x, y, z + skidthickness - 0.002, x + casesize[0], y + casesize[1], z + casesize[2], 'hdpe', rotate90origin=rotate90origin) # new new (0.300 x 0.300 x 0.170) box(x + casethickness, y + casethickness, z + skidthickness - 0.002, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + casesize[2] - casethickness, 'free_space', rotate90origin=rotate90origin) # (0.296 x 0.296 x 0.168) # Metallic enclosure box(x + casethickness, y + casethickness, z + skidthickness + (metalmiddleplateheight - metalboxheight), x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + (metalmiddleplateheight - metalboxheight) + metalboxheight, 'pec', rotate90origin=rotate90origin) # new (0.296 x 0.296 x 0.088) # Absorber, and foam (modelled as PCB material) around edge of absorber box(x + casethickness, y + casethickness, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + (metalmiddleplateheight - metalboxheight), 'absorber', rotate90origin=rotate90origin) # new 4 (0.296 x 0.296 x 0.022) box(x + casethickness + shieldthickness, y + casethickness + shieldthickness, z + skidthickness + (metalmiddleplateheight - metalboxheight), x + casesize[0] - casethickness - shieldthickness, y + casesize[1] - casethickness - shieldthickness, z + skidthickness - shieldthickness + metalmiddleplateheight, 'absorber', rotate90origin=rotate90origin) # new 4 (0.292 x 0.292 x 0.086) # PCB if resolution == 0.0005: box(x + 0.01 + 0.005 + 0.018, y + casethickness + 0.005 + 0.0235, z + skidthickness, x + 0.01 + 0.005 + 0.034 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) # new box(x + 0.01 + 0.005 + 0.178, y + casethickness + 0.005 + 0.0235, z + skidthickness, x + 0.01 + 0.005 + 0.194 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) # new elif resolution == 0.001: box(x + 0.01 + 0.005 + 0.018, y + casethickness + 0.005 + 0.023, z + skidthickness, x + 0.01 + 0.005 + 0.034 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) # new box(x + 0.01 + 0.005 + 0.178, y + casethickness + 0.005 + 0.023, z + skidthickness, x + 0.01 + 0.005 + 0.194 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) # new elif resolution == 0.002: box(x + 0.01 + 0.005 + 0.017, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.033 + bowtiebase, y + casethickness + 0.006 + 0.202 + patchheight, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) # new (for use with edges) box(x + 0.01 + 0.005 + 0.179, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.195 + bowtiebase, y + casethickness + 0.006 + 0.202 + patchheight, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) # new (for use with edges) elif smooth_dec == 'no': # Plastic case box(x, y, z + skidthickness - 0.002, x + casesize[0], y + casesize[1], z + casesize[2], 'hdpe', 'n', rotate90origin=rotate90origin) # new new (0.300 x 0.300 x 0.170) box(x + casethickness, y + casethickness, z + skidthickness - 0.002, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + casesize[2] - casethickness, 'free_space', 'n', rotate90origin=rotate90origin) # (0.296 x 0.296 x 0.168) # Metallic enclosure box(x + casethickness, y + casethickness, z + skidthickness + (metalmiddleplateheight - metalboxheight), x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + (metalmiddleplateheight - metalboxheight) + metalboxheight, 'pec', rotate90origin=rotate90origin) # new (0.296 x 0.296 x 0.088) # Absorber, and foam (modelled as PCB material) around edge of absorber box(x + casethickness, y + casethickness, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + (metalmiddleplateheight - metalboxheight), 'absorber', 'n', rotate90origin=rotate90origin) # new 4 (0.296 x 0.296 x 0.022) box(x + casethickness + shieldthickness, y + casethickness + shieldthickness, z + skidthickness + (metalmiddleplateheight - metalboxheight), x + casesize[0] - casethickness - shieldthickness, y + casesize[1] - casethickness - shieldthickness, z + skidthickness - shieldthickness + metalmiddleplateheight, 'absorber', 'n', rotate90origin=rotate90origin) # new 4 (0.292 x 0.292 x 0.086) # PCB if resolution == 0.0005: box(x + 0.01 + 0.005 + 0.018, y + casethickness + 0.005 + 0.0235, z + skidthickness, x + 0.01 + 0.005 + 0.034 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + pcbthickness, 'pcb', 'n', rotate90origin=rotate90origin) # new box(x + 0.01 + 0.005 + 0.178, y + casethickness + 0.005 + 0.0235, z + skidthickness, x + 0.01 + 0.005 + 0.194 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + pcbthickness, 'pcb', 'n', rotate90origin=rotate90origin) # new elif resolution == 0.001: box(x + 0.01 + 0.005 + 0.018, y + casethickness + 0.005 + 0.023, z + skidthickness, x + 0.01 + 0.005 + 0.034 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + pcbthickness, 'pcb', 'n', rotate90origin=rotate90origin) # new box(x + 0.01 + 0.005 + 0.178, y + casethickness + 0.005 + 0.023, z + skidthickness, x + 0.01 + 0.005 + 0.194 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + pcbthickness, 'pcb', 'n', rotate90origin=rotate90origin) # new elif resolution == 0.002: box(x + 0.01 + 0.005 + 0.017, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.033 + bowtiebase, y + casethickness + 0.006 + 0.202 + patchheight, z + skidthickness + pcbthickness, 'pcb', 'n', rotate90origin=rotate90origin) # new (for use with edges) box(x + 0.01 + 0.005 + 0.179, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.195 + bowtiebase, y + casethickness + 0.006 + 0.202 + patchheight, z + skidthickness + pcbthickness, 'pcb', 'n', rotate90origin=rotate90origin) # new (for use with edges) # PCB components # My own bowties with triangle commands if resolution == 0.0005: # "left" side # extension plates plate(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.0235, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.0235 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new # box(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.0235, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.0235 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new new plate(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new # box(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new new # triangles # triangle(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.0835, z + skidthickness, # x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.0835, z + skidthickness, # x + 0.01 + 0.005 + 0.026 + (bowtiebase/2), y + casethickness + 0.005 + 0.0835 + bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) triangle(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.0835, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.0835, z + skidthickness, x + 0.01 + 0.005 + 0.026 + (bowtiebase/2), y + casethickness + 0.005 + 0.0835 + bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new # triangle(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.204, z + skidthickness, # x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.204, z + skidthickness, # x + 0.01 + 0.005 + 0.026 + (bowtiebase/2), y + casethickness + 0.005 + 0.204 - bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) triangle(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.026 + (bowtiebase/2), y + casethickness + 0.005 + 0.204 - bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new # "right" side plate(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.0235, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.0235 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new # box(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.0235, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.0235 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new new plate(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new # box(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new # triangles # triangle(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.0835, z + skidthickness, # x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.0835, z + skidthickness, # x + 0.01 + 0.005 + 0.186 + (bowtiebase/2), y + casethickness + 0.005 + 0.0835 + bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) triangle(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.0835, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.0835, z + skidthickness, x + 0.01 + 0.005 + 0.186 + (bowtiebase/2), y + casethickness + 0.005 + 0.0835 + bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # triangle(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.204, z + skidthickness, # x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.204, z + skidthickness, # x + 0.01 + 0.005 + 0.186 + (bowtiebase/2), y + casethickness + 0.005 + 0.204 - bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) triangle(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.186 + (bowtiebase/2), y + casethickness + 0.005 + 0.204 - bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # Edges that represent wire between bowtie halves in 1mm model edge(tx[0] + 0.16, tx[1] - dy, tx[2], tx[0] + 0.16, tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0] + 0.16, tx[1] + dy, tx[2], tx[0] + 0.16, tx[1] + 2*dy, tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] - dy, tx[2], tx[0], tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] + dy, tx[2], tx[0], tx[1] + 2*dy, tx[2], 'pec', rotate90origin=rotate90origin) elif resolution == 0.001: # "left" side # extension plates plate(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.023, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.023 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new # box(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.023, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.023 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new plate(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new # box(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new # triangles # triangle(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.083, z + skidthickness, # x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.083, z + skidthickness, # x + 0.01 + 0.005 + 0.026 + (bowtiebase/2), y + casethickness + 0.005 + 0.083 + bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) triangle(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.083, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.083, z + skidthickness, x + 0.01 + 0.005 + 0.026 + (bowtiebase/2), y + casethickness + 0.005 + 0.083 + bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new # triangle(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.204, z + skidthickness, # x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.204, z + skidthickness, # x + 0.01 + 0.005 + 0.026 + (bowtiebase/2), y + casethickness + 0.005 + 0.204 - bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) triangle(x + 0.01 + 0.005 + 0.026, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.026 + bowtiebase, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.026 + (bowtiebase/2), y + casethickness + 0.005 + 0.204 - bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new # "right" side plate(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.023, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.023 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new # box(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.023, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.023 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new plate(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new # box(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.204 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new # triangles # triangle(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.083, z + skidthickness, # x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.083, z + skidthickness, # x + 0.01 + 0.005 + 0.186 + (bowtiebase/2), y + casethickness + 0.005 + 0.083 + bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) triangle(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.083, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.083, z + skidthickness, x + 0.01 + 0.005 + 0.186 + (bowtiebase/2), y + casethickness + 0.005 + 0.083 + bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # triangle(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.204, z + skidthickness, # x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.204, z + skidthickness, # x + 0.01 + 0.005 + 0.186 + (bowtiebase/2), y + casethickness + 0.005 + 0.204 - bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) triangle(x + 0.01 + 0.005 + 0.186, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.186 + bowtiebase, y + casethickness + 0.005 + 0.204, z + skidthickness, x + 0.01 + 0.005 + 0.186 + (bowtiebase/2), y + casethickness + 0.005 + 0.204 - bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # Edges that represent wire between bowtie halves in 1mm model edge(tx[0] + 0.16, tx[1] - dy, tx[2], tx[0] + 0.16, tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0] + 0.16, tx[1] + dy, tx[2], tx[0] + 0.16, tx[1] + 2*dy, tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] - dy, tx[2], tx[0], tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] + dy, tx[2], tx[0], tx[1] + 2*dy, tx[2], 'pec', rotate90origin=rotate90origin) elif resolution == 0.002: # "left" side # extension plates plate(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.021 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # box(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.021 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new (for use with edges) plate(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.203 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # box(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.203 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # triangles # triangle(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.081, z + skidthickness, # x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.081, z + skidthickness, # x + 0.01 + 0.005 + 0.025 + (bowtiebase/2), y + casethickness + 0.005 + 0.081 + bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) # new (for use with edges) triangle(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.081, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.081, z + skidthickness, x + 0.01 + 0.005 + 0.025 + (bowtiebase/2), y + casethickness + 0.005 + 0.081 + bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new (for use with edges) # triangle(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.203, z + skidthickness, # x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.203, z + skidthickness, # x + 0.01 + 0.005 + 0.025 + (bowtiebase/2), y + casethickness + 0.005 + 0.203 - bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) # new (for use with edges) triangle(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.025 + (bowtiebase/2), y + casethickness + 0.005 + 0.203 - bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new (for use with edges) # "right" side plate(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.021 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # box(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.021 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new (for use with edges) plate(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.203 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # box(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.203 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # triangles # triangle(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.081, z + skidthickness, # x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.081, z + skidthickness, # x + 0.01 + 0.005 + 0.187 + (bowtiebase/2), y + casethickness + 0.005 + 0.081 + bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) # new (for use with edges) triangle(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.081, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.081, z + skidthickness, x + 0.01 + 0.005 + 0.187 + (bowtiebase/2), y + casethickness + 0.005 + 0.081 + bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new (for use with edges) # triangle(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.203, z + skidthickness, # x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.203, z + skidthickness, # x + 0.01 + 0.005 + 0.187 + (bowtiebase/2), y + casethickness + 0.005 + 0.203 - bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) # new (for use with edges) triangle(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.187 + (bowtiebase/2), y + casethickness + 0.005 + 0.203 - bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new (for use with edges) # Edges that represent wire between bowtie halves in 2mm model edge(tx[0] + 0.162, tx[1] - dy, tx[2], tx[0] + 0.162, tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0] + 0.162, tx[1] + dy, tx[2], tx[0] + 0.162, tx[1] + 2*dy, tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] - dy, tx[2], tx[0], tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] + dy, tx[2], tx[0], tx[1] + 2*dy, tx[2], 'pec', rotate90origin=rotate90origin) # "left" side # extension plates plate(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.021 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # box(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.021 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new (for use with edges) plate(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.203 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # box(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.203 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # triangles # triangle(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.081, z + skidthickness, # x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.081, z + skidthickness, # x + 0.01 + 0.005 + 0.025 + (bowtiebase/2), y + casethickness + 0.005 + 0.081 + bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) # new (for use with edges) triangle(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.081, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.081, z + skidthickness, x + 0.01 + 0.005 + 0.025 + (bowtiebase/2), y + casethickness + 0.005 + 0.081 + bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new (for use with edges) # triangle(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.203, z + skidthickness, # x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.203, z + skidthickness, # x + 0.01 + 0.005 + 0.025 + (bowtiebase/2), y + casethickness + 0.005 + 0.203 - bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) # new (for use with edges) triangle(x + 0.01 + 0.005 + 0.025, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.025 + bowtiebase, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.025 + (bowtiebase/2), y + casethickness + 0.005 + 0.203 - bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new (for use with edges) # "right" side plate(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.021 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # box(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.021, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.021 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new (for use with edges) plate(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.203 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # box(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.203 + patchheight, z + skidthickness + 0.002, 'pec', rotate90origin=rotate90origin) # new (for use with edges) # triangles # triangle(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.081, z + skidthickness, # x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.081, z + skidthickness, # x + 0.01 + 0.005 + 0.187 + (bowtiebase/2), y + casethickness + 0.005 + 0.081 + bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) # new (for use with edges) triangle(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.081, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.081, z + skidthickness, x + 0.01 + 0.005 + 0.187 + (bowtiebase/2), y + casethickness + 0.005 + 0.081 + bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new (for use with edges) # triangle(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.203, z + skidthickness, # x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.203, z + skidthickness, # x + 0.01 + 0.005 + 0.187 + (bowtiebase/2), y + casethickness + 0.005 + 0.203 - bowtieheight, z + skidthickness, # 0.002,'pec', rotate90origin=rotate90origin) # new (for use with edges) triangle(x + 0.01 + 0.005 + 0.187, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.187 + bowtiebase, y + casethickness + 0.005 + 0.203, z + skidthickness, x + 0.01 + 0.005 + 0.187 + (bowtiebase/2), y + casethickness + 0.005 + 0.203 - bowtieheight, z + skidthickness, 0,'pec', rotate90origin=rotate90origin) # new (for use with edges) # Edges that represent wire between bowtie halves in 2mm model edge(tx[0] + 0.162, tx[1] - dy, tx[2], tx[0] + 0.162, tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0] + 0.162, tx[1] + dy, tx[2], tx[0] + 0.162, tx[1] + 2*dy, tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] - dy, tx[2], tx[0], tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] + dy, tx[2], tx[0], tx[1] + 2*dy, tx[2], 'pec', rotate90origin=rotate90origin) # metallic plate extension box(x + (casesize[0] / 2), y + casethickness, z + skidthickness, x + (casesize[0] / 2) + shieldthickness, y + casesize[1] - casethickness, z + skidthickness + metalmiddleplateheight, 'pec', rotate90origin=rotate90origin) # new if smooth_dec == 'yes': # Skid box(x, y, z, x + casesize[0], y + casesize[1], z + skidthickness - 0.002, 'hdpe', rotate90origin=rotate90origin) # new elif smooth_dec == 'no': # Skid box(x, y, z, x + casesize[0], y + casesize[1], z + skidthickness - 0.002, 'hdpe', 'n', rotate90origin=rotate90origin) # new # Excitation - Gaussian pulse print('#waveform: gaussian 1 {} myGaussian'.format(excitationfreq)) if src_type == 'voltage_source': print('#voltage_source: y {} {} {} {} myGaussian'.format(tx[0], tx[1], tx[2], sourceresistance)) elif src_type == 'transmission_line': print('#transmission_line: y {} {} {} {} myGaussian'.format(tx[0], tx[1], tx[2], sourceresistance)) # Output point - receiver bowtie print('#waveform: gaussian 0 4e8 my_zero_src') if resolution == 0.001 or resolution == 0.0005: if src_type == 'transmission_line': print('#transmission_line: y {} {} {} {} my_zero_src'.format(tx[0] + 0.16, tx[1], tx[2], receiverresistance)) elif src_type == 'voltage_source': print('#voltage_source: y {} {} {} {} my_zero_src'.format(tx[0] + 0.16, tx[1], tx[2], receiverresistance)) print('#rx: {} {} {} {} {}'.format(tx[0] + 0.16, tx[1], tx[2], 'rx1', 'Ey')) elif resolution == 0.002: if src_type == 'transmission_line': print('#transmission_line: y {} {} {} {} my_zero_src'.format(tx[0] + 0.162, tx[1], tx[2], receiverresistance)) elif src_type == 'voltage_source': print('#rx: {} {} {} {} {}'.format(tx[0] + 0.162, tx[1], tx[2], 'rx1', 'Ey'))
def process_python_include_code(inputfile, usernamespace): """Looks for and processes any Python code found in the input file. It will ignore any lines that are comments, i.e. begin with a double hash (##), and any blank lines. It will also ignore any lines that do not begin with a hash (#) after it has processed Python commands. It will also process any include commands and insert the contents of the included file at that location. Args: inputfile (str): Name of the input file to open. usernamespace (dict): Namespace that can be accessed by user in any Python code blocks in input file. Returns: processedlines (list): Input commands after Python processing. """ with open(inputfile, 'r') as f: # Strip out any newline characters and comments that must begin with double hashes inputlines = [ line.rstrip() for line in f if (not line.startswith('##') and line.rstrip('\n')) ] # List to hold final processed commands processedlines = [] x = 0 while (x < len(inputlines)): # Process any Python code if (inputlines[x].startswith('#python:')): # String to hold Python code to be executed pythoncode = '' x += 1 while not inputlines[x].startswith('#end_python:'): # Add all code in current code block to string pythoncode += inputlines[x] + '\n' x += 1 if x == len(inputlines): raise CmdInputError( 'Cannot find the end of the Python code block, i.e. missing #end_python: command.' ) # Compile code for faster execution pythoncompiledcode = compile(pythoncode, '<string>', 'exec') # Redirect stdout to a text stream sys.stdout = result = StringIO() # Execute code block & make available only usernamespace exec(pythoncompiledcode, usernamespace) # String containing buffer of executed code codeout = result.getvalue().split('\n') result.close() # Reset stdio sys.stdout = sys.__stdout__ # Separate commands from any other generated output hashcmds = [] pythonstdout = [] for line in codeout: if line.startswith('#'): hashcmds.append(line + '\n') elif line: pythonstdout.append(line) # Add commands to a list processedlines.extend(hashcmds) # Print any generated output that is not commands if pythonstdout: print( 'Python messages (from stdout): {}\n'.format(pythonstdout)) # Process any include commands elif (inputlines[x].startswith('#include_file:')): includefile = inputlines[x].split() if len(includefile) != 2: raise CmdInputError( '#include_file requires exactly one parameter') includefile = includefile[1] # See if file exists at specified path and if not try input file directory if not os.path.isfile(includefile): includefile = os.path.join(usernamespace['inputdirectory'], includefile) with open(includefile, 'r') as f: # Strip out any newline characters and comments that must begin with double hashes includelines = [ includeline.rstrip() + '\n' for includeline in f if (not includeline.startswith('##') and includeline.rstrip('\n')) ] # Add lines from include file to list processedlines.extend(includelines) # Add any other commands to list elif (inputlines[x].startswith('#')): # Add gprMax command to list inputlines[x] += ('\n') processedlines.append(inputlines[x]) x += 1 return processedlines
def process_singlecmds(singlecmds, G): """Checks the validity of command parameters and creates instances of classes of parameters. Args: singlecmds (dict): Commands that can only occur once in the model. G (class): Grid class instance - holds essential parameters describing the model. """ # Check validity of command parameters in order needed # messages cmd = '#messages' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') if singlecmds[cmd].lower() == 'y': G.messages = True elif singlecmds[cmd].lower() == 'n': G.messages = False else: raise CmdInputError(cmd + ' requires input values of either y or n') # Title cmd = '#title' if singlecmds[cmd] != 'None': G.title = singlecmds[cmd] if G.messages: print('Model title: {}'.format(G.title)) # Number of threads (OpenMP) to use cmd = '#num_threads' if sys.platform == 'darwin': os.environ['OMP_WAIT_POLICY'] = 'ACTIVE' # What to do with threads when they are waiting; can drastically effect performance os.environ['OMP_DYNAMIC'] = 'FALSE' os.environ['OMP_PROC_BIND'] = 'TRUE' # Bind threads to physical cores if singlecmds[cmd] != 'None': tmp = tuple(int(x) for x in singlecmds[cmd].split()) if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter to specify the number of threads to use') if tmp[0] < 1: raise CmdInputError(cmd + ' requires the value to be an integer not less than one') G.nthreads = tmp[0] os.environ['OMP_NUM_THREADS'] = str(G.nthreads) elif os.environ.get('OMP_NUM_THREADS'): G.nthreads = int(os.environ.get('OMP_NUM_THREADS')) else: # Set number of threads to number of physical CPU cores, i.e. avoid hyperthreading with OpenMP G.nthreads = psutil.cpu_count(logical=False) os.environ['OMP_NUM_THREADS'] = str(G.nthreads) if G.messages: machineID, cpuID, osversion = get_machine_cpu_os() print('Number of threads: {} ({})'.format(G.nthreads, cpuID)) if G.nthreads > psutil.cpu_count(logical=False): print(Fore.RED + 'WARNING: You have specified more threads ({}) than available physical CPU cores ({}). This may lead to degraded performance.'.format(G.nthreads, psutil.cpu_count(logical=False)) + Style.RESET_ALL) # Spatial discretisation cmd = '#dx_dy_dz' tmp = [float(x) for x in singlecmds[cmd].split()] if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') if tmp[0] <= 0: raise CmdInputError(cmd + ' requires the x-direction spatial step to be greater than zero') if tmp[1] <= 0: raise CmdInputError(cmd + ' requires the y-direction spatial step to be greater than zero') if tmp[2] <= 0: raise CmdInputError(cmd + ' requires the z-direction spatial step to be greater than zero') G.dx = tmp[0] G.dy = tmp[1] G.dz = tmp[2] if G.messages: print('Spatial discretisation: {:g} x {:g} x {:g}m'.format(G.dx, G.dy, G.dz)) # Domain cmd = '#domain' tmp = [float(x) for x in singlecmds[cmd].split()] if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.nx = round_value(tmp[0] / G.dx) G.ny = round_value(tmp[1] / G.dy) G.nz = round_value(tmp[2] / G.dz) if G.nx == 0 or G.ny == 0 or G.nz == 0: raise CmdInputError(cmd + ' requires at least one cell in every dimension') if G.messages: print('Domain size: {:g} x {:g} x {:g}m ({:d} x {:d} x {:d} = {:g} cells)'.format(tmp[0], tmp[1], tmp[2], G.nx, G.ny, G.nz, (G.nx * G.ny * G.nz))) # Estimate memory (RAM) usage stdoverhead = 70e6 floatarrays = (6 + 6 + 1) * (G.nx + 1) * (G.ny + 1) * (G.nz + 1) * np.dtype(floattype).itemsize # 6 x field arrays + 6 x ID arrays + 1 x solid array rigidarray = (12 + 6) * (G.nx + 1) * (G.ny + 1) * (G.nz + 1) * np.dtype(np.int8).itemsize memestimate = stdoverhead + floatarrays + rigidarray if memestimate > psutil.virtual_memory().total: print(Fore.RED + 'WARNING: Estimated memory (RAM) required ~{} exceeds {} detected!\n'.format(human_size(memestimate), human_size(psutil.virtual_memory().total, a_kilobyte_is_1024_bytes=True)) + Style.RESET_ALL) if G.messages: print('Estimated memory (RAM) required: ~{} ({} detected)'.format(human_size(memestimate), human_size(psutil.virtual_memory().total, a_kilobyte_is_1024_bytes=True))) # Time step CFL limit (use either 2D or 3D) and default PML thickness if G.nx == 1: G.dt = 1 / (c * np.sqrt((1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz))) G.dimension = '2D' G.pmlthickness['xminus'] = 0 G.pmlthickness['xplus'] = 0 elif G.ny == 1: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dz) * (1 / G.dz))) G.dimension = '2D' G.pmlthickness['yminus'] = 0 G.pmlthickness['yplus'] = 0 elif G.nz == 1: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy))) G.dimension = '2D' G.pmlthickness['zminus'] = 0 G.pmlthickness['zplus'] = 0 else: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz))) G.dimension = '3D' # Round down time step to nearest float with precision one less than hardware maximum. Avoids inadvertently exceeding the CFL due to binary representation of floating point number. G.dt = round_value(G.dt, decimalplaces=d.getcontext().prec - 1) if G.messages: print('Time step (at {} CFL limit): {:g} secs'.format(G.dimension, G.dt)) # Time step stability factor cmd = '#time_step_stability_factor' if singlecmds[cmd] != 'None': tmp = tuple(float(x) for x in singlecmds[cmd].split()) if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') if tmp[0] <= 0 or tmp[0] > 1: raise CmdInputError(cmd + ' requires the value of the time step stability factor to be between zero and one') G.dt = G.dt * tmp[0] if G.messages: print('Time step (modified): {:g} secs'.format(G.dt)) # Time window cmd = '#time_window' tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter to specify the time window. Either in seconds or number of iterations.') tmp = tmp[0].lower() # If number of iterations given try: tmp = int(tmp) G.timewindow = (tmp - 1) * G.dt G.iterations = tmp # If real floating point value given except: tmp = float(tmp) if tmp > 0: G.timewindow = tmp G.iterations = round_value((tmp / G.dt)) + 1 else: raise CmdInputError(cmd + ' must have a value greater than zero') if G.messages: print('Time window: {:g} secs ({} iterations)'.format(G.timewindow, G.iterations)) # PML cmd = '#pml_cells' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 1 and len(tmp) != 6: raise CmdInputError(cmd + ' requires either one or six parameters') if len(tmp) == 1: for key in G.pmlthickness.keys(): G.pmlthickness[key] = int(tmp[0]) else: G.pmlthickness['xminus'] = int(tmp[0]) G.pmlthickness['yminus'] = int(tmp[1]) G.pmlthickness['zminus'] = int(tmp[2]) G.pmlthickness['xplus'] = int(tmp[3]) G.pmlthickness['yplus'] = int(tmp[4]) G.pmlthickness['zplus'] = int(tmp[5]) if 2 * G.pmlthickness['xminus'] >= G.nx or 2 * G.pmlthickness['yminus'] >= G.ny or 2 * G.pmlthickness['zminus'] >= G.nz or 2 * G.pmlthickness['xplus'] >= G.nx or 2 * G.pmlthickness['yplus'] >= G.ny or 2 * G.pmlthickness['zplus'] >= G.nz: raise CmdInputError(cmd + ' has too many cells for the domain size') # src_steps cmd = '#src_steps' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.srcsteps[0] = round_value(float(tmp[0]) / G.dx) G.srcsteps[1] = round_value(float(tmp[1]) / G.dy) G.srcsteps[2] = round_value(float(tmp[2]) / G.dz) if G.messages: print('Simple sources will step {:g}m, {:g}m, {:g}m for each model run.'.format(G.srcsteps[0] * G.dx, G.srcsteps[1] * G.dy, G.srcsteps[2] * G.dz)) # rx_steps cmd = '#rx_steps' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.rxsteps[0] = round_value(float(tmp[0]) / G.dx) G.rxsteps[1] = round_value(float(tmp[1]) / G.dy) G.rxsteps[2] = round_value(float(tmp[2]) / G.dz) if G.messages: print('All receivers will step {:g}m, {:g}m, {:g}m for each model run.'.format(G.rxsteps[0] * G.dx, G.rxsteps[1] * G.dy, G.rxsteps[2] * G.dz)) # Excitation file for user-defined source waveforms cmd = '#excitation_file' if singlecmds[cmd] != 'None': tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') excitationfile = tmp[0] # See if file exists at specified path and if not try input file directory if not os.path.isfile(excitationfile): excitationfile = os.path.abspath(os.path.join(G.inputdirectory, excitationfile)) # Get waveform names with open(excitationfile, 'r') as f: waveformIDs = f.readline().split() # Read all waveform values into an array waveformvalues = np.loadtxt(excitationfile, skiprows=1, dtype=floattype) for waveform in range(len(waveformIDs)): if any(x.ID == waveformIDs[waveform] for x in G.waveforms): raise CmdInputError('Waveform with ID {} already exists'.format(waveformIDs[waveform])) w = Waveform() w.ID = waveformIDs[waveform] w.type = 'user' if len(waveformvalues.shape) == 1: w.uservalues = waveformvalues[:] else: w.uservalues = waveformvalues[:, waveform] if G.messages: print('User waveform {} created.'.format(w.ID)) G.waveforms.append(w)
# fig.savefig(path + os.sep + savefile + '.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 tools.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']) args = parser.parse_args() # Open output file and read number of outputs (receivers) f = h5py.File(args.outputfile, 'r') nrx = f.attrs['nrx'] f.close() # Check there are any receivers if nrx == 0: raise CmdInputError('No receivers found in {}'.format(args.outputfile)) for rx in range(1, nrx + 1): outputdata, dt = get_output_data(args.outputfile, rx, args.rx_component) plthandle = mpl_plot(args.outputfile, outputdata, dt, rx, args.rx_component) plthandle.show()
elif cmdname == '#geometry_vtk': # Syntax of old command: #geometry_vtk: x1 y1 z1 x2 y2 z2 dx dy dz filename type replacement = '#geometry_view: {} {} {} {} {} {} {} {} {} {} {}'.format( params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7], params[8], params[9], params[10]) print("Command '{}', replaced with '{}'".format( inputlines[lindex], replacement)) inputlines.pop(lindex) inputlines.insert(lindex, replacement) lindex += 1 elif cmdname in ['#plane_wave', '#thin_wire', '#huygens_surface']: raise CmdInputError( "Command '{}' has not yet implemented in the new version of gprMax. For now please continue to use the old version." .format(inputlines[lindex])) else: lindex += 1 else: lindex += 1 # Convert separate #line_source and associated #tx to #waveform and #hertzian_dipole for source in linesources: params = source.split() if params[3] is badwaveforms: raise CmdInputError( "Waveform types {} are not compatible between new and old versions of gprMax." .format(''.join(badwaveforms)))
def process_singlecmds(singlecmds, G): """Checks the validity of command parameters and creates instances of classes of parameters. Args: singlecmds (dict): Commands that can only occur once in the model. G (class): Grid class instance - holds essential parameters describing the model. """ # Check validity of command parameters in order needed # messages cmd = '#messages' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') if singlecmds[cmd].lower() == 'y': G.messages = True elif singlecmds[cmd].lower() == 'n': G.messages = False else: raise CmdInputError(cmd + ' requires input values of either y or n') # Title cmd = '#title' if singlecmds[cmd] is not None: G.title = singlecmds[cmd] if G.messages: print('Model title: {}'.format(G.title)) # Get information about host machine hostinfo = get_host_info() # Number of threads (OpenMP) to use cmd = '#num_threads' if sys.platform == 'darwin': os.environ['OMP_WAIT_POLICY'] = 'ACTIVE' # Should waiting threads consume CPU power (can drastically effect performance) os.environ['OMP_DYNAMIC'] = 'FALSE' # Number of threads may be adjusted by the run time environment to best utilize system resources os.environ['OMP_PLACES'] = 'cores' # Each place corresponds to a single core (having one or more hardware threads) os.environ['OMP_PROC_BIND'] = 'TRUE' # Bind threads to physical cores # os.environ['OMP_DISPLAY_ENV'] = 'TRUE' # Prints OMP version and environment variables (useful for debug) # Catch bug with Windows Subsystem for Linux (https://github.com/Microsoft/BashOnWindows/issues/785) if 'Microsoft' in G.hostinfo['osversion']: os.environ['KMP_AFFINITY'] = 'disabled' del os.environ['OMP_PLACES'] del os.environ['OMP_PROC_BIND'] if singlecmds[cmd] is not None: tmp = tuple(int(x) for x in singlecmds[cmd].split()) if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter to specify the number of threads to use') if tmp[0] < 1: raise CmdInputError(cmd + ' requires the value to be an integer not less than one') G.nthreads = tmp[0] os.environ['OMP_NUM_THREADS'] = str(G.nthreads) elif os.environ.get('OMP_NUM_THREADS'): G.nthreads = int(os.environ.get('OMP_NUM_THREADS')) else: # Set number of threads to number of physical CPU cores G.nthreads = hostinfo['physicalcores'] os.environ['OMP_NUM_THREADS'] = str(G.nthreads) if G.messages: print('Number of CPU (OpenMP) threads: {}'.format(G.nthreads)) if G.nthreads > G.hostinfo['physicalcores']: print(Fore.RED + 'WARNING: You have specified more threads ({}) than available physical CPU cores ({}). This may lead to degraded performance.'.format(G.nthreads, hostinfo['physicalcores']) + Style.RESET_ALL) # Print information about any GPU in use if G.messages: if G.gpu is not None: print('GPU solving using: {} - {}'.format(G.gpu.deviceID, G.gpu.name)) # Spatial discretisation cmd = '#dx_dy_dz' tmp = [float(x) for x in singlecmds[cmd].split()] if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') if tmp[0] <= 0: raise CmdInputError(cmd + ' requires the x-direction spatial step to be greater than zero') if tmp[1] <= 0: raise CmdInputError(cmd + ' requires the y-direction spatial step to be greater than zero') if tmp[2] <= 0: raise CmdInputError(cmd + ' requires the z-direction spatial step to be greater than zero') G.dx = tmp[0] G.dy = tmp[1] G.dz = tmp[2] if G.messages: print('Spatial discretisation: {:g} x {:g} x {:g}m'.format(G.dx, G.dy, G.dz)) # Domain cmd = '#domain' tmp = [float(x) for x in singlecmds[cmd].split()] if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.nx = round_value(tmp[0] / G.dx) G.ny = round_value(tmp[1] / G.dy) G.nz = round_value(tmp[2] / G.dz) if G.nx == 0 or G.ny == 0 or G.nz == 0: raise CmdInputError(cmd + ' requires at least one cell in every dimension') if G.messages: print('Domain size: {:g} x {:g} x {:g}m ({:d} x {:d} x {:d} = {:g} cells)'.format(tmp[0], tmp[1], tmp[2], G.nx, G.ny, G.nz, (G.nx * G.ny * G.nz))) # Time step CFL limit (either 2D or 3D); switch off appropriate PMLs for 2D if G.nx == 1: G.dt = 1 / (c * np.sqrt((1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz))) G.mode = '2D TMx' G.pmlthickness['x0'] = 0 G.pmlthickness['xmax'] = 0 elif G.ny == 1: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dz) * (1 / G.dz))) G.mode = '2D TMy' G.pmlthickness['y0'] = 0 G.pmlthickness['ymax'] = 0 elif G.nz == 1: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy))) G.mode = '2D TMz' G.pmlthickness['z0'] = 0 G.pmlthickness['zmax'] = 0 else: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz))) G.mode = '3D' # Round down time step to nearest float with precision one less than hardware maximum. # Avoids inadvertently exceeding the CFL due to binary representation of floating point number. G.dt = round_value(G.dt, decimalplaces=d.getcontext().prec - 1) if G.messages: print('Mode: {}'.format(G.mode)) print('Time step (at CFL limit): {:g} secs'.format(G.dt)) # Time step stability factor cmd = '#time_step_stability_factor' if singlecmds[cmd] is not None: tmp = tuple(float(x) for x in singlecmds[cmd].split()) if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') if tmp[0] <= 0 or tmp[0] > 1: raise CmdInputError(cmd + ' requires the value of the time step stability factor to be between zero and one') G.dt = G.dt * tmp[0] if G.messages: print('Time step (modified): {:g} secs'.format(G.dt)) # Time window cmd = '#time_window' tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter to specify the time window. Either in seconds or number of iterations.') tmp = tmp[0].lower() # If number of iterations given # The +/- 1 used in calculating the number of iterations is to account for # the fact that the solver (iterations) loop runs from 0 to < G.iterations try: tmp = int(tmp) G.timewindow = (tmp - 1) * G.dt G.iterations = tmp # If real floating point value given except ValueError: tmp = float(tmp) if tmp > 0: G.timewindow = tmp G.iterations = int(np.ceil(tmp / G.dt)) + 1 else: raise CmdInputError(cmd + ' must have a value greater than zero') if G.messages: print('Time window: {:g} secs ({} iterations)'.format(G.timewindow, G.iterations)) # PML cells cmd = '#pml_cells' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 1 and len(tmp) != 6: raise CmdInputError(cmd + ' requires either one or six parameter(s)') if len(tmp) == 1: for key in G.pmlthickness.keys(): G.pmlthickness[key] = int(tmp[0]) else: G.pmlthickness['x0'] = int(tmp[0]) G.pmlthickness['y0'] = int(tmp[1]) G.pmlthickness['z0'] = int(tmp[2]) G.pmlthickness['xmax'] = int(tmp[3]) G.pmlthickness['ymax'] = int(tmp[4]) G.pmlthickness['zmax'] = int(tmp[5]) if 2 * G.pmlthickness['x0'] >= G.nx or 2 * G.pmlthickness['y0'] >= G.ny or 2 * G.pmlthickness['z0'] >= G.nz or 2 * G.pmlthickness['xmax'] >= G.nx or 2 * G.pmlthickness['ymax'] >= G.ny or 2 * G.pmlthickness['zmax'] >= G.nz: raise CmdInputError(cmd + ' has too many cells for the domain size') # PML formulation cmd = '#pml_formulation' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') if singlecmds[cmd].upper() in PML.formulations: G.pmlformulation = singlecmds[cmd].upper() else: raise CmdInputError(cmd + ' PML formulation is not found') # src_steps cmd = '#src_steps' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.srcsteps[0] = round_value(float(tmp[0]) / G.dx) G.srcsteps[1] = round_value(float(tmp[1]) / G.dy) G.srcsteps[2] = round_value(float(tmp[2]) / G.dz) if G.messages: print('Simple sources will step {:g}m, {:g}m, {:g}m for each model run.'.format(G.srcsteps[0] * G.dx, G.srcsteps[1] * G.dy, G.srcsteps[2] * G.dz)) # rx_steps cmd = '#rx_steps' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.rxsteps[0] = round_value(float(tmp[0]) / G.dx) G.rxsteps[1] = round_value(float(tmp[1]) / G.dy) G.rxsteps[2] = round_value(float(tmp[2]) / G.dz) if G.messages: print('All receivers will step {:g}m, {:g}m, {:g}m for each model run.'.format(G.rxsteps[0] * G.dx, G.rxsteps[1] * G.dy, G.rxsteps[2] * G.dz)) # Excitation file for user-defined source waveforms cmd = '#excitation_file' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 1 and len(tmp) != 3: raise CmdInputError(cmd + ' requires either one or three parameter(s)') excitationfile = tmp[0] # Optional parameters passed directly to scipy.interpolate.interp1d kwargs = dict() if len(tmp) > 1: kwargs['kind'] = tmp[1] kwargs['fill_value'] = tmp[2] else: args, varargs, keywords, defaults = inspect.getargspec(interpolate.interp1d) kwargs = dict(zip(reversed(args), reversed(defaults))) # See if file exists at specified path and if not try input file directory if not os.path.isfile(excitationfile): excitationfile = os.path.abspath(os.path.join(G.inputdirectory, excitationfile)) if G.messages: print('\nExcitation file: {}'.format(excitationfile)) # Get waveform names with open(excitationfile, 'r') as f: waveformIDs = f.readline().split() # Read all waveform values into an array waveformvalues = np.loadtxt(excitationfile, skiprows=1, dtype=floattype) # Time array (if specified) for interpolation, otherwise use simulation time if waveformIDs[0].lower() == 'time': waveformIDs = waveformIDs[1:] waveformtime = waveformvalues[:, 0] waveformvalues = waveformvalues[:, 1:] timestr = 'user-defined time array' else: waveformtime = np.arange(0, G.timewindow + G.dt, G.dt) timestr = 'simulation time array' for waveform in range(len(waveformIDs)): if any(x.ID == waveformIDs[waveform] for x in G.waveforms): raise CmdInputError('Waveform with ID {} already exists'.format(waveformIDs[waveform])) w = Waveform() w.ID = waveformIDs[waveform] w.type = 'user' # Select correct column of waveform values depending on array shape singlewaveformvalues = waveformvalues[:] if len(waveformvalues.shape) == 1 else waveformvalues[:, waveform] # Truncate waveform array if it is longer than time array if len(singlewaveformvalues) > len(waveformtime): singlewaveformvalues = singlewaveformvalues[:len(waveformtime)] # Zero-pad end of waveform array if it is shorter than time array elif len(singlewaveformvalues) < len(waveformtime): tmp = np.zeros(len(waveformtime)) tmp[:len(singlewaveformvalues)] = singlewaveformvalues singlewaveformvalues = tmp # Interpolate waveform values w.userfunc = interpolate.interp1d(waveformtime, singlewaveformvalues, **kwargs) if G.messages: print('User waveform {} created using {} and, if required, interpolation parameters (kind: {}, fill value: {}).'.format(w.ID, timestr, kwargs['kind'], kwargs['fill_value'])) G.waveforms.append(w) # Set the output directory cmd = '#output_dir' if singlecmds[cmd] is not None: outputdir = singlecmds[cmd] G.outputdirectory = outputdir
import argparse import os import sys import h5py import numpy as np import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec from gprMax.exceptions import CmdInputError from gprMax.receivers import Rx from gprMax.utilities import fft_power f = h5py.File(filename, 'r') nrx = f.attrs['nrx'] dt = f.attrs['dt'] iterations = f.attrs['Iterations'] time = np.linspace(0, (iterations - 1) * dt, num=iterations) # Check there are any receivers if nrx == 0: raise CmdInputError('No receivers found in {}'.format(filename)) for rx in range(1, nrx + 1): path = '/rxs/rx' + str(rx) + '/' availableoutputs = list(f[path].keys()) f.close() return plt
default=False, help='plot FFT (single output must be specified)') args = parser.parse_args() # Open output file and read some attributes file = args.outputfile f = h5py.File(file, 'r') nrx = f.attrs['nrx'] dt = f.attrs['dt'] iterations = f.attrs['Iterations'] time = np.linspace(0, 1, iterations) time *= (iterations * dt) # Check there are any receivers if nrx == 0: raise CmdInputError('No receivers found in {}'.format(file)) # Check for single output component when doing a FFT if args.fft: if not len(args.outputs) == 1: raise CmdInputError( 'A single output must be specified when using the -fft option') # New plot for each receiver for rx in range(1, nrx + 1): path = '/rxs/rx' + str(rx) + '/' availableoutputs = list(f[path].keys()) # If only a single output is required, create one subplot if len(args.outputs) == 1:
def antenna_like_GSSI_1500(x, y, z, resolution=0.001, rotate90=False, **kwargs): """Inserts a description of an antenna similar to the GSSI 1.5GHz antenna. Can be used with 1mm (default) or 2mm spatial resolution. The external dimensions of the antenna are 170x108x45mm. One output point is defined between the arms of the receiever bowtie. The bowties are aligned with the y axis so the output is the y component of the electric field. Args: x, y, z (float): Coordinates of a location in the model to insert the antenna. Coordinates are relative to the geometric 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. rotate90 (bool): Rotate model 90 degrees CCW in xy plane. kwargs (dict): Optional variables, e.g. can be fed from an optimisation process. """ # Antenna geometry properties casesize = (0.170, 0.108, 0.043) casethickness = 0.002 shieldthickness = 0.002 foamsurroundthickness = 0.003 pcbthickness = 0.002 skidthickness = 0.004 bowtiebase = 0.022 bowtieheight = 0.014 patchheight = 0.015 # Set origin for rotation to geometric centre of antenna in x-y plane if required if rotate90: rotate90origin = (x, y) output = 'Ex' else: rotate90origin = () output = 'Ey' # Unknown properties if kwargs: excitationfreq = kwargs['excitationfreq'] sourceresistance = kwargs['sourceresistance'] absorberEr = kwargs['absorberEr'] absorbersig = kwargs['absorbersig'] rxres = 50 else: # excitationfreq = 1.5e9 # GHz # sourceresistance = 50 # Ohms # absorberEr = 1.7 # absorbersig = 0.59 # Values from http://hdl.handle.net/1842/4074 excitationfreq = 1.71e9 # sourceresistance = 4 sourceresistance = 230 # Correction for old (< 123) GprMax3D bug absorberEr = 1.58 absorbersig = 0.428 rxres = 925 # Resistance at Rx bowtie x = x - (casesize[0] / 2) y = y - (casesize[1] / 2) # Coordinates of source excitation point in antenna tx = x + 0.114, y + 0.053, z + skidthickness if resolution == 0.001: dx = 0.001 dy = 0.001 dz = 0.001 elif resolution == 0.002: dx = 0.002 dy = 0.002 dz = 0.002 foamsurroundthickness = 0.002 patchheight = 0.016 tx = x + 0.112, y + 0.052, z + skidthickness else: raise CmdInputError( 'This antenna module can only be used with a spatial discretisation of 1mm or 2mm' ) # Material definitions material(absorberEr, absorbersig, 1, 0, 'absorber') material(3, 0, 1, 0, 'pcb') material(2.35, 0, 1, 0, 'hdpe') material(3, (1 / rxres) * (dy / (dx * dz)), 1, 0, 'rxres') # Antenna geometry # Plastic case box(x, y, z + skidthickness, x + casesize[0], y + casesize[1], z + skidthickness + casesize[2], 'hdpe', rotate90origin=rotate90origin) box(x + casethickness, y + casethickness, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + casesize[2] - casethickness, 'free_space', rotate90origin=rotate90origin) # Metallic enclosure box(x + 0.025, y + casethickness, z + skidthickness, x + casesize[0] - 0.025, y + casesize[1] - casethickness, z + skidthickness + 0.027, 'pec', rotate90origin=rotate90origin) # Absorber material, and foam (modelled as PCB material) around edge of absorber box(x + 0.025 + shieldthickness, y + casethickness + shieldthickness, z + skidthickness, x + 0.025 + shieldthickness + 0.057, y + casesize[1] - casethickness - shieldthickness, z + skidthickness + 0.027 - shieldthickness - 0.001, 'pcb', rotate90origin=rotate90origin) box(x + 0.025 + shieldthickness + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.025 + shieldthickness + 0.057 - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + 0.027 - shieldthickness, 'absorber', rotate90origin=rotate90origin) box(x + 0.086, y + casethickness + shieldthickness, z + skidthickness, x + 0.086 + 0.057, y + casesize[1] - casethickness - shieldthickness, z + skidthickness + 0.027 - shieldthickness - 0.001, 'pcb', rotate90origin=rotate90origin) box(x + 0.086 + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.086 + 0.057 - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + 0.027 - shieldthickness, 'absorber', rotate90origin=rotate90origin) # PCB box(x + 0.025 + shieldthickness + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.086 - shieldthickness - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) box(x + 0.086 + foamsurroundthickness, y + casethickness + shieldthickness + foamsurroundthickness, z + skidthickness, x + 0.086 + 0.057 - foamsurroundthickness, y + casesize[1] - casethickness - shieldthickness - foamsurroundthickness, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) # PCB components if resolution == 0.001: # Rx & Tx bowties a = 0 b = 0 while b < 13: plate(x + 0.045 + a * dx, y + 0.039 + b * dx, z + skidthickness, x + 0.065 - a * dx, y + 0.039 + b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.045 + a * dx, y + 0.067 - b * dx, z + skidthickness, x + 0.065 - a * dx, y + 0.067 - b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.104 + a * dx, y + 0.039 + b * dx, z + skidthickness, x + 0.124 - a * dx, y + 0.039 + b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.104 + a * dx, y + 0.067 - b * dx, z + skidthickness, x + 0.124 - a * dx, y + 0.067 - b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) b += 1 if a == 2 or a == 4 or a == 7: plate(x + 0.045 + a * dx, y + 0.039 + b * dx, z + skidthickness, x + 0.065 - a * dx, y + 0.039 + b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.045 + a * dx, y + 0.067 - b * dx, z + skidthickness, x + 0.065 - a * dx, y + 0.067 - b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.104 + a * dx, y + 0.039 + b * dx, z + skidthickness, x + 0.124 - a * dx, y + 0.039 + b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.104 + a * dx, y + 0.067 - b * dx, z + skidthickness, x + 0.124 - a * dx, y + 0.067 - b * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) b += 1 a += 1 # Rx extension section (upper y) plate(x + 0.044, y + 0.068, z + skidthickness, x + 0.044 + bowtiebase, y + 0.068 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Tx extension section (upper y) plate(x + 0.103, y + 0.068, z + skidthickness, x + 0.103 + bowtiebase, y + 0.068 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Edges that represent wire between bowtie halves in 1mm model edge(tx[0] - 0.059, tx[1] - dy, tx[2], tx[0] - 0.059, tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0] - 0.059, tx[1] + dy, tx[2], tx[0] - 0.059, tx[1] + 0.002, tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] - dy, tx[2], tx[0], tx[1], tx[2], 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] + dz, tx[2], tx[0], tx[1] + 0.002, tx[2], 'pec', rotate90origin=rotate90origin) elif resolution == 0.002: # Rx & Tx bowties for a in range(0, 6): plate(x + 0.044 + a * dx, y + 0.040 + a * dx, z + skidthickness, x + 0.066 - a * dx, y + 0.040 + a * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.044 + a * dx, y + 0.064 - a * dx, z + skidthickness, x + 0.066 - a * dx, y + 0.064 - a * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.103 + a * dx, y + 0.040 + a * dx, z + skidthickness, x + 0.125 - a * dx, y + 0.040 + a * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) plate(x + 0.103 + a * dx, y + 0.064 - a * dx, z + skidthickness, x + 0.125 - a * dx, y + 0.064 - a * dx + dy, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Rx extension section (upper y) plate(x + 0.044, y + 0.066, z + skidthickness, x + 0.044 + bowtiebase, y + 0.066 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Tx extension section (upper y) plate(x + 0.103, y + 0.066, z + skidthickness, x + 0.103 + bowtiebase, y + 0.066 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Rx extension section (lower y) plate(x + 0.044, y + 0.024, z + skidthickness, x + 0.044 + bowtiebase, y + 0.024 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Tx extension section (lower y) plate(x + 0.103, y + 0.024, z + skidthickness, x + 0.103 + bowtiebase, y + 0.024 + patchheight, z + skidthickness, 'pec', rotate90origin=rotate90origin) # Skid box(x, y, z, x + casesize[0], y + casesize[1], z + skidthickness, 'hdpe', rotate90origin=rotate90origin) # Geometry views # geometry_view(x - dx, y - dy, z - dz, x + casesize[0] + dx, y + casesize[1] + dy, z + skidthickness + casesize[2] + dz, dx, dy, dz, 'antenna_like_GSSI_1500') # geometry_view(x, y, z, x + casesize[0], y + casesize[1], z + 0.010, dx, dy, dz, 'antenna_like_GSSI_1500_pcb', type='f') # Excitation - custom pulse # print('#excitation_file: {}'.format(os.path.join(moduledirectory, 'GSSIgausspulse1.txt'))) # print('#transmission_line: y {} {} {} {} GSSIgausspulse1'.format(tx[0], tx[1], tx[2], sourceresistance)) # Excitation - Gaussian pulse print('#waveform: gaussian 1 {} myGaussian'.format(excitationfreq)) transmission_line('y', tx[0], tx[1], tx[2], sourceresistance, 'myGaussian', dxdy=(resolution, resolution), rotate90origin=rotate90origin) # Output point - receiver bowtie if resolution == 0.001: edge(tx[0] - 0.059, tx[1], tx[2], tx[0] - 0.059, tx[1] + dy, tx[2], 'rxres', rotate90origin=rotate90origin) rx(tx[0] - 0.059, tx[1], tx[2], identifier='rxbowtie', to_save=[output], polarisation='y', dxdy=(resolution, resolution), rotate90origin=rotate90origin) elif resolution == 0.002: edge(tx[0] - 0.058, tx[1], tx[2], tx[0] - 0.058, tx[1] + dy, tx[2], 'rxres', rotate90origin=rotate90origin) rx(tx[0] - 0.058, tx[1], tx[2], identifier='rxbowtie', to_save=[output], polarisation='y', dxdy=(resolution, resolution), rotate90origin=rotate90origin)
def process_singlecmds(singlecmds, G): """Checks the validity of command parameters and creates instances of classes of parameters. Args: singlecmds (dict): Commands that can only occur once in the model. G (class): Grid class instance - holds essential parameters describing the model. """ # Check validity of command parameters in order needed # messages cmd = '#messages' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') if singlecmds[cmd].lower() == 'y': G.messages = True elif singlecmds[cmd].lower() == 'n': G.messages = False else: raise CmdInputError(cmd + ' requires input values of either y or n') # Title cmd = '#title' if singlecmds[cmd] is not None: G.title = singlecmds[cmd] if G.messages: print('Model title: {}'.format(G.title)) # Get information about host machine hostinfo = get_host_info() # Number of threads (OpenMP) to use cmd = '#num_threads' if sys.platform == 'darwin': os.environ[ 'OMP_WAIT_POLICY'] = 'ACTIVE' # Should waiting threads consume CPU power (can drastically effect performance) os.environ[ 'OMP_DYNAMIC'] = 'FALSE' # Number of threads may be adjusted by the run time environment to best utilize system resources os.environ[ 'OMP_PLACES'] = 'cores' # Each place corresponds to a single core (having one or more hardware threads) os.environ['OMP_PROC_BIND'] = 'TRUE' # Bind threads to physical cores # os.environ['OMP_DISPLAY_ENV'] = 'TRUE' # Prints OMP version and environment variables (useful for debug) # Catch bug with Windows Subsystem for Linux (https://github.com/Microsoft/BashOnWindows/issues/785) if 'Microsoft' in hostinfo['osversion']: os.environ['KMP_AFFINITY'] = 'disabled' del os.environ['OMP_PLACES'] del os.environ['OMP_PROC_BIND'] if singlecmds[cmd] is not None: tmp = tuple(int(x) for x in singlecmds[cmd].split()) if len(tmp) != 1: raise CmdInputError( cmd + ' requires exactly one parameter to specify the number of threads to use' ) if tmp[0] < 1: raise CmdInputError( cmd + ' requires the value to be an integer not less than one') G.nthreads = tmp[0] os.environ['OMP_NUM_THREADS'] = str(G.nthreads) elif os.environ.get('OMP_NUM_THREADS'): G.nthreads = int(os.environ.get('OMP_NUM_THREADS')) else: # Set number of threads to number of physical CPU cores G.nthreads = hostinfo['physicalcores'] os.environ['OMP_NUM_THREADS'] = str(G.nthreads) if G.messages: print('Number of CPU (OpenMP) threads: {}'.format(G.nthreads)) if G.nthreads > hostinfo['physicalcores']: print( Fore.RED + 'WARNING: You have specified more threads ({}) than available physical CPU cores ({}). This may lead to degraded performance.' .format(G.nthreads, hostinfo['physicalcores']) + Style.RESET_ALL) # Spatial discretisation cmd = '#dx_dy_dz' tmp = [float(x) for x in singlecmds[cmd].split()] if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') if tmp[0] <= 0: raise CmdInputError( cmd + ' requires the x-direction spatial step to be greater than zero') if tmp[1] <= 0: raise CmdInputError( cmd + ' requires the y-direction spatial step to be greater than zero') if tmp[2] <= 0: raise CmdInputError( cmd + ' requires the z-direction spatial step to be greater than zero') G.dx = tmp[0] G.dy = tmp[1] G.dz = tmp[2] if G.messages: print('Spatial discretisation: {:g} x {:g} x {:g}m'.format( G.dx, G.dy, G.dz)) # Domain cmd = '#domain' tmp = [float(x) for x in singlecmds[cmd].split()] if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.nx = round_value(tmp[0] / G.dx) G.ny = round_value(tmp[1] / G.dy) G.nz = round_value(tmp[2] / G.dz) if G.nx == 0 or G.ny == 0 or G.nz == 0: raise CmdInputError(cmd + ' requires at least one cell in every dimension') if G.messages: print( 'Domain size: {:g} x {:g} x {:g}m ({:d} x {:d} x {:d} = {:g} cells)' .format(tmp[0], tmp[1], tmp[2], G.nx, G.ny, G.nz, (G.nx * G.ny * G.nz))) # Estimate memory (RAM) usage memestimate = memory_usage(G) # Check if model can be built and/or run on host if memestimate > hostinfo['ram']: raise GeneralError( 'Estimated memory (RAM) required ~{} exceeds {} detected!\n'. format(human_size(memestimate), human_size(hostinfo['ram'], a_kilobyte_is_1024_bytes=True))) if G.messages: print('Estimated memory (RAM) required: ~{}'.format( human_size(memestimate))) # Time step CFL limit (use either 2D or 3D) and default PML thickness if G.nx == 1: G.dt = 1 / (c * np.sqrt((1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz))) G.dimension = '2D' G.pmlthickness['x0'] = 0 G.pmlthickness['xmax'] = 0 elif G.ny == 1: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dz) * (1 / G.dz))) G.dimension = '2D' G.pmlthickness['y0'] = 0 G.pmlthickness['ymax'] = 0 elif G.nz == 1: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy))) G.dimension = '2D' G.pmlthickness['z0'] = 0 G.pmlthickness['zmax'] = 0 else: G.dt = 1 / (c * np.sqrt((1 / G.dx) * (1 / G.dx) + (1 / G.dy) * (1 / G.dy) + (1 / G.dz) * (1 / G.dz))) G.dimension = '3D' # Round down time step to nearest float with precision one less than hardware maximum. Avoids inadvertently exceeding the CFL due to binary representation of floating point number. G.dt = round_value(G.dt, decimalplaces=d.getcontext().prec - 1) if G.messages: print('Time step (at {} CFL limit): {:g} secs'.format( G.dimension, G.dt)) # Time step stability factor cmd = '#time_step_stability_factor' if singlecmds[cmd] is not None: tmp = tuple(float(x) for x in singlecmds[cmd].split()) if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') if tmp[0] <= 0 or tmp[0] > 1: raise CmdInputError( cmd + ' requires the value of the time step stability factor to be between zero and one' ) G.dt = G.dt * tmp[0] if G.messages: print('Time step (modified): {:g} secs'.format(G.dt)) # Time window cmd = '#time_window' tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError( cmd + ' requires exactly one parameter to specify the time window. Either in seconds or number of iterations.' ) tmp = tmp[0].lower() # If number of iterations given try: tmp = int(tmp) G.timewindow = (tmp - 1) * G.dt G.iterations = tmp # If real floating point value given except: tmp = float(tmp) if tmp > 0: G.timewindow = tmp G.iterations = round_value((tmp / G.dt)) + 1 else: raise CmdInputError(cmd + ' must have a value greater than zero') if G.messages: print('Time window: {:g} secs ({} iterations)'.format( G.timewindow, G.iterations)) # PML cmd = '#pml_cells' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 1 and len(tmp) != 6: raise CmdInputError(cmd + ' requires either one or six parameters') if len(tmp) == 1: for key in G.pmlthickness.keys(): G.pmlthickness[key] = int(tmp[0]) else: G.pmlthickness['x0'] = int(tmp[0]) G.pmlthickness['y0'] = int(tmp[1]) G.pmlthickness['z0'] = int(tmp[2]) G.pmlthickness['xmax'] = int(tmp[3]) G.pmlthickness['ymax'] = int(tmp[4]) G.pmlthickness['zmax'] = int(tmp[5]) if 2 * G.pmlthickness['x0'] >= G.nx or 2 * G.pmlthickness[ 'y0'] >= G.ny or 2 * G.pmlthickness[ 'z0'] >= G.nz or 2 * G.pmlthickness[ 'xmax'] >= G.nx or 2 * G.pmlthickness[ 'ymax'] >= G.ny or 2 * G.pmlthickness['zmax'] >= G.nz: raise CmdInputError(cmd + ' has too many cells for the domain size') # src_steps cmd = '#src_steps' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.srcsteps[0] = round_value(float(tmp[0]) / G.dx) G.srcsteps[1] = round_value(float(tmp[1]) / G.dy) G.srcsteps[2] = round_value(float(tmp[2]) / G.dz) if G.messages: print( 'Simple sources will step {:g}m, {:g}m, {:g}m for each model run.' .format(G.srcsteps[0] * G.dx, G.srcsteps[1] * G.dy, G.srcsteps[2] * G.dz)) # rx_steps cmd = '#rx_steps' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 3: raise CmdInputError(cmd + ' requires exactly three parameters') G.rxsteps[0] = round_value(float(tmp[0]) / G.dx) G.rxsteps[1] = round_value(float(tmp[1]) / G.dy) G.rxsteps[2] = round_value(float(tmp[2]) / G.dz) if G.messages: print( 'All receivers will step {:g}m, {:g}m, {:g}m for each model run.' .format(G.rxsteps[0] * G.dx, G.rxsteps[1] * G.dy, G.rxsteps[2] * G.dz)) # Excitation file for user-defined source waveforms cmd = '#excitation_file' if singlecmds[cmd] is not None: tmp = singlecmds[cmd].split() if len(tmp) != 1: raise CmdInputError(cmd + ' requires exactly one parameter') excitationfile = tmp[0] # See if file exists at specified path and if not try input file directory if not os.path.isfile(excitationfile): excitationfile = os.path.abspath( os.path.join(G.inputdirectory, excitationfile)) # Get waveform names with open(excitationfile, 'r') as f: waveformIDs = f.readline().split() # Read all waveform values into an array waveformvalues = np.loadtxt(excitationfile, skiprows=1, dtype=floattype) for waveform in range(len(waveformIDs)): if any(x.ID == waveformIDs[waveform] for x in G.waveforms): raise CmdInputError( 'Waveform with ID {} already exists'.format( waveformIDs[waveform])) w = Waveform() w.ID = waveformIDs[waveform] w.type = 'user' if len(waveformvalues.shape) == 1: w.uservalues = waveformvalues[:] else: w.uservalues = waveformvalues[:, waveform] if G.messages: print('User waveform {} created.'.format(w.ID)) G.waveforms.append(w)
def antenna_like_MALA_1200(x, y, z, resolution=0.001, rotate90=False, **kwargs): """Inserts a description of an antenna similar to the MALA 1.2GHz antenna. Can be used with 1mm (default) or 2mm spatial resolution. The external dimensions of the antenna are 184x109x46mm. One output point is defined between the arms of the receiever bowtie. The bowties are aligned with the y axis so the output is the y component of the electric field. Args: x, y, z (float): Coordinates of a location in the model to insert the antenna. Coordinates are relative to the geometric 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. rotate90 (bool): Rotate model 90 degrees CCW in xy plane. kwargs (dict): Optional variables, e.g. can be fed from an optimisation process. """ # Antenna geometry properties casesize = (0.184, 0.109, 0.040) casethickness = 0.002 cavitysize = (0.062, 0.062, 0.037) cavitythickness = 0.001 pcbthickness = 0.002 polypropylenethickness = 0.003 hdpethickness = 0.003 skidthickness = 0.006 bowtieheight = 0.025 # Set origin for rotation to geometric centre of antenna in x-y plane if required if rotate90: rotate90origin = (x, y) output = 'Ex' else: rotate90origin = () output = 'Ey' # Unknown properties if kwargs: excitationfreq = kwargs['excitationfreq'] sourceresistance = kwargs['sourceresistance'] absorberEr = kwargs['absorberEr'] absorbersig = kwargs['absorbersig'] else: # Values from http://hdl.handle.net/1842/4074 excitationfreq = 0.978e9 sourceresistance = 1000 absorberEr = 6.49 absorbersig = 0.252 x = x - (casesize[0] / 2) y = y - (casesize[1] / 2) # Coordinates of source excitation point in antenna tx = x + 0.063, y + 0.052, z + skidthickness if resolution == 0.001: dx = 0.001 dy = 0.001 dz = 0.001 elif resolution == 0.002: dx = 0.002 dy = 0.002 dz = 0.002 cavitysize = (0.062, 0.062, 0.036) cavitythickness = 0.002 polypropylenethickness = 0.002 hdpethickness = 0.004 bowtieheight = 0.024 tx = x + 0.062, y + 0.052, z + skidthickness else: raise CmdInputError( 'This antenna module can only be used with a spatial resolution of 1mm or 2mm' ) # SMD resistors - 3 on each Tx & Rx bowtie arm txres = 470 # Ohms txrescellupper = txres / 3 # Resistor over 3 cells txsigupper = ( (1 / txrescellupper) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor txrescelllower = txres / 4 # Resistor over 4 cells txsiglower = ( (1 / txrescelllower) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor rxres = 150 # Ohms rxrescellupper = rxres / 3 # Resistor over 3 cells rxsigupper = ( (1 / rxrescellupper) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor rxrescelllower = rxres / 4 # Resistor over 4 cells rxsiglower = ( (1 / rxrescelllower) * (dy / (dx * dz))) / 2 # Divide by number of parallel edges per resistor # Material definitions material(absorberEr, absorbersig, 1, 0, 'absorber') material(3, 0, 1, 0, 'pcb') material(2.35, 0, 1, 0, 'hdpe') material(2.26, 0, 1, 0, 'polypropylene') material(3, txsiglower, 1, 0, 'txreslower') material(3, txsigupper, 1, 0, 'txresupper') material(3, rxsiglower, 1, 0, 'rxreslower') material(3, rxsigupper, 1, 0, 'rxresupper') # Antenna geometry # Shield - metallic enclosure box(x, y, z + skidthickness, x + casesize[0], y + casesize[1], z + skidthickness + casesize[2], 'pec', rotate90origin=rotate90origin) box(x + 0.020, y + casethickness, z + skidthickness, x + 0.100, y + casesize[1] - casethickness, z + skidthickness + casethickness, 'free_space', rotate90origin=rotate90origin) box(x + 0.100, y + casethickness, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + casethickness, 'free_space', rotate90origin=rotate90origin) # Absorber material box(x + 0.020, y + casethickness, z + skidthickness, x + 0.100, y + casesize[1] - casethickness, z + skidthickness + casesize[2] - casethickness, 'absorber', rotate90origin=rotate90origin) box(x + 0.100, y + casethickness, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - casethickness, z + skidthickness + casesize[2] - casethickness, 'absorber', rotate90origin=rotate90origin) # Shield - cylindrical sections cylinder(x + 0.055, y + casesize[1] - 0.008, z + skidthickness, x + 0.055, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness, 0.008, 'pec', rotate90origin=rotate90origin) cylinder(x + 0.055, y + 0.008, z + skidthickness, x + 0.055, y + 0.008, z + skidthickness + casesize[2] - casethickness, 0.008, 'pec', rotate90origin=rotate90origin) cylinder(x + 0.147, y + casesize[1] - 0.008, z + skidthickness, x + 0.147, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness, 0.008, 'pec', rotate90origin=rotate90origin) cylinder(x + 0.147, y + 0.008, z + skidthickness, x + 0.147, y + 0.008, z + skidthickness + casesize[2] - casethickness, 0.008, 'pec', rotate90origin=rotate90origin) cylinder(x + 0.055, y + casesize[1] - 0.008, z + skidthickness, x + 0.055, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness, 0.007, 'free_space', rotate90origin=rotate90origin) cylinder(x + 0.055, y + 0.008, z + skidthickness, x + 0.055, y + 0.008, z + skidthickness + casesize[2] - casethickness, 0.007, 'free_space', rotate90origin=rotate90origin) cylinder(x + 0.147, y + casesize[1] - 0.008, z + skidthickness, x + 0.147, y + casesize[1] - 0.008, z + skidthickness + casesize[2] - casethickness, 0.007, 'free_space', rotate90origin=rotate90origin) cylinder(x + 0.147, y + 0.008, z + skidthickness, x + 0.147, y + 0.008, z + skidthickness + casesize[2] - casethickness, 0.007, 'free_space', rotate90origin=rotate90origin) box(x + 0.054, y + casesize[1] - 0.016, z + skidthickness, x + 0.056, y + casesize[1] - 0.014, z + skidthickness + casesize[2] - casethickness, 'free_space', rotate90origin=rotate90origin) box(x + 0.054, y + 0.014, z + skidthickness, x + 0.056, y + 0.016, z + skidthickness + casesize[2] - casethickness, 'free_space', rotate90origin=rotate90origin) box(x + 0.146, y + casesize[1] - 0.016, z + skidthickness, x + 0.148, y + casesize[1] - 0.014, z + skidthickness + casesize[2] - casethickness, 'free_space', rotate90origin=rotate90origin) box(x + 0.146, y + 0.014, z + skidthickness, x + 0.148, y + 0.016, z + skidthickness + casesize[2] - casethickness, 'free_space', rotate90origin=rotate90origin) # PCB box(x + 0.020, y + 0.018, z + skidthickness, x + casesize[0] - casethickness, y + casesize[1] - 0.018, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) # Shield - Tx & Rx cavities box(x + 0.032, y + 0.022, z + skidthickness, x + 0.032 + cavitysize[0], y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2], 'pec', rotate90origin=rotate90origin) box(x + 0.032 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness, x + 0.032 + cavitysize[0] - cavitythickness, y + 0.022 + cavitysize[1] - cavitythickness, z + skidthickness + cavitysize[2], 'absorber', rotate90origin=rotate90origin) box(x + 0.108, y + 0.022, z + skidthickness, x + 0.108 + cavitysize[0], y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2], 'pec', rotate90origin=rotate90origin) box(x + 0.108 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness, x + 0.108 + cavitysize[0] - cavitythickness, y + 0.022 + cavitysize[1] - cavitythickness, z + skidthickness + cavitysize[2], 'free_space', rotate90origin=rotate90origin) # Shield - Tx & Rx cavities - joining strips box(x + 0.032 + cavitysize[0], y + 0.022 + cavitysize[1] - 0.006, z + skidthickness + cavitysize[2] - casethickness, x + 0.108, y + 0.022 + cavitysize[1], z + skidthickness + cavitysize[2], 'pec', rotate90origin=rotate90origin) box(x + 0.032 + cavitysize[0], y + 0.022, z + skidthickness + cavitysize[2] - casethickness, x + 0.108, y + 0.022 + 0.006, z + skidthickness + cavitysize[2], 'pec', rotate90origin=rotate90origin) # PCB - replace bits chopped by TX & Rx cavities box(x + 0.032 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness, x + 0.032 + cavitysize[0] - cavitythickness, y + 0.022 + cavitysize[1] - cavitythickness, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) box(x + 0.108 + cavitythickness, y + 0.022 + cavitythickness, z + skidthickness, x + 0.108 + cavitysize[0] - cavitythickness, y + 0.022 + cavitysize[1] - cavitythickness, z + skidthickness + pcbthickness, 'pcb', rotate90origin=rotate90origin) # PCB components # Tx bowtie if resolution == 0.001: triangle(tx[0], tx[1] - 0.001, tx[2], tx[0] - 0.026, tx[1] - bowtieheight - 0.001, tx[2], tx[0] + 0.026, tx[1] - bowtieheight - 0.001, tx[2], 0, 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] - 0.001, tx[2], tx[0], tx[1], tx[2], 'pec', rotate90origin=rotate90origin) triangle(tx[0], tx[1] + 0.002, tx[2], tx[0] - 0.026, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.026, tx[1] + bowtieheight + 0.002, tx[2], 0, 'pec', rotate90origin=rotate90origin) edge(tx[0], tx[1] + 0.001, tx[2], tx[0], tx[1] + 0.002, tx[2], 'pec', rotate90origin=rotate90origin) elif resolution == 0.002: triangle(tx[0], tx[1], tx[2], tx[0] - 0.026, tx[1] - bowtieheight, tx[2], tx[0] + 0.026, tx[1] - bowtieheight, tx[2], 0, 'pec', rotate90origin=rotate90origin) triangle(tx[0], tx[1] + 0.002, tx[2], tx[0] - 0.026, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.026, tx[1] + bowtieheight + 0.002, tx[2], 0, 'pec', rotate90origin=rotate90origin) # Rx bowtie if resolution == 0.001: triangle(tx[0] + 0.076, tx[1] - 0.001, tx[2], tx[0] + 0.076 - 0.026, tx[1] - bowtieheight - 0.001, tx[2], tx[0] + 0.076 + 0.026, tx[1] - bowtieheight - 0.001, tx[2], 0, 'pec', rotate90origin=rotate90origin) edge(tx[0] + 0.076, tx[1] - 0.001, tx[2], tx[0] + 0.076, tx[1], tx[2], 'pec', rotate90origin=rotate90origin) triangle(tx[0] + 0.076, tx[1] + 0.002, tx[2], tx[0] + 0.076 - 0.026, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.076 + 0.026, tx[1] + bowtieheight + 0.002, tx[2], 0, 'pec', rotate90origin=rotate90origin) edge(tx[0] + 0.076, tx[1] + 0.001, tx[2], tx[0] + 0.076, tx[1] + 0.002, tx[2], 'pec', rotate90origin=rotate90origin) elif resolution == 0.002: triangle(tx[0] + 0.076, tx[1], tx[2], tx[0] + 0.076 - 0.026, tx[1] - bowtieheight, tx[2], tx[0] + 0.076 + 0.026, tx[1] - bowtieheight, tx[2], 0, 'pec', rotate90origin=rotate90origin) triangle(tx[0] + 0.076, tx[1] + 0.002, tx[2], tx[0] + 0.076 - 0.026, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.076 + 0.026, tx[1] + bowtieheight + 0.002, tx[2], 0, 'pec', rotate90origin=rotate90origin) # Tx surface mount resistors (lower y coordinate) if resolution == 0.001: edge(tx[0] - 0.023, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023, tx[1] - bowtieheight - dy, tx[2], 'txreslower', rotate90origin=rotate90origin) edge(tx[0] - 0.023 + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + dx, tx[1] - bowtieheight - dy, tx[2], 'txreslower', rotate90origin=rotate90origin) edge(tx[0], tx[1] - bowtieheight - 0.004, tx[2], tx[0], tx[1] - bowtieheight - dy, tx[2], 'txreslower', rotate90origin=rotate90origin) edge(tx[0] + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + dx, tx[1] - bowtieheight - dy, tx[2], 'txreslower', rotate90origin=rotate90origin) edge(tx[0] + 0.022, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.022, tx[1] - bowtieheight - dy, tx[2], 'txreslower', rotate90origin=rotate90origin) edge(tx[0] + 0.022 + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.022 + dx, tx[1] - bowtieheight - dy, tx[2], 'txreslower', rotate90origin=rotate90origin) elif resolution == 0.002: edge(tx[0] - 0.023, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023, tx[1] - bowtieheight, tx[2], 'txreslower', rotate90origin=rotate90origin) edge(tx[0] - 0.023 + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + dx, tx[1] - bowtieheight, tx[2], 'txreslower', rotate90origin=rotate90origin) edge(tx[0], tx[1] - bowtieheight - 0.004, tx[2], tx[0], tx[1] - bowtieheight, tx[2], 'txreslower', rotate90origin=rotate90origin) edge(tx[0] + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + dx, tx[1] - bowtieheight, tx[2], 'txreslower', rotate90origin=rotate90origin) edge(tx[0] + 0.020, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.020, tx[1] - bowtieheight, tx[2], 'txreslower', rotate90origin=rotate90origin) edge(tx[0] + 0.020 + dx, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.020 + dx, tx[1] - bowtieheight, tx[2], 'txreslower', rotate90origin=rotate90origin) # Tx surface mount resistors (upper y coordinate) if resolution == 0.001: edge(tx[0] - 0.023, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023, tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) edge(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) edge(tx[0], tx[1] + bowtieheight + 0.002, tx[2], tx[0], tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) edge(tx[0] + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + dx, tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) edge(tx[0] + 0.022, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.022, tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) edge(tx[0] + 0.022 + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.022 + dx, tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) elif resolution == 0.002: edge(tx[0] - 0.023, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023, tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) edge(tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + dx, tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) edge(tx[0], tx[1] + bowtieheight + 0.002, tx[2], tx[0], tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) edge(tx[0] + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + dx, tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) edge(tx[0] + 0.020, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.020, tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) edge(tx[0] + 0.020 + dx, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.020 + dx, tx[1] + bowtieheight + 0.006, tx[2], 'txresupper', rotate90origin=rotate90origin) # Rx surface mount resistors (lower y coordinate) if resolution == 0.001: edge(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - dy, tx[2], 'rxreslower', rotate90origin=rotate90origin) edge(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - dy, tx[2], 'rxreslower', rotate90origin=rotate90origin) edge(tx[0] + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.076, tx[1] - bowtieheight - dy, tx[2], 'rxreslower', rotate90origin=rotate90origin) edge(tx[0] + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + dx + 0.076, tx[1] - bowtieheight - dy, tx[2], 'rxreslower', rotate90origin=rotate90origin) edge(tx[0] + 0.022 + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.022 + 0.076, tx[1] - bowtieheight - dy, tx[2], 'rxreslower', rotate90origin=rotate90origin) edge(tx[0] + 0.022 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.022 + dx + 0.076, tx[1] - bowtieheight - dy, tx[2], 'rxreslower', rotate90origin=rotate90origin) elif resolution == 0.002: edge(tx[0] - 0.023 + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + 0.076, tx[1] - bowtieheight, tx[2], 'rxreslower', rotate90origin=rotate90origin) edge(tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] - 0.023 + dx + 0.076, tx[1] - bowtieheight, tx[2], 'rxreslower', rotate90origin=rotate90origin) edge(tx[0] + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.076, tx[1] - bowtieheight, tx[2], 'rxreslower', rotate90origin=rotate90origin) edge(tx[0] + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + dx + 0.076, tx[1] - bowtieheight, tx[2], 'rxreslower', rotate90origin=rotate90origin) edge(tx[0] + 0.020 + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.020 + 0.076, tx[1] - bowtieheight, tx[2], 'rxreslower', rotate90origin=rotate90origin) edge(tx[0] + 0.020 + dx + 0.076, tx[1] - bowtieheight - 0.004, tx[2], tx[0] + 0.020 + dx + 0.076, tx[1] - bowtieheight, tx[2], 'rxreslower', rotate90origin=rotate90origin) # Rx surface mount resistors (upper y coordinate) if resolution == 0.001: edge(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) edge(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) edge(tx[0] + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) edge(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) edge(tx[0] + 0.022 + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.022 + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) edge(tx[0] + 0.022 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.022 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) elif resolution == 0.002: edge(tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) edge(tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] - 0.023 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) edge(tx[0] + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) edge(tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) edge(tx[0] + 0.020 + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.020 + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) edge(tx[0] + 0.020 + dx + 0.076, tx[1] + bowtieheight + 0.002, tx[2], tx[0] + 0.020 + dx + 0.076, tx[1] + bowtieheight + 0.006, tx[2], 'rxresupper', rotate90origin=rotate90origin) # Skid box(x, y, z, x + casesize[0], y + casesize[1], z + polypropylenethickness, 'polypropylene', rotate90origin=rotate90origin) box(x, y, z + polypropylenethickness, x + casesize[0], y + casesize[1], z + polypropylenethickness + hdpethickness, 'hdpe', rotate90origin=rotate90origin) # Geometry views # geometry_view(x - dx, y - dy, z - dz, x + casesize[0] + dx, y + casesize[1] + dy, z + casesize[2] + skidthickness + dz, dx, dy, dz, 'antenna_like_MALA_1200') # geometry_view(x, y, z, x + casesize[0], y + casesize[1], z + 0.010, dx, dy, dz, 'antenna_like_MALA_1200_pcb', type='f') # Excitation print('#waveform: gaussian 1.0 {} myGaussian'.format(excitationfreq)) voltage_source('y', tx[0], tx[1], tx[2], sourceresistance, 'myGaussian', dxdy=(resolution, resolution), rotate90origin=rotate90origin) # Output point - receiver bowtie rx(tx[0] + 0.076, tx[1], tx[2], identifier='rxbowtie', to_save=[output], polarisation='y', dxdy=(resolution, resolution), rotate90origin=rotate90origin)
# Model results f = h5py.File(args.modelfile, 'r') path = '/rxs/rx1/' availablecomponents = list(f[path].keys()) # Check for polarity of output and if requested output is in file if args.output[0][0] == 'm': polarity = -1 args.outputs[0] = args.output[0][1:] else: polarity = 1 if args.output[0] not in availablecomponents: raise CmdInputError( '{} output requested to plot, but the available output for receiver 1 is {}' .format(args.output[0], ', '.join(availablecomponents))) floattype = f[path + args.output[0]].dtype iterations = f.attrs['Iterations'] dt = f.attrs['dt'] model = np.zeros(iterations, dtype=floattype) model = f[path + args.output[0]][:] * polarity model /= np.amax(np.abs(model)) timemodel = np.linspace(0, 1, iterations) timemodel *= (iterations * dt) f.close() # Find location of maximum value from model modelmax = np.where(np.abs(model) == 1)[0][0]
def python_code_blocks(inputfile, usernamespace): """Looks for and processes any Python code found in the input file. It will ignore any lines that are comments, i.e. begin with a double hash (##), and any blank lines. It will also ignore any lines that do not begin with a hash (#) after it has processed Python commands. Args: inputfile (str): Name of the input file to open. usernamespace (dict): Namespace that can be accessed by user in any Python code blocks in input file. Returns: processedlines (list): Input commands after Python processing. """ with open(inputfile, 'r') as f: # Strip out any newline characters and comments that must begin with double hashes inputlines = [ line.rstrip() for line in f if (not line.startswith('##') and line.rstrip('\n')) ] # List to hold final processed commands processedlines = [] x = 0 while (x < len(inputlines)): if (inputlines[x].startswith('#python:')): # String to hold Python code to be executed pythoncode = '' x += 1 while not inputlines[x].startswith('#end_python:'): # Add all code in current code block to string pythoncode += inputlines[x] + '\n' x += 1 if x == len(inputlines): raise CmdInputError( 'Cannot find the end of the Python code block, i.e. missing #end_python: command.' ) # Compile code for faster execution pythoncompiledcode = compile(pythoncode, '<string>', 'exec') # Redirect stdio to a ListStream sys.stdout = codeout = ListStream() # Execute code block & make available only usernamespace exec(pythoncompiledcode, usernamespace) # Now strip out any lines that don't begin with a hash command codeproc = [ line + ('\n') for line in codeout.data if (line.startswith('#')) ] # Add processed Python code to list processedlines.extend(codeproc) elif (inputlines[x].startswith('#')): # Add gprMax command to list inputlines[x] += ('\n') processedlines.append(inputlines[x]) x += 1 sys.stdout = sys.__stdout__ # Reset stdio return processedlines