Пример #1
0
    def init_callback(self, boundary_data, **_):
        dim = boundary_data.dim
        coord_names = ['x', 'y', 'z'][:dim]
        pdf_acc = AccessPdfValues(self.stencil, streaming_pattern=self.streaming_pattern,
                                  timestep=self.zeroth_timestep, streaming_dir='out')

        def get_boundary_cell_pdfs(f_cell, b_cell, direction):
            if self.equilibrium_calculation is not None:
                density = self.initial_density(
                    *b_cell) if callable(self.initial_density) else self.initial_density
                velocity = self.initial_velocity(
                    *b_cell) if callable(self.initial_velocity) else self.initial_velocity
                return self.equilibrium_calculation(density, velocity, direction)
            else:
                return pdf_acc.read_pdf(boundary_data.pdf_array, f_cell, direction)

        for entry in boundary_data.index_array:
            center = tuple(entry[c] for c in coord_names)
            direction = self.stencil[entry["dir"]]
            inv_dir = self.stencil.index(inverse_direction(direction))
            tangential_offset = tuple(offset - normal for offset, normal in zip(direction, self.normal_direction))
            domain_cell = tuple(f + o for f, o in zip(center, tangential_offset))
            outflow_cell = tuple(f + o for f, o in zip(center, direction))

            #   Initial fluid cell PDF values
            entry['pdf'] = pdf_acc.read_pdf(boundary_data.pdf_array, domain_cell, inv_dir)
            entry['pdf_nd'] = get_boundary_cell_pdfs(domain_cell, outflow_cell, inv_dir)
Пример #2
0
 def read(field, stencil):
     res = []
     for i, d in enumerate(stencil):
         inv_dir = inverse_direction(d)
         field_access = field[inv_dir](stencil.index(inv_dir))
         res.append(field_access)
     return res
Пример #3
0
 def write(field, stencil):
     result = []
     for direction in stencil:
         inv_dir = inverse_direction(direction)
         spatial_offset = tuple(max(e, 0) for e in direction)
         result.append(field[spatial_offset](stencil.index(inv_dir)))
     return result
Пример #4
0
    def read(self, field, stencil):
        result = []
        for i, d in enumerate(stencil):
            pull_direction = inverse_direction(d)
            periodic_pull_direction = []
            for coord_id, dir_element in enumerate(pull_direction):
                if not self._periodicity[coord_id]:
                    periodic_pull_direction.append(dir_element)
                    continue

                lower_limit = self._ghostLayers
                upper_limit = field.spatial_shape[
                    coord_id] - 1 - self._ghostLayers
                limit_diff = upper_limit - lower_limit
                loop_counter = LoopOverCoordinate.get_loop_counter_symbol(
                    coord_id)
                if dir_element == 0:
                    periodic_pull_direction.append(0)
                elif dir_element == 1:
                    new_dir_element = sp.Piecewise(
                        (dir_element, loop_counter < upper_limit),
                        (-limit_diff, True))
                    periodic_pull_direction.append(new_dir_element)
                elif dir_element == -1:
                    new_dir_element = sp.Piecewise(
                        (dir_element, loop_counter > lower_limit),
                        (limit_diff, True))
                    periodic_pull_direction.append(new_dir_element)
                else:
                    raise NotImplementedError(
                        "This accessor supports only nearest neighbor stencils"
                    )
            result.append(field[tuple(periodic_pull_direction)](i))
        return result
Пример #5
0
def boundary_substitutions(lb_method):
    stencil = lb_method.stencil
    w = lb_method.weights
    replacements = {}
    for idx, offset in enumerate(stencil):
        symbolic_offset = BoundaryOffsetInfo.offset_from_dir(idx,
                                                             dim=lb_method.dim)
        for sym, value in zip(symbolic_offset, offset):
            replacements[sym] = value

        replacements[BoundaryOffsetInfo.inv_dir(idx)] = stencil.index(
            inverse_direction(offset))
        replacements[LbmWeightInfo.weight_of_direction(idx)] = w[idx]
    return replacements
