def ffc_jit(ufl_form, form_compiler_parameters=None): # Prepare form compiler parameters with overrides from dolfin and kwargs p = ffc.default_jit_parameters() p.update(dict(parameters["form_compiler"])) p.update(form_compiler_parameters or {}) return ffc.jit(ufl_form, parameters=p)
def element_pair(request): """Given a UFL element, returns UFL element and a JIT-compiled and wrapped UFC element.""" ufl_element = request.param ufc_element, ufc_dofmap = ffc.jit(ufl_element, parameters=None) ufc_element = ffc_factory.make_ufc_finite_element(ufc_element) return ufl_element, ufc_element
def element_pair(request): """Given a UFL element, returns UFL element and a JIT-compiled and wrapped UFC element. """ ufl_element = request.param ufc_element, ufc_dofmap = ffc.jit(ufl_element, parameters=None) ufc_element = ffc_factory.make_ufc_finite_element(ufc_element) return ufl_element, ufc_element
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 test_poisson(self): "Test that JIT compiler is fast enough." # FIXME: Use local cache: cache_dir argument to instant.build_module #options = {"log_level": INFO + 5} #options = {"log_level": 5} options = {"log_level": WARNING} # Define two forms with the same signatures element = FiniteElement("Lagrange", "triangle", 1) v = TestFunction(element) u = TrialFunction(element) f = Coefficient(element) g = Coefficient(element) a0 = f*dot(grad(v), grad(u))*dx a1 = g*dot(grad(v), grad(u))*dx # Strange this needs to be done twice # Compile a0 so it will be in the cache (both in-memory and disk) jit(a0, options) jit(a0, options) # Compile a0 again (should be really fast, using in-memory cache) t = time() jit(a0, options) dt0 = time() - t # Compile a1 (should be fairly fast, using disk cache) t = time() jit(a1, options) dt1 = time() - t # Good values dt0_good = 0.005 dt1_good = 0.01 print("\nJIT in-memory cache:", dt0) print("JIT disk cache: ", dt1) print("Reasonable values are %g and %g" % (dt0_good, dt1_good)) # Check times assert dt0 < 10*dt0_good assert dt1 < 10*dt1_good
def _init_from_ufl(self, mesh, element, constrained_domain=None): # Initialize the ufl.FunctionSpace first to check for good # meaning ufl.FunctionSpace.__init__(self, mesh.ufl_domain(), element) # Compile dofmap and element ufc_element, ufc_dofmap = ffc.jit(element, parameters=None) ufc_element = cpp.fem.make_ufc_finite_element(ufc_element) # Create DOLFIN element and dofmap dolfin_element = cpp.fem.FiniteElement(ufc_element) ufc_dofmap = cpp.fem.make_ufc_dofmap(ufc_dofmap) if constrained_domain is None: dolfin_dofmap = cpp.fem.DofMap(ufc_dofmap, mesh) else: dolfin_dofmap = cpp.fem.DofMap(ufc_dofmap, mesh, constrained_domain) # Initialize the cpp.FunctionSpace self._cpp_object = cpp.function.FunctionSpace(mesh, dolfin_element, dolfin_dofmap)
def __init__(self, form, **kwargs): # Check form argument if not isinstance(form, ufl.Form): raise RuntimeError("Expected a ufl.Form.") sd = form.subdomain_data() self.subdomains, = list(sd.values()) # Assuming single domain domain, = list(sd.keys()) # Assuming single domain mesh = domain.ufl_cargo() # Having a mesh in the form is a requirement if mesh is None: raise RuntimeError("Expecting to find a Mesh in the form.") form_compiler_parameters = kwargs.pop("form_compiler_parameters", None) # Add DOLFIN include paths (just the Boost path for special # math functions is really required) # FIXME: move getting include paths to elsewhere import pkgconfig d = pkgconfig.parse('dolfin') if form_compiler_parameters is None: form_compiler_parameters = {"external_include_dirs": d["include_dirs"]} else: # FIXME: add paths if dict entry already exists form_compiler_parameters["external_include_dirs"] = d["include_dirs"] ufc_form = ffc.jit(form, form_compiler_parameters) ufc_form = cpp.fem.make_ufc_form(ufc_form[0]) function_spaces = [func.function_space()._cpp_object for func in form.arguments()] cpp.fem.Form.__init__(self, ufc_form, function_spaces) original_coefficients = form.coefficients() self.coefficients = [] for i in range(self.num_coefficients()): j = self.original_coefficient_position(i) self.coefficients.append(original_coefficients[j].cpp_object()) # Type checking coefficients if not all(isinstance(c, (cpp.function.GenericFunction)) for c in self.coefficients): coefficient_error = "Error while extracting coefficients. " raise TypeError(coefficient_error + "Either provide a dict of cpp.function.GenericFunctions, " + "or use Function to define your form.") for i in range(self.num_coefficients()): if isinstance(self.coefficients[i], cpp.function.GenericFunction): self.set_coefficient(i, self.coefficients[i]) # Attach mesh (because function spaces and coefficients may be # empty lists) if not function_spaces: self.set_mesh(mesh) # Attach subdomains to C++ Form 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("vertex") if subdomains is not None: self.set_vertex_domains(subdomains)
def ffc_jit(ufl_form, form_compiler_parameters=None): # Prepare form compiler parameters with overrides from dolfin p = ffc.default_jit_parameters() p["scalar_type"] = "double complex" if common.has_petsc_complex else "double" p.update(form_compiler_parameters or {}) return ffc.jit(ufl_form, parameters=p)