diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index e212e7aeab0..fced6b309aa 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -789,6 +789,10 @@ Here's a list of deprecations made this release. For a more detailed breakdown o
Documentation 📝
+* The functions in `qml.qchem.vibrational` are updated to include additional information about the
+ theory and input arguments.
+ [(#6918)](https://github.com/PennyLaneAI/pennylane/pull/6918)
+
* The usage examples for `qml.decomposition.DecompositionGraph` have been updated.
[(#7692)](https://github.com/PennyLaneAI/pennylane/pull/7692)
diff --git a/pennylane/labs/tests/vibrational/test_pes_generator.py b/pennylane/labs/tests/vibrational/test_pes_generator.py
index c1522e1d469..6a06c23e5c3 100644
--- a/pennylane/labs/tests/vibrational/test_pes_generator.py
+++ b/pennylane/labs/tests/vibrational/test_pes_generator.py
@@ -27,7 +27,7 @@
h5py = pytest.importorskip("h5py")
-# pylint: disable=too-many-arguments, protected-access, too-many-positional-arguments
+# pylint: disable=too-many-arguments, protected-access, too-many-positional-arguments, unsubscriptable-object
ref_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_ref_files")
diff --git a/pennylane/qchem/vibrational/localize_modes.py b/pennylane/qchem/vibrational/localize_modes.py
index 92aa94eead8..0da70f739b4 100644
--- a/pennylane/qchem/vibrational/localize_modes.py
+++ b/pennylane/qchem/vibrational/localize_modes.py
@@ -174,26 +174,38 @@ def _localize_modes(freqs, vecs):
def localize_normal_modes(freqs, vecs, bins=[2600]):
- """
- Localizes vibrational normal modes.
+ r"""Computes spatially localized vibrational normal modes.
- The normal modes are localized by separating frequencies into specified ranges following the
- procedure described in `J. Chem. Phys. 141, 104105 (2014)
+ The vibrational normal modes are localized using a localizing unitary following the procedure
+ described in `J. Chem. Phys. 141, 104105 (2014)
`_.
+ Efficient-anharmonic-vibrational-spectroscopy-for?redirectedFrom=fulltext>`_. The localizing
+ unitary :math:`U` is defined in terms of the normal and local coordinates, :math:`q` and
+ :math:`\tilde{q}`, respectively as:
+
+ .. math::
+
+ \tilde{q} = \sum_{j=1}^M U_{ij} q_j,
+
+ where :math:`M` is the number of modes. The normal modes
+ can be separately localized, to prevent mixing between specific groups of normal modes, by
+ defining frequency ranges in ``bins``. For instance, ``bins = [2600]`` allows to separately
+ localize modes that have frequencies above and below :math:`2600` reciprocal centimetre (:math:`\text{cm}^{-1}`).
+ Similarly, ``bins = [1300, 2600]`` allows to separately localize modes in three groups that have
+ frequencies below :math:`1300`, between :math:`1300-2600` and above :math:`2600`.
Args:
- freqs (list[float]): normal mode frequencies in ``cm^-1``
- vecs (TensorLike[float]): displacement vectors for normal modes
- bins (list[float]): List of upper bound frequencies in ``cm^-1`` for creating separation bins .
- Default is ``[2600]`` which means having one bin for all frequencies between ``0`` and ``2600 cm^-1``.
+ freqs (TensorLike[float]): normal mode frequencies in reciprocal centimetre (:math:`\text{cm}^{-1}`).
+ vecs (TensorLike[float]): displacement vectors of the normal modes
+ bins (List[float]): grid of frequencies for grouping normal modes.
+ Default is ``[2600]``.
Returns:
tuple: A tuple containing the following:
- - list[float] : localized frequencies
- - TensorLike[float] : localized displacement vectors
- - TensorLike[float] : localization matrix describing the relationship between
- original and localized modes.
+ - TensorLike[float] : localized frequencies in reciprocal centimetre (:math:`\text{cm}^{-1}`).
+ - List[TensorLike[float]] : localized displacement vectors
+ - TensorLike[float] : localization matrix describing the relationship between the
+ original and the localized modes
**Example**
@@ -209,7 +221,7 @@ def localize_normal_modes(freqs, vecs, bins=[2600]):
... [-5.49709883e-17, 7.49851221e-08, -2.77912798e-02]]])
>>> freqs_loc, vecs_loc, uloc = qml.qchem.localize_normal_modes(freqs, vectors)
>>> freqs_loc
- array([1332.62008773, 2296.73455892, 2296.7346082 ])
+ array([1332.62013257, 2296.73453455, 2296.73460655])
"""
if not bins:
diff --git a/pennylane/qchem/vibrational/taylor_ham.py b/pennylane/qchem/vibrational/taylor_ham.py
index 88323055ea7..29c64161a1a 100644
--- a/pennylane/qchem/vibrational/taylor_ham.py
+++ b/pennylane/qchem/vibrational/taylor_ham.py
@@ -274,51 +274,79 @@ def _fit_threebody(threemode_op, max_deg, min_deg=3):
def taylor_coeffs(pes, max_deg=4, min_deg=3):
- r"""Compute fitted coefficients for Taylor vibrational Hamiltonian.
+ r"""Computes the coefficients of a Taylor vibrational Hamiltonian.
- The coefficients are defined following Eq. 5 of `arXiv:1703.09313
- `_ as:
-
- .. math::
-
- \Phi_{ijk} = \frac{k_{ijk}}{\sqrt{\omega_i \omega_j \omega_k}}
- \quad \text{and} \quad
- \Phi_{ijkl} = \frac{k_{ijkl}}{\sqrt{\omega_i \omega_j \omega_k \omega_l}},
-
- where :math:`\Phi_{ijk}` and :math:`\Phi_{ijkl}` are the third- and fourth-order reduced force
- constants, respectively, defined in terms of the third- and fourth-order partial derivatives
- of the potential energy surface data.
+ The coefficients are computed from a multi-dimensional polynomial fit over potential energy data
+ computed along normal coordinates, with a polynomial specified by ``min_deg`` and ``max_deg``.
Args:
- pes (VibrationalPES): object containing the vibrational potential energy surface data
- max_deg (int): maximum degree of Taylor form polynomial
- min_deg (int): minimum degree of Taylor form polynomial
+ pes (VibrationalPES): the vibrational potential energy surface object
+ max_deg (int): maximum degree of the polynomial used to compute the coefficients
+ min_deg (int): minimum degree of the polynomial used to compute the coefficients
Returns:
- tuple(TensorLike[float]): the coefficients of the one-body, two-body and three-body terms
+ List(TensorLike[float]): the coefficients of the Taylor vibrational Hamiltonian
**Example**
- >>> pes_onemode = np.array([[0.309, 0.115, 0.038, 0.008, 0.000, 0.006, 0.020, 0.041, 0.070]])
- >>> pes_twomode = np.zeros((1, 1, 9, 9))
- >>> dipole_onemode = np.zeros((1, 9, 3))
- >>> gauss_weights = np.array([3.96e-05, 4.94e-03, 8.85e-02,
- ... 4.33e-01, 7.20e-01, 4.33e-01,
- ... 8.85e-02, 4.94e-03, 3.96e-05])
- >>> grid = np.array([-3.19, -2.27, -1.47, -0.72, 0.0, 0.72, 1.47, 2.27, 3.19])
- >>> pes_object = qml.qchem.VibrationalPES(
- ... freqs=np.array([0.025]),
- ... grid=grid,
- ... uloc=np.array([[1.0]]),
- ... gauss_weights=gauss_weights,
- ... pes_data=[pes_onemode, pes_twomode],
- ... dipole_data=[dipole_onemode],
- ... localized=True,
- ... dipole_level=1,
- ... )
- >>> one, two = qml.qchem.taylor_coeffs(pes_object, 4, 2)
- >>> print(one)
- [[-0.00088528 -0.00361425 0.00068143]]
+ >>> freqs = np.array([0.0249722])
+ >>> pes_onemode = np.array([[0.08477, 0.01437, 0.00000, 0.00937, 0.03414]])
+ >>> pes_object = qml.qchem.VibrationalPES(freqs=freqs, pes_data=[pes_onemode])
+ >>> coeffs = qml.qchem.taylor_coeffs(pes_object, 4, 2)
+ >>> print(coeffs)
+ [array([[-4.73959071e-05, -3.06785775e-03, 5.21798831e-04]])]
+
+ .. details::
+ :title: Theory
+
+ A molecular potential energy surface can be defined as [Eq. 7 of
+ `J. Chem. Phys. 135, 134108 (2011) `_]:
+
+ .. math::
+
+ V = V_0 + \sum_{i} F_i q_i + \sum_{i,j} F_{ij} q_i q_j +
+ \sum_{i,j,k} F_{ijk} q_i q_j q_k + \cdots,
+
+ where :math:`q` is a normal coordinate and :math:`F` represents the derivatives of the
+ potential energy surface.
+
+ This function computes these derivatives via Taylor expansion of the potential energy data
+ by performing a multi-dimensional polynomial fit.
+
+ The potential energy surface along the normal coordinate can be defined as
+
+ .. math::
+
+ V(q_1,\cdots,q_M) = V_0 + \sum_{i=1}^M V_1^{(i)}(q_i) + \sum_{i>j}
+ V_2^{(i,j)}(q_i,q_j) + \sum_{i>> freqs = np.array([0.01885397])
- >>> grid, weights = np.polynomial.hermite.hermgauss(9)
- >>> pes_onebody = np.array([[0.05235573, 0.03093067, 0.01501878, 0.00420778, 0.0,
- ... 0.00584504, 0.02881817, 0.08483433, 0.22025702]])
- >>> pes_twobody = None
- >>> dipole_onebody = np.array([[[-1.92201700e-16, 1.45397041e-16, -1.40451549e-01],
- ... [-1.51005108e-16, 9.53185441e-17, -1.03377032e-01],
- ... [-1.22793018e-16, 7.22781963e-17, -6.92825934e-02],
- ... [-1.96537436e-16, -5.86686504e-19, -3.52245369e-02],
- ... [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
- ... [ 5.24758835e-17, -1.40650833e-16, 3.69955543e-02],
- ... [-4.52407941e-17, 1.38406311e-16, 7.60888733e-02],
- ... [-4.63820104e-16, 5.42928787e-17, 1.17726042e-01],
- ... [ 1.19224372e-16, 9.12491386e-17, 1.64013197e-01]]])
- >>> vib_obj = qml.qchem.VibrationalPES(
- ... freqs=freqs,
- ... grid=grid,
- ... gauss_weights=weights,
- ... uloc=None,
- ... pes_data=[pes_onebody, pes_twobody],
- ... dipole_data=[dipole_onebody],
- ... localized=False
- ... )
- >>> x, y, z = qml.qchem.taylor_dipole_coeffs(vib_obj, 4, 2)
- >>> print(z)
- [array([[ 1.64124324e-03, 5.39120159e-03, -4.80053702e-05]])]
+ >>> freqs = np.array([0.0249722])
+ >>> dipole_onemode = np.array([[[-1.24222060e-16, -6.29170686e-17, -7.04678188e-02],
+ ... [ 3.83941489e-16, -2.31579327e-18, -3.24444991e-02],
+ ... [ 1.67813138e-17, -5.63904474e-17, -5.60662627e-15],
+ ... [-7.37584781e-17, -5.51948189e-17, 2.96786374e-02],
+ ... [ 1.40526000e-16, -3.67126324e-17, 5.92006212e-02]]])
+ >>> pes_object = qml.qchem.VibrationalPES(freqs=freqs, dipole_data=[dipole_onemode])
+ >>> coeffs_x, coeffs_y, coeffs_z = qml.qchem.taylor_dipole_coeffs(pes_object, 4, 2)
+ >>> print(coeffs_z)
+ [array([[-1.54126823e-03, 8.17300533e-03, 3.94178001e-05]])]
+
+ .. details::
+ :title: Theory
+
+ The dipole :math:`D` along each of the :math:`x, y,` and :math:`z` directions is defined as:
+
+ .. math::
+
+ D(q_1,\cdots,q_M) = D_0 + \sum_{i=1}^M D_1^{(i)}(q_i) + \sum_{i>j}
+ D_2^{(i,j)}(q_i,q_j) + \sum_{ij}
+ V_2^{(i,j)}(q_i,q_j) + \sum_{i`_.
+ .. math::
+
+ V_0 &\equiv V(q_1=0,\cdots,q_M=0) \\
+ V_1^{(i)}(q_i) &\equiv V(0,\cdots,0,q_i,0,\cdots,0) - V_0 \\
+ V_2^{(i,j)}(q_i,q_j) &\equiv V(0,\cdots,q_i,\cdots,q_j,\cdots,0) -
+ V_1^{(i)}(q_i) - V_1^{(j)}(q_j) - V_0 \\
+ \nonumber \vdots
+
+ These terms are then used in a multi-dimensional polynomial fit to get :math:`n`-mode Taylor
+ coefficients. For instance, the one-mode Taylor coefficient :math:`\Phi` is related to the
+ one-mode potential energy surface data as:
+
+ .. math::
+
+ V_1^{(j)}(q_j) \approx \Phi^{(2)}_j q_j^2 + \Phi^{(3)}_j q_j^3 + ...
+
+ Similarly, the two-mode and three-mode Taylor coefficients are computed if the two-mode and
+ three-mode potential energy surface data, :math:`V_2^{(j, k)}(q_j, q_k)` and
+ :math:`V_3^{(j, k, l)}(q_j, q_k, q_l)`, are provided.
+
+ This real-space form of the vibrational Hamiltonian can be represented in the bosonic basis by
+ using equations defined in Eqs. 6, 7 of `arXiv:1703.09313 `_:
+
+ .. math::
+
+ \hat q_i = \frac{1}{\sqrt{2}}(b_i^\dagger + b_i), \quad
+ \hat p_i = \frac{1}{\sqrt{2}}(b_i^\dagger - b_i),
+
+ where :math:`b^\dagger` and :math:`b` are bosonic creation and annihilation operators,
+ respectively.
Args:
- coeffs (list(float)): the coefficients of the Hamiltonian
- freqs (list(float)): the harmonic frequencies in atomic units
- is_local (bool): Flag whether the vibrational modes are localized. Default is ``True``.
- uloc (list(list(float))): localization matrix indicating the relationship between original
- and localized modes
+ coeffs (list(tensorlike(float))): the coefficients of a Taylor vibrational Hamiltonian
+ freqs (array(float)): the harmonic vibrational frequencies in atomic units
+ is_local (bool): Whether the vibrational modes are localized. Default is ``True``.
+ uloc (tensorlike(float)): normal mode localization matrix with shape ``(m, m)`` where
+ ``m = len(freqs)``
Returns:
- pennylane.bose.BoseSentence: Taylor bosonic hamiltonian
+ pennylane.bose.BoseSentence: Taylor bosonic Hamiltonian
**Example**
- >>> one_mode = np.array([[-0.00088528, -0.00361425, 0.00068143]])
- >>> two_mode = np.array([[[0., 0., 0., 0., 0., 0.]]])
>>> freqs = np.array([0.025])
+ >>> one_mode = np.array([[-0.00088528, -0.00361425, 0.00068143]])
>>> uloc = np.array([[1.0]])
- >>> ham = qml.qchem.taylor_bosonic(coeffs=[one_mode, two_mode], freqs=freqs, uloc=uloc)
+ >>> ham = qml.qchem.taylor_bosonic(coeffs=[one_mode], freqs=freqs, uloc=uloc)
>>> print(ham)
-0.0012778303419517393 * b⁺(0) b⁺(0) b⁺(0)
+ -0.0038334910258552178 * b⁺(0) b⁺(0) b(0)
@@ -635,51 +741,102 @@ def taylor_bosonic(coeffs, freqs, is_local=True, uloc=None):
def taylor_hamiltonian(
pes, max_deg=4, min_deg=3, mapping="binary", n_states=2, wire_map=None, tol=1e-12
):
- """Return Taylor vibrational Hamiltonian.
+ r"""Returns Taylor vibrational Hamiltonian.
+
+ The Taylor vibrational Hamiltonian is defined in terms of kinetic :math:`T` and potential
+ :math:`V` components as:
+
+ .. math::
+
+ H = T + V.
+
+ The kinetic term is defined in terms of momentum :math:`p` operator as
+
+ .. math::
+
+ T = \sum_{i\geq j} K_{ij} p_i p_j,
+
+ where the :math:`K` matrix is defined in terms of vibrational frequencies, :math:`\omega`, and
+ mode localization unitary matrix, :math:`U`, as:
+
+ .. math::
+
+ K_{ij} = \sum_{k=1}^M \frac{\omega_k}{2} U_{ki} U_{kj}.
+
+ The potential term is defined in terms of the normal coordinate operator :math:`q` as:
+
+ .. math::
+
+ V(q_1,\cdots,q_M) = V_0 + \sum_{i=1}^M V_1^{(i)}(q_i) + \sum_{i>j}
+ V_2^{(i,j)}(q_i,q_j) + \sum_{i`_.
- The Hamiltonian is then converted to a qubit operator with a selected ``mapping`` method.
+ Similarly, the two-mode and three-mode Taylor coefficients are computed if the two-mode and
+ three-mode potential energy surface data, :math:`V_2^{(j, k)}(q_j, q_k)` and
+ :math:`V_3^{(j, k, l)}(q_j, q_k, q_l)`, are provided.
+
+ This real space form of the vibrational Hamiltonian can be represented in the bosonic basis by
+ using equations defined in Eqs. 6, 7 of `arXiv:1703.09313 `_:
+
+ .. math::
+
+ \hat q_i = \frac{1}{\sqrt{2}}(b_i^\dagger + b_i), \quad
+ \hat p_i = \frac{1}{\sqrt{2}}(b_i^\dagger - b_i),
+
+ where :math:`b^\dagger` and :math:`b` are bosonic creation and annihilation operators,
+ respectively.
+
+ The bosonic Hamiltonian is then converted to a qubit operator with a selected ``mapping``
+ method to obtain a linear combination as:
+
+ .. math::
+
+ H = \sum_{i} c_i P_i,
+
+ where :math:`P` is a tensor product of Pauli operators and :math:`c` is a constant.
Args:
pes (VibrationalPES): object containing the vibrational potential energy surface data
- max_deg (int): maximum degree of Taylor form polynomial
- min_deg (int): minimum degree of Taylor form polynomial
+ max_deg (int): maximum degree of the polynomial used to compute the coefficients
+ min_deg (int): minimum degree of the polynomial used to compute the coefficients
mapping (str): Method used to map to qubit basis. Input values can be ``"binary"``
or ``"unary"``. Default is ``"binary"``.
n_states(int): maximum number of allowed bosonic states
wire_map (dict): A dictionary defining how to map the states of the Bose operator to qubit
wires. If ``None``, integers used to label the bosonic states will be used as wire labels.
Defaults to ``None``.
- tol (float): tolerance for discarding the imaginary part of the coefficients
+ tol (float): tolerance for discarding the imaginary part of the coefficients during mapping
Returns:
Operator: the Taylor Hamiltonian
**Example**
- >>> pes_onemode = np.array([[0.309, 0.115, 0.038, 0.008, 0.000, 0.006, 0.020, 0.041, 0.070]])
- >>> pes_twomode = np.zeros((1, 1, 9, 9))
- >>> dipole_onemode = np.zeros((1, 9, 3))
- >>> gauss_weights = np.array([3.96e-05, 4.94e-03, 8.85e-02,
- ... 4.33e-01, 7.20e-01, 4.33e-01,
- ... 8.85e-02, 4.94e-03, 3.96e-05])
- >>> grid = np.array([-3.19, -2.27, -1.47, -0.72, 0.0, 0.72, 1.47, 2.27, 3.19])
- >>> pes_object = qml.qchem.VibrationalPES(
- ... freqs=np.array([0.025]),
- ... grid=grid,
- ... uloc=np.array([[1.0]]),
- ... gauss_weights=gauss_weights,
- ... pes_data=[pes_onemode, pes_twomode],
- ... dipole_data=[dipole_onemode],
- ... localized=True,
- ... dipole_level=1,
- ... )
- >>> qml.qchem.taylor_hamiltonian(pes_object, 4, 2)
- (
- -0.003833496032473659 * X(0)
- + (0.0256479442871582+0j) * I(0)
- + (-0.013079509779221888+0j) * Z(0)
- )
+ >>> freqs = np.array([0.0249722])
+ >>> pes_onemode = np.array([[0.08477, 0.01437, 0.00000, 0.00937, 0.03414]])
+ >>> pes_object = qml.qchem.VibrationalPES(freqs=freqs, pes_data=[pes_onemode], localized=False)
+ >>> ham = qml.qchem.taylor_hamiltonian(pes_object)
+ >>> print(ham)
+ 0.026123120450329353 * I(0) + -0.01325338030021957 * Z(0) + -0.0032539545260859464 * X(0)
"""
coeffs_arr = taylor_coeffs(pes, max_deg, min_deg)
bose_op = taylor_bosonic(coeffs_arr, pes.freqs, is_local=pes.localized, uloc=pes.uloc)
diff --git a/pennylane/qchem/vibrational/vibrational_class.py b/pennylane/qchem/vibrational/vibrational_class.py
index f12358c7e83..9f1e2c0c5ad 100644
--- a/pennylane/qchem/vibrational/vibrational_class.py
+++ b/pennylane/qchem/vibrational/vibrational_class.py
@@ -11,8 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-"""This module contains functions and classes to generate a pes object.
-This object stores all the necessary information to construct
+"""This module contains functions and classes to generate data needed to construct a
vibrational Hamiltonian for a given molecule."""
from dataclasses import dataclass
@@ -26,52 +25,84 @@
@dataclass
class VibrationalPES:
- r"""Data class to save potential energy surface information computed along vibrational normal modes.
+ r"""Data class to store information needed to construct a vibrational Hamiltonian for a molecule.
Args:
- freqs (list[float]): normal-mode frequencies in atomic units
- grid (list[float]): the sample points on the Gauss-Hermite quadrature grid
- gauss_weights (list[float]): the weights on the Gauss-Hermite quadrature grid
- uloc (TensorLike[float]): localization matrix indicating the relationship between original and localized modes
- pes_data (list[TensorLike[float]]): tuple containing one-mode, two-mode and three-mode PES
- dipole_data (list[TensorLike[float]]): tuple containing one-mode, two-mode and three-mode dipole
- localized (bool): Flag that localization of modes was used to generate PES and dipole. Default is ``True``.
- dipole_level (int): The level up to which dipole matrix elements are to be calculated. Input values can be
- 1, 2, or 3 for upto one-mode dipole, two-mode dipole and three-mode dipole, respectively. Default
- value is 1.
+ freqs (array[float]): normal-mode frequencies in atomic units
+ grid (array[float]): grid points to compute potential energy surface data.
+ Should be the sample points of the Gauss-Hermite quadrature.
+ gauss_weights (array[float]): weights associate with each point in ``grid``.
+ Should be the weights of the Gauss-Hermite quadrature.
+ uloc (TensorLike[float]): normal mode localization matrix with shape ``(m, m)`` where
+ ``m = len(freqs)``
+ pes_data (list[TensorLike[float]]): list of one-mode, two-mode and three-mode potential
+ energy surface data, with shapes ``(m, l)``, ``(m, m, l, l)`` ``(m, m, m, l, l, l)``,
+ respectively, where ``m = len(freqs)`` and ``l > 0``
+ dipole_data (list[TensorLike[float]]): list of one-mode, two-mode and three-mode dipole
+ moment data, with shapes ``(m, l, 3)``, ``(m, m, l, l, 3)`` ``(m, m, m, l, l, l, 3)``,
+ respectively, where ``m = len(freqs)`` and ``l > 0``
+ localized (bool): Whether the potential energy surface data correspond to localized normal
+ modes. Default is ``True``.
+ dipole_level (int): The level up to which dipole moment data are to be calculated. Input
+ values can be ``1``, ``2``, or ``3`` for up to one-mode dipole, two-mode dipole and
+ three-mode dipole, respectively. Default value is ``1``.
**Example**
+ This example shows how to construct the :class:`~.qchem.vibrational.VibrationalPES` object for a
+ linear diatomic molecule, e.g., :math:`H_2`, with only one vibrational normal mode. The one-mode
+ potential energy surface data is obtained by sampling ``9`` points along the normal mode, with
+ grid points and weights that correspond to a Gauss-Hermite quadrature.
+
>>> freqs = np.array([0.01885397])
>>> grid, weights = np.polynomial.hermite.hermgauss(9)
- >>> pes_onebody = [[0.05235573, 0.03093067, 0.01501878, 0.00420778, 0.0,
+ >>> pes_onemode = [[0.05235573, 0.03093067, 0.01501878, 0.00420778, 0.0,
... 0.00584504, 0.02881817, 0.08483433, 0.22025702]]
- >>> pes_twobody = None
- >>> dipole_onebody = [[[-1.92201700e-16, 1.45397041e-16, -1.40451549e-01],
- ... [-1.51005108e-16, 9.53185441e-17, -1.03377032e-01],
- ... [-1.22793018e-16, 7.22781963e-17, -6.92825934e-02],
- ... [-1.96537436e-16, -5.86686504e-19, -3.52245369e-02],
- ... [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
- ... [ 5.24758835e-17, -1.40650833e-16, 3.69955543e-02],
- ... [-4.52407941e-17, 1.38406311e-16, 7.60888733e-02],
- ... [-4.63820104e-16, 5.42928787e-17, 1.17726042e-01],
- ... [ 1.19224372e-16, 9.12491386e-17, 1.64013197e-01]]]
- >>> vib_obj = qml.qchem.VibrationalPES(freqs=freqs, grid=grid, gauss_weights=weights,
- ... uloc=None, pes_data=[pes_onebody, pes_twobody],
- ... dipole_data=[dipole_onebody], localized=False)
- >>> vib_obj.freqs
+ >>> vib_pes = qml.qchem.VibrationalPES(freqs=freqs, grid=grid,
+ ... gauss_weights=weights, pes_data=[pes_onemode])
+ >>> vib_pes.freqs
array([0.01885397])
+ The following example shows how to construct the :class:`~.qchem.vibrational.VibrationalPES`
+ object for a nonlinear triatomic molecule, e.g., :math:`H_3^+`, with three vibrational
+ normal modes. We assume that the potential energy surface and dipole data are obtained by
+ sampling ``5`` points along the normal mode, with grid points and weights that correspond to a
+ Gauss-Hermite quadrature.
+
+ >>> freqs = np.array([0.00978463, 0.00978489, 0.01663723])
+ >>> grid, weights = np.polynomial.hermite.hermgauss(5)
+ >>>
+ >>> uloc = np.array([[-0.99098585, 0.13396657, 0.],
+ ... [-0.13396657, -0.99098585, 0.],
+ ... [ 0. , 0. , 1.]])
+ >>>
+ >>> pes_onemode = np.random.rand(3, 5)
+ >>> pes_twomode = np.random.rand(3, 3, 5, 5)
+ >>> pes_threemode = np.random.rand(3, 3, 3, 5, 5, 5)
+ >>>
+ >>> dipole_onemode = np.random.rand(3, 5, 3)
+ >>> dipole_twomode = np.random.rand(3, 3, 5, 5, 3)
+ >>> dipole_threemode = np.random.rand(3, 3, 3, 5, 5, 5, 3)
+ >>>
+ >>> localized = True
+ >>> dipole_level = 3
+ >>>
+ >>> vib_obj = qml.qchem.VibrationalPES(freqs=freqs, grid=grid, gauss_weights=weights,
+ ... uloc=uloc, pes_data=[pes_onemode, pes_twomode, pes_threemode],
+ ... dipole_data=[dipole_onemode, dipole_twomode, dipole_threemode],
+ ... localized=True, dipole_level=3)
+ >>> print(vib_obj.dipole_threemode.shape)
+ (3, 3, 3, 5, 5, 5, 3)
"""
def __init__(
self,
- freqs,
- grid,
- gauss_weights,
- uloc,
- pes_data,
- dipole_data,
+ freqs=None,
+ grid=None,
+ gauss_weights=None,
+ uloc=None,
+ pes_data=None,
+ dipole_data=None,
localized=True,
dipole_level=1,
):
@@ -79,10 +110,10 @@ def __init__(
self.grid = grid
self.gauss_weights = gauss_weights
self.uloc = uloc
- self.pes_onemode = pes_data[0]
- self.pes_twomode = pes_data[1]
- self.pes_threemode = pes_data[2] if len(pes_data) > 2 else None
- self.dipole_onemode = dipole_data[0]
+ self.pes_onemode = pes_data[0] if pes_data else None
+ self.pes_twomode = pes_data[1] if pes_data and len(pes_data) > 1 else None
+ self.pes_threemode = pes_data[2] if pes_data and len(pes_data) > 2 else None
+ self.dipole_onemode = dipole_data[0] if dipole_data else None
self.dipole_twomode = dipole_data[1] if dipole_level >= 2 else None
self.dipole_threemode = dipole_data[2] if dipole_level >= 3 else None
self.localized = localized
@@ -165,9 +196,10 @@ def optimize_geometry(molecule, method="rhf"):
r"""Computes the equilibrium geometry of a molecule.
Args:
- molecule (:func:`~pennylane.qchem.molecule.Molecule`): Molecule object
- method (str): Electronic structure method that can be either restricted and unrestricted
- Hartree-Fock, ``'rhf'`` and ``'uhf'``, respectively. Default is ``'rhf'``.
+ molecule (~qchem.molecule.Molecule): the molecule object
+ method (str): Electronic structure method used to perform geometry optimization.
+ Available options are ``"rhf"`` and ``"uhf"`` for restricted and unrestricted
+ Hartree-Fock, respectively. Default is ``"rhf"``.
Returns:
array[array[float]]: optimized atomic positions in Cartesian coordinates
diff --git a/pennylane/qchem/vibrational/vscf.py b/pennylane/qchem/vibrational/vscf.py
index 95dedbceaba..5a5f07f8d4e 100644
--- a/pennylane/qchem/vibrational/vscf.py
+++ b/pennylane/qchem/vibrational/vscf.py
@@ -429,7 +429,7 @@ def vscf_integrals(h_integrals, d_integrals=None, modals=None, cutoff=None, cuto
The ``h_integral`` tensor must have one of these dimensions:
- - 1-mode coupled integrals: `(n, m)`
+ - 1-mode coupled integrals: `(n, m, m)`
- 2-mode coupled integrals: `(n, n, m, m, m, m)`
- 3-mode coupled integrals: `(n, n, n, m, m, m, m, m, m)`