From e9416e34c87ee90e0d6a537e7ba255d0647de892 Mon Sep 17 00:00:00 2001 From: Sai-Suraj-27 Date: Fri, 23 Jun 2023 18:42:17 +0530 Subject: [PATCH 1/4] Refactored some code to make it cleaner/better. --- gprMax/cmds_multiuse.py | 4 ++-- gprMax/config.py | 2 +- gprMax/contexts.py | 3 +-- gprMax/gprMax.py | 3 +-- gprMax/grid.py | 2 +- gprMax/hash_cmds_file.py | 11 +++++------ gprMax/updates.py | 5 ++--- 7 files changed, 13 insertions(+), 17 deletions(-) diff --git a/gprMax/cmds_multiuse.py b/gprMax/cmds_multiuse.py index 9fb768cc..c6dfa146 100644 --- a/gprMax/cmds_multiuse.py +++ b/gprMax/cmds_multiuse.py @@ -390,7 +390,7 @@ class HertzianDipole(UserObjectMulti): # Check if there is a waveformID in the waveforms list - if not any(x.ID == waveform_id for x in grid.waveforms): + if all(x.ID == waveform_id for x in grid.waveforms): logger.exception(f'{self.params_str()} there is no waveform ' + f'with the identifier {waveform_id}.') raise ValueError @@ -526,7 +526,7 @@ class MagneticDipole(UserObjectMulti): # Check if there is a waveformID in the waveforms list - if not any(x.ID == waveform_id for x in grid.waveforms): + if all(x.ID == waveform_id for x in grid.waveforms): logger.exception(f'{self.params_str()} there is no waveform ' + f'with the identifier {waveform_id}.') raise ValueError diff --git a/gprMax/config.py b/gprMax/config.py index 162b06c8..cd2025fc 100644 --- a/gprMax/config.py +++ b/gprMax/config.py @@ -72,7 +72,7 @@ class ModelConfig: # N.B. This will happen if the requested snapshots are too large to # fit on the memory of the GPU. If True this will slow # performance significantly. - if sim_config.general['solver'] == 'cuda' or sim_config.general['solver'] == 'opencl': + if sim_config.general['solver'] in ['cuda', 'opencl']: if sim_config.general['solver'] == 'cuda': devs = sim_config.args.gpu elif sim_config.general['solver'] == 'opencl': diff --git a/gprMax/contexts.py b/gprMax/contexts.py index fbde3698..bc3004f8 100644 --- a/gprMax/contexts.py +++ b/gprMax/contexts.py @@ -53,7 +53,6 @@ class Context: results: dict that can contain useful results/data from simulation. """ - results = {} self.tsimstart = timer() self.print_logo_copyright() print_host_info(config.sim_config.hostinfo) @@ -88,7 +87,7 @@ class Context: self.tsimend = timer() self.print_sim_time_taken() - return results + return {} def print_logo_copyright(self): """Prints gprMax logo, version, and copyright/licencing information.""" diff --git a/gprMax/gprMax.py b/gprMax/gprMax.py index 91776ca8..6454becf 100644 --- a/gprMax/gprMax.py +++ b/gprMax/gprMax.py @@ -214,10 +214,9 @@ def run_main(args): # MPI running with (OpenMP/CUDA/OpenCL) if config.sim_config.args.mpi: context = MPIContext() - results = context.run() # Standard running (OpenMP/CUDA/OpenCL) else: context = Context() - results = context.run() + results = context.run() return results \ No newline at end of file diff --git a/gprMax/grid.py b/gprMax/grid.py index a4960727..b118019e 100644 --- a/gprMax/grid.py +++ b/gprMax/grid.py @@ -414,7 +414,7 @@ def dispersion_analysis(G): # Find maximum significant frequency if G.waveforms: for waveform in G.waveforms: - if waveform.type == 'sine' or waveform.type == 'contsine': + if waveform.type in ['sine', 'contsine']: results['maxfreq'].append(4 * waveform.freq) elif waveform.type == 'impulse': diff --git a/gprMax/hash_cmds_file.py b/gprMax/hash_cmds_file.py index 845b21d5..fc99385f 100644 --- a/gprMax/hash_cmds_file.py +++ b/gprMax/hash_cmds_file.py @@ -278,12 +278,11 @@ def check_cmd_names(processedlines, checkessential=True): lindex += 1 - if checkessential: - if (countessentialcmds < len(essentialcmds)): - logger.exception('Your input file is missing essential commands ' + - 'required to run a model. Essential commands are: ' + - ', '.join(essentialcmds)) - raise SyntaxError + if checkessential and countessentialcmds < len(essentialcmds): + logger.exception('Your input file is missing essential commands ' + + 'required to run a model. Essential commands are: ' + + ', '.join(essentialcmds)) + raise SyntaxError return singlecmds, multiplecmds, geometry diff --git a/gprMax/updates.py b/gprMax/updates.py index 8c05f560..5f258852 100644 --- a/gprMax/updates.py +++ b/gprMax/updates.py @@ -1056,7 +1056,6 @@ class OpenCLUpdates: self.grid.Hx_dev, self.grid.Hy_dev, self.grid.Hz_dev) - event.wait() # If there are any dispersive materials do 1st part of dispersive update # (it is split into two parts as it requires present and updated electric field values). @@ -1076,7 +1075,8 @@ class OpenCLUpdates: self.grid.Hx_dev, self.grid.Hy_dev, self.grid.Hz_dev) - event.wait() + + event.wait() def update_electric_pml(self): """Updates electric field components with the PML correction.""" @@ -1158,7 +1158,6 @@ class OpenCLUpdates: # if iteration == self.grid.iterations - 1: # return self.drv.mem_get_info()[1] - self.drv.mem_get_info()[0] logger.debug('Look at memory estimate for pyopencl') - pass def calculate_solve_time(self): """Calculates solving time for model.""" From c0762cc112075b65ee640eee5105fdfc03badee5 Mon Sep 17 00:00:00 2001 From: Sai-Suraj-27 Date: Fri, 23 Jun 2023 19:35:54 +0530 Subject: [PATCH 2/4] Removed unnecessary if conditions at some places, and used itertools.product to make code more readable/cleaner. --- gprMax/cmds_geometry/add_grass.py | 13 ++--- gprMax/cmds_geometry/add_surface_roughness.py | 11 ++-- gprMax/cmds_geometry/fractal_box.py | 11 ++-- testing/benchmarking/bench_simple.py | 54 +++++++++---------- 4 files changed, 41 insertions(+), 48 deletions(-) diff --git a/gprMax/cmds_geometry/add_grass.py b/gprMax/cmds_geometry/add_grass.py index 43b80f25..cedfeab8 100644 --- a/gprMax/cmds_geometry/add_grass.py +++ b/gprMax/cmds_geometry/add_grass.py @@ -111,7 +111,7 @@ class AddGrass(UserObjectGeometry): if ys == yf or zs == zf: logger.exception(f'{self.__str__()} dimensions are not specified correctly') raise ValueError - if xs != volume.xs and xs != volume.xf: + if xs not in [volume.xs and volume.xf]: logger.exception(f'{self.__str__()} must specify external surfaces on a fractal box') raise ValueError fractalrange = (round_value(limits[0] / grid.dx), round_value(limits[1] / grid.dx)) @@ -130,10 +130,10 @@ class AddGrass(UserObjectGeometry): requestedsurface = 'xplus' elif ys == yf: - if xs == xf or zs == zf: + if zs == zf: logger.exception(f'{self.__str__()} dimensions are not specified correctly') raise ValueError - if ys != volume.ys and ys != volume.yf: + if ys not in [volume.ys and volume.yf]: logger.exception(f'{self.__str__()} must specify external surfaces on a fractal box') raise ValueError fractalrange = (round_value(limits[0] / grid.dy), round_value(limits[1] / grid.dy)) @@ -152,10 +152,7 @@ class AddGrass(UserObjectGeometry): requestedsurface = 'yplus' elif zs == zf: - if xs == xf or ys == yf: - logger.exception(f'{self.__str__()} dimensions are not specified correctly') - raise ValueError - if zs != volume.zs and zs != volume.zf: + if zs not in [volume.zs and volume.zf]: logger.exception(f'{self.__str__()} must specify external surfaces on a fractal box') raise ValueError fractalrange = (round_value(limits[0] / grid.dz), round_value(limits[1] / grid.dz)) @@ -227,7 +224,7 @@ class AddGrass(UserObjectGeometry): surface.grass.append(g) # Check to see if grass has been already defined as a material - if not any(x.ID == 'grass' for x in grid.materials): + if all(x.ID == 'grass' for x in grid.materials): create_grass(grid) # Check if time step for model is suitable for using grass diff --git a/gprMax/cmds_geometry/add_surface_roughness.py b/gprMax/cmds_geometry/add_surface_roughness.py index df4b02da..a822696e 100644 --- a/gprMax/cmds_geometry/add_surface_roughness.py +++ b/gprMax/cmds_geometry/add_surface_roughness.py @@ -118,7 +118,7 @@ class AddSurfaceRoughness(UserObjectGeometry): if ys == yf or zs == zf: logger.exception(f'{self.__str__()} dimensions are not specified correctly') raise ValueError - if xs != volume.xs and xs != volume.xf: + if xs not in [volume.xs, volume.xf]: logger.exception(f'{self.__str__()} can only be used on the external ' + 'surfaces of a fractal box') raise ValueError @@ -144,10 +144,10 @@ class AddSurfaceRoughness(UserObjectGeometry): requestedsurface = 'xplus' elif ys == yf: - if xs == xf or zs == zf: + if zs == zf: logger.exception(f'{self.__str__()} dimensions are not specified correctly') raise ValueError - if ys != volume.ys and ys != volume.yf: + if ys not in [volume.ys and volume.yf]: logger.exception(f'{self.__str__()} can only be used on the external ' + 'surfaces of a fractal box') raise ValueError @@ -173,10 +173,7 @@ class AddSurfaceRoughness(UserObjectGeometry): requestedsurface = 'yplus' elif zs == zf: - if xs == xf or ys == yf: - logger.exception(f'{self.__str__()} dimensions are not specified correctly') - raise ValueError - if zs != volume.zs and zs != volume.zf: + if zs not in [volume.zs and volume.zf]: logger.exception(f'{self.__str__()} can only be used on the external ' + 'surfaces of a fractal box') raise ValueError diff --git a/gprMax/cmds_geometry/fractal_box.py b/gprMax/cmds_geometry/fractal_box.py index 5e6cc598..1ae6a376 100644 --- a/gprMax/cmds_geometry/fractal_box.py +++ b/gprMax/cmds_geometry/fractal_box.py @@ -140,12 +140,11 @@ class FractalBox(UserObjectGeometry): logger.exception(f'{self.__str__()} must be used with more than ' + 'one material from the mixing model.') raise ValueError - if isinstance(mixingmodel, ListMaterial): - if nbins > len(mixingmodel.mat): - logger.exception(f'{self.__str__()} too many materials/bins ' + - 'requested compared to materials in ' + - 'mixing model.') - raise ValueError + if isinstance(mixingmodel, ListMaterial) and nbins > len(mixingmodel.mat): + logger.exception(f'{self.__str__()} too many materials/bins ' + + 'requested compared to materials in ' + + 'mixing model.') + raise ValueError # Create materials from mixing model as number of bins now known # from fractal_box command. mixingmodel.calculate_properties(nbins, grid) diff --git a/testing/benchmarking/bench_simple.py b/testing/benchmarking/bench_simple.py index 9688ca56..6c82c016 100644 --- a/testing/benchmarking/bench_simple.py +++ b/testing/benchmarking/bench_simple.py @@ -3,9 +3,11 @@ receiver at the centre. """ + from pathlib import Path import gprMax +import itertools # File path for output fn = Path(__file__) @@ -17,38 +19,36 @@ ompthreads = [1, 2, 4, 8, 16, 32, 64, 128] scenes = [] -for d in domains: - for threads in ompthreads: +# Discretisation +dl = 0.001 - # Discretisation - dl = 0.001 +for d, threads in itertools.product(domains, ompthreads): + # Domain + x = d + y = x + z = x - # Domain - x = d - y = x - z = x + scene = gprMax.Scene() - scene = gprMax.Scene() + title = gprMax.Title(name=fn.with_suffix('').name) + domain = gprMax.Domain(p1=(x, y, z)) + dxdydz = gprMax.Discretisation(p1=(dl, dl, dl)) + time_window = gprMax.TimeWindow(time=3e-9) + wv = gprMax.Waveform(wave_type='gaussiandotnorm', amp=1, freq=900e6, + id='MySource') + src = gprMax.HertzianDipole(p1=(x/2, y/2, z/2), polarisation='x', + waveform_id='MySource') - title = gprMax.Title(name=fn.with_suffix('').name) - domain = gprMax.Domain(p1=(x, y, z)) - dxdydz = gprMax.Discretisation(p1=(dl, dl, dl)) - time_window = gprMax.TimeWindow(time=3e-9) - wv = gprMax.Waveform(wave_type='gaussiandotnorm', amp=1, freq=900e6, - id='MySource') - src = gprMax.HertzianDipole(p1=(x/2, y/2, z/2), polarisation='x', - waveform_id='MySource') + omp = gprMax.OMPThreads(n=threads) - omp = gprMax.OMPThreads(n=threads) - - scene.add(title) - scene.add(domain) - scene.add(dxdydz) - scene.add(time_window) - scene.add(wv) - scene.add(src) - scene.add(omp) - scenes.append(scene) + scene.add(title) + scene.add(domain) + scene.add(dxdydz) + scene.add(time_window) + scene.add(wv) + scene.add(src) + scene.add(omp) + scenes.append(scene) # Run model gprMax.run(scenes=scenes, n=len(scenes), geometry_only=False, outputfile=fn, gpu=None) \ No newline at end of file From 7e4a4fff343742b51cd343080251c16c9e7a7b83 Mon Sep 17 00:00:00 2001 From: Sai-Suraj-27 Date: Fri, 23 Jun 2023 20:08:13 +0530 Subject: [PATCH 3/4] updated code in a few files to make it more understandable, also used .join method at a place to increase the speed. --- toolboxes/AntennaPatterns/plot_fields.py | 4 ++-- toolboxes/DebyeFit/Debye_Fit.py | 29 ++++++++++-------------- toolboxes/DebyeFit/optimization.py | 3 +-- toolboxes/Plotting/plot_Ascan.py | 9 ++++---- toolboxes/Plotting/plot_source_wave.py | 8 +++---- toolboxes/STLtoVoxel/perimeter.py | 11 ++++----- toolboxes/STLtoVoxel/slice.py | 6 ++--- 7 files changed, 30 insertions(+), 40 deletions(-) diff --git a/toolboxes/AntennaPatterns/plot_fields.py b/toolboxes/AntennaPatterns/plot_fields.py index f9e49a75..c549a28b 100644 --- a/toolboxes/AntennaPatterns/plot_fields.py +++ b/toolboxes/AntennaPatterns/plot_fields.py @@ -58,9 +58,9 @@ if epsr: wavelength = v1 / f # Print some useful information -logger.info('Centre frequency: {} GHz'.format(f / 1e9)) +logger.info(f'Centre frequency: {f / 1000000000.0} GHz') if epsr: - logger.info('Critical angle for Er {} is {} degrees'.format(epsr, thetac)) + logger.info(f'Critical angle for Er {epsr} is {thetac} degrees') logger.info('Wavelength: {:.3f} m'.format(wavelength)) logger.info('Observation distance(s) from {:.3f} m ({:.1f} wavelengths) to {:.3f} m ({:.1f} wavelengths)'.format(radii[0], radii[0] / wavelength, radii[-1], radii[-1] / wavelength)) logger.info('Theoretical boundary between reactive & radiating near-field (0.62*sqrt((D^3/wavelength): {:.3f} m'.format(0.62 * np.sqrt((D**3) / wavelength))) diff --git a/toolboxes/DebyeFit/Debye_Fit.py b/toolboxes/DebyeFit/Debye_Fit.py index 362b8950..a6f6bbfe 100644 --- a/toolboxes/DebyeFit/Debye_Fit.py +++ b/toolboxes/DebyeFit/Debye_Fit.py @@ -119,9 +119,7 @@ class Relaxation(object): print(f"Approximating {self.name}" f" using {self.number_of_debye_poles} Debye poles") print(f"{self.name} parameters: ") - s = '' - for k, v in self.params.items(): - s += f"{k:10s} = {v}\n" + s = ''.join(f"{k:10s} = {v}\n" for k, v in self.params.items()) print(s) return f'{self.name}:\n{s}' @@ -231,16 +229,14 @@ class Relaxation(object): print("_" * 65) # Print the Debye expnasion in a gprMax format - material_prop = [] - material_prop.append("#material: {} {} {} {} {}\n".format(ee, self.sigma, - self.mu, - self.mu_sigma, - self.material_name)) + material_prop = [ + f"#material: {ee} {self.sigma} {self.mu} {self.mu_sigma} {self.material_name}\n" + ] print(material_prop[0], end="") - dispersion_prop = "#add_dispersion_debye: {}".format(len(tau)) + dispersion_prop = f"#add_dispersion_debye: {len(tau)}" for i in range(len(tau)): - dispersion_prop += " {} {}".format(weights[i], 10**tau[i]) - dispersion_prop += " {}".format(self.material_name) + dispersion_prop += f" {weights[i]} {10**tau[i]}" + dispersion_prop += f" {self.material_name}" print(dispersion_prop) material_prop.append(dispersion_prop + '\n') return material_prop @@ -327,11 +323,10 @@ class Relaxation(object): else: sys.exit("Cannot save material properties " f"in {os.path.join(fdir, 'my_materials.txt')}!") - fileH = open(file_path, "a") - fileH.write(f"## {output[0].split(' ')[-1]}") - fileH.writelines(output) - fileH.write("\n") - fileH.close() + with open(file_path, "a") as fileH: + fileH.write(f"## {output[0].split(' ')[-1]}") + fileH.writelines(output) + fileH.write("\n") print(f"Material properties save at: {file_path}") @@ -562,7 +557,7 @@ class Crim(Relaxation): f" using {self.number_of_debye_poles} Debye poles") print("CRIM parameters: ") for i in range(len(self.volumetric_fractions)): - print("Material {}.:".format(i+1)) + print(f"Material {i + 1}.:") print("---------------------------------") print(f"{'Vol. fraction':>27s} = {self.volumetric_fractions[i]}") print(f"{'e_inf':>27s} = {self.materials[i][0]}") diff --git a/toolboxes/DebyeFit/optimization.py b/toolboxes/DebyeFit/optimization.py index a2828e37..0f3c0c90 100644 --- a/toolboxes/DebyeFit/optimization.py +++ b/toolboxes/DebyeFit/optimization.py @@ -456,7 +456,6 @@ def DLS(logt, rl, im, freq): d.imag, x[np.newaxis].T).T[0] cost_i = np.sum(np.abs(ip-im))/len(im) ee = np.mean(rl - rp) - if ee < 1: - ee = 1 + ee = max(ee, 1) cost_r = np.sum(np.abs(rp + ee - rl))/len(im) return cost_i, cost_r, x, ee, rp, ip diff --git a/toolboxes/Plotting/plot_Ascan.py b/toolboxes/Plotting/plot_Ascan.py index 4087c83b..7a07a26e 100644 --- a/toolboxes/Plotting/plot_Ascan.py +++ b/toolboxes/Plotting/plot_Ascan.py @@ -79,11 +79,10 @@ def mpl_plot(filename, outputs=Rx.defaultoutputs, fft=False, save=False): time = np.linspace(0, (iterations - 1) * dt, num=iterations) # Check for single output component when doing a FFT - if fft: - if not len(outputs) == 1: - logger.exception('A single output must be specified when using ' + - 'the -fft option') - raise ValueError + if fft and not len(outputs) == 1: + logger.exception('A single output must be specified when using ' + + 'the -fft option') + raise ValueError # New plot for each receiver for rx in range(1, nrx + 1): diff --git a/toolboxes/Plotting/plot_source_wave.py b/toolboxes/Plotting/plot_source_wave.py index ba4cfaf5..2e9a1182 100644 --- a/toolboxes/Plotting/plot_source_wave.py +++ b/toolboxes/Plotting/plot_source_wave.py @@ -86,14 +86,14 @@ def mpl_plot(w, timewindow, dt, iterations, fft=False, save=False): logging.info(f'Type: {w.type}') logging.info(f'Maximum (absolute) amplitude: {np.max(np.abs(waveform)):g}') - if w.freq and not w.type == 'gaussian' and not w.type == 'impulse': + if w.freq and w.type != 'gaussian' and w.type != 'impulse': logging.info(f'Centre frequency: {w.freq:g} Hz') - if (w.type == 'gaussian' or w.type == 'gaussiandot' or w.type == 'gaussiandotnorm' - or w.type == 'gaussianprime' or w.type == 'gaussiandoubleprime'): + if w.type in ['gaussian', 'gaussiandot', 'gaussiandotnorm', + 'gaussianprime', 'gaussiandoubleprime']: delay = 1 / w.freq logging.info(f'Time to centre of pulse: {delay:g} s') - elif w.type == 'gaussiandotdot' or w.type == 'gaussiandotdotnorm' or w.type == 'ricker': + elif w.type in ['gaussiandotdot', 'gaussiandotdotnorm', 'ricker']: delay = np.sqrt(2) / w.freq logging.info(f'Time to centre of pulse: {delay:g} s') diff --git a/toolboxes/STLtoVoxel/perimeter.py b/toolboxes/STLtoVoxel/perimeter.py index e583626d..80d61691 100644 --- a/toolboxes/STLtoVoxel/perimeter.py +++ b/toolboxes/STLtoVoxel/perimeter.py @@ -36,12 +36,11 @@ def generate_y(p1, p2, x): def paint_y_axis(lines, pixels, x): is_black = False - target_ys = list(map(lambda line: int(generate_y(line[0], line[1], x)), lines)) - target_ys.sort() + target_ys = sorted( + map(lambda line: int(generate_y(line[0], line[1], x)), lines) + ) if len(target_ys) % 2: - distances = [] - for i in range(len(target_ys) - 1): - distances.append(target_ys[i+1] - target_ys[i]) + distances = [target_ys[i+1] - target_ys[i] for i in range(len(target_ys) - 1)] # https://stackoverflow.com/a/17952763 min_idx = -min((x, -i) for i, x in enumerate(distances))[1] del target_ys[min_idx] @@ -54,7 +53,7 @@ def paint_y_axis(lines, pixels, x): pixels[target_y][x] = True is_black = not is_black yi = target_y - assert is_black is False, 'an error has occured at x%s' % x + assert is_black is False, f'an error has occured at x{x}' def generate_line_events(line_list): diff --git a/toolboxes/STLtoVoxel/slice.py b/toolboxes/STLtoVoxel/slice.py index 8b609ca9..b2e37ad0 100644 --- a/toolboxes/STLtoVoxel/slice.py +++ b/toolboxes/STLtoVoxel/slice.py @@ -1,3 +1,4 @@ +import itertools import multiprocessing as mp import sys @@ -90,10 +91,7 @@ def triangle_to_intersecting_lines(triangle, height, pixels, lines): y = int(same[0][1]) pixels[y][x] = True else: - cross_lines = [] - for a in above: - for b in below: - cross_lines.append((b, a)) + cross_lines = [(b, a) for a, b in itertools.product(above, below)] side1 = where_line_crosses_z(cross_lines[0][0], cross_lines[0][1], height) side2 = where_line_crosses_z(cross_lines[1][0], cross_lines[1][1], height) lines.append((side1, side2)) From 48a4c39a12943605b317df170eee52eb2b017070 Mon Sep 17 00:00:00 2001 From: Sai-Suraj-27 Date: Fri, 23 Jun 2023 23:16:03 +0530 Subject: [PATCH 4/4] Reverting back a small change made. --- toolboxes/DebyeFit/Debye_Fit.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/toolboxes/DebyeFit/Debye_Fit.py b/toolboxes/DebyeFit/Debye_Fit.py index a6f6bbfe..caa08f60 100644 --- a/toolboxes/DebyeFit/Debye_Fit.py +++ b/toolboxes/DebyeFit/Debye_Fit.py @@ -229,9 +229,11 @@ class Relaxation(object): print("_" * 65) # Print the Debye expnasion in a gprMax format - material_prop = [ - f"#material: {ee} {self.sigma} {self.mu} {self.mu_sigma} {self.material_name}\n" - ] + material_prop = [] + material_prop.append("#material: {} {} {} {} {}\n".format(ee, self.sigma, + self.mu, + self.mu_sigma, + self.material_name)) print(material_prop[0], end="") dispersion_prop = f"#add_dispersion_debye: {len(tau)}" for i in range(len(tau)):