def build_refinementboxes(domain_box, **kwargs): refinement_ratio = kwargs["refinement_ratio"] boxes = {} for ilvl, boxes_data in kwargs["refinement_boxes"].items(): level_number = int(ilvl.strip("L")) + 1 if level_number not in boxes: boxes[level_number] = [] assert isinstance(boxes_data, (list, dict)) if isinstance(boxes_data, list): for _, refinement_box in enumerate(boxes_data): refined_box = boxm.refine(refinement_box, refinement_ratio) boxes[level_number].append(refined_box) else: for boxname, lower_upper in boxes_data.items(): refinement_box = Box(lower_upper[0][0], lower_upper[1][0]) refined_box = boxm.refine(refinement_box, refinement_ratio) boxes[level_number].append(refined_box) # coarse level boxes are arbitrarily divided in 2 patches in the middle middle_cell = np.round(domain_box.upper / 2) lower_box = Box(0, middle_cell) upper_box = Box(middle_cell + 1, domain_box.upper) boxes[0] = [lower_box, upper_box] return boxes
def build_boxes(domain_box, **kwargs): refinement_ratio = kwargs["refinement_ratio"] ndim = domain_box.ndim boxes = {} for ilvl, boxes_data in kwargs["refinement_boxes"].items(): level_number = int(ilvl.strip("L")) + 1 if level_number not in boxes: boxes[level_number] = [] assert isinstance(boxes_data, (list, dict)) if isinstance(boxes_data, list): for _, refinement_box in enumerate(boxes_data): refined_box = boxm.refine(refinement_box, refinement_ratio) boxes[level_number].append(refined_box) else: for boxname, box in boxes_data.items(): if isinstance(box, Box): refinement_box = Box(box.lower, box.upper) else: refinement_box = Box(box[0], box[1]) refined_box = boxm.refine(refinement_box, refinement_ratio) boxes[level_number].append(refined_box) # coarse level boxes are arbitrarily divided in 2 patches in the middle if ( "largest_patch_size" in kwargs and (kwargs["largest_patch_size"] == domain_box.upper + 1).all() ): boxes[0] = [Box(domain_box.lower, domain_box.upper + 1)] else: if ndim == 1: middle_cell = np.round(domain_box.upper / 2) lower_box = Box(0, middle_cell) upper_box = Box(middle_cell + 1, domain_box.upper) if ndim >= 2: middle_cell = np.round(domain_box.upper / 2) lower_box = Box([0] * ndim, middle_cell - 1) upper_box = Box(middle_cell, domain_box.upper) boxes[0] = [lower_box, upper_box] if ndim >= 2: boxes[0].append( Box([0, middle_cell[1]], [middle_cell[0] - 1, domain_box.upper[1]]) ) boxes[0].append( Box([middle_cell[0], 0], [domain_box.upper[0], middle_cell[1] - 1]) ) return boxes
def refine(field, **kwargs): """ optional kwargs data : for overriding the field dataset so you don't have to make a temporary copy of a field just to have a different dataset """ assert isinstance(field, FieldData) kwarg_keys = ["data"] assert any([key in kwarg_keys for key in list(kwargs.keys())]) refinement_ratio = 2 primal_directions = field.primal_directions() data = kwargs.get("data", field.dataset[:]) if "data" in kwargs: assert data.shape == field.dataset.shape fine_box = boxm.refine(field.box, refinement_ratio) fine_layout = GridLayout(fine_box, field.origin, field.layout.dl/refinement_ratio, interp_order=field.layout.interp_order) assert field.box.ndim == 1 fine_data = np.zeros(fine_box.shape + primal_directions + (field.ghosts_nbr[0] * 2)) ghostX = field.ghosts_nbr[0] assert ghostX > 0 cadence = 2 if primal_directions[0]: fine_data[ghostX:-ghostX:cadence] = data[ghostX:-ghostX] # coarse primal on top of fine fine_data[ghostX + 1:-(ghostX - 1):cadence] = 0.5*data[ghostX:-ghostX] + 0.5*data[ghostX + 1:-(ghostX - 1)] else: fine_data[ghostX:-(ghostX + 1):cadence] = 0.25*data[ghostX - 1:-(ghostX + 1)] + 0.75*data[ghostX:-ghostX] fine_data[ghostX + 1:-(ghostX - 1):cadence] = 0.25*data[ghostX + 1:-(ghostX - 1)] + 0.75*data[ghostX:-ghostX] return FieldData(fine_layout, field.field_name, data=fine_data)
def make_fig(hier, fig_name, ilvl, extra_collections=[]): if cpp.mpi_rank() == 0: l0_in_l1 = [boxm.refine(p.box, 2) for p in hier.level(0).patches] collections=[{ "boxes": l0_in_l1, "facecolor": "grey", }] if 1 in hier.levels(): l1_over_l0 = [p.box for p in hier.level(1).patches] collections += [{ "boxes": l1_over_l0, "facecolor": "yellow", }] hier.plot_2d_patches(1, collections=collections + extra_collections, ).savefig(fig_name+".png")
def build_patch_datas(domain_box, boxes, **kwargs): quantities = kwargs["quantities"] origin = kwargs["origin"] interp_order = kwargs["interp_order"] domain_size = kwargs["domain_size"] cell_width = kwargs["cell_width"] refinement_ratio = kwargs["refinement_ratio"] skip_particles = False if "particles" in quantities: del quantities[quantities.index("particles")] else: skip_particles = True domain_layout = GridLayout(domain_box, origin, cell_width, interp_order) coarse_particles = Particles(box=domain_box) # copy domain particles and put them in ghost cells particle_ghost_nbr = domain_layout.particleGhostNbr(interp_order) box_extend = particle_ghost_nbr - 1 upper_slct_box = Box(domain_box.upper - box_extend, domain_box.upper) lower_slct_box = Box(domain_box.lower, domain_box.lower + box_extend) if not skip_particles: coarse_particles = Particles(box=domain_box) upper_cell_particles = coarse_particles.select(upper_slct_box) lower_cell_particles = coarse_particles.select(lower_slct_box) coarse_particles.add( upper_cell_particles.shift_icell(-domain_box.shape())) coarse_particles.add( lower_cell_particles.shift_icell(domain_box.shape())) patch_datas = {} for ilvl, lvl_box in boxes.items(): lvl_cell_width = cell_width / (refinement_ratio**ilvl) if not skip_particles: if ilvl == 0: lvl_particles = coarse_particles else: level_domain_box = boxm.refine(domain_box, refinement_ratio) lvl_ghost_domain_box = boxm.grow( level_domain_box, domain_layout.particleGhostNbr(interp_order)) lvl_particles = Particles(box=lvl_ghost_domain_box) if ilvl not in patch_datas: patch_datas[ilvl] = [] for box in lvl_box: ghost_box = boxm.grow(box, 5) origin = box.lower * lvl_cell_width layout = GridLayout(box, origin, lvl_cell_width, interp_order) datas = { qty: globals()[qty](ghost_box, layout, domain_size) for qty in quantities } if not skip_particles: datas["particles"] = lvl_particles.select(ghost_box) boxed_patch_datas = {} for qty_name, data in datas.items(): if qty_name == 'particles': pdata = ParticleData(layout, data, "pop_name") else: pdata = FieldData(layout, qty_name, data) boxed_patch_datas[qty_name] = pdata patch_datas[ilvl].append(boxed_patch_datas) return patch_datas
def test_box_refinement(self, coarse, exp_refined): actual_refined = boxm.refine(coarse, 2) self.assertEqual(actual_refined, exp_refined)
def coarsen(qty, coarseField, fineField, coarseBox, fineData, coarseData): coarseLayout = coarseField.layout fineLayout = fineField.layout ndim = coarseLayout.box.ndim nGhosts = coarseLayout.nbrGhostFor(qty) coarseStartIndex = coarseLayout.physicalStartIndices(qty) fineOffset = fineLayout.box.lower - boxm.refine(coarseLayout.box, 2).lower is_primal = [] for direction in directions[:ndim]: is_primal += [gridlayout.yee_element_is_primal(qty, direction)] def coarse_indices(dim): return np.arange(coarseBox.lower[dim], coarseBox.upper[dim] + 1) def fineLocal(coarse_index, dim): return fineLayout.AMRIndexToLocal(dim, coarse_index * refinement_ratio) def coarseLocal(index, dim): return coarseLayout.AMRIndexToLocal(dim, index) if ndim == 1: for index in coarse_indices(0): fineIndex = fineLocal(index, 0) coarseLocalIndex = coarseLocal(index, 0) if is_primal[0]: coarseData[coarseLocalIndex] = ( fineData[fineIndex - 1] * .25 + fineData[fineIndex] * .5 + fineData[fineIndex + 1] * .25 ) else: coarseData[coarseLocalIndex] = ( fineData[fineIndex] * .5 + fineData[fineIndex + 1] * .5 ) if ndim == 2: for indexX in coarse_indices(0): fineIndexX = fineLocal(indexX, 0) coarseLocalIndexX = coarseLocal(indexX, 0) for indexY in coarse_indices(1): fineIndexY = fineLocal(indexY, 1) coarseLocalIndexY = coarseLocal(indexY, 1) left, middle, right = 0, 0, 0 if all(is_primal): left += fineData[fineIndexX - 1][fineIndexY - 1] * .25 left += fineData[fineIndexX - 1][fineIndexY] * .5 left += fineData[fineIndexX - 1][fineIndexY + 1] * .25 middle += fineData[fineIndexX][fineIndexY - 1] * .25 middle += fineData[fineIndexX][fineIndexY] * .5 middle += fineData[fineIndexX][fineIndexY + 1] * .25 right += fineData[fineIndexX + 1][fineIndexY - 1] * .25 right += fineData[fineIndexX + 1][fineIndexY] * .5 right += fineData[fineIndexX + 1][fineIndexY + 1] * .25 coarseData[coarseLocalIndexX][coarseLocalIndexY] = ( left * .25 + middle * .5 + right * .25 ) if is_primal[0] and not is_primal[1]: left += fineData[fineIndexX - 1][fineIndexY] * .5 left += fineData[fineIndexX - 1][fineIndexY + 1] * .5 middle += fineData[fineIndexX][fineIndexY] * .5 middle += fineData[fineIndexX][fineIndexY + 1] * .5 right += fineData[fineIndexX + 1][fineIndexY] * .5 right += fineData[fineIndexX + 1][fineIndexY + 1] * .5 coarseData[coarseLocalIndexX][coarseLocalIndexY] = ( left * .25 + middle * .5 + right * .25 ) if not is_primal[0] and is_primal[1]: left += fineData[fineIndexX][fineIndexY - 1] * .25 left += fineData[fineIndexX][fineIndexY] * .5 left += fineData[fineIndexX][fineIndexY + 1] * .25 right += fineData[fineIndexX + 1][fineIndexY - 1] * .25 right += fineData[fineIndexX + 1][fineIndexY] * .5 right += fineData[fineIndexX + 1][fineIndexY + 1] * .25 coarseData[coarseLocalIndexX][coarseLocalIndexY] = (left * .5 + right * .5) if not any(is_primal): left += fineData[fineIndexX][fineIndexY] * .5 left += fineData[fineIndexX][fineIndexY + 1] * .5 right += fineData[fineIndexX + 1][fineIndexY] * .5 right += fineData[fineIndexX + 1][fineIndexY + 1] * .5 coarseData[coarseLocalIndexX][coarseLocalIndexY] = (left * .5 + right * .5)
def _test_field_coarsening_via_subcycles(self, dim, interp_order, refinement_boxes, **kwargs): print("test_field_coarsening_via_subcycles for dim/interp : {}/{}". format(dim, interp_order)) from tests.amr.data.field.coarsening.test_coarsen_field import coarsen from pyphare.pharein import global_vars time_step_nbr = 3 diag_outputs = f"subcycle_coarsening/{dim}/{interp_order}/{self.ddt_test_id()}" datahier = self.getHierarchy( interp_order, refinement_boxes, "eb", cells=60, diag_outputs=diag_outputs, time_step=0.001, extra_diag_options={"fine_dump_lvl_max": 10}, time_step_nbr=time_step_nbr, largest_patch_size=30, ndim=dim, **kwargs) lvl_steps = global_vars.sim.level_time_steps print("LEVELSTEPS === ", lvl_steps) assert len(lvl_steps) > 1, "this test makes no sense with only 1 level" finestTimeStep = lvl_steps[-1] secondFinestTimeStep = lvl_steps[-2] finest_level_step_nbr = global_vars.sim.level_step_nbr[-1] uniqTimes = set([0]) for step in range(1, finest_level_step_nbr + 1): checkTime = datahier.format_timestamp(finestTimeStep * step) self.assertIn(checkTime, datahier.times()) uniqTimes.add(checkTime) self.assertEqual(len(uniqTimes), len(datahier.time_hier.items())) syncSteps = global_vars.sim.level_step_nbr[ -2] # ignore finest subcycles # FIX THIS AFTER NO MORE REGRIDS # SEE: https://github.com/PHAREHUB/PHARE/issues/400 assert syncSteps % time_step_nbr == 0 # perfect division startStep = int( syncSteps / time_step_nbr) + 1 # skip first coarsest step due to issue 400 for step in range(startStep, syncSteps + 1): checkTime = datahier.format_timestamp(secondFinestTimeStep * step) self.assertIn(checkTime, datahier.times()) nLevels = datahier.levelNbr(checkTime) self.assertGreaterEqual(nLevels, 2) levelNbrs = datahier.levelNbrs(checkTime) finestLevelNbr = max(levelNbrs) coarsestLevelNbr = min(levelNbrs) for coarseLevelNbr in range(coarsestLevelNbr, finestLevelNbr): coarsePatches = datahier.level(coarseLevelNbr, checkTime).patches finePatches = datahier.level(coarseLevelNbr + 1, checkTime).patches for coarsePatch in coarsePatches: for finePatch in finePatches: lvlOverlap = boxm.refine(coarsePatch.box, 2) * finePatch.box if lvlOverlap is not None: for EM in ["E", "B"]: for xyz in ["x", "y", "z"]: qty = f"{EM}{xyz}" coarse_pd = coarsePatch.patch_datas[qty] fine_pd = finePatch.patch_datas[qty] coarseBox = boxm.coarsen(lvlOverlap, 2) coarse_pdDataset = coarse_pd.dataset[:] fine_pdDataset = fine_pd.dataset[:] coarseOffset = coarseBox.lower - coarse_pd.layout.box.lower dataBox_lower = coarseOffset + coarse_pd.layout.nbrGhostFor( qty) dataBox = Box( dataBox_lower, dataBox_lower + coarseBox.shape - 1) afterCoarse = np.copy(coarse_pdDataset) # change values that should be updated to make failure obvious assert (dim < 3) # update if dim == 1: afterCoarse[dataBox. lower[0]:dataBox.upper[0] + 1] = -144123 if dim == 2: afterCoarse[ dataBox.lower[0]:dataBox.upper[0] + 1, dataBox.lower[1]:dataBox.upper[1] + 1] = -144123 coarsen(qty, coarse_pd, fine_pd, coarseBox, fine_pdDataset, afterCoarse) np.testing.assert_allclose( coarse_pdDataset, afterCoarse, atol=1e-16, rtol=0)
def refine(field, **kwargs): """ optional kwargs data : for overriding the field dataset so you don't have to make a temporary copy of a field just to have a different dataset """ assert isinstance(field, FieldData) kwarg_keys = ["data"] assert any([key in kwarg_keys for key in list(kwargs.keys())]) refinement_ratio = 2 primal_directions = field.primal_directions() data = kwargs.get("data", field.dataset[:]) if "data" in kwargs: assert data.shape == field.dataset.shape fine_layout = GridLayout( boxm.refine(field.box, refinement_ratio), field.origin, field.layout.dl / refinement_ratio, interp_order=field.layout.interp_order, ) # fine box has extra ghosts for padding against coarser such that at the normal number of ghosts are filled fine_box = boxm.shrink(boxm.refine(field.ghost_box, refinement_ratio), field.ghosts_nbr) fine_data = np.zeros(fine_box.shape + primal_directions + (field.ghosts_nbr * 2)) ghostX = field.ghosts_nbr[0] assert ghostX > 1 cadence = 2 assert cadence == refinement_ratio gX = 2 # level 0 ghost buffer from edge of normal coarse data box rgX = 4 # level 1 ghost buffer from edge of extra large fine data box if field.box.ndim == 1: if primal_directions[0]: # coarse primal on top of fine fine_data[rgX:-rgX:cadence] = data[gX:-gX] fine_data[rgX + 1:-(rgX - 1):cadence] = (0.5 * data[gX:-gX] + 0.5 * data[gX + 1:-(gX - 1)]) else: fine_data[rgX:-(rgX + 1):cadence] = ( 0.25 * data[gX - 1:-(gX + 1)] + 0.75 * data[gX:-gX]) fine_data[rgX + 1:-(rgX - 1):cadence] = (0.25 * data[gX + 1:-(gX - 1)] + 0.75 * data[gX:-gX]) if fine_box.ndim > 1: assert field.ghosts_nbr[1] > 1 gY = 2 rgY = 4 cad = cadence if fine_box.ndim == 2: if all(primal_directions): fine_data[rgX:-rgX:cad, rgY:-rgY:cad] = data[gX:-gX, gY:-gY] fine_data[rgX + 1:-(rgX - 1):cad, rgY:-rgY:cad] = (0.5 * data[gX:-gX, gY:-gY] + 0.5 * data[gX + 1:-(gX - 1), gY:-gY]) fine_data[rgX:-rgX:cad, rgY + 1:-(rgY - 1):cad] = ( 0.5 * data[gX:-gX, gY:-gY] + 0.5 * data[gX:-gX, gY + 1:-(gY - 1)]) fine_data[rgX + 1:-(rgX - 1):cad, rgY + 1:-(rgY - 1):cad] = ( 0.25 * data[gX:-gX, gY:-gY] + 0.25 * data[gX + 1:-(gX - 1), gY:-gY] + 0.25 * data[gX:-gX, gY + 1:-(gY - 1)] + 0.25 * data[gX + 1:-(gX - 1), gY + 1:-(gY - 1)]) elif primal_directions[0] and not primal_directions[1]: fine_data[rgX:-rgX:cad, rgY:-rgY:cad] = (0.25 * data[gX:-gX, gY - 1:-(gY + 1)] + 0.75 * data[gX:-gX, gY:-gY]) fine_data[rgX + 1:-(rgX - 1):cad, rgY:-rgY:cad] = 0.75 * ( 0.5 * data[gX + 1:-(gX - 1), gY:-gY] + 0.5 * data[gX:-gX, gY:-gY]) + 0.25 * ( 0.5 * data[gX + 1:-(gX - 1), gY - 1:-(gY + 1)] + 0.5 * data[gX:-gX, gY - 1:-(gY + 1)]) fine_data[rgX:-rgX:cad, rgY + 1:-(rgY - 1):cad] = ( 0.25 * data[gX:-gX, gY + 1:-(gY - 1)] + 0.75 * data[gX:-gX, gY:-gY]) fine_data[rgX + 1:-(rgX - 1):cad, rgY + 1:-(rgY - 1):cad] = 0.75 * ( 0.5 * data[gX + 1:-(gX - 1), gY:-gY] + 0.5 * data[gX:-gX, gY:-gY]) + 0.25 * ( 0.5 * data[gX + 1:-(gX - 1), gY + 1:-(gY - 1)] + 0.5 * data[gX:-gX, gY + 1:-(gY - 1)]) elif not primal_directions[0] and primal_directions[1]: fine_data[rgX:-rgX:cad, rgY:-rgY:cad] = (0.25 * data[gX - 1:-(gX + 1), gY:-gY] + 0.75 * data[gX:-gX, gY:-gY]) fine_data[rgX + 1:-(rgX - 1):cad, rgY:-rgY:cad] = (0.25 * data[gX + 1:-(gX - 1), gY:-gY] + 0.75 * data[gX:-gX, gY:-gY]) fine_data[rgX:-rgX:cad, rgY + 1:-(rgY - 1):cad] = 0.5 * ( 0.25 * data[gX - 1:-(gX + 1), gY:-gY] + 0.75 * data[gX:-gX, gY:-gY]) + 0.5 * ( 0.25 * data[gX - 1:-(gX + 1), gY + 1:-(gY - 1)] + 0.75 * data[gX:-gX, gY + 1:-(gY - 1)]) fine_data[rgX + 1:-(rgX - 1):cad, rgY + 1:-(rgY - 1):cad] = 0.5 * ( 0.25 * data[gX + 1:-(gX - 1), gY:-gY] + 0.75 * data[gX:-gX, gY:-gY]) + 0.5 * ( 0.25 * data[gX + 1:-(gX - 1), gY + 1:-(gY - 1)] + 0.75 * data[gX:-gX, gY + 1:-(gY - 1)]) elif not any(primal_directions): fine_data[rgX:-rgX:cad, rgY:-rgY:cad] = 0.75 * ( 0.25 * data[gX - 1:-(gX + 1), gY:-gY] + 0.75 * data[gX:-gX, gY:-gY]) + 0.25 * ( 0.25 * data[gX - 1:-(gX + 1), gY - 1:-(gY + 1)] + 0.75 * data[gX:-gX, gY - 1:-(gY + 1)]) fine_data[rgX + 1:-(rgX - 1):cad, rgY:-rgY:cad] = 0.75 * ( 0.25 * data[gX + 1:-(gX - 1), gY:-gY] + 0.75 * data[gX:-gX, gY:-gY]) + 0.25 * ( 0.25 * data[gX + 1:-(gX - 1), gY - 1:-(gY + 1)] + 0.75 * data[gX:-gX, gY - 1:-(gY + 1)]) fine_data[rgX:-rgX:cad, rgY + 1:-(rgY - 1):cad] = 0.75 * ( 0.25 * data[gX - 1:-(gX + 1), gY:-gY] + 0.75 * data[gX:-gX, gY:-gY]) + 0.25 * ( 0.25 * data[gX - 1:-(gX + 1), gY + 1:-(gY - 1)] + 0.75 * data[gX:-gX, gY + 1:-(gY - 1)]) fine_data[rgX + 1:-(rgX - 1):cad, rgY + 1:-(rgY - 1):cad] = 0.75 * ( 0.25 * data[gX + 1:-(gX - 1), gY:-gY] + 0.75 * data[gX:-gX, gY:-gY]) + 0.25 * ( 0.25 * data[gX + 1:-(gX - 1), gY + 1:-(gY - 1)] + 0.75 * data[gX:-gX, gY + 1:-(gY - 1)]) # the fine data is ghost_nbr larger than expected to include ghost values from the coarser, so we drop the outer values if field.box.ndim == 1: fine_data = fine_data[field.ghosts_nbr[0]:-field.ghosts_nbr[0]] elif field.box.ndim == 2: fine_data = fine_data[field.ghosts_nbr[0]:-field.ghosts_nbr[0], field.ghosts_nbr[1]:-field.ghosts_nbr[1], ] elif field.box.ndim == 3: fine_data = fine_data[field.ghosts_nbr[0]:-field.ghosts_nbr[0], field.ghosts_nbr[1]:-field.ghosts_nbr[1], field.ghosts_nbr[2]:-field.ghosts_nbr[2], ] return FieldData(fine_layout, field.field_name, data=fine_data)