예제 #1
0
    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)
예제 #2
0
파일: multipole.py 프로젝트: xywei/sumpy
    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))
예제 #3
0
파일: local.py 프로젝트: inducer/sumpy
    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
예제 #4
0
 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
예제 #5
0
    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))
예제 #6
0
파일: local.py 프로젝트: inducer/sumpy
 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
예제 #7
0
    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]