Ejemplo n.º 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
Ejemplo n.º 2
0
    def coefficients_from_source(self, avec, bvec, rscale):
        from sumpy.tools import MiDerivativeTaker
        ppkernel = self.kernel.postprocess_at_source(
                self.kernel.get_expression(avec), avec)

        taker = MiDerivativeTaker(ppkernel, avec)
        return [
                taker.diff(mi) * rscale ** sum(mi)
                for mi in self.get_coefficient_identifiers()]
Ejemplo n.º 3
0
    def coefficients_from_source(self, avec, bvec, rscale):
        from sumpy.tools import MiDerivativeTaker
        ppkernel = self.kernel.postprocess_at_source(
            self.kernel.get_expression(avec), avec)

        taker = MiDerivativeTaker(ppkernel, avec)
        return [
            taker.diff(mi) * rscale**sum(mi)
            for mi in self.get_coefficient_identifiers()
        ]
Ejemplo n.º 4
0
    def coefficients_from_source(self, avec, bvec, rscale):
        # no point in heeding rscale here--just ignore it
        if bvec is None:
            raise RuntimeError(
                "cannot use line-Taylor expansions in a setting "
                "where the center-target vector is not known at coefficient "
                "formation")

        tau = sym.Symbol("tau")

        avec_line = avec + tau * bvec

        line_kernel = self.kernel.get_expression(avec_line)

        from sumpy.symbolic import USE_SYMENGINE

        if USE_SYMENGINE:
            from sumpy.tools import MiDerivativeTaker, my_syntactic_subs
            deriv_taker = MiDerivativeTaker(line_kernel, (tau, ))

            return [
                my_syntactic_subs(
                    self.kernel.postprocess_at_target(
                        self.kernel.postprocess_at_source(
                            deriv_taker.diff(i), avec), bvec), {tau: 0})
                for i in self.get_coefficient_identifiers()
            ]
        else:
            # Workaround for sympy. The automatic distribution after
            # single-variable diff makes the expressions very large
            # (https://github.com/sympy/sympy/issues/4596), so avoid doing
            # single variable diff.
            #
            # See also https://gitlab.tiker.net/inducer/pytential/merge_requests/12

            return [
                self.kernel.postprocess_at_target(
                    self.kernel.postprocess_at_source(
                        line_kernel.diff("tau", i), avec),
                    bvec).subs("tau", 0)
                for i in self.get_coefficient_identifiers()
            ]
Ejemplo n.º 5
0
    def coefficients_from_source(self, avec, bvec, rscale):
        # no point in heeding rscale here--just ignore it
        if bvec is None:
            raise RuntimeError("cannot use line-Taylor expansions in a setting "
                    "where the center-target vector is not known at coefficient "
                    "formation")

        tau = sym.Symbol("tau")

        avec_line = avec + tau*bvec

        line_kernel = self.kernel.get_expression(avec_line)

        from sumpy.symbolic import USE_SYMENGINE

        if USE_SYMENGINE:
            from sumpy.tools import MiDerivativeTaker, my_syntactic_subs
            deriv_taker = MiDerivativeTaker(line_kernel, (tau,))

            return [my_syntactic_subs(
                        self.kernel.postprocess_at_target(
                            self.kernel.postprocess_at_source(
                                deriv_taker.diff(i),
                                avec), bvec),
                        {tau: 0})
                    for i in self.get_coefficient_identifiers()]
        else:
            # Workaround for sympy. The automatic distribution after
            # single-variable diff makes the expressions very large
            # (https://github.com/sympy/sympy/issues/4596), so avoid doing
            # single variable diff.
            #
            # See also https://gitlab.tiker.net/inducer/pytential/merge_requests/12

            return [self.kernel.postprocess_at_target(
                        self.kernel.postprocess_at_source(
                            line_kernel.diff("tau", i), avec),
                        bvec)
                    .subs("tau", 0)
                    for i in self.get_coefficient_identifiers()]
Ejemplo n.º 6
0
 def get_derivative_taker(self, expr, dvec):
     return MiDerivativeTaker(expr, dvec)
Ejemplo n.º 7
0
 def get_kernel_derivative_taker(self, bvec):
     from sumpy.tools import MiDerivativeTaker
     return MiDerivativeTaker(self.kernel.get_expression(bvec), bvec)
Ejemplo n.º 8
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
Ejemplo n.º 9
0
Archivo: local.py Proyecto: xywei/sumpy
    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