Пример #1
0
    def __init__(self, mesh, conditions, timestepping, params, output, solver_params):

        self.timestepping = timestepping
        self.timestep = timestepping.timestep
        self.timescale = timestepping.timescale
        self.params = params
        if output is None:
            raise RuntimeError("You must provide a directory name for dumping results")
        else:
            self.output = output
        self.outfile = File(output.dirname)
        self.dump_count = 0
        self.dump_freq = output.dumpfreq
        self.solver_params = solver_params
        self.mesh = mesh
        self.conditions = conditions

        if conditions.steady_state == True:
            self.ind = 1
        else:
            self.ind = 1
        
        family = conditions.family
        self.x, self.y = SpatialCoordinate(mesh)
        self.n = FacetNormal(mesh)
        self.V = VectorFunctionSpace(mesh, family, conditions.order + 1)
        self.U = FunctionSpace(mesh, family, conditions.order + 1)
        self.U1 = FunctionSpace(mesh, 'DG', conditions.order)
        self.S = TensorFunctionSpace(mesh, 'DG', conditions.order)
        self.D = FunctionSpace(mesh, 'DG', 0)
        self.W1 = MixedFunctionSpace([self.V, self.S])
        self.W2 = MixedFunctionSpace([self.V, self.U1, self.U1])
        self.W3 = MixedFunctionSpace([self.V, self.S, self.U1, self.U1])
Пример #2
0
    def _prepare_output(self, function, cg):
        from firedrake import FunctionSpace, VectorFunctionSpace, \
            TensorFunctionSpace, Function, Projector, Interpolator

        name = function.name()

        # Need to project/interpolate?
        # If space is linear and continuity of output space matches
        # continuity of current space, then we can just use the
        # input function.
        if is_linear(function.function_space()) and \
           is_dg(function.function_space()) == (not cg) and \
           is_cg(function.function_space()) == cg:
            return OFunction(array=get_array(function),
                             name=name, function=function)

        # OK, let's go and do it.
        if cg:
            family = "Lagrange"
        else:
            family = "Discontinuous Lagrange"

        output = self._output_functions.get(function)
        if output is None:
            # Build appropriate space for output function.
            shape = function.ufl_shape
            if len(shape) == 0:
                V = FunctionSpace(function.ufl_domain(), family, 1)
            elif len(shape) == 1:
                if numpy.prod(shape) > 3:
                    raise ValueError("Can't write vectors with more than 3 components")
                V = VectorFunctionSpace(function.ufl_domain(), family, 1,
                                        dim=shape[0])
            elif len(shape) == 2:
                if numpy.prod(shape) > 9:
                    raise ValueError("Can't write tensors with more than 9 components")
                V = TensorFunctionSpace(function.ufl_domain(), family, 1,
                                        shape=shape)
            else:
                raise ValueError("Unsupported shape %s" % (shape, ))
            output = Function(V)
            self._output_functions[function] = output

        if self.project:
            projector = self._mappers.get(function)
            if projector is None:
                projector = Projector(function, output)
                self._mappers[function] = projector
            projector.project()
        else:
            interpolator = self._mappers.get(function)
            if interpolator is None:
                interpolator = Interpolator(function, output)
                self._mappers[function] = interpolator
            interpolator.interpolate()

        return OFunction(array=get_array(output), name=name, function=output)
