Distance between two atoms.

        Parameters
        ----------
        g_num
            |int| -- Index of the desired geometry

        at_1
            |int| -- Index of the first atom

        at_2
            |int| -- Index of the second atom

        Returns
        -------
        dist
            |npfloat_| --
            Distance in Bohrs between `at_1` and `at_2` from
            geometry `g_num`

        Raises
        ------
        ~exceptions.IndexError
            If an invalid (out-of-range) `g_num` or `at_#` is provided

def dist_single(self, g_num, at_1, at_2):
        """ Distance between two atoms.

        Parameters
        ----------
        g_num
            |int| -- Index of the desired geometry

        at_1
            |int| -- Index of the first atom

        at_2
            |int| -- Index of the second atom

        Returns
        -------
        dist
            |npfloat_| --
            Distance in Bohrs between `at_1` and `at_2` from
            geometry `g_num`

        Raises
        ------
        ~exceptions.IndexError
            If an invalid (out-of-range) `g_num` or `at_#` is provided

        """

        # Import used math library function(s)
        import numpy as np
        from scipy import linalg as spla
        from .utils import safe_cast as scast

        # The below errors are explicitly thrown since values are multiplied by
        #  three when they are used as an index and thus give non-intuitive
        #  errors in subsequent code.
        # Complain if at_1 is invalid
        if not (-self.num_atoms <= at_1 < self.num_atoms):
            raise IndexError("Invalid index for 'at_1' ({0})".format(at_1))

        # Complain if at_2 is invalid
        if not (-self.num_atoms <= at_2 < self.num_atoms):
            raise IndexError("Invalid index for 'at_2' ({0})".format(at_2))

        # Should never be necessary (save for badly erroneous calling code),
        #  but coerce at_1 and at_2 to their floor() values.  This is again
        #  needed since they are multiplied by three in the index expresssions
        #  below, and can cause funny behavior when truncated by the indexing
        at_1 = scast(np.floor(at_1), np.int_)
        at_2 = scast(np.floor(at_2), np.int_)

        # Calculate the interatomic distance and return. Return identically
        #  zero if the indices are equal
        if at_1 == at_2:
            dist = 0.0
        else:
            dist = scast(
                    spla.norm(self.displ_single(g_num, at_1, at_2)),
                            np.float_)
        ## end if

        return dist