Exemple #1
0
    def translate_from(self, src_expansion, src_coeff_exprs, src_rscale, dvec,
                       tgt_rscale):
        logger.info("building translation operator: %s(%d) -> %s(%d): start" %
                    (type(src_expansion).__name__, src_expansion.order,
                     type(self).__name__, self.order))

        if not self.use_rscale:
            src_rscale = 1
            tgt_rscale = 1

        from sumpy.expansion.multipole import VolumeTaylorMultipoleExpansionBase
        if isinstance(src_expansion, VolumeTaylorMultipoleExpansionBase):
            # We know the general form of the multipole expansion is:
            #
            #    coeff0 * diff(kernel, mi0) + coeff1 * diff(kernel, mi1) + ...
            #
            # To get the local expansion coefficients, we take derivatives of
            # the multipole expansion.
            #
            # This code speeds up derivative taking by caching all kernel
            # derivatives.

            taker = src_expansion.get_kernel_derivative_taker(dvec)

            from sumpy.tools import add_mi

            result = []
            for deriv in self.get_coefficient_identifiers():
                local_result = []
                for coeff, term in zip(
                        src_coeff_exprs,
                        src_expansion.get_coefficient_identifiers()):

                    kernel_deriv = (src_expansion.get_scaled_multipole(
                        taker.diff(add_mi(deriv, term)),
                        dvec,
                        src_rscale,
                        nderivatives=sum(deriv) + sum(term),
                        nderivatives_for_scaling=sum(term)))

                    local_result.append(coeff * kernel_deriv *
                                        tgt_rscale**sum(deriv))
                result.append(sym.Add(*local_result))
        else:
            from sumpy.tools import MiDerivativeTaker
            expr = src_expansion.evaluate(src_coeff_exprs,
                                          dvec,
                                          rscale=src_rscale)
            taker = MiDerivativeTaker(expr, dvec)

            # Rscale/operand magnitude is fairly sensitive to the order of
            # operations--which is something we don't have fantastic control
            # over at the symbolic level. The '.expand()' below moves the two
            # canceling "rscales" closer to each other in the hope of helping
            # with that.
            result = [(taker.diff(mi) * tgt_rscale**sum(mi)).expand()
                      for mi in self.get_coefficient_identifiers()]

        logger.info("building translation operator: done")
        return result
Exemple #2
0
    def evaluate(self, coeffs, bvec, rscale, sac=None):
        if not self.use_rscale:
            rscale = 1

        taker = self.get_kernel_derivative_taker(bvec)

        result = sym.Add(*tuple(
                coeff
                * self.get_scaled_multipole(taker.diff(mi), bvec, rscale, sum(mi))
                for coeff, mi in zip(coeffs, self.get_coefficient_identifiers())))

        return result
Exemple #3
0
 def evaluate(self, coeffs, bvec, rscale):
     # no point in heeding rscale here--just ignore it
     from pytools import factorial
     return sym.Add(*(coeffs[self.get_storage_index(i)] / factorial(i)
                      for i in self.get_coefficient_identifiers()))
