def sigma_identity( domain, range_, dual_to_range, parameters=None, device_interface=None, precision=None, ): """ Evaluate the sigma identity operator. For Galerkin methods this operator is equivalent to .5 * identity. For collocation methods the value may differ from .5 on piecewise smooth domains. """ from bempp.api.utils.helpers import assign_parameters parameters = assign_parameters(parameters) if parameters.assembly.discretization_type == "galerkin": return 0.5 * identity( domain, range_, dual_to_range, parameters=parameters, device_interface=device_interface, precision=precision, ) elif parameters.assembly.discretization_type == "collocation": raise ValueError("Not yet implemented.")
def __init__( self, space, dual_space=None, fun=None, coefficients=None, projections=None, parameters=None, ): """ Construct a grid function. A grid function can be initialized in three different ways. 1. By providing a Python callable. Any Python callable of the following form is valid.:: callable(x,n,domain_index,result) Here, x, n, and result are all numpy arrays. x contains the current evaluation point, n the associated outward normal direction and result is a numpy array that will store the result of the Python callable. The variable domain_index stores the index of the subdomain on which x lies (default 0). This makes it possible to define different functions for different subdomains. The following example defines input data that is the inner product of the coordinate x with the normal direction n.:: fun(x,n,domain_index,result): result[0] = np.dot(x,n) 2. By providing a vector of coefficients at the nodes. This is preferable if the coefficients of the data are coming from an external code. 3. By providing a vector of projection data and a corresponding dual space. Parameters ---------- space : bempp.api.space.Space The space over which the GridFunction is defined. dual_space : bempp.api.Space A representation of the dual space. If not specified then space == dual_space is assumed (optional). fun : callable A Python function from which the GridFunction is constructed (optional). coefficients : np.ndarray A 1-dimensional array with the coefficients of the GridFunction at the interpolatoin points of the space (optional). projections : np.ndarray A 1-dimensional array with the projections of the GridFunction onto a dual space (optional). parameters : bempp.api.ParameterList A ParameterList object used for the assembly of the GridFunction (optional). Notes ----- * Only one of projections, coefficients, or fun is allowed as parameter. Examples -------- To create a GridFunction from a Python callable my_fun use >>> grid_function = GridFunction(space, fun=my_fun) To create a GridFunction from a vector of coefficients coeffs use >>> grid_function = GridFunction(space,coefficients=coeffs) To create a GridFunction from a vector of projections proj use >>> grid_function = GridFunction( space,dual_space=dual_space, projections=proj) """ from bempp.api.utils.helpers import assign_parameters from bempp.api.space.space import return_compatible_representation self._space = None self._dual_space = None self._coefficients = None self._grid_coefficients = None self._projections = None self._representation = None if dual_space is None: dual_space = space self._space, self._dual_space = space, dual_space # Now check that space and dual are defined over same grid # with the same normal directions. If one space is barycentric, # need to take this into account. comp_domain, comp_dual = return_compatible_representation(space, dual_space) self._comp_domain = comp_domain self._comp_dual = comp_dual if ( not comp_domain.grid == comp_dual.grid or not _np.all( comp_domain.normal_multipliers == comp_dual.normal_multipliers ) ): raise ValueError( "Space and dual space must be defined on the " + "same grid with same normal directions." ) self._parameters = assign_parameters(parameters) if sum(1 for e in [fun, coefficients, projections] if e is not None) != 1: raise ValueError( "Exactly one of 'fun', 'coefficients' or 'projections' " + "must be nonzero." ) if coefficients is not None: self._coefficients = coefficients self._representation = "primal" if projections is not None: self._projections = projections self._representation = "dual" if fun is not None: from bempp.api.integration.triangle_gauss import rule points, weights = rule(self._parameters.quadrature.regular) if fun.bempp_type == "real": dtype = "float64" else: dtype = "complex128" grid_projections = _np.zeros(comp_dual.grid_dof_count, dtype=dtype) # Create a Numba callable from the function _project_function( fun, comp_dual.grid.data, comp_dual.support_elements, comp_dual.local2global, comp_dual.local_multipliers, comp_dual.normal_multipliers, comp_dual.numba_evaluate, comp_dual.shapeset.evaluate, points, weights, comp_domain.codomain_dimension, grid_projections, ) self._projections = comp_dual.dof_transformation.T @ grid_projections self._representation = "dual"
def __init__( self, grid_function, domain, range_, dual_to_range, parameters=None, mode="component", ): """ Initialize the multiplication operator. This class initializes a multiplication operator mult from a given grid function g, such that the result h = mult @ f for a given grid function f is the result of projecting g * f onto the space `dual_to_range`. The number of components of the shapesets of grid_function.space, domain and dual_to_range must be compatible. For example, grid_function could be scalar, and space and dual_to_range vectorial with 3 components. Parameters ---------- grid_function : GridFunction object The grid function object from which the multiplication operator is built. It needs to allow representation in primal (coordinate) form. domain : Space object The domain space of the operator. range_ : Space object The range space of the operator dual_to_range : Space object The dual space on which the result of the multiplication is projected. parameters : Parameters object The parameters associated with this operator. mode : string Either 'component' or 'inner'. If mode is 'component' (default) then the multiplication is componentwise at each quadrature point. Hence, if the shapesets of grid_function.space and domain.space both have dimension 3, then the result of the multiplication is also of dimension 3, and the dual_to_range space needs to be compatible to it. If mode is 'inner', then inner product is taken of the values of grid_function at the quadrature point and the basis functions in space at the quadrature points. """ from bempp.api.utils.helpers import assign_parameters self._mode = mode self._grid_fun = grid_function # Check compatibility dim = grid_function.component_count dual_dim = dual_to_range.codomain_dimension dimensions_compatible = False if mode == "component": dimensions_compatible = dim == domain.codomain_dimension and dim == dual_dim elif mode == "inner": dimensions_compatible = dim == domain.codomain_dimension and dual_dim == 1 else: raise ValueError( "Unknown value for 'mode'. Allowed: 'component', 'inner'") if not dimensions_compatible: raise ValueError("Incompatible codomain dimensions.") super().__init__(domain, range_, dual_to_range, assign_parameters(parameters))