Source code for chemcoord.internal_coordinates.zmat_functions

# -*- coding: utf-8 -*-
import numpy as np
import sympy

from chemcoord import export
from chemcoord.internal_coordinates.zmat_class_main import Zmat


[docs]@export class DummyManipulation(object): """Contextmanager that controls the behaviour of :meth:`~chemcoord.Zmat.safe_loc` and :meth:`~chemcoord.Zmat.safe_iloc`. In the following examples it is assumed, that using the assignment with :meth:`~chemcoord.Zmat.safe_loc` would lead to an invalid reference. Then there are two possible usecases:: with DummyManipulation(zmat, True): zmat.safe_loc[...] = ... # This inserts required dummy atoms and removes them, # if they are not needed anymore. # Removes only dummy atoms, that were automatically inserted. with DummyManipulation(zmat, False): zmat.safe_loc[...] = ... # This raises an exception # :class:`~chemcoord.exceptions.InvalidReference`. # which can be handled appropiately. # The zmat instance is unmodified, if an exception was raised. """ def __init__(self, dummy_manipulation_allowed, cls=None): if cls is None: cls = Zmat self.cls = cls self.dummy_manipulation_allowed = dummy_manipulation_allowed self.old_value = self.cls.dummy_manipulation_allowed def __enter__(self): self.cls.dummy_manipulation_allowed = self.dummy_manipulation_allowed def __exit__(self, exc_type, exc_value, traceback): self.cls.dummy_manipulation_allowed = self.old_value
[docs]@export class TestOperators(object): """Switch the validity testing of zmatrices resulting from operators. The following examples is done with ``+`` it is assumed, that adding ``zmat_1`` and ``zmat_2`` leads to a zmatrix with an invalid reference:: with TestOperators(True): zmat_1 + zmat_2 # Raises InvalidReference Exception """ def __init__(self, test_operators, cls=None): if cls is None: cls = Zmat self.cls = cls self.test_operators = test_operators self.old_value = self.cls.test_operators def __enter__(self): self.cls.test_operators = self.test_operators def __exit__(self, exc_type, exc_value, traceback): self.cls.test_operators = self.old_value
[docs]@export class PureInternalMovement(object): """Remove the translational and rotational degrees of freedom. When doing assignments to the z-matrix:: with PureInternalMovement(True): zmat_1.loc[1, 'bond'] = value the translational and rotational degrees of freedom are automatically projected oout. For infinitesimal movements this would be done with the Eckhard conditions, but in this case we allow large non-infinitesimal movements. For the details read [6]_. """ def __init__(self, pure_internal_mov, cls=None): if cls is None: cls = Zmat self.cls = cls self.pure_internal_mov = pure_internal_mov self.old_value = self.cls.pure_internal_mov def __enter__(self): self.cls.pure_internal_mov = self.pure_internal_mov def __exit__(self, exc_type, exc_value, traceback): self.cls.pure_internal_mov = self.old_value
[docs]def apply_grad_cartesian_tensor(grad_X, zmat_dist): """Apply the gradient for transformation to cartesian space onto zmat_dist. Args: grad_X (:class:`numpy.ndarray`): A ``(3, n, n, 3)`` array. The mathematical details of the index layout is explained in :meth:`~chemcoord.Cartesian.get_grad_zmat()`. zmat_dist (:class:`~chemcoord.Zmat`): Distortions in Zmatrix space. Returns: :class:`~chemcoord.Cartesian`: Distortions in cartesian space. """ columns = ['bond', 'angle', 'dihedral'] C_dist = zmat_dist.loc[:, columns].values.T try: C_dist = C_dist.astype('f8') C_dist[[1, 2], :] = np.radians(C_dist[[1, 2], :]) except (TypeError, AttributeError): C_dist[[1, 2], :] = sympy.rad(C_dist[[1, 2], :]) cart_dist = np.tensordot(grad_X, C_dist, axes=([3, 2], [0, 1])).T from chemcoord.cartesian_coordinates.cartesian_class_main import Cartesian return Cartesian(atoms=zmat_dist['atom'], coords=cart_dist, index=zmat_dist.index)