Exemple #4
0
    def translate_from(self,
                       src_expansion,
                       src_coeff_exprs,
                       src_rscale,
                       dvec,
                       tgt_rscale,
                       sac=None):
        logger.info("building translation operator: %s(%d) -> %s(%d): start" %
                    (type(src_expansion).__name__, src_expansion.order,
                     type(self).__name__, self.order))

        if not self.use_rscale:
            src_rscale = 1
            tgt_rscale = 1

        from sumpy.expansion.multipole import VolumeTaylorMultipoleExpansionBase
        if isinstance(src_expansion, VolumeTaylorMultipoleExpansionBase):
            # We know the general form of the multipole expansion is:
            #
            #    coeff0 * diff(kernel, mi0) + coeff1 * diff(kernel, mi1) + ...
            #
            # To get the local expansion coefficients, we take derivatives of
            # the multipole expansion.
            #
            # This code speeds up derivative taking by caching all kernel
            # derivatives.

            taker = src_expansion.get_kernel_derivative_taker(dvec)

            from sumpy.tools import add_mi

            # Calculate a elementwise maximum multi-index because the number
            # of multi-indices needed is much less than
            # gnitstam(src_order + tgt order) when PDE conforming expansions
            # are used. For full Taylor, there's no difference.

            def calc_max_mi(mis):
                return (max(mi[i] for mi in mis) for i in range(self.dim))

            src_max_mi = calc_max_mi(
                src_expansion.get_coefficient_identifiers())
            tgt_max_mi = calc_max_mi(self.get_coefficient_identifiers())
            max_mi = add_mi(src_max_mi, tgt_max_mi)

            # Create a expansion terms wrangler for derivatives up to order
            # (tgt order)+(src order) including a corresponding reduction matrix
            tgtplusderiv_exp_terms_wrangler = \
                src_expansion.expansion_terms_wrangler.copy(
                        order=self.order + src_expansion.order, max_mi=tuple(max_mi))
            tgtplusderiv_coeff_ids = \
                tgtplusderiv_exp_terms_wrangler.get_coefficient_identifiers()
            tgtplusderiv_full_coeff_ids = \
                tgtplusderiv_exp_terms_wrangler.get_full_coefficient_identifiers()

            tgtplusderiv_ident_to_index = {
                ident: i
                for i, ident in enumerate(tgtplusderiv_full_coeff_ids)
            }

            result = []
            for lexp_mi in self.get_coefficient_identifiers():
                lexp_mi_terms = []

                # Embed the source coefficients in the coefficient array
                # for the (tgt order)+(src order) wrangler, offset by lexp_mi.
                embedded_coeffs = [0] * len(tgtplusderiv_full_coeff_ids)
                for coeff, term in zip(
                        src_coeff_exprs,
                        src_expansion.get_coefficient_identifiers()):
                    embedded_coeffs[
                            tgtplusderiv_ident_to_index[add_mi(lexp_mi, term)]] \
                                    = coeff

                # Compress the embedded coefficient set
                stored_coeffs = tgtplusderiv_exp_terms_wrangler \
                        .get_stored_mpole_coefficients_from_full(
                                embedded_coeffs, src_rscale, sac=sac)

                # Sum the embedded coefficient set
                for tgtplusderiv_coeff_id, coeff in zip(
                        tgtplusderiv_coeff_ids, stored_coeffs):
                    if coeff == 0:
                        continue
                    nderivatives_for_scaling = \
                            sum(tgtplusderiv_coeff_id)-sum(lexp_mi)
                    kernel_deriv = (src_expansion.get_scaled_multipole(
                        taker.diff(tgtplusderiv_coeff_id),
                        dvec,
                        src_rscale,
                        nderivatives=sum(tgtplusderiv_coeff_id),
                        nderivatives_for_scaling=nderivatives_for_scaling))

                    lexp_mi_terms.append(coeff * kernel_deriv *
                                         tgt_rscale**sum(lexp_mi))
                result.append(sym.Add(*lexp_mi_terms))

        else:
            from sumpy.tools import MiDerivativeTaker
            # Rscale/operand magnitude is fairly sensitive to the order of
            # operations--which is something we don't have fantastic control
            # over at the symbolic level. Scaling dvec, then differentiating,
            # and finally rescaling dvec leaves the expression needing a scaling
            # to compensate for differentiating which is done at the end.
            # This moves the two cancelling "rscales" closer to each other at
            # the end in the hope of helping rscale magnitude.
            dvec_scaled = [d * src_rscale for d in dvec]
            expr = src_expansion.evaluate(src_coeff_exprs,
                                          dvec_scaled,
                                          rscale=src_rscale,
                                          sac=sac)
            replace_dict = dict((d, d / src_rscale) for d in dvec)
            taker = MiDerivativeTaker(expr, dvec)
            rscale_ratio = sym.UnevaluatedExpr(tgt_rscale / src_rscale)
            result = [
                (taker.diff(mi).xreplace(replace_dict) * rscale_ratio**sum(mi))
                for mi in self.get_coefficient_identifiers()
            ]

        logger.info("building translation operator: done")
        return result