Пример #3
0
    def _prepare_output(self, function, max_elem):
        from firedrake import FunctionSpace, VectorFunctionSpace, \
            TensorFunctionSpace, Function, Projector, Interpolator

        name = function.name()
        # Need to project/interpolate?
        # If space is not the max element, we can do so.
        if function.ufl_element == max_elem:
            return OFunction(array=get_array(function),
                             name=name,
                             function=function)
        #  OK, let's go and do it.
        shape = function.ufl_shape
        output = self._output_functions.get(function)
        if output is None:
            # Build appropriate space for output function.
            shape = function.ufl_shape
            if len(shape) == 0:
                V = FunctionSpace(function.ufl_domain(), max_elem)
            elif len(shape) == 1:
                if numpy.prod(shape) > 3:
                    raise ValueError(
                        "Can't write vectors with more than 3 components")
                V = VectorFunctionSpace(function.ufl_domain(),
                                        max_elem,
                                        dim=shape[0])
            elif len(shape) == 2:
                if numpy.prod(shape) > 9:
                    raise ValueError(
                        "Can't write tensors with more than 9 components")
                V = TensorFunctionSpace(function.ufl_domain(),
                                        max_elem,
                                        shape=shape)
            else:
                raise ValueError("Unsupported shape %s" % (shape, ))
            output = Function(V)
            self._output_functions[function] = output
        if self.project:
            projector = self._mappers.get(function)
            if projector is None:
                projector = Projector(function, output)
                self._mappers[function] = projector
            projector.project()
        else:
            interpolator = self._mappers.get(function)
            if interpolator is None:
                interpolator = Interpolator(function, output)
                self._mappers[function] = interpolator
            interpolator.interpolate()

        return OFunction(array=get_array(output), name=name, function=output)
Пример #4
0
    def _prepare_output(self, function, max_elem):
        from firedrake import FunctionSpace, VectorFunctionSpace, \
            TensorFunctionSpace, Function
        from tsfc.finatinterface import create_element as create_finat_element

        name = function.name()
        # Need to project/interpolate?
        # If space is not the max element, we must do so.
        finat_elem = function.function_space().finat_element
        if finat_elem == create_finat_element(max_elem):
            return OFunction(array=get_array(function),
                             name=name,
                             function=function)
        #  OK, let's go and do it.
        # Build appropriate space for output function.
        shape = function.ufl_shape
        if len(shape) == 0:
            V = FunctionSpace(function.ufl_domain(), max_elem)
        elif len(shape) == 1:
            if numpy.prod(shape) > 3:
                raise ValueError(
                    "Can't write vectors with more than 3 components")
            V = VectorFunctionSpace(function.ufl_domain(),
                                    max_elem,
                                    dim=shape[0])
        elif len(shape) == 2:
            if numpy.prod(shape) > 9:
                raise ValueError(
                    "Can't write tensors with more than 9 components")
            V = TensorFunctionSpace(function.ufl_domain(),
                                    max_elem,
                                    shape=shape)
        else:
            raise ValueError("Unsupported shape %s" % (shape, ))
        output = Function(V)
        if self.project:
            output.project(function)
        else:
            output.interpolate(function)

        return OFunction(array=get_array(output), name=name, function=output)
Пример #5
0
    def setup(self, state):
        if not self._initialised:
            mesh_dim = state.mesh.geometric_dimension()
            try:
                field_dim = state.fields(self.fname).ufl_shape[0]
            except IndexError:
                field_dim = 1
            shape = (mesh_dim, ) * field_dim
            space = TensorFunctionSpace(state.mesh, "CG", 1, shape=shape)
            super().setup(state, space=space)

        f = state.fields(self.fname)
        test = TestFunction(space)
        trial = TrialFunction(space)
        n = FacetNormal(state.mesh)
        a = inner(test, trial)*dx
        L = -inner(div(test), f)*dx
        if space.extruded:
            L += dot(dot(test, n), f)*(ds_t + ds_b)
        prob = LinearVariationalProblem(a, L, self.field)
        self.solver = LinearVariationalSolver(prob)
