def coefficients_from_source(self, avec, bvec): from sumpy.kernel import DirectionalSourceDerivative kernel = self.kernel from sumpy.tools import mi_power, mi_factorial if isinstance(kernel, DirectionalSourceDerivative): if kernel.get_base_kernel() is not kernel.inner_kernel: raise NotImplementedError("more than one source derivative " "not supported at present") from sumpy.symbolic import make_sympy_vector dir_vec = make_sympy_vector(kernel.dir_vec_name, kernel.dim) coeff_identifiers = self.get_full_coefficient_identifiers() result = [0] * len(coeff_identifiers) for idim in range(kernel.dim): for i, mi in enumerate(coeff_identifiers): if mi[idim] == 0: continue derivative_mi = tuple(mi_i - 1 if iaxis == idim else mi_i for iaxis, mi_i in enumerate(mi)) result[i] += ( - mi_power(avec, derivative_mi) * mi[idim] * dir_vec[idim]) for i, mi in enumerate(coeff_identifiers): result[i] /= mi_factorial(mi) else: result = [ mi_power(avec, mi) / mi_factorial(mi) for mi in self.get_full_coefficient_identifiers()] return self.full_to_stored(result)
def coefficients_from_source(self, avec, bvec, rscale, sac=None): from sumpy.kernel import DirectionalSourceDerivative kernel = self.kernel from sumpy.tools import mi_power, mi_factorial if not self.use_rscale: rscale = 1 if isinstance(kernel, DirectionalSourceDerivative): from sumpy.symbolic import make_sym_vector dir_vecs = [] tmp_kernel = kernel while isinstance(tmp_kernel, DirectionalSourceDerivative): dir_vecs.append( make_sym_vector(tmp_kernel.dir_vec_name, kernel.dim)) tmp_kernel = tmp_kernel.inner_kernel if kernel.get_base_kernel() is not tmp_kernel: raise NotImplementedError("Unknown kernel wrapper.") nderivs = len(dir_vecs) coeff_identifiers = self.get_full_coefficient_identifiers() result = [0] * len(coeff_identifiers) for i, mi in enumerate(coeff_identifiers): # One source derivative is the dot product of the gradient and # directional vector. # For multiple derivatives, gradient of gradients is taken. # For eg: in 3D, 2 source derivatives gives 9 terms and # cartesian_product below enumerates these 9 terms. for deriv_terms in cartesian_product(*[range(kernel.dim)] * nderivs): prod = 1 derivative_mi = list(mi) for nderivative, deriv_dim in enumerate(deriv_terms): prod *= -derivative_mi[deriv_dim] prod *= dir_vecs[nderivative][deriv_dim] derivative_mi[deriv_dim] -= 1 if any(v < 0 for v in derivative_mi): continue result[i] += mi_power(avec, derivative_mi) * prod for i, mi in enumerate(coeff_identifiers): result[i] /= (mi_factorial(mi) * rscale**sum(mi)) else: avec = [sym.UnevaluatedExpr(a * rscale**-1) for a in avec] result = [ mi_power(avec, mi) / mi_factorial(mi) for mi in self.get_full_coefficient_identifiers() ] return (self.expansion_terms_wrangler. get_stored_mpole_coefficients_from_full(result, rscale, sac=sac))
def evaluate(self, coeffs, bvec): from sumpy.tools import mi_power, mi_factorial evaluated_coeffs = self.stored_to_full(coeffs) result = sum( coeff * self.kernel.postprocess_at_target(mi_power(bvec, mi), bvec) / mi_factorial(mi) for coeff, mi in zip(evaluated_coeffs, self.get_full_coefficient_identifiers()) ) return result
def evaluate(self, coeffs, bvec, rscale): from sumpy.tools import mi_power, mi_factorial evaluated_coeffs = ( self.derivative_wrangler.get_full_kernel_derivatives_from_stored( coeffs, rscale)) bvec = bvec * rscale**-1 result = sum( coeff * mi_power(bvec, mi) / mi_factorial(mi) for coeff, mi in zip( evaluated_coeffs, self.get_full_coefficient_identifiers())) return result
def coefficients_from_source(self, avec, bvec, rscale): from sumpy.kernel import DirectionalSourceDerivative kernel = self.kernel from sumpy.tools import mi_power, mi_factorial if not self.use_rscale: rscale = 1 if isinstance(kernel, DirectionalSourceDerivative): if kernel.get_base_kernel() is not kernel.inner_kernel: raise NotImplementedError("more than one source derivative " "not supported at present") from sumpy.symbolic import make_sym_vector dir_vec = make_sym_vector(kernel.dir_vec_name, kernel.dim) coeff_identifiers = self.get_full_coefficient_identifiers() result = [0] * len(coeff_identifiers) for idim in range(kernel.dim): for i, mi in enumerate(coeff_identifiers): if mi[idim] == 0: continue derivative_mi = tuple(mi_i - 1 if iaxis == idim else mi_i for iaxis, mi_i in enumerate(mi)) result[i] += ( - mi_power(avec, derivative_mi) * mi[idim] * dir_vec[idim]) for i, mi in enumerate(coeff_identifiers): result[i] /= (mi_factorial(mi) * rscale ** sum(mi)) else: avec = avec * rscale**-1 result = [ mi_power(avec, mi) / mi_factorial(mi) for mi in self.get_full_coefficient_identifiers()] return ( self.derivative_wrangler.get_stored_mpole_coefficients_from_full( result, rscale))
def evaluate(self, coeffs, bvec, rscale): from sumpy.tools import mi_power, mi_factorial evaluated_coeffs = ( self.derivative_wrangler.get_full_kernel_derivatives_from_stored( coeffs, rscale)) bvec = bvec * rscale**-1 result = sum( coeff * mi_power(bvec, mi, evaluate=False) / mi_factorial(mi) for coeff, mi in zip( evaluated_coeffs, self.get_full_coefficient_identifiers())) return result
def evaluate(self, coeffs, bvec, rscale): from pytools import factorial evaluated_coeffs = ( self.derivative_wrangler.get_full_kernel_derivatives_from_stored( coeffs, rscale)) bvec = [b * rscale**-1 for b in bvec] mi_to_index = dict( (mi, i) for i, mi in enumerate(self.get_full_coefficient_identifiers())) # Sort multi-indices so that last dimension varies fastest sorted_target_mis = sorted(self.get_full_coefficient_identifiers()) dim = self.dim # Start with an invalid "seen" multi-index seen_mi = [-1] * dim # Local sum keep the sum of the terms that differ by each dimension local_sum = [0] * dim # Local multiplier keep the scalar that the sum has to be multiplied by # when adding to the sum of the preceding dimension. local_multiplier = [0] * dim # For the multi-indices in 3D, local_sum looks like this: # # Multi-index | coef | local_sum | local_mult # (0, 0, 0) | c0 | 0, 0, c0 | 0, 1, 1 # (0, 0, 1) | c1 | 0, 0, c0+c1*dz | 0, 1, 1 # (0, 0, 2) | c2 | 0, 0, c0+c1*dz+c2*dz^2 | 0, 1, 1 # (0, 1, 0) | c3 | 0, c0+c1*dz+c2*dz^2, c3 | 0, 1, dy # (0, 1, 1) | c4 | 0, c0+c1*dz+c2*dz^2, c3+c4*dz | 0, 1, dy # (0, 1, 2) | c5 | 0, c0+c1*dz+c2*dz^2, c3+c4*dz+c5*dz^2 | 0, 1, dy # (0, 2, 0) | c6 | 0, c0+c1*dz+c2*dz^2, c6 | 0, 1, dy^2 # | | +dy*(c3+c4*dz+c5*dz^2) | # (0, 2, 1) | c7 | 0, c0+c1*dz+c2*dz^2, c6+c7*dz | 0, 1, dy^2 # | | +dy*(c3+c4*dz+c5*dz^2) | # (0, 2, 2) | c8 | 0, c0+c1*dz+c2*dz^2, c6+c7*dz+x8*dz^2 | 0, 1, dy^2 # | | +dy*(c3+c4*dz+c5*dz^2) | # (1, 0, 0) | c8 | c0+c1*dz+c2*dz^2, 0, 0 | 0, dx, 1 # | | +dy*(c3+c4*dz+c5*dz^2) | # | | +dy^2*(c6+c7*dz+c8*dz^2) | for mi in sorted_target_mis: # {{{ handle the case where a not-last dimension "clicked over" # (where d will be that not-last dimension) # Iterate in reverse order of dimensions to properly handle a # "double click-over". for d in reversed(range(dim - 1)): if seen_mi[d] != mi[d]: # If the dimension d of mi changed from the previous value # then the sum for dimension d+1 is complete, add it to # dimension d after multiplying and restart. local_sum[d] += local_sum[d + 1] * local_multiplier[d + 1] local_sum[d + 1] = 0 local_multiplier[d + 1] = bvec[d]**mi[d] / factorial(mi[d]) # }}} local_sum[dim-1] += evaluated_coeffs[mi_to_index[mi]] * \ bvec[dim-1]**mi[dim-1] / factorial(mi[dim-1]) seen_mi = mi for d in reversed(range(dim - 1)): local_sum[d] += local_sum[d + 1] * local_multiplier[d + 1] # {{{ simpler, functionally equivalent code if 0: from sumpy.tools import mi_power, mi_factorial return sum( coeff * mi_power(bvec, mi, evaluate=False) / mi_factorial(mi) for coeff, mi in zip(evaluated_coeffs, self.get_full_coefficient_identifiers())) # }}} return local_sum[0]