Пример #6
0
def generate_pack_info_from_kernel(generation_context,
                                   class_name: str,
                                   assignments: Sequence[Assignment],
                                   kind='pull',
                                   **create_kernel_params):
    """Generates a waLBerla GPU PackInfo from a (pull) kernel.

    Args:
        generation_context: see documentation of `generate_sweep`
        class_name: name of the generated class
        assignments: list of assignments from the compute kernel - generates PackInfo for "pull" part only
                     i.e. the kernel is expected to only write to the center
        kind:                      
        **create_kernel_params: remaining keyword arguments are passed to `pystencils.create_kernel`
    """
    assert kind in ('push', 'pull')
    reads = set()
    writes = set()

    if isinstance(assignments, AssignmentCollection):
        assignments = assignments.all_assignments

    for a in assignments:
        if not isinstance(a, Assignment):
            continue
        reads.update(a.rhs.atoms(Field.Access))
        writes.update(a.lhs.atoms(Field.Access))
    spec = defaultdict(set)
    if kind == 'pull':
        for fa in reads:
            assert all(abs(e) <= 1 for e in fa.offsets)
            if all(offset == 0 for offset in fa.offsets):
                continue
            comm_direction = inverse_direction(fa.offsets)
            for comm_dir in comm_directions(comm_direction):
                spec[(comm_dir, )].add(fa.field.center(*fa.index))
    elif kind == 'push':
        for fa in writes:
            assert all(abs(e) <= 1 for e in fa.offsets)
            if all(offset == 0 for offset in fa.offsets):
                continue
            for comm_dir in comm_directions(fa.offsets):
                spec[(comm_dir, )].add(fa)
    else:
        raise ValueError("Invalid 'kind' parameter")
    return generate_pack_info(generation_context, class_name, spec,
                              **create_kernel_params)
Пример #7
0
def test_extrapolation_outflow_initialization_by_copy():
    stencil = LBStencil(Stencil.D2Q9)
    domain_size = (1, 5)

    streaming_pattern = 'esotwist'
    zeroth_timestep = 'even'

    pdf_acc = AccessPdfValues(stencil,
                              streaming_pattern=streaming_pattern,
                              timestep=zeroth_timestep,
                              streaming_dir='out')

    dh = create_data_handling(domain_size, default_target=Target.CPU)
    lb_method = create_lb_method(stencil=stencil)
    pdf_field = dh.add_array('f', values_per_cell=stencil.Q)
    dh.fill(pdf_field.name, np.nan, ghost_layers=True)
    pdf_arr = dh.cpu_arrays[pdf_field.name]
    bh = LatticeBoltzmannBoundaryHandling(lb_method,
                                          dh,
                                          pdf_field.name,
                                          streaming_pattern=streaming_pattern,
                                          target=Target.CPU)

    for y in range(1, 6):
        for j in range(stencil.Q):
            pdf_acc.write_pdf(pdf_arr, (1, y), j, j)

    normal_dir = (1, 0)
    outflow = ExtrapolationOutflow(normal_dir,
                                   lb_method,
                                   streaming_pattern=streaming_pattern,
                                   zeroth_timestep=zeroth_timestep)
    boundary_slice = get_ghost_region_slice(normal_dir)
    bh.set_boundary(outflow, boundary_slice)
    bh.prepare()

    blocks = list(dh.iterate())
    index_list = blocks[0][
        bh._index_array_name].boundary_object_to_index_list[outflow]
    assert len(index_list) == 13
    for entry in index_list:
        direction = stencil[entry["dir"]]
        inv_dir = stencil.index(inverse_direction(direction))
        assert entry[f'pdf'] == inv_dir
        assert entry[f'pdf_nd'] == inv_dir
Пример #8
0
    def _force_on_boundary(self, boundary_obj, prev_timestep):
        dh = self._data_handling
        ff_ghost_layers = dh.ghost_layers_of_field(
            self.flag_interface.flag_field_name)
        method = self._lb_method
        stencil = np.array(method.stencil)
        inv_direction = np.array([
            method.stencil.index(inverse_direction(d)) for d in method.stencil
        ])
        result = np.zeros(self.dim)

        for b in dh.iterate(ghost_layers=ff_ghost_layers):
            obj_to_ind_list = b[
                self._index_array_name].boundary_object_to_index_list
            pdf_array = b[self._field_name]
            if boundary_obj in obj_to_ind_list:
                ind_arr = obj_to_ind_list[boundary_obj]
                inverse_ind_arr = ind_arr.copy()
                inverse_ind_arr['dir'] = inv_direction[inverse_ind_arr['dir']]
                acc_out = AccessPdfValues(
                    self._lb_method.stencil,
                    streaming_pattern=self._streaming_pattern,
                    timestep=prev_timestep,
                    streaming_dir='out')
                acc_in = AccessPdfValues(
                    self._lb_method.stencil,
                    streaming_pattern=self._streaming_pattern,
                    timestep=prev_timestep.next(),
                    streaming_dir='in')
                acc_fluid = acc_out if boundary_obj.inner_or_boundary else acc_in
                acc_boundary = acc_in if boundary_obj.inner_or_boundary else acc_out
                fluid_values = acc_fluid.collect_from_index_list(
                    pdf_array, ind_arr)
                boundary_values = acc_boundary.collect_from_index_list(
                    pdf_array, inverse_ind_arr)
                values = fluid_values + boundary_values
                forces = stencil[ind_arr['dir']] * values[:, np.newaxis]
                result += forces.sum(axis=0)

        return dh.reduce_float_sequence(list(result), 'sum')
Пример #9
0
def test_extrapolation_outflow_initialization_by_callback():
    stencil = LBStencil(Stencil.D2Q9)
    domain_size = (1, 5)

    streaming_pattern = 'esotwist'
    zeroth_timestep = 'even'

    dh = create_data_handling(domain_size, default_target=Target.CPU)
    lb_method = create_lb_method(stencil=stencil)
    pdf_field = dh.add_array('f', values_per_cell=stencil.Q)
    dh.fill(pdf_field.name, np.nan, ghost_layers=True)
    bh = LatticeBoltzmannBoundaryHandling(lb_method,
                                          dh,
                                          pdf_field.name,
                                          streaming_pattern=streaming_pattern,
                                          target=Target.CPU)

    normal_dir = (1, 0)
    outflow = ExtrapolationOutflow(normal_direction=normal_dir,
                                   lb_method=lb_method,
                                   streaming_pattern=streaming_pattern,
                                   zeroth_timestep=zeroth_timestep,
                                   initial_density=lambda x, y: 1,
                                   initial_velocity=lambda x, y: (0, 0))
    boundary_slice = get_ghost_region_slice(normal_dir)
    bh.set_boundary(outflow, boundary_slice)
    bh.prepare()

    weights = [w.evalf() for w in lb_method.weights]

    blocks = list(dh.iterate())
    index_list = blocks[0][
        bh._index_array_name].boundary_object_to_index_list[outflow]
    assert len(index_list) == 13
    for entry in index_list:
        direction = stencil[entry["dir"]]
        inv_dir = stencil.index(inverse_direction(direction))
        assert entry[f'pdf_nd'] == weights[inv_dir]
Пример #10
0
    def init_callback(self, boundary_data, **_):
        if len(boundary_data.index_array) > 1e6:
            warn(f"The calculation of the normal direction for each cell might take a long time, because "
                 f"{len(boundary_data.index_array)} cells are marked as Free Slip boundary cells. Consider specifying "
                 f" the normal direction beforehand, which is possible if it is equal for all cells (e.g. at a wall)")

        dim = boundary_data.dim
        coords = [coord for coord, _ in zip(['x', 'y', 'z'], range(dim))]

        boundary_cells = set()

        # get a set containing all boundary cells
        for cell in boundary_data.index_array:
            fluid_cell = tuple([cell[coord] for coord in coords])
            direction = self.stencil[cell['dir']]
            boundary_cell = tuple([i + d for i, d in zip(fluid_cell, direction)])
            boundary_cells.add(boundary_cell)

        for cell in boundary_data.index_array:
            fluid_cell = tuple([cell[coord] for coord in coords])
            direction = self.stencil[cell['dir']]
            ref_direction = direction
            normal_direction = [0] * dim

            for i in range(dim):
                sub_direction = [0] * dim
                sub_direction[i] = direction[i]
                test_cell = tuple([x + y for x, y in zip(fluid_cell, sub_direction)])

                if test_cell in boundary_cells:
                    normal_direction[i] = direction[i]
                    ref_direction = MirroredStencilDirections.mirror_stencil(ref_direction, i)

            ref_direction = inverse_direction(ref_direction)
            for i, cell_name in zip(range(dim), self.additional_data):
                cell[cell_name[0]] = -normal_direction[i]
            cell['ref_dir'] = self.stencil.index(ref_direction)
Пример #11
0
def test_free_slip_index_list():
    stencil = LBStencil(Stencil.D2Q9)
    dh = create_data_handling(domain_size=(4, 4), periodicity=(False, False))
    src = dh.add_array('src', values_per_cell=len(stencil), alignment=True)
    dh.fill('src', 0.0, ghost_layers=True)

    lbm_config = LBMConfig(stencil=stencil,
                           method=Method.SRT,
                           relaxation_rate=1.8)
    method = create_lb_method(lbm_config=lbm_config)

    bh = LatticeBoltzmannBoundaryHandling(method, dh, 'src', name="bh")

    free_slip = FreeSlip(stencil=stencil)
    add_box_boundary(bh, free_slip)

    bh.prepare()
    for b in dh.iterate():
        for b_obj, idx_arr in b[
                bh._index_array_name].boundary_object_to_index_list.items():
            index_array = idx_arr

    # normal directions
    normal_west = (1, 0)
    normal_east = (-1, 0)
    normal_south = (0, 1)
    normal_north = (0, -1)

    normal_south_west = (1, 1)
    normal_north_west = (1, -1)
    normal_south_east = (-1, 1)
    normal_north_east = (-1, -1)

    for cell in index_array:
        direction = stencil[cell[2]]
        inv_dir = inverse_direction(direction)

        boundary_cell = (cell[0] + direction[0], cell[1] + direction[1])
        normal = (cell[3], cell[4])
        # the data is written on the inverse direction of the fluid cell near the boundary
        # the data is read from the mirrored direction of the inverse direction where the mirror axis is the normal
        assert cell[5] == stencil.index(mirror_stencil(list(inv_dir), normal))

        if boundary_cell[0] == 0 and 0 < boundary_cell[1] < 5:
            assert normal == normal_west

        if boundary_cell[0] == 5 and 0 < boundary_cell[1] < 5:
            assert normal == normal_east

        if 0 < boundary_cell[0] < 5 and boundary_cell[1] == 0:
            assert normal == normal_south

        if 0 < boundary_cell[0] < 5 and boundary_cell[1] == 5:
            assert normal == normal_north

        if boundary_cell == (0, 0):
            assert cell[2] == cell[5]
            assert normal == normal_south_west

        if boundary_cell == (5, 0):
            assert cell[2] == cell[5]
            assert normal == normal_south_east

        if boundary_cell == (0, 5):
            assert cell[2] == cell[5]
            assert normal == normal_north_west

        if boundary_cell == (5, 5):
            assert cell[2] == cell[5]
            assert normal == normal_north_east
Пример #12
0
 def read(field, stencil):
     return [field[inverse_direction(d)](i) for i, d in enumerate(stencil)]
Пример #13
0
 def write(field, stencil):
     return [field(stencil.index(inverse_direction(d))) for d in stencil]
Пример #14
0
def generate_mpidtype_info_from_kernel(
    generation_context,
    class_name: str,
    assignments: Sequence[Assignment],
    kind='pull',
    namespace='pystencils',
):
    assert kind in ('push', 'pull')
    reads = set()
    writes = set()

    if isinstance(assignments, AssignmentCollection):
        assignments = assignments.all_assignments

    for a in assignments:
        if not isinstance(a, Assignment):
            continue
        reads.update(a.rhs.atoms(Field.Access))
        writes.update(a.lhs.atoms(Field.Access))

    spec = defaultdict(set)
    if kind == 'pull':
        read_fields = set(fa.field for fa in reads)
        assert len(
            read_fields
        ) == 1, "Only scenarios where one fields neighbors are accessed"
        field = read_fields.pop()
        for fa in reads:
            assert all(abs(e) <= 1 for e in fa.offsets)
            if all(offset == 0 for offset in fa.offsets):
                continue
            comm_direction = inverse_direction(fa.offsets)
            for comm_dir in comm_directions(comm_direction):
                assert len(
                    fa.index
                ) == 1, "Supports only fields with a single index dimension"
                spec[(offset_to_direction_string(comm_dir), )].add(fa.index[0])
    elif kind == 'push':
        written_fields = set(fa.field for fa in writes)
        assert len(
            written_fields
        ) == 1, "Only scenarios where one fields neighbors are accessed"
        field = written_fields.pop()

        for fa in writes:
            assert all(abs(e) <= 1 for e in fa.offsets)
            if all(offset == 0 for offset in fa.offsets):
                continue
            for comm_dir in comm_directions(fa.offsets):
                assert len(
                    fa.index
                ) == 1, "Supports only fields with a single index dimension"
                spec[(offset_to_direction_string(comm_dir), )].add(fa.index[0])
    else:
        raise ValueError("Invalid 'kind' parameter")

    jinja_context = {
        'class_name': class_name,
        'namespace': namespace,
        'kind': kind,
        'field_name': field.name,
        'f_size': field.index_shape[0],
        'spec': spec,
    }
    env = Environment(loader=PackageLoader('pystencils_walberla'),
                      undefined=StrictUndefined)
    header = env.get_template("MpiDtypeInfo.tmpl.h").render(**jinja_context)
    generation_context.write_file("{}.h".format(class_name), header)