def uvc_return_mapping(x_sol, data, tol=1e-08, maximum_iterations=1000):
    " Implements the time integration of the updated Voce-Chaboche material model.\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 dict: History of: stress ('stress'), strain ('strain'), the total error ('error') calculated by the\n        updated Voce-Chaboche model, number of iterations for convergence at each increment ('num_its').\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
    error = 0.0
    sum_abs_de = 0.0
    stress_sim = 0.0
    stress_test = 0.0
    area_test = 0.0
    stress_track = []
    strain_track = []
    strain_inc_track = []
    iteration_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
        stress_sim_1 = (stress_sim * 1.0)
        stress_test_1 = (stress_test * 1.0)
        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)
        stress_sim = (stress * 1.0)
        stress_test = data['Sigma_true'].iloc[(increment_number + 1)]
        sum_abs_de += np.abs(strain_inc)
        area_test += ((np.abs(strain_inc) * ((stress_test ** 2) + (stress_test_1 ** 2))) / 2.0)
        error += ((np.abs(strain_inc) * (((stress_sim - stress_test) ** 2) + ((stress_sim_1 - stress_test_1) ** 2))) / 2.0)
        if (number_of_iterations >= maximum_iterations):
            print('Increment number = ', increment_number)
            print('Parameters = ', x_sol)
            print('Numerator = ', numerator)
            raise RuntimeError((('Return mapping did not converge in ' + str(maximum_iterations)) + ' iterations.'))
    area = (area_test / sum_abs_de)
    error = (error / sum_abs_de)
    return {'stress': stress_track, 'strain': strain_track, 'error': error, 'num_its': iteration_track, 'area': area}
Implements the time integration of the updated Voce-Chaboche material model.

: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 dict: History of: stress ('stress'), strain ('strain'), the total error ('error') calculated by the
    updated Voce-Chaboche model, number of iterations for convergence at each increment ('num_its').
def uvc_return_mapping(x_sol, data, tol=1e-08, maximum_iterations=1000):
    " Implements the time integration of the updated Voce-Chaboche material model.\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 dict: History of: stress ('stress'), strain ('strain'), the total error ('error') calculated by the\n        updated Voce-Chaboche model, number of iterations for convergence at each increment ('num_its').\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
    error = 0.0
    sum_abs_de = 0.0
    stress_sim = 0.0
    stress_test = 0.0
    area_test = 0.0
    stress_track = []
    strain_track = []
    strain_inc_track = []
    iteration_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
        stress_sim_1 = (stress_sim * 1.0)
        stress_test_1 = (stress_test * 1.0)
        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)
        stress_sim = (stress * 1.0)
        stress_test = data['Sigma_true'].iloc[(increment_number + 1)]
        sum_abs_de += np.abs(strain_inc)
        area_test += ((np.abs(strain_inc) * ((stress_test ** 2) + (stress_test_1 ** 2))) / 2.0)
        error += ((np.abs(strain_inc) * (((stress_sim - stress_test) ** 2) + ((stress_sim_1 - stress_test_1) ** 2))) / 2.0)
        if (number_of_iterations >= maximum_iterations):
            print('Increment number = ', increment_number)
            print('Parameters = ', x_sol)
            print('Numerator = ', numerator)
            raise RuntimeError((('Return mapping did not converge in ' + str(maximum_iterations)) + ' iterations.'))
    area = (area_test / sum_abs_de)
    error = (error / sum_abs_de)
    return {'stress': stress_track, 'strain': strain_track, 'error': error, 'num_its': iteration_track, 'area': area}