def compute_ir(analysis, parameters): "Compute intermediate representation." begin("Compiler stage 2: Computing intermediate representation") # Set code generation parameters set_float_formatting(int(parameters["precision"])) # Extract data from analysis form_datas, elements, element_numbers = analysis # Compute representation of elements info("Computing representation of %d elements" % len(elements)) ir_elements = [_compute_element_ir(e, i, element_numbers) \ for (i, e) in enumerate(elements)] # Compute representation of dofmaps info("Computing representation of %d dofmaps" % len(elements)) ir_dofmaps = [_compute_dofmap_ir(e, i, element_numbers) for (i, e) in enumerate(elements)] # Compute and flatten representation of integrals info("Computing representation of integrals") irs = [_compute_integral_ir(fd, i, parameters) \ for (i, fd) in enumerate(form_datas)] ir_integrals = [ir for ir in chain(*irs) if not ir is None] # Compute representation of forms info("Computing representation of forms") ir_forms = [_compute_form_ir(fd, i, element_numbers) \ for (i, fd) in enumerate(form_datas)] end() return ir_elements, ir_dofmaps, ir_integrals, ir_forms
def compute_ir(analysis, prefix, parameters, object_names=None): "Compute intermediate representation." begin("Compiler stage 2: Computing intermediate representation") # Set code generation parameters set_float_formatting(int(parameters["precision"])) # Extract data from analysis form_datas, elements, element_numbers, coordinate_elements = analysis # Compute representation of elements if not parameters["format"] == "pyop2": info("Computing representation of %d elements" % len(elements)) ir_elements = [_compute_element_ir(e, prefix, element_numbers) for e in elements] else: ir_elements = [None] # Compute representation of dofmaps if not parameters["format"] == "pyop2": info("Computing representation of %d dofmaps" % len(elements)) ir_dofmaps = [_compute_dofmap_ir(e, prefix, element_numbers) for e in elements] # Compute representation of coordinate mappings info("Computing representation of %d coordinate mappings" % len(coordinate_elements)) ir_compute_coordinate_mappings = [_compute_coordinate_mapping_ir(e, prefix, element_numbers) for e in coordinate_elements] else: ir_dofmaps = [None] ir_compute_coordinate_mappings = [None] # Compute and flatten representation of integrals info("Computing representation of integrals") irs = [_compute_integral_ir(fd, i, prefix, element_numbers, parameters, object_names=object_names) for (i, fd) in enumerate(form_datas)] ir_integrals = [ir for ir in chain(*irs) if not ir is None] # Compute representation of forms if not parameters["format"] == "pyop2": info("Computing representation of forms") ir_forms = [_compute_form_ir(fd, i, prefix, element_numbers) for (i, fd) in enumerate(form_datas)] else: ir_forms = [None] end() return ir_elements, ir_dofmaps, ir_compute_coordinate_mappings, ir_integrals, ir_forms
def compute_ir(analysis, parameters): "Compute intermediate representation." begin("Compiler stage 2: Computing intermediate representation") # Set code generation parameters set_float_formatting(int(parameters["precision"])) # Extract data from analysis form_datas, elements, element_numbers = analysis # Compute representation of elements info("Computing representation of %d elements" % len(elements)) ir_elements = [_compute_element_ir(e, i, element_numbers) \ for (i, e) in enumerate(elements)] # Compute representation of dofmaps info("Computing representation of %d dofmaps" % len(elements)) ir_dofmaps = [ _compute_dofmap_ir(e, i, element_numbers) for (i, e) in enumerate(elements) ] # Compute and flatten representation of integrals info("Computing representation of integrals") irs = [_compute_integral_ir(fd, i, parameters) \ for (i, fd) in enumerate(form_datas)] ir_integrals = [ir for ir in chain(*irs) if not ir is None] # Compute representation of forms info("Computing representation of forms") ir_forms = [_compute_form_ir(fd, i, element_numbers) \ for (i, fd) in enumerate(form_datas)] end() return ir_elements, ir_dofmaps, ir_integrals, ir_forms
# You should have received a copy of the GNU Lesser General Public License # along with FFC. If not, see <http://www.gnu.org/licenses/>. # # First added: 2010-01-06 # Last changed: 2010-03-11 # Pyhton modules import unittest import time # FFC modules from ffc.quadrature.symbolics import * from ffc.cpp import format, set_float_formatting from ffc.parameters import FFC_PARAMETERS set_float_formatting(FFC_PARAMETERS['precision']) class TestElasticityTerm(unittest.TestCase): def testElasticityTerm(self): # expr: 0.25*W1*det*(FE0_C2_D001[0][j]*FE0_C2_D001[0][k]*Jinv_00*Jinv_21 + FE0_C2_D001[0][j]*FE0_C2_D001[0][k]*Jinv_00*Jinv_21) expr = Product([ FloatValue(0.25), Symbol('W1', GEO), Symbol('det', GEO), Sum([ Product([ Symbol('FE0_C2_D001_0_j', BASIS), Symbol('FE0_C2_D001_0_k', BASIS), Symbol('Jinv_00', GEO), Symbol('Jinv_21', GEO)
# You should have received a copy of the GNU Lesser General Public License # along with FFC. If not, see <http://www.gnu.org/licenses/>. # # First added: 2010-01-06 # Last changed: 2010-02-01 # Pyhton modules from __future__ import print_function import unittest import time # FFC modules from ffc.quadrature.symbolics import * from ffc.cpp import format, set_float_formatting from ffc.parameters import FFC_PARAMETERS set_float_formatting(FFC_PARAMETERS['precision']) class TestRealExamples(unittest.TestCase): def testRealExamples(self): # p = Product([ # Sum([ # Product([ # Symbol('w[5][0]', GEO), # Fraction( # Product([ # Symbol('FE0_C1_D01[ip][k]', BASIS), Symbol('Jinv_10', GEO) # ]), # Product([ # Symbol('w[5][0]', GEO), Symbol('w[5][0]', GEO)
def compile_coordinate_element(ufl_coordinate_element): """Generates C code for changing to reference coordinates. :arg ufl_coordinate_element: UFL element of the coordinates :returns: C code as string """ from ffc.cpp import set_float_formatting, format from ffc.fiatinterface import create_actual_fiat_element from ffc.symbolic import ssa_arrays, c_print from FIAT.reference_element import two_product_cell import ufl import sympy as sp import numpy as np # Set code generation parameters parameters = _check_parameters(None) set_float_formatting(int(parameters["precision"])) def dX_norm_square(topological_dimension): return " + ".join("dX[{0}]*dX[{0}]".format(i) for i in xrange(topological_dimension)) def X_isub_dX(topological_dimension): return "\n".join("\tX[{0}] -= dX[{0}];".format(i) for i in xrange(topological_dimension)) def is_affine(ufl_element): return ufl_element.cell().is_simplex() and ufl_element.degree() <= 1 and ufl_element.family() in ["Discontinuous Lagrange", "Lagrange"] def inside_check(ufl_cell, fiat_cell): dim = ufl_cell.topological_dimension() point = tuple(sp.Symbol("X[%d]" % i) for i in xrange(dim)) return " && ".join("(%s)" % arg for arg in fiat_cell.contains_point(point, epsilon=1e-14).args) def init_X(fiat_element): f_float = format["floating point"] f_assign = format["assign"] fiat_cell = fiat_element.get_reference_element() vertices = np.array(fiat_cell.get_vertices()) X = np.average(vertices, axis=0) return "\n".join(f_assign("X[%d]" % i, f_float(v)) for i, v in enumerate(X)) def to_reference_coordinates(ufl_cell, fiat_element): f_decl = format["declaration"] f_float_decl = format["float declaration"] # Get the element cell name and geometric dimension. cell = ufl_cell gdim = cell.geometric_dimension() tdim = cell.topological_dimension() code = [] # Symbolic tabulation tabs = fiat_element.tabulate(1, np.array([[sp.Symbol("X[%d]" % i) for i in xrange(tdim)]])) tabs = sorted((d, value.reshape(value.shape[:-1])) for d, value in tabs.iteritems()) # Generate code for intermediate values s_code, d_phis = ssa_arrays(map(lambda (k, v): v, tabs), prefix="t") phi = d_phis.pop(0) for name, value in s_code: code += [f_decl(f_float_decl, name, c_print(value))] # Cell coordinate data C = np.array([[sp.Symbol("C[%d][%d]" % (i, j)) for j in range(gdim)] for i in range(fiat_element.space_dimension())]) # Generate physical coordinates x = phi.dot(C) for i, e in enumerate(x): code += ["\tx[%d] = %s;" % (i, e)] # Generate Jacobian grad_phi = np.vstack(reversed(d_phis)) J = np.transpose(grad_phi.dot(C)) for i, row in enumerate(J): for j, e in enumerate(row): code += ["\tJ[%d * %d + %d] = %s;" % (i, tdim, j, e)] # Get code snippets for Jacobian, inverse of Jacobian and mapping of # coordinates from physical element to the FIAT reference element. code_ = [format["compute_jacobian_inverse"](cell)] # FIXME: use cell orientations! # if needs_orientation: # code_ += [format["orientation"]["ufc"](tdim, gdim)] # FIXME: ugly hack code_ = "\n".join(code_).split("\n") code_ = filter(lambda line: not line.startswith(("double J", "double K", "double detJ")), code_) code += code_ x = np.array([sp.Symbol("x[%d]" % i) for i in xrange(gdim)]) x0 = np.array([sp.Symbol("x0[%d]" % i) for i in xrange(gdim)]) K = np.array([[sp.Symbol("K[%d]" % (i*gdim + j)) for j in range(gdim)] for i in range(tdim)]) dX = K.dot(x - x0) for i, e in enumerate(dX): code += ["\tdX[%d] = %s;" % (i, e)] return "\n".join(code) # Create FIAT element element = create_actual_fiat_element(ufl_coordinate_element) cell = ufl_coordinate_element.cell() # calculate_basisvalues, vdim = calculate_basisvalues(cell, element) extruded = isinstance(element.get_reference_element(), two_product_cell) code = { "geometric_dimension": cell.geometric_dimension(), "topological_dimension": cell.topological_dimension(), "inside_predicate": inside_check(cell, element.get_reference_element()), "to_reference_coords": to_reference_coordinates(cell, element), "init_X": init_X(element), "max_iteration_count": 1 if is_affine(ufl_coordinate_element) else 16, "convergence_epsilon": 1e-12, "dX_norm_square": dX_norm_square(cell.topological_dimension()), "X_isub_dX": X_isub_dX(cell.topological_dimension()), "extruded_arg": ", int nlayers" if extruded else "", "nlayers": ", f->n_layers" if extruded else "", } evaluate_template_c = """#include <math.h> #include <firedrake_geometry.h> struct ReferenceCoords { double X[%(geometric_dimension)d]; double J[%(geometric_dimension)d * %(topological_dimension)d]; double K[%(topological_dimension)d * %(geometric_dimension)d]; double detJ; }; static inline void to_reference_coords_kernel(void *result_, double *x0, int *return_value, double **C) { struct ReferenceCoords *result = (struct ReferenceCoords *) result_; const int space_dim = %(geometric_dimension)d; /* * Mapping coordinates from physical to reference space */ double *X = result->X; %(init_X)s double x[space_dim]; double *J = result->J; double *K = result->K; double detJ; double dX[%(topological_dimension)d]; int converged = 0; for (int it = 0; !converged && it < %(max_iteration_count)d; it++) { %(to_reference_coords)s if (%(dX_norm_square)s < %(convergence_epsilon)g * %(convergence_epsilon)g) { converged = 1; } %(X_isub_dX)s } result->detJ = detJ; // Are we inside the reference element? *return_value = %(inside_predicate)s; } static inline void wrap_to_reference_coords(void *result_, double *x, int *return_value, double *coords, int *coords_map%(extruded_arg)s, int cell); int to_reference_coords(void *result_, struct Function *f, int cell, double *x) { int return_value; wrap_to_reference_coords(result_, x, &return_value, f->coords, f->coords_map%(nlayers)s, cell); return return_value; } """ return evaluate_template_c % code
def compile_element(ufl_element, cdim): """Generates C code for point evaluations. :arg ufl_element: UFL element of the function space :arg cdim: ``cdim`` of the function space :returns: C code as string """ from ffc.cpp import set_float_formatting, format from ffc.fiatinterface import create_actual_fiat_element from ffc.symbolic import ssa_arrays, c_print from FIAT.reference_element import two_product_cell import ufl import sympy as sp import numpy as np # Set code generation parameters parameters = _check_parameters(None) set_float_formatting(int(parameters["precision"])) def calculate_basisvalues(ufl_cell, fiat_element): f_component = format["component"] f_decl = format["declaration"] f_float_decl = format["float declaration"] f_tensor = format["tabulate tensor"] f_new_line = format["new line"] tdim = ufl_cell.topological_dimension() gdim = ufl_cell.geometric_dimension() code = [] # Symbolic tabulation tabs = fiat_element.tabulate(0, np.array([[sp.Symbol("reference_coords.X[%d]" % i) for i in xrange(tdim)]])) tabs = tabs[(0,) * tdim] tabs = tabs.reshape(tabs.shape[:-1]) # Generate code for intermediate values s_code, (theta,) = ssa_arrays([tabs]) for name, value in s_code: code += [f_decl(f_float_decl, name, c_print(value))] # Prepare Jacobian, Jacobian inverse and determinant s_detJ = sp.Symbol('detJ') s_J = np.array([[sp.Symbol("J[{i}*{tdim} + {j}]".format(i=i, j=j, tdim=tdim)) for j in range(tdim)] for i in range(gdim)]) s_Jinv = np.array([[sp.Symbol("K[{i}*{gdim} + {j}]".format(i=i, j=j, gdim=gdim)) for j in range(gdim)] for i in range(tdim)]) # Apply transformations phi = [] for i, val in enumerate(theta): mapping = fiat_element.mapping()[i] if mapping == "affine": phi.append(val) elif mapping == "contravariant piola": phi.append(s_J.dot(val) / s_detJ) elif mapping == "covariant piola": phi.append(s_Jinv.transpose().dot(val)) else: error("Unknown mapping: %s" % mapping) phi = np.asarray(phi, dtype=object) # Dump tables of basis values code += ["", "\t// Values of basis functions"] code += [f_decl("double", f_component("phi", phi.shape), f_new_line + f_tensor(phi))] shape = phi.shape if len(shape) <= 1: vdim = 1 elif len(shape) == 2: vdim = shape[1] return "\n".join(code), vdim # Create FIAT element element = create_actual_fiat_element(ufl_element) cell = ufl_element.cell() calculate_basisvalues, vdim = calculate_basisvalues(cell, element) extruded = isinstance(element.get_reference_element(), two_product_cell) code = { "cdim": cdim, "vdim": vdim, "geometric_dimension": cell.geometric_dimension(), "ndofs": element.space_dimension(), "calculate_basisvalues": calculate_basisvalues, "extruded_arg": ", int nlayers" if extruded else "", "nlayers": ", f->n_layers" if extruded else "", } evaluate_template_c = """static inline void evaluate_kernel(double *result, double *phi_, double **F) { const int ndofs = %(ndofs)d; const int cdim = %(cdim)d; const int vdim = %(vdim)d; double (*phi)[vdim] = (double (*)[vdim]) phi_; // F: ndofs x cdim // phi: ndofs x vdim // result = F' * phi: cdim x vdim // // Usually cdim == 1 or vdim == 1. for (int q = 0; q < cdim * vdim; q++) { result[q] = 0.0; } for (int i = 0; i < ndofs; i++) { for (int c = 0; c < cdim; c++) { for (int v = 0; v < vdim; v++) { result[c*vdim + v] += F[i][c] * phi[i][v]; } } } } static inline void wrap_evaluate(double *result, double *phi, double *data, int *map%(extruded_arg)s, int cell); int evaluate(struct Function *f, double *x, double *result) { struct ReferenceCoords reference_coords; int cell = locate_cell(f, x, %(geometric_dimension)d, &to_reference_coords, &reference_coords); if (cell == -1) { return -1; } if (!result) { return 0; } double *J = reference_coords.J; double *K = reference_coords.K; double detJ = reference_coords.detJ; %(calculate_basisvalues)s wrap_evaluate(result, (double *)phi, f->f, f->f_map%(nlayers)s, cell); return 0; } """ return evaluate_template_c % code
# # You should have received a copy of the GNU Lesser General Public License # along with FFC. If not, see <http://www.gnu.org/licenses/>. # # First added: 2010-01-06 # Last changed: 2010-02-01 # Pyhton modules import unittest import time # FFC modules from ffc.quadrature.symbolics import * from ffc.cpp import format, set_float_formatting from ffc.parameters import FFC_PARAMETERS set_float_formatting(FFC_PARAMETERS["precision"]) class TestFloat(unittest.TestCase): def testFloat(self): "Test simple FloatValue instance." f0 = FloatValue(1.5) f1 = FloatValue(-5) f2 = FloatValue(-1e-14) f3 = FloatValue(-1e-11) f4 = FloatValue(1.5) # print "\nTesting FloatValue" # print "f0: '%s'" %f0 # print "f1: '%s'" %f1 # print "f2: '%s'" %f2