def power(self, o): #print("\n\nVisiting Power: " + repr(o)) # Get base and exponent. base, expo = o.ufl_operands # Visit base to get base code. base_code = self.visit(base) # TODO: Are these safety checks needed? ffc_assert(() in base_code and len(base_code) == 1, "Only support function type base: " + repr(base_code)) # Get the base code and create power. val = base_code[()] # Handle different exponents if isinstance(expo, IntValue): return {(): create_product([val] * expo.value())} elif isinstance(expo, FloatValue): if self.parameters["format"] == "pyop2": exp = create_float(expo.value()) else: exp = format["floating point"](expo.value()) var = format["std power"][self.parameters["format"]](str(val), exp) if self.parameters["format"] == "pyop2": sym = create_funcall(var, [val, exp]) else: sym = create_symbol(var, val.t, val, 1, iden=var) return {(): sym} elif isinstance(expo, (Coefficient, Operator)): exp = self.visit(expo)[()] # print "pow exp: ", exp # print "pow val: ", val var = format["std power"][self.parameters["format"]](str(val), exp) if self.parameters["format"] == "pyop2": sym = create_funcall(var, [val, exp]) else: sym = create_symbol(var, val.t, val, 1, iden=var) return {(): sym} else: error("power does not support this exponent: " + repr(expo))
def _format_scalar_value(self, value): # print("format_scalar_value: %d" % value) if value is None: return {(): create_float(0.0)} return {(): create_float(value)}
def create_function(self, ufl_function, derivatives, component, local_comp, local_offset, ffc_element, is_quad_element, transformation, multiindices, tdim, gdim, avg): "Create code for basis functions, and update relevant tables of used basis." ffc_assert( ufl_function in self._function_replace_values, "Expecting ufl_function to have been mapped prior to this call.") # Prefetch formats to speed up code generation. f_transform = format["transform"] f_detJ = format["det(J)"] # Reset code code = [] # Handle affine mappings. if transformation == "affine": # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] # Create function name. function_name = self._create_function_name( component, deriv, avg, is_quad_element, ufl_function, ffc_element) if function_name: # Add transformation if needed. code.append( self.__apply_transform(function_name, derivatives, multi, tdim, gdim)) # Handle non-affine mappings. else: ffc_assert( avg is None, "Taking average is not supported for non-affine mappings.") # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] if transformation in [ "covariant piola", "contravariant piola" ]: for c in range(tdim): function_name = self._create_function_name( c + local_offset, deriv, avg, is_quad_element, ufl_function, ffc_element) if function_name: # Multiply basis by appropriate transform. if transformation == "covariant piola": dxdX = create_symbol( f_transform("JINV", c, local_comp, tdim, gdim, self.restriction), GEO) function_name = create_product( [dxdX, function_name]) elif transformation == "contravariant piola": detJ = create_fraction( create_float(1), create_symbol(f_detJ(self.restriction), GEO)) dXdx = create_symbol( f_transform("J", local_comp, c, gdim, tdim, self.restriction), GEO) function_name = create_product( [detJ, dXdx, function_name]) # Add transformation if needed. code.append( self.__apply_transform(function_name, derivatives, multi, tdim, gdim)) elif transformation == "double covariant piola": # g_ij = (Jinv)_ki G_kl (Jinv)lj i = local_comp // tdim j = local_comp % tdim for k in range(tdim): for l in range(tdim): # Create mapping and basis name. function_name = self._create_function_name( k * tdim + l + local_offset, deriv, avg, is_quad_element, ufl_function, ffc_element) J1 = create_symbol( f_transform("JINV", k, i, tdim, gdim, self.restriction), GEO) J2 = create_symbol( f_transform("JINV", l, j, tdim, gdim, self.restriction), GEO) function_name = create_product( [J1, function_name, J2]) # Add transformation if needed. code.append( self.__apply_transform(function_name, derivatives, multi, tdim, gdim)) elif transformation == "double contravariant piola": # g_ij = (detJ)^(-2) J_ik G_kl J_jl i = local_comp // tdim j = local_comp % tdim for k in range(tdim): for l in range(tdim): # Create mapping and basis name. function_name = self._create_function_name( k * tdim + l + local_offset, deriv, avg, is_quad_element, ufl_function, ffc_element) J1 = create_symbol( f_transform("J", i, k, tdim, gdim, self.restriction), GEO) J2 = create_symbol( f_transform("J", j, l, tdim, gdim, self.restriction), GEO) invdetJ = create_fraction( create_float(1), create_symbol(f_detJ(self.restriction), GEO)) function_name = create_product( [invdetJ, invdetJ, J1, function_name, J2]) # Add transformation if needed. code.append( self.__apply_transform(function_name, derivatives, multi, tdim, gdim)) else: error("Transformation is not supported: ", repr(transformation)) if not code: return create_float(0.0) elif len(code) > 1: code = create_sum(code) else: code = code[0] return code
def create_argument(self, ufl_argument, derivatives, component, local_comp, local_offset, ffc_element, transformation, multiindices, tdim, gdim, avg): "Create code for basis functions, and update relevant tables of used basis." # Prefetch formats to speed up code generation. f_transform = format["transform"] f_detJ = format["det(J)"] # Reset code code = {} # Affine mapping if transformation == "affine": # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] # Create mapping and basis name. mapping, basis = self._create_mapping_basis( component, deriv, avg, ufl_argument, ffc_element) if mapping not in code: code[mapping] = [] if basis is not None: # Add transformation if needed. code[mapping].append( self.__apply_transform(basis, derivatives, multi, tdim, gdim)) # Handle non-affine mappings. else: ffc_assert( avg is None, "Taking average is not supported for non-affine mappings.") # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] if transformation in [ "covariant piola", "contravariant piola" ]: for c in range(tdim): # Create mapping and basis name. mapping, basis = self._create_mapping_basis( c + local_offset, deriv, avg, ufl_argument, ffc_element) if mapping not in code: code[mapping] = [] if basis is not None: # Multiply basis by appropriate transform. if transformation == "covariant piola": dxdX = create_symbol( f_transform("JINV", c, local_comp, tdim, gdim, self.restriction), GEO) basis = create_product([dxdX, basis]) elif transformation == "contravariant piola": detJ = create_fraction( create_float(1), create_symbol(f_detJ(self.restriction), GEO)) dXdx = create_symbol( f_transform("J", local_comp, c, gdim, tdim, self.restriction), GEO) basis = create_product([detJ, dXdx, basis]) # Add transformation if needed. code[mapping].append( self.__apply_transform(basis, derivatives, multi, tdim, gdim)) elif transformation == "double covariant piola": # g_ij = (Jinv)_ki G_kl (Jinv)lj i = local_comp // tdim j = local_comp % tdim for k in range(tdim): for l in range(tdim): # Create mapping and basis name. mapping, basis = self._create_mapping_basis( k * tdim + l + local_offset, deriv, avg, ufl_argument, ffc_element) if mapping not in code: code[mapping] = [] if basis is not None: J1 = create_symbol( f_transform("JINV", k, i, tdim, gdim, self.restriction), GEO) J2 = create_symbol( f_transform("JINV", l, j, tdim, gdim, self.restriction), GEO) basis = create_product([J1, basis, J2]) # Add transformation if needed. code[mapping].append( self.__apply_transform( basis, derivatives, multi, tdim, gdim)) elif transformation == "double contravariant piola": # g_ij = (detJ)^(-2) J_ik G_kl J_jl i = local_comp // tdim j = local_comp % tdim for k in range(tdim): for l in range(tdim): # Create mapping and basis name. mapping, basis = self._create_mapping_basis( k * tdim + l + local_offset, deriv, avg, ufl_argument, ffc_element) if mapping not in code: code[mapping] = [] if basis is not None: J1 = create_symbol( f_transform("J", i, k, gdim, tdim, self.restriction), GEO) J2 = create_symbol( f_transform("J", j, l, gdim, tdim, self.restriction), GEO) invdetJ = create_fraction( create_float(1), create_symbol(f_detJ(self.restriction), GEO)) basis = create_product( [invdetJ, invdetJ, J1, basis, J2]) # Add transformation if needed. code[mapping].append( self.__apply_transform( basis, derivatives, multi, tdim, gdim)) else: error("Transformation is not supported: " + repr(transformation)) # Add sums and group if necessary. for key, val in list(code.items()): if len(val) > 1: code[key] = create_sum(val) else: code[key] = val[0] return code
def create_function(self, ufl_function, derivatives, component, local_comp, local_offset, ffc_element, is_quad_element, transformation, multiindices, tdim, gdim, avg): "Create code for basis functions, and update relevant tables of used basis." ffc_assert( ufl_function in self._function_replace_values, "Expecting ufl_function to have been mapped prior to this call.") # Prefetch formats to speed up code generation. f_transform = format["transform"] f_detJ = format["det(J)"] # Reset code code = [] # Handle affine mappings. if transformation == "affine": # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] # Create function name. function_name = self._create_function_name( component, deriv, avg, is_quad_element, ufl_function, ffc_element) if function_name: # Add transformation if needed. code.append( self.__apply_transform(function_name, derivatives, multi, tdim, gdim)) # Handle non-affine mappings. else: ffc_assert( avg is None, "Taking average is not supported for non-affine mappings.") # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] for c in range(tdim): function_name = self._create_function_name( c + local_offset, deriv, avg, is_quad_element, ufl_function, ffc_element) if function_name: # Multiply basis by appropriate transform. if transformation == "covariant piola": dxdX = create_symbol( f_transform("JINV", c, local_comp, tdim, gdim, self.restriction), GEO, loop_index=[c * gdim + local_comp], iden="K%s" % _choose_map(self.restriction)) function_name = create_product( [dxdX, function_name]) elif transformation == "contravariant piola": detJ = create_fraction( create_float(1), create_symbol(f_detJ(self.restriction), GEO, iden=f_detJ(self.restriction))) dXdx = create_symbol(f_transform("J", local_comp, c, gdim, tdim, self.restriction), GEO, \ loop_index=[local_comp*tdim + c], iden="J%s" % _choose_map(self.restriction)) function_name = create_product( [detJ, dXdx, function_name]) else: error("Transformation is not supported: ", repr(transformation)) # Add transformation if needed. code.append( self.__apply_transform(function_name, derivatives, multi, tdim, gdim)) if not code: return create_float(0.0) elif len(code) > 1: code = create_sum(code) else: code = code[0] return code
def create_argument(self, ufl_argument, derivatives, component, local_comp, local_offset, ffc_element, transformation, multiindices, tdim, gdim, avg): "Create code for basis functions, and update relevant tables of used basis." # Prefetch formats to speed up code generation. f_transform = format["transform"] f_detJ = format["det(J)"] # Reset code code = {} # Affine mapping if transformation == "affine": # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] # Create mapping and basis name. mapping, basis = self._create_mapping_basis( component, deriv, avg, ufl_argument, ffc_element) if isinstance(mapping, list): for ma, ba in zip(mapping, basis): if not ma in code: code[ma] = [] if basis is not None: # Add transformation if needed. code[ma].append( self.__apply_transform(ba, derivatives, multi, tdim, gdim)) else: if not mapping in code: code[mapping] = [] if basis is not None: # Add transformation if needed. code[mapping].append( self.__apply_transform(basis, derivatives, multi, tdim, gdim)) # Handle non-affine mappings. else: ffc_assert( avg is None, "Taking average is not supported for non-affine mappings.") # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] for c in range(tdim): # Create mapping and basis name. mapping, basis = self._create_mapping_basis( c + local_offset, deriv, avg, ufl_argument, ffc_element) if not mapping in code: code[mapping] = [] if basis is not None: # Multiply basis by appropriate transform. if transformation == "covariant piola": dxdX = create_symbol( f_transform("JINV", c, local_comp, tdim, gdim, self.restriction), GEO, loop_index=[c * gdim + local_comp], iden="K%s" % _choose_map(self.restriction)) basis = create_product([dxdX, basis]) elif transformation == "contravariant piola": detJ = create_fraction(create_float(1), \ create_symbol(f_detJ(self.restriction), GEO, iden=f_detJ(self.restriction))) dXdx = create_symbol(f_transform("J", local_comp, c, gdim, tdim, self.restriction), GEO, \ loop_index=[local_comp*tdim + c], iden="J%s" % _choose_map(self.restriction)) basis = create_product([detJ, dXdx, basis]) else: error("Transformation is not supported: " + repr(transformation)) # Add transformation if needed. code[mapping].append( self.__apply_transform(basis, derivatives, multi, tdim, gdim)) # Add sums and group if necessary. for key, val in list(code.items()): if len(val) > 1: code[key] = create_sum(val) else: code[key] = val[0] return code
def _compute_basisvalues(data, dof_data): """From FIAT_NEW.expansions.""" UNROLL = True # Prefetch formats to speed up code generation. f_comment = format["comment"] f_add = format["add"] f_mul = format["mul"] f_imul = format["imul"] f_sub = format["sub"] f_group = format["grouping"] f_assign = format["assign"] f_sqrt = format["sqrt"]["ufc"] f_x = format["x coordinate"] f_y = format["y coordinate"] f_z = format["z coordinate"] f_double = format["float declaration"] f_basisvalue = format["basisvalues"] f_component = format["component"] f_float = format["floating point"] f_uint = format["uint declaration"] f_tensor = format["tabulate tensor"] f_loop = format["generate loop"] f_decl = format["declaration"] f_tmp = format["tmp value"] f_int = format["int"] f_r = format["free indices"][0] # Create temporary values. f1, f2, f3, f4, f5 = [create_symbol(f_tmp(i), CONST) for i in range(0,5)] # Get embedded degree. embedded_degree = dof_data["embedded_degree"] # Create helper symbols. symbol_p = create_symbol(f_r, CONST) symbol_x = create_symbol(f_x, CONST) symbol_y = create_symbol(f_y, CONST) symbol_z = create_symbol(f_z, CONST) int_n1 = f_int(embedded_degree + 1) float_1 = create_float(1) float_2 = create_float(2) float_0_5 = create_float(0.5) float_0_25 = create_float(0.25) # Initialise return code. code = [""] # Create zero array for basisvalues. # Get number of members of the expansion set. num_mem = dof_data["num_expansion_members"] code += [f_comment("Array of basisvalues")] code += [f_decl(f_double, f_component(f_basisvalue, num_mem), f_tensor([0.0]*num_mem))] # Declare helper variables, will be removed if not used. code += ["", f_comment("Declare helper variables")] # Keeping this here to avoid changing references # Get the element cell name element_cellname = data["cellname"] def _jrc(a, b, n): an = float( ( 2*n+1+a+b)*(2*n+2+a+b))/ float( 2*(n+1)*(n+1+a+b)) bn = float( (a*a-b*b) * (2*n+1+a+b))/ float( 2*(n+1)*(2*n+a+b)*(n+1+a+b) ) cn = float( (n+a)*(n+b)*(2*n+2+a+b))/ float( (n+1)*(n+1+a+b)*(2*n+a+b) ) return (an,bn,cn) # 1D if (element_cellname == "interval"): # FIAT_NEW.expansions.LineExpansionSet. # FIAT_NEW code # psitilde_as = jacobi.eval_jacobi_batch(0,0,n,ref_pts) # FIAT_NEW.jacobi.eval_jacobi_batch(a,b,n,xs) # The initial value basisvalue 0 is always 1.0 # FIAT_NEW code # for ii in range(result.shape[1]): # result[0,ii] = 1.0 + xs[ii,0] - xs[ii,0] code += ["", f_comment("Compute basisvalues")] code += [f_assign(f_component(f_basisvalue, 0), f_float(1.0))] # Only continue if the embedded degree is larger than zero. if embedded_degree > 0: # FIAT_NEW.jacobi.eval_jacobi_batch(a,b,n,xs). # result[1,:] = 0.5 * ( a - b + ( a + b + 2.0 ) * xsnew ) # The initial value basisvalue 1 is always x code += [f_assign(f_component(f_basisvalue, 1), f_x)] # Only active is embedded_degree > 1. if embedded_degree > 1: # FIAT_NEW.jacobi.eval_jacobi_batch(a,b,n,xs). # apb = a + b (equal to 0 because of function arguments) # for k in range(2,n+1): # a1 = 2.0 * k * ( k + apb ) * ( 2.0 * k + apb - 2.0 ) # a2 = ( 2.0 * k + apb - 1.0 ) * ( a * a - b * b ) # a3 = ( 2.0 * k + apb - 2.0 ) \ # * ( 2.0 * k + apb - 1.0 ) \ # * ( 2.0 * k + apb ) # a4 = 2.0 * ( k + a - 1.0 ) * ( k + b - 1.0 ) \ # * ( 2.0 * k + apb ) # a2 = a2 / a1 # a3 = a3 / a1 # a4 = a4 / a1 # result[k,:] = ( a2 + a3 * xsnew ) * result[k-1,:] \ # - a4 * result[k-2,:] # The below implements the above (with a = b = apb = 0) for r in range(2, embedded_degree+1): # Define helper variables a1 = 2.0*r*r*(2.0*r - 2.0) a3 = ((2.0*r - 2.0)*(2.0*r - 1.0 )*(2.0*r))/a1 a4 = (2.0*(r - 1.0)*(r - 1.0)*(2.0*r))/a1 assign_to = f_component(f_basisvalue, r) assign_from = f_sub([f_mul([f_x, f_component(f_basisvalue, r-1), f_float(a3)]), f_mul([f_component(f_basisvalue, r-2), f_float(a4)])]) code += [f_assign(assign_to, assign_from)] # Scale values. # FIAT_NEW.expansions.LineExpansionSet. # FIAT_NEW code # results = numpy.zeros( ( n+1 , len(pts) ) , type( pts[0][0] ) ) # for k in range( n + 1 ): # results[k,:] = psitilde_as[k,:] * math.sqrt( k + 0.5 ) lines = [] loop_vars = [(str(symbol_p), 0, int_n1)] # Create names. basis_k = create_symbol(f_component(f_basisvalue, str(symbol_p)), CONST) # Compute value. fac1 = create_symbol( f_sqrt(str(symbol_p + float_0_5)), CONST ) lines += [format["imul"](str(basis_k), str(fac1))] # Create loop (block of lines). code += f_loop(lines, loop_vars) # 2D elif (element_cellname == "triangle"): # FIAT_NEW.expansions.TriangleExpansionSet. # Compute helper factors # FIAT_NEW code # f1 = (1.0+2*x+y)/2.0 # f2 = (1.0 - y) / 2.0 # f3 = f2**2 fac1 = create_fraction(float_1 + float_2*symbol_x + symbol_y, float_2) fac2 = create_fraction(float_1 - symbol_y, float_2) code += [f_decl(f_double, str(f1), fac1)] code += [f_decl(f_double, str(f2), fac2)] code += [f_decl(f_double, str(f3), f2*f2)] code += ["", f_comment("Compute basisvalues")] # The initial value basisvalue 0 is always 1.0. # FIAT_NEW code # for ii in range( results.shape[1] ): # results[0,ii] = 1.0 + apts[ii,0]-apts[ii,0]+apts[ii,1]-apts[ii,1] code += [f_assign(f_component(f_basisvalue, 0), f_float(1.0))] def _idx2d(p, q): return (p + q)*(p + q + 1)//2 + q # Only continue if the embedded degree is larger than zero. if embedded_degree > 0: # The initial value of basisfunction 1 is equal to f1. # FIAT_NEW code # results[idx(1,0),:] = f1 code += [f_assign(f_component(f_basisvalue, 1), str(f1))] # NOTE: KBO: The order of the loops is VERY IMPORTANT!! # Only active is embedded_degree > 1. if embedded_degree > 1: # FIAT_NEW code (loop 1 in FIAT) # for p in range(1,n): # a = (2.0*p+1)/(1.0+p) # b = p / (p+1.0) # results[idx(p+1,0)] = a * f1 * results[idx(p,0),:] \ # - p/(1.0+p) * f3 *results[idx(p-1,0),:] # FIXME: KBO: Is there an error in FIAT? why is b not used? for r in range(1, embedded_degree): rr = _idx2d((r + 1), 0) assign_to = f_component(f_basisvalue, rr) ss = _idx2d(r, 0) tt = _idx2d((r - 1), 0) A = (2*r + 1.0)/(r + 1) B = r/(1.0 + r) v1 = f_mul([f_component(f_basisvalue, ss), f_float(A), str(f1)]) v2 = f_mul([f_component(f_basisvalue, tt), f_float(B), str(f3)]) assign_from = f_sub([v1, v2]) code += [f_assign(assign_to, assign_from)] # FIAT_NEW code (loop 2 in FIAT). # for p in range(n): # results[idx(p,1),:] = 0.5 * (1+2.0*p+(3.0+2.0*p)*y) \ # * results[idx(p,0)] for r in range(0, embedded_degree): # (p+q)*(p+q+1)//2 + q rr = _idx2d(r, 1) assign_to = f_component(f_basisvalue, rr) ss = _idx2d(r, 0) A = 0.5*(1 + 2*r) B = 0.5*(3 + 2*r) C = f_add([f_float(A), f_mul([f_float(B), str(symbol_y)])]) assign_from = f_mul([f_component(f_basisvalue, ss), f_group(C)]) code += [f_assign(assign_to, assign_from)] # Only active is embedded_degree > 1. if embedded_degree > 1: # FIAT_NEW code (loop 3 in FIAT). # for p in range(n-1): # for q in range(1,n-p): # (a1,a2,a3) = jrc(2*p+1,0,q) # results[idx(p,q+1),:] \ # = ( a1 * y + a2 ) * results[idx(p,q)] \ # - a3 * results[idx(p,q-1)] for r in range(0, embedded_degree - 1): for s in range(1, embedded_degree - r): rr = _idx2d(r, (s + 1)) ss = _idx2d(r, s) tt = _idx2d(r, s - 1) A, B, C = _jrc(2*r + 1, 0, s) assign_to = f_component(f_basisvalue, rr) assign_from = f_sub([f_mul([f_component(f_basisvalue, ss), f_group(f_add([f_float(B), f_mul([str(symbol_y), f_float(A)])]))]), f_mul([f_component(f_basisvalue, tt), f_float(C)])]) code += [f_assign(assign_to, assign_from)] # FIAT_NEW code (loop 4 in FIAT). # for p in range(n+1): # for q in range(n-p+1): # results[idx(p,q),:] *= math.sqrt((p+0.5)*(p+q+1.0)) n1 = embedded_degree + 1 for r in range(0, n1): for s in range(0, n1 - r): rr = _idx2d(r, s) A = (r + 0.5)*(r + s + 1) assign_to = f_component(f_basisvalue, rr) code += [f_imul(assign_to, f_sqrt(A))] # 3D elif (element_cellname == "tetrahedron"): # FIAT_NEW code (compute index function) TetrahedronExpansionSet. # def idx(p,q,r): # return (p+q+r)*(p+q+r+1)*(p+q+r+2)//6 + (q+r)*(q+r+1)//2 + r def _idx3d(p, q, r): return (p+q+r)*(p+q+r+1)*(p+q+r+2)//6 + (q+r)*(q+r+1)//2 + r # FIAT_NEW.expansions.TetrahedronExpansionSet. # Compute helper factors. # FIAT_NEW code # factor1 = 0.5 * ( 2.0 + 2.0*x + y + z ) # factor2 = (0.5*(y+z))**2 # factor3 = 0.5 * ( 1 + 2.0 * y + z ) # factor4 = 0.5 * ( 1 - z ) # factor5 = factor4 ** 2 fac1 = create_product([float_0_5, float_2 + float_2*symbol_x + symbol_y + symbol_z]) fac2 = create_product([float_0_25, symbol_y + symbol_z, symbol_y + symbol_z]) fac3 = create_product([float_0_5, float_1 + float_2*symbol_y + symbol_z]) fac4 = create_product([float_0_5, float_1 - symbol_z]) code += [f_decl(f_double, str(f1), fac1)] code += [f_decl(f_double, str(f2), fac2)] code += [f_decl(f_double, str(f3), fac3)] code += [f_decl(f_double, str(f4), fac4)] code += [f_decl(f_double, str(f5), f4*f4)] code += ["", f_comment("Compute basisvalues")] # The initial value basisvalue 0 is always 1.0. # FIAT_NEW code # for ii in range( results.shape[1] ): # results[0,ii] = 1.0 + apts[ii,0]-apts[ii,0]+apts[ii,1]-apts[ii,1] code += [f_assign(f_component(f_basisvalue, 0), f_float(1.0))] # Only continue if the embedded degree is larger than zero. if embedded_degree > 0: # The initial value of basisfunction 1 is equal to f1. # FIAT_NEW code # results[idx(1,0),:] = f1 code += [f_assign(f_component(f_basisvalue, 1), str(f1))] # NOTE: KBO: The order of the loops is VERY IMPORTANT!! # Only active is embedded_degree > 1 if embedded_degree > 1: # FIAT_NEW code (loop 1 in FIAT). # for p in range(1,n): # a1 = ( 2.0 * p + 1.0 ) / ( p + 1.0 ) # a2 = p / (p + 1.0) # results[idx(p+1,0,0)] = a1 * factor1 * results[idx(p,0,0)] \ # -a2 * factor2 * results[ idx(p-1,0,0) ] for r in range(1, embedded_degree): rr = _idx3d((r + 1), 0, 0) ss = _idx3d(r, 0, 0) tt = _idx3d((r - 1), 0, 0) A = (2*r + 1.0)/(r + 1) B = r/(r + 1.0) assign_to = f_component(f_basisvalue, rr) assign_from = f_sub([f_mul([f_float(A), str(f1), f_component(f_basisvalue, ss)]), f_mul([f_float(B), str(f2), f_component(f_basisvalue, tt)])]) code += [f_assign(assign_to, assign_from)] # FIAT_NEW code (loop 2 in FIAT). # q = 1 # for p in range(0,n): # results[idx(p,1,0)] = results[idx(p,0,0)] \ # * ( p * (1.0 + y) + ( 2.0 + 3.0 * y + z ) / 2 ) for r in range(0, embedded_degree): rr = _idx3d(r, 1, 0) ss = _idx3d(r, 0, 0) assign_to = f_component(f_basisvalue, rr) term0 = f_mul([f_float(0.5), f_group(f_add([f_float(2), f_mul([f_float(3), str(symbol_y)]), str(symbol_z)]))]) if r == 0: assign_from = f_mul([term0, f_component(f_basisvalue, ss)]) else: term1 = f_mul([f_float(r), f_group(f_add([f_float(1), str(symbol_y)]))]) assign_from = f_mul([f_group(f_add([term0, term1])), f_component(f_basisvalue, ss)]) code += [f_assign(assign_to, assign_from)] # Only active is embedded_degree > 1. if embedded_degree > 1: # FIAT_NEW code (loop 3 in FIAT). # for p in range(0,n-1): # for q in range(1,n-p): # (aq,bq,cq) = jrc(2*p+1,0,q) # qmcoeff = aq * factor3 + bq * factor4 # qm1coeff = cq * factor5 # results[idx(p,q+1,0)] = qmcoeff * results[idx(p,q,0)] \ # - qm1coeff * results[idx(p,q-1,0)] for r in range(0, embedded_degree - 1): for s in range(1, embedded_degree - r): rr = _idx3d(r, (s + 1), 0) ss = _idx3d(r, s, 0) tt = _idx3d(r, s - 1, 0) (A, B, C) = _jrc(2*r + 1, 0, s) assign_to = f_component(f_basisvalue, rr) term0 = f_mul([f_group(f_add([f_mul([f_float(A), str(f3)]), f_mul([f_float(B), str(f4)])])), f_component(f_basisvalue, ss)]) term1 = f_mul([f_float(C), str(f5), f_component(f_basisvalue, tt)]) assign_from = f_sub([term0, term1]) code += [f_assign(assign_to, assign_from)] # FIAT_NEW code (loop 4 in FIAT). # now handle r=1 # for p in range(n): # for q in range(n-p): # results[idx(p,q,1)] = results[idx(p,q,0)] \ # * ( 1.0 + p + q + ( 2.0 + q + p ) * z ) for r in range(0, embedded_degree): for s in range(0, embedded_degree - r): rr = _idx3d(r, s, 1) ss = _idx3d(r, s, 0) assign_to = f_component(f_basisvalue, rr) A = f_add([f_mul([f_float(2 + r + s), str(symbol_z)]), f_float(1 + r + s)]) assign_from = f_mul([f_group(A), f_component(f_basisvalue, ss)]) code += [f_assign(assign_to, assign_from)] # Only active is embedded_degree > 1. if embedded_degree > 1: # FIAT_NEW code (loop 5 in FIAT). # general r by recurrence # for p in range(n-1): # for q in range(0,n-p-1): # for r in range(1,n-p-q): # ar,br,cr = jrc(2*p+2*q+2,0,r) # results[idx(p,q,r+1)] = \ # (ar * z + br) * results[idx(p,q,r) ] \ # - cr * results[idx(p,q,r-1) ] for r in range(embedded_degree - 1): for s in range(0, embedded_degree - r - 1): for t in range(1, embedded_degree - r - s): rr = _idx3d(r, s, ( t + 1)) ss = _idx3d(r, s, t) tt = _idx3d(r, s, t - 1) (A, B, C) = _jrc(2*r + 2*s + 2, 0, t) assign_to = f_component(f_basisvalue, rr) az_b = f_group(f_add([f_float(B), f_mul([f_float(A), str(symbol_z)])])) assign_from = f_sub([f_mul([f_component(f_basisvalue, ss), az_b]), f_mul([f_float(C), f_component(f_basisvalue, tt)])]) code += [f_assign(assign_to, assign_from)] # FIAT_NEW code (loop 6 in FIAT). # for p in range(n+1): # for q in range(n-p+1): # for r in range(n-p-q+1): # results[idx(p,q,r)] *= math.sqrt((p+0.5)*(p+q+1.0)*(p+q+r+1.5)) for r in range(embedded_degree + 1): for s in range(embedded_degree - r + 1): for t in range(embedded_degree - r - s + 1): rr = _idx3d(r, s, t) A = (r + 0.5)*(r + s + 1)*(r + s + t + 1.5) assign_to = f_component(f_basisvalue, rr) multiply_by = f_sqrt(A) myline = f_imul(assign_to, multiply_by) code += [myline] else: error("Cannot compute basis values for shape: %d" % elemet_cell_domain) return code + [""]
def create_function(self, ufl_function, derivatives, component, local_comp, local_offset, ffc_element, is_quad_element, transformation, multiindices, tdim, gdim, avg): "Create code for basis functions, and update relevant tables of used basis." ffc_assert(ufl_function in self._function_replace_values, "Expecting ufl_function to have been mapped prior to this call.") # Prefetch formats to speed up code generation. f_transform = format["transform"] f_detJ = format["det(J)"] # Reset code code = [] # Handle affine mappings. if transformation == "affine": # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] # Create function name. function_name = self._create_function_name(component, deriv, avg, is_quad_element, ufl_function, ffc_element) if function_name: # Add transformation if needed. code.append(self.__apply_transform(function_name, derivatives, multi, tdim, gdim)) # Handle non-affine mappings. else: ffc_assert(avg is None, "Taking average is not supported for non-affine mappings.") # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] if transformation in ["covariant piola", "contravariant piola"]: for c in range(tdim): function_name = self._create_function_name(c + local_offset, deriv, avg, is_quad_element, ufl_function, ffc_element) if function_name: # Multiply basis by appropriate transform. if transformation == "covariant piola": dxdX = create_symbol(f_transform("JINV", c, local_comp, tdim, gdim, self.restriction), GEO) function_name = create_product([dxdX, function_name]) elif transformation == "contravariant piola": detJ = create_fraction(create_float(1), create_symbol(f_detJ(self.restriction), GEO)) dXdx = create_symbol(f_transform("J", local_comp, c, gdim, tdim, self.restriction), GEO) function_name = create_product([detJ, dXdx, function_name]) # Add transformation if needed. code.append(self.__apply_transform(function_name, derivatives, multi, tdim, gdim)) elif transformation == "double covariant piola": # g_ij = (Jinv)_ki G_kl (Jinv)lj i = local_comp // tdim j = local_comp % tdim for k in range(tdim): for l in range(tdim): # Create mapping and basis name. function_name = self._create_function_name( k * tdim + l + local_offset, deriv, avg, is_quad_element, ufl_function, ffc_element) J1 = create_symbol( f_transform("JINV", k, i, tdim, gdim, self.restriction), GEO) J2 = create_symbol( f_transform("JINV", l, j, tdim, gdim, self.restriction), GEO) function_name = create_product([J1, function_name, J2]) # Add transformation if needed. code.append(self.__apply_transform( function_name, derivatives, multi, tdim, gdim)) elif transformation == "double contravariant piola": # g_ij = (detJ)^(-2) J_ik G_kl J_jl i = local_comp // tdim j = local_comp % tdim for k in range(tdim): for l in range(tdim): # Create mapping and basis name. function_name = self._create_function_name( k * tdim + l + local_offset, deriv, avg, is_quad_element, ufl_function, ffc_element) J1 = create_symbol( f_transform("J", i, k, tdim, gdim, self.restriction), GEO) J2 = create_symbol( f_transform("J", j, l, tdim, gdim, self.restriction), GEO) invdetJ = create_fraction( create_float(1), create_symbol(f_detJ(self.restriction), GEO)) function_name = create_product([invdetJ, invdetJ, J1, function_name, J2]) # Add transformation if needed. code.append(self.__apply_transform(function_name, derivatives, multi, tdim, gdim)) else: error("Transformation is not supported: ", repr(transformation)) if not code: return create_float(0.0) elif len(code) > 1: code = create_sum(code) else: code = code[0] return code
def create_argument(self, ufl_argument, derivatives, component, local_comp, local_offset, ffc_element, transformation, multiindices, tdim, gdim, avg): "Create code for basis functions, and update relevant tables of used basis." # Prefetch formats to speed up code generation. f_transform = format["transform"] f_detJ = format["det(J)"] # Reset code code = {} # Affine mapping if transformation == "affine": # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] # Create mapping and basis name. mapping, basis = self._create_mapping_basis(component, deriv, avg, ufl_argument, ffc_element) if mapping not in code: code[mapping] = [] if basis is not None: # Add transformation if needed. code[mapping].append(self.__apply_transform(basis, derivatives, multi, tdim, gdim)) # Handle non-affine mappings. else: ffc_assert(avg is None, "Taking average is not supported for non-affine mappings.") # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(tdim)] if not any(deriv): deriv = [] if transformation in ["covariant piola", "contravariant piola"]: for c in range(tdim): # Create mapping and basis name. mapping, basis = self._create_mapping_basis(c + local_offset, deriv, avg, ufl_argument, ffc_element) if mapping not in code: code[mapping] = [] if basis is not None: # Multiply basis by appropriate transform. if transformation == "covariant piola": dxdX = create_symbol(f_transform("JINV", c, local_comp, tdim, gdim, self.restriction), GEO) basis = create_product([dxdX, basis]) elif transformation == "contravariant piola": detJ = create_fraction(create_float(1), create_symbol(f_detJ(self.restriction), GEO)) dXdx = create_symbol(f_transform("J", local_comp, c, gdim, tdim, self.restriction), GEO) basis = create_product([detJ, dXdx, basis]) # Add transformation if needed. code[mapping].append(self.__apply_transform(basis, derivatives, multi, tdim, gdim)) elif transformation == "double covariant piola": # g_ij = (Jinv)_ki G_kl (Jinv)lj i = local_comp // tdim j = local_comp % tdim for k in range(tdim): for l in range(tdim): # Create mapping and basis name. mapping, basis = self._create_mapping_basis( k * tdim + l + local_offset, deriv, avg, ufl_argument, ffc_element) if mapping not in code: code[mapping] = [] if basis is not None: J1 = create_symbol( f_transform("JINV", k, i, tdim, gdim, self.restriction), GEO) J2 = create_symbol( f_transform("JINV", l, j, tdim, gdim, self.restriction), GEO) basis = create_product([J1, basis, J2]) # Add transformation if needed. code[mapping].append( self.__apply_transform( basis, derivatives, multi, tdim, gdim)) elif transformation == "double contravariant piola": # g_ij = (detJ)^(-2) J_ik G_kl J_jl i = local_comp // tdim j = local_comp % tdim for k in range(tdim): for l in range(tdim): # Create mapping and basis name. mapping, basis = self._create_mapping_basis( k * tdim + l + local_offset, deriv, avg, ufl_argument, ffc_element) if mapping not in code: code[mapping] = [] if basis is not None: J1 = create_symbol( f_transform("J", i, k, gdim, tdim, self.restriction), GEO) J2 = create_symbol( f_transform("J", j, l, gdim, tdim, self.restriction), GEO) invdetJ = create_fraction( create_float(1), create_symbol(f_detJ(self.restriction), GEO)) basis = create_product([invdetJ, invdetJ, J1, basis, J2]) # Add transformation if needed. code[mapping].append( self.__apply_transform( basis, derivatives, multi, tdim, gdim)) else: error("Transformation is not supported: " + repr(transformation)) # Add sums and group if necessary. for key, val in list(code.items()): if len(val) > 1: code[key] = create_sum(val) else: code[key] = val[0] return code
def create_argument(self, ufl_argument, derivatives, component, local_comp, local_offset, ffc_element, transformation, multiindices, tdim, gdim, avg): "Create code for basis functions, and update relevant tables of used basis." ffc_assert(ufl_argument in self._function_replace_values, "Expecting ufl_argument to have been mapped prior to this call.") # Prefetch formats to speed up code generation. f_transform = format["transform"] f_detJ = format["det(J)"] # Reset code code = {} # Affine mapping if transformation == "affine": # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(self.tdim)] if not any(deriv): deriv = [] # Create mapping and basis name. mapping, basis = self._create_mapping_basis(component, deriv, avg, ufl_argument, ffc_element) if not mapping in code: code[mapping] = [] if basis is not None: # Add transformation if needed. code[mapping].append(self.__apply_transform(basis, derivatives, multi, tdim, gdim)) # Handle non-affine mappings. else: ffc_assert(avg is None, "Taking average is not supported for non-affine mappings.") # Loop derivatives and get multi indices. for multi in multiindices: deriv = [multi.count(i) for i in range(self.tdim)] if not any(deriv): deriv = [] for c in range(self.tdim): # Create mapping and basis name. mapping, basis = self._create_mapping_basis(c + local_offset, deriv, avg, ufl_argument, ffc_element) if not mapping in code: code[mapping] = [] if basis is not None: # Multiply basis by appropriate transform. if transformation == "covariant piola": dxdX = create_symbol(f_transform("JINV", c, local_comp, tdim, gdim, self.restriction), GEO) basis = create_product([dxdX, basis]) elif transformation == "contravariant piola": detJ = create_fraction(create_float(1), create_symbol(f_detJ(self.restriction), GEO)) dXdx = create_symbol(f_transform("J", local_comp, c, gdim, tdim, self.restriction), GEO) basis = create_product([detJ, dXdx, basis]) else: error("Transformation is not supported: " + repr(transformation)) # Add transformation if needed. code[mapping].append(self.__apply_transform(basis, derivatives, multi, tdim, gdim)) # Add sums and group if necessary. for key, val in code.items(): if len(val) > 1: code[key] = create_sum(val) else: code[key] = val[0] return code
def _compute_basisvalues(data, dof_data): """From FIAT_NEW.expansions.""" UNROLL = True # Prefetch formats to speed up code generation. f_comment = format["comment"] f_add = format["add"] f_mul = format["mul"] f_imul = format["imul"] f_sub = format["sub"] f_group = format["grouping"] f_assign = format["assign"] f_sqrt = format["sqrt"]["ufc"] f_x = format["x coordinate"] f_y = format["y coordinate"] f_z = format["z coordinate"] f_double = format["float declaration"] f_basisvalue = format["basisvalues"] f_component = format["component"] f_float = format["floating point"] f_uint = format["uint declaration"] f_tensor = format["tabulate tensor"] f_loop = format["generate loop"] f_decl = format["declaration"] f_tmp = format["tmp value"] f_int = format["int"] f_r = format["free indices"][0] # Create temporary values. f1, f2, f3, f4, f5 = [create_symbol(f_tmp(i), CONST) for i in range(0, 5)] # Get embedded degree. embedded_degree = dof_data["embedded_degree"] # Create helper symbols. symbol_p = create_symbol(f_r, CONST) symbol_x = create_symbol(f_x, CONST) symbol_y = create_symbol(f_y, CONST) symbol_z = create_symbol(f_z, CONST) int_n1 = f_int(embedded_degree + 1) float_1 = create_float(1) float_2 = create_float(2) float_0_5 = create_float(0.5) float_0_25 = create_float(0.25) # Initialise return code. code = [""] # Create zero array for basisvalues. # Get number of members of the expansion set. num_mem = dof_data["num_expansion_members"] code += [f_comment("Array of basisvalues")] code += [ f_decl(f_double, f_component(f_basisvalue, num_mem), f_tensor([0.0] * num_mem)) ] # Declare helper variables, will be removed if not used. code += ["", f_comment("Declare helper variables") ] # Keeping this here to avoid changing references # Get the element cell name element_cellname = data["cellname"] def _jrc(a, b, n): an = float((2 * n + 1 + a + b) * (2 * n + 2 + a + b)) / float(2 * (n + 1) * (n + 1 + a + b)) bn = float((a * a - b * b) * (2 * n + 1 + a + b)) / float(2 * (n + 1) * (2 * n + a + b) * (n + 1 + a + b)) cn = float((n + a) * (n + b) * (2 * n + 2 + a + b)) / float( (n + 1) * (n + 1 + a + b) * (2 * n + a + b)) return (an, bn, cn) # 1D if (element_cellname == "interval"): # FIAT_NEW.expansions.LineExpansionSet. # FIAT_NEW code # psitilde_as = jacobi.eval_jacobi_batch(0,0,n,ref_pts) # FIAT_NEW.jacobi.eval_jacobi_batch(a,b,n,xs) # The initial value basisvalue 0 is always 1.0 # FIAT_NEW code # for ii in range(result.shape[1]): # result[0,ii] = 1.0 + xs[ii,0] - xs[ii,0] code += ["", f_comment("Compute basisvalues")] code += [f_assign(f_component(f_basisvalue, 0), f_float(1.0))] # Only continue if the embedded degree is larger than zero. if embedded_degree > 0: # FIAT_NEW.jacobi.eval_jacobi_batch(a,b,n,xs). # result[1,:] = 0.5 * ( a - b + ( a + b + 2.0 ) * xsnew ) # The initial value basisvalue 1 is always x code += [f_assign(f_component(f_basisvalue, 1), f_x)] # Only active is embedded_degree > 1. if embedded_degree > 1: # FIAT_NEW.jacobi.eval_jacobi_batch(a,b,n,xs). # apb = a + b (equal to 0 because of function arguments) # for k in range(2,n+1): # a1 = 2.0 * k * ( k + apb ) * ( 2.0 * k + apb - 2.0 ) # a2 = ( 2.0 * k + apb - 1.0 ) * ( a * a - b * b ) # a3 = ( 2.0 * k + apb - 2.0 ) \ # * ( 2.0 * k + apb - 1.0 ) \ # * ( 2.0 * k + apb ) # a4 = 2.0 * ( k + a - 1.0 ) * ( k + b - 1.0 ) \ # * ( 2.0 * k + apb ) # a2 = a2 / a1 # a3 = a3 / a1 # a4 = a4 / a1 # result[k,:] = ( a2 + a3 * xsnew ) * result[k-1,:] \ # - a4 * result[k-2,:] # The below implements the above (with a = b = apb = 0) for r in range(2, embedded_degree + 1): # Define helper variables a1 = 2.0 * r * r * (2.0 * r - 2.0) a3 = ((2.0 * r - 2.0) * (2.0 * r - 1.0) * (2.0 * r)) / a1 a4 = (2.0 * (r - 1.0) * (r - 1.0) * (2.0 * r)) / a1 assign_to = f_component(f_basisvalue, r) assign_from = f_sub([ f_mul([ f_x, f_component(f_basisvalue, r - 1), f_float(a3) ]), f_mul([f_component(f_basisvalue, r - 2), f_float(a4)]) ]) code += [f_assign(assign_to, assign_from)] # Scale values. # FIAT_NEW.expansions.LineExpansionSet. # FIAT_NEW code # results = numpy.zeros( ( n+1 , len(pts) ) , type( pts[0][0] ) ) # for k in range( n + 1 ): # results[k,:] = psitilde_as[k,:] * math.sqrt( k + 0.5 ) lines = [] loop_vars = [(str(symbol_p), 0, int_n1)] # Create names. basis_k = create_symbol(f_component(f_basisvalue, str(symbol_p)), CONST) # Compute value. fac1 = create_symbol(f_sqrt(str(symbol_p + float_0_5)), CONST) lines += [format["imul"](str(basis_k), str(fac1))] # Create loop (block of lines). code += f_loop(lines, loop_vars) # 2D elif (element_cellname == "triangle"): # FIAT_NEW.expansions.TriangleExpansionSet. # Compute helper factors # FIAT_NEW code # f1 = (1.0+2*x+y)/2.0 # f2 = (1.0 - y) / 2.0 # f3 = f2**2 fac1 = create_fraction(float_1 + float_2 * symbol_x + symbol_y, float_2) fac2 = create_fraction(float_1 - symbol_y, float_2) code += [f_decl(f_double, str(f1), fac1)] code += [f_decl(f_double, str(f2), fac2)] code += [f_decl(f_double, str(f3), f2 * f2)] code += ["", f_comment("Compute basisvalues")] # The initial value basisvalue 0 is always 1.0. # FIAT_NEW code # for ii in range( results.shape[1] ): # results[0,ii] = 1.0 + apts[ii,0]-apts[ii,0]+apts[ii,1]-apts[ii,1] code += [f_assign(f_component(f_basisvalue, 0), f_float(1.0))] def _idx2d(p, q): return (p + q) * (p + q + 1) // 2 + q # Only continue if the embedded degree is larger than zero. if embedded_degree > 0: # The initial value of basisfunction 1 is equal to f1. # FIAT_NEW code # results[idx(1,0),:] = f1 code += [f_assign(f_component(f_basisvalue, 1), str(f1))] # NOTE: KBO: The order of the loops is VERY IMPORTANT!! # Only active is embedded_degree > 1. if embedded_degree > 1: # FIAT_NEW code (loop 1 in FIAT) # for p in range(1,n): # a = (2.0*p+1)/(1.0+p) # b = p / (p+1.0) # results[idx(p+1,0)] = a * f1 * results[idx(p,0),:] \ # - p/(1.0+p) * f3 *results[idx(p-1,0),:] # FIXME: KBO: Is there an error in FIAT? why is b not used? for r in range(1, embedded_degree): rr = _idx2d((r + 1), 0) assign_to = f_component(f_basisvalue, rr) ss = _idx2d(r, 0) tt = _idx2d((r - 1), 0) A = (2 * r + 1.0) / (r + 1) B = r / (1.0 + r) v1 = f_mul( [f_component(f_basisvalue, ss), f_float(A), str(f1)]) v2 = f_mul( [f_component(f_basisvalue, tt), f_float(B), str(f3)]) assign_from = f_sub([v1, v2]) code += [f_assign(assign_to, assign_from)] # FIAT_NEW code (loop 2 in FIAT). # for p in range(n): # results[idx(p,1),:] = 0.5 * (1+2.0*p+(3.0+2.0*p)*y) \ # * results[idx(p,0)] for r in range(0, embedded_degree): # (p+q)*(p+q+1)//2 + q rr = _idx2d(r, 1) assign_to = f_component(f_basisvalue, rr) ss = _idx2d(r, 0) A = 0.5 * (1 + 2 * r) B = 0.5 * (3 + 2 * r) C = f_add([f_float(A), f_mul([f_float(B), str(symbol_y)])]) assign_from = f_mul( [f_component(f_basisvalue, ss), f_group(C)]) code += [f_assign(assign_to, assign_from)] # Only active is embedded_degree > 1. if embedded_degree > 1: # FIAT_NEW code (loop 3 in FIAT). # for p in range(n-1): # for q in range(1,n-p): # (a1,a2,a3) = jrc(2*p+1,0,q) # results[idx(p,q+1),:] \ # = ( a1 * y + a2 ) * results[idx(p,q)] \ # - a3 * results[idx(p,q-1)] for r in range(0, embedded_degree - 1): for s in range(1, embedded_degree - r): rr = _idx2d(r, (s + 1)) ss = _idx2d(r, s) tt = _idx2d(r, s - 1) A, B, C = _jrc(2 * r + 1, 0, s) assign_to = f_component(f_basisvalue, rr) assign_from = f_sub([ f_mul([ f_component(f_basisvalue, ss), f_group( f_add([ f_float(B), f_mul([str(symbol_y), f_float(A)]) ])) ]), f_mul([f_component(f_basisvalue, tt), f_float(C)]) ]) code += [f_assign(assign_to, assign_from)] # FIAT_NEW code (loop 4 in FIAT). # for p in range(n+1): # for q in range(n-p+1): # results[idx(p,q),:] *= math.sqrt((p+0.5)*(p+q+1.0)) n1 = embedded_degree + 1 for r in range(0, n1): for s in range(0, n1 - r): rr = _idx2d(r, s) A = (r + 0.5) * (r + s + 1) assign_to = f_component(f_basisvalue, rr) code += [f_imul(assign_to, f_sqrt(A))] # 3D elif (element_cellname == "tetrahedron"): # FIAT_NEW code (compute index function) TetrahedronExpansionSet. # def idx(p,q,r): # return (p+q+r)*(p+q+r+1)*(p+q+r+2)//6 + (q+r)*(q+r+1)//2 + r def _idx3d(p, q, r): return (p + q + r) * (p + q + r + 1) * (p + q + r + 2) // 6 + ( q + r) * (q + r + 1) // 2 + r # FIAT_NEW.expansions.TetrahedronExpansionSet. # Compute helper factors. # FIAT_NEW code # factor1 = 0.5 * ( 2.0 + 2.0*x + y + z ) # factor2 = (0.5*(y+z))**2 # factor3 = 0.5 * ( 1 + 2.0 * y + z ) # factor4 = 0.5 * ( 1 - z ) # factor5 = factor4 ** 2 fac1 = create_product( [float_0_5, float_2 + float_2 * symbol_x + symbol_y + symbol_z]) fac2 = create_product( [float_0_25, symbol_y + symbol_z, symbol_y + symbol_z]) fac3 = create_product( [float_0_5, float_1 + float_2 * symbol_y + symbol_z]) fac4 = create_product([float_0_5, float_1 - symbol_z]) code += [f_decl(f_double, str(f1), fac1)] code += [f_decl(f_double, str(f2), fac2)] code += [f_decl(f_double, str(f3), fac3)] code += [f_decl(f_double, str(f4), fac4)] code += [f_decl(f_double, str(f5), f4 * f4)] code += ["", f_comment("Compute basisvalues")] # The initial value basisvalue 0 is always 1.0. # FIAT_NEW code # for ii in range( results.shape[1] ): # results[0,ii] = 1.0 + apts[ii,0]-apts[ii,0]+apts[ii,1]-apts[ii,1] code += [f_assign(f_component(f_basisvalue, 0), f_float(1.0))] # Only continue if the embedded degree is larger than zero. if embedded_degree > 0: # The initial value of basisfunction 1 is equal to f1. # FIAT_NEW code # results[idx(1,0),:] = f1 code += [f_assign(f_component(f_basisvalue, 1), str(f1))] # NOTE: KBO: The order of the loops is VERY IMPORTANT!! # Only active is embedded_degree > 1 if embedded_degree > 1: # FIAT_NEW code (loop 1 in FIAT). # for p in range(1,n): # a1 = ( 2.0 * p + 1.0 ) / ( p + 1.0 ) # a2 = p / (p + 1.0) # results[idx(p+1,0,0)] = a1 * factor1 * results[idx(p,0,0)] \ # -a2 * factor2 * results[ idx(p-1,0,0) ] for r in range(1, embedded_degree): rr = _idx3d((r + 1), 0, 0) ss = _idx3d(r, 0, 0) tt = _idx3d((r - 1), 0, 0) A = (2 * r + 1.0) / (r + 1) B = r / (r + 1.0) assign_to = f_component(f_basisvalue, rr) assign_from = f_sub([ f_mul([ f_float(A), str(f1), f_component(f_basisvalue, ss) ]), f_mul([ f_float(B), str(f2), f_component(f_basisvalue, tt) ]) ]) code += [f_assign(assign_to, assign_from)] # FIAT_NEW code (loop 2 in FIAT). # q = 1 # for p in range(0,n): # results[idx(p,1,0)] = results[idx(p,0,0)] \ # * ( p * (1.0 + y) + ( 2.0 + 3.0 * y + z ) / 2 ) for r in range(0, embedded_degree): rr = _idx3d(r, 1, 0) ss = _idx3d(r, 0, 0) assign_to = f_component(f_basisvalue, rr) term0 = f_mul([ f_float(0.5), f_group( f_add([ f_float(2), f_mul([f_float(3), str(symbol_y)]), str(symbol_z) ])) ]) if r == 0: assign_from = f_mul([term0, f_component(f_basisvalue, ss)]) else: term1 = f_mul([ f_float(r), f_group(f_add([f_float(1), str(symbol_y)])) ]) assign_from = f_mul([ f_group(f_add([term0, term1])), f_component(f_basisvalue, ss) ]) code += [f_assign(assign_to, assign_from)] # Only active is embedded_degree > 1. if embedded_degree > 1: # FIAT_NEW code (loop 3 in FIAT). # for p in range(0,n-1): # for q in range(1,n-p): # (aq,bq,cq) = jrc(2*p+1,0,q) # qmcoeff = aq * factor3 + bq * factor4 # qm1coeff = cq * factor5 # results[idx(p,q+1,0)] = qmcoeff * results[idx(p,q,0)] \ # - qm1coeff * results[idx(p,q-1,0)] for r in range(0, embedded_degree - 1): for s in range(1, embedded_degree - r): rr = _idx3d(r, (s + 1), 0) ss = _idx3d(r, s, 0) tt = _idx3d(r, s - 1, 0) (A, B, C) = _jrc(2 * r + 1, 0, s) assign_to = f_component(f_basisvalue, rr) term0 = f_mul([ f_group( f_add([ f_mul([f_float(A), str(f3)]), f_mul([f_float(B), str(f4)]) ])), f_component(f_basisvalue, ss) ]) term1 = f_mul([ f_float(C), str(f5), f_component(f_basisvalue, tt) ]) assign_from = f_sub([term0, term1]) code += [f_assign(assign_to, assign_from)] # FIAT_NEW code (loop 4 in FIAT). # now handle r=1 # for p in range(n): # for q in range(n-p): # results[idx(p,q,1)] = results[idx(p,q,0)] \ # * ( 1.0 + p + q + ( 2.0 + q + p ) * z ) for r in range(0, embedded_degree): for s in range(0, embedded_degree - r): rr = _idx3d(r, s, 1) ss = _idx3d(r, s, 0) assign_to = f_component(f_basisvalue, rr) A = f_add([ f_mul([f_float(2 + r + s), str(symbol_z)]), f_float(1 + r + s) ]) assign_from = f_mul( [f_group(A), f_component(f_basisvalue, ss)]) code += [f_assign(assign_to, assign_from)] # Only active is embedded_degree > 1. if embedded_degree > 1: # FIAT_NEW code (loop 5 in FIAT). # general r by recurrence # for p in range(n-1): # for q in range(0,n-p-1): # for r in range(1,n-p-q): # ar,br,cr = jrc(2*p+2*q+2,0,r) # results[idx(p,q,r+1)] = \ # (ar * z + br) * results[idx(p,q,r) ] \ # - cr * results[idx(p,q,r-1) ] for r in range(embedded_degree - 1): for s in range(0, embedded_degree - r - 1): for t in range(1, embedded_degree - r - s): rr = _idx3d(r, s, (t + 1)) ss = _idx3d(r, s, t) tt = _idx3d(r, s, t - 1) (A, B, C) = _jrc(2 * r + 2 * s + 2, 0, t) assign_to = f_component(f_basisvalue, rr) az_b = f_group( f_add([ f_float(B), f_mul([f_float(A), str(symbol_z)]) ])) assign_from = f_sub([ f_mul([f_component(f_basisvalue, ss), az_b]), f_mul([ f_float(C), f_component(f_basisvalue, tt) ]) ]) code += [f_assign(assign_to, assign_from)] # FIAT_NEW code (loop 6 in FIAT). # for p in range(n+1): # for q in range(n-p+1): # for r in range(n-p-q+1): # results[idx(p,q,r)] *= math.sqrt((p+0.5)*(p+q+1.0)*(p+q+r+1.5)) for r in range(embedded_degree + 1): for s in range(embedded_degree - r + 1): for t in range(embedded_degree - r - s + 1): rr = _idx3d(r, s, t) A = (r + 0.5) * (r + s + 1) * (r + s + t + 1.5) assign_to = f_component(f_basisvalue, rr) multiply_by = f_sqrt(A) myline = f_imul(assign_to, multiply_by) code += [myline] else: error("Cannot compute basis values for shape: %d" % elemet_cell_domain) return code + [""]