예제 #1
0
def coarse_to_fine_node_map(coarse, fine):
    if len(coarse) > 1:
        assert len(fine) == len(coarse)
        return op2.MixedMap(coarse_to_fine_node_map(c, f) for c, f in zip(coarse, fine))
    mesh = coarse.mesh()
    assert hasattr(mesh, "_shared_data_cache")
    if not (coarse.ufl_element() == fine.ufl_element()):
        raise ValueError("Can't transfer between different spaces")
    ch, level = get_level(mesh)
    fh, fine_level = get_level(fine.mesh())
    if ch is not fh:
        raise ValueError("Can't map between different hierarchies")
    refinements_per_level = ch.refinements_per_level
    if refinements_per_level*level + 1 != refinements_per_level*fine_level:
        raise ValueError("Can't map between level %s and level %s" % (level, fine_level))
    c2f, vperm = ch._cells_vperm[int(level*refinements_per_level)]

    key = entity_dofs_key(coarse.fiat_element.entity_dofs()) + (level, )
    cache = mesh._shared_data_cache["hierarchy_cell_node_map"]
    try:
        return cache[key]
    except KeyError:
        from .impl import create_cell_node_map
        map_vals, offset = create_cell_node_map(coarse, fine, c2f, vperm)
        return cache.setdefault(key, op2.Map(op2.LocalSet(mesh.cell_set),
                                             fine.node_set,
                                             map_vals.shape[1],
                                             map_vals, offset=offset))
예제 #2
0
def get_restriction_weights(coarse, fine):
    mesh = coarse.mesh()
    assert hasattr(mesh, "_shared_data_cache")
    cache = mesh._shared_data_cache["hierarchy_restriction_weights"]
    key = entity_dofs_key(coarse.fiat_element.entity_dofs())
    try:
        return cache[key]
    except KeyError:
        # We hit each fine dof more than once since we loop
        # elementwise over the coarse cells.  So we need a count of
        # how many times we did this to weight the final contribution
        # appropriately.
        if not (coarse.ufl_element() == fine.ufl_element()):
            raise ValueError("Can't transfer between different spaces")
        if coarse.fiat_element.entity_dofs() == coarse.fiat_element.entity_closure_dofs():
            return cache.setdefault(key, None)
        ele = coarse.ufl_element()
        if isinstance(ele, ufl.VectorElement):
            ele = ele.sub_elements()[0]
            weights = firedrake.Function(firedrake.FunctionSpace(fine.mesh(), ele))
        else:
            weights = firedrake.Function(fine)
        c2f_map = coarse_to_fine_node_map(coarse, fine)
        kernel = get_count_kernel(c2f_map.arity)
        op2.par_loop(kernel, op2.LocalSet(mesh.cell_set),
                     weights.dat(op2.INC, c2f_map[op2.i[0]]))
        weights.assign(1/weights)
        return cache.setdefault(key, weights)
예제 #3
0
    def __init__(self, mesh_hierarchy, fses):
        """
        Build a hierarchy of function spaces

        :arg mesh_hierarchy: a :class:`~.MeshHierarchy` on which to
             build the function spaces.
        :arg fses: an iterable of :class:`~.FunctionSpace`\s.
        """
        self._mesh_hierarchy = mesh_hierarchy
        self._hierarchy = tuple(
            [set_level(fs, self, lvl) for lvl, fs in enumerate(fses)])
        self._map_cache = {}
        self._cell_sets = tuple(
            op2.LocalSet(m.cell_set) for m in self._mesh_hierarchy)
        self._ufl_element = self[0].ufl_element()
        self._restriction_weights = None
        fiat_element = fses[0].fiat_element
        ncelldof = len(
            fiat_element.entity_dofs()[fses[0].mesh().cell_dimension()][0])
        self._discontinuous = ncelldof == fses[0].cell_node_map().arity
        try:
            element = self[0].fiat_element
            omap = self[1].cell_node_map().values
            c2f, vperm = self._mesh_hierarchy._cells_vperm[0]
            indices, _ = utils.get_unique_indices(element,
                                                  omap[c2f[0, :],
                                                       ...].reshape(-1),
                                                  vperm[0, :],
                                                  offset=None)
            self._prolong_kernel = utils.get_prolongation_kernel(
                element, indices, self.dim)
            self._restrict_kernel = utils.get_restriction_kernel(
                element, indices, self.dim, no_weights=self._discontinuous)
            self._inject_kernel = utils.get_injection_kernel(
                element, indices, self.dim)
        except:
            pass

        for V in self:
            dm = V._dm
            dm.setCoarsen(coarsen)
            dm.setRefine(refine)