"""The WaveBlocks Project
This file contains the class which represents an inhomogeneous Hagedorn wavepacket.
@author: R. Bourquin
@copyright: Copyright (C) 2010, 2011, 2012, 2013, 2014, 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.HagedornBasisEvaluationPhi import HagedornBasisEvaluationPhi
__all__ = ["HagedornWavepacketInhomogeneous"]
[docs]class HagedornWavepacketInhomogeneous(HagedornWavepacketBase, HagedornBasisEvaluationPhi):
r"""This class represents inhomogeneous 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 in homogeneous Hagedorn wavepacket.
: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:`HagedornWavepacketInhomogeneous`.
"""
self._dimension = dimension
self._number_components = ncomponents
self._eps = eps
# The parameter sets Pi_i
self._Pis = []
# 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))
# 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)
self._Pis.append([q, p, Q, P, S])
# Cache basis sizes
self._basis_sizes = [bs.get_basis_size() for bs in self._basis_shapes]
# No inner product set
self._IP = None
# Function for taking continuous roots
self._sqrt = [ContinuousSqrt(angle(det(self._Pis[n][2]))) for n in range(self._number_components)]
[docs] def __str__(self):
r""":return: A string describing the Hagedorn wavepacket :math:`\Psi`.
"""
s = "Inhomogeneous 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[component]
[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"] = "HagedornWavepacketInhomogeneous"
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 = HagedornWavepacketInhomogeneous(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 caches
other._sqrt = [item.clone() for item in self._sqrt]
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_i` of each component :math`\Phi_i`
of the wavepacket :math:`\Psi`.
:param component: The index :math:`i` of the component :math:`\Phi_i` whose
parameters :math:`\Pi_i` we want to get.
:param aslist: Dummy parameter for API compatibility with the homogeneous packets.
:return: A list with all parameter sets :math:`\Pi_i` or a single parameter set.
The parameters :math:`\Pi_i = (q_i, p_i, Q_i, P_i, S_i)` are always in this order.
"""
if component is None:
components = range(self._number_components)
else:
components = [component]
Pilist = []
for index in components:
tmp = []
for k in key:
if k == "q":
tmp.append(self._Pis[index][0].copy())
elif k == "p":
tmp.append(self._Pis[index][1].copy())
elif k == "Q":
tmp.append(self._Pis[index][2].copy())
elif k == "P":
tmp.append(self._Pis[index][3].copy())
elif k == "S":
tmp.append(self._Pis[index][4].copy())
elif k == "adQ":
tmp.append(array(self._get_sqrt(index).get(), dtype=complexfloating))
else:
raise KeyError("Invalid parameter key: {}".format(key))
Pilist.append(tmp)
if component is not None:
return Pilist[0]
return Pilist
[docs] def set_parameters(self, Pi, component=None, key=("q", "p", "Q", "P", "S")):
r"""Set the Hagedorn parameter set :math:`\Pi_i` of each component :math`\Phi_i`
of the wavepacket :math:`\Psi`.
:param Pi: The parameter sets :math:`\Pi_i = (q_i, p_i, Q_i, P_i, S_i)` with its values in this order.
:type Pi: A single tuple or a list of tuples
:param component: The index :math:`i` of the component :math:`\Phi_i` whose parameters :math:`\Pi_i` we want to update.
"""
if component is None:
component = range(self._number_components)
else:
component = [component]
Pi = [Pi]
D = self._dimension
for index, pic in zip(component, Pi):
for k, item in zip(key, pic):
if k == "q":
self._Pis[index][0] = atleast_2d(array(item, dtype=complexfloating)).reshape(D, 1)
elif k == "p":
self._Pis[index][1] = atleast_2d(array(item, dtype=complexfloating)).reshape(D, 1)
elif k == "Q":
self._Pis[index][2] = atleast_2d(array(item, dtype=complexfloating)).reshape(D, D)
elif k == "P":
self._Pis[index][3] = atleast_2d(array(item, dtype=complexfloating)).reshape(D, D)
elif k == "S":
self._Pis[index][4] = atleast_2d(array(item, dtype=complexfloating)).reshape(1, 1)
elif k == "adQ":
self._get_sqrt(index).set(squeeze(item))
else:
raise KeyError("Invalid parameter key: {}".format(key))