Ejemplo n.º 1
0
    def propagate(self):
        r"""Given a wavepacket :math:`\Psi` at time :math:`t` compute the propagated
        wavepacket at time :math:`t + \tau`. We perform exactly one timestep of size
        :math:`\tau` here. This propagation is done for all packets in the list
        :math:`\{\Psi_i\}_i` and neglects any interaction between two packets.

        More details can be found in [#]_.

        .. [#] E. Faou, V. Gradinaru and C. Lubich, "Computing semiclassical quantum dynamics with Hagedorn wavepackets",
               SIAM Journal on Scientific Computing, volume 31 number 4 (2009) 3027-3041.
        """
        # Cache some parameter values
        dt = self._dt
        Mi = self._Minv
        key = ("q", "p", "Q", "P", "S", "adQ")

        # Propagate all packets
        for packet, leading_chi in self._packets:
            eps = packet.get_eps()

            # Do a kinetic step of dt/2
            q, p, Q, P, S, adQ = packet.get_parameters(key=key)
            q = q + 0.5 * dt * dot(Mi, p)
            Q = Q + 0.5 * dt * dot(Mi, P)
            S = S + 0.25 * dt * dot(p.T, dot(Mi, p))
            adQn = cont_angle(det(Q), reference=adQ)[0]
            packet.set_parameters((q, p, Q, P, S, adQn), key=key)

            # Do a potential step with the local quadratic part
            q, p, Q, P, S = packet.get_parameters()
            V = self._potential.evaluate_local_quadratic_at(
                q, diagonal_component=leading_chi)

            p = p - dt * V[1]
            P = P - dt * dot(V[2], Q)
            S = S - dt * V[0]
            packet.set_parameters((q, p, Q, P, S))

            # Do a potential step with the local non-quadratic Taylor remainder
            innerproduct = packet.get_innerproduct()
            F = innerproduct.build_matrix(
                packet,
                operator=partial(self._potential.evaluate_local_remainder_at,
                                 diagonal_component=leading_chi))

            coefficients = packet.get_coefficient_vector()
            coefficients = self._matrix_exponential(F, coefficients,
                                                    -1.0j * dt / eps**2)
            packet.set_coefficient_vector(coefficients)

            # Do a kinetic step of dt/2
            q, p, Q, P, S, adQ = packet.get_parameters(key=key)
            q = q + 0.5 * dt * dot(Mi, p)
            Q = Q + 0.5 * dt * dot(Mi, P)
            S = S + 0.25 * dt * dot(p.T, dot(Mi, p))
            adQn = cont_angle(det(Q), reference=adQ)[0]
            packet.set_parameters((q, p, Q, P, S, adQn), key=key)
    def propagate(self):
        r"""Given a wavepacket :math:`\Psi` at time :math:`t` compute the propagated
        wavepacket at time :math:`t + \tau`. We perform exactly one timestep of size
        :math:`\tau` here. This propagation is done for all packets in the list
        :math:`\{\Psi_i\}_i` and neglects any interaction between two packets.

        More details can be found in [#]_.

        .. [#] E. Faou, V. Gradinaru and C. Lubich, "Computing semiclassical quantum dynamics with Hagedorn wavepackets",
               SIAM Journal on Scientific Computing, volume 31 number 4 (2009) 3027-3041.
        """
        # Cache some parameter values
        dt = self._dt
        Mi = self._Minv

        # Propagate all packets
        for packet in self._packets:
            # Unpack, no codata:
            packet = packet[0]
            eps = packet.get_eps()
            key = ("q", "p", "Q", "P", "S", "adQ")

            # Do a kinetic step of dt/2
            for component in range(self._number_components):
                q, p, Q, P, S, adQ = packet.get_parameters(component=component, key=key)
                q = q + 0.5 * dt * dot(Mi, p)
                Q = Q + 0.5 * dt * dot(Mi, P)
                S = S + 0.25 * dt * dot(p.T, dot(Mi, p))
                adQn = cont_angle(det(Q), reference=adQ)[0]
                packet.set_parameters((q, p, Q, P, S, adQn), component=component, key=key)

            # Do a potential step with the local quadratic part
            for component in range(self._number_components):
                q, p, Q, P, S = packet.get_parameters(component=component)
                V = self._potential.evaluate_local_quadratic_at(q, diagonal_component=component)

                p = p - dt * V[1]
                P = P - dt * dot(V[2], Q)
                S = S - dt * V[0]
                packet.set_parameters((q, p, Q, P, S), component=component)

            # Do a potential step with the local non-quadratic Taylor remainder
            innerproduct = packet.get_innerproduct()
            F = innerproduct.build_matrix(packet, packet, self._potential.evaluate_local_remainder_at)

            coefficients = packet.get_coefficient_vector()
            coefficients = self._matrix_exponential(F, coefficients, -1.0j * dt / eps**2)
            packet.set_coefficient_vector(coefficients)

            # Do a kinetic step of dt/2
            for component in range(self._number_components):
                q, p, Q, P, S, adQ = packet.get_parameters(component=component, key=key)
                q = q + 0.5 * dt * dot(Mi, p)
                Q = Q + 0.5 * dt * dot(Mi, P)
                S = S + 0.25 * dt * dot(p.T, dot(Mi, p))
                adQn = cont_angle(det(Q), reference=adQ)[0]
                packet.set_parameters((q, p, Q, P, S, adQn), component=component, key=key)
Ejemplo n.º 3
0
 def _propkin(self, h, packet):
     """Do a kinetic step of size h.
     """
     Mi = self._Minv
     key = ("q", "p", "Q", "P", "S", "adQ")
     q, p, Q, P, S, adQ = packet.get_parameters(key=key)
     q = q + h * dot(Mi, p)
     Q = Q + h * dot(Mi, P)
     S = S + 0.5 * h * dot(p.T, dot(Mi, p))
     adQn = cont_angle(det(Q), reference=adQ)[0]
     packet.set_parameters((q, p, Q, P, S, adQn), key=key)
Ejemplo n.º 4
0
 def _propkin(self, h, packet):
     """Do a kinetic step of size h.
     """
     Mi = self._Minv
     key = ("q", "p", "Q", "P", "S", "adQ")
     q, p, Q, P, S, adQ = packet.get_parameters(key=key)
     q = q + h * dot(Mi, p)
     Q = Q + h * dot(Mi, P)
     S = S + 0.5 * h * dot(p.T, dot(Mi, p))
     adQn = cont_angle(det(Q), reference=adQ)[0]
     packet.set_parameters((q, p, Q, P, S, adQn), key=key)
Ejemplo n.º 5
0
    def propagate(self):
        r"""Given a wavepacket :math:`\Psi` at time :math:`t` compute the propagated
        wavepacket at time :math:`t + \tau`. We perform exactly one timestep of size
        :math:`\tau` here. This propagation is done for all packets in the list
        :math:`\{\Psi_i\}_i` and neglects any interaction between two packets.

        More details can be found in [#]_.

        .. [#] E. Faou, V. Gradinaru and C. Lubich, "Computing semiclassical quantum dynamics with Hagedorn wavepackets",
               SIAM Journal on Scientific Computing, volume 31 number 4 (2009) 3027-3041.
        """
        # Cache some parameter values
        dt = self._dt
        Mi = self._Minv
        key = ("q", "p", "Q", "P", "S", "adQ")

        # Propagate all packets
        for packet, leading_chi in self._packets:
            eps = packet.get_eps()

            # Do a kinetic step of dt/2
            q, p, Q, P, S, adQ = packet.get_parameters(key=key)
            q = q + 0.5 * dt * dot(Mi, p)
            Q = Q + 0.5 * dt * dot(Mi, P)
            S = S + 0.25 * dt * dot(p.T, dot(Mi, p))
            adQn = cont_angle(det(Q), reference=adQ)[0]
            packet.set_parameters((q, p, Q, P, S, adQn), key=key)

            # Do a potential step with the local quadratic part
            q, p, Q, P, S = packet.get_parameters()
            V = self._potential.evaluate_local_quadratic_at(q, diagonal_component=leading_chi)

            p = p - dt * V[1]
            P = P - dt * dot(V[2], Q)
            S = S - dt * V[0]
            packet.set_parameters((q, p, Q, P, S))

            # Do a potential step with the local non-quadratic Taylor remainder
            innerproduct = packet.get_innerproduct()

            # Transform to psi
            packet2psi = self._TR.transform_phi_to_psi(packet)

            # G is F but in the new basis <psi|W|psi> at actual time t_{1/2}
            G = innerproduct.build_matrix(packet2psi, operator=partial(self._potential.evaluate_local_remainder_at, diagonal_component=leading_chi))

            coefficients = packet2psi.get_coefficient_vector()
            coefficients = self._matrix_exponential(G, coefficients, -1.0j * dt / eps**2)
            packet2psi.set_coefficient_vector(coefficients)

            # Transform back to phi
            packet2phi = self._TR.transform_psi_to_phi(packet2psi)
            packet.set_coefficient_vector(packet2phi.get_coefficient_vector())

            # Do a kinetic step of dt/2
            q, p, Q, P, S, adQ = packet.get_parameters(key=key)
            q = q + 0.5 * dt * dot(Mi, p)
            Q = Q + 0.5 * dt * dot(Mi, P)
            S = S + 0.25 * dt * dot(p.T, dot(Mi, p))
            adQn = cont_angle(det(Q), reference=adQ)[0]
            packet.set_parameters((q, p, Q, P, S, adQn), key=key)