def uvc_tangent_modulus(x_sol, data, tol=1e-08, maximum_iterations=1000):
    ' Returns the tangent modulus at each strain step.\n\n    :param np.array x_sol: Updated Voce-Chaboche model parameters.\n    :param pd.DataFrame data: stress-strain data.\n    :param float tol: Local Newton tolerance.\n    :param int maximum_iterations: maximum iterations in local Newton procedure, raises RuntimeError if exceeded.\n    :return np.ndarray: Tangent modulus array.\n    '
    if (len(x_sol) < 8):
        raise RuntimeError('No backstresses or using original V-C params.')
    n_param_per_back = 2
    n_basic_param = 6
    E = (x_sol[0] * 1.0)
    sy_0 = (x_sol[1] * 1.0)
    Q = (x_sol[2] * 1.0)
    b = (x_sol[3] * 1.0)
    D = (x_sol[4] * 1.0)
    a = (x_sol[5] * 1.0)
    n_backstresses = int(((len(x_sol) - n_basic_param) / n_param_per_back))
    c_k = []
    gamma_k = []
    for i in range(0, n_backstresses):
        c_k.append(x_sol[(n_basic_param + (n_param_per_back * i))])
        gamma_k.append(x_sol[((n_basic_param + 1) + (n_param_per_back * i))])
    alpha_components = np.zeros(n_backstresses, dtype=object)
    strain = 0.0
    stress = 0.0
    ep_eq = 0.0
    stress_track = []
    strain_track = []
    strain_inc_track = []
    iteration_track = []
    tangent_track = []
    loading = np.diff(data['e_true'])
    for (increment_number, strain_inc) in enumerate(loading):
        strain += strain_inc
        alpha = np.sum(alpha_components)
        yield_stress = ((sy_0 + (Q * (1.0 - np.exp(((- b) * ep_eq))))) - (D * (1.0 - np.exp(((- a) * ep_eq)))))
        trial_stress = (stress + (E * strain_inc))
        relative_stress = (trial_stress - alpha)
        flow_dir = np.sign(relative_stress)
        yield_condition = (np.abs(relative_stress) - yield_stress)
        if (yield_condition > tol):
            is_converged = False
        else:
            is_converged = True
        ep_eq_init = ep_eq
        alpha_init = alpha
        consist_param = 0.0
        number_of_iterations = 0
        while ((is_converged is False) and (number_of_iterations < maximum_iterations)):
            number_of_iterations += 1
            yield_stress = ((sy_0 + (Q * (1.0 - np.exp(((- b) * ep_eq))))) - (D * (1.0 - np.exp(((- a) * ep_eq)))))
            iso_modulus = (((Q * b) * np.exp(((- b) * ep_eq))) - ((D * a) * np.exp(((- a) * ep_eq))))
            alpha = 0.0
            kin_modulus = 0.0
            for i in range(0, n_backstresses):
                e_k = np.exp(((- gamma_k[i]) * (ep_eq - ep_eq_init)))
                alpha += (((flow_dir * c_k[i]) / gamma_k[i]) + ((alpha_components[i] - ((flow_dir * c_k[i]) / gamma_k[i])) * e_k))
                kin_modulus += ((c_k[i] * e_k) - (((flow_dir * gamma_k[i]) * e_k) * alpha_components[i]))
            delta_alpha = (alpha - alpha_init)
            numerator = (np.abs(relative_stress) - (((consist_param * E) + yield_stress) + (flow_dir * delta_alpha)))
            denominator = (- ((E + iso_modulus) + kin_modulus))
            consist_param = (consist_param - (numerator / denominator))
            ep_eq = (ep_eq_init + consist_param)
            if (np.abs(numerator) < tol):
                is_converged = True
        stress = (trial_stress - ((E * flow_dir) * consist_param))
        for i in range(0, n_backstresses):
            e_k = np.exp(((- gamma_k[i]) * (ep_eq - ep_eq_init)))
            alpha_components[i] = (((flow_dir * c_k[i]) / gamma_k[i]) + ((alpha_components[i] - ((flow_dir * c_k[i]) / gamma_k[i])) * e_k))
        stress_track.append(stress)
        strain_track.append(strain)
        strain_inc_track.append(strain_inc)
        iteration_track.append(number_of_iterations)
        if (number_of_iterations > 0):
            h_prime = 0.0
            for i in range(0, n_backstresses):
                h_prime += (c_k[i] - ((flow_dir * gamma_k[i]) * alpha_components[i]))
            k_prime = (((Q * b) * np.exp(((- b) * ep_eq))) - ((D * a) * np.exp(((- a) * ep_eq))))
            tangent_track.append(((E * (k_prime + h_prime)) / ((E + k_prime) + h_prime)))
        else:
            tangent_track.append(E)
    return np.append([0.0], np.array(tangent_track))
Returns the tangent modulus at each strain step.