Пример #6
0
    def firedrake_fspace(self, shape=None):
        """
        Return a firedrake function space that
        *self.discr.groups[self.group_nr]* is connected to
        of the appropriate vector dimension

        :arg shape: Either *None*, in which case a function space which maps
                   to scalar values is returned, a positive integer *n*,
                   in which case a function space which maps into *\\R^n*
                   is returned, or a tuple of integers defining
                   the shape of values in a tensor function space,
                   in which case a tensor function space is returned
        :return: A :class:`firedrake.functionspaceimpl.WithGeometry` which
                corresponds to *self.discr.groups[self.group_nr]* of the appropriate
                vector dimension

        :raises TypeError: If *shape* is of the wrong type
        """
        if shape is None:
            from firedrake import FunctionSpace
            return FunctionSpace(self._mesh_geometry,
                                 self._ufl_element.family(),
                                 degree=self._ufl_element.degree())
        elif isinstance(shape, int):
            from firedrake import VectorFunctionSpace
            return VectorFunctionSpace(self._mesh_geometry,
                                       self._ufl_element.family(),
                                       degree=self._ufl_element.degree(),
                                       dim=shape)
        elif isinstance(shape, tuple):
            from firedrake import TensorFunctionSpace
            return TensorFunctionSpace(self._mesh_geometry,
                                       self._ufl_element.family(),
                                       degree=self._ufl_element.degree(),
                                       shape=shape)
        else:
            raise TypeError("'shape' must be *None*, an integer, "
                            " or a tuple of integers, not of type '%s'."
                            % type(shape))
Пример #7
0
def test_from_fd_idempotency(ctx_factory, fdrake_mesh, fspace_degree,
                             fspace_type, only_convert_bdy):
    """
    Make sure fd->mm->fd and (fd->)->mm->fd->mm are identity
    """
    # Make a function space and a function with unique values at each node
    if fspace_type == "scalar":
        fdrake_fspace = FunctionSpace(fdrake_mesh, "DG", fspace_degree)
        # Just use the node nr
        fdrake_unique = Function(fdrake_fspace)
        fdrake_unique.dat.data[:] = np.arange(fdrake_unique.dat.data.shape[0])
    elif fspace_type == "vector":
        fdrake_fspace = VectorFunctionSpace(fdrake_mesh, "DG", fspace_degree)
        # use the coordinates
        xx = SpatialCoordinate(fdrake_fspace.mesh())
        fdrake_unique = Function(fdrake_fspace).interpolate(xx)
    elif fspace_type == "tensor":
        fdrake_fspace = TensorFunctionSpace(fdrake_mesh, "DG", fspace_degree)
        # use the coordinates, duplicated into the right tensor shape
        xx = SpatialCoordinate(fdrake_fspace.mesh())
        dim = fdrake_fspace.mesh().geometric_dimension()
        unique_expr = as_tensor([xx for _ in range(dim)])
        fdrake_unique = Function(fdrake_fspace).interpolate(unique_expr)

    # Make connection
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    # If only converting boundary, first go ahead and do one round of
    # fd->mm->fd. This will zero out any degrees of freedom absent in
    # the meshmode mesh (because they are not associated to cells
    #                    with >= 1 node on the boundary)
    #
    # Otherwise, just continue as normal
    if only_convert_bdy:
        fdrake_connection = \
            build_connection_from_firedrake(actx,
                                            fdrake_fspace,
                                            restrict_to_boundary="on_boundary")
        temp = fdrake_connection.from_firedrake(fdrake_unique, actx=actx)
        fdrake_unique = fdrake_connection.from_meshmode(temp)
    else:
        fdrake_connection = build_connection_from_firedrake(
            actx, fdrake_fspace)

    # Test for idempotency fd->mm->fd
    mm_field = fdrake_connection.from_firedrake(fdrake_unique, actx=actx)
    fdrake_unique_copy = Function(fdrake_fspace)
    fdrake_connection.from_meshmode(mm_field, out=fdrake_unique_copy)

    np.testing.assert_allclose(fdrake_unique_copy.dat.data,
                               fdrake_unique.dat.data,
                               atol=CLOSE_ATOL)

    # Test for idempotency (fd->)mm->fd->mm
    mm_field_copy = fdrake_connection.from_firedrake(fdrake_unique_copy,
                                                     actx=actx)
    if fspace_type == "scalar":
        np.testing.assert_allclose(actx.to_numpy(mm_field_copy[0]),
                                   actx.to_numpy(mm_field[0]),
                                   atol=CLOSE_ATOL)
    else:
        for dof_arr_cp, dof_arr in zip(mm_field_copy.flatten(),
                                       mm_field.flatten()):
            np.testing.assert_allclose(actx.to_numpy(dof_arr_cp[0]),
                                       actx.to_numpy(dof_arr[0]),
                                       atol=CLOSE_ATOL)
Пример #8
0
def run_method(trial,
               method,
               cl_ctx=None,
               queue=None,
               clear_memoized_objects=False,
               true_sol_name="True Solution",
               comp_sol_name="Computed Solution",
               **kwargs):
    """
        Returns (true solution, computed solution, snes_or_ksp)

        :arg clear_memoized_objects: Destroy memoized objects if true.
        :arg trial: A dict mapping each trial option to a valid value
        :arg method: A valid method (see the keys of *method_options*)
        :arg cl_ctx: the computing context
        :arg queue: the computing queue for the context

        kwargs should include the boundary id of the scatterer as 'scatterer_bdy_id'
        and the boundary id of the outer boundary as 'outer_bdy_id'

        kwargs should include the method options for :arg:`trial['method']`.
        for the given method.
    """
    if clear_memoized_objects:
        global memoized_objects
        memoized_objects = {}

    if cl_ctx is None:
        raise ValueError("Missing cl_ctx")
    if queue is None:
        raise ValueError("Missing queue")

    # Get boundary ids
    scatterer_bdy_id = kwargs['scatterer_bdy_id']
    outer_bdy_id = kwargs['outer_bdy_id']

    # Get degree and wave number
    degree = trial['degree']
    wave_number = trial['kappa']

    # Get options prefix and solver parameters, if any
    options_prefix = kwargs.get('options_prefix', None)
    solver_parameters = dict(kwargs.get('solver_parameters', None))

    # Get prepared trial args in kwargs
    prepared_trial = prepare_trial(trial, true_sol_name, cl_ctx, queue)
    mesh, fspace, vfspace, true_sol, true_sol_grad_expr = prepared_trial

    # Create a place to memoize any objects if necessary
    tuple_trial = trial_to_tuple(trial)
    memo_key = tuple_trial[:2]
    if memo_key not in memoized_objects:
        memoized_objects[memo_key] = {}

    comp_sol = None

    # Handle any special kwargs and get computed solution
    if method == 'pml':
        # Get required objects
        pml_max = kwargs['pml_max']
        pml_min = kwargs['pml_min']

        # Get optional argumetns
        pml_type = kwargs.get('pml_type', None)
        quad_const = kwargs.get('quad_const', None)
        speed = kwargs.get('speed', None)

        # Make tensor function space
        if 'tfspace' not in memoized_objects[memo_key]:
            memoized_objects[memo_key]['tfspace'] = \
                TensorFunctionSpace(mesh, 'CG', degree)

        tfspace = memoized_objects[memo_key]['tfspace']

        snes, comp_sol = pml(
            mesh,
            scatterer_bdy_id,
            outer_bdy_id,
            wave_number,
            options_prefix=options_prefix,
            solver_parameters=solver_parameters,
            fspace=fspace,
            tfspace=tfspace,
            true_sol_grad_expr=true_sol_grad_expr,
            pml_type=pml_type,
            quad_const=quad_const,
            speed=speed,
            pml_min=pml_min,
            pml_max=pml_max,
        )
        snes_or_ksp = snes

    elif method == 'nonlocal':
        # Build DG spaces if not already built
        if 'dgfspace' not in memoized_objects[memo_key]:
            memoized_objects[memo_key]['dgfspace'] = \
                FunctionSpace(mesh, 'DG', degree)
        if 'dgvfspace' not in memoized_objects[memo_key]:
            memoized_objects[memo_key]['dgvfspace'] = \
                VectorFunctionSpace(mesh, 'DG', degree)

        dgfspace = memoized_objects[memo_key]['dgfspace']
        dgvfspace = memoized_objects[memo_key]['dgvfspace']

        # Get opencl array context
        from meshmode.array_context import PyOpenCLArrayContext
        actx = PyOpenCLArrayContext(queue)

        # Build connection fd -> meshmode if not already built
        if 'meshmode_src_connection' not in memoized_objects[memo_key]:
            from meshmode.interop.firedrake import build_connection_from_firedrake
            memoized_objects[memo_key]['meshmode_src_connection'] = \
                build_connection_from_firedrake(
                    actx,
                    dgfspace,
                    grp_factory=None,
                    restrict_to_boundary=scatterer_bdy_id)

        meshmode_src_connection = memoized_objects[memo_key][
            'meshmode_src_connection']

        # Set defaults for qbx kwargs
        qbx_order = kwargs.get('qbx_order', degree + 2)
        fine_order = kwargs.get('fine_order', 4 * degree)
        fmm_order = kwargs.get('FMM Order', None)
        fmm_tol = kwargs.get('FMM Tol', None)
        # make sure got either fmm_order xor fmm_tol
        if fmm_order is None and fmm_tol is None:
            raise ValueError("At least one of 'fmm_order', 'fmm_tol' must not "
                             "be *None*")
        if fmm_order is not None and fmm_tol is not None:
            raise ValueError("At most one of 'fmm_order', 'fmm_tol' must not "
                             "be *None*")
        # if got fmm_tol, make a level-to-order
        fmm_level_to_order = None
        if fmm_tol is not None:
            if not isinstance(fmm_tol, float):
                raise TypeError("fmm_tol of type '%s' is not of type float" %
                                type(fmm_tol))
            if fmm_tol <= 0.0:
                raise ValueError(
                    "fmm_tol of '%s' is less than or equal to 0.0" % fmm_tol)
            from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder
            fmm_level_to_order = SimpleExpansionOrderFinder(fmm_tol)
        # Otherwise, make sure we got a valid fmm_order
        else:
            if not isinstance(fmm_order, int):
                if fmm_order != False:
                    raise TypeError(
                        "fmm_order of type '%s' is not of type int" %
                        type(fmm_order))
            if fmm_order != False and fmm_order < 1:
                raise ValueError("fmm_order of '%s' is less than 1" %
                                 fmm_order)

        qbx_kwargs = {
            'qbx_order': qbx_order,
            'fine_order': fine_order,
            'fmm_order': fmm_order,
            'fmm_level_to_order': fmm_level_to_order,
            'fmm_backend': 'fmmlib',
        }
        # }}}

        ksp, comp_sol = nonlocal_integral_eq(
            mesh,
            scatterer_bdy_id,
            outer_bdy_id,
            wave_number,
            options_prefix=options_prefix,
            solver_parameters=solver_parameters,
            fspace=fspace,
            vfspace=vfspace,
            true_sol_grad_expr=true_sol_grad_expr,
            actx=actx,
            dgfspace=dgfspace,
            dgvfspace=dgvfspace,
            meshmode_src_connection=meshmode_src_connection,
            qbx_kwargs=qbx_kwargs,
        )

        snes_or_ksp = ksp

    elif method == 'transmission':

        snes, comp_sol = transmission(
            mesh,
            scatterer_bdy_id,
            outer_bdy_id,
            wave_number,
            options_prefix=options_prefix,
            solver_parameters=solver_parameters,
            fspace=fspace,
            true_sol_grad_expr=true_sol_grad_expr,
        )
        snes_or_ksp = snes
    else:
        raise ValueError("Invalid method")

    comp_sol.rename(name=comp_sol_name)
    return true_sol, comp_sol, snes_or_ksp
Пример #9
0
def run_method(trial, method, wave_number,
               true_sol_name="True Solution",
               comp_sol_name="Computed Solution", **kwargs):
    """
        Returns (true solution, computed solution, snes_or_ksp)

        :arg trial: A dict mapping each trial option to a valid value
        :arg method: A valid method (see the keys of *method_options*)
        :arg wave_number: The wave number

        kwargs should include the boundary id of the scatterer as 'scatterer_bdy_id'
        and the boundary id of the outer boundary as 'outer_bdy_id'

        kwargs should include the method options for :arg:`trial['method']`.
        for the given method.
    """
    # Get boundary ids
    scatterer_bdy_id = kwargs['scatterer_bdy_id']
    outer_bdy_id = kwargs['outer_bdy_id']

    # Get degree
    degree = trial['degree']

    # Get options prefix and solver parameters, if any
    options_prefix = kwargs.get('options_prefix', None)
    solver_parameters = dict(kwargs.get('solver_parameters', None))

    # Get prepared trial args in kwargs
    prepared_trial = prepare_trial(trial, true_sol_name)
    mesh, fspace, vfspace, true_sol, true_sol_grad = prepared_trial

    # Create a place to memoize any objects if necessary
    tuple_trial = trial_to_tuple(trial)
    memo_key = tuple_trial[:2]
    if memo_key not in memoized_objects:
        memoized_objects[memo_key] = {}

    comp_sol = None

    # Handle any special kwargs and get computed solution
    if method == 'pml':
        # Get required objects
        inner_region = kwargs['inner_region']
        pml_max = kwargs['pml_max']
        pml_min = kwargs['pml_min']

        # Get optional argumetns
        pml_type = kwargs.get('pml_type', None)
        delta = kwargs.get('delta', None)
        quad_const = kwargs.get('quad_const', None)
        speed = kwargs.get('speed', None)

        # Make tensor function space
        if 'tfspace' not in memoized_objects[memo_key]:
            memoized_objects[memo_key]['tfspace'] = \
                TensorFunctionSpace(mesh, 'CG', degree)

        tfspace = memoized_objects[memo_key]['tfspace']

        snes, comp_sol = pml(mesh, scatterer_bdy_id, outer_bdy_id, wave_number,
                             options_prefix=options_prefix,
                             solver_parameters=solver_parameters,
                             inner_region=inner_region,
                             fspace=fspace, tfspace=tfspace,
                             true_sol_grad=true_sol_grad,
                             pml_type=pml_type, delta=delta, quad_const=quad_const,
                             speed=speed,
                             pml_min=pml_min,
                             pml_max=pml_max,
                             )
        snes_or_ksp = snes

    elif method == 'nonlocal':
        # Get required arguments
        queue = kwargs['queue']
        cl_ctx = queue.context

        # Set defaults for qbx kwargs
        qbx_order = kwargs.get('qbx_order', degree+2)
        fine_order = kwargs.get('fine_order', 4 * degree)
        fmm_order = kwargs.get('FMM Order', 6)

        qbx_kwargs = {'qbx_order': qbx_order,
                      'fine_order': fine_order,
                      'fmm_order': fmm_order,
                      'fmm_backend': 'fmmlib',
                      }
        # }}}

        # Make function converter if not already built
        if 'fspace_analog' not in memoized_objects[memo_key]:
            mesh_analog = fd2mm.MeshAnalog(mesh, near_bdy=scatterer_bdy_id)
            fspace_analog = fd2mm.FunctionSpaceAnalog(cl_ctx, mesh_analog, fspace)
            memoized_objects[memo_key]['fspace_analog'] = fspace_analog

        fspace_analog = memoized_objects[memo_key]['fspace_analog']

        ksp, comp_sol = nonlocal_integral_eq(
            mesh, scatterer_bdy_id, outer_bdy_id,
            wave_number,
            options_prefix=options_prefix,
            solver_parameters=solver_parameters,
            fspace=fspace, vfspace=vfspace,
            true_sol_grad=true_sol_grad,
            queue=queue, fspace_analog=fspace_analog,
            qbx_kwargs=qbx_kwargs,
            )

        snes_or_ksp = ksp

    elif method == 'transmission':

        snes, comp_sol = transmission(mesh, scatterer_bdy_id, outer_bdy_id,
                                      wave_number,
                                      options_prefix=options_prefix,
                                      solver_parameters=solver_parameters,
                                      fspace=fspace,
                                      true_sol_grad=true_sol_grad,
                                      )
        snes_or_ksp = snes
    else:
        raise ValueError("Invalid method")

    comp_sol.rename(name=comp_sol_name)
    return true_sol, comp_sol, snes_or_ksp