Provides the decomposition and energy above convex hull for an entry.
        Due to caching, can be much faster if entries with the same composition
        are processed together.

        Args:
            entry: A PDEntry like object
            allow_negative: Whether to allow negative e_above_hulls. Used to
                calculate equilibrium reaction energies. Defaults to False.

        Returns:
            (decomp, energy above convex hull)  Stable entries should have
            energy above hull of 0. The decomposition is provided as a dict of
            {Entry: amount}.

def get_decomp_and_e_above_hull(self, entry, allow_negative=False):
        """
        Provides the decomposition and energy above convex hull for an entry.
        Due to caching, can be much faster if entries with the same composition
        are processed together.

        Args:
            entry: A PDEntry like object
            allow_negative: Whether to allow negative e_above_hulls. Used to
                calculate equilibrium reaction energies. Defaults to False.

        Returns:
            (decomp, energy above convex hull)  Stable entries should have
            energy above hull of 0. The decomposition is provided as a dict of
            {Entry: amount}.
        """
        if entry in self.stable_entries:
            return {entry: 1}, 0

        comp = entry.composition
        facet, simplex = self._get_facet_and_simplex(comp)
        decomp_amts = simplex.bary_coords(self.pd_coords(comp))
        decomp = {self.qhull_entries[f]: amt
                  for f, amt in zip(facet, decomp_amts)
                  if abs(amt) > PhaseDiagram.numerical_tol}
        energies = [self.qhull_entries[i].energy_per_atom for i in facet]
        ehull = entry.energy_per_atom - np.dot(decomp_amts, energies)
        if allow_negative or ehull >= -PhaseDiagram.numerical_tol:
            return decomp, ehull
        raise ValueError("No valid decomp found!")