Initialize :class:`OrcaEngrad` object from .engrad file

        Searches indicated file for energy, geometry, gradient, and number
        of atoms and stores in the corresponding instance variables.


        Parameters
        ----------
        path
            |str| -- Complete path to the .engrad file to be read.

        Raises
        ------
        ~opan.error.GradError

            Typecode :attr:`~opan.error.GradError.OVERWRITE` --
            If :class:`~orca.grad.OrcaEngrad` instance has already
            been instantiated.

            Various typecodes --
            If indicated gradient file is malformed in some fashion

        ~exceptions.IOError
            If the indicated file does not exist or cannot be read

def _load(self, **kwargs):
        """ Initialize :class:`OrcaEngrad` object from .engrad file

        Searches indicated file for energy, geometry, gradient, and number
        of atoms and stores in the corresponding instance variables.


        Parameters
        ----------
        path
            |str| -- Complete path to the .engrad file to be read.

        Raises
        ------
        ~opan.error.GradError

            Typecode :attr:`~opan.error.GradError.OVERWRITE` --
            If :class:`~orca.grad.OrcaEngrad` instance has already
            been instantiated.

            Various typecodes --
            If indicated gradient file is malformed in some fashion

        ~exceptions.IOError
            If the indicated file does not exist or cannot be read

        """

        # Imports
        from .const import CIC, atom_sym, atom_num
        from .error import GradError
        from .utils import safe_cast as scast
        import numpy as np

        # Check if instantiated; complain if so
        if 'engrad_path' in dir(self):
            raise GradError(GradError.OVERWRITE,
                    "Cannot overwrite contents of existing OrcaEngrad", "")
        ## end if

        # Retrieve the file target
        engrad_path = kwargs['path']

        # Open file, read contents, close stream
        with open(engrad_path,'rU') as in_fl:
            self.engrad_path = engrad_path
            self.in_str = in_fl.read()
        ## end with

        # Store source string
        srcstr = "ENGRAD File: {0}".format(engrad_path)

        # Check to ensure all relevant data blocks are found
        if not self.Pat.numats.search(self.in_str):
            raise GradError(GradError.NUMATS,
                    "Number of atoms specification not found", srcstr)
        ## end if
        if not self.Pat.energy.search(self.in_str):
            raise GradError(GradError.ENERGY,
                    "Energy specification not found", srcstr)
        ## end if
        if not self.Pat.gradblock.search(self.in_str):
            raise GradError(GradError.GRADBLOCK,
                    "Gradient data block not found", srcstr)
        ## end if
        if not self.Pat.atblock.search(self.in_str):
            raise GradError(GradError.GEOMBLOCK,
                    "Geometry data block not found", srcstr)
        ## end if

        # Retrieve the number of atoms
        self.num_ats = np.int_(self.Pat.numats.search(self.in_str).group("num"))

        # Retrieve the energy
        self.energy = np.float_(self.Pat.energy.search(self.in_str).group("en"))

        # Retrieve the gradient and store numerically. Raise an error if
        #  the number of gradient elements is not equal to three times the
        #  number of atoms.
        grad_str = self.Pat.gradblock.search(self.in_str).group("block")
        if not len(grad_str.splitlines()) == 3 * self.num_ats:
            raise GradError(GradError.GRADBLOCK,
                    "Gradient block size mismatch with number of atoms",
                    srcstr)
        ## end if
        self.gradient = np.array(grad_str.splitlines(), dtype=np.float_)

        # Pull and store the geometry block
        geom_str = self.Pat.atblock.search(self.in_str).group("block")

        # Confirm the correct number of atoms
        if not len(self.Pat.atline.findall(geom_str)) ==  self.num_ats:
            raise GradError(GradError.GEOMBLOCK,
                    "Inconsistent number of atom coordinates in \
                    geometry block", srcstr)
        ## end if

        # Initialize the atom symbols list
        self.atom_syms = []

        # Assemble the coordinates vector and assemble/check the element
        #  ID vector.
        # Init the atom counter and the coordinates vector
        atom_count = 0
        self.geom = np.zeros((0,), dtype=np.float_)

        # Iterate over the atom spec lines and store element and coordinates
        for line_mch in self.Pat.atline.finditer(geom_str):
            # Populate the atom symbols list; have to check for
            #  whether it's an atomic number or an element symbol
            if str.isdigit(line_mch.group("at")):
                # Atomic number
                # Check for valid number
                at_num = scast(line_mch.group("at"), np.int_)
                if not (CIC.MIN_ATOMIC_NUM <= at_num <= CIC.MAX_ATOMIC_NUM):
                    raise GradError(GradError.GEOMBLOCK,
                            "Atom #{0} is an unsupported element"
                            .format(atom_count), srcstr)
                ##end if

                # Tag on the new symbol
                self.atom_syms.append(atom_sym[at_num])

            else:
                # Element symbol; store as all caps
                # Check for valid element, first by catching if the
                #  specified element string is even valid
                try:
                    at_num = atom_num[line_mch.group("at").upper()]
                except KeyError:
                    raise GradError(GradError.GEOMBLOCK,
                            "Atom #{0} is an unrecognized element"
                            .format(atom_count), srcstr)
                ## end try

                # Tag on the new symbol
                self.atom_syms.append(line_mch.group("at").upper())
            ## end if

            # Append the three coordinates of the current atom to the
            #  temp coordinates vector. Unit conversion not needed since
            #  ENGRAD files report coordinates in Bohrs.
            self.geom = np.concatenate(
                    (
                        self.geom,
                        [scast(line_mch.group("c{0}".format(i)), np.float_)
                                                        for i in range(1,4)]
                     ))