:param np.array x_sol: Updated Voce-Chaboche model parameters.
:param pd.DataFrame data: stress-strain data.
:param float tol: Local Newton tolerance.
:param int maximum_iterations: maximum iterations in local Newton procedure, raises RuntimeError if exceeded.
:return np.ndarray: Tangent modulus array.
def uvc_tangent_modulus(x_sol, data, tol=1e-08, maximum_iterations=1000):
    ' Returns the tangent modulus at each strain step.\n\n    :param np.array x_sol: Updated Voce-Chaboche model parameters.\n    :param pd.DataFrame data: stress-strain data.\n    :param float tol: Local Newton tolerance.\n    :param int maximum_iterations: maximum iterations in local Newton procedure, raises RuntimeError if exceeded.\n    :return np.ndarray: Tangent modulus array.\n    '
    if (len(x_sol) < 8):
        raise RuntimeError('No backstresses or using original V-C params.')
    n_param_per_back = 2
    n_basic_param = 6
    E = (x_sol[0] * 1.0)
    sy_0 = (x_sol[1] * 1.0)
    Q = (x_sol[2] * 1.0)
    b = (x_sol[3] * 1.0)
    D = (x_sol[4] * 1.0)
    a = (x_sol[5] * 1.0)
    n_backstresses = int(((len(x_sol) - n_basic_param) / n_param_per_back))
    c_k = []
    gamma_k = []
    for i in range(0, n_backstresses):
        c_k.append(x_sol[(n_basic_param + (n_param_per_back * i))])
        gamma_k.append(x_sol[((n_basic_param + 1) + (n_param_per_back * i))])
    alpha_components = np.zeros(n_backstresses, dtype=object)
    strain = 0.0
    stress = 0.0
    ep_eq = 0.0
    stress_track = []
    strain_track = []
    strain_inc_track = []
    iteration_track = []
    tangent_track = []
    loading = np.diff(data['e_true'])
    for (increment_number, strain_inc) in enumerate(loading):
        strain += strain_inc
        alpha = np.sum(alpha_components)
        yield_stress = ((sy_0 + (Q * (1.0 - np.exp(((- b) * ep_eq))))) - (D * (1.0 - np.exp(((- a) * ep_eq)))))
        trial_stress = (stress + (E * strain_inc))
        relative_stress = (trial_stress - alpha)
        flow_dir = np.sign(relative_stress)
        yield_condition = (np.abs(relative_stress) - yield_stress)
        if (yield_condition > tol):
            is_converged = False
        else:
            is_converged = True
        ep_eq_init = ep_eq
        alpha_init = alpha
        consist_param = 0.0
        number_of_iterations = 0
        while ((is_converged is False) and (number_of_iterations < maximum_iterations)):
            number_of_iterations += 1
            yield_stress = ((sy_0 + (Q * (1.0 - np.exp(((- b) * ep_eq))))) - (D * (1.0 - np.exp(((- a) * ep_eq)))))
            iso_modulus = (((Q * b) * np.exp(((- b) * ep_eq))) - ((D * a) * np.exp(((- a) * ep_eq))))
            alpha = 0.0
            kin_modulus = 0.0
            for i in range(0, n_backstresses):
                e_k = np.exp(((- gamma_k[i]) * (ep_eq - ep_eq_init)))
                alpha += (((flow_dir * c_k[i]) / gamma_k[i]) + ((alpha_components[i] - ((flow_dir * c_k[i]) / gamma_k[i])) * e_k))
                kin_modulus += ((c_k[i] * e_k) - (((flow_dir * gamma_k[i]) * e_k) * alpha_components[i]))
            delta_alpha = (alpha - alpha_init)
            numerator = (np.abs(relative_stress) - (((consist_param * E) + yield_stress) + (flow_dir * delta_alpha)))
            denominator = (- ((E + iso_modulus) + kin_modulus))
            consist_param = (consist_param - (numerator / denominator))
            ep_eq = (ep_eq_init + consist_param)
            if (np.abs(numerator) < tol):
                is_converged = True
        stress = (trial_stress - ((E * flow_dir) * consist_param))
        for i in range(0, n_backstresses):
            e_k = np.exp(((- gamma_k[i]) * (ep_eq - ep_eq_init)))
            alpha_components[i] = (((flow_dir * c_k[i]) / gamma_k[i]) + ((alpha_components[i] - ((flow_dir * c_k[i]) / gamma_k[i])) * e_k))
        stress_track.append(stress)
        strain_track.append(strain)
        strain_inc_track.append(strain_inc)
        iteration_track.append(number_of_iterations)
        if (number_of_iterations > 0):
            h_prime = 0.0
            for i in range(0, n_backstresses):
                h_prime += (c_k[i] - ((flow_dir * gamma_k[i]) * alpha_components[i]))
            k_prime = (((Q * b) * np.exp(((- b) * ep_eq))) - ((D * a) * np.exp(((- a) * ep_eq))))
            tangent_track.append(((E * (k_prime + h_prime)) / ((E + k_prime) + h_prime)))
        else:
            tangent_track.append(E)
    return np.append([0.0], np.array(tangent_track))