def EnrichedFunctionSpace(spaces): """ Create enriched finite element function space. *Arguments* spaces a list (or tuple) of :py:class:`FunctionSpaces <dolfin.functions.functionspace.FunctionSpace>`. *Usage* The function space may be created by .. code-block:: python V = EnrichedFunctionSpace(spaces) """ cpp.deprecation("'EnrichedFunctionSpace'", "1.7.0", "2.0.0", "Use 'FunctionSpace(mesh, EnrichedElement(...))'.") # Check arguments if not len(spaces) > 0: cpp.dolfin_error("functionspace.py", "create enriched function space", "Need at least one subspace") if not all(isinstance(V, FunctionSpace) for V in spaces): cpp.dolfin_error("functionspace.py", "create enriched function space", "Invalid subspaces: " + str(spaces)) # Get common mesh and constrained_domain, must all be the same mesh, constrained_domain = _get_common_mesh_and_constrained_domain(spaces) # Create element element = ufl.EnrichedElement(*[V.ufl_element() for V in spaces]) return FunctionSpace(mesh, element, constrained_domain=constrained_domain)
def _plot_matplotlib(obj, mesh, kwargs): if isinstance(obj, (cpp.MultiMesh, cpp.MultiMeshFunction, cpp.MultiMeshDirichletBC)): cpp.warning("Don't know how to plot type %s" % type(obj)) return # Avoid importing pyplot until used try: import matplotlib.pyplot as plt except: print("*** Warning: matplotlib.pyplot not available, cannot plot") return gdim = mesh.geometry().dim() if gdim == 3 or kwargs.get("mode") in ("warp",): # Importing this toolkit has side effects enabling 3d support from mpl_toolkits.mplot3d import axes3d # Enabling the 3d toolbox requires some additional arguments ax = plt.gca(projection='3d') else: ax = plt.gca() ax.set_aspect('equal') title = kwargs.pop("title", None) if title is not None: ax.set_title(title) # Translate range_min/max kwargs supported by VTKPlotter vmin = kwargs.pop("range_min", None) vmax = kwargs.pop("range_max", None) if vmin and not "vmin" in kwargs: kwargs["vmin"] = vmin if vmax and not "vmax" in kwargs: kwargs["vmax"] = vmax # Let's stays consistent and use mode='color' instead of 'surface' if kwargs.get("mode") == "surface": cpp.deprecation("plot kwarg mode='surface'", "2016.1", "Use mode='color' instead.") kwargs["mode"] = "color" # Drop unsupported kwargs and inform user _unsupported_kwargs = ["interactive", "rescale", "wireframe"] for kw in _unsupported_kwargs: if kwargs.pop(kw, None): cpp.warning("Matplotlib backend does not support '%s' kwarg yet. " "Ignoring it..." % kw) if isinstance(obj, cpp.Function): return mplot_function(ax, obj, **kwargs) elif isinstance(obj, cpp.Expression): return mplot_expression(ax, obj, mesh, **kwargs) elif isinstance(obj, cpp.Mesh): return mplot_mesh(ax, obj, **kwargs) elif isinstance(obj, cpp.DirichletBC): return mplot_dirichletbc(ax, obj, **kwargs) elif isinstance(obj, _meshfunction_types): return mplot_meshfunction(ax, obj, **kwargs) else: raise AttributeError('Failed to plot %s' % type(obj))
def _plot_matplotlib(obj, mesh, kwargs): if isinstance(obj, (cpp.MultiMesh, cpp.MultiMeshFunction, cpp.MultiMeshDirichletBC)): cpp.warning("Don't know how to plot type %s" % type(obj)) return # Avoid importing pyplot until used try: import matplotlib.pyplot as plt except: print("*** Warning: matplotlib.pyplot not available, cannot plot") return gdim = mesh.geometry().dim() if gdim == 3 or kwargs.get("mode") in ("warp",): # Importing this toolkit has side effects enabling 3d support from mpl_toolkits.mplot3d import axes3d # Enabling the 3d toolbox requires some additional arguments ax = plt.gca(projection='3d') else: ax = plt.gca() ax.set_aspect('equal') title = kwargs.pop("title", None) if title is not None: ax.set_title(title) # Translate range_min/max kwargs supported by VTKPlotter vmin = kwargs.pop("range_min", None) vmax = kwargs.pop("range_max", None) if vmin and not "vmin" in kwargs: kwargs["vmin"] = vmin if vmax and not "vmax" in kwargs: kwargs["vmax"] = vmax # Let's stays consistent and use mode='color' instead of 'surface' if kwargs.get("mode") == "surface": cpp.deprecation("plot kwarg mode='surface'", "1.7.0", "1.7.0", "Use mode='color' instead.") kwargs["mode"] = "color" # Drop unsupported kwargs and inform user _unsupported_kwargs = ["interactive", "rescale", "wireframe"] for kw in _unsupported_kwargs: if kwargs.pop(kw, None): cpp.warning("Matplotlib backend does not support '%s' kwarg yet. " "Ignoring it..." % kw) if isinstance(obj, cpp.Function): return mplot_function(ax, obj, **kwargs) elif isinstance(obj, cpp.Expression): return mplot_expression(ax, obj, mesh, **kwargs) elif isinstance(obj, cpp.Mesh): return mplot_mesh(ax, obj, **kwargs) elif isinstance(obj, cpp.DirichletBC): return mplot_dirichletbc(ax, obj, **kwargs) elif isinstance(obj, _meshfunction_types): return mplot_meshfunction(ax, obj, **kwargs) else: raise AttributeError('Failed to plot %s' % type(obj))
def __init__(self, *args, **kwargs): """Initialize Function.""" # Initial quick check for valid arguments (other checks sprinkled below) if len(args) == 0: raise TypeError("expected 1 or more arguments") # Type switch on argument types if isinstance(args[0], Function): other = args[0] if len(args) == 1: # NOTE: Turn this into error when removing deprecation warning cpp.deprecation( "Function copy constructor", "1.7.0", "2.0.0", "Use 'Function.copy(deepcopy=True)' for copying.") self.__init_copy_constructor(other) elif len(args) == 2: i = args[1] if not isinstance(i, int): raise TypeError("Invalid subfunction number %s" % (i, )) self.__init_subfunction_constructor(other, i) else: raise TypeError("expected one or two arguments when " "instantiating from another Function") elif isinstance(args[0], cpp.Function): other = args[0] if len(args) == 1: # If creating a dolfin.Function from a cpp.Function self.__init_from_cpp_function(other) else: raise TypeError( "expected only one argument when passing cpp.Function" "to dolfin.Function constructor") elif isinstance(args[0], FunctionSpace): V = args[0] # If initialising from a FunctionSpace if len(args) == 1: # If passing only the FunctionSpace self.__init_from_function_space(V) elif len(args) == 2: # If passing FunctionSpace together with cpp.Function # Attached passed FunctionSpace and initialize the # cpp.Function using the passed Function other = args[1] if isinstance(other, cpp.Function): self.__init_from_function_space_and_cpp_function(V, other) else: self.__init_from_function_space_and_function(V, other) else: raise TypeError("too many arguments") else: raise TypeError( "expected a FunctionSpace or a Function as argument 1") # Set name as given or automatic name = kwargs.get("name") or "f_%d" % self.count() self.rename(name, "a Function")
def __init__(self, *args, **kwargs): """Initialize Function.""" # Initial quick check for valid arguments (other checks sprinkled below) if len(args) == 0: raise TypeError("expected 1 or more arguments") # Type switch on argument types if isinstance(args[0], Function): other = args[0] if len(args) == 1: # NOTE: Turn this into error when removing deprecation warning cpp.deprecation("Function copy constructor", "1.7.0", "2.0.0", "Use 'Function.copy(deepcopy=True)' for copying.") self.__init_copy_constructor(other) elif len(args) == 2: i = args[1] if not isinstance(i, int): raise TypeError("Invalid subfunction number %s" % (i,)) self.__init_subfunction_constructor(other, i) else: raise TypeError("expected one or two arguments when " "instantiating from another Function") elif isinstance(args[0], cpp.Function): other = args[0] if len(args) == 1: # If creating a dolfin.Function from a cpp.Function self.__init_from_cpp_function(other) else: raise TypeError("expected only one argument when passing cpp.Function" "to dolfin.Function constructor") elif isinstance(args[0], FunctionSpace): V = args[0] # If initialising from a FunctionSpace if len(args) == 1: # If passing only the FunctionSpace self.__init_from_function_space(V) elif len(args) == 2: # If passing FunctionSpace together with cpp.Function # Attached passed FunctionSpace and initialize the # cpp.Function using the passed Function other = args[1] if isinstance(other, cpp.Function): self.__init_from_function_space_and_cpp_function(V, other) else: self.__init_from_function_space_and_function(V, other) else: raise TypeError("too many arguments") else: raise TypeError("expected a FunctionSpace or a Function as argument 1") # Set name as given or automatic name = kwargs.get("name") or "f_%d" % self.count() self.rename(name, "a Function")
def MixedFunctionSpace(spaces): """ Create mixed finite element function space. *Arguments* spaces a list (or tuple) of :py:class:`FunctionSpaces <dolfin.functions.functionspace.FunctionSpace>`. *Examples of usage* The function space may be created by .. code-block:: python V = MixedFunctionSpace(spaces) ``spaces`` may consist of multiple occurances of the same space: .. code-block:: python P1 = FunctionSpace(mesh, "CG", 1) P2v = VectorFunctionSpace(mesh, "Lagrange", 2) ME = MixedFunctionSpace([P2v, P1, P1, P1]) """ cpp.deprecation("'MixedFunctionSpace'", "1.7.0", "2.0.0", "Use 'FunctionSpace(mesh, MixedElement(...))'.") # Check arguments if not len(spaces) > 0: cpp.dolfin_error("functionspace.py", "create mixed function space", "Need at least one subspace") if not all(isinstance(V, FunctionSpace) for V in spaces): cpp.dolfin_error("functionspace.py", "create mixed function space", "Invalid subspaces: " + str(spaces)) # Get common mesh and constrained_domain, must all be the same mesh, constrained_domain = _get_common_mesh_and_constrained_domain(spaces) # Create UFL element element = ufl.MixedElement(*[V.ufl_element() for V in spaces]) return FunctionSpace(mesh, element, constrained_domain=constrained_domain)
def compile_subdomains(cppcode): """ Compile C++ string expressions into SubDomain instances. *Arguments* expressions a string or a list of strings containing expressions in C++ syntax. NOTE: This function is deprecated. Use CompiledSubDomain instead. If expressions is a `str`, it is interpreted as a C++ string with complete implementations of subclasses of SubDomain. The compiled subdomains returned will be in the same order as they are defined in this code. If it is a list, each item of the list is interpreted as a logical `inside` expression, and the compiled subdomains returned will be in the same order as they occur in this list. If an expression string contains a name, it is assumed to be a scalar variable name, and is added as a public member of the generated subdomain. *Examples of usage* .. code-block:: python left = compile_subdomains("x[0] == 0") right = compile_subdomains("x[1] == 1") or .. code-block:: python bc = compile_subdomains(["x[0] == 0", "x[1] == 1"]) """ deprecation("compile_subdomains", "1.3.0", \ "compiled_subdomains has been renamed to CompiledSubDomain.") # If passing a list we compile each SubDomain on its own if isinstance(cppcode, list): return [CompiledSubDomain(code_str) for code_str in cppcode] return CompiledSubDomain(cppcode)
def derivative(form, u, du=None, coefficient_derivatives=None): if du is None: # Get existing arguments from form and position the new one with the next argument number form_arguments = form.arguments() number = max([-1] + [arg.number() for arg in form_arguments]) + 1 if any(arg.part() is not None for arg in form_arguments): cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Cannot automatically create new Argument using " "parts, please supply one") part = None if isinstance(u, Function): V = u.function_space() du = Argument(V, number, part) elif isinstance(u, (list, tuple)) and all( isinstance(w, Function) for w in u): cpp.deprecation( "derivative of form w.r.t. a tuple of Coefficients", "1.7.0", "2.0.0", "Take derivative w.r.t. a single Coefficient on " "a mixed space instead.") # Get mesh mesh = u[0].function_space().mesh() if not all(mesh.id() == v.function_space().mesh().id() for v in u): cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Don't know how to compute derivative with " "respect to Coefficients on different meshes yet") # Build mixed element, space and argument element = ufl.MixedElement( [v.function_space().ufl_element() for v in u]) V = FunctionSpace(mesh, element) du = ufl.split(Argument(V, number, part)) else: cpp.dolfin_error("formmanipulation.py", "compute derivative of form w.r.t. '%s'" % u, "Supply Function as a Coefficient") return ufl.derivative(form, u, du, coefficient_derivatives)
def _plot_matplotlib(obj, mesh, kwargs): # Avoid importing until used import matplotlib.pyplot as plt gdim = mesh.geometry().dim() if gdim == 3 or kwargs.get("mode") in ("warp",): # Importing this toolkit has side effects enabling 3d support from mpl_toolkits.mplot3d import axes3d # Enabling the 3d toolbox requires some additional arguments ax = plt.gca(projection='3d') else: ax = plt.gca() ax.set_aspect('equal') title = kwargs.pop("title", None) if title is not None: ax.set_title(title) # Translate range_min/max kwargs supported by VTKPlotter vmin = kwargs.pop("range_min", None) vmax = kwargs.pop("range_max", None) if vmin and not "vmin" in kwargs: kwargs["vmin"] = vmin if vmax and not "vmax" in kwargs: kwargs["vmax"] = vmax # Let's stays consistent and use mode='color' instead of 'surface' if kwargs.get("mode") == "surface": cpp.deprecation("plot kwarg mode='surface'", "1.7.0", "1.7.0", "Use mode='color' instead.") kwargs["mode"] = "color" if isinstance(obj, cpp.Function): return mplot_function(ax, obj, **kwargs) elif isinstance(obj, cpp.Expression): return mplot_expression(ax, obj, mesh, **kwargs) elif isinstance(obj, cpp.Mesh): return mplot_mesh(ax, obj, **kwargs) elif isinstance(obj, cpp.DirichletBC): return mplot_dirichletbc(ax, obj, **kwargs) elif isinstance(obj, _meshfunction_types): return mplot_meshfunction(ax, obj, **kwargs) else: raise AttributeError('Failed to plot %s' % type(obj))
def _plot_matplotlib(obj, mesh, kwargs): # Avoid importing until used import matplotlib.pyplot as plt gdim = mesh.geometry().dim() if gdim == 3 or kwargs.get("mode") in ("warp", ): # Importing this toolkit has side effects enabling 3d support from mpl_toolkits.mplot3d import axes3d # Enabling the 3d toolbox requires some additional arguments ax = plt.gca(projection='3d') else: ax = plt.gca() ax.set_aspect('equal') title = kwargs.pop("title", None) if title is not None: ax.set_title(title) # Translate range_min/max kwargs supported by VTKPlotter vmin = kwargs.pop("range_min", None) vmax = kwargs.pop("range_max", None) if vmin and not "vmin" in kwargs: kwargs["vmin"] = vmin if vmax and not "vmax" in kwargs: kwargs["vmax"] = vmax # Let's stays consistent and use mode='color' instead of 'surface' if kwargs.get("mode") == "surface": cpp.deprecation("plot kwarg mode='surface'", "1.7.0", "1.7.0", "Use mode='color' instead.") kwargs["mode"] = "color" if isinstance(obj, cpp.Function): return mplot_function(ax, obj, **kwargs) elif isinstance(obj, cpp.Expression): return mplot_expression(ax, obj, mesh, **kwargs) elif isinstance(obj, cpp.Mesh): return mplot_mesh(ax, obj, **kwargs) elif isinstance(obj, cpp.DirichletBC): return mplot_dirichletbc(ax, obj, **kwargs) elif isinstance(obj, _meshfunction_types): return mplot_meshfunction(ax, obj, **kwargs) else: raise AttributeError('Failed to plot %s' % type(obj))
def derivative(form, u, du=None, coefficient_derivatives=None): if du is None: # Get existing arguments from form and position the new one with the next argument number form_arguments = form.arguments() number = max([-1] + [arg.number() for arg in form_arguments]) + 1 if any(arg.part() is not None for arg in form_arguments): cpp.dolfin_error("formmanipulation.py", "compute derivative of form", "Cannot automatically create new Argument using " "parts, please supply one") part = None if isinstance(u, Function): V = u.function_space() du = Argument(V, number, part) elif isinstance(u, (list,tuple)) and all(isinstance(w, Function) for w in u): cpp.deprecation("derivative of form w.r.t. a tuple of Coefficients", "1.7.0", "2.0.0", "Take derivative w.r.t. a single Coefficient on " "a mixed space instead.") # Get mesh mesh = u[0].function_space().mesh() if not all(mesh.id() == v.function_space().mesh().id() for v in u): cpp.dolfin_error("formmanipulation.py", "compute derivative of form", "Don't know how to compute derivative with " "respect to Coefficients on different meshes yet") # Build mixed element, space and argument element = ufl.MixedElement([v.function_space().ufl_element() for v in u]) V = FunctionSpace(mesh, element) du = ufl.split(Argument(V, number, part)) else: cpp.dolfin_error("formmanipulation.py", "compute derivative of form w.r.t. '%s'" % u, "Supply Function as a Coefficient") return ufl.derivative(form, u, du, coefficient_derivatives)
def homogenize(bc): """ **DEPRECATED**: Return a homogeneous version of the given boundary condition. *Arguments* bc a :py:class:`DirichletBC <dolfin.fem.bcs.DirichletBC>` instance, or a list/tuple of :py:class:`DirichletBC <dolfin.fem.bcs.DirichletBC>` instances. Other types of boundary conditions are ignored. If the given boundary condition is a list of boundary conditions, then a list of homogeneous boundary conditions is returned. """ # Deprecating it as it is very unclear what should it do # because DirichletBC employs some caching prepared on first use. # So if args of DirichetBC(*args) change it is not clear whether # whether cached dofs should be reused or thrown away on copy # cnstruction cpp.deprecation( "Free function 'homogenize(bc)'", "1.6.0", "1.7.0", "Use member function 'homogenize()' (in a combination" "with copy constructor 'DirichletBC(bc)'.") # Handle case when boundary condition is a list if isinstance(bc, (list, tuple)): bcs = bc return [homogenize(bc) for bc in bcs] # Only consider Dirichlet boundary conditions if not isinstance(bc, cpp.DirichletBC): cpp.dolfin_error("bcs.py", "homogenize boundary condition", "Can only homogenize DirichletBCs") # Return homogenized copy new_bc = DirichletBC(bc) new_bc.homogenize() return new_bc
def homogenize(bc): """ **DEPRECATED**: Return a homogeneous version of the given boundary condition. *Arguments* bc a :py:class:`DirichletBC <dolfin.fem.bcs.DirichletBC>` instance, or a list/tuple of :py:class:`DirichletBC <dolfin.fem.bcs.DirichletBC>` instances. Other types of boundary conditions are ignored. If the given boundary condition is a list of boundary conditions, then a list of homogeneous boundary conditions is returned. """ # Deprecating it as it is very unclear what should it do # because DirichletBC employs some caching prepared on first use. # So if args of DirichetBC(*args) change it is not clear whether # whether cached dofs should be reused or thrown away on copy # cnstruction cpp.deprecation("Free function 'homogenize(bc)'", "1.6.0", "1.7.0", "Use member function 'homogenize()' (in a combination" "with copy constructor 'DirichletBC(bc)'.") # Handle case when boundary condition is a list if isinstance(bc, (list, tuple)): bcs = bc return [homogenize(bc) for bc in bcs] # Only consider Dirichlet boundary conditions if not isinstance(bc, cpp.DirichletBC): cpp.dolfin_error("bcs.py", "homogenize boundary condition", "Can only homogenize DirichletBCs") # Return homogenized copy new_bc = DirichletBC(bc) new_bc.homogenize() return new_bc
def FunctionSpaceFromCpp(cppV): cpp.deprecation("'FunctionSpaceFromCpp'", "1.7.0", "2.0.0", "Use 'FunctionSpace(cppV)' instead.") return FunctionSpace(cppV)
def cell(self): "Return the UFL cell." cpp.deprecation("'FunctionSpace.cell()'", "1.7.0", "2.0.0", "Use 'FunctionSpace.ufl_cell()' instead.") return self.ufl_cell()
def __init__(self, form, form_compiler_parameters=None, subdomains=None): "Create JIT-compiled form from any given form (compiled or not)." # Check form argument if isinstance(form, ufl.Form): # Cutoff for better error message than ffc would give if not form.empty() and not form.domains(): raise RuntimeError("Expecting a completed form with domains at this point.") # Extract subdomain data sd = form.subdomain_data() if len(sd) != 1: # Until the assembler and ufc has multimesh support, we impose this limitation raise RuntimeError("Expecting subdomain data for a single domain only.") if subdomains is None: self.subdomains, = list(sd.values()) # Assuming single domain domain, = list(sd.keys()) # Assuming single domain mesh = domain.data() # Jit the module, this will take some time... self._compiled_form, module, prefix \ = jit(form, form_compiler_parameters, mpi_comm=mesh.mpi_comm()) # Extract function spaces of form arguments self.function_spaces = [func.function_space() for func in form.arguments()] # Extract coefficients from form (pass only the ones that the compiled form actually uses to the assembler) original_coefficients = form.coefficients() self.coefficients = [original_coefficients[self._compiled_form.original_coefficient_position(i)] for i in range(self._compiled_form.num_coefficients())] elif isinstance(form, cpp.Form): cpp.deprecation("Passing a cpp.Form to dolfin.Form constructor", "1.3.0", "1.4.0", "Passing a cpp.Form to dolfin.Form constructor" " will be removed.") self._compiled_form = form._compiled_form self.function_spaces = form.function_spaces self.coefficients = form.coefficients self.subdomains = form.subdomains mesh = form.mesh() else: cpp.dolfin_error("form.py", "creating dolfin.Form", "Expected a ufl.Form or a dolfin.Form") # This is now a strict requirement if mesh is None: raise RuntimeError("Expecting to find a Mesh in the form.") # Type checking argument function_spaces r = self._compiled_form.rank() if len(self.function_spaces) != r: raise ValueError(function_space_error + " Wrong number of test spaces (should be %d)." % r) if not all(isinstance(fs, cpp.FunctionSpace) for fs in self.function_spaces): raise ValueError(function_space_error + " Invalid type of test spaces.") # Type checking coefficients if not all(isinstance(c, cpp.GenericFunction) for c in self.coefficients): coefficient_error = "Error while extracting coefficients. " raise TypeError(coefficient_error + "Either provide a dict of cpp.GenericFunctions, " + "or use Function to define your form.") # Type checking subdomain data # Check that we have no additional subdomain data (user misspelling) # TODO: Get from ufl list? integral_types = ("cell", "exterior_facet", "interior_facet", "point") for k in list(self.subdomains.keys()): if self.subdomains[k] is None: del self.subdomains[k] additional_keys = set(self.subdomains.keys()) - set(integral_types) if additional_keys: cpp.warning("Invalid keys in subdomains: %s" % additional_keys) # Check that we have only MeshFunctions for data in list(self.subdomains.values()): # TODO: This wasn't here before, disable if it's too restrictive: if not (data is None or isinstance(data, MeshFunctionSizet)): cpp.warning("Invalid subdomain data type %s, expecting a MeshFunction" % type(data)) # Initialize base class cpp.Form.__init__(self, self._compiled_form, self.function_spaces, self.coefficients) # Attach subdomains if we have them subdomains = self.subdomains.get("cell") if subdomains is not None: self.set_cell_domains(subdomains) subdomains = self.subdomains.get("exterior_facet") if subdomains is not None: self.set_exterior_facet_domains(subdomains) subdomains = self.subdomains.get("interior_facet") if subdomains is not None: self.set_interior_facet_domains(subdomains) subdomains = self.subdomains.get("point") if subdomains is not None: self.set_vertex_domains(subdomains) # Attach mesh self.set_mesh(mesh)
def _mesh2domain(mesh): "Deprecation mechanism for symbolic geometry." if isinstance(mesh, ufl.Cell): cpp.deprecation("Constructing geometry from a Cell", "1.4", "1.5", "Pass mesh instead, for example use FacetNormal(mesh) instead of FacetNormal(triangle) or triangle.n") return ufl.as_domain(mesh)
def assemble(form, tensor=None, mesh=None, coefficients=None, function_spaces=None, cell_domains=None, exterior_facet_domains=None, interior_facet_domains=None, reset_sparsity=True, add_values=False, finalize_tensor=True, keep_diagonal=False, backend=None, form_compiler_parameters=None, bcs=None): """ Assemble the given form and return the corresponding tensor. *Arguments* Depending on the input form, which may be a functional, linear form, bilinear form or higher rank form, a scalar value, a vector, a matrix or a higher rank tensor is returned. In the simplest case, no additional arguments are needed. However, additional arguments may and must in some cases be provided as outlined below. The ``form`` can be either an FFC form or a precompiled UFC form. If a precompiled or 'pure' UFC form is given, then ``coefficients`` and ``function_spaces`` have to be provided too. The coefficient functions should be provided as a 'dict' using the FFC functions as keys. The function spaces should be provided either as a list where the number of function spaces must correspond to the number of basis functions in the form, or as a single argument, implying that the same FunctionSpace is used for all test/trial spaces. If the form defines integrals over different subdomains, :py:class:`MeshFunctions <dolfin.cpp.MeshFunction>` over the corresponding topological entities defining the subdomains can be provided. An instance of a :py:class:`SubDomain <dolfin.cpp.SubDomain>` can also be passed for each subdomain. The implementation of the returned tensor is determined by the default linear algebra backend. This can be overridden by specifying a different backend. Each call to assemble() will create a new tensor. If the ``tensor`` argument is provided, this will be used instead. If ``reset_sparsity`` is set to False, the provided tensor will not be reset to zero before assembling (adding) values to the tensor. If the ``keep_diagonal`` is set to True, assembler ensures that potential zeros on a matrix diagonal are kept in sparsity pattern so every diagonal entry can be changed in a future (for example by ident() or ident_zeros()). Specific form compiler parameters can be provided by the ``form_compiler_parameters`` argument. Form compiler parameters can also be controlled using the global parameters stored in parameters["form_compiler"]. *Examples of usage* The standard stiffness matrix ``A`` and a load vector ``b`` can be assembled as follows: .. code-block:: python A = assemble(inner(grad(u),grad(v))*dx()) b = assemble(f*v*dx()) It is possible to explicitly prescribe the domains over which integrals wll be evaluated using the arguments ``cell_domains``, ``exterior_facet_domains`` and ``interior_facet_domains``. For instance, using a mesh function marking parts of the boundary: .. code-block:: python # MeshFunction marking boundary parts boundary_parts = MeshFunction("size_t", mesh, mesh.topology().dim()-1) # Sample variational forms a = inner(grad(u), grad(v))*dx() + p*u*v*ds(0) L = f*v*dx() - g*v*ds(1) + p*q*v*ds(0) A = assemble(a, exterior_facet_domains=boundary_parts) b = assemble(L, exterior_facet_domains=boundary_parts) To ensure that the assembled matrix has the right type, one may use the ``tensor`` argument: .. code-block:: python A = PETScMatrix() assemble(a, tensor=A) The form ``a`` is now assembled into the PETScMatrix ``A``. """ # Create dolfin Form object referencing all data needed by assembler dolfin_form = _create_dolfin_form(form, mesh, coefficients, function_spaces, cell_domains, exterior_facet_domains, interior_facet_domains, form_compiler_parameters) # Create tensor tensor = _create_tensor(form, dolfin_form.rank(), backend, tensor) # Call C++ assemble function assembler = cpp.Assembler() assembler.reset_sparsity = reset_sparsity assembler.add_values = add_values assembler.finalize_tensor = finalize_tensor assembler.keep_diagonal = keep_diagonal assembler.assemble(tensor, dolfin_form) # Convert to float for scalars if dolfin_form.rank() == 0: tensor = tensor.getval() # Apply (possibly list of) boundary conditions bcs = _wrap_in_list(bcs, 'bcs', cpp.DirichletBC) if bcs: cpp.deprecation("Passing \"bcs\" to assemble", "1.3.0", "Apply DirichletBC manually after an assemble.") for bc in bcs: bc.apply(tensor) # Return value return tensor
def _sub(self, i, deepcopy = False): cpp.deprecation("Using Function._sub", "1.3.0", "Use Function.sub instead") self.sub(i, deepcopy)
def _sub(self, i, deepcopy=False): cpp.deprecation("Using Function._sub", "1.3.0", "Use Function.sub instead") self.sub(i, deepcopy)
def assemble_system(A_form, b_form, bcs=None, x0=None, A_coefficients=None, b_coefficients=None, A_function_spaces=None, b_function_spaces=None, cell_domains=None, exterior_facet_domains=None, interior_facet_domains=None, reset_sparsity=None, add_values=False, finalize_tensor=True, keep_diagonal=False, A_tensor=None, b_tensor=None, mesh=None, backend=None, form_compiler_parameters=None): """ Assemble form(s) and apply any given boundary conditions in a symmetric fashion and return tensor(s). The standard application of boundary conditions does not necessarily preserve the symmetry of the assembled matrix. In order to perserve symmetry in a system of equations with boundary conditions, one may use the alternative assemble_system instead of multiple calls to :py:func:`assemble <dolfin.fem.assembling.assemble>`. *Examples of usage* For instance, the statements .. code-block:: python A = assemble(a) b = assemble(L) bc.apply(A, b) can alternatively be carried out by .. code-block:: python A, b = assemble_system(a, L, bc) The statement above is valid even if ``bc`` is a list of :py:class:`DirichletBC <dolfin.fem.bcs.DirichletBC>` instances. For more info and options, see :py:func:`assemble <dolfin.fem.assembling.assemble>`. """ if reset_sparsity is not None: cpp.deprecation("Parameter reset_sparsity of assembler", "1.4", "1.5", "Parameter reset_sparsity of assembler" " is no longer used. Tensor is reset iff empty().") # Create dolfin Form objects referencing all data needed by assembler A_dolfin_form = _create_dolfin_form(A_form, mesh, A_coefficients, A_function_spaces, cell_domains, exterior_facet_domains, interior_facet_domains, form_compiler_parameters) b_dolfin_form = _create_dolfin_form(b_form, mesh, b_coefficients, b_function_spaces, cell_domains, exterior_facet_domains, interior_facet_domains, form_compiler_parameters) # Create tensors A_tensor = _create_tensor(A_form, A_dolfin_form.rank(), backend, A_tensor) b_tensor = _create_tensor(b_form, b_dolfin_form.rank(), backend, b_tensor) # Check bcs bcs = _wrap_in_list(bcs, 'bcs', cpp.DirichletBC) # Call C++ assemble function assembler = cpp.SystemAssembler(A_dolfin_form, b_dolfin_form, bcs) assembler.add_values = add_values assembler.finalize_tensor = finalize_tensor assembler.keep_diagonal = keep_diagonal if x0 is not None: assembler.assemble(A_tensor, b_tensor, x0) else: assembler.assemble(A_tensor, b_tensor) return A_tensor, b_tensor
def FunctionSpaceBase(mesh, element, constrained_domain=None): cpp.deprecation("'FunctionSpaceBase'", "1.7.0", "2.0.0", "Use 'FunctionSpace(...)' instead.") return FunctionSpace(mesh, element, constrained_domain=None)
def assemble(form, tensor=None, mesh=None, coefficients=None, function_spaces=None, cell_domains=None, exterior_facet_domains=None, interior_facet_domains=None, reset_sparsity=True, add_values=False, finalize_tensor=True, keep_diagonal=False, backend=None, form_compiler_parameters=None, bcs=None): """ Assemble the given form and return the corresponding tensor. *Arguments* Depending on the input form, which may be a functional, linear form, bilinear form or higher rank form, a scalar value, a vector, a matrix or a higher rank tensor is returned. In the simplest case, no additional arguments are needed. However, additional arguments may and must in some cases be provided as outlined below. The ``form`` can be either an FFC form or a precompiled UFC form. If a precompiled or 'pure' UFC form is given, then ``coefficients`` and ``function_spaces`` have to be provided too. The coefficient functions should be provided as a 'dict' using the FFC functions as keys. The function spaces should be provided either as a list where the number of function spaces must correspond to the number of basis functions in the form, or as a single argument, implying that the same FunctionSpace is used for all test/trial spaces. If the form defines integrals over different subdomains, :py:class:`MeshFunctions <dolfin.cpp.MeshFunction>` over the corresponding topological entities defining the subdomains can be provided. An instance of a :py:class:`SubDomain <dolfin.cpp.SubDomain>` can also be passed for each subdomain. The implementation of the returned tensor is determined by the default linear algebra backend. This can be overridden by specifying a different backend. Each call to assemble() will create a new tensor. If the ``tensor`` argument is provided, this will be used instead. If ``reset_sparsity`` is set to False, the provided tensor will not be reset to zero before assembling (adding) values to the tensor. If the ``keep_diagonal`` is set to True, assembler ensures that potential zeros on a matrix diagonal are kept in sparsity pattern so every diagonal entry can be changed in a future (for example by ident() or ident_zeros()). Specific form compiler parameters can be provided by the ``form_compiler_parameters`` argument. Form compiler parameters can also be controlled using the global parameters stored in parameters["form_compiler"]. *Examples of usage* The standard stiffness matrix ``A`` and a load vector ``b`` can be assembled as follows: .. code-block:: python A = assemble(inner(grad(u),grad(v))*dx()) b = assemble(f*v*dx()) It is possible to explicitly prescribe the domains over which integrals wll be evaluated using the arguments ``cell_domains``, ``exterior_facet_domains`` and ``interior_facet_domains``. For instance, using a mesh function marking parts of the boundary: .. code-block:: python # MeshFunction marking boundary parts boundary_parts = MeshFunction("size_t", mesh, mesh.topology().dim()-1) # Sample variational forms a = inner(grad(u), grad(v))*dx() + p*u*v*ds(0) L = f*v*dx() - g*v*ds(1) + p*q*v*ds(0) A = assemble(a, exterior_facet_domains=boundary_parts) b = assemble(L, exterior_facet_domains=boundary_parts) To ensure that the assembled matrix has the right type, one may use the ``tensor`` argument: .. code-block:: python A = PETScMatrix() assemble(a, tensor=A) The form ``a`` is now assembled into the PETScMatrix ``A``. """ # Extract common cell from mesh (may be missing in form definition) common_cell = None if mesh is None else mesh.ufl_cell() # First check if we got a cpp.Form which originates from cpp layer if isinstance(form, cpp.Form) and not hasattr(form, "_compiled_form"): # Then we just try to use that one dolfin_form = form else: # Wrap form dolfin_form = Form(form, function_spaces=function_spaces, coefficients=coefficients, form_compiler_parameters=form_compiler_parameters, common_cell=common_cell) # Set mesh if specified (important for functionals without a function spaces) if mesh is not None: dolfin_form.set_mesh(mesh) # Create tensor tensor = _create_tensor(form, dolfin_form.rank(), backend, tensor) # Extract domains cell_domains, exterior_facet_domains, interior_facet_domains = \ _extract_domains(dolfin_form.mesh(), cell_domains, exterior_facet_domains, interior_facet_domains) # Attach domains to form if cell_domains is not None: dolfin_form.set_cell_domains(cell_domains) if interior_facet_domains is not None: dolfin_form.set_interior_facet_domains(interior_facet_domains) if exterior_facet_domains is not None: dolfin_form.set_exterior_facet_domains(exterior_facet_domains) # Call C++ assemble function assembler = cpp.Assembler() assembler.reset_sparsity = reset_sparsity assembler.add_values = add_values assembler.finalize_tensor = finalize_tensor assembler.keep_diagonal = keep_diagonal assembler.assemble(tensor, dolfin_form) # Convert to float for scalars if dolfin_form.rank() == 0: tensor = tensor.getval() # Apply (possibly list of) boundary conditions bcs = _wrap_in_list(bcs, 'bcs', cpp.DirichletBC) if bcs: cpp.deprecation("Passing \"bcs\" to assemble", "1.3.0", "Apply DirichletBC manually after an assemble.") for bc in bcs: bc.apply(tensor) # Return value return tensor