Source code for WaveBlocksND.PhaseSpaceLattice
"""The WaveBlocks Project
This file contains code for constructing phase space lattices.
@author: R. Bourquin
@copyright: Copyright (C) 2013 R. Bourquin
@license: Modified BSD License
"""
from numpy import array, sqrt, pi, mgrid, complexfloating, einsum, product, sum
__all__ = ["PhaseSpaceLattice"]
[docs]class PhaseSpaceLattice(object):
r"""A phase space lattice centered around an energy :math:`E_0`
and bounded by an energy delta :math:`\Delta E`.
"""
[docs] def __init__(self, potential, energy, energydelta, eps, D):
r"""
Configure a new phase space lattice centered around an energy :math:`E_0`
and bounded by an energy delta :math:`\Delta E`. The actual lattice points
are computed by the member function :py:func:`compute_lattice`.
:param potential: The potential :math:`V`.
:type potential: Not a :py:class:`MatrixPotential` instance but possible a (partially evaluated)
member method like :py:func:`evaluate_at` or any scalar valued function.
:param energy: The energy :math:`E_0` around which to center the lattice points.
:param energydelta: The energy delta :math:`\Delta E`.
:param eps: The semiclassical scaling parameter :math:`\varepsilon`.
:param D: The dimensionality :math:`D` of position space.
"""
self._potential = potential
self._eps = eps
self._energy = energy
self._energydelta = energydelta
self._dimension = D
self._lattice_computed = False
[docs] def compute_lattice(self, qlimits, plimits):
r"""Compute the lattice points. Search for valid points an a hypercubic
region of phase space given by limits for position :math:`q` and
momentum :math:`p`.
:param qlimits: The position limits :math:`q^d_{\mathrm{min}}` and :math:`q^d_{\mathrm{max}}`
for all dimensions :math:`d \in [0,\ldots,D-1]`.
:type qlimits: A list of pairs of floats.
:param plimits: The momentum limit :math:`p^d_{\mathrm{min}}` and :math:`p^d_{\mathrm{max}}`
for all dimensions :math:`d \in [0,\ldots,D-1]`.
:type plimits: A list of pairs of floats.
"""
dimension = self._dimension
latdist = 0.75 * self._eps * sqrt(pi)
qslicers = [slice(lims[0], lims[1] + latdist, latdist) for lims in qlimits]
pslicers = [slice(lims[0], lims[1] + latdist, latdist) for lims in plimits]
qgrid = array(mgrid[qslicers], dtype=complexfloating).reshape((dimension, -1))
pgrid = array(mgrid[pslicers], dtype=complexfloating).reshape((dimension, -1))
qvals = self._potential(qgrid)
pvals = 0.5 * einsum("ij,ij->j", pgrid, pgrid).reshape(-1, 1)
Z = qvals + pvals
indices = (abs(Z - self._energy) < self._energydelta)
keepq = []
keepp = []
rows, cols = indices.shape
for r in range(rows):
for c in range(cols):
if bool(indices[r, c]) is True:
keepq.append(c)
keepp.append(r)
qgridf = qgrid[:, keepq]
pgridf = pgrid[:, keepp]
ps_size = sum(indices)
ps_size_full = product(Z.shape)
print("Phase space lattice size: {}".format(ps_size))
print(" number candidates tested: {}".format(ps_size_full))
print(" pruning factor: "+str((1.0 - ps_size / (1.0 * ps_size_full)) * 100)+"%")
self._qgrid = qgridf
self._pgrid = pgridf
self._lattice_size = ps_size
self._lattice_computed = True
[docs] def get_lattice(self):
r"""
:return: The phase space lattice in the form ``(qgrid, pgrid)``
where each grid is an :py:class:`ndarray` of shape ``(D, lattice_size)``
"""
if self._lattice_computed:
return (self._qgrid, self._pgrid)
else:
raise ValueError("Phase space lattice not yet computed")
[docs] def get_lattice_size(self):
r"""
:return: The number of points :math:`(q_i,p_i)` in the lattice.
"""
if self._lattice_computed:
return self._lattice_size
else:
raise ValueError("Phase space lattice not yet computed")