diff --git a/gprMax/subgrids/solver.py b/gprMax/subgrids/solver.py index 4c164d25..8cb01e8d 100644 --- a/gprMax/subgrids/solver.py +++ b/gprMax/subgrids/solver.py @@ -14,6 +14,9 @@ from time import perf_counter import os import sys +from ..updates import CPUUpdates + + def create_solver(G): """Return the solver for the given subgrids.""" @@ -32,10 +35,33 @@ def create_solver(G): sgu = SubgridUpdater(sg, precursors, G) updaters.append(sgu) - solver = SubGridSolver(G, updaters) + updates = SubgridUpdates(G, updaters) + solver = SubGridSolver(G, updates) return solver +class SubgridUpdates(CPUUpdates): + + def __init__(self, G, updaters): + super().__init__(G) + self.updaters = updaters + + def hsg_1(self): + """Method to update the subgrids over the first phase.""" + for sg_updater in self.updaters: + sg_updater.hsg_1() + + def hsg_2(self): + """Method to update the subgrids over the second phase.""" + for sg_updater in self.updaters: + sg_updater.hsg_2() + + def store_outputs(self, iteration): + super().store_outputs(iteration) + """Method to store field outputs for all grid for each main grid iteration.""" + for updater in self.updaters: + updater.store_outputs(iteration) + class SubGridSolver: """Solver for subgridding simulations.""" @@ -44,47 +70,25 @@ class SubGridSolver: array. """ - def __init__(self, G, subgrid_updaters, hsg=True): + def __init__(self, G, updates, hsg=True): """ Args: G (G): Grid class instance - holds essential parameters describing the model. - subgrid_updaters: (list): list of subgrid_updaters used for updating + updates: (list): list of subgrid_updaters used for updating the subgrids - iterations (int): number of iterations for the simulation. hsg (bool): HSG methods for subgrids will not be called if False. - """ - self.G = G - self.grids = [self.G] + G.subgrids - self.subgrid_updaters = subgrid_updaters - self.materials = G.materials - self.abs_time = 0 + self.updates = updates self.hsg = hsg - def store_outputs(self): - """Method to store field outputs for all grid for each main grid iteration.""" - for grid in self.grids: - store_outputs(self.G.iteration, grid.Ex, grid.Ey, grid.Ez, - grid.Hx, grid.Hy, grid.Hz, grid) - def store_snapshots(self): """Store any snapshots.""" for snap in self.G.snapshots: if snap.time == self.G.iteration + 1: snap.store(self.G) - def hsg_1(self): - """Method to update the subgrids over the first phase.""" - for sg_updater in self.subgrid_updaters: - sg_updater.hsg_1() - - def hsg_2(self): - """Method to update the subgrids over the second phase.""" - for sg_updater in self.subgrid_updaters: - sg_updater.hsg_2() - def solve(self, iterations): """Run timestepping.""" tsolvestart = perf_counter() @@ -94,63 +98,26 @@ class SubGridSolver: # The main grid FDTD loop for iteration in self.iterations: + self.updates.store_outputs(iteration) + #self.updates.store_snapshots(iteration) + self.updates.update_magnetic() + self.updates.update_magnetic_pml() + self.updates.update_magnetic_sources(iteration) + self.updates.hsg_2() + self.updates.update_electric_a() + self.updates.update_electric_pml() + self.updates.update_electric_sources(iteration) + self.updates.hsg_1() + self.updates.update_electric_b() + # Keep track of the index. Required for saving output correctly self.G.iteration = iteration - # Write any snapshots of the E, H, I fields/currents - self.write_snapshots(iteration) - - self.store_outputs() - # Update main grid electric field components including sources - self.update_magnetic() - # Update the fields in the subgrids / main grid - if self.hsg: - self.hsg_2() - - # Update main grid electric field components including sources - self.update_electric() - # Update the fields in the subgrids / main grid - if self.hsg: - self.hsg_1() - # Return the elapsed time tsolve = perf_counter() - tsolvestart return tsolve - def update_electric(self): - """Method to update E fields, PML and electric sources.""" - # All materials are non-dispersive so do standard update - G = self.G - - update_electric(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsE, G.ID, - G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz) - - # Update electric field components with the PML correction - for pml in G.pmls: - pml.update_electric(G) - # Update electric field components from sources (update any Hertzian dipole sources last) - for source in G.voltagesources + G.transmissionlines + G.hertziandipoles: - source.update_electric(G.iteration, G.updatecoeffsE, G.ID, G.Ex, - G.Ey, G.Ez, G) - - def update_magnetic(self): - """Method to update H fields, PML and magnetic sources.""" - # Update magnetic field components - G = self.G - - update_magnetic(G.nx, G.ny, G.nz, G.nthreads, G.updatecoeffsH, G.ID, - G.Ex, G.Ey, G.Ez, G.Hx, G.Hy, G.Hz) - - # Update magnetic field components with the PML correction - for pml in G.pmls: - pml.update_magnetic(G) - - # Update magnetic field components from sources - for source in G.transmissionlines + G.magneticdipoles: - source.update_magnetic(G.iteration, G.updatecoeffsH, G.ID, - G.Hx, G.Hy, G.Hz, G) - def write_snapshots(self, iteration): # Write any snapshots to file for i, snap in enumerate(self.G.snapshots): @@ -169,7 +136,7 @@ class SubGridSolver: pbar.close() -class SubgridUpdater: +class SubgridUpdater(CPUUpdates): """Class to handle updating the electric and magnetic fields of an HSG subgrid. The IS, OS, subgrid region and the electric/magnetic sources are updated using the precursor regions. @@ -184,7 +151,7 @@ class SubgridUpdater: G (class): Grid class instance - holds essential parameters describing the model. """ - self.subgrid = subgrid + super().__init__(subgrid) self.precursors = precursors self.G = G self.source_iteration = 0 @@ -193,7 +160,7 @@ class SubgridUpdater: """This is the first half of the subgrid update. Takes the time step up to the main grid magnetic update""" G = self.G - sub_grid = self.subgrid + sub_grid = self.grid precursors = self.precursors precursors.update_electric() @@ -202,73 +169,33 @@ class SubgridUpdater: for m in range(1, upper_m + 1): - # store_outputs(self.grid) # STD update, interpolate inc. field in time, apply correction - update_electric(sub_grid.nx, - sub_grid.ny, - sub_grid.nz, - G.nthreads, - sub_grid.updatecoeffsE, - sub_grid.ID, - sub_grid.Ex, - sub_grid.Ey, - sub_grid.Ez, - sub_grid.Hx, - sub_grid.Hy, - sub_grid.Hz) - for pml in sub_grid.pmls: - pml.update_electric(sub_grid) + self.update_electric_a() + self.update_electric_pml() precursors.interpolate_magnetic_in_time(int(m + sub_grid.ratio / 2 - 0.5)) sub_grid.update_electric_is(precursors) self.update_sub_grid_electric_sources() # STD update, interpolate inc. field in time, apply correction - update_magnetic(sub_grid.nx, - sub_grid.ny, - sub_grid.nz, - G.nthreads, - sub_grid.updatecoeffsH, - sub_grid.ID, - sub_grid.Ex, - sub_grid.Ey, - sub_grid.Ez, - sub_grid.Hx, - sub_grid.Hy, - sub_grid.Hz) - for pml in sub_grid.pmls: - pml.update_magnetic(sub_grid) - + self.update_magnetic() + self.update_magnetic_pml() precursors.interpolate_electric_in_time(m) sub_grid.update_magnetic_is(precursors) self.update_sub_grid_magnetic_sources() - # store_outputs(self.grid) - update_electric(sub_grid.nx, - sub_grid.ny, - sub_grid.nz, - G.nthreads, - sub_grid.updatecoeffsE, - sub_grid.ID, - sub_grid.Ex, - sub_grid.Ey, - sub_grid.Ez, - sub_grid.Hx, - sub_grid.Hy, - sub_grid.Hz) - for pml in sub_grid.pmls: - pml.update_electric(sub_grid) + self.update_electric_a() + self.update_electric_pml() precursors.calc_exact_magnetic_in_time() sub_grid.update_electric_is(precursors) self.update_sub_grid_electric_sources() - sub_grid.update_electric_os(G) def hsg_2(self): """This is the first half of the subgrid update. Takes the time step up to the main grid electric update""" G = self.G - sub_grid = self.subgrid + sub_grid = self.grid precursors = self.precursors precursors.update_magnetic() @@ -277,71 +204,30 @@ class SubgridUpdater: for m in range(1, upper_m + 1): - update_magnetic(sub_grid.nx, - sub_grid.ny, - sub_grid.nz, - G.nthreads, - sub_grid.updatecoeffsH, - sub_grid.ID, - sub_grid.Ex, - sub_grid.Ey, - sub_grid.Ez, - sub_grid.Hx, - sub_grid.Hy, - sub_grid.Hz) - - for pml in sub_grid.pmls: - pml.update_magnetic(sub_grid) + self.update_magnetic() + self.update_magnetic_pml() precursors.interpolate_electric_in_time(int(m + sub_grid.ratio / 2 - 0.5)) sub_grid.update_magnetic_is(precursors) self.update_sub_grid_magnetic_sources() - # store_outputs(self.grid) - update_electric(sub_grid.nx, - sub_grid.ny, - sub_grid.nz, - G.nthreads, - sub_grid.updatecoeffsE, - sub_grid.ID, - sub_grid.Ex, - sub_grid.Ey, - sub_grid.Ez, - sub_grid.Hx, - sub_grid.Hy, - sub_grid.Hz) - - for pml in sub_grid.pmls: - pml.update_electric(sub_grid) + self.update_electric_a() + self.update_electric_pml() precursors.interpolate_magnetic_in_time(m) sub_grid.update_electric_is(precursors) self.update_sub_grid_electric_sources() - - update_magnetic(sub_grid.nx, - sub_grid.ny, - sub_grid.nz, - G.nthreads, - sub_grid.updatecoeffsH, - sub_grid.ID, - sub_grid.Ex, - sub_grid.Ey, - sub_grid.Ez, - sub_grid.Hx, - sub_grid.Hy, - sub_grid.Hz) - for pml in sub_grid.pmls: - pml.update_magnetic(sub_grid) + self.update_magnetic() + self.update_magnetic_pml() precursors.calc_exact_electric_in_time() sub_grid.update_magnetic_is(precursors) self.update_sub_grid_magnetic_sources() - sub_grid.update_magnetic_os(G) def update_sub_grid_electric_sources(self): """Update any electric sources in the subgrid""" - sg = self.subgrid + sg = self.grid for source in sg.voltagesources + sg.transmissionlines + sg.hertziandipoles: source.update_electric(self.source_iteration, sg.updatecoeffsE, sg.ID, sg.Ex, sg.Ey, sg.Ez, sg) @@ -349,7 +235,7 @@ class SubgridUpdater: def update_sub_grid_magnetic_sources(self): """Update any magnetic sources in the subgrid""" - sg = self.subgrid + sg = self.grid for source in sg.transmissionlines + sg.magneticdipoles: source.update_magnetic(self.source_iteration, sg.updatecoeffsH, sg.ID, sg.Hx, sg.Hy, sg.Hz, sg) diff --git a/gprMax/subgrids/user_objects.py b/gprMax/subgrids/user_objects.py index 34104592..dc3e9de9 100644 --- a/gprMax/subgrids/user_objects.py +++ b/gprMax/subgrids/user_objects.py @@ -62,9 +62,8 @@ class SubGridBase(UserObjectMulti): sg.x1, sg.y1, sg.z1 = np.add([sg.x1_u, sg.y1_u, sg.z1_u], sg.is_os_sep * sg.dx) sg.x2, sg.y2, sg.z2 = np.subtract([sg.x2_u, sg.y2_u, sg.z2_u], sg.is_os_sep * sg.dx) - def set_name(self): - self.name = self.kwargs['id'] - + def set_name(self, sg): + sg.name = self.kwargs['id'] def set_working_region_cells(self, sg): """Number of cells in each dimension for the working region.""" @@ -115,7 +114,7 @@ class SubGridBase(UserObjectMulti): self.set_working_region_cells(sg) self.set_total_cells(sg) self.set_iterations(sg, grid) - self.set_name() + self.set_name(sg) # Copy a reference for the main grid to the sub grid sg.parent_grid = grid