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)
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)
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)