Similar to get_fermi except that when get_fermi fails to converge,
        an interpolated or extrapolated fermi (depending on c) is returned with
        the assumption that the fermi level changes linearly with log(abs(c)).

        Args:
            c (float): doping concentration in 1/cm3. c<0 represents n-type
                doping and c>0 p-type doping (i.e. majority carriers are holes)
            T (float): absolute temperature in Kelvin
            warn (bool): whether to warn for the first time when no fermi can
                be found.
            c_ref (float): a doping concentration where get_fermi returns a
                value without error for both c_ref and -c_ref
            **kwargs: see keyword arguments of the get_fermi function

        Returns (float): the fermi level that is possibly interapolated or
            extrapolated and must be used with caution.

def get_fermi_interextrapolated(self, c, T, warn=True, c_ref=1e10, **kwargs):
        """
        Similar to get_fermi except that when get_fermi fails to converge,
        an interpolated or extrapolated fermi (depending on c) is returned with
        the assumption that the fermi level changes linearly with log(abs(c)).

        Args:
            c (float): doping concentration in 1/cm3. c<0 represents n-type
                doping and c>0 p-type doping (i.e. majority carriers are holes)
            T (float): absolute temperature in Kelvin
            warn (bool): whether to warn for the first time when no fermi can
                be found.
            c_ref (float): a doping concentration where get_fermi returns a
                value without error for both c_ref and -c_ref
            **kwargs: see keyword arguments of the get_fermi function

        Returns (float): the fermi level that is possibly interapolated or
            extrapolated and must be used with caution.
        """
        try:
            return self.get_fermi(c, T, **kwargs)
        except ValueError as e:
            if warn:
                warnings.warn(str(e))
            if abs(c) < c_ref:
                if abs(c) < 1e-10:
                    c = 1e-10
                # max(10, ) is to avoid log(0<x<1) and log(1+x) both of which are slow
                f2 = self.get_fermi_interextrapolated(max(10, abs(c) * 10.), T, warn=False, **kwargs)
                f1 = self.get_fermi_interextrapolated(-max(10, abs(c) * 10.), T, warn=False, **kwargs)
                c2 = np.log(abs(1 + self.get_doping(f2, T)))
                c1 = -np.log(abs(1 + self.get_doping(f1, T)))
                slope = (f2 - f1) / (c2 - c1)
                return f2 + slope * (np.sign(c) * np.log(abs(1 + c)) - c2)
            else:
                f_ref = self.get_fermi_interextrapolated(np.sign(c) * c_ref, T, warn=False, **kwargs)
                f_new = self.get_fermi_interextrapolated(c / 10., T, warn=False, **kwargs)
                clog = np.sign(c) * np.log(abs(c))
                c_newlog = np.sign(c) * np.log(abs(self.get_doping(f_new, T)))
                slope = (f_new - f_ref) / (c_newlog - np.sign(c) * 10.)
                return f_new + slope * (clog - c_newlog)