From f514c0c9169664ff2457e2419bbf4b0d531a7fc5 Mon Sep 17 00:00:00 2001 From: John Hartley Date: Thu, 1 Aug 2019 12:13:31 +0100 Subject: [PATCH] refactor methods --- gprMax/model_build_run.py | 199 ++++++++++++++++++++------------------ 1 file changed, 105 insertions(+), 94 deletions(-) diff --git a/gprMax/model_build_run.py b/gprMax/model_build_run.py index f44bb485..86359492 100644 --- a/gprMax/model_build_run.py +++ b/gprMax/model_build_run.py @@ -86,13 +86,65 @@ class ModelBuildRun: self.model_config = model_config self.G = solver.get_G() - def tm_grid_update(self): - if '2D TMx' in self.model_config.mode: - self.G.tmx() - elif '2D TMy' in self.model_config.mode: - self.G.tmy() - elif '2D TMz' in self.model_config.mode: - self.G.tmz() + def build(self): + """Runs a model - processes the input file; builds the Yee cells; calculates update coefficients; runs main FDTD loop. + + Args: + args (dict): Namespace with command line arguments + currentmodelrun (int): Current model run number. + modelend (int): Number of last model to run. + numbermodelruns (int): Total number of model runs. + 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. + + Returns: + tsolve (int): Length of time (seconds) of main FDTD calculations + """ + # Monitor memory usage + p = psutil.Process() + + # Normal model reading/building process; bypassed if geometry information to be reused + if not self.sim_config.geometry_fixed: + self.build_geometry() + else: + self.reuse_geometry() + + # Adjust position of simple sources and receivers if required + if G.srcsteps[0] != 0 or G.srcsteps[1] != 0 or G.srcsteps[2] != 0: + for source in itertools.chain(G.hertziandipoles, G.magneticdipoles): + if currentmodelrun == 1: + if source.xcoord + G.srcsteps[0] * modelend < 0 or source.xcoord + G.srcsteps[0] * modelend > G.nx or source.ycoord + G.srcsteps[1] * modelend < 0 or source.ycoord + G.srcsteps[1] * modelend > G.ny or source.zcoord + G.srcsteps[2] * modelend < 0 or source.zcoord + G.srcsteps[2] * modelend > G.nz: + raise GeneralError('Source(s) will be stepped to a position outside the domain.') + source.xcoord = source.xcoordorigin + (currentmodelrun - 1) * G.srcsteps[0] + source.ycoord = source.ycoordorigin + (currentmodelrun - 1) * G.srcsteps[1] + source.zcoord = source.zcoordorigin + (currentmodelrun - 1) * G.srcsteps[2] + if G.rxsteps[0] != 0 or G.rxsteps[1] != 0 or G.rxsteps[2] != 0: + for receiver in G.rxs: + if currentmodelrun == 1: + if receiver.xcoord + G.rxsteps[0] * modelend < 0 or receiver.xcoord + G.rxsteps[0] * modelend > G.nx or receiver.ycoord + G.rxsteps[1] * modelend < 0 or receiver.ycoord + G.rxsteps[1] * modelend > G.ny or receiver.zcoord + G.rxsteps[2] * modelend < 0 or receiver.zcoord + G.rxsteps[2] * modelend > G.nz: + raise GeneralError('Receiver(s) will be stepped to a position outside the domain.') + receiver.xcoord = receiver.xcoordorigin + (currentmodelrun - 1) * G.rxsteps[0] + receiver.ycoord = receiver.ycoordorigin + (currentmodelrun - 1) * G.rxsteps[1] + receiver.zcoord = receiver.zcoordorigin + (currentmodelrun - 1) * G.rxsteps[2] + + # Write files for any geometry views and geometry object outputs + if not (G.geometryviews or G.geometryobjectswrite) and args.geometry_only and config.general['messages']: + print(Fore.RED + '\nWARNING: No geometry views or geometry objects to output found.' + Style.RESET_ALL) + if config.general['messages']: print() + for i, geometryview in enumerate(G.geometryviews): + geometryview.set_filename(appendmodelnumber) + pbar = tqdm(total=geometryview.datawritesize, unit='byte', unit_scale=True, desc='Writing geometry view file {}/{}, {}'.format(i + 1, len(G.geometryviews), os.path.split(geometryview.filename)[1]), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars']) + geometryview.write_vtk(G, pbar) + pbar.close() + for i, geometryobject in enumerate(G.geometryobjectswrite): + pbar = tqdm(total=geometryobject.datawritesize, unit='byte', unit_scale=True, desc='Writing geometry object file {}/{}, {}'.format(i + 1, len(G.geometryobjectswrite), os.path.split(geometryobject.filename)[1]), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars']) + geometryobject.write_hdf5(G, pbar) + pbar.close() + + # If only writing geometry information + if args.geometry_only: + tsolve = 0 def build_geometry(self): model_config = self.model_config @@ -102,46 +154,18 @@ class ModelBuildRun: printer = Printer(sim_config) printer.print(model_config.next_model) - # api for multiple scenes / model runs - try: - scene = model_config.get_scene() - # process using hashcommands - except AttributeError: - scene = Scene() - # parse the input file into user objects and add them to the scene - scene = parse_hash_commands(args, usernamespace, appendmodelnumber, G, scene) - - # Creates the internal simulation objects. - scene.create_internal_objects(G) + scene = self.build_scene() # print PML information printer.print(pml_information(G)) - # build the PMLS - pbar = tqdm(total=sum(1 for value in G.pmlthickness.values() if value > 0), desc='Building PML boundaries', ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars']) - - for pml_id, thickness in G.pmlthickness.items(): - build_pml(G, pml_id, thickness) - pbar.update() - pbar.close() - - # Build the model, i.e. set the material properties (ID) for every edge - # of every Yee cell - printer.print('') - pbar = tqdm(total=2, desc='Building main grid', ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars']) - build_electric_components(G.solid, G.rigidE, G.ID, G) - pbar.update() - build_magnetic_components(G.solid, G.rigidH, G.ID, G) - pbar.update() - pbar.close() + self.build_pmls() + self.build_components() # update grid for tm modes - tm_grid_update(model_config) + self.tm_grid_update() - # Process any voltage sources (that have resistance) to create a new - # material at the source location - for voltagesource in G.voltagesources: - voltagesource.create_material(G) + self.update_voltage_source_materials() # Initialise arrays of update coefficients to pass to update functions G.initialise_std_update_coeff_arrays() @@ -206,66 +230,53 @@ class ModelBuildRun: printer.print(Fore.GREEN + '{} {}\n'.format(model_config.inputfilestr, '-' * (get_terminal_width() - 1 - len(model_config.inputfilestr))) + Style.RESET_ALL) self.G.reset_fields() + def tm_grid_update(self): + if '2D TMx' in self.model_config.mode: + self.G.tmx() + elif '2D TMy' in self.model_config.mode: + self.G.tmy() + elif '2D TMz' in self.model_config.mode: + self.G.tmz() - def build(self): - """Runs a model - processes the input file; builds the Yee cells; calculates update coefficients; runs main FDTD loop. + def build_scene(self): + # api for multiple scenes / model runs + try: + scene = self.model_config.get_scene() + # process using hashcommands + except AttributeError: + scene = Scene() + # parse the input file into user objects and add them to the scene + scene = parse_hash_commands(args, usernamespace, appendmodelnumber, G, scene) - Args: - args (dict): Namespace with command line arguments - currentmodelrun (int): Current model run number. - modelend (int): Number of last model to run. - numbermodelruns (int): Total number of model runs. - 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. + # Creates the internal simulation objects. + scene.create_internal_objects(G) + return scene - Returns: - tsolve (int): Length of time (seconds) of main FDTD calculations - """ - # Monitor memory usage - p = psutil.Process() + def build_pmls(self): + # build the PMLS + pbar = tqdm(total=sum(1 for value in G.pmlthickness.values() if value > 0), desc='Building PML boundaries', ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars']) - # Normal model reading/building process; bypassed if geometry information to be reused - if not self.sim_config.geometry_fixed: - self.build_geometry() - else: - self.reuse_geometry() + for pml_id, thickness in G.pmlthickness.items(): + build_pml(G, pml_id, thickness) + pbar.update() + pbar.close() - # Adjust position of simple sources and receivers if required - if G.srcsteps[0] != 0 or G.srcsteps[1] != 0 or G.srcsteps[2] != 0: - for source in itertools.chain(G.hertziandipoles, G.magneticdipoles): - if currentmodelrun == 1: - if source.xcoord + G.srcsteps[0] * modelend < 0 or source.xcoord + G.srcsteps[0] * modelend > G.nx or source.ycoord + G.srcsteps[1] * modelend < 0 or source.ycoord + G.srcsteps[1] * modelend > G.ny or source.zcoord + G.srcsteps[2] * modelend < 0 or source.zcoord + G.srcsteps[2] * modelend > G.nz: - raise GeneralError('Source(s) will be stepped to a position outside the domain.') - source.xcoord = source.xcoordorigin + (currentmodelrun - 1) * G.srcsteps[0] - source.ycoord = source.ycoordorigin + (currentmodelrun - 1) * G.srcsteps[1] - source.zcoord = source.zcoordorigin + (currentmodelrun - 1) * G.srcsteps[2] - if G.rxsteps[0] != 0 or G.rxsteps[1] != 0 or G.rxsteps[2] != 0: - for receiver in G.rxs: - if currentmodelrun == 1: - if receiver.xcoord + G.rxsteps[0] * modelend < 0 or receiver.xcoord + G.rxsteps[0] * modelend > G.nx or receiver.ycoord + G.rxsteps[1] * modelend < 0 or receiver.ycoord + G.rxsteps[1] * modelend > G.ny or receiver.zcoord + G.rxsteps[2] * modelend < 0 or receiver.zcoord + G.rxsteps[2] * modelend > G.nz: - raise GeneralError('Receiver(s) will be stepped to a position outside the domain.') - receiver.xcoord = receiver.xcoordorigin + (currentmodelrun - 1) * G.rxsteps[0] - receiver.ycoord = receiver.ycoordorigin + (currentmodelrun - 1) * G.rxsteps[1] - receiver.zcoord = receiver.zcoordorigin + (currentmodelrun - 1) * G.rxsteps[2] + def build_components(self): + # Build the model, i.e. set the material properties (ID) for every edge + # of every Yee cell + printer.print('') + pbar = tqdm(total=2, desc='Building main grid', ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars']) + build_electric_components(G.solid, G.rigidE, G.ID, G) + pbar.update() + build_magnetic_components(G.solid, G.rigidH, G.ID, G) + pbar.update() + pbar.close() - # Write files for any geometry views and geometry object outputs - if not (G.geometryviews or G.geometryobjectswrite) and args.geometry_only and config.general['messages']: - print(Fore.RED + '\nWARNING: No geometry views or geometry objects to output found.' + Style.RESET_ALL) - if config.general['messages']: print() - for i, geometryview in enumerate(G.geometryviews): - geometryview.set_filename(appendmodelnumber) - pbar = tqdm(total=geometryview.datawritesize, unit='byte', unit_scale=True, desc='Writing geometry view file {}/{}, {}'.format(i + 1, len(G.geometryviews), os.path.split(geometryview.filename)[1]), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars']) - geometryview.write_vtk(G, pbar) - pbar.close() - for i, geometryobject in enumerate(G.geometryobjectswrite): - pbar = tqdm(total=geometryobject.datawritesize, unit='byte', unit_scale=True, desc='Writing geometry object file {}/{}, {}'.format(i + 1, len(G.geometryobjectswrite), os.path.split(geometryobject.filename)[1]), ncols=get_terminal_width() - 1, file=sys.stdout, disable=not config.general['progressbars']) - geometryobject.write_hdf5(G, pbar) - pbar.close() - - # If only writing geometry information - if args.geometry_only: - tsolve = 0 + def update_voltage_source_materials(self): + # Process any voltage sources (that have resistance) to create a new + # material at the source location + for voltagesource in G.voltagesources: + voltagesource.create_material(G) def run_model(self):