Source code for WaveBlocksND.HagedornWavepacketPsi

"""The WaveBlocks Project

This file contains the class which represents a homogeneous Hagedorn wavepacket.

@author: R. Bourquin
@copyright: Copyright (C) 2016 R. Bourquin
@license: Modified BSD License
"""

from numpy import zeros, complexfloating, array, eye, atleast_2d, angle, squeeze
from numpy.linalg import det

from WaveBlocksND.HagedornWavepacketBase import HagedornWavepacketBase
from WaveBlocksND.HyperCubicShape import HyperCubicShape
from WaveBlocksND.ComplexMath import ContinuousSqrt
from WaveBlocksND.GradientHAWPpsi import GradientHAWPpsi
from WaveBlocksND.HagedornBasisEvaluationPsi import HagedornBasisEvaluationPsi

__all__ = ["HagedornWavepacketPsi"]


[docs]class HagedornWavepacketPsi(HagedornWavepacketBase, HagedornBasisEvaluationPsi): r"""This class represents homogeneous vector valued Hagedorn wavepackets :math:`\Psi` with :math:`N` components in :math:`D` space dimensions. """
[docs] def __init__(self, dimension, ncomponents, eps): r"""Initialize a new homogeneous Hagedorn wavepacket of the new kind. :param dimension: The space dimension :math:`D` the packet has. :param ncomponents: The number :math:`N` of components the packet has. :param eps: The semi-classical scaling parameter :math:`\varepsilon` of the basis functions. :return: An instance of :py:class:`HagedornWavepacket`. """ self._dimension = dimension self._number_components = ncomponents self._eps = eps # The basis shapes K_i self._basis_shapes = [] # The coefficients c^i self._coefficients = [] for d in range(self._number_components): # Default basis shapes for all components BS = HyperCubicShape(self._dimension * [1]) self._basis_shapes.append(BS) # A Gaussian self._coefficients.append(zeros((BS.get_basis_size(), 1), dtype=complexfloating)) # Cache basis sizes self._basis_sizes = [bs.get_basis_size() for bs in self._basis_shapes] # Default parameters of harmonic oscillator eigenstates q = zeros((self._dimension, 1), dtype=complexfloating) p = zeros((self._dimension, 1), dtype=complexfloating) Q = eye(self._dimension, dtype=complexfloating) P = 1.0j * eye(self._dimension, dtype=complexfloating) S = zeros((1, 1), dtype=complexfloating) # The parameter set Pi self._Pis = [q, p, Q, P, S] # No inner product set self._IP = None # Function for taking continuous roots self._sqrt = ContinuousSqrt(reference=angle(det(Q)))
[docs] def __str__(self): r""":return: A string describing the Hagedorn wavepacket :math:`\Psi`. """ s = "Homogeneous Hagedorn wavepacket with " + str(self._number_components) + " component(s) in " + str(self._dimension) + " space dimension(s)\n" return s
def _get_sqrt(self, component): r"""Compatibility method """ return self._sqrt
[docs] def get_description(self): r"""Return a description of this wavepacket object. A description is a ``dict`` containing all key-value pairs necessary to reconstruct the current instance. A description never contains any data. """ d = {} d["type"] = "HagedornWavepacketPsi" d["dimension"] = self._dimension d["ncomponents"] = self._number_components d["eps"] = self._eps if self._IP is not None: d["innerproduct"] = self._IP.get_description() return d
def clone(self, keepid=False): # Parameters of this packet params = self.get_description() # Create a new Packet # TODO: Consider using the block factory other = HagedornWavepacketPsi(params["dimension"], params["ncomponents"], params["eps"]) # If we wish to keep the packet ID if keepid is True: other.set_id(self.get_id()) # And copy over all (private) data # Basis shapes are immutable, no issues with sharing same instance other.set_basis_shapes(self.get_basis_shapes()) other.set_parameters(self.get_parameters()) other.set_coefficients(self.get_coefficients()) # Innerproducts are stateless and finally immutable, # no issues with sharing same instance other.set_innerproduct(self.get_innerproduct()) # The complex root cache other._sqrt = self._sqrt.clone() return other
[docs] def get_parameters(self, component=None, aslist=False, key=("q", "p", "Q", "P", "S")): r"""Get the Hagedorn parameter set :math:`\Pi` of the wavepacket :math:`\Psi`. :param component: Dummy parameter for API compatibility with the inhomogeneous packets. :param aslist: Return a list of :math:`N` parameter tuples. This is for API compatibility with inhomogeneous packets. :return: The Hagedorn parameter set :math:`\Pi = (q, p, Q, P, S)` in this order. """ Pilist = [] for k in key: if k == "q": Pilist.append(self._Pis[0].copy()) elif k == "p": Pilist.append(self._Pis[1].copy()) elif k == "Q": Pilist.append(self._Pis[2].copy()) elif k == "P": Pilist.append(self._Pis[3].copy()) elif k == "S": Pilist.append(self._Pis[4].copy()) elif k == "adQ": Pilist.append(array(self._get_sqrt(component).get(), dtype=complexfloating)) else: raise KeyError("Invalid parameter key: {}".format(key)) if aslist is True: return self._number_components * [Pilist] return Pilist
[docs] def set_parameters(self, Pi, component=None, key=("q", "p", "Q", "P", "S")): r"""Set the Hagedorn parameters :math:`\Pi` of the wavepacket :math:`\Psi`. :param Pi: The Hagedorn parameter set :math:`\Pi = (q, p, Q, P, S)` in this order. :param component: Dummy parameter for API compatibility with the inhomogeneous packets. """ D = self._dimension for k, item in zip(key, Pi): if k == "q": self._Pis[0] = atleast_2d(array(item, dtype=complexfloating)).reshape(D, 1) elif k == "p": self._Pis[1] = atleast_2d(array(item, dtype=complexfloating)).reshape(D, 1) elif k == "Q": self._Pis[2] = atleast_2d(array(item, dtype=complexfloating)).reshape(D, D) elif k == "P": self._Pis[3] = atleast_2d(array(item, dtype=complexfloating)).reshape(D, D) elif k == "S": self._Pis[4] = atleast_2d(array(item, dtype=complexfloating)).reshape(1, 1) elif k == "adQ": self._get_sqrt(component).set(squeeze(item)) else: raise KeyError("Invalid parameter key: {}".format(key))
[docs] def get_gradient_operator(self): r"""Return the :py:class:`Gradient` subclass suitable for computing gradients of this wavepacket. :return: A :py:class:`GradientHAWP` instance. """ return GradientHAWPpsi()