def _init_from_ufl(self, mesh, element, constrained_domain=None): if not isinstance(element, ufl.FiniteElementBase): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a finite element: " + str(element)) if constrained_domain is not None: if not isinstance(constrained_domain, cpp.SubDomain): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a subdomain: " + str(constrained_domain)) # Compile element and dofmap and construct corresponding dolfin objects #if dolfin_element is None or dolfin_dofmap is None: # assert dolfin_element is None and dolfin_dofmap is None, "Expecting both or none of these." dolfin_element, dolfin_dofmap = _compile_dolfin_element(element, mesh, constrained_domain=constrained_domain) # Initialize the cpp.FunctionSpace cpp.FunctionSpace.__init__(self, mesh, dolfin_element, dolfin_dofmap) # Initialize the ufl.FunctionSpace ufl.FunctionSpace.__init__(self, mesh.ufl_domain(), element) # Store reference to constrained domain to avoid possible SWIG # director memory error (see # https://bitbucket.org/fenics-project/dolfin/issue/71) # TODO: Make constrained_domain private with getter? Attribute access breaks interface consistency. self.constrained_domain = constrained_domain
def jit(form, form_compiler_parameters=None): """Just-in-time compile any provided form. It uses the jit function from the form compiler registered by parameters["form_compiler"]["name"]. """ # Check that form is not empty if isinstance(form, ufl.Form): if form.empty(): raise RuntimeError, "Form is empty. Cannot pass to JIT compiler." # Import form compiler form_compiler_name = cpp.parameters["form_compiler"]["name"] try: form_compiler = __import__(form_compiler_name) except ImportError, message: print message warning("Could not import %s form compiler, falling back to FFC." \ % form_compiler_name) try: form_compiler = __import__("ffc") except: cpp.dolfin_error("jit.py", "perform just-in-time compilation of form", "Could not import FFC form compiler")
def interpolate(v, V): """ Return interpolation of a given function into a given finite element space. *Arguments* v a :py:class:`Function <dolfin.functions.function.Function>` or an :py:class:`Expression <dolfin.functions.expression.Expression>` V a :py:class:`FunctionSpace (standard, mixed, etc.) <dolfin.functions.functionspace.FunctionSpaceBase>` *Example of usage* .. code-block:: python v = Expression("sin(pi*x[0])") V = FunctionSpace(mesh, "Lagrange", 1) Iv = interpolate(v, V) """ # Check arguments if not isinstance(V, FunctionSpaceBase): cpp.dolfin_error( "interpolation.py", "compute interpolation", "Illegal function space for interpolation, not a FunctionSpace (%s)" % str(v)) # Compute interpolation Pv = Function(V) Pv.interpolate(v) return Pv
def MultiMeshFunctionSpace(multimesh, family, degree=None): """Create multimesh finite element function space. *Arguments* multimesh a :py:class:`MultiMesh <dolfin.cpp.MultiMesh>`. family a string specifying the element family, see :py:class:`FunctionSpace <dolfin.functions.functionspace.FunctionSpace>` for alternatives. This argument may also be a `FiniteElement`, in which case the `degree` argument should not be specified. degree the degree of the element. *Example of usage* .. code-block:: python V = MultiMeshFunctionSpace(mesh, "CG", 1) element = FiniteElement("Lagrange", triangle, 1) V = MultiMeshFunctionSpace(mesh, element) Note: Multimesh function spaces does currently not support function space algebra. For this reason, mixed function spaces and the like must be created via a finite element. """ # Check arguments if not isinstance(multimesh, cpp.MultiMesh): cpp.dolfin_error("functionspace.py", "create multimesh function space", "Illegal argument, not a multimesh: " + str(multimesh)) # Create element if not supplied if isinstance(family, ufl.FiniteElementBase): element = family else: mesh = multimesh.part(0) element = ufl.FiniteElement(family, mesh.ufl_cell(), degree) # Create and add individual function spaces V = cpp.MultiMeshFunctionSpace(multimesh) V_parts = [] for part in range(multimesh.num_parts()): V_part = FunctionSpace(multimesh.part(part), element) V_parts.append(V_part) V.add(V_part) # Build multimesh function space V.build() # Store full function spaces V._parts = V_parts return V
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 _init_convenience(self, mesh, family, degree, form_degree=None, constrained_domain=None, restriction=None): # Check arguments if not isinstance(family, string_types): cpp.dolfin_error( "functionspace.py", "create function space", "Illegal argument for finite element family, not a string: " + str(family)) if not isinstance(degree, int): cpp.dolfin_error( "functionspace.py", "create function space", "Illegal argument for degree, not an integer: " + str(degree)) # Create UFL element element = ufl.FiniteElement(family, mesh.ufl_cell(), degree, form_degree=form_degree) if restriction is not None: element = element[restriction] self._init_from_ufl(mesh, element, constrained_domain=constrained_domain)
def jit(form, form_compiler_parameters=None, common_cell=None): """Just-in-time compile any provided form. It uses the jit function from the form compiler registered by parameters["form_compiler"]["name"]. """ # Check that form is not empty if isinstance(form, ufl.Form): if form.integrals() == (): raise RuntimeError, "Form is empty. Cannot pass to JIT compiler." # Import form compiler form_compiler_name = cpp.parameters["form_compiler"]["name"] try: form_compiler = __import__(form_compiler_name) except ImportError, message: print message warning("Could not import %s form compiler, falling back to FFC." % form_compiler_name) try: form_compiler = __import__("ffc") except: cpp.dolfin_error("jit.py", "perform just-in-time compilation of form", "Could not import FFC form compiler")
def _init_from_ufl(self, mesh, element, constrained_domain=None): if not isinstance(element, ufl.FiniteElementBase): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a finite element: " + str(element)) if constrained_domain is not None: if not isinstance(constrained_domain, cpp.SubDomain): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a subdomain: " + str(constrained_domain)) # Initialize the ufl.FunctionSpace first to check for good meaning ufl.FunctionSpace.__init__(self, mesh.ufl_domain(), element) # Compile element and dofmap and construct corresponding dolfin objects dolfin_element, dolfin_dofmap = _compile_dolfin_element(element, mesh, constrained_domain=constrained_domain) # Initialize the cpp.FunctionSpace cpp.FunctionSpace.__init__(self, mesh, dolfin_element, dolfin_dofmap) # Store reference to constrained domain to avoid possible SWIG # director memory error (see # https://bitbucket.org/fenics-project/dolfin/issue/71) # TODO: Make constrained_domain private with getter? Attribute access breaks interface consistency. self.constrained_domain = constrained_domain
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 from ufl.algorithms import extract_arguments form_arguments = extract_arguments(form) 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 third 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): V = MixedFunctionSpace([w.function_space() for w in u]) du = ufl.split(Argument(V, number, part)) else: cpp.dolfin_error("formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument, please supply one") return ufl.derivative(form, u, du, coefficient_derivatives)
def extract_sub_space(self, component): """ Extract subspace for component *Arguments* component (numpy.array(uint)) The component. *Returns* _FunctionSpace_ The subspace. """ # Transform the argument to a NumPy array if not hasattr(component, "__len__"): cpp.dolfin_error("functionspace.py", "extracting sub spaces", "Expected a component which is iterable") component = numpy.asarray(component, dtype=numpy.uintp) # Get the cpp version of the FunctionSpace cpp_space = cpp.FunctionSpace.extract_sub_space(self, component) # Instantiate a ufl finite element based on the dolfin element signature element = eval(cpp_space.element().signature(), ufl.__dict__).reconstruct(domain=self.mesh()) return FunctionSpaceFromCpp(cpp_space, element)
def _extract_u(u): "Extract and check argument u" if not isinstance(u, cpp.Function): cpp.dolfin_error("solving.py", "solve variational problem", "Expecting second argument to be a Function") return u
def _extract_eq(eq): "Extract and check argument eq" if not isinstance(eq, ufl.classes.Equation): cpp.dolfin_error("solving.py", "solve variational problem", "Expecting first argument to be an Equation") return eq
def compute_edge_map(mesh0, mesh1): """ Compute map from edges of mesh0 to vertices of mesh1. *Arguments* mesh0 a :py:class:`Mesh <dolfin.cpp.Mesh>`. mesh1 a :py:class:`Mesh <dolfin.cpp.Mesh>`. It is assumed that both meshes have a :py:class:`MeshFunction <dolfin.cpp.MeshFunction>` over the vertices named "parent_vertex_indices" which contain a mapping from the local vertices to a common parent vertex numbering. """ # Check arguments if not isinstance(mesh0, Mesh): raise TypeError, "expected 'Mesh' as argument" if not isinstance(mesh1, Mesh): raise TypeError, "expected 'Mesh' as argument" # Get parent vertex numbers vertices0 = mesh0.data().array("parent_vertex_indices", 0) vertices1 = mesh1.data().array("parent_vertex_indices", 0) # Check mappings if len(vertices0) == 0 or len(vertices1) == 0: cpp.dolfin_error("ale.py", "compute edge map", "Parent vertex indices are missing") # Initialize edges mesh0.init(1) mesh1.init(1) # Build parent to local map from vertex pair to local edge for mesh0 parent_to_local_mesh0 = {} for edge in edges(mesh0): v = [vertices0[int(i)] for i in edge.entities(0)] v.sort() parent_to_local_mesh0[tuple(v)] = edge.index() # Build parent to local map from vertex pair to local edge for mesh1 parent_to_local_mesh1 = {} for edge in edges(mesh1): v = [vertices1[int(i)] for i in edge.entities(0)] v.sort() parent_to_local_mesh1[tuple(v)] = edge.index() # Get common edges common_edges = set(parent_to_local_mesh0.iterkeys()).intersection(set(parent_to_local_mesh1.iterkeys())) # Compute map edge_map = {} for edge in common_edges: edge_map[parent_to_local_mesh0[edge]] = parent_to_local_mesh1[edge] return edge_map
def compute_edge_map(mesh0, mesh1): """ Compute map from edges of mesh0 to vertices of mesh1. *Arguments* mesh0 a :py:class:`Mesh <dolfin.cpp.Mesh>`. mesh1 a :py:class:`Mesh <dolfin.cpp.Mesh>`. It is assumed that both meshes have a :py:class:`MeshFunction <dolfin.cpp.MeshFunction>` over the vertices named "parent_vertex_indices" which contain a mapping from the local vertices to a common parent vertex numbering. """ # Check arguments if not isinstance(mesh0, cpp.mesh.Mesh) or not isinstance( mesh1, cpp.mesh.Mesh): cpp.dolfin_error("ale.py", "compute edge map", "Expected 'Mesh' as argument") # Get parent vertex numbers vertices0 = mesh0.data().array("parent_vertex_indices", 0) vertices1 = mesh1.data().array("parent_vertex_indices", 0) # Check mappings if len(vertices0) == 0 or len(vertices1) == 0: cpp.dolfin_error("ale.py", "compute edge map", "Parent vertex indices are missing") # Initialize edges mesh0.init(1) mesh1.init(1) # Build parent to local map from vertex pair to local edge for mesh0 parent_to_local_mesh0 = {} for edge in edges(mesh0): v = [vertices0[int(i)] for i in edge.entities(0)] v.sort() parent_to_local_mesh0[tuple(v)] = edge.index() # Build parent to local map from vertex pair to local edge for mesh1 parent_to_local_mesh1 = {} for edge in edges(mesh1): v = [vertices1[int(i)] for i in edge.entities(0)] v.sort() parent_to_local_mesh1[tuple(v)] = edge.index() # Get common edges common_edges = set(parent_to_local_mesh0.keys()).intersection( set(parent_to_local_mesh1.keys())) # Compute map edge_map = {} for edge in common_edges: edge_map[parent_to_local_mesh0[edge]] = parent_to_local_mesh1[edge] return edge_map
def __init__(self, *args, **kwargs): "Create Dirichlet boundary condition" # Copy constructor if len(args) == 1: if not isinstance(args[0], cpp.DirichletBC): cpp.dolfin_error("bcs.py", "create DirichletBC", "Expecting a DirichleBC as only argument"\ " for copy constructor") # Initialize base class cpp.DirichletBC.__init__(self, args[0]) return # Special case for value specified as float, tuple or similar if len(args) >= 2 and not isinstance(args[1], cpp.GenericFunction): if isinstance(args[1], ufl.classes.Expr): expr = project(args[1], args[0]) else: expr = Constant(args[1]) # let Constant handle all problems args = args[:1] + (expr,) + args[2:] # Special case for sub domain specified as a function if len(args) >= 3 and isinstance(args[2], types.FunctionType): sub_domain = AutoSubDomain(args[2]) args = args[:2] + (sub_domain,) + args[3:] # Special case for sub domain specified as a string if len(args) >= 3 and isinstance(args[2], str): sub_domain = compile_subdomains(args[2]) args = args[:2] + (sub_domain,) + args[3:] # Store Expression to avoid scoping issue with SWIG directors if isinstance(args[1], cpp.Expression): self.function_arg = args[1] # Store SubDomain to avoid scoping issue with SWIG directors self.domain_args = args[2:] # FIXME: Handling of multiple default arguments does not # really work between Python and C++ when C++ requires them to # be ordered and cannot accept the latter without the # former... # Add keyword arguments (in correct order...) allowed_kwargs = ["method", "check_midpoint"] for key in allowed_kwargs: if key in kwargs: args = tuple(list(args) + [kwargs[key]]) # Check for other keyword arguments for key in kwargs: if not key in allowed_kwargs: cpp.dolfin_error("bcs.py", "create boundary condition", "Unknown keyword argument \"%s\"" % key) # Initialize base class cpp.DirichletBC.__init__(self, *args)
def interpolate(v, V): """ Return interpolation of a given function into a given finite element space. *Arguments* v a :py:class:`Function <dolfin.functions.function.Function>` or an :py:class:`Expression <dolfin.functions.expression.Expression>` V a :py:class:`FunctionSpace (standard, mixed, etc.) <dolfin.functions.functionspace.FunctionSpace>` *Example of usage* .. code-block:: python v = Expression("sin(pi*x[0])") V = FunctionSpace(mesh, "Lagrange", 1) Iv = interpolate(v, V) """ # Check arguments if not isinstance(V, FunctionSpace): cpp.dolfin_error("interpolation.py", "compute interpolation", "Illegal function space for interpolation, not a FunctionSpace (%s)" % str(v)) # Compute interpolation Pv = Function(V) Pv.interpolate(v) return Pv
def __init__(self, *args, **kwargs): "Create Dirichlet boundary condition" # Copy constructor if len(args) == 1: if not isinstance(args[0], cpp.DirichletBC): cpp.dolfin_error("bcs.py", "create DirichletBC", "Expecting a DirichleBC as only argument"\ " for copy constructor") # Initialize base class cpp.DirichletBC.__init__(self, args[0]) self.domain_args = args[0].domain_args return # Special case for value specified as float, tuple or similar if len(args) >= 2 and not isinstance(args[1], cpp.GenericFunction): if isinstance(args[1], ufl.classes.Expr): expr = project(args[1], args[0]) else: expr = Constant(args[1]) # let Constant handle all problems args = args[:1] + (expr, ) + args[2:] # Special case for sub domain specified as a function if len(args) >= 3 and isinstance(args[2], types.FunctionType): sub_domain = AutoSubDomain(args[2]) args = args[:2] + (sub_domain, ) + args[3:] # Special case for sub domain specified as a string if len(args) >= 3 and isinstance(args[2], str): sub_domain = CompiledSubDomain(args[2]) args = args[:2] + (sub_domain, ) + args[3:] # Store Expression to avoid scoping issue with SWIG directors if isinstance(args[1], cpp.Expression): self.function_arg = args[1] # Store SubDomain to avoid scoping issue with SWIG directors self.domain_args = args[2:] # FIXME: Handling of multiple default arguments does not # really work between Python and C++ when C++ requires them to # be ordered and cannot accept the latter without the # former... # Add keyword arguments (in correct order...) allowed_kwargs = ["method", "check_midpoint"] for key in allowed_kwargs: if key in kwargs: args = tuple(list(args) + [kwargs[key]]) # Check for other keyword arguments for key in kwargs: if not key in allowed_kwargs: cpp.dolfin_error("bcs.py", "create boundary condition", "Unknown keyword argument \"%s\"" % key) # Initialize base class cpp.DirichletBC.__init__(self, *args)
def adjoint(form, reordered_arguments=None): # Call UFL directly if new arguments are provided directly if reordered_arguments is not None: return ufl.adjoint(form, reordered_arguments=reordered_arguments) # Extract form arguments arguments = form.arguments() if any(arg.part() is not None for arg in arguments): cpp.dolfin_error("formmanipulation.py", "compute adjoint of form", "parts not supported") if not (len(arguments) == 2): cpp.dolfin_error("formmanipulation.py", "compute adjoint of form", "Form is not bilinear") # Define new Argument(s) in the same spaces (NB: Order does not # matter anymore here because number is absolute) v_1 = Argument(arguments[1].function_space(), arguments[0].number(), arguments[0].part()) v_0 = Argument(arguments[0].function_space(), arguments[1].number(), arguments[1].part()) # Call ufl.adjoint with swapped arguments as new arguments return ufl.adjoint(form, reordered_arguments=(v_1, v_0))
def extract_sub_space(self, component): """ Extract subspace for component *Arguments* component (numpy.array(uint)) The component. *Returns* _FunctionSpace_ The subspace. """ # Transform the argument to a NumPy array if not hasattr(component, "__len__"): cpp.dolfin_error("functionspace.py", "extracting sub spaces", "Expected a component which is iterable") component = numpy.asarray(component, dtype=numpy.uintp) # Get the cpp version of the FunctionSpace cpp_space = cpp.FunctionSpace.extract_sub_space(self, component) # Instantiate a ufl finite element based on the dolfin element signature element = eval(cpp_space.element().signature(), ufl.__dict__) return FunctionSpaceFromCpp(cpp_space, element)
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 from ufl.algorithms import extract_arguments form_arguments = extract_arguments(form) 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 third 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): V = MixedFunctionSpace([w.function_space() for w in u]) du = ufl.split(Argument(V, number, part)) else: cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument, please supply one" ) return ufl.derivative(form, u, du, coefficient_derivatives)
def MultiMeshFunctionSpace(multimesh, family, degree=None): """Create multimesh finite element function space. *Arguments* multimesh a :py:class:`MultiMesh <dolfin.cpp.MultiMesh>`. family a string specifying the element family, see :py:class:`FunctionSpace <dolfin.functions.functionspace.FunctionSpace>` for alternatives. This argument may also be a `FiniteElement`, in which case the `degree` argument should not be specified. degree the degree of the element. *Example of usage* .. code-block:: python V = MultiMeshFunctionSpace(mesh, "CG", 1) element = FiniteElement("Lagrange", triangle, 1) V = MultiMeshFunctionSpace(mesh, element) Note: Multimesh function spaces does currently not support function space algebra. For this reason, mixed function spaces and the like must be created via a finite element. """ # Check arguments if not isinstance(multimesh, cpp.MultiMesh): cpp.dolfin_error( "functionspace.py", "create multimesh function space", "Illegal argument, not a multimesh: " + str(multimesh)) # Create element if not supplied if isinstance(family, ufl.FiniteElementBase): element = family else: mesh = multimesh.part(0) element = ufl.FiniteElement(family, mesh.ufl_cell(), degree) # Create and add individual function spaces V = cpp.MultiMeshFunctionSpace(multimesh) V_parts = [] for part in range(multimesh.num_parts()): V_part = FunctionSpace(multimesh.part(part), element) V_parts.append(V_part) V.add(V_part) # Build multimesh function space V.build() # Store full function spaces V._parts = V_parts return V
def expect_arg(argtype, arg, argname): # Check the type of the argument if isinstance(arg, argtype): return cpp.dolfin_error("compilemodule.py", "ensure correct argument for compile_extension_module", "Provide a '%s', for the '%s' argument" % \ (argtype.__name__, argname))
def check_swig_version(compiled_module): # Check swig version of compiled module if compiled_module and compiled_module.swigversion != cpp.__swigversion__: cpp.dolfin_error("compilemodule.py", "compiling extension module", "Incompatible swig versions detected. DOLFIN swig "\ "version is not the same as extension module swig "\ "version: '%s' != '%s' " % \ (cpp.__swigversion__, compiled_module.swigversion))
def _solve_varproblem_adaptive(*args, **kwargs): "Solve variational problem a == L or F == 0 adaptively" # Extract arguments eq, u, bcs, J, tol, M, form_compiler_parameters, \ solver_parameters = _extract_args(*args, **kwargs) print('eq.lhs = ', eq.lhs, ' eq.rhs=', eq.rhs) # Check that we received the goal functional if M is None: cpp.dolfin_error("solving.py", "solve variational problem adaptively", "Missing goal functional") # Solve linear variational problem if isinstance(eq.lhs, ufl.Form) and isinstance(eq.rhs, ufl.Form): # Create problem problem = LinearVariationalProblem( eq.lhs, eq.rhs, u, bcs, form_compiler_parameters=form_compiler_parameters) # Create solver and call solve solver = AdaptiveLinearVariationalSolver(problem, M) solver.parameters.update(solver_parameters) solver.solve(tol) # Solve nonlinear variational problem else: # Create Jacobian if missing if J is None: cpp.log.info( "No Jacobian form specified for nonlinear variational problem." ) cpp.log.info( "Differentiating residual form F to obtain Jacobian J = F'.") F = eq.lhs J = derivative(F, u) # Create problem problem = NonlinearVariationalProblem( eq.lhs, u, bcs, J, form_compiler_parameters=form_compiler_parameters) # Create solver and call solve solver = AdaptiveNonlinearVariationalSolver(problem, M) solver.parameters.update(solver_parameters) solver.solve(tol)
def assign(self, rhs): """ Assign either a Function or linear combination of Functions. *Arguments* rhs (_Function_) A Function or a linear combination of Functions. If a linear combination is passed all Functions need to be in the same FunctionSpaces. """ from ufl.classes import ComponentTensor, Sum, Product, Division if isinstance(rhs, (cpp.Function, cpp.Expression, cpp.FunctionAXPY)): # Avoid self assignment if self == rhs: return self._assign(rhs) elif isinstance(rhs, (Sum, Product, Division, ComponentTensor)): if isinstance(rhs, ComponentTensor): rhs, multi_index = rhs.ufl_operands else: multi_index = None linear_comb = _check_and_contract_linear_comb(rhs, self, multi_index) assert linear_comb # If the assigned Function lives in a different FunctionSpace # we cannot operate on this function directly same_func_space = linear_comb[0][0] in self.function_space() func, weight = linear_comb.pop() # Assign values from first func if not same_func_space: self._assign(func) vector = self.vector() else: vector = self.vector() vector[:] = func.vector() # If first weight is not 1 scale if weight != 1.0: vector *= weight # AXPY the other functions for func, weight in linear_comb: if weight == 0.0: continue vector.axpy(weight, func.vector()) else: cpp.dolfin_error( "function.py", "function assignment", "Expects a Function or linear combinations of " "Functions in the same FunctionSpaces", )
def __new__(cls, cppV, element=None): if not isinstance(cppV, (cpp.FunctionSpace)): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a cpp.FunctionSpace: " + str(cppV)) # Lets be agressive in abusing dynamic typing shall we... cppV._dolfin_element = cppV.element() cppV._ufl_element = eval(cppV.element().signature(), ufl.__dict__).reconstruct(domain=cppV.mesh()) cppV.__class__ = FunctionSpaceBase return cppV
def assign(self, rhs): """ Assign either a Function or linear combination of Functions. *Arguments* rhs (_Function_) A Function or a linear combination of Functions. If a linear combination is passed all Functions need to be in the same FunctionSpaces. """ from ufl.classes import ComponentTensor, Sum, Product, Division if isinstance(rhs, (cpp.Function, cpp.Expression, cpp.FunctionAXPY)): # Avoid self assignment if self == rhs: return self._assign(rhs) elif isinstance(rhs, (Sum, Product, Division, ComponentTensor)): if isinstance(rhs, ComponentTensor): rhs, multi_index = rhs.ufl_operands else: multi_index = None linear_comb = _check_and_contract_linear_comb(rhs, self, \ multi_index) assert (linear_comb) # If the assigned Function lives in a different FunctionSpace # we cannot operate on this function directly same_func_space = linear_comb[0][0] in self.function_space() func, weight = linear_comb.pop() # Assign values from first func if not same_func_space: self._assign(func) vector = self.vector() else: vector = self.vector() vector[:] = func.vector() # If first weight is not 1 scale if weight != 1.0: vector *= weight # AXPY the other functions for func, weight in linear_comb: if weight == 0.0: continue vector.axpy(weight, func.vector()) else: cpp.dolfin_error("function.py", "function assignment", "Expects a Function or linear combinations of "\ "Functions in the same FunctionSpaces")
def _extract_bcs(bcs): "Extract and check argument bcs" if bcs is None: bcs = [] elif not isinstance(bcs, (list, tuple)): bcs = [bcs] for bc in bcs: if not isinstance(bc, cpp.DirichletBC): cpp.dolfin_error("solving.py", "solve variational problem", "Unable to extract boundary condition arguments") return bcs
def expect_list_of(argtype, arg, argname): if arg is None: return [] if isinstance(arg, (types.NoneType, list, tuple)): if all(isinstance(s, argtype) for s in arg): return arg cpp.dolfin_error("compilemodule.py", "ensure correct argument for compile_extension_module", "Provide a 'tuple' or 'list' with '%s', for the "\ "'%s' argument" % (argtype.__name__, argname))
def init_parent_edge_indices(submesh, mesh): "Initialize data 'parent_edge_indices' for submesh." # Check arguments if not isinstance(submesh, Mesh): raise TypeError, "expected 'Mesh' as argument" if not isinstance(mesh, Mesh): raise TypeError, "expected 'Mesh' as argument" # Check if edge map has already been computed if not submesh.data().mesh_function("parent_edge_indices") is None: info("Edge map 'parent_edge_indices' already computed, not computing again.") # Get parent vertex numbers parent_vertex_indices = submesh.data().mesh_function("parent_vertex_indices") if parent_vertex_indices is None: cpp.dolfin_error("ale.py", "initialize parent edge indices", "Parent vertex indice are missing") # Make sure that we have edges for both meshes submesh.init(1) mesh.init(1) # Make sure we have vertex-edge connectivity for parent mesh mesh.init(0, 1) # Create the edge map parent_edge_indices = submesh.data().create_mesh_function("parent_edge_indices") parent_edge_indices.init(1) # Iterate over the edges and figure out their parent number for local_edge in edges(submesh): # Get parent indices for edge vertices v0, v1 = local_edge.entities(0) V0 = Vertex(mesh, parent_vertex_indices[int(v0)]) V1 = Vertex(mesh, parent_vertex_indices[int(v1)]) # Get outgoing edges from the two parent vertices edges0 = set(V0.entities(1)) edges1 = set(V1.entities(1)) # Check intersection common_edges = edges0.intersection(edges1) if not len(common_edges) == 1: cpp.dolfin_error("ale.py", "initialize parent edge indices", "Parent vertices do not share exactly one common edge") parent_edge_index = list(common_edges)[0] # Set value parent_edge_indices[local_edge.index()] = parent_edge_index
def init_parent_edge_indices(submesh, mesh): "Initialize data 'parent_edge_indices' for submesh." # Check arguments if not isinstance(submesh, Mesh): raise TypeError("expected 'Mesh' as argument") if not isinstance(mesh, Mesh): raise TypeError("expected 'Mesh' as argument") # Check if edge map has already been computed if not submesh.data().exists("parent_edge_indices", 1): info( "Edge map 'parent_edge_indices' already computed, not computing again." ) # Get parent vertex numbers parent_vertex_indices = submesh.data().array("parent_vertex_indices", 0) if parent_vertex_indices is None: cpp.dolfin_error("ale.py", "initialize parent edge indices", "Parent vertex indice are missing") # Make sure that we have edges for both meshes submesh.init(1) mesh.init(1) # Make sure we have vertex-edge connectivity for parent mesh mesh.init(0, 1) # Create the edge map parent_edge_indices = submesh.data().create_array("parent_edge_indices", 1) # Iterate over the edges and figure out their parent number for local_edge in edges(submesh): # Get parent indices for edge vertices v0, v1 = local_edge.entities(0) V0 = Vertex(mesh, parent_vertex_indices[int(v0)]) V1 = Vertex(mesh, parent_vertex_indices[int(v1)]) # Get outgoing edges from the two parent vertices edges0 = set(V0.entities(1)) edges1 = set(V1.entities(1)) # Check intersection common_edges = edges0.intersection(edges1) if not len(common_edges) == 1: cpp.dolfin_error( "ale.py", "initialize parent edge indices", "Parent vertices do not share exactly one common edge") parent_edge_index = list(common_edges)[0] # Set value parent_edge_indices[local_edge.index()] = parent_edge_index
def __init__(self, form, function_spaces=None, coefficients=None, subdomains=None, form_compiler_parameters=None, common_cell=None): "Create JIT-compiled form from any given form (compiled or not)." # Check form argument if isinstance(form, ufl.Form): self._compiled_form, module, self.form_data, prefix \ = jit(form, form_compiler_parameters, common_cell) elif isinstance(form, ufc.form): self._compiled_form = form self.form_data = None elif isinstance(form, cpp.Form): self._compiled_form = form._compiled_form self.form_data = form.form_data else: cpp.dolfin_error("form.py", "creating dolfin.Form", "Expected a ufl.Form, ufc.form or a dolfin.Form") # Extract function spaces self.function_spaces = _extract_function_spaces(self.form_data, self._compiled_form, function_spaces) # Extract coefficients (self.coefficients, self._compiled_coefficients) = \ _extract_coefficients(self.form_data, coefficients) # Initialize base class cpp.Form.__init__(self, self._compiled_form, self.function_spaces, self.coefficients) # Extract subdomains from form_data, override if given explicitly self.subdomains = _extract_subdomains(self.form_data, subdomains) # 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)
def __init__(self, mesh): "Create function that evaluates to the mesh coordinates at each vertex." # Initialize C++ part cpp.MeshCoordinates.__init__(self, mesh) # Initialize UFL part ufl_element = mesh.ufl_domain().ufl_coordinate_element() if ufl_element.family() != "Lagrange" or ufl_element.degree() != 1: cpp.dolfin_error("specialfunctions.py", "initialize MeshCoordinates", "dolfin::MeshCoordinates only supports affine meshes") ufl_function_space = ufl.FunctionSpace(mesh.ufl_domain(), ufl_element) ufl.Coefficient.__init__(self, ufl_function_space, count=self.id())
def __init__(self, mesh, element, constrained_domain=None): """Create function space on given mesh for given finite element. *Arguments* mesh A :py:class:`Mesh <dolfin.cpp.Mesh>` element A :py:class:`(UFL) FiniteElement <ufl.FiniteElementBase>` """ # Store reference to constrained domain to avoid possible SWIG # director memory error (see # https://bitbucket.org/fenics-project/dolfin/issue/71) self.constrained_domain = constrained_domain # Check arguments if not isinstance(mesh, (cpp.Mesh, cpp.Restriction)): cpp.dolfin_error( "functionspace.py", "create function space", "Illegal argument, not a mesh or restriction: " + str(mesh)) if not isinstance(element, (ufl.FiniteElementBase)): cpp.dolfin_error( "functionspace.py", "create function space", "Illegal argument, not a finite element: " + str(element)) if constrained_domain is not None: if not isinstance(constrained_domain, cpp.SubDomain): cpp.dolfin_error( "functionspace.py", "create function space", "Illegal argument, not a subdomain: " + str(constrained_domain)) # Store element Note: self._ufl_element cannot be a private # attribute as we want to be able to set the element from a # derived class. self._ufl_element = element # JIT-compile element to get ufc_element and ufc_dofmap ufc_element, ufc_dofmap = jit(self._ufl_element, mpi_comm=mesh.mpi_comm()) # Instantiate DOLFIN FiniteElement and DofMap self._dolfin_element = cpp.FiniteElement(ufc_element) if constrained_domain is not None: if isinstance(mesh, cpp.Restriction): cpp.dolfin_error( "functionspace.py", "create function space", "Cannot use constrained domains together with restrictions." ) dolfin_dofmap = cpp.DofMap(ufc_dofmap, mesh, constrained_domain) else: if isinstance(mesh, cpp.Restriction): dolfin_dofmap = cpp.DofMap(ufc_dofmap, mesh) mesh = mesh.mesh() else: dolfin_dofmap = cpp.DofMap(ufc_dofmap, mesh) # Initialize the cpp_FunctionSpace cpp.FunctionSpace.__init__(self, mesh, self._dolfin_element, dolfin_dofmap)
def derivative(form, u, du=None): if du is None: if isinstance(u, Function): V = u.function_space() du = Argument(V) elif isinstance(u, (list,tuple)) and all(isinstance(w, Function) for w in u): V = MixedFunctionSpace([w.function_space() for w in u]) du = ufl.split(Argument(V)) else: cpp.dolfin_error("formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument, please supply one") return ufl.derivative(form, u, du)
def mpi_jit(*args, **kwargs): # FIXME: should require mpi_comm to be explicit # and not default to comm_world? mpi_comm = kwargs.pop("mpi_comm", cpp.MPI.comm_world) # Just call JIT compiler when running in serial if cpp.MPI.size(mpi_comm) == 1: return local_jit(*args, **kwargs) # Default status (0 == ok, 1 == fail) status = 0 # Compile first on process 0 root = cpp.MPI.rank(mpi_comm) == 0 if root: try: output = local_jit(*args, **kwargs) except Exception as e: status = 1 error_msg = str(e) # TODO: This would have lower overhead if using the dijitso.jit # features to inject a waiting callback instead of waiting out # here. That approach allows all processes to first look in the # cache, introducing a barrier only on cache miss. There's also # a sketch in dijitso of how to make only one process per # physical cache directory do the compilation. # Wait for the compiling process to finish and get status # TODO: Would be better to broadcast the status from root but # this works. global_status = cpp.MPI.max(mpi_comm, status) if global_status == 0: # Success, call jit on all other processes (this should just # read the cache) if not root: output = local_jit(*args, **kwargs) else: # Fail simultaneously on all processes, to allow catching # the error without deadlock if not root: error_msg = "Compilation failed on root node." cpp.dolfin_error("jit.py", "perform just-in-time compilation of form", error_msg) return output
def __init__(self, mesh, element, constrained_domain=None): """Create function space on given mesh for given finite element. *Arguments* mesh A :py:class:`Mesh <dolfin.cpp.Mesh>` element A :py:class:`(UFL) FiniteElement <ufl.FiniteElementBase>` """ # Store reference to constrained domain to avoid possible SWIG # director memory error (see # https://bitbucket.org/fenics-project/dolfin/issue/71) self.constrained_domain = constrained_domain # Check arguments if not isinstance(mesh, (cpp.Mesh, cpp.Restriction)): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a mesh or restriction: " + str(mesh)) if not isinstance(element, (ufl.FiniteElementBase)): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a finite element: " + str(element)) if constrained_domain is not None: if not isinstance(constrained_domain, cpp.SubDomain): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a subdomain: " + str(constrained_domain)) # Store element Note: self._ufl_element cannot be a private # attribute as we want to be able to set the element from a # derived class. self._ufl_element = element # JIT-compile element to get ufc_element and ufc_dofmap ufc_element, ufc_dofmap = jit(self._ufl_element, mpi_comm=mesh.mpi_comm()) # Instantiate DOLFIN FiniteElement and DofMap self._dolfin_element = cpp.FiniteElement(ufc_element) if constrained_domain is not None: if isinstance(mesh, cpp.Restriction): cpp.dolfin_error("functionspace.py", "create function space", "Cannot use constrained domains together with restrictions.") dolfin_dofmap = cpp.DofMap(ufc_dofmap, mesh, constrained_domain) else: if isinstance(mesh, cpp.Restriction): dolfin_dofmap = cpp.DofMap(ufc_dofmap, mesh) mesh = mesh.mesh() else: dolfin_dofmap = cpp.DofMap(ufc_dofmap, mesh) # Initialize the cpp_FunctionSpace cpp.FunctionSpace.__init__(self, mesh, self._dolfin_element, dolfin_dofmap)
def derivative(form, u, du=None): if du is None: if isinstance(u, Function): V = u.function_space() du = Argument(V) elif isinstance(u, (list, tuple)) and all( isinstance(w, Function) for w in u): V = MixedFunctionSpace([w.function_space() for w in u]) du = ufl.split(Argument(V)) else: cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument, please supply one" ) return ufl.derivative(form, u, du)
def jit(form, form_compiler_parameters=None, mpi_comm=None): """Just-in-time compile any provided form. It uses the jit function from the form compiler registered by parameters["form_compiler"]["name"]. """ # Check that form is not empty if isinstance(form, ufl.Form): if form.empty(): raise RuntimeError("Form is empty. Cannot pass to JIT compiler.") # Import form compiler form_compiler_name = cpp.parameters["form_compiler"]["name"] try: form_compiler = __import__(form_compiler_name) except ImportError as message: print(message) warning("Could not import %s form compiler, falling back to FFC." \ % form_compiler_name) try: form_compiler = __import__("ffc") except: cpp.dolfin_error("jit.py", "perform just-in-time compilation of form", "Could not import FFC form compiler") # Checks on form compiler interface if not (hasattr(form_compiler, 'default_parameters') and hasattr(form_compiler, 'jit')): raise RuntimeError( "Form compiler must implement the default_parameters and jit functions." ) # Prepare form compiler parameters p = form_compiler.default_parameters() # Set parameters from global DOLFIN parameter set for key, value in six.iteritems(parameters["form_compiler"]): p[key] = value # Override with local parameters if any if form_compiler_parameters: p.update(form_compiler_parameters) # Execute! return form_compiler.jit(form, parameters=p)
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 __init__(self, 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]) """ # 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, FunctionSpaceBase) for V in spaces): cpp.dolfin_error("functionspace.py", "create mixed function space", "Invalid subspaces: " + str(spaces)) # Create UFL element element = ufl.MixedElement(*[V.ufl_element() for V in spaces]) # Get common mesh and constrained_domain, must all be the same mesh, constrained_domain \ = _get_common_mesh_and_constrained_domain(spaces, "mixed") # Initialize base class using mesh from first space FunctionSpaceBase.__init__(self, mesh, element, \ constrained_domain=constrained_domain)
def __init__(self, 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]) """ # 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, FunctionSpaceBase) for V in spaces): cpp.dolfin_error("functionspace.py", "create mixed function space", "Invalid subspaces: " + str(spaces)) #if not all(V.mesh() == spaces[0].mesh() for V in spaces): # cpp.dolfin_error("functionspace.py", "Nonmatching meshes for mixed function space: " \ # + str([V.mesh() for V in spaces])) # Check that all spaces share same constrained_domain map # Create UFL element element = ufl.MixedElement(*[V.ufl_element() for V in spaces]) # Initialize base class using mesh from first space FunctionSpaceBase.__init__(self, spaces[0].mesh(), element, constrained_domain=spaces[0].dofmap().constrained_domain)
def jit(form, form_compiler_parameters=None, common_cell=None): """Just-in-time compile any provided form. It uses the jit function from the form compiler registered by parameters["form_compiler"]["name"]. """ # Check that form is not empty if isinstance(form, ufl.Form): if form.integrals() == (): raise RuntimeError, "Form is empty. Cannot pass to JIT compiler." global _swig_version_ok # Check and set swig binary if not _swig_version_ok and not check_and_set_swig_binary(\ parameters["swig_binary"], parameters["swig_path"]): raise OSError, "Could not find swig installation. Pass an existing "\ "swig binary or install SWIG version 2.0 or higher.\n" # Check that the form compiler will use the same swig version # that PyDOLFIN was compiled with _swig_version_ok = _swig_version_ok or \ check_swig_version(cpp.__swigversion__, same=True) if not _swig_version_ok: raise OSError, """\ PyDOLFIN was not compiled with the present version of swig. Install swig version %s or recompiled PyDOLFIN with present swig """%cpp.__swigversion__ # Cache swig version test _swig_version_ok = True # Import form compiler form_compiler_name = cpp.parameters["form_compiler"]["name"] try: form_compiler = __import__(form_compiler_name) except ImportError, message: print message warning("Could not import %s form compiler, falling back to FFC." % form_compiler_name) try: form_compiler = __import__("ffc") except: cpp.dolfin_error("jit.py", "perform just-in-time compilation of form", "Could not import FFC form compiler")
def compute_vertex_map(mesh0, mesh1): """ Compute map from vertices of mesh0 to vertices of mesh1. *Arguments* mesh0 a :py:class:`Mesh <dolfin.cpp.Mesh>`. mesh1 a :py:class:`Mesh <dolfin.cpp.Mesh>`. It is assumed that both meshes have a :py:class:`MeshFunction <dolfin.cpp.MeshFunction>` over the vertices named "parent_vertex_indices" which contain a mapping from the local vertices to a common parent vertex numbering. """ # Check arguments if not isinstance(mesh0, Mesh): raise TypeError, "expected 'Mesh' as argument" if not isinstance(mesh1, Mesh): raise TypeError, "expected 'Mesh' as argument" # Get parent vertex numbers vertices0 = mesh0.data().array("parent_vertex_indices", 0) vertices1 = mesh1.data().array("parent_vertex_indices", 0) # Check mappings if vertices0 is None or vertices1 is None: cpp.dolfin_error("ale.py", "compute vertex map", "Parent vertex indices are missing") # Compute parent-to-local mapping for mesh1 parent_to_local_mesh1 = {} for i in range(len(vertices1)): parent_to_local_mesh1[vertices1[i]] = i # Compute local-to-local mapping vertex_map = {} for i in range(vertices0.size): parent_vertex = vertices0[i] if parent_vertex in parent_to_local_mesh1: vertex_map[i] = parent_to_local_mesh1[parent_vertex] return vertex_map
def __init__(self, *args, **kwargs): "Create Dirichlet boundary condition" # Copy constructor if len(args) == 1: if not isinstance(args[0], cpp.DirichletBC): cpp.dolfin_error("bcs.py", "create DirichletBC", "Expecting a DirichleBC as only argument"\ " for copy constructor") # Initialize base class cpp.DirichletBC.__init__(self, args[0]) return # Special case for value specified as float, tuple or similar if len(args) >= 2 and not isinstance(args[1], cpp.GenericFunction): if isinstance(args[1], ufl.classes.Expr): expr = project(args[1], args[0]) else: expr = Constant(args[1]) # let Constant handle all problems args = args[:1] + (expr,) + args[2:] # Special case for sub domain specified as a function if len(args) >= 3 and isinstance(args[2], types.FunctionType): sub_domain = AutoSubDomain(args[2]) args = args[:2] + (sub_domain,) + args[3:] # Special case for sub domain specified as a string if len(args) >= 3 and isinstance(args[2], str): sub_domain = compile_subdomains(args[2]) args = args[:2] + (sub_domain,) + args[3:] # Store Expression to avoid scoping issue with SWIG directors if isinstance(args[1], cpp.Expression): self.function_arg = args[1] # Store SubDomain to avoid scoping issue with SWIG directors self.domain_args = args[2:] # Add method argument if it's given if "method" in kwargs: args = tuple(list(args) + [kwargs["method"]]) # Initialize base class cpp.DirichletBC.__init__(self, *args)
def jit(ufl_object, form_compiler_parameters=None, mpi_comm=None): """Just-in-time compile any provided UFL Form or FiniteElement using FFC. Default parameters from FFC are overridden by parameters["form_compiler"] first and then the form_compiler_parameters argument to this function. """ # Check that form is not empty (workaround for bug in UFL where # bilinear form 0*u*v*dx becomes the functional 0*dx) if isinstance(ufl_object, ufl.Form) and ufl_object.empty(): cpp.dolfin_error("jit.py", "perform just-in-time compilation of form", "Form is empty. Cannot pass to JIT compiler") # Compatibility checks on ffc interface if not (hasattr(ffc, 'default_parameters') and hasattr(ffc, 'jit') and hasattr(ffc, 'ufc_signature')): cpp.dolfin_error( "jit.py", "perform just-in-time compilation of form", "Form compiler must implement 'default_parameters()', " "'jit(ufl_object, parameters=None)' " "and 'ufc_signature()' functions") # Check DOLFIN build time UFC matches currently loaded UFC if cpp.__ufcsignature__ != ffc.ufc_signature(): cpp.dolfin_error( "jit.py", "perform just-in-time compilation of form", "DOLFIN was not compiled against matching" "UFC from current FFC installation.") # Prepare form compiler parameters with overrides from dolfin and kwargs p = ffc.default_parameters() p.update(parameters["form_compiler"]) p.update(form_compiler_parameters or {}) # Execute! try: result = ffc.jit(ufl_object, parameters=p) except Exception as e: tb_text = ''.join(traceback.format_exception(*sys.exc_info())) cpp.dolfin_error("jit.py", "perform just-in-time compilation of form", "ffc.jit failed with message:\n%s" % (tb_text, )) if isinstance(ufl_object, ufl.Form): compiled_form, module, prefix = result compiled_form = cpp.make_ufc_form(compiled_form) return compiled_form, module, prefix elif isinstance(ufl_object, ufl.FiniteElementBase): ufc_element, ufc_dofmap = result ufc_element = cpp.make_ufc_finite_element(ufc_element) ufc_dofmap = cpp.make_ufc_dofmap(ufc_dofmap) return ufc_element, ufc_dofmap elif isinstance(ufl_object, ufl.Mesh): ufc_coordinate_mapping = result ufc_coordinate_mapping = cpp.make_ufc_coordinate_mapping( ufc_coordinate_mapping) return ufc_coordinate_mapping
def compute_vertex_map(mesh0, mesh1): """ Compute map from vertices of mesh0 to vertices of mesh1. *Arguments* mesh0 a :py:class:`Mesh <dolfin.cpp.Mesh>`. mesh1 a :py:class:`Mesh <dolfin.cpp.Mesh>`. It is assumed that both meshes have a :py:class:`MeshFunction <dolfin.cpp.MeshFunction>` over the vertices named "parent_vertex_indices" which contain a mapping from the local vertices to a common parent vertex numbering. """ # Check arguments if not isinstance(mesh0, cpp.mesh.Mesh) or not isinstance( mesh1, cpp.mesh.Mesh): cpp.dolfin_error("ale.py", "compute vertex map", "Expected 'Mesh' as argument") # Get parent vertex numbers vertices0 = mesh0.data().array("parent_vertex_indices", 0) vertices1 = mesh1.data().array("parent_vertex_indices", 0) # Check mappings if vertices0 is None or vertices1 is None: cpp.dolfin_error("ale.py", "compute vertex map", "Parent vertex indices are missing") # Compute parent-to-local mapping for mesh1 parent_to_local_mesh1 = {} for i in range(len(vertices1)): parent_to_local_mesh1[vertices1[i]] = i # Compute local-to-local mapping vertex_map = {} for i in range(vertices0.size): parent_vertex = vertices0[i] if parent_vertex in parent_to_local_mesh1: vertex_map[i] = parent_to_local_mesh1[parent_vertex] return vertex_map
def __init__(self, inside_function): "Create SubDomain subclass for given inside() function" # Check that we get a function if not isinstance(inside_function, types.FunctionType): cpp.dolfin_error("bcs.py", "auto-create subdomain", "Expecting a function (not %s)" % \ str(type(inside_function))) self.inside_function = inside_function # Check the number of arguments if not inside_function.func_code.co_argcount in (1, 2): cpp.dolfin_error("bcs.py", "auto-create subdomain", "Expecting a function of the form inside(x) or inside(x, on_boundary)") self.num_args = inside_function.func_code.co_argcount cpp.SubDomain.__init__(self)
def __init__(self, mesh, element, constrained_domain=None): """Create function space on given mesh for given finite element. *Arguments* mesh A :py:class:`Mesh <dolfin.cpp.Mesh>` element A :py:class:`(UFL) FiniteElement <ufl.FiniteElementBase>` """ # Check arguments if not isinstance(mesh, (cpp.Mesh, cpp.Restriction)): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a mesh or restriction: " + str(mesh)) if not isinstance(element, (ufl.FiniteElementBase)): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a finite element: " + str(element)) if constrained_domain is not None: if not isinstance(constrained_domain, cpp.SubDomain): cpp.dolfin_error("functionspace.py", "create function space", "Illegal argument, not a subdomain: " + str(constrained_domain)) # Store element # Note: self._ufl_element cannot be a private attribute as we want to be able to # set the element from a derived class. self._ufl_element = element # JIT-compile element to get ufc_element and ufc_dofmap ufc_element, ufc_dofmap = jit(self._ufl_element) # Instantiate DOLFIN FiniteElement and DofMap self._dolfin_element = cpp.FiniteElement(ufc_element) if constrained_domain is not None: if isinstance(mesh, cpp.Restriction): cpp.dolfin_error("functionspace.py", "create function space", "Cannot use constrained domains together with restrictions.") dolfin_dofmap = cpp.DofMap(ufc_dofmap, mesh, constrained_domain) else: if isinstance(mesh, cpp.Restriction): dolfin_dofmap = cpp.DofMap(ufc_dofmap, mesh) mesh = mesh.mesh() else: dolfin_dofmap = cpp.DofMap(ufc_dofmap, mesh) # Initialize the cpp_FunctionSpace cpp.FunctionSpace.__init__(self, mesh, self._dolfin_element, dolfin_dofmap)