wavepacket.grid =============== .. py:module:: wavepacket.grid .. autoapi-nested-parse:: This module contains the classes to define a grid and represent states on it. .. !! processed by numpydoc !! Classes ------- .. autoapisummary:: wavepacket.grid.DofBase wavepacket.grid.Grid wavepacket.grid.PlaneWaveDof wavepacket.grid.SphericalHarmonicsDof wavepacket.grid.State Package Contents ---------------- .. py:class:: DofBase(dvr_points: wavepacket.typing.RealData, fbr_points: wavepacket.typing.RealData) Bases: :py:obj:`abc.ABC` Abstract base class of a one-dimensional basis expansion. We assemble a multidimensional grid as direct product of one-dimensional grids. To distinguish these two types of grids, we call the one-dimensional grids DOF (Degree of Freedom). They are defined by a basis expansion (the FBR), its corresponding grid definition in real space (the DVR, see :doc:`/representations`), the transformation between the two representations, and some descriptive quantum numbers for the FBR. Note that the transformation functions are highly flexible, but awkward and error-prone to use, so they should generally be avoided outside Wavepacket-internal code. In general, you should use convenience functions instead that perform the required transformation behind the scenes, such as :py:func:`wavepacket.grid.dvr_density`. :Parameters: **dvr_points** : real-valued array_like The grid points in real space. **fbr_points** : real-valued array_like This is typically used to assign useful numbers to the underlying basis. For example, in a plane-wave expansion, we would use the wave vectors as fbr_grid. The size must match that of the `dvr_points`. :Attributes: **dvr_points: wpt.RealData, readonly** Numpy array that gives the grid points in real space as supplied in the constructor. This array is read-only and must never be modified. **fbr_points: wpt.RealData, readonly** Numpy array that gives the grid points of the underlying basis as supplied in the constructor. This array is read-only and must never be modified. **size: int, readonly** The size of the grid (number of elements of `dvr_points`/`fbr_points`) :Raises: wp.InvalidValueError If the input grids are empty, multidimensional, or if the FBR and DVR grid do not match in size. .. seealso:: :obj:`wavepacket.grid.Grid` The multidimensional grid formed from one or more degrees of freedom. :obj:`wavepacket.grid.PlaneWaveDof` An implementation of a degree of freedom based on a plane wave expansion. .. !! processed by numpydoc !! .. py:attribute:: dvr_points :type: Final[wavepacket.typing.RealData] .. py:attribute:: fbr_points :type: Final[wavepacket.typing.RealData] .. py:attribute:: size :type: Final[int] .. py:method:: to_fbr(data: wavepacket.typing.ComplexData, index: int, is_ket: bool = True) -> wavepacket.typing.ComplexData :abstractmethod: Translates a dimension of the input coefficients from the Wavepacket-default "weighted DVR" into the FBR. This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. **is_ket** : bool, default=True If the index is the coefficient for a ket state (True) or a bra state. :Returns: wpt.ComplexData The appropriately transformed coefficients. You will generally not wrap the results into a :py:class:`wavepacket.grid.State`, because that class implicitly assumes a weighted DVR transformation. .. !! processed by numpydoc !! .. py:method:: from_fbr(data: wavepacket.typing.ComplexData, index: int, is_ket: bool = True) -> wavepacket.typing.ComplexData :abstractmethod: Translates a dimension of the input coefficients from the FBR into the Wavepacket-default "weighted DVR" This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. **is_ket** : bool, default=True If the index is the coefficient for a ket state (True) or a bra state. :Returns: wpt.ComplexData The appropriately transformed coefficients. You generally need to wrap the result in a :py:class:`wavepacket.grid.State` before further use. .. !! processed by numpydoc !! .. py:method:: to_dvr(data: wavepacket.typing.ComplexData, index: int) -> wavepacket.typing.ComplexData :abstractmethod: Translates a dimension of the input coefficients from the Wavepacket-default "weighted DVR" into the DVR. This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. :Returns: wpt.ComplexData The appropriately transformed coefficients. You will generally not wrap the results into a :py:class:`wavepacket.grid.State`, because that class implicitly assumes a weighted DVR transformation. .. !! processed by numpydoc !! .. py:method:: from_dvr(data: wavepacket.typing.ComplexData, index: int) -> wavepacket.typing.ComplexData :abstractmethod: Translates a dimension of the input coefficients from the DVR into the Wavepacket-default "weighted DVR". This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. :Returns: wpt.ComplexData The appropriately transformed coefficients. They need to be wrapped in a :py:class:`wavepacket.grid.State` before further use. .. !! processed by numpydoc !! .. py:class:: Grid(dofs: Iterable[wavepacket.grid.dofbase.DofBase] | wavepacket.grid.dofbase.DofBase) Definition of a one- or multidimensional grid. This class collects multiple :py:class:`wavepacket.grid.DofBase`-derived objects, each corresponding to a one-dimensional basis expansion, and represents the resulting one- or multidimensional grid that you can operate with. :Parameters: **dofs** : Sequence[wp.grid.DofBase] | DofBase The degree(s) of freedom that make up the grid. The order determines the order of the coefficient array indices. :Attributes: **shape: tuple[int, ...], readonly** The shape of a NumPy array that describes a wave function. **operator_shape: tuple[int, ...], readonly** The shape of a NumPy array that describes an operator An example of such a matrix would be the coefficient array for a density operator. The operator dimensions are the dimensions of the grid concatenated with themselves. For example, a grid with dimensions (5, 4) has operator dimensions (5, 4, 5, 4). **size: int, readonly** The total number of grid points **dofs: int, readonly** A list of degrees of freedom that describe the degrees of freedom of the grid :Raises: wp.InvalidValueError If no degrees of freedom are supplied. .. !! processed by numpydoc !! .. py:attribute:: shape :type: Final[tuple[int, Ellipsis]] .. py:attribute:: operator_shape :type: Final[tuple[int, Ellipsis]] .. py:attribute:: size :type: Final[int] .. py:attribute:: dofs :type: Final[collections.abc.Sequence] .. py:method:: normalize_index(index: int) -> int Maps indices on the interval [0, rank_of_grid]. Meant for Wavepacket-internal use. For operator matrices, we want to address bra and ket indices separately, and with normal Python convention, i.e., -n meaning the n-th entry from the end. However, an operator matrix has 2N dimensions, with the first N denoting bra indices, and the last N denoting ket indices. Then, the arithmetic becomes cumbersome unless we first map the input index onto the range [0,N]. .. !! processed by numpydoc !! .. py:method:: broadcast(data: wavepacket.typing.AnyData, index: int) -> wavepacket.typing.AnyData Transforms a 1D array into a more suitable form for scaling. Meant for Wavepacket-internal use. Note that this function is rather slow, and should not be used in tight loops. This function has a very specific purpose. Imagine, you have a grid with shape (5, 4, 3). On this grid, you have a wave function specified by a coefficient array "a" of the same shape. Now you define a potential along the second degree of freedom only. The potential is given by a one-dimensional array "V" of size 4. If you want to apply this potential to the wave function within the DVR approximation, the new coefficients are given as :math:`b_{ijk} = V_j a_{ijk}`. Unfortunately, Numpy does not offer a function for this scaling operation. What we can do instead is to blow up the array V into a 3D array of shape (1, 4, 1). then you can map the above multiplication onto Numpy's broadcasting rules. This reshaping is done by this function. .. !! processed by numpydoc !! .. py:method:: operator_broadcast(data: wavepacket.typing.AnyData, dof_index: int, is_ket: bool = True) -> wavepacket.typing.AnyData Similar to broadcast, but blows up the array into a form suitable for multiplication with operators. Meant for Wavepacket-internal use. Note that this function is rather slow, and should not be used in tight loops. See :py:meth:`broadcast` for a description of the problem. For the (5, 4, 3) grid shape, this function would blow up the potential array into a shape (1, 4, 1, 1, 1, 1) or (1, 1, 1, 1, 4, 1). The is_ket parameter switches between the two variants, we call the first three indices "ket" and the latter three "bra" indices. .. !! processed by numpydoc !! .. py:class:: PlaneWaveDof(xmin: float, xmax: float, n: int) Bases: :py:obj:`wavepacket.grid.dofbase.DofBase` One-dimensional plane wave basis expansion. This expansion is a good base choice for non-rotational degrees of freedom. The DVR grid consists of equally-spaced grid points from xmin to (xmax - dx), the FBR grid are the wave vectors of the plane waves centered around 0. In the FBR, derivatives become simple multiplications wih the wave vectors, so this grid allows a simple representation of kinetic energy operators. The transformation between DVR and FBR uses an FFT, so the performance is ok, even though you might need more grid points than with more suitable expansions. Be aware that this degree of freedom implicitly uses periodic boundary conditions in real space. That is, if the wave function leaves the grid on one side, it reenters the grid on the other side. This problem can only be mitigated with negative imaginary potentials. Periodic boundary conditions also hold in the FBR, causing aliasing. Nevertheless, the monitoring of convergence is rather simple, see [R43725d022a50-1]_. :Parameters: **xmin** : float The start of the grid. **xmax** : float The end of the grid. Note that the last grid point is at xmax - dx. **n** : int The number of grid points. :Raises: wavepacket.InvalidValueError If the length of the grid is negative or the number of grid points is non-positive. .. rubric:: References .. [R43725d022a50-1] https://sourceforge.net/p/wavepacket/cpp/blog/2020/11/convergence-1-equally-space-grids .. only:: latex [R43725d022a50-1]_ .. !! processed by numpydoc !! .. py:method:: to_fbr(data: wavepacket.typing.ComplexData, index: int, is_ket: bool = True) -> wavepacket.typing.ComplexData Translates a dimension of the input coefficients from the Wavepacket-default "weighted DVR" into the FBR. This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. **is_ket** : bool, default=True If the index is the coefficient for a ket state (True) or a bra state. :Returns: wpt.ComplexData The appropriately transformed coefficients. You will generally not wrap the results into a :py:class:`wavepacket.grid.State`, because that class implicitly assumes a weighted DVR transformation. .. !! processed by numpydoc !! .. py:method:: from_fbr(data: wavepacket.typing.ComplexData, index: int, is_ket: bool = True) -> wavepacket.typing.ComplexData Translates a dimension of the input coefficients from the FBR into the Wavepacket-default "weighted DVR" This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. **is_ket** : bool, default=True If the index is the coefficient for a ket state (True) or a bra state. :Returns: wpt.ComplexData The appropriately transformed coefficients. You generally need to wrap the result in a :py:class:`wavepacket.grid.State` before further use. .. !! processed by numpydoc !! .. py:method:: to_dvr(data: wavepacket.typing.ComplexData, index: int) -> wavepacket.typing.ComplexData Translates a dimension of the input coefficients from the Wavepacket-default "weighted DVR" into the DVR. This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. :Returns: wpt.ComplexData The appropriately transformed coefficients. You will generally not wrap the results into a :py:class:`wavepacket.grid.State`, because that class implicitly assumes a weighted DVR transformation. .. !! processed by numpydoc !! .. py:method:: from_dvr(data: wavepacket.typing.ComplexData, index: int) -> wavepacket.typing.ComplexData Translates a dimension of the input coefficients from the DVR into the Wavepacket-default "weighted DVR". This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. :Returns: wpt.ComplexData The appropriately transformed coefficients. They need to be wrapped in a :py:class:`wavepacket.grid.State` before further use. .. !! processed by numpydoc !! .. py:class:: SphericalHarmonicsDof(lmax: int, m: int) Bases: :py:obj:`wavepacket.grid.dofbase.DofBase` One-dimensional expansion in rotational eigenstates / spherical harmonics. This expansion is obviously useful for systems that involve rotations. It takes a fixed magnetic quantum number m, because no DVR is known for arbitrary rotations. Wave functions are given at points :math:`(\theta_i, \phi=0)``, and the weights include the integration over :math:`\phi`. The FBR is an expansion in spherical harmonics :math:`Y_{lm}`, and the azimuthal quantum numbers :math:`l` form the FBR grid. :Parameters: **lmax: int** The maximum azimuthal quantum number that is expressed by the grid. **m: int** The magnetic quantum number :Attributes: **lmax: int, readonly** The maximum azimuthal quantum number that is expressed by the grid. **m: int, readonly** The magnetic quantum number :Raises: wavepacket.InvalidError If the magnetic quantum number is too large (i.e., if lmax < abs(m)) .. !! processed by numpydoc !! .. py:attribute:: lmax :type: Final[int] .. py:attribute:: m :type: Final[int] .. py:method:: to_fbr(data: wavepacket.typing.ComplexData, index: int, is_ket: bool = True) -> wavepacket.typing.ComplexData Translates a dimension of the input coefficients from the Wavepacket-default "weighted DVR" into the FBR. This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. **is_ket** : bool, default=True If the index is the coefficient for a ket state (True) or a bra state. :Returns: wpt.ComplexData The appropriately transformed coefficients. You will generally not wrap the results into a :py:class:`wavepacket.grid.State`, because that class implicitly assumes a weighted DVR transformation. .. !! processed by numpydoc !! .. py:method:: from_fbr(data: wavepacket.typing.ComplexData, index: int, is_ket: bool = True) -> wavepacket.typing.ComplexData Translates a dimension of the input coefficients from the FBR into the Wavepacket-default "weighted DVR" This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. **is_ket** : bool, default=True If the index is the coefficient for a ket state (True) or a bra state. :Returns: wpt.ComplexData The appropriately transformed coefficients. You generally need to wrap the result in a :py:class:`wavepacket.grid.State` before further use. .. !! processed by numpydoc !! .. py:method:: to_dvr(data: wavepacket.typing.ComplexData, index: int) -> wavepacket.typing.ComplexData Translates a dimension of the input coefficients from the Wavepacket-default "weighted DVR" into the DVR. This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. :Returns: wpt.ComplexData The appropriately transformed coefficients. You will generally not wrap the results into a :py:class:`wavepacket.grid.State`, because that class implicitly assumes a weighted DVR transformation. .. !! processed by numpydoc !! .. py:method:: from_dvr(data: wavepacket.typing.ComplexData, index: int) -> wavepacket.typing.ComplexData Translates a dimension of the input coefficients from the DVR into the Wavepacket-default "weighted DVR". This function is not meant for public use. It does not handle errors explicitly, and is just awkward to use; you need to reach through the state abstraction and transform each index correctly. :Parameters: **data** : wp.typing.ComplexData The input coefficients of the state to transform. **index** : int The index of the coefficient array that should be transformed. :Returns: wpt.ComplexData The appropriately transformed coefficients. They need to be wrapped in a :py:class:`wavepacket.grid.State` before further use. .. !! processed by numpydoc !! .. py:class:: State This class holds the definition of a specific quantum state. A state can be a wave function or a density operator. While invalid states can be constructed, they have no use. A state is composed of three parts: 1. The grid on which the state is defined. 2. The expansion coefficients. 3. The representation / basis for the expansion. This is always weighted DVR, see :doc:`/representations`. Once constructed, a State is meant to be immutable. It supports elementary arithmetic operations, however, to allow easy composition. The technical reason for a state class is to store grids together with the coefficients, which greatly simplifies the Wavepacket API. :Attributes: **grid** The grid on which the state is defined. **data** The coefficients of the state. .. rubric:: Examples States are usually generated using functions in the wavepacket.builder package. Those functions require a grid. >>> psi = wp.builder.product_wave_function(grid, wp.Gaussian(rms=0.5)) >>> zero = wp.builder.zero_wave_function(grid) >>> rho = wp.builder.pure_density(psi) Ordinary arithmetic is possible. >>> psi2 = psi + zero + 1.0 You can access the low-level details of the state. >>> import numpy >>> assert psi2.grid = grid >>> assert numpy.all(zero.data == 0.0) States are input to and output from most operations >>> wp.trace(psi) 1.0 .. !! processed by numpydoc !! .. py:attribute:: grid :type: wavepacket.grid.grid.Grid .. py:attribute:: data :type: wavepacket.typing.ComplexData .. py:method:: is_wave_function() -> bool Returns whether the state represents a wave function. .. !! processed by numpydoc !! .. py:method:: is_density_operator() -> bool Returns whether the state represents a density operator. .. !! processed by numpydoc !!