From 408a546c4e745dc9f741e642aba06cfd389cef79 Mon Sep 17 00:00:00 2001 From: Shadi Alameddin Date: Fri, 23 Sep 2022 14:39:21 +0200 Subject: [PATCH 01/30] add initial support for plastic models --- eg2_compare_approximations.py | 31 ++++++++++++--------- eg3_hierarchical_sampling.py | 17 ++++++++---- eg4_hierarchical_sampling_efficient.py | 32 +++++++++++++++------- interpolate_fluctuation_modes.py | 15 ++++++---- tests/test_approximations.py | 31 ++++++++++++--------- utilities.py | 38 ++++++++++++++++++-------- 6 files changed, 104 insertions(+), 60 deletions(-) diff --git a/eg2_compare_approximations.py b/eg2_compare_approximations.py index 0e2597c..3600a5a 100644 --- a/eg2_compare_approximations.py +++ b/eg2_compare_approximations.py @@ -30,7 +30,7 @@ _, samples = read_h5(file_name, data_path, [temp1, temp2], get_mesh=False) -strains = np.random.normal(size=(n_loading_directions, mesh['strain_dof'])) +strains = np.random.normal(size=(n_loading_directions, strain_dof)) strains /= la.norm(strains, axis=1)[:, None] n_approaches = 5 @@ -54,38 +54,43 @@ Eref = ref[idx]['strain_localization'] ref_C = ref[idx]['mat_stiffness'] ref_eps = ref[idx]['mat_thermal_strain'] + plastic_modes = ref[idx]['plastic_modes'] normalization_factor_mech = ref[idx]['normalization_factor_mech'] - Sref = construct_stress_localization(Eref, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Sref = construct_stress_localization(Eref, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSref = volume_average(Sref) # interpolated quantities using an explicit interpolation scheme with one DOF approx_C, approx_eps = naive(alpha, sampling_C, sampling_eps, ref_C, ref_eps) Enaive = interpolate_temp(E0, E1) - Snaive = construct_stress_localization(Enaive, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Snaive = construct_stress_localization(Enaive, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSnaive = volume_average(Snaive) # interpolated quantities using an explicit interpolation scheme with one DOF - Eopt0, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, mat_id, n_gauss, strain_dof, n_modes, n_gp) - Sopt0 = construct_stress_localization(Eopt0, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Eopt0, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt0 = construct_stress_localization(Eopt0, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSopt0 = volume_average(Sopt0) # interpolated quantities using an implicit interpolation scheme with one DOF approx_C, approx_eps = opt1(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt1, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, mat_id, n_gauss, strain_dof, n_modes, n_gp) - Sopt1 = construct_stress_localization(Eopt1, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Eopt1, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt1 = construct_stress_localization(Eopt1, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSopt1 = volume_average(Sopt1) # interpolated quantities using an implicit interpolation scheme with two DOF approx_C, approx_eps = opt2(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt2, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, mat_id, n_gauss, strain_dof, n_modes, n_gp) - Sopt2 = construct_stress_localization(Eopt2, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Eopt2, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt2 = construct_stress_localization(Eopt2, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSopt2 = volume_average(Sopt2) # interpolated quantities using an implicit interpolation scheme with four DOF approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, mat_id, n_gauss, strain_dof, n_modes, n_gp) - Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSopt4 = volume_average(Sopt4) err = lambda x, y: np.mean(la.norm(x - y, axis=(-1, -2)) / la.norm(y, axis=(-1, -2))) * 100 @@ -97,7 +102,7 @@ err(effSopt2, effSref), err(effSopt4, effSref)] for strain_idx, strain in enumerate(strains): - zeta = np.hstack((strain, 1)) + zeta = np.hstack((strain, 1, np.ones(plastic_modes.shape[-1]))) eff_stress_ref = effSref @ zeta err_eff_stress[:, idx * n_loading_directions + strain_idx] = \ @@ -112,7 +117,7 @@ stress_opt4 = np.einsum('ijk,k', Sopt4, zeta, optimize='optimal') residuals = compute_residual_efficient([stress_naive, stress_opt0, stress_opt1, stress_opt2, stress_opt4], - mesh['global_gradient']) + global_gradient) err_f[:, idx * n_loading_directions + strain_idx] = la.norm(residuals, np.inf, axis=0) / normalization_factor_mech * 100 diff --git a/eg3_hierarchical_sampling.py b/eg3_hierarchical_sampling.py index f4fa926..1020857 100644 --- a/eg3_hierarchical_sampling.py +++ b/eg3_hierarchical_sampling.py @@ -60,22 +60,27 @@ sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) # reference values + Eref = ref[idx]['strain_localization'] ref_C = ref[idx]['mat_stiffness'] ref_eps = ref[idx]['mat_thermal_strain'] + plastic_modes = ref[idx]['plastic_modes'] normalization_factor_mech = ref[idx]['normalization_factor_mech'] - effSref = np.vstack((ref[idx]['eff_stiffness'], -ref[idx]['eff_stiffness'] @ ref[idx]['eff_thermal_strain'])).T + Sref = construct_stress_localization(Eref, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + effSref = volume_average(Sref) + # effSref = np.vstack((ref[idx]['eff_stiffness'], -ref[idx]['eff_stiffness'] @ ref[idx]['eff_thermal_strain'])).T # interpolated quantities using an implicit interpolation scheme with four DOF approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, mat_id, n_gauss, strain_dof, n_modes, n_gp) - Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSopt = volume_average(Sopt4) err_indicators[level, idx] = np.mean(np.max(np.abs(compute_err_indicator_efficient(Sopt4, global_gradient)), axis=0)) / normalization_factor_mech * 100 for strain_idx, strain in enumerate(strains): - zeta = np.hstack((strain, 1)) + zeta = np.hstack((strain, 1, np.ones(plastic_modes.shape[-1]))) stress_opt4 = np.einsum('ijk,k', Sopt4, zeta, optimize='optimal') residual = compute_residual_efficient(stress_opt4, global_gradient) @@ -89,11 +94,11 @@ invL = la.inv(la.cholesky(Cref)) err_eff_C[level, idx] = la.norm(invL @ Capprox @ invL.T - np.eye(6)) / la.norm(np.eye(6)) * 100 - err_eff_eps[level, idx] = err(la.solve(Capprox, effSopt[:, -1]), la.solve(Cref, effSref[:, -1])) + err_eff_eps[level, idx] = err(la.solve(Capprox, effSopt[:, 7]), la.solve(Cref, effSref[:, 7])) # max_err_idx = np.argmax(np.mean(err_nodal_force[level], axis=1)) max_err_idx = np.argmax(err_indicators[level]) - alpha_levels.append(np.sort(np.hstack((alphas, test_alphas[max_err_idx])))) + alpha_levels.append(np.unique(np.sort(np.hstack((alphas, test_alphas[max_err_idx]))))) print(f'{np.max(np.mean(err_nodal_force[level], axis=1)) = }') print(f'{np.max(err_indicators[level]) = }') diff --git a/eg4_hierarchical_sampling_efficient.py b/eg4_hierarchical_sampling_efficient.py index 90c14e9..f31e2c2 100644 --- a/eg4_hierarchical_sampling_efficient.py +++ b/eg4_hierarchical_sampling_efficient.py @@ -6,8 +6,8 @@ from interpolate_fluctuation_modes import update_affine_decomposition, effective_S, effective_stress_localization, \ interpolate_fluctuation_modes, get_phi, transform_strain_localization from microstructures import * -from optimize_alpha import opt4_alphas -from utilities import read_h5, construct_stress_localization, compute_err_indicator_efficient +from optimize_alpha import opt4_alphas, opt4 +from utilities import read_h5, construct_stress_localization, compute_err_indicator_efficient, volume_average np.random.seed(0) # np.set_printoptions(precision=3) @@ -40,16 +40,20 @@ # extract temperature dependent data from the reference solutions # such as: material stiffness and thermal strain at each temperature and for all phases + Erefs = np.zeros((n_tests, *refs[0]['strain_localization'].shape)) # n_tests x n_phases x 6 x 6 ref_Cs = np.zeros((n_tests, *refs[0]['mat_stiffness'].shape)) # n_tests x n_phases x 6 x 6 ref_epss = np.zeros((n_tests, *refs[0]['mat_thermal_strain'].shape)) # n_tests x n_phases x 6 x 1 effSref = np.zeros((n_tests, strain_dof, n_modes)) normalization_factor_mech = np.zeros((n_tests)) + plastic_modes = refs[0]['plastic_modes'] # temperature independent for idx, alpha in enumerate(test_alphas): + Erefs[idx] = refs[idx]['strain_localization'] ref_Cs[idx] = refs[idx]['mat_stiffness'] ref_epss[idx] = refs[idx]['mat_thermal_strain'] normalization_factor_mech[idx] = refs[idx]['normalization_factor_mech'] - effSref[idx] = np.hstack( - (refs[idx]['eff_stiffness'], -np.reshape(refs[idx]['eff_stiffness'] @ refs[idx]['eff_thermal_strain'], (-1, 1)))) + Sref = construct_stress_localization(Erefs[idx], ref_Cs[idx], ref_epss[idx], plastic_modes, mat_id, n_gauss, + strain_dof) + effSref[idx] = volume_average(Sref) err_indicators, err_eff_S, err_eff_C, err_eff_eps = [np.zeros((n_hierarchical_levels, n_tests)) for _ in range(4)] interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) @@ -105,7 +109,9 @@ current_sampling_id = alphas_indexing[idx] K0, K1, F0, F1, F2, F3, S001, S101, S103, S002, S102, S104 = update_affine_decomposition( - E01s[current_sampling_id], sampling_C, sampling_eps, n_modes, n_phases, n_gp, strain_dof, mat_id, n_gauss) + E01s[current_sampling_id], sampling_C, sampling_eps, plastic_modes, n_modes, n_phases, + n_gp, strain_dof, + mat_id, n_gauss) phi = get_phi(K0, K1, F0, F1, F2, F3, alpha_C, alpha_eps, alpha_C_eps) @@ -113,12 +119,16 @@ if speed == 0: C, eps = ref_Cs[idx], ref_epss[idx] # C, eps = opt4(sampling_C, sampling_eps, ref_Cs[idx], ref_epss[idx]) - _, effSopt = interpolate_fluctuation_modes(E01s[current_sampling_id], C, eps, mat_id, n_gauss, strain_dof, + _, effSopt = interpolate_fluctuation_modes(E01s[current_sampling_id], C, eps, plastic_modes, mat_id, n_gauss, + strain_dof, n_modes, n_gp) elif speed == 1: - effSopt = effective_stress_localization(E01s[current_sampling_id], phi, ref_Cs[idx], ref_epss[idx], mat_id, + # TODO verify the result when plasticity is on + effSopt = effective_stress_localization(E01s[current_sampling_id], phi, ref_Cs[idx], ref_epss[idx], plastic_modes, + mat_id, n_gauss, n_gp, strain_dof, n_modes) elif speed == 2: + # TODO verify the result when plasticity is on # matches the result from interpolate_fluctuation_modes with a difference # that depends on using ref_Cs[idx],ref_epss[idx] instead of alphas effSopt, phi = effective_S(phi, S001, S101, S103, S002, S102, S104, alpha_C, np.squeeze(alpha_eps, axis=-1), @@ -128,7 +138,9 @@ if not given_alpha_levels: Eopt4 = transform_strain_localization(E01s[current_sampling_id], phi, n_gp, strain_dof, n_modes) - Sopt4 = construct_stress_localization(Eopt4, ref_Cs[idx], ref_epss[idx], mat_id, n_gauss, strain_dof) + Sopt4 = construct_stress_localization(Eopt4, ref_Cs[idx], ref_epss[idx], plastic_modes, mat_id, n_gauss, + strain_dof) + # effSopt = volume_average(Sopt4) err_indicators[level, idx] = np.mean(np.max(np.abs(compute_err_indicator_efficient(Sopt4, global_gradient)), axis=0)) / normalization_factor_mech[idx] * 100 @@ -140,7 +152,7 @@ invL = la.inv(la.cholesky(Cref)) err_eff_C[level, idx] = la.norm(invL @ Capprox @ invL.T - np.eye(6)) / la.norm(np.eye(6)) * 100 - err_eff_eps[level, idx] = err(la.solve(Capprox, effSopt[:, -1]), la.solve(Cref, effSref[idx][:, -1])) + err_eff_eps[level, idx] = err(la.solve(Capprox, effSopt[:, 7]), la.solve(Cref, effSref[idx][:, 7])) # TODO remove dtype='f' group = file.require_group(f'{data_path}_level{level}') @@ -149,7 +161,7 @@ dset_stiffness = group.require_dataset(f'eff_stiffness_{temperature:07.2f}', (6, 6), dtype='f') dset_thermal_strain = group.require_dataset(f'eff_thermal_strain_{temperature:07.2f}', (6), dtype='f') dset_stiffness[:] = Capprox.T - dset_thermal_strain[:] = la.solve(Capprox, effSopt[:, -1]) + dset_thermal_strain[:] = la.solve(Capprox, effSopt[:, 7]) if not given_alpha_levels: max_err_idx = np.argmax(err_indicators[level]) diff --git a/interpolate_fluctuation_modes.py b/interpolate_fluctuation_modes.py index 5882ccd..d10e232 100644 --- a/interpolate_fluctuation_modes.py +++ b/interpolate_fluctuation_modes.py @@ -2,7 +2,8 @@ from numba import jit, prange @jit(nopython=True, cache=True, parallel=True, nogil=True) -def interpolate_fluctuation_modes(E01, mat_stiffness, mat_thermal_strain, mat_id, n_gauss, strain_dof, n_modes, n_gp): +def interpolate_fluctuation_modes(E01, mat_stiffness, mat_thermal_strain, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp): K = np.zeros((2 * n_modes, 2 * n_modes)) F = np.zeros((2 * n_modes, n_modes)) E_approx = np.zeros((n_gp, strain_dof, n_modes)) @@ -12,7 +13,7 @@ def interpolate_fluctuation_modes(E01, mat_stiffness, mat_thermal_strain, mat_id for gp_id in prange(n_gp): phase_id = mat_id[gp_id // n_gauss] - P = np.hstack((-I, mat_thermal_strain[phase_id])) + P = np.hstack((-I, mat_thermal_strain[phase_id], plastic_modes[gp_id])) E01t_C = E01[gp_id].T @ mat_stiffness[phase_id] @@ -29,7 +30,8 @@ def interpolate_fluctuation_modes(E01, mat_stiffness, mat_thermal_strain, mat_id return E_approx, S_average[:6, :] -def update_affine_decomposition(E01, sampling_C, sampling_eps, n_modes, n_phases, n_gp, strain_dof, mat_id, n_gauss): +def update_affine_decomposition(E01, sampling_C, sampling_eps, plastic_modes, n_modes, n_phases, n_gp, strain_dof, mat_id, + n_gauss): I = np.eye(strain_dof) K0 = np.zeros((2 * n_modes, 2 * n_modes)) @@ -59,7 +61,7 @@ def update_affine_decomposition(E01, sampling_C, sampling_eps, n_modes, n_phases eps0phase = eps0[phase_id] deltaCphase = deltaC[phase_id] deltaEPSphase = delta_eps[phase_id] - P0_phase = np.hstack((-I, eps0phase)) + P0_phase = np.hstack((-I, eps0phase, plastic_modes[gp_id])) E01_transposed = E01[gp_id].T # essential terms that construct all other precomputed terms @@ -116,11 +118,12 @@ def transform_strain_localization(E01, phi, n_gp, strain_dof, n_modes): return E_approx @jit(nopython=True, cache=True, parallel=True, nogil=True) -def effective_stress_localization(E01, phi, mat_stiffness, mat_thermal_strain, mat_id, n_gauss, n_gp, strain_dof, n_modes): +def effective_stress_localization(E01, phi, mat_stiffness, mat_thermal_strain, plastic_modes, mat_id, n_gauss, n_gp, strain_dof, + n_modes): S_average = np.zeros((strain_dof, n_modes)) I = np.eye(strain_dof) for gp_id in prange(n_gp): phase_id = mat_id[gp_id // n_gauss] - P = np.hstack((-I, mat_thermal_strain[phase_id])) + P = np.hstack((-I, mat_thermal_strain[phase_id], plastic_modes[gp_id])) S_average += mat_stiffness[phase_id] @ (E01[gp_id] @ phi - P) return S_average / n_gp diff --git a/tests/test_approximations.py b/tests/test_approximations.py index 533fc79..b3f5595 100644 --- a/tests/test_approximations.py +++ b/tests/test_approximations.py @@ -32,7 +32,7 @@ def test_approximations(): _, samples = read_h5(file_name, data_path, [temp1, temp2], get_mesh=False) - strains = np.random.normal(size=(n_loading_directions, mesh['strain_dof'])) + strains = np.random.normal(size=(n_loading_directions, strain_dof)) strains /= la.norm(strains, axis=1)[:, None] n_approaches = 5 @@ -56,38 +56,43 @@ def test_approximations(): Eref = ref[idx]['strain_localization'] ref_C = ref[idx]['mat_stiffness'] ref_eps = ref[idx]['mat_thermal_strain'] + plastic_modes = ref[idx]['plastic_modes'] normalization_factor_mech = ref[idx]['normalization_factor_mech'] - Sref = construct_stress_localization(Eref, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Sref = construct_stress_localization(Eref, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSref = volume_average(Sref) # interpolated quantities using an explicit interpolation scheme with one DOF approx_C, approx_eps = naive(alpha, sampling_C, sampling_eps, ref_C, ref_eps) Enaive = interpolate_temp(E0, E1) - Snaive = construct_stress_localization(Enaive, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Snaive = construct_stress_localization(Enaive, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSnaive = volume_average(Snaive) # interpolated quantities using an explicit interpolation scheme with one DOF - Eopt0, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, mat_id, n_gauss, strain_dof, n_modes, n_gp) - Sopt0 = construct_stress_localization(Eopt0, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Eopt0, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt0 = construct_stress_localization(Eopt0, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSopt0 = volume_average(Sopt0) # interpolated quantities using an implicit interpolation scheme with one DOF approx_C, approx_eps = opt1(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt1, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, mat_id, n_gauss, strain_dof, n_modes, n_gp) - Sopt1 = construct_stress_localization(Eopt1, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Eopt1, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt1 = construct_stress_localization(Eopt1, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSopt1 = volume_average(Sopt1) # interpolated quantities using an implicit interpolation scheme with two DOF approx_C, approx_eps = opt2(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt2, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, mat_id, n_gauss, strain_dof, n_modes, n_gp) - Sopt2 = construct_stress_localization(Eopt2, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Eopt2, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt2 = construct_stress_localization(Eopt2, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSopt2 = volume_average(Sopt2) # interpolated quantities using an implicit interpolation scheme with four DOF approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, mat_id, n_gauss, strain_dof, n_modes, n_gp) - Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, mat_id, n_gauss, strain_dof) + Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) effSopt4 = volume_average(Sopt4) err = lambda x, y: np.mean(la.norm(x - y, axis=(-1, -2)) / la.norm(y, axis=(-1, -2))) * 100 @@ -99,7 +104,7 @@ def test_approximations(): err(effSopt2, effSref), err(effSopt4, effSref)] for strain_idx, strain in enumerate(strains): - zeta = np.hstack((strain, 1)) + zeta = np.hstack((strain, 1, np.ones(plastic_modes.shape[-1]))) eff_stress_ref = effSref @ zeta err_eff_stress[:, idx * n_loading_directions + strain_idx] = \ @@ -114,7 +119,7 @@ def test_approximations(): stress_opt4 = np.einsum('ijk,k', Sopt4, zeta, optimize='optimal') residuals = compute_residual_efficient([stress_naive, stress_opt0, stress_opt1, stress_opt2, stress_opt4], - mesh['global_gradient']) + global_gradient) err_f[:, idx * n_loading_directions + strain_idx] = la.norm(residuals, np.inf, axis=0) / normalization_factor_mech * 100 diff --git a/utilities.py b/utilities.py index 9a71d72..5e143dc 100644 --- a/utilities.py +++ b/utilities.py @@ -131,7 +131,7 @@ def read_h5(file_name, data_path, temperatures, get_mesh=True): sample['combo_strain_loc0'] = None sample['combo_strain_loc1'] = None - with contextlib.suppress(Exception): + with contextlib.suppress(Exception): # used because some strain localizations are deleted to make h5 files smaller sample['strain_localization'] = file[f'{data_path}/localization_strain_{temperature:07.2f}'][:].transpose( axis_order) @@ -141,6 +141,12 @@ def read_h5(file_name, data_path, temperatures, get_mesh=True): sample['combo_strain_loc1'] = \ file[f'{data_path}/localization_strain1_{temperature:07.2f}'][:].transpose(axis_order) + + if 'plastic_modes' in file[f'{data_path}'].keys(): + sample['plastic_modes'] = file[f'{data_path}/plastic_modes'][:].transpose(axis_order) + else: + sample['plastic_modes'] = np.zeros((*sample['strain_localization'].shape[:2], 0)) + if get_mesh: mesh['volume_fraction'] = file[f'{data_path}'].attrs['combo_volume_fraction'] mesh['combo_discretisation'] = np.int64(file[f'{data_path}'].attrs['combo_discretisation']) @@ -210,25 +216,31 @@ def verify_data(mesh, sample): eff_stiffness, eff_thermal_strain = sample['eff_stiffness'], sample['eff_thermal_strain'] mat_thermal_strain, mat_stiffness = sample['mat_thermal_strain'], sample['mat_stiffness'] combo_strain_loc0, combo_strain_loc1 = sample['combo_strain_loc0'], sample['combo_strain_loc1'] + plastic_modes = sample['plastic_modes'] macro_strain = np.asarray([3, .7, 1.5, 0.5, 2, 1]) - zeta = np.hstack((macro_strain, 1)) # 1 accounts for thermoelastic strain, more details in the paper cited in readme.md + xi = np.ones(plastic_modes.shape[-1]) + # 1 accounts for thermoelastic strain, more details in the paper cited in readme.md + # xi accounts for plastic mode activations + zeta = np.hstack((macro_strain, 1, xi)) strain = macro_strain + np.einsum('ijk,k', strain_localization, zeta, optimize='optimal') - stress_localization = construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, mesh['mat_id'], - mesh['n_gauss'], mesh['strain_dof']) + stress_localization = construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, + mesh['mat_id'], mesh['n_gauss'], mesh['strain_dof']) eff_stiffness_from_localization = volume_average(stress_localization) stress = np.einsum('ijk,k', stress_localization, zeta, optimize='optimal') residual = compute_residual(stress, mesh['dof'], mesh['n_elements'], mesh['element_dof'], mesh['n_gauss'], mesh['assembly_idx'], mesh['gradient_operators_times_w']) - abs_err = eff_stiffness_from_localization - np.hstack((eff_stiffness, -np.reshape(eff_stiffness @ eff_thermal_strain, - (-1, 1)))) + eff_thermoelastic_stiffness = eff_stiffness_from_localization[:, :7] + abs_err = eff_thermoelastic_stiffness - np.hstack((eff_stiffness, -np.reshape(eff_stiffness @ eff_thermal_strain, + (-1, 1)))) + # - C @ eff_plastic_strain # eff_plastic_strain is not stored because it depends on the macroscopic strain err = lambda x, y: np.mean(la.norm(x - y) / la.norm(y)) - assert err(eff_stiffness_from_localization, + assert err(eff_thermoelastic_stiffness, np.vstack((eff_stiffness, -eff_stiffness @ eff_thermal_strain)).T) < convergence_tolerance, \ 'incompatibility between stress_localization and effective quantities' @@ -239,7 +251,7 @@ def verify_data(mesh, sample): 'stress field is not statically admissible' stress_localization0, stress_localization1, combo_stress_loc0, combo_stress_loc1 = construct_stress_localization_phases( - strain_localization, mat_stiffness, mat_thermal_strain, combo_strain_loc0, combo_strain_loc1, mesh) + strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, combo_strain_loc0, combo_strain_loc1, mesh) combo_stress0 = np.einsum('ijk,k', combo_stress_loc0, zeta, optimize='optimal') if combo_stress_loc0 is not None else None combo_stress1 = np.einsum('ijk,k', combo_stress_loc1, zeta, optimize='optimal') if combo_stress_loc1 is not None else None @@ -317,7 +329,8 @@ def cheap_err_indicator(stress_loc, global_gradient): return la.norm(global_gradient.T @ np.sum(stress_loc, -1).flatten()) @jit(nopython=True, cache=True, parallel=True, nogil=True) -def construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, mat_id, n_gauss, strain_dof): +def construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mat_id, n_gauss, + strain_dof): """ Construct stress localization operator out of the strain localization one. :param strain_localization: strain localization 3D array @@ -331,11 +344,11 @@ def construct_stress_localization(strain_localization, mat_stiffness, mat_therma I = np.eye(strain_dof) for gp_id in prange(strain_localization.shape[0]): phase_id = mat_id[gp_id // n_gauss] - P = np.hstack((-I, mat_thermal_strain[phase_id])) + P = np.hstack((-I, mat_thermal_strain[phase_id], plastic_modes[gp_id])) stress_localization[gp_id] = mat_stiffness[phase_id] @ (strain_localization[gp_id] - P) return stress_localization -def construct_stress_localization_phases(strain_localization, mat_stiffness, mat_thermal_strain, combo_strain_loc0, +def construct_stress_localization_phases(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, combo_strain_loc0, combo_strain_loc1, mesh): """ Same as construct_stress_localization() but it returns stress localization operators for each material phase @@ -354,7 +367,8 @@ def construct_stress_localization_phases(strain_localization, mat_stiffness, mat n_gauss = mesh['n_gauss'] idx0 = np.repeat(mesh['mat_id'] == 0, n_gauss) idx1 = np.repeat(mesh['mat_id'] == 1, n_gauss) - stress_localization = construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, mesh['mat_id'], + stress_localization = construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, + mesh['mat_id'], mesh['n_gauss'], mesh['strain_dof']) stress_localization0 = stress_localization[idx0] if np.any(idx0) else np.zeros((1, *stress_localization.shape[1:])) stress_localization1 = stress_localization[idx1] if np.any(idx1) else np.zeros((1, *stress_localization.shape[1:])) From 825d54dceb5cebd221d54e9c67ce1867cae9b615 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Tue, 9 May 2023 17:31:33 +0200 Subject: [PATCH 02/30] Add first version of mode identification algorithm --- utilities.py | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/utilities.py b/utilities.py index 5e143dc..97980bd 100644 --- a/utilities.py +++ b/utilities.py @@ -21,6 +21,7 @@ cm = 1 / 2.54 # centimeters in inches + def plot_and_save(xlabel, ylabel, fig_name, xlim=None, ylim=None, loc='best'): gca = plt.gca() gca.set_xlim(xlim) @@ -33,12 +34,14 @@ def plot_and_save(xlabel, ylabel, fig_name, xlim=None, ylim=None, loc='best'): plt.savefig(f'output/{fig_name}.png') plt.show() + def ecdf(x): """empirical cumulative distribution function""" # plt.step(*ecdf(np.asarray([1, 1, 2, 3, 4])), where='post') n = len(x) return [np.hstack((np.min(x), np.sort(np.squeeze(np.asarray(x))))), np.hstack((0, np.linspace(1 / n, 1, n)))] + def voxel_quadrature(discretisation, strain_dof=6, nodal_dof=3): """ Voxel formulation with full integration, works with structured grids only @@ -90,6 +93,7 @@ def voxel_quadrature(discretisation, strain_dof=6, nodal_dof=3): return gradient_operators, integration_weights + def read_h5(file_name, data_path, temperatures, get_mesh=True): """ Read an H5 file that contains responses of simulated microstructures @@ -204,6 +208,7 @@ def read_h5(file_name, data_path, temperatures, get_mesh=True): return mesh, samples + def verify_data(mesh, sample): """ Sanity check to see if it is possible to reconstruct stress, strain fields and effective properties @@ -268,6 +273,7 @@ def verify_data(mesh, sample): vol_frac0 * average_stress_0 + vol_frac1 * average_stress_1) < convergence_tolerance, \ 'phasewise volume average is not admissible' + def compute_residual(stress, dof, n_elements, element_dof, n_gauss, assembly_idx, gradient_operators_times_w): """ Compute FEM residual given a stress field @@ -291,6 +297,7 @@ def compute_residual(stress, dof, n_elements, element_dof, n_gauss, assembly_idx residuals[assembly_idx[element_id], idx] += elmental_force return residuals + def compute_residual_efficient(stress, global_gradient): stresses = stress if not isinstance(stress, list): @@ -298,6 +305,7 @@ def compute_residual_efficient(stress, global_gradient): return (np.vstack([x.flatten() for x in stresses]) @ global_gradient).T + @jit(nopython=True, cache=True, parallel=True, nogil=True) def compute_err_indicator(stress_loc, gradient_operators_times_w, dof, n_gauss, assembly_idx): """ @@ -321,13 +329,16 @@ def compute_err_indicator(stress_loc, gradient_operators_times_w, dof, n_gauss, # return la.norm(err_indicator) return err_indicator + def compute_err_indicator_efficient(stress_loc, global_gradient): return global_gradient.T @ stress_loc.reshape(global_gradient.shape[0], -1) + # @jit(nopython=True, cache=True, parallel=True, nogil=True) def cheap_err_indicator(stress_loc, global_gradient): return la.norm(global_gradient.T @ np.sum(stress_loc, -1).flatten()) + @jit(nopython=True, cache=True, parallel=True, nogil=True) def construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mat_id, n_gauss, strain_dof): @@ -348,6 +359,7 @@ def construct_stress_localization(strain_localization, mat_stiffness, mat_therma stress_localization[gp_id] = mat_stiffness[phase_id] @ (strain_localization[gp_id] - P) return stress_localization + def construct_stress_localization_phases(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, combo_strain_loc0, combo_strain_loc1, mesh): """ @@ -386,6 +398,7 @@ def construct_stress_localization_phases(strain_localization, mat_stiffness, mat combo_stress_loc1[idx] = mat_stiffness[1] @ combo_strain_loc1[idx] - mat_stiffness[stiffness_idx] @ P return stress_localization0, stress_localization1, combo_stress_loc0, combo_stress_loc1 + def volume_average_phases(stress0, stress1, combo_stress0, combo_stress1, mesh): """ Volume average of stress field in each phase @@ -414,6 +427,96 @@ def volume_average_phases(stress0, stress1, combo_stress0, combo_stress1, mesh): return average_stress_0, average_stress_1 + def volume_average(field): """ Volume average of a given field in case of identical weights that sum to one """ return np.mean(field, axis=0) + + +def read_snapshots(file_name, data_path, temperatures): + """ + Read an H5 file that contains responses of simulated microstructures + :param file_name: e.g. "input/simple_3d_rve_combo.h5" + :param data_path: the path to the simulation results within the h5 file, e.g. '/ms_1p/dset0_sim' + :param temperatures: all responses corresponding to these temperatures will be read + :return: + strain_snapshots: plastic strain snapshots eps_p + with shape (n_integration_points, strain_dof, n_frames) + """ + # TODO: read snapshots from H5 file + # TODO: Reorder snapshots as follows: | 1st strain path: last timestep to first timestep | 2nd strain path: last timestep to first timestep | ... + pass + + +def inner_product(a, b): + """ + Compute inner product between tensor fields a and b + :param a: array with shape (n_integration_points, ...) + :param b: array with same shape as b + """ + assert a.shape == b.shape + summation_axes = tuple(ax for ax in range(1, a.ndim)) + return np.sum(a * b, axis=summation_axes) + + +def norm_2(a): + """ + Compute euclidean norm of tensor field a + :param a: array with shape (n_integration_points, ...) + :param b: array with same shape as b + """ + return np.sqrt(inner_product(a, a)) + + +def mode_identification(strain_snapshots, r_min): + """ + Identification of plastic strain modes µ using POD and renormalization + :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) + with shape (n_integration_points, strain_dof, n_frames) + :param r_min: stop criterion + :return: + strain_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, N_modes) + """ + n_integration_points, strain_dof, n_frames = strain_snapshots.shape + N_modes = 0 + strain_modes = np.zeros((n_integration_points, strain_dof, N_modes)) + for i in range(n_frames): + eps_i = strain_snapshots[:, :, i] + r = volume_average(inner_product(eps_i, eps_i)) # TODO: average only over Omega_p? + k = np.zeros(N_modes) # Coefficients k_j + for j in range(N_modes): + k[j] = volume_average(inner_product(eps_i, strain_modes[:, :, j])) + r = r - k[j]**2 + if r > r_min: + break + N_modes = N_modes + 1 # increment number of modes + # Generate new strain mode: + strain_mode = (eps_i - np.tensordot(k, strain_modes, axes=(0,2))) / np.sqrt(r) + strain_modes = np.concatenate([strain_modes, np.expand_dims(strain_mode, 2)], axis=2) + # Renormalize all modes: + for i in range(N_modes): + strain_modes[:, :, i] = strain_modes[:, :, i] / volume_average(norm_2(strain_modes[:, :, i])) + return strain_modes + + +def mode_processing(strain_modes): + """ + Processing of the plastic strain modes µ to compute the matrices A, D^0, C and theta + as tabular data at given temperatures + :param strain_modes: + :param ...: + :return: + A + D0 + C + theta + """ + pass + + +def save_tabular_data(file_name, data_path, temperatures, A, D0, C, theta): + """ + Save tabular data + :param file_name: e.g. "input/simple_3d_rve_combo.h5" + """ + pass From b594c09c033585c67dad9ca01a54ee84de83c4e9 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Wed, 10 May 2023 00:54:24 +0200 Subject: [PATCH 03/30] Add first version of mode processing --- eg9_plastic_modes_example.py | 51 +++++++++++++++++++++++ utilities.py | 78 +++++++++++++++++++++++++++--------- 2 files changed, 110 insertions(+), 19 deletions(-) create mode 100644 eg9_plastic_modes_example.py diff --git a/eg9_plastic_modes_example.py b/eg9_plastic_modes_example.py new file mode 100644 index 0000000..f8af1bf --- /dev/null +++ b/eg9_plastic_modes_example.py @@ -0,0 +1,51 @@ +""" +Plot the strain localization operator E and stress localization operator S at different temperatures +""" +#%% +from operator import itemgetter + +import numpy.linalg as la +import matplotlib.pyplot as plt +from microstructures import * +from utilities import read_h5, mode_identification, mode_processing + +np.random.seed(0) +file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( + "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" +)(microstructures[0]) +print(file_name, "\t", data_path) + +test_temperatures = np.linspace(temp1, temp2, num=n_tests) +test_alphas = np.linspace(0, 1, num=n_tests) + +mesh, samples = read_h5(file_name, data_path, test_temperatures) +mat_id = mesh["mat_id"] +n_gauss = mesh["n_gauss"] +strain_dof = mesh["strain_dof"] +nodal_dof = mesh["nodal_dof"] +n_elements = mesh["n_elements"] +n_integration_points = mesh["n_integration_points"] +global_gradient = mesh["global_gradient"] +n_gp = mesh["n_integration_points"] +disc = mesh["combo_discretisation"] + +#%% Mode identification + +# TODO: Read plastic snapshots from h5 file +N_modes = 10 +plastic_snapshots = np.random.rand(n_integration_points, strain_dof, N_modes) + +# Mode identification using POD +r_min = 1e-3 +plastic_modes = mode_identification(plastic_snapshots, r_min) + +# TODO: save identified plastic modes to h5 file + +#%% Mode processing to compute system matrices (after snapshots have been computed using FANS) + +# TODO: compute system matrices for multiple temperatures in an efficient way +strain_localization = samples[0]["strain_localization"] +mat_stiffness = samples[0]["mat_stiffness"] +A_bar, D_xi, tau_theta, C_bar = mode_processing(strain_localization, mat_stiffness, mesh, plastic_modes) + +# TODO: save system matrices for multiple temperatures as tabular data diff --git a/utilities.py b/utilities.py index 97980bd..ae4940c 100644 --- a/utilities.py +++ b/utilities.py @@ -468,53 +468,93 @@ def norm_2(a): return np.sqrt(inner_product(a, a)) -def mode_identification(strain_snapshots, r_min): +def mode_identification(plastic_snapshots, r_min): """ Identification of plastic strain modes µ using POD and renormalization :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) with shape (n_integration_points, strain_dof, n_frames) :param r_min: stop criterion :return: - strain_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, N_modes) + plastic_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, N_modes) """ - n_integration_points, strain_dof, n_frames = strain_snapshots.shape + n_integration_points, strain_dof, n_frames = plastic_snapshots.shape N_modes = 0 - strain_modes = np.zeros((n_integration_points, strain_dof, N_modes)) + plastic_modes = np.zeros((n_integration_points, strain_dof, N_modes)) for i in range(n_frames): - eps_i = strain_snapshots[:, :, i] + eps_i = plastic_snapshots[:, :, i] r = volume_average(inner_product(eps_i, eps_i)) # TODO: average only over Omega_p? k = np.zeros(N_modes) # Coefficients k_j for j in range(N_modes): - k[j] = volume_average(inner_product(eps_i, strain_modes[:, :, j])) + k[j] = volume_average(inner_product(eps_i, plastic_modes[:, :, j])) r = r - k[j]**2 if r > r_min: break N_modes = N_modes + 1 # increment number of modes # Generate new strain mode: - strain_mode = (eps_i - np.tensordot(k, strain_modes, axes=(0,2))) / np.sqrt(r) - strain_modes = np.concatenate([strain_modes, np.expand_dims(strain_mode, 2)], axis=2) + plastic_mode = (eps_i - np.tensordot(k, plastic_modes, axes=(0,2))) / np.sqrt(r) + plastic_modes = np.concatenate([plastic_modes, np.expand_dims(plastic_mode, 2)], axis=2) # Renormalize all modes: for i in range(N_modes): - strain_modes[:, :, i] = strain_modes[:, :, i] / volume_average(norm_2(strain_modes[:, :, i])) - return strain_modes + plastic_modes[:, :, i] = plastic_modes[:, :, i] / volume_average(norm_2(plastic_modes[:, :, i])) + return plastic_modes -def mode_processing(strain_modes): +def mode_processing(strain_localization, mat_stiffness, mesh, plastic_modes): """ - Processing of the plastic strain modes µ to compute the matrices A, D^0, C and theta + Processing of the plastic strain modes µ to compute the matrices A_bar, D_xi, C_bar and the vector tau_theta as tabular data at given temperatures - :param strain_modes: + :param strain_localization: strain localization 3D array + with shape (n_integration_points, strain_dof, 7) + :param mat_stiffness: stiffness tensors of the phases + with shape (n_phases, strain_dof, strain_dof) + :param mat_id: material phase identification + with shape (n_elements,) + :param mesh: + :param plastic_modes: plastic strain modes µ + with shape (n_integration_points, strain_dof, N_modes) + :param eigen_strains: solutions of the auxiliary eigenstress problems eps_star + with shape (n_integration_points, strain_dof, N_modes) :param ...: :return: - A - D0 - C - theta + A_bar with shape (strain_dof, strain_dof) + D_xi with shape (strain_dof, N_modes) + tau_theta with shape (strain_dof,) + C_bar with shape (strain_dof, strain_dof) """ - pass + strain_dof = mesh['strain_dof'] + n_gauss = mesh['n_gauss'] + mat_id = mesh['mat_id'] + mat_thermal_strain = None # TODO + N_modes = plastic_modes.shape[2] + + # compute stress localization operator S (including plastic contributions) + stress_localization = construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, \ + plastic_modes, mat_id, n_gauss, strain_dof) + + # slice stress localization operator S into S_eps, S_xi, S_theta + S_eps = stress_localization[:, :, :strain_dof] + S_xi = stress_localization[:, :, strain_dof:(strain_dof + N_modes)] + S_theta = stress_localization[:, :, -1] + + # volume averaging S_eps -> C_bar, S_xi -> A_bar, S_theta -> tau_theta + C_bar = volume_average(S_eps) + A_bar = volume_average(S_xi) + tau_theta = volume_average(S_theta) + + # Now we have A_bar, C_bar and tau_theta. Still missing: D_xi + + # Compute D_xi + # plastic_modes has shape (n_integration_points, strain_dof, N_modes) -> transpose + # S_xi has shape (n_integration_points, strain_dof, N_modes) + # Then, D_xi has shape (N_modes, N_modes) + D_xi = -volume_average(plastic_modes.transpose((0, 2, 1)) @ S_xi) + + # Should A_bar be transposed before saving data? + + return A_bar, D_xi, tau_theta, C_bar -def save_tabular_data(file_name, data_path, temperatures, A, D0, C, theta): +def save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, theta_theta, C_bar): """ Save tabular data :param file_name: e.g. "input/simple_3d_rve_combo.h5" From 57ca4fe419727e71e3fbe7d43284abd51885c626 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Wed, 10 May 2023 06:42:20 +0200 Subject: [PATCH 04/30] Documentation --- eg9_plastic_modes_example.py | 8 ++++--- utilities.py | 43 +++++++++++++++++++++--------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/eg9_plastic_modes_example.py b/eg9_plastic_modes_example.py index f8af1bf..d8f3a57 100644 --- a/eg9_plastic_modes_example.py +++ b/eg9_plastic_modes_example.py @@ -1,5 +1,5 @@ """ -Plot the strain localization operator E and stress localization operator S at different temperatures +Demo code for plastic mode identification and processing, i.e. computation of the system matrices """ #%% from operator import itemgetter @@ -44,8 +44,10 @@ #%% Mode processing to compute system matrices (after snapshots have been computed using FANS) # TODO: compute system matrices for multiple temperatures in an efficient way -strain_localization = samples[0]["strain_localization"] -mat_stiffness = samples[0]["mat_stiffness"] +sample = samples[0] # For now, choose one arbitrary sample +strain_localization = sample["strain_localization"] +mat_stiffness = sample["mat_stiffness"] +plastic_modes = sample['plastic_modes'] A_bar, D_xi, tau_theta, C_bar = mode_processing(strain_localization, mat_stiffness, mesh, plastic_modes) # TODO: save system matrices for multiple temperatures as tabular data diff --git a/utilities.py b/utilities.py index ae4940c..807937b 100644 --- a/utilities.py +++ b/utilities.py @@ -104,7 +104,7 @@ def read_h5(file_name, data_path, temperatures, get_mesh=True): mesh: dictionary that contains microstructural details such as volume fraction, voxel type, ... samples: list of simulation results at each temperature """ - axis_order = [0, 2, 1] # n_gauss x strain_dof x 7 (7=6 mechanical + 1 thermal expansion) + axis_order = [0, 2, 1] # n_gauss x strain_dof x (N + 7) (N + 7 = 6 mechanical + N plastic + 1 thermal expansion) samples = [] with h5py.File(file_name, 'r') as file: @@ -429,28 +429,16 @@ def volume_average_phases(stress0, stress1, combo_stress0, combo_stress1, mesh): def volume_average(field): - """ Volume average of a given field in case of identical weights that sum to one """ - return np.mean(field, axis=0) - - -def read_snapshots(file_name, data_path, temperatures): """ - Read an H5 file that contains responses of simulated microstructures - :param file_name: e.g. "input/simple_3d_rve_combo.h5" - :param data_path: the path to the simulation results within the h5 file, e.g. '/ms_1p/dset0_sim' - :param temperatures: all responses corresponding to these temperatures will be read - :return: - strain_snapshots: plastic strain snapshots eps_p - with shape (n_integration_points, strain_dof, n_frames) + Volume average of a given field in case of identical weights that sum to one + :param field: array with shape (n_integration_points, ...) """ - # TODO: read snapshots from H5 file - # TODO: Reorder snapshots as follows: | 1st strain path: last timestep to first timestep | 2nd strain path: last timestep to first timestep | ... - pass + return np.mean(field, axis=0) def inner_product(a, b): """ - Compute inner product between tensor fields a and b + Compute inner product between tensor fields a and b in case of identical weights that sum to one :param a: array with shape (n_integration_points, ...) :param b: array with same shape as b """ @@ -461,13 +449,32 @@ def inner_product(a, b): def norm_2(a): """ - Compute euclidean norm of tensor field a + Compute euclidean norm of tensor field a in case of identical weights that sum to one :param a: array with shape (n_integration_points, ...) :param b: array with same shape as b """ return np.sqrt(inner_product(a, a)) +def read_snapshots(file_name, data_path, temperatures): + """ + Read an H5 file that contains responses of simulated microstructures + :param file_name: e.g. "input/simple_3d_rve_combo.h5" + :param data_path: the path to the simulation results within the h5 file, e.g. '/ms_1p/dset0_sim' + :param temperatures: all responses corresponding to these temperatures will be read + :return: + strain_snapshots: plastic strain snapshots eps_p + with shape (n_integration_points, strain_dof, n_frames) + """ + # TODO: read snapshots from H5 file. Because of the sheer amount of data it may be better to use a separate h5 file for the snapshots. + # For now, use dummy data: + n_integration_points, strain_dof, n_frames = 512, 6, 1000 + plastic_snapshots = np.random.rand(n_integration_points, strain_dof, n_frames) + # TODO: Reorder snapshots as follows: | 1st strain path: last timestep to first timestep | 2nd strain path: last timestep to first timestep | ... + # or: reorder snapshots already in FANS? + pass + + def mode_identification(plastic_snapshots, r_min): """ Identification of plastic strain modes µ using POD and renormalization From 2ab3ef88b91357c9d40e93a9a63294ca32908a59 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Wed, 10 May 2023 06:47:29 +0200 Subject: [PATCH 05/30] Documentation --- eg9_plastic_modes_example.py | 13 ++++++------- utilities.py | 7 +++---- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/eg9_plastic_modes_example.py b/eg9_plastic_modes_example.py index d8f3a57..17b34cd 100644 --- a/eg9_plastic_modes_example.py +++ b/eg9_plastic_modes_example.py @@ -7,7 +7,7 @@ import numpy.linalg as la import matplotlib.pyplot as plt from microstructures import * -from utilities import read_h5, mode_identification, mode_processing +from utilities import read_h5, read_snapshots, mode_identification, mode_processing, save_tabular_data np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( @@ -15,10 +15,9 @@ )(microstructures[0]) print(file_name, "\t", data_path) -test_temperatures = np.linspace(temp1, temp2, num=n_tests) -test_alphas = np.linspace(0, 1, num=n_tests) +temperatures = np.linspace(temp1, temp2, num=n_tests) -mesh, samples = read_h5(file_name, data_path, test_temperatures) +mesh, samples = read_h5(file_name, data_path, temperatures) mat_id = mesh["mat_id"] n_gauss = mesh["n_gauss"] strain_dof = mesh["strain_dof"] @@ -32,8 +31,7 @@ #%% Mode identification # TODO: Read plastic snapshots from h5 file -N_modes = 10 -plastic_snapshots = np.random.rand(n_integration_points, strain_dof, N_modes) +plastic_snapshots = read_snapshots(file_name, data_path, temperatures) # Mode identification using POD r_min = 1e-3 @@ -41,7 +39,7 @@ # TODO: save identified plastic modes to h5 file -#%% Mode processing to compute system matrices (after snapshots have been computed using FANS) +#%% Mode processing to compute system matrices (after eigenstress problems have been solved using FANS) # TODO: compute system matrices for multiple temperatures in an efficient way sample = samples[0] # For now, choose one arbitrary sample @@ -51,3 +49,4 @@ A_bar, D_xi, tau_theta, C_bar = mode_processing(strain_localization, mat_stiffness, mesh, plastic_modes) # TODO: save system matrices for multiple temperatures as tabular data +save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar) diff --git a/utilities.py b/utilities.py index 807937b..c1d4520 100644 --- a/utilities.py +++ b/utilities.py @@ -472,7 +472,7 @@ def read_snapshots(file_name, data_path, temperatures): plastic_snapshots = np.random.rand(n_integration_points, strain_dof, n_frames) # TODO: Reorder snapshots as follows: | 1st strain path: last timestep to first timestep | 2nd strain path: last timestep to first timestep | ... # or: reorder snapshots already in FANS? - pass + return plastic_snapshots def mode_identification(plastic_snapshots, r_min): @@ -548,8 +548,6 @@ def mode_processing(strain_localization, mat_stiffness, mesh, plastic_modes): A_bar = volume_average(S_xi) tau_theta = volume_average(S_theta) - # Now we have A_bar, C_bar and tau_theta. Still missing: D_xi - # Compute D_xi # plastic_modes has shape (n_integration_points, strain_dof, N_modes) -> transpose # S_xi has shape (n_integration_points, strain_dof, N_modes) @@ -561,9 +559,10 @@ def mode_processing(strain_localization, mat_stiffness, mesh, plastic_modes): return A_bar, D_xi, tau_theta, C_bar -def save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, theta_theta, C_bar): +def save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar): """ Save tabular data :param file_name: e.g. "input/simple_3d_rve_combo.h5" + :param ...: """ pass From 59cc1fdf4f1ca747c53e8f3d91ec8a3acc28f63e Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Wed, 10 May 2023 16:46:03 +0200 Subject: [PATCH 06/30] Update mode identification algorithm --- eg9_plastic_modes_example.py | 11 +++++++++-- utilities.py | 20 +++++++++++--------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/eg9_plastic_modes_example.py b/eg9_plastic_modes_example.py index 17b34cd..75d72ee 100644 --- a/eg9_plastic_modes_example.py +++ b/eg9_plastic_modes_example.py @@ -32,10 +32,12 @@ # TODO: Read plastic snapshots from h5 file plastic_snapshots = read_snapshots(file_name, data_path, temperatures) +print('plastic_snapshots.shape:', plastic_snapshots.shape) # Mode identification using POD -r_min = 1e-3 +r_min = 6e-5 plastic_modes = mode_identification(plastic_snapshots, r_min) +print('plastic_modes.shape:', plastic_modes.shape) # TODO: save identified plastic modes to h5 file @@ -45,8 +47,13 @@ sample = samples[0] # For now, choose one arbitrary sample strain_localization = sample["strain_localization"] mat_stiffness = sample["mat_stiffness"] +mat_thermal_strain = sample["mat_thermal_strain"] plastic_modes = sample['plastic_modes'] -A_bar, D_xi, tau_theta, C_bar = mode_processing(strain_localization, mat_stiffness, mesh, plastic_modes) +A_bar, D_xi, tau_theta, C_bar = mode_processing(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mesh) +print('A_bar.shape:', A_bar.shape) +print('D_xi.shape:', D_xi.shape) +print('tau_theta.shape:', tau_theta.shape) +print('C_bar.shape:', C_bar.shape) # TODO: save system matrices for multiple temperatures as tabular data save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar) diff --git a/utilities.py b/utilities.py index c1d4520..09a8074 100644 --- a/utilities.py +++ b/utilities.py @@ -468,8 +468,10 @@ def read_snapshots(file_name, data_path, temperatures): """ # TODO: read snapshots from H5 file. Because of the sheer amount of data it may be better to use a separate h5 file for the snapshots. # For now, use dummy data: - n_integration_points, strain_dof, n_frames = 512, 6, 1000 - plastic_snapshots = np.random.rand(n_integration_points, strain_dof, n_frames) + n_integration_points, strain_dof, n_frames = 512, 6, 100 + # plastic_snapshots = np.random.rand(n_integration_points, strain_dof, n_frames) + plastic_snapshots = np.random.rand(n_integration_points, strain_dof)[:, :, np.newaxis] * np.random.rand(n_frames) \ + + 1e-2 * np.random.rand(n_integration_points, strain_dof, n_frames) # TODO: Reorder snapshots as follows: | 1st strain path: last timestep to first timestep | 2nd strain path: last timestep to first timestep | ... # or: reorder snapshots already in FANS? return plastic_snapshots @@ -494,19 +496,20 @@ def mode_identification(plastic_snapshots, r_min): for j in range(N_modes): k[j] = volume_average(inner_product(eps_i, plastic_modes[:, :, j])) r = r - k[j]**2 - if r > r_min: + if r < r_min: break - N_modes = N_modes + 1 # increment number of modes - # Generate new strain mode: - plastic_mode = (eps_i - np.tensordot(k, plastic_modes, axes=(0,2))) / np.sqrt(r) - plastic_modes = np.concatenate([plastic_modes, np.expand_dims(plastic_mode, 2)], axis=2) + if r > r_min: + N_modes = N_modes + 1 # increment number of modes + # Generate new strain mode: + plastic_mode = (eps_i - np.tensordot(k, plastic_modes, axes=(0,2))) / np.sqrt(r) + plastic_modes = np.concatenate([plastic_modes, np.expand_dims(plastic_mode, 2)], axis=2) # Renormalize all modes: for i in range(N_modes): plastic_modes[:, :, i] = plastic_modes[:, :, i] / volume_average(norm_2(plastic_modes[:, :, i])) return plastic_modes -def mode_processing(strain_localization, mat_stiffness, mesh, plastic_modes): +def mode_processing(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mesh): """ Processing of the plastic strain modes µ to compute the matrices A_bar, D_xi, C_bar and the vector tau_theta as tabular data at given temperatures @@ -531,7 +534,6 @@ def mode_processing(strain_localization, mat_stiffness, mesh, plastic_modes): strain_dof = mesh['strain_dof'] n_gauss = mesh['n_gauss'] mat_id = mesh['mat_id'] - mat_thermal_strain = None # TODO N_modes = plastic_modes.shape[2] # compute stress localization operator S (including plastic contributions) From e1361fe61e36648fa2b6c609b02f3846d46b8d76 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Wed, 10 May 2023 16:54:50 +0200 Subject: [PATCH 07/30] Add dummy data for mode processing --- eg9_plastic_modes_example.py | 5 ++++- utilities.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/eg9_plastic_modes_example.py b/eg9_plastic_modes_example.py index 75d72ee..8dd09a5 100644 --- a/eg9_plastic_modes_example.py +++ b/eg9_plastic_modes_example.py @@ -45,10 +45,13 @@ # TODO: compute system matrices for multiple temperatures in an efficient way sample = samples[0] # For now, choose one arbitrary sample +# plastic_modes = sample['plastic_modes'] (until we have real data) +N_modes = plastic_modes.shape[2] strain_localization = sample["strain_localization"] +# Add dummy data to strain_localization until we have real data: +strain_localization = np.concatenate([strain_localization, np.random.rand(n_integration_points, strain_dof, N_modes)], axis=2) mat_stiffness = sample["mat_stiffness"] mat_thermal_strain = sample["mat_thermal_strain"] -plastic_modes = sample['plastic_modes'] A_bar, D_xi, tau_theta, C_bar = mode_processing(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mesh) print('A_bar.shape:', A_bar.shape) print('D_xi.shape:', D_xi.shape) diff --git a/utilities.py b/utilities.py index 09a8074..2e7e7f9 100644 --- a/utilities.py +++ b/utilities.py @@ -339,7 +339,7 @@ def cheap_err_indicator(stress_loc, global_gradient): return la.norm(global_gradient.T @ np.sum(stress_loc, -1).flatten()) -@jit(nopython=True, cache=True, parallel=True, nogil=True) +#@jit(nopython=True, cache=True, parallel=True, nogil=True) def construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mat_id, n_gauss, strain_dof): """ From 8f3a821f1e19fe302eba43848472f3c4e556748f Mon Sep 17 00:00:00 2001 From: sha79396 Date: Thu, 8 Jun 2023 18:36:20 +0200 Subject: [PATCH 08/30] test on plastic striped_normal_4x4x4 RVE --- eg2_compare_approximations.py | 2 +- eg3_hierarchical_sampling.py | 4 ++-- microstructures.py | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/eg2_compare_approximations.py b/eg2_compare_approximations.py index 3600a5a..4440b7e 100644 --- a/eg2_compare_approximations.py +++ b/eg2_compare_approximations.py @@ -12,7 +12,7 @@ np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[0]) + 'sampling_alphas')(microstructures[-1]) print(file_name, '\t', data_path) n_loading_directions = 10 diff --git a/eg3_hierarchical_sampling.py b/eg3_hierarchical_sampling.py index 1020857..e5bfb9f 100644 --- a/eg3_hierarchical_sampling.py +++ b/eg3_hierarchical_sampling.py @@ -13,11 +13,11 @@ np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[6]) + 'sampling_alphas')(microstructures[-1]) print(file_name, '\t', data_path) n_loading_directions = 1 -n_hierarchical_levels = 5 +n_hierarchical_levels = 2 test_temperatures = np.linspace(temp1, temp2, num=n_tests) test_alphas = np.linspace(0, 1, num=n_tests) diff --git a/microstructures.py b/microstructures.py index 2447e07..4f67c40 100644 --- a/microstructures.py +++ b/microstructures.py @@ -120,4 +120,11 @@ np.asarray([0., 0.72727273, 0.8989899, 0.96969697, 1.]), np.asarray([0., 0.52525253, 0.72727273, 0.8989899, 0.96969697, 1.]) ], dtype=object) +}, { + 'data_path': '/ms_1p/dset0_sim', + 'file_name': path("input/striped_normal_4x4x4_plastic.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 10, + 'sampling_alphas': None }] From 97aa0dffec5a29f5e315993e5844e101d30f379c Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Sat, 27 May 2023 10:53:33 +0200 Subject: [PATCH 09/30] testing --- eg0_affine_thermoelastic_solver.py | 7 ++ eg4_hierarchical_sampling_efficient.py | 17 ++-- eg8_plot_localization.py | 24 ++++++ eg9_plastic_modes_example.py | 2 + utilities.py | 115 ++++++++++++++++++++++--- 5 files changed, 143 insertions(+), 22 deletions(-) diff --git a/eg0_affine_thermoelastic_solver.py b/eg0_affine_thermoelastic_solver.py index 29195bb..6d8a579 100644 --- a/eg0_affine_thermoelastic_solver.py +++ b/eg0_affine_thermoelastic_solver.py @@ -17,6 +17,13 @@ mesh, samples = read_h5(file_name, data_path, temperatures) + print(mesh.keys()) + print(samples[0].keys()) + print(samples[0]['strain_localization'].shape) + print(samples[0]['mat_stiffness'].shape) + print(samples[0]['plastic_modes'].shape) + #print(mesh) + #break for sample in samples: verify_data(mesh, sample) diff --git a/eg4_hierarchical_sampling_efficient.py b/eg4_hierarchical_sampling_efficient.py index f31e2c2..7016fbc 100644 --- a/eg4_hierarchical_sampling_efficient.py +++ b/eg4_hierarchical_sampling_efficient.py @@ -12,7 +12,7 @@ np.random.seed(0) # np.set_printoptions(precision=3) -for ms_id in [6, 7, 8, 9]: +for ms_id in [7, 8, 9]: file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', 'sampling_alphas')(microstructures[ms_id]) @@ -36,17 +36,18 @@ global_gradient = mesh['global_gradient'] n_gp = mesh['n_integration_points'] n_phases = len(np.unique(mat_id)) - n_modes = refs[0]['strain_localization'].shape[-1] + N_modes = refs[0]['strain_localization'].shape[2] - 7 # extract temperature dependent data from the reference solutions # such as: material stiffness and thermal strain at each temperature and for all phases Erefs = np.zeros((n_tests, *refs[0]['strain_localization'].shape)) # n_tests x n_phases x 6 x 6 ref_Cs = np.zeros((n_tests, *refs[0]['mat_stiffness'].shape)) # n_tests x n_phases x 6 x 6 ref_epss = np.zeros((n_tests, *refs[0]['mat_thermal_strain'].shape)) # n_tests x n_phases x 6 x 1 - effSref = np.zeros((n_tests, strain_dof, n_modes)) + effSref = np.zeros((n_tests, strain_dof, N_modes + 7)) # n_tests x 6 x (N + 7) normalization_factor_mech = np.zeros((n_tests)) plastic_modes = refs[0]['plastic_modes'] # temperature independent for idx, alpha in enumerate(test_alphas): + print(idx) Erefs[idx] = refs[idx]['strain_localization'] ref_Cs[idx] = refs[idx]['mat_stiffness'] ref_epss[idx] = refs[idx]['mat_thermal_strain'] @@ -109,7 +110,7 @@ current_sampling_id = alphas_indexing[idx] K0, K1, F0, F1, F2, F3, S001, S101, S103, S002, S102, S104 = update_affine_decomposition( - E01s[current_sampling_id], sampling_C, sampling_eps, plastic_modes, n_modes, n_phases, + E01s[current_sampling_id], sampling_C, sampling_eps, plastic_modes, N_modes, n_phases, n_gp, strain_dof, mat_id, n_gauss) @@ -121,15 +122,15 @@ # C, eps = opt4(sampling_C, sampling_eps, ref_Cs[idx], ref_epss[idx]) _, effSopt = interpolate_fluctuation_modes(E01s[current_sampling_id], C, eps, plastic_modes, mat_id, n_gauss, strain_dof, - n_modes, n_gp) + N_modes, n_gp) elif speed == 1: # TODO verify the result when plasticity is on effSopt = effective_stress_localization(E01s[current_sampling_id], phi, ref_Cs[idx], ref_epss[idx], plastic_modes, mat_id, - n_gauss, n_gp, strain_dof, n_modes) + n_gauss, n_gp, strain_dof, N_modes) elif speed == 2: # TODO verify the result when plasticity is on - # matches the result from interpolate_fluctuation_modes with a difference + # matches the result from interpolate_fluctuatioN_modes with a difference # that depends on using ref_Cs[idx],ref_epss[idx] instead of alphas effSopt, phi = effective_S(phi, S001, S101, S103, S002, S102, S104, alpha_C, np.squeeze(alpha_eps, axis=-1), np.squeeze(alpha_C_eps, axis=-1)) @@ -137,7 +138,7 @@ raise NotImplementedError() if not given_alpha_levels: - Eopt4 = transform_strain_localization(E01s[current_sampling_id], phi, n_gp, strain_dof, n_modes) + Eopt4 = transform_strain_localization(E01s[current_sampling_id], phi, n_gp, strain_dof, N_modes) Sopt4 = construct_stress_localization(Eopt4, ref_Cs[idx], ref_epss[idx], plastic_modes, mat_id, n_gauss, strain_dof) # effSopt = volume_average(Sopt4) diff --git a/eg8_plot_localization.py b/eg8_plot_localization.py index 5a92306..c73e7f5 100644 --- a/eg8_plot_localization.py +++ b/eg8_plot_localization.py @@ -9,6 +9,30 @@ from microstructures import * from utilities import read_h5, construct_stress_localization +################ + + + + stress_localization = np.empty_like(strain_localization) + strain_localization_transp = ... + I = np.eye(strain_dof) + for gp_id in prange(strain_localization.shape[0]): + phase_id = mat_id[gp_id // n_gauss] + stress_localization[gp_id] = strain_localization_transp[gp_id] @ mat_stiffness[phase_id] @ (plastic_modes - eigen_strains) + A = volume_average(stress_localization) + + D0 = volume_average(inner_product((plastic_modes - eigen_strains), eigen_strains)) + + K0 = -volume_average(inner_product(plastic_modes, K @ eigen_strains)) + K = k * K0 + + D = D0 + K + + R = volume_average(thermal_stresses @ (plastic_modes - eigen_strains)) / delta_theta + + +########### + np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" diff --git a/eg9_plastic_modes_example.py b/eg9_plastic_modes_example.py index 8dd09a5..8e09407 100644 --- a/eg9_plastic_modes_example.py +++ b/eg9_plastic_modes_example.py @@ -58,5 +58,7 @@ print('tau_theta.shape:', tau_theta.shape) print('C_bar.shape:', C_bar.shape) +# TODO: compute system matrices for multiple intermediate temperatures in an efficient way + # TODO: save system matrices for multiple temperatures as tabular data save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar) diff --git a/utilities.py b/utilities.py index 2e7e7f9..1e73591 100644 --- a/utilities.py +++ b/utilities.py @@ -7,6 +7,10 @@ import scipy.sparse from numba import jit, prange from sympy import symbols, lambdify, Array +from operator import itemgetter +from optimize_alpha import opt4 +from interpolate_fluctuation_modes import interpolate_fluctuation_modes +from microstructures import * plt.rcParams.update({ 'font.size': 8, @@ -94,7 +98,7 @@ def voxel_quadrature(discretisation, strain_dof=6, nodal_dof=3): return gradient_operators, integration_weights -def read_h5(file_name, data_path, temperatures, get_mesh=True): +def read_h5(file_name, data_path, temperatures, get_mesh=True, dummy_plastic_data=True): """ Read an H5 file that contains responses of simulated microstructures :param file_name: e.g. "input/simple_3d_rve_combo.h5" @@ -104,7 +108,7 @@ def read_h5(file_name, data_path, temperatures, get_mesh=True): mesh: dictionary that contains microstructural details such as volume fraction, voxel type, ... samples: list of simulation results at each temperature """ - axis_order = [0, 2, 1] # n_gauss x strain_dof x (N + 7) (N + 7 = 6 mechanical + N plastic + 1 thermal expansion) + axis_order = [0, 2, 1] # n_gauss x strain_dof x (N_modes + 7) (N_modes + 7 = 6 mechanical + N_modes plastic + 1 thermal expansion) samples = [] with h5py.File(file_name, 'r') as file: @@ -149,7 +153,12 @@ def read_h5(file_name, data_path, temperatures, get_mesh=True): if 'plastic_modes' in file[f'{data_path}'].keys(): sample['plastic_modes'] = file[f'{data_path}/plastic_modes'][:].transpose(axis_order) else: - sample['plastic_modes'] = np.zeros((*sample['strain_localization'].shape[:2], 0)) + # sample['plastic_modes'] = np.zeros((*sample['strain_localization'].shape[:2], 0)) + sample['plastic_modes'] = create_dummy_plastic_modes(*sample['strain_localization'].shape[:2], N_modes=13) + sample['strain_localization'] = create_dummy_plastic_strain_localization(sample['strain_localization'], N_modes=13) + if mesh['vox_type'] == 'combo': + sample['combo_strain_loc0'] = create_dummy_plastic_strain_localization(sample['combo_strain_loc0'], N_modes=13) + sample['combo_strain_loc1'] = create_dummy_plastic_strain_localization(sample['combo_strain_loc1'], N_modes=13) if get_mesh: mesh['volume_fraction'] = file[f'{data_path}'].attrs['combo_volume_fraction'] @@ -245,15 +254,17 @@ def verify_data(mesh, sample): # - C @ eff_plastic_strain # eff_plastic_strain is not stored because it depends on the macroscopic strain err = lambda x, y: np.mean(la.norm(x - y) / la.norm(y)) - assert err(eff_thermoelastic_stiffness, - np.vstack((eff_stiffness, -eff_stiffness @ eff_thermal_strain)).T) < convergence_tolerance, \ - 'incompatibility between stress_localization and effective quantities' + # TODO: reenable assert when using real data + #assert err(eff_thermoelastic_stiffness, + # np.vstack((eff_stiffness, -eff_stiffness @ eff_thermal_strain)).T) < convergence_tolerance, \ + # 'incompatibility between stress_localization and effective quantities' with np.printoptions(precision=4, suppress=True, formatter={'float': '{:>2.2e}'.format}, linewidth=100): print('\n', abs_err) - assert la.norm(residual, np.inf) / sample['normalization_factor_mech'] < 10 * convergence_tolerance, \ - 'stress field is not statically admissible' + # TODO: reenable assert when using real data + #assert la.norm(residual, np.inf) / sample['normalization_factor_mech'] < 10 * convergence_tolerance, \ + # 'stress field is not statically admissible' stress_localization0, stress_localization1, combo_stress_loc0, combo_stress_loc1 = construct_stress_localization_phases( strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, combo_strain_loc0, combo_strain_loc1, mesh) @@ -269,9 +280,10 @@ def verify_data(mesh, sample): vol_frac0 = mesh['volume_fraction'][0] vol_frac1 = mesh['volume_fraction'][1] - assert err(average_stress, \ - vol_frac0 * average_stress_0 + vol_frac1 * average_stress_1) < convergence_tolerance, \ - 'phasewise volume average is not admissible' + # TODO: reenable assert when using real data + #assert err(average_stress, \ + # vol_frac0 * average_stress_0 + vol_frac1 * average_stress_1) < convergence_tolerance, \ + # 'phasewise volume average is not admissible' def compute_residual(stress, dof, n_elements, element_dof, n_gauss, assembly_idx, gradient_operators_times_w): @@ -394,6 +406,8 @@ def construct_stress_localization_phases(strain_localization, mat_stiffness, mat for idx in range(len(mesh['combo_idx'])): stiffness_idx = idx + 2 P = np.hstack([-I, mat_thermal_strain[stiffness_idx]]) + # TODO: do we need separate plastic modes for each material phase? + P = np.hstack((-I, mat_thermal_strain[stiffness_idx], plastic_modes[stiffness_idx // 2])) combo_stress_loc0[idx] = mat_stiffness[0] @ combo_strain_loc0[idx] - mat_stiffness[stiffness_idx] @ P combo_stress_loc1[idx] = mat_stiffness[1] @ combo_strain_loc1[idx] - mat_stiffness[stiffness_idx] @ P return stress_localization0, stress_localization1, combo_stress_loc0, combo_stress_loc1 @@ -456,6 +470,32 @@ def norm_2(a): return np.sqrt(inner_product(a, a)) +def create_dummy_plastic_snapshots(n_integration_points, strain_dof, n_frames=100): + """ + TODO: remove when FANS can compute plastic snapshots + """ + # plastic_snapshots = np.random.rand(n_integration_points, strain_dof, n_frames) + plastic_snapshots = np.random.rand(n_integration_points, strain_dof)[:, :, np.newaxis] * np.random.rand(n_frames) \ + + 1e-2 * np.random.rand(n_integration_points, strain_dof, n_frames) + return plastic_snapshots + + +def create_dummy_plastic_modes(n_integration_points, strain_dof, N_modes): + """ + TODO: remove when FANS can compute plastic snapshots + """ + plastic_modes = np.random.rand(n_integration_points, strain_dof, N_modes) + return plastic_modes + + +def create_dummy_plastic_strain_localization(strain_localization, N_modes): + E_eps = strain_localization[:, :, :6] + E_xi = np.random.rand(*strain_localization.shape[:2], N_modes) + E_theta = np.expand_dims(strain_localization[:, :, -1], axis=2) + strain_localization = np.concatenate([E_eps, E_xi, E_theta], axis=2) + return strain_localization + + def read_snapshots(file_name, data_path, temperatures): """ Read an H5 file that contains responses of simulated microstructures @@ -469,9 +509,7 @@ def read_snapshots(file_name, data_path, temperatures): # TODO: read snapshots from H5 file. Because of the sheer amount of data it may be better to use a separate h5 file for the snapshots. # For now, use dummy data: n_integration_points, strain_dof, n_frames = 512, 6, 100 - # plastic_snapshots = np.random.rand(n_integration_points, strain_dof, n_frames) - plastic_snapshots = np.random.rand(n_integration_points, strain_dof)[:, :, np.newaxis] * np.random.rand(n_frames) \ - + 1e-2 * np.random.rand(n_integration_points, strain_dof, n_frames) + plastic_snapshots = create_dummy_plastic_modes(n_integration_points, strain_dof, n_frames) # TODO: Reorder snapshots as follows: | 1st strain path: last timestep to first timestep | 2nd strain path: last timestep to first timestep | ... # or: reorder snapshots already in FANS? return plastic_snapshots @@ -561,6 +599,55 @@ def mode_processing(strain_localization, mat_stiffness, mat_thermal_strain, plas return A_bar, D_xi, tau_theta, C_bar +def compute_tabular_data_for_ms(ms_id): + """ + Perform `compute_tabular_data` for microstructure with id `ms_id` + """ + file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', + 'sampling_alphas')(microstructures[7]) + test_temperatures = np.linspace(temp1, temp2, num=n_tests) + test_alphas = np.linspace(0, 1, num=n_tests) + + mesh, ref = read_h5(file_name, data_path, test_temperatures) # TODO: remove? + _, samples = read_h5(file_name, data_path, temperatures) + + +def compute_tabular_data(samples, mesh, temp1, temp2, dns_alphas, temperatures): + """ + """ + mat_id = mesh['mat_id'] + n_gauss = mesh['n_gauss'] + strain_dof = mesh['strain_dof'] + global_gradient = mesh['global_gradient'] + n_gp = mesh['n_integration_points'] + n_phases = len(np.unique(mat_id)) + n_modes = samples[0]['strain_localization'].shape[-1] + interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) + dns_temperatures = interpolate_temp(temp1, temp2, dns_alphas) + for idx in enumerate(dns_alphas): + temperature = temperatures[idx] # TODO: does not work? + + upper_bound = np.searchsorted(dns_alphas, alpha) + id1 = upper_bound if upper_bound > 0 else 1 + id0 = id1 - 1 + + E0 = samples[id0]['strain_localization'] + E1 = samples[id1]['strain_localization'] + E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) + + sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) + sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) + plastic_modes = samples[idx]['plastic_modes'] # TODO: does exist? + normalization_factor_mech = samples[idx]['normalization_factor_mech'] # TODO: does exist? + + # interpolated quantities using an implicit interpolation scheme with four DOF + approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) + Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + effSopt = volume_average(Sopt4) + + def save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar): """ Save tabular data From 623397e0cb892183b197fcfcb2d156d4eb5d4ba3 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Fri, 9 Jun 2023 18:51:49 +0200 Subject: [PATCH 10/30] test on plastic striped_normal_4x4x4 RVE --- eg0_affine_thermoelastic_solver.py | 2 +- eg1_approximation_of_mat_properties.py | 2 + eg2_compare_approximations.py | 6 + eg3_hierarchical_sampling.py | 2 + eg4_hierarchical_sampling_efficient.py | 41 +++--- eg9_plastic_modes_example.py | 36 +++-- interpolate_fluctuation_modes.py | 37 ++--- material_parameters.py | 2 +- utilities.py | 196 ++++++++++++++++++------- 9 files changed, 215 insertions(+), 109 deletions(-) diff --git a/eg0_affine_thermoelastic_solver.py b/eg0_affine_thermoelastic_solver.py index 6d8a579..92b1394 100644 --- a/eg0_affine_thermoelastic_solver.py +++ b/eg0_affine_thermoelastic_solver.py @@ -7,7 +7,7 @@ from microstructures import * from utilities import verify_data, read_h5 -for microstructure in microstructures: +for microstructure in microstructures[-2:]: file_name, data_path, temp1, temp2 = itemgetter('file_name', 'data_path', 'temp1', 'temp2')(microstructure) diff --git a/eg1_approximation_of_mat_properties.py b/eg1_approximation_of_mat_properties.py index 1613e66..8feb476 100644 --- a/eg1_approximation_of_mat_properties.py +++ b/eg1_approximation_of_mat_properties.py @@ -6,6 +6,8 @@ from material_parameters import * from optimize_alpha import naive, opt1, opt2, opt4 from utilities import plot_and_save, cm +from matplotlib import rc +rc('text', usetex=False) temp1 = 300 temp2 = 1300 diff --git a/eg2_compare_approximations.py b/eg2_compare_approximations.py index 4440b7e..18b517f 100644 --- a/eg2_compare_approximations.py +++ b/eg2_compare_approximations.py @@ -7,8 +7,11 @@ from interpolate_fluctuation_modes import interpolate_fluctuation_modes from microstructures import * +from material_parameters import * from optimize_alpha import opt1, opt2, opt4, naive from utilities import read_h5, construct_stress_localization, volume_average, compute_residual_efficient +from matplotlib import rc +rc('text', usetex=False) np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', @@ -54,6 +57,9 @@ Eref = ref[idx]['strain_localization'] ref_C = ref[idx]['mat_stiffness'] ref_eps = ref[idx]['mat_thermal_strain'] + ref_C_ = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) + ref_eps_ = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) + print(np.linalg.norm(ref_C - ref_C_), np.linalg.norm(ref_eps - ref_eps_)) plastic_modes = ref[idx]['plastic_modes'] normalization_factor_mech = ref[idx]['normalization_factor_mech'] diff --git a/eg3_hierarchical_sampling.py b/eg3_hierarchical_sampling.py index e5bfb9f..f28efe8 100644 --- a/eg3_hierarchical_sampling.py +++ b/eg3_hierarchical_sampling.py @@ -10,6 +10,8 @@ from optimize_alpha import opt4 from utilities import read_h5, construct_stress_localization, volume_average, compute_residual_efficient, \ compute_err_indicator_efficient +from matplotlib import rc +rc('text', usetex=False) np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', diff --git a/eg4_hierarchical_sampling_efficient.py b/eg4_hierarchical_sampling_efficient.py index 7016fbc..8a67346 100644 --- a/eg4_hierarchical_sampling_efficient.py +++ b/eg4_hierarchical_sampling_efficient.py @@ -12,7 +12,7 @@ np.random.seed(0) # np.set_printoptions(precision=3) -for ms_id in [7, 8, 9]: +for ms_id in [0]: file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', 'sampling_alphas')(microstructures[ms_id]) @@ -117,25 +117,26 @@ phi = get_phi(K0, K1, F0, F1, F2, F3, alpha_C, alpha_eps, alpha_C_eps) speed = 1 - if speed == 0: - C, eps = ref_Cs[idx], ref_epss[idx] - # C, eps = opt4(sampling_C, sampling_eps, ref_Cs[idx], ref_epss[idx]) - _, effSopt = interpolate_fluctuation_modes(E01s[current_sampling_id], C, eps, plastic_modes, mat_id, n_gauss, - strain_dof, - N_modes, n_gp) - elif speed == 1: - # TODO verify the result when plasticity is on - effSopt = effective_stress_localization(E01s[current_sampling_id], phi, ref_Cs[idx], ref_epss[idx], plastic_modes, - mat_id, - n_gauss, n_gp, strain_dof, N_modes) - elif speed == 2: - # TODO verify the result when plasticity is on - # matches the result from interpolate_fluctuatioN_modes with a difference - # that depends on using ref_Cs[idx],ref_epss[idx] instead of alphas - effSopt, phi = effective_S(phi, S001, S101, S103, S002, S102, S104, alpha_C, np.squeeze(alpha_eps, axis=-1), - np.squeeze(alpha_C_eps, axis=-1)) - else: - raise NotImplementedError() + # if speed == 0: + C, eps = ref_Cs[idx], ref_epss[idx] + # C, eps = opt4(sampling_C, sampling_eps, ref_Cs[idx], ref_epss[idx]) + _, effSopt = interpolate_fluctuation_modes(E01s[current_sampling_id], C, eps, plastic_modes, mat_id, n_gauss, + strain_dof, + N_modes, n_gp) + #elif speed == 1: + # TODO verify the result when plasticity is on + effSopt1 = effective_stress_localization(E01s[current_sampling_id], phi, ref_Cs[idx], ref_epss[idx], plastic_modes, + mat_id, + n_gauss, n_gp, strain_dof, N_modes) + #elif speed == 2: + # TODO verify the result when plasticity is on + # matches the result from interpolate_fluctuatioN_modes with a difference + # that depends on using ref_Cs[idx],ref_epss[idx] instead of alphas + effSopt2, phi2 = effective_S(phi, S001, S101, S103, S002, S102, S104, alpha_C, np.squeeze(alpha_eps, axis=-1), + np.squeeze(alpha_C_eps, axis=-1)) + #else: + # raise NotImplementedError() + print(np.linalg.norm(effSopt - effSopt1)) if not given_alpha_levels: Eopt4 = transform_strain_localization(E01s[current_sampling_id], phi, n_gp, strain_dof, N_modes) diff --git a/eg9_plastic_modes_example.py b/eg9_plastic_modes_example.py index 8e09407..3009796 100644 --- a/eg9_plastic_modes_example.py +++ b/eg9_plastic_modes_example.py @@ -6,8 +6,9 @@ import numpy.linalg as la import matplotlib.pyplot as plt +import time from microstructures import * -from utilities import read_h5, read_snapshots, mode_identification, mode_processing, save_tabular_data +from utilities import read_h5, read_snapshots, mode_identification, mode_identification_svd, compute_tabular_data, save_tabular_data np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( @@ -15,9 +16,9 @@ )(microstructures[0]) print(file_name, "\t", data_path) -temperatures = np.linspace(temp1, temp2, num=n_tests) +sample_temperatures = np.linspace(temp1, temp2, num=n_tests) -mesh, samples = read_h5(file_name, data_path, temperatures) +mesh, samples = read_h5(file_name, data_path, sample_temperatures) mat_id = mesh["mat_id"] n_gauss = mesh["n_gauss"] strain_dof = mesh["strain_dof"] @@ -31,13 +32,18 @@ #%% Mode identification # TODO: Read plastic snapshots from h5 file -plastic_snapshots = read_snapshots(file_name, data_path, temperatures) +plastic_snapshots = read_snapshots(file_name, data_path) print('plastic_snapshots.shape:', plastic_snapshots.shape) +# Mode identification using SVD +r_min = 1e-8 +plastic_modes_svd = mode_identification_svd(plastic_snapshots, r_min) +print('plastic_modes_svd.shape:', plastic_modes_svd.shape) + # Mode identification using POD -r_min = 6e-5 -plastic_modes = mode_identification(plastic_snapshots, r_min) -print('plastic_modes.shape:', plastic_modes.shape) +r_min = 1e-8 +plastic_modes_pod = mode_identification(plastic_snapshots, r_min) +print('plastic_modes_pod.shape:', plastic_modes_pod.shape) # TODO: save identified plastic modes to h5 file @@ -45,20 +51,26 @@ # TODO: compute system matrices for multiple temperatures in an efficient way sample = samples[0] # For now, choose one arbitrary sample -# plastic_modes = sample['plastic_modes'] (until we have real data) +plastic_modes = sample['plastic_modes'] N_modes = plastic_modes.shape[2] strain_localization = sample["strain_localization"] # Add dummy data to strain_localization until we have real data: -strain_localization = np.concatenate([strain_localization, np.random.rand(n_integration_points, strain_dof, N_modes)], axis=2) +# strain_localization = np.concatenate([strain_localization, np.random.rand(n_integration_points, strain_dof, N_modes)], axis=2) mat_stiffness = sample["mat_stiffness"] mat_thermal_strain = sample["mat_thermal_strain"] -A_bar, D_xi, tau_theta, C_bar = mode_processing(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mesh) +#A_bar, D_xi, tau_theta, C_bar = compute_ntfa_matrices(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mesh) + +# TODO: compute system matrices for multiple intermediate temperatures in an efficient way +n_temp = 1000 +temperatures = np.linspace(temp1, temp2, num=n_temp) +start_time = time.time() +A_bar, D_xi, tau_theta, C_bar = compute_tabular_data(samples, mesh, temperatures) +elapsed_time = time.time() - start_time +print(f'Computed tabular data for {n_temp} temperatures in {elapsed_time}s') print('A_bar.shape:', A_bar.shape) print('D_xi.shape:', D_xi.shape) print('tau_theta.shape:', tau_theta.shape) print('C_bar.shape:', C_bar.shape) -# TODO: compute system matrices for multiple intermediate temperatures in an efficient way - # TODO: save system matrices for multiple temperatures as tabular data save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar) diff --git a/interpolate_fluctuation_modes.py b/interpolate_fluctuation_modes.py index d10e232..e0cdaa3 100644 --- a/interpolate_fluctuation_modes.py +++ b/interpolate_fluctuation_modes.py @@ -4,16 +4,17 @@ @jit(nopython=True, cache=True, parallel=True, nogil=True) def interpolate_fluctuation_modes(E01, mat_stiffness, mat_thermal_strain, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, n_gp): - K = np.zeros((2 * n_modes, 2 * n_modes)) - F = np.zeros((2 * n_modes, n_modes)) - E_approx = np.zeros((n_gp, strain_dof, n_modes)) + K = np.zeros((2 * (n_modes + 7), 2 * (n_modes + 7))) + F = np.zeros((2 * (n_modes + 7), (n_modes + 7))) + E_approx = np.zeros((n_gp, strain_dof, n_modes + 7)) I = np.eye(strain_dof) - S_average = np.zeros((n_modes, n_modes)) + S_average = np.zeros((n_modes + 7, n_modes + 7)) for gp_id in prange(n_gp): phase_id = mat_id[gp_id // n_gauss] - P = np.hstack((-I, mat_thermal_strain[phase_id], plastic_modes[gp_id])) + P = np.hstack((-I, mat_thermal_strain[phase_id], plastic_modes[gp_id])) # existing code + # P = np.hstack((-I, plastic_modes[gp_id], mat_thermal_strain[phase_id])) # why not this way? E01t_C = E01[gp_id].T @ mat_stiffness[phase_id] @@ -34,18 +35,18 @@ def update_affine_decomposition(E01, sampling_C, sampling_eps, plastic_modes, n_ n_gauss): I = np.eye(strain_dof) - K0 = np.zeros((2 * n_modes, 2 * n_modes)) - K1 = np.zeros((n_phases, 2 * n_modes, 2 * n_modes)) - F0 = np.zeros((2 * n_modes, n_modes)) - F1 = np.zeros((n_phases, 2 * n_modes, n_modes)) - F2, F3 = [np.zeros((n_phases, 2 * n_modes, 1)) for _ in range(2)] + K0 = np.zeros((2 * (n_modes + 7), 2 * (n_modes + 7))) + K1 = np.zeros((n_phases, 2 * (n_modes + 7), 2 * (n_modes + 7))) + F0 = np.zeros((2 * (n_modes + 7), (n_modes + 7))) + F1 = np.zeros((n_phases, 2 * (n_modes + 7), (n_modes + 7))) + F2, F3 = [np.zeros((n_phases, 2 * (n_modes + 7), 1)) for _ in range(2)] quick = True dim0 = 1 if quick else n_gp - S001 = np.zeros((dim0, strain_dof, 2 * n_modes)) - S002 = np.zeros((dim0, n_phases, strain_dof, 2 * n_modes)) - S101 = np.zeros((dim0, strain_dof, n_modes)) - S102 = np.zeros((dim0, n_phases, strain_dof, n_modes)) + S001 = np.zeros((dim0, strain_dof, 2 * (n_modes + 7))) + S002 = np.zeros((dim0, n_phases, strain_dof, 2 * (n_modes + 7))) + S101 = np.zeros((dim0, strain_dof, n_modes + 7)) + S102 = np.zeros((dim0, n_phases, strain_dof, n_modes + 7)) S103 = np.zeros((dim0, n_phases, strain_dof, 1)) S104 = np.zeros((dim0, n_phases, strain_dof, 1)) @@ -95,7 +96,7 @@ def update_affine_decomposition(E01, sampling_C, sampling_eps, plastic_modes, n_ else: return K0, K1, F0, F1, F2, F3, S001, S101, S103, S002, S102, S104 -# @jit(nopython=True, cache=True, parallel=True, nogil=True) +@jit(nopython=True, cache=True, parallel=True, nogil=True) def get_phi(K0, K1, F0, F1, F2, F3, alpha_C, alpha_eps, alpha_C_eps): K = K0 + np.sum(K1 * alpha_C, 0) # sum over the phases F = F0 + np.sum(F1 * alpha_C, 0) @@ -103,7 +104,7 @@ def get_phi(K0, K1, F0, F1, F2, F3, alpha_C, alpha_eps, alpha_C_eps): return np.linalg.lstsq(K, F, rcond=-1)[0] -# @jit(nopython=True, cache=True, parallel=True, nogil=True) +@jit(nopython=True, cache=True, parallel=True, nogil=True) def effective_S(phi, S001, S101, S103, S002, S102, S104, alpha_C, alpha_eps2D, alpha_C_eps2D): S00 = S001 + np.sum(S002 * alpha_C, 0) # sum over the phases S11 = S101 + np.sum(S102 * alpha_C, 0) @@ -112,7 +113,7 @@ def effective_S(phi, S001, S101, S103, S002, S102, S104, alpha_C, alpha_eps2D, a @jit(nopython=True, cache=True, parallel=True, fastmath=True, nogil=True) def transform_strain_localization(E01, phi, n_gp, strain_dof, n_modes): - E_approx = np.zeros((n_gp, strain_dof, n_modes)) + E_approx = np.zeros((n_gp, strain_dof, n_modes + 7)) for gp_id in prange(n_gp): E_approx[gp_id] = E01[gp_id] @ phi return E_approx @@ -120,7 +121,7 @@ def transform_strain_localization(E01, phi, n_gp, strain_dof, n_modes): @jit(nopython=True, cache=True, parallel=True, nogil=True) def effective_stress_localization(E01, phi, mat_stiffness, mat_thermal_strain, plastic_modes, mat_id, n_gauss, n_gp, strain_dof, n_modes): - S_average = np.zeros((strain_dof, n_modes)) + S_average = np.zeros((strain_dof, n_modes + 7)) I = np.eye(strain_dof) for gp_id in prange(n_gp): phase_id = mat_id[gp_id // n_gauss] diff --git a/material_parameters.py b/material_parameters.py index 8dcb4d5..9c59985 100644 --- a/material_parameters.py +++ b/material_parameters.py @@ -8,7 +8,7 @@ import numpy as np import scipy.integrate as integrate -from utilities import cm +cm = 1 / 2.54 # centimeters in inches I2 = np.asarray([1., 1., 1., 0, 0, 0]) I4 = np.eye(6) diff --git a/utilities.py b/utilities.py index 1e73591..90934b0 100644 --- a/utilities.py +++ b/utilities.py @@ -11,6 +11,7 @@ from optimize_alpha import opt4 from interpolate_fluctuation_modes import interpolate_fluctuation_modes from microstructures import * +from material_parameters import * plt.rcParams.update({ 'font.size': 8, @@ -108,7 +109,7 @@ def read_h5(file_name, data_path, temperatures, get_mesh=True, dummy_plastic_dat mesh: dictionary that contains microstructural details such as volume fraction, voxel type, ... samples: list of simulation results at each temperature """ - axis_order = [0, 2, 1] # n_gauss x strain_dof x (N_modes + 7) (N_modes + 7 = 6 mechanical + N_modes plastic + 1 thermal expansion) + axis_order = [0, 2, 1] # n_gauss x strain_dof x (n_modes + 7) (n_modes + 7 = 6 mechanical + n_modes plastic + 1 thermal expansion) samples = [] with h5py.File(file_name, 'r') as file: @@ -153,12 +154,12 @@ def read_h5(file_name, data_path, temperatures, get_mesh=True, dummy_plastic_dat if 'plastic_modes' in file[f'{data_path}'].keys(): sample['plastic_modes'] = file[f'{data_path}/plastic_modes'][:].transpose(axis_order) else: - # sample['plastic_modes'] = np.zeros((*sample['strain_localization'].shape[:2], 0)) - sample['plastic_modes'] = create_dummy_plastic_modes(*sample['strain_localization'].shape[:2], N_modes=13) - sample['strain_localization'] = create_dummy_plastic_strain_localization(sample['strain_localization'], N_modes=13) - if mesh['vox_type'] == 'combo': - sample['combo_strain_loc0'] = create_dummy_plastic_strain_localization(sample['combo_strain_loc0'], N_modes=13) - sample['combo_strain_loc1'] = create_dummy_plastic_strain_localization(sample['combo_strain_loc1'], N_modes=13) + sample['plastic_modes'] = np.zeros((*sample['strain_localization'].shape[:2], 0)) + # sample['plastic_modes'] = create_dummy_plastic_modes(*sample['strain_localization'].shape[:2], N_modes=13) + # sample['strain_localization'] = create_dummy_plastic_strain_localization(sample['strain_localization'], N_modes=13) + # if mesh['vox_type'] == 'combo': + # sample['combo_strain_loc0'] = create_dummy_plastic_strain_localization(sample['combo_strain_loc0'], N_modes=13) + # sample['combo_strain_loc1'] = create_dummy_plastic_strain_localization(sample['combo_strain_loc1'], N_modes=13) if get_mesh: mesh['volume_fraction'] = file[f'{data_path}'].attrs['combo_volume_fraction'] @@ -254,17 +255,15 @@ def verify_data(mesh, sample): # - C @ eff_plastic_strain # eff_plastic_strain is not stored because it depends on the macroscopic strain err = lambda x, y: np.mean(la.norm(x - y) / la.norm(y)) - # TODO: reenable assert when using real data - #assert err(eff_thermoelastic_stiffness, - # np.vstack((eff_stiffness, -eff_stiffness @ eff_thermal_strain)).T) < convergence_tolerance, \ - # 'incompatibility between stress_localization and effective quantities' + assert err(eff_thermoelastic_stiffness, + np.vstack((eff_stiffness, -eff_stiffness @ eff_thermal_strain)).T) < convergence_tolerance, \ + 'incompatibility between stress_localization and effective quantities' with np.printoptions(precision=4, suppress=True, formatter={'float': '{:>2.2e}'.format}, linewidth=100): print('\n', abs_err) - # TODO: reenable assert when using real data - #assert la.norm(residual, np.inf) / sample['normalization_factor_mech'] < 10 * convergence_tolerance, \ - # 'stress field is not statically admissible' + assert la.norm(residual, np.inf) / sample['normalization_factor_mech'] < 10 * convergence_tolerance, \ + 'stress field is not statically admissible' stress_localization0, stress_localization1, combo_stress_loc0, combo_stress_loc1 = construct_stress_localization_phases( strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, combo_strain_loc0, combo_strain_loc1, mesh) @@ -346,12 +345,12 @@ def compute_err_indicator_efficient(stress_loc, global_gradient): return global_gradient.T @ stress_loc.reshape(global_gradient.shape[0], -1) -# @jit(nopython=True, cache=True, parallel=True, nogil=True) +@jit(nopython=True, cache=True, parallel=True, nogil=True) def cheap_err_indicator(stress_loc, global_gradient): return la.norm(global_gradient.T @ np.sum(stress_loc, -1).flatten()) -#@jit(nopython=True, cache=True, parallel=True, nogil=True) +@jit(nopython=True, cache=True, parallel=True, nogil=True) def construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mat_id, n_gauss, strain_dof): """ @@ -496,20 +495,22 @@ def create_dummy_plastic_strain_localization(strain_localization, N_modes): return strain_localization -def read_snapshots(file_name, data_path, temperatures): +def read_snapshots(file_name, data_path): """ Read an H5 file that contains responses of simulated microstructures :param file_name: e.g. "input/simple_3d_rve_combo.h5" :param data_path: the path to the simulation results within the h5 file, e.g. '/ms_1p/dset0_sim' - :param temperatures: all responses corresponding to these temperatures will be read :return: strain_snapshots: plastic strain snapshots eps_p with shape (n_integration_points, strain_dof, n_frames) """ # TODO: read snapshots from H5 file. Because of the sheer amount of data it may be better to use a separate h5 file for the snapshots. + plastic_snapshots = None + with h5py.File(file_name, 'r') as file: + plastic_snapshots = np.transpose(file[f'{data_path}/plastic_strains'][:], (0, 2, 1)) # For now, use dummy data: - n_integration_points, strain_dof, n_frames = 512, 6, 100 - plastic_snapshots = create_dummy_plastic_modes(n_integration_points, strain_dof, n_frames) + # n_integration_points, strain_dof, n_frames = 512, 6, 100 + # plastic_snapshots = create_dummy_plastic_modes(n_integration_points, strain_dof, n_frames) # TODO: Reorder snapshots as follows: | 1st strain path: last timestep to first timestep | 2nd strain path: last timestep to first timestep | ... # or: reorder snapshots already in FANS? return plastic_snapshots @@ -522,32 +523,50 @@ def mode_identification(plastic_snapshots, r_min): with shape (n_integration_points, strain_dof, n_frames) :param r_min: stop criterion :return: - plastic_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, N_modes) + plastic_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, n_modes) """ n_integration_points, strain_dof, n_frames = plastic_snapshots.shape - N_modes = 0 - plastic_modes = np.zeros((n_integration_points, strain_dof, N_modes)) + n_modes = 0 + plastic_modes = np.zeros((n_integration_points, strain_dof, n_modes)) for i in range(n_frames): eps_i = plastic_snapshots[:, :, i] r = volume_average(inner_product(eps_i, eps_i)) # TODO: average only over Omega_p? - k = np.zeros(N_modes) # Coefficients k_j - for j in range(N_modes): + k = np.zeros(n_modes) # Coefficients k_j + for j in range(n_modes): k[j] = volume_average(inner_product(eps_i, plastic_modes[:, :, j])) r = r - k[j]**2 if r < r_min: break if r > r_min: - N_modes = N_modes + 1 # increment number of modes + n_modes = n_modes + 1 # increment number of modes # Generate new strain mode: plastic_mode = (eps_i - np.tensordot(k, plastic_modes, axes=(0,2))) / np.sqrt(r) plastic_modes = np.concatenate([plastic_modes, np.expand_dims(plastic_mode, 2)], axis=2) # Renormalize all modes: - for i in range(N_modes): - plastic_modes[:, :, i] = plastic_modes[:, :, i] / volume_average(norm_2(plastic_modes[:, :, i])) + for i in range(n_modes): + plastic_modes[:, :, i] = plastic_modes[:, :, i] / volume_average(norm_2(plastic_modes[:, :, i])) # TODO: average only over specific phase! return plastic_modes -def mode_processing(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mesh): +def mode_identification_svd(plastic_snapshots, r_min=1e-8): + """ + Identification of plastic strain modes µ using POD and renormalization + :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) + with shape (n_integration_points, strain_dof, n_frames) + :param r_min: stop criterion + :return: + plastic_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, n_modes) + """ + n_integration_points, strain_dof, n_frames = plastic_snapshots.shape + plastic_snapshots_rs = plastic_snapshots.transpose(1, 0, 2).reshape((strain_dof * n_integration_points, n_frames)) + u, s, v = np.linalg.svd(plastic_snapshots_rs, full_matrices=False) + s = s / s[0] + n_modes = np.argwhere(s > r_min).size + plastic_modes = u[:, :n_modes].reshape((strain_dof, n_integration_points, n_modes)).transpose(1, 0, 2) + return plastic_modes + + +def compute_ntfa_matrices(stress_localization, plastic_modes, thermal_strain, mesh): """ Processing of the plastic strain modes µ to compute the matrices A_bar, D_xi, C_bar and the vector tau_theta as tabular data at given temperatures @@ -570,17 +589,12 @@ def mode_processing(strain_localization, mat_stiffness, mat_thermal_strain, plas C_bar with shape (strain_dof, strain_dof) """ strain_dof = mesh['strain_dof'] - n_gauss = mesh['n_gauss'] mat_id = mesh['mat_id'] - N_modes = plastic_modes.shape[2] - - # compute stress localization operator S (including plastic contributions) - stress_localization = construct_stress_localization(strain_localization, mat_stiffness, mat_thermal_strain, \ - plastic_modes, mat_id, n_gauss, strain_dof) + n_modes = plastic_modes.shape[2] # slice stress localization operator S into S_eps, S_xi, S_theta S_eps = stress_localization[:, :, :strain_dof] - S_xi = stress_localization[:, :, strain_dof:(strain_dof + N_modes)] + S_xi = stress_localization[:, :, strain_dof:(strain_dof + n_modes)] S_theta = stress_localization[:, :, -1] # volume averaging S_eps -> C_bar, S_xi -> A_bar, S_theta -> tau_theta @@ -588,31 +602,86 @@ def mode_processing(strain_localization, mat_stiffness, mat_thermal_strain, plas A_bar = volume_average(S_xi) tau_theta = volume_average(S_theta) - # Compute D_xi - # plastic_modes has shape (n_integration_points, strain_dof, N_modes) -> transpose - # S_xi has shape (n_integration_points, strain_dof, N_modes) - # Then, D_xi has shape (N_modes, N_modes) - D_xi = -volume_average(plastic_modes.transpose((0, 2, 1)) @ S_xi) + # Compute D_xi, D_theta, tau_hat by volume averaging after matrix multiplication + # plastic_modes has shape (n_integration_points, strain_dof, n_modes) -> transpose + # plastic_modes_T has shape (n_integration_points, n_modes, strain_dof) + # thermal_strain has shape (n_integration_points, strain_dof, n_modes) -> transpose + # S_xi has shape (n_integration_points, strain_dof, n_modes) -> D_xi has shape (n_modes, n_modes) + # S_theta has shape (n_integration_points, strain_dof, 1) -> D_theta has shape (N_modes, N_modes) + plastic_modes_T = plastic_modes.transpose((0, 2, 1)) + thermal_strain_T = thermal_strain.reshape((1, -1)) + D_xi = -volume_average(plastic_modes_T @ S_xi) + # D_theta = -volume_average(thermal_strain_T @ S_theta) + # tau_hat = -volume_average(plastic_modes_T @ S_theta) # Should A_bar be transposed before saving data? return A_bar, D_xi, tau_theta, C_bar -def compute_tabular_data_for_ms(ms_id): +def compute_tabular_data_for_ms(ms_id, temperatures): """ Perform `compute_tabular_data` for microstructure with id `ms_id` """ file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[7]) - test_temperatures = np.linspace(temp1, temp2, num=n_tests) - test_alphas = np.linspace(0, 1, num=n_tests) + 'sampling_alphas')(microstructures[ms_id]) + sample_temperatures = np.linspace(temp1, temp2, num=n_tests) + sample_alphas = np.linspace(0, 1, num=n_tests) + mesh, samples = read_h5(file_name, data_path, sample_temperatures) + return compute_tabular_data(samples, mesh, temperatures) - mesh, ref = read_h5(file_name, data_path, test_temperatures) # TODO: remove? - _, samples = read_h5(file_name, data_path, temperatures) + +#@jit(nopython=True, cache=True, parallel=True, nogil=True) +def compute_tabular_data(samples, mesh, temperatures): + """ + """ + mat_id = mesh['mat_id'] + n_gauss = mesh['n_gauss'] + strain_dof = mesh['strain_dof'] + global_gradient = mesh['global_gradient'] + n_gp = mesh['n_integration_points'] + n_phases = len(np.unique(mat_id)) + n_modes = samples[0]['plastic_modes'].shape[-1] + n_temps = len(temperatures) + A_bar = np.zeros((strain_dof, n_modes, n_temps)) + D_xi = np.zeros((n_modes, n_modes, n_temps)) + tau_theta = np.zeros((strain_dof, n_temps)) + C_bar = np.zeros((strain_dof, strain_dof, n_temps)) + # interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) + # dns_temperatures = interpolate_temp(temp1, temp2, sample_alphas) + sample_temperatures = np.array([sample['temperature'] for sample in samples]) + temp1, temp2 = min(sample_temperatures), max(sample_temperatures) + sample_alphas = (sample_temperatures - temp1) / (temp2 - temp1) + for idx in prange(n_temps): + temperature = temperatures[idx] + alpha = (temperature - temp1) / (temp2 - temp1) + upper_bound = np.searchsorted(sample_alphas, alpha) + id1 = upper_bound if upper_bound > 0 else 1 + id0 = id1 - 1 + + E0 = samples[id0]['strain_localization'] + E1 = samples[id1]['strain_localization'] + E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) + + sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) + sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) + plastic_modes = samples[id0]['plastic_modes'] # TODO: does exist? + # normalization_factor_mech = samples[idx]['normalization_factor_mech'] # TODO: does exist? + ref_C = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) + ref_eps = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) + + # interpolated quantities using an implicit interpolation scheme with four DOF + approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) + Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + # effSopt = volume_average(Sopt4) + A_bar[:,:,idx], D_xi[:,:,idx], tau_theta[:,idx], C_bar[:,:,idx] = compute_ntfa_matrices(Sopt4, plastic_modes, approx_eps, mesh) + return A_bar, D_xi, tau_theta, C_bar -def compute_tabular_data(samples, mesh, temp1, temp2, dns_alphas, temperatures): +@jit(nopython=True, cache=True, parallel=True, nogil=True) +def compute_tabular_data_efficient(samples, mesh, temperatures): """ """ mat_id = mesh['mat_id'] @@ -622,12 +691,21 @@ def compute_tabular_data(samples, mesh, temp1, temp2, dns_alphas, temperatures): n_gp = mesh['n_integration_points'] n_phases = len(np.unique(mat_id)) n_modes = samples[0]['strain_localization'].shape[-1] - interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) - dns_temperatures = interpolate_temp(temp1, temp2, dns_alphas) - for idx in enumerate(dns_alphas): - temperature = temperatures[idx] # TODO: does not work? - - upper_bound = np.searchsorted(dns_alphas, alpha) + n_temps = len(temperatures) + A_bar = np.zeros((strain_dof, n_modes - 7, n_temps)) + D_xi = np.zeros((n_modes - 7, n_modes - 7, n_temps)) + tau_theta = np.zeros((strain_dof, n_temps)) + C_bar = np.zeros((strain_dof, strain_dof, n_temps)) + # interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) + # dns_temperatures = interpolate_temp(temp1, temp2, sample_alphas) + sample_temperatures = np.array([sample['temperature'] for sample in samples]) + temp1, temp2 = min(sample_temperatures), max(sample_temperatures) + sample_alphas = (sample_temperatures - temp1) / (temp2 - temp1) + # for idx, temperature in enumerate(temperatures): + for idx in prange(n_temps): + temperature = temperatures[idx] + alpha = (temperature - temp1) / (temp2 - temp1) + upper_bound = np.searchsorted(sample_alphas, alpha) id1 = upper_bound if upper_bound > 0 else 1 id0 = id1 - 1 @@ -637,15 +715,19 @@ def compute_tabular_data(samples, mesh, temp1, temp2, dns_alphas, temperatures): sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) - plastic_modes = samples[idx]['plastic_modes'] # TODO: does exist? - normalization_factor_mech = samples[idx]['normalization_factor_mech'] # TODO: does exist? + plastic_modes = samples[id0]['plastic_modes'] # TODO: does exist? + # normalization_factor_mech = samples[idx]['normalization_factor_mech'] # TODO: does exist? + ref_C = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) + ref_eps = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) # interpolated quantities using an implicit interpolation scheme with four DOF approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, n_gp) Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - effSopt = volume_average(Sopt4) + # effSopt = volume_average(Sopt4) + A_bar[:,:,idx], D_xi[:,:,idx], tau_theta[:,idx], C_bar[:,:,idx] = compute_ntfa_matrices(Sopt4, plastic_modes, mesh) + return A_bar, D_xi, tau_theta, C_bar def save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar): From 13fcd2c8da481d91f91698170f56d32382170d5b Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Sat, 10 Jun 2023 23:58:53 +0200 Subject: [PATCH 11/30] Check plastic modes normalization in verify_data --- utilities.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/utilities.py b/utilities.py index 90934b0..1479121 100644 --- a/utilities.py +++ b/utilities.py @@ -279,10 +279,15 @@ def verify_data(mesh, sample): vol_frac0 = mesh['volume_fraction'][0] vol_frac1 = mesh['volume_fraction'][1] - # TODO: reenable assert when using real data - #assert err(average_stress, \ - # vol_frac0 * average_stress_0 + vol_frac1 * average_stress_1) < convergence_tolerance, \ - # 'phasewise volume average is not admissible' + assert err(average_stress, \ + vol_frac0 * average_stress_0 + vol_frac1 * average_stress_1) < convergence_tolerance, \ + 'phasewise volume average is not admissible' + + plastic_modes = sample['plastic_modes'] + n_modes = plastic_modes.shape[-1] + gramian = volume_average(np.einsum('ndi,ndj->nij', plastic_modes, plastic_modes)) + assert np.allclose(gramian, np.diag(np.diag(gramian))), 'plastic modes are not orthogonal' + assert np.allclose([volume_average(norm_2(plastic_modes[:,:,i])) for i in range(n_modes)], vol_frac0), 'plastic modes are not normalized correctly' def compute_residual(stress, dof, n_elements, element_dof, n_gauss, assembly_idx, gradient_operators_times_w): From 409845dea6ff11f415a4433643db0822789bde43 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Sun, 11 Jun 2023 01:44:55 +0200 Subject: [PATCH 12/30] Implement mode identification --- eg0_affine_thermoelastic_solver.py | 15 ++++++------ eg1_approximation_of_mat_properties.py | 2 +- eg2_compare_approximations.py | 4 ++-- ...example.py => eg9_compute_ntfa_matrices.py | 24 +++++++++---------- interpolate_fluctuation_modes.py | 5 ++-- microstructures.py | 7 ++++++ utilities.py | 16 +++++++++---- 7 files changed, 41 insertions(+), 32 deletions(-) rename eg9_plastic_modes_example.py => eg9_compute_ntfa_matrices.py (80%) diff --git a/eg0_affine_thermoelastic_solver.py b/eg0_affine_thermoelastic_solver.py index 92b1394..8a4b4bc 100644 --- a/eg0_affine_thermoelastic_solver.py +++ b/eg0_affine_thermoelastic_solver.py @@ -7,7 +7,7 @@ from microstructures import * from utilities import verify_data, read_h5 -for microstructure in microstructures[-2:]: +for microstructure in microstructures[-1:]: file_name, data_path, temp1, temp2 = itemgetter('file_name', 'data_path', 'temp1', 'temp2')(microstructure) @@ -17,13 +17,12 @@ mesh, samples = read_h5(file_name, data_path, temperatures) - print(mesh.keys()) - print(samples[0].keys()) - print(samples[0]['strain_localization'].shape) - print(samples[0]['mat_stiffness'].shape) - print(samples[0]['plastic_modes'].shape) - #print(mesh) - #break + # print(mesh.keys()) + # print(samples[0].keys()) + print('strain localication shape:', samples[0]['strain_localization'].shape) + print('material stiffness shape:', samples[0]['mat_stiffness'].shape) + print('plastic modes shape:', samples[0]['plastic_modes'].shape) + for sample in samples: verify_data(mesh, sample) diff --git a/eg1_approximation_of_mat_properties.py b/eg1_approximation_of_mat_properties.py index 8feb476..404e891 100644 --- a/eg1_approximation_of_mat_properties.py +++ b/eg1_approximation_of_mat_properties.py @@ -7,7 +7,7 @@ from optimize_alpha import naive, opt1, opt2, opt4 from utilities import plot_and_save, cm from matplotlib import rc -rc('text', usetex=False) +rc('text', usetex=True) temp1 = 300 temp2 = 1300 diff --git a/eg2_compare_approximations.py b/eg2_compare_approximations.py index 18b517f..fc43f80 100644 --- a/eg2_compare_approximations.py +++ b/eg2_compare_approximations.py @@ -11,7 +11,7 @@ from optimize_alpha import opt1, opt2, opt4, naive from utilities import read_h5, construct_stress_localization, volume_average, compute_residual_efficient from matplotlib import rc -rc('text', usetex=False) +rc('text', usetex=True) np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', @@ -29,7 +29,7 @@ strain_dof = mesh['strain_dof'] global_gradient = mesh['global_gradient'] n_gp = mesh['n_integration_points'] -n_modes = ref[0]['strain_localization'].shape[-1] +n_modes = ref[0]['plastic_modes'].shape[-1] _, samples = read_h5(file_name, data_path, [temp1, temp2], get_mesh=False) diff --git a/eg9_plastic_modes_example.py b/eg9_compute_ntfa_matrices.py similarity index 80% rename from eg9_plastic_modes_example.py rename to eg9_compute_ntfa_matrices.py index 3009796..c48562d 100644 --- a/eg9_plastic_modes_example.py +++ b/eg9_compute_ntfa_matrices.py @@ -8,12 +8,12 @@ import matplotlib.pyplot as plt import time from microstructures import * -from utilities import read_h5, read_snapshots, mode_identification, mode_identification_svd, compute_tabular_data, save_tabular_data +from utilities import read_h5, read_snapshots, mode_identification, compute_tabular_data, save_tabular_data np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" -)(microstructures[0]) +)(microstructures[-1]) print(file_name, "\t", data_path) sample_temperatures = np.linspace(temp1, temp2, num=n_tests) @@ -28,23 +28,19 @@ global_gradient = mesh["global_gradient"] n_gp = mesh["n_integration_points"] disc = mesh["combo_discretisation"] +vol_frac = mesh['volume_fraction'][0] #%% Mode identification -# TODO: Read plastic snapshots from h5 file +# Read plastic snapshots from h5 file plastic_snapshots = read_snapshots(file_name, data_path) print('plastic_snapshots.shape:', plastic_snapshots.shape) -# Mode identification using SVD +# Identification of plastic modes r_min = 1e-8 -plastic_modes_svd = mode_identification_svd(plastic_snapshots, r_min) +plastic_modes_svd = mode_identification(plastic_snapshots, vol_frac, r_min) print('plastic_modes_svd.shape:', plastic_modes_svd.shape) -# Mode identification using POD -r_min = 1e-8 -plastic_modes_pod = mode_identification(plastic_snapshots, r_min) -print('plastic_modes_pod.shape:', plastic_modes_pod.shape) - # TODO: save identified plastic modes to h5 file #%% Mode processing to compute system matrices (after eigenstress problems have been solved using FANS) @@ -54,14 +50,16 @@ plastic_modes = sample['plastic_modes'] N_modes = plastic_modes.shape[2] strain_localization = sample["strain_localization"] -# Add dummy data to strain_localization until we have real data: -# strain_localization = np.concatenate([strain_localization, np.random.rand(n_integration_points, strain_dof, N_modes)], axis=2) + +# Compare computed plastic modes with plastic modes from h5 file +assert np.allclose(plastic_modes, plastic_modes_svd), '' + mat_stiffness = sample["mat_stiffness"] mat_thermal_strain = sample["mat_thermal_strain"] #A_bar, D_xi, tau_theta, C_bar = compute_ntfa_matrices(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mesh) # TODO: compute system matrices for multiple intermediate temperatures in an efficient way -n_temp = 1000 +n_temp = 100 temperatures = np.linspace(temp1, temp2, num=n_temp) start_time = time.time() A_bar, D_xi, tau_theta, C_bar = compute_tabular_data(samples, mesh, temperatures) diff --git a/interpolate_fluctuation_modes.py b/interpolate_fluctuation_modes.py index e0cdaa3..f5e20dd 100644 --- a/interpolate_fluctuation_modes.py +++ b/interpolate_fluctuation_modes.py @@ -1,7 +1,7 @@ import numpy as np from numba import jit, prange -@jit(nopython=True, cache=True, parallel=True, nogil=True) +# @jit(nopython=True, cache=True, parallel=True, nogil=True) def interpolate_fluctuation_modes(E01, mat_stiffness, mat_thermal_strain, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, n_gp): K = np.zeros((2 * (n_modes + 7), 2 * (n_modes + 7))) @@ -13,8 +13,7 @@ def interpolate_fluctuation_modes(E01, mat_stiffness, mat_thermal_strain, plasti for gp_id in prange(n_gp): phase_id = mat_id[gp_id // n_gauss] - P = np.hstack((-I, mat_thermal_strain[phase_id], plastic_modes[gp_id])) # existing code - # P = np.hstack((-I, plastic_modes[gp_id], mat_thermal_strain[phase_id])) # why not this way? + P = np.hstack((-I, mat_thermal_strain[phase_id], plastic_modes[gp_id])) E01t_C = E01[gp_id].T @ mat_stiffness[phase_id] diff --git a/microstructures.py b/microstructures.py index 4f67c40..f45eee3 100644 --- a/microstructures.py +++ b/microstructures.py @@ -127,4 +127,11 @@ 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None +}, { + 'data_path': '/ms_1p/dset0_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 10, + 'sampling_alphas': None }] diff --git a/utilities.py b/utilities.py index 1479121..f612488 100644 --- a/utilities.py +++ b/utilities.py @@ -521,9 +521,9 @@ def read_snapshots(file_name, data_path): return plastic_snapshots -def mode_identification(plastic_snapshots, r_min): +def mode_identification_iterative(plastic_snapshots, vol_frac, r_min=1e-8): """ - Identification of plastic strain modes µ using POD and renormalization + Identification of plastic strain modes µ using an iterative algorithm and renormalization :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) with shape (n_integration_points, strain_dof, n_frames) :param r_min: stop criterion @@ -547,13 +547,14 @@ def mode_identification(plastic_snapshots, r_min): # Generate new strain mode: plastic_mode = (eps_i - np.tensordot(k, plastic_modes, axes=(0,2))) / np.sqrt(r) plastic_modes = np.concatenate([plastic_modes, np.expand_dims(plastic_mode, 2)], axis=2) - # Renormalize all modes: + # Renormalize plastic modes for i in range(n_modes): - plastic_modes[:, :, i] = plastic_modes[:, :, i] / volume_average(norm_2(plastic_modes[:, :, i])) # TODO: average only over specific phase! + weighting_factor = vol_frac / volume_average(norm_2(plastic_modes[:, :, i])) + plastic_modes[:, :, i] = plastic_modes[:, :, i] * weighting_factor * np.sign(plastic_modes[0, 0, i]) return plastic_modes -def mode_identification_svd(plastic_snapshots, r_min=1e-8): +def mode_identification(plastic_snapshots, vol_frac, r_min=1e-8): """ Identification of plastic strain modes µ using POD and renormalization :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) @@ -568,6 +569,10 @@ def mode_identification_svd(plastic_snapshots, r_min=1e-8): s = s / s[0] n_modes = np.argwhere(s > r_min).size plastic_modes = u[:, :n_modes].reshape((strain_dof, n_integration_points, n_modes)).transpose(1, 0, 2) + # Renormalize plastic modes + for i in range(n_modes): + weighting_factor = vol_frac / volume_average(norm_2(plastic_modes[:, :, i])) + plastic_modes[:, :, i] = plastic_modes[:, :, i] * weighting_factor * np.sign(plastic_modes[0, 0, i]) return plastic_modes @@ -688,6 +693,7 @@ def compute_tabular_data(samples, mesh, temperatures): @jit(nopython=True, cache=True, parallel=True, nogil=True) def compute_tabular_data_efficient(samples, mesh, temperatures): """ + WIP """ mat_id = mesh['mat_id'] n_gauss = mesh['n_gauss'] From adf5c64f04489bb1f4eb676e0f8094d59b9690a3 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Sun, 11 Jun 2023 02:09:38 +0200 Subject: [PATCH 13/30] Change order of thermal and plastic modes --- utilities.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/utilities.py b/utilities.py index f612488..0aa5ed6 100644 --- a/utilities.py +++ b/utilities.py @@ -109,7 +109,7 @@ def read_h5(file_name, data_path, temperatures, get_mesh=True, dummy_plastic_dat mesh: dictionary that contains microstructural details such as volume fraction, voxel type, ... samples: list of simulation results at each temperature """ - axis_order = [0, 2, 1] # n_gauss x strain_dof x (n_modes + 7) (n_modes + 7 = 6 mechanical + n_modes plastic + 1 thermal expansion) + axis_order = [0, 2, 1] # n_gauss x strain_dof x (n_modes + 7) (n_modes + 7 = 6 mechanical + 1 thermal expansion + n_modes plastic) samples = [] with h5py.File(file_name, 'r') as file: @@ -602,22 +602,22 @@ def compute_ntfa_matrices(stress_localization, plastic_modes, thermal_strain, me mat_id = mesh['mat_id'] n_modes = plastic_modes.shape[2] - # slice stress localization operator S into S_eps, S_xi, S_theta + # slice stress localization operator S into S_eps, S_theta, S_xi S_eps = stress_localization[:, :, :strain_dof] - S_xi = stress_localization[:, :, strain_dof:(strain_dof + n_modes)] - S_theta = stress_localization[:, :, -1] + S_theta = stress_localization[:, :, strain_dof] + S_xi = stress_localization[:, :, strain_dof+1:] - # volume averaging S_eps -> C_bar, S_xi -> A_bar, S_theta -> tau_theta + # volume averaging S_eps -> C_bar, S_theta -> tau_theta, S_xi -> A_bar C_bar = volume_average(S_eps) - A_bar = volume_average(S_xi) tau_theta = volume_average(S_theta) + A_bar = volume_average(S_xi) # Compute D_xi, D_theta, tau_hat by volume averaging after matrix multiplication # plastic_modes has shape (n_integration_points, strain_dof, n_modes) -> transpose # plastic_modes_T has shape (n_integration_points, n_modes, strain_dof) # thermal_strain has shape (n_integration_points, strain_dof, n_modes) -> transpose # S_xi has shape (n_integration_points, strain_dof, n_modes) -> D_xi has shape (n_modes, n_modes) - # S_theta has shape (n_integration_points, strain_dof, 1) -> D_theta has shape (N_modes, N_modes) + # S_theta has shape (n_integration_points, strain_dof, 1) -> D_theta has shape (n_modes, n_modes) plastic_modes_T = plastic_modes.transpose((0, 2, 1)) thermal_strain_T = thermal_strain.reshape((1, -1)) D_xi = -volume_average(plastic_modes_T @ S_xi) From a70d657614f459e5b1e5fb1867c6b2c3816cf3a9 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Sun, 11 Jun 2023 16:09:22 +0200 Subject: [PATCH 14/30] Save tabular data --- eg0_affine_thermoelastic_solver.py | 2 +- eg2_compare_approximations.py | 2 +- eg9_compute_ntfa_matrices.py | 97 ++++++++++++++---------------- microstructures.py | 7 +++ utilities.py | 71 ++++++++++++++-------- 5 files changed, 100 insertions(+), 79 deletions(-) diff --git a/eg0_affine_thermoelastic_solver.py b/eg0_affine_thermoelastic_solver.py index 8a4b4bc..e06b954 100644 --- a/eg0_affine_thermoelastic_solver.py +++ b/eg0_affine_thermoelastic_solver.py @@ -7,7 +7,7 @@ from microstructures import * from utilities import verify_data, read_h5 -for microstructure in microstructures[-1:]: +for microstructure in microstructures[-2:]: file_name, data_path, temp1, temp2 = itemgetter('file_name', 'data_path', 'temp1', 'temp2')(microstructure) diff --git a/eg2_compare_approximations.py b/eg2_compare_approximations.py index fc43f80..25856e0 100644 --- a/eg2_compare_approximations.py +++ b/eg2_compare_approximations.py @@ -19,7 +19,7 @@ print(file_name, '\t', data_path) n_loading_directions = 10 -n_tests = 10 +n_tests = 100 test_temperatures = np.linspace(temp1, temp2, num=n_tests) test_alphas = np.linspace(0, 1, num=n_tests) diff --git a/eg9_compute_ntfa_matrices.py b/eg9_compute_ntfa_matrices.py index c48562d..3464661 100644 --- a/eg9_compute_ntfa_matrices.py +++ b/eg9_compute_ntfa_matrices.py @@ -11,64 +11,59 @@ from utilities import read_h5, read_snapshots, mode_identification, compute_tabular_data, save_tabular_data np.random.seed(0) -file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( - "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" -)(microstructures[-1]) -print(file_name, "\t", data_path) +for microstructure in microstructures[-2:]: + file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( + "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" + )(microstructure) + print(file_name, "\t", data_path) -sample_temperatures = np.linspace(temp1, temp2, num=n_tests) + sample_temperatures = np.linspace(temp1, temp2, num=n_tests) -mesh, samples = read_h5(file_name, data_path, sample_temperatures) -mat_id = mesh["mat_id"] -n_gauss = mesh["n_gauss"] -strain_dof = mesh["strain_dof"] -nodal_dof = mesh["nodal_dof"] -n_elements = mesh["n_elements"] -n_integration_points = mesh["n_integration_points"] -global_gradient = mesh["global_gradient"] -n_gp = mesh["n_integration_points"] -disc = mesh["combo_discretisation"] -vol_frac = mesh['volume_fraction'][0] + mesh, samples = read_h5(file_name, data_path, sample_temperatures) + mat_id = mesh["mat_id"] + n_gauss = mesh["n_gauss"] + strain_dof = mesh["strain_dof"] + nodal_dof = mesh["nodal_dof"] + n_elements = mesh["n_elements"] + n_integration_points = mesh["n_integration_points"] + global_gradient = mesh["global_gradient"] + n_gp = mesh["n_integration_points"] + disc = mesh["combo_discretisation"] + vol_frac = mesh['volume_fraction'][0] -#%% Mode identification + # Mode identification -# Read plastic snapshots from h5 file -plastic_snapshots = read_snapshots(file_name, data_path) -print('plastic_snapshots.shape:', plastic_snapshots.shape) + # Read plastic snapshots from h5 file + plastic_snapshots = read_snapshots(file_name, data_path) + print('plastic_snapshots.shape:', plastic_snapshots.shape) -# Identification of plastic modes -r_min = 1e-8 -plastic_modes_svd = mode_identification(plastic_snapshots, vol_frac, r_min) -print('plastic_modes_svd.shape:', plastic_modes_svd.shape) + # Identification of plastic modes + r_min = 1e-8 + plastic_modes_svd = mode_identification(plastic_snapshots, vol_frac, r_min) + print('plastic_modes_svd.shape:', plastic_modes_svd.shape) -# TODO: save identified plastic modes to h5 file + # Compare computed plastic modes with plastic modes from h5 file + plastic_modes = samples[0]['plastic_modes'] + assert np.allclose(plastic_modes, plastic_modes_svd), 'Identified plastic modes do not match plastic modes in h5 file' -#%% Mode processing to compute system matrices (after eigenstress problems have been solved using FANS) + # Mode processing to compute system matrices (after eigenstress problems have been solved using FANS) -# TODO: compute system matrices for multiple temperatures in an efficient way -sample = samples[0] # For now, choose one arbitrary sample -plastic_modes = sample['plastic_modes'] -N_modes = plastic_modes.shape[2] -strain_localization = sample["strain_localization"] + n_temp = 100 + temperatures = np.linspace(temp1, temp2, num=n_temp) + start_time = time.time() + # TODO: compute system matrices for multiple intermediate temperatures in an efficient way + A_bar, D_xi, tau_theta, C_bar = compute_tabular_data(samples, mesh, temperatures) + elapsed_time = time.time() - start_time + print(f'Computed tabular data for {n_temp} temperatures in {elapsed_time}s') + print('A_bar.shape:', A_bar.shape) + print('D_xi.shape:', D_xi.shape) + print('tau_theta.shape:', tau_theta.shape) + print('C_bar.shape:', C_bar.shape) -# Compare computed plastic modes with plastic modes from h5 file -assert np.allclose(plastic_modes, plastic_modes_svd), '' + # Save system matrices for multiple temperatures as tabular data + save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar) + # Tabular data is saved to the input h5 file and can be copied to a new h5 file using e.g. + # h5copy -i input/file.h5 -o input/file_ntfa.h5 -s ms_1p/dset0_ntfa -d ms_1p/dset0_ntfa -p -mat_stiffness = sample["mat_stiffness"] -mat_thermal_strain = sample["mat_thermal_strain"] -#A_bar, D_xi, tau_theta, C_bar = compute_ntfa_matrices(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mesh) - -# TODO: compute system matrices for multiple intermediate temperatures in an efficient way -n_temp = 100 -temperatures = np.linspace(temp1, temp2, num=n_temp) -start_time = time.time() -A_bar, D_xi, tau_theta, C_bar = compute_tabular_data(samples, mesh, temperatures) -elapsed_time = time.time() - start_time -print(f'Computed tabular data for {n_temp} temperatures in {elapsed_time}s') -print('A_bar.shape:', A_bar.shape) -print('D_xi.shape:', D_xi.shape) -print('tau_theta.shape:', tau_theta.shape) -print('C_bar.shape:', C_bar.shape) - -# TODO: save system matrices for multiple temperatures as tabular data -save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar) +#%% Compare interpolated NTFA matrices with exact NTFA matrices +# TODO: compute errors diff --git a/microstructures.py b/microstructures.py index f45eee3..fa1a01d 100644 --- a/microstructures.py +++ b/microstructures.py @@ -134,4 +134,11 @@ 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None +}, { + 'data_path': '/ms_1p/dset0_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_100samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 100, + 'sampling_alphas': None }] diff --git a/utilities.py b/utilities.py index 0aa5ed6..436cce4 100644 --- a/utilities.py +++ b/utilities.py @@ -1,5 +1,5 @@ import contextlib - +import re import h5py import matplotlib.pyplot as plt import numpy as np @@ -285,7 +285,7 @@ def verify_data(mesh, sample): plastic_modes = sample['plastic_modes'] n_modes = plastic_modes.shape[-1] - gramian = volume_average(np.einsum('ndi,ndj->nij', plastic_modes, plastic_modes)) + gramian = volume_average(np.einsum('ijk,ijl->ikl', plastic_modes, plastic_modes)) assert np.allclose(gramian, np.diag(np.diag(gramian))), 'plastic modes are not orthogonal' assert np.allclose([volume_average(norm_2(plastic_modes[:,:,i])) for i in range(n_modes)], vol_frac0), 'plastic modes are not normalized correctly' @@ -662,31 +662,35 @@ def compute_tabular_data(samples, mesh, temperatures): sample_temperatures = np.array([sample['temperature'] for sample in samples]) temp1, temp2 = min(sample_temperatures), max(sample_temperatures) sample_alphas = (sample_temperatures - temp1) / (temp2 - temp1) + plastic_modes = samples[0]['plastic_modes'] for idx in prange(n_temps): temperature = temperatures[idx] - alpha = (temperature - temp1) / (temp2 - temp1) - upper_bound = np.searchsorted(sample_alphas, alpha) - id1 = upper_bound if upper_bound > 0 else 1 - id0 = id1 - 1 - - E0 = samples[id0]['strain_localization'] - E1 = samples[id1]['strain_localization'] - E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) - - sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) - sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) - plastic_modes = samples[id0]['plastic_modes'] # TODO: does exist? - # normalization_factor_mech = samples[idx]['normalization_factor_mech'] # TODO: does exist? ref_C = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) ref_eps = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) - - # interpolated quantities using an implicit interpolation scheme with four DOF - approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, - n_gp) - Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - # effSopt = volume_average(Sopt4) - A_bar[:,:,idx], D_xi[:,:,idx], tau_theta[:,idx], C_bar[:,:,idx] = compute_ntfa_matrices(Sopt4, plastic_modes, approx_eps, mesh) + alpha = (temperature - temp1) / (temp2 - temp1) + upper_bound = np.searchsorted(sample_alphas, alpha) + if np.floor(alpha) == alpha: + # sample for given temperature exists, no need for interpolation + id = upper_bound + C, eps = ref_C, ref_eps + E = samples[id]['strain_localization'] + S = construct_stress_localization(E, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + else: + id1 = upper_bound if upper_bound > 0 else 1 + id0 = id1 - 1 + + E0 = samples[id0]['strain_localization'] + E1 = samples[id1]['strain_localization'] + E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) + + sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) + sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) + + # interpolated quantities using an implicit interpolation scheme with four DOF + C, eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) + E, _ = interpolate_fluctuation_modes(E01, C, eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, n_gp) + S = construct_stress_localization(E, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + A_bar[:, :, idx], D_xi[:, :, idx], tau_theta[:, idx], C_bar[:, :, idx] = compute_ntfa_matrices(S, plastic_modes, eps, mesh) return A_bar, D_xi, tau_theta, C_bar @@ -745,6 +749,21 @@ def save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta """ Save tabular data :param file_name: e.g. "input/simple_3d_rve_combo.h5" - :param ...: - """ - pass + :param data_path: + :param temperatures: + :param A_bar: tabular data for A_bar with shape (strain_dof, strain_dof, n_temp) + :param D_xi: tabular data for D_xi with shape (n_modes, n_modes, n_temp) + :param tau_theta: tabular data for tau_theta with shape (strain_dof, n_temp) + :param C_bar: tabular data for C_bar with shape (strain_dof, strain_dof, n_temp) + """ + with h5py.File(file_name, 'a') as file: + dset_sim = file[data_path] + dset = dset_sim.parent + ntfa_path = re.sub('_sim$', '_ntfa', dset_sim.name) + dset_ntfa = dset.create_group(ntfa_path) + [dset_ntfa.attrs.create(key, value) for key, value in dset_sim.attrs.items()] + dset_temperatures = dset_ntfa.create_dataset('temperatures', data=temperatures) + dset_A_bar = dset_ntfa.create_dataset('A_bar', data=A_bar) + dset_D_xi = dset_ntfa.create_dataset('D_xi', data=D_xi) + dset_tau_theta = dset_ntfa.create_dataset('tau_theta', data=tau_theta) + dset_C_bar = dset_ntfa.create_dataset('C_bar', data=C_bar) From 1df632e9a47c079d1295267574c2a3793d8f28f7 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Sun, 11 Jun 2023 16:16:49 +0200 Subject: [PATCH 15/30] Delete h5 group if it already exists --- utilities.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utilities.py b/utilities.py index 436cce4..81c8d3b 100644 --- a/utilities.py +++ b/utilities.py @@ -760,6 +760,9 @@ def save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta dset_sim = file[data_path] dset = dset_sim.parent ntfa_path = re.sub('_sim$', '_ntfa', dset_sim.name) + if ntfa_path in file: + # Delete h5 group with tabular data if it already exists + del file[ntfa_path] dset_ntfa = dset.create_group(ntfa_path) [dset_ntfa.attrs.create(key, value) for key, value in dset_sim.attrs.items()] dset_temperatures = dset_ntfa.create_dataset('temperatures', data=temperatures) From 2482bb8bc8f7f7f3378222221e823da94443db28 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Tue, 13 Jun 2023 01:12:09 +0200 Subject: [PATCH 16/30] Change computation of ntfa matrices --- eg9_compute_ntfa_matrices.py | 14 +++--- utilities.py | 86 ++++++++++++++++++++++-------------- 2 files changed, 60 insertions(+), 40 deletions(-) diff --git a/eg9_compute_ntfa_matrices.py b/eg9_compute_ntfa_matrices.py index 3464661..93a5cff 100644 --- a/eg9_compute_ntfa_matrices.py +++ b/eg9_compute_ntfa_matrices.py @@ -46,22 +46,24 @@ plastic_modes = samples[0]['plastic_modes'] assert np.allclose(plastic_modes, plastic_modes_svd), 'Identified plastic modes do not match plastic modes in h5 file' - # Mode processing to compute system matrices (after eigenstress problems have been solved using FANS) + # Mode processing to compute system matrices - n_temp = 100 + n_temp = 1000 temperatures = np.linspace(temp1, temp2, num=n_temp) start_time = time.time() # TODO: compute system matrices for multiple intermediate temperatures in an efficient way - A_bar, D_xi, tau_theta, C_bar = compute_tabular_data(samples, mesh, temperatures) + C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta = compute_tabular_data(samples, mesh, temperatures) elapsed_time = time.time() - start_time print(f'Computed tabular data for {n_temp} temperatures in {elapsed_time}s') + print('C_bar.shape:', C_bar.shape) + print('tau_theta.shape:', tau_theta.shape) print('A_bar.shape:', A_bar.shape) + print('tau_xi.shape:', tau_xi.shape) print('D_xi.shape:', D_xi.shape) - print('tau_theta.shape:', tau_theta.shape) - print('C_bar.shape:', C_bar.shape) + print('D_theta.shape:', D_theta.shape) # Save system matrices for multiple temperatures as tabular data - save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar) + save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta) # Tabular data is saved to the input h5 file and can be copied to a new h5 file using e.g. # h5copy -i input/file.h5 -o input/file_ntfa.h5 -s ms_1p/dset0_ntfa -d ms_1p/dset0_ntfa -p diff --git a/utilities.py b/utilities.py index 81c8d3b..31d3c59 100644 --- a/utilities.py +++ b/utilities.py @@ -576,12 +576,14 @@ def mode_identification(plastic_snapshots, vol_frac, r_min=1e-8): return plastic_modes -def compute_ntfa_matrices(stress_localization, plastic_modes, thermal_strain, mesh): +def compute_ntfa_matrices(strain_localization, stress_localization, plastic_modes, thermal_strain, mesh): """ Processing of the plastic strain modes µ to compute the matrices A_bar, D_xi, C_bar and the vector tau_theta as tabular data at given temperatures :param strain_localization: strain localization 3D array - with shape (n_integration_points, strain_dof, 7) + with shape (n_integration_points, strain_dof, 7 + n_modes) + :param stress_localization: stress localization 3D array + with shape (n_integration_points, strain_dof, 7 + n_modes) :param mat_stiffness: stiffness tensors of the phases with shape (n_phases, strain_dof, strain_dof) :param mat_id: material phase identification @@ -593,40 +595,48 @@ def compute_ntfa_matrices(stress_localization, plastic_modes, thermal_strain, me with shape (n_integration_points, strain_dof, N_modes) :param ...: :return: - A_bar with shape (strain_dof, strain_dof) - D_xi with shape (strain_dof, N_modes) - tau_theta with shape (strain_dof,) C_bar with shape (strain_dof, strain_dof) + tau_theta with shape (strain_dof,) + A_bar with shape (strain_dof, strain_dof) + tau_xi with shape (n_modes,) + D_xi with shape (strain_dof, n_modes) + D_theta with shape (strain_dof, n_modes) """ strain_dof = mesh['strain_dof'] mat_id = mesh['mat_id'] n_modes = plastic_modes.shape[2] + # slice strain localization operator E into E_eps, E_theta, E_xi + E_eps = strain_localization[:, :, :strain_dof] + E_theta = strain_localization[:, :, strain_dof] + E_xi = strain_localization[:, :, strain_dof + 1:] + + # slice stress localization operator S into S_eps, S_theta, S_xi S_eps = stress_localization[:, :, :strain_dof] S_theta = stress_localization[:, :, strain_dof] - S_xi = stress_localization[:, :, strain_dof+1:] + S_xi = stress_localization[:, :, strain_dof + 1:] - # volume averaging S_eps -> C_bar, S_theta -> tau_theta, S_xi -> A_bar - C_bar = volume_average(S_eps) - tau_theta = volume_average(S_theta) - A_bar = volume_average(S_xi) + I = np.eye(6) + # Compute C_bar via < (E_eps + I).T @ S_eps > + C_bar = volume_average((E_eps + I).transpose((0, 2, 1)) @ S_eps) - # Compute D_xi, D_theta, tau_hat by volume averaging after matrix multiplication - # plastic_modes has shape (n_integration_points, strain_dof, n_modes) -> transpose - # plastic_modes_T has shape (n_integration_points, n_modes, strain_dof) - # thermal_strain has shape (n_integration_points, strain_dof, n_modes) -> transpose - # S_xi has shape (n_integration_points, strain_dof, n_modes) -> D_xi has shape (n_modes, n_modes) - # S_theta has shape (n_integration_points, strain_dof, 1) -> D_theta has shape (n_modes, n_modes) - plastic_modes_T = plastic_modes.transpose((0, 2, 1)) - thermal_strain_T = thermal_strain.reshape((1, -1)) - D_xi = -volume_average(plastic_modes_T @ S_xi) - # D_theta = -volume_average(thermal_strain_T @ S_theta) - # tau_hat = -volume_average(plastic_modes_T @ S_theta) + # Compute tau_theta via < (E_eps + I).T @ S_theta > + tau_theta = volume_average(np.einsum('nij,nj->ni', (E_eps + I).transpose((0, 2, 1)), S_theta)) - # Should A_bar be transposed before saving data? + # Compute A_bar via < (E_eps + I).T @ S_eps > + A_bar = volume_average((E_eps + I).transpose((0, 2, 1)) @ S_xi) - return A_bar, D_xi, tau_theta, C_bar + # Compute tau_xi via < (E_theta - P_theta).T @ S_xi > + tau_xi = volume_average(np.einsum('ni,nij->nj', E_theta - thermal_strain, S_xi)) + + # Compute D_xi via < (E_xi - P_xi).T @ S_xi > + D_xi = volume_average((E_xi - plastic_modes).transpose((0, 2, 1)) @ S_xi) + + # Compute D_theta via < (E_theta - P_theta).T @ S_theta > + D_theta = volume_average(np.einsum('ni,ni->n', E_theta - thermal_strain, S_theta)) + + return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta def compute_tabular_data_for_ms(ms_id, temperatures): @@ -653,10 +663,12 @@ def compute_tabular_data(samples, mesh, temperatures): n_phases = len(np.unique(mat_id)) n_modes = samples[0]['plastic_modes'].shape[-1] n_temps = len(temperatures) + C_bar = np.zeros((strain_dof, strain_dof, n_temps)) + tau_theta = np.zeros((strain_dof, n_temps)) A_bar = np.zeros((strain_dof, n_modes, n_temps)) + tau_xi = np.zeros((n_modes, n_temps)) D_xi = np.zeros((n_modes, n_modes, n_temps)) - tau_theta = np.zeros((strain_dof, n_temps)) - C_bar = np.zeros((strain_dof, strain_dof, n_temps)) + D_theta = np.zeros((n_temps)) # interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) # dns_temperatures = interpolate_temp(temp1, temp2, sample_alphas) sample_temperatures = np.array([sample['temperature'] for sample in samples]) @@ -690,15 +702,15 @@ def compute_tabular_data(samples, mesh, temperatures): C, eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) E, _ = interpolate_fluctuation_modes(E01, C, eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, n_gp) S = construct_stress_localization(E, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - A_bar[:, :, idx], D_xi[:, :, idx], tau_theta[:, idx], C_bar[:, :, idx] = compute_ntfa_matrices(S, plastic_modes, eps, mesh) - return A_bar, D_xi, tau_theta, C_bar + C_bar[:, :, idx], tau_theta[:, idx], A_bar[:, :, idx], tau_xi[:, idx], D_xi[:, :, idx], D_theta[idx] = \ + compute_ntfa_matrices(E, S, plastic_modes, eps[0,:,0], mesh) + return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta @jit(nopython=True, cache=True, parallel=True, nogil=True) def compute_tabular_data_efficient(samples, mesh, temperatures): """ WIP - """ mat_id = mesh['mat_id'] n_gauss = mesh['n_gauss'] strain_dof = mesh['strain_dof'] @@ -742,19 +754,23 @@ def compute_tabular_data_efficient(samples, mesh, temperatures): Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) # effSopt = volume_average(Sopt4) A_bar[:,:,idx], D_xi[:,:,idx], tau_theta[:,idx], C_bar[:,:,idx] = compute_ntfa_matrices(Sopt4, plastic_modes, mesh) - return A_bar, D_xi, tau_theta, C_bar + return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta + """ + pass -def save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta, C_bar): +def save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta): """ Save tabular data :param file_name: e.g. "input/simple_3d_rve_combo.h5" :param data_path: :param temperatures: + :param C_bar: tabular data for C_bar with shape (strain_dof, strain_dof, n_temp) + :param tau_theta: tabular data for tau_theta with shape (strain_dof, n_temp) :param A_bar: tabular data for A_bar with shape (strain_dof, strain_dof, n_temp) + :param tau_xi: tabular data for tau_xi with shape (n_modes, n_temp) :param D_xi: tabular data for D_xi with shape (n_modes, n_modes, n_temp) - :param tau_theta: tabular data for tau_theta with shape (strain_dof, n_temp) - :param C_bar: tabular data for C_bar with shape (strain_dof, strain_dof, n_temp) + :param D_xi: tabular data for D_theta with shape (n_temp) """ with h5py.File(file_name, 'a') as file: dset_sim = file[data_path] @@ -766,7 +782,9 @@ def save_tabular_data(file_name, data_path, temperatures, A_bar, D_xi, tau_theta dset_ntfa = dset.create_group(ntfa_path) [dset_ntfa.attrs.create(key, value) for key, value in dset_sim.attrs.items()] dset_temperatures = dset_ntfa.create_dataset('temperatures', data=temperatures) + dset_C_bar = dset_ntfa.create_dataset('C_bar', data=C_bar) + dset_tau_theta = dset_ntfa.create_dataset('tau_theta', data=tau_theta) dset_A_bar = dset_ntfa.create_dataset('A_bar', data=A_bar) + dset_tau_xi = dset_ntfa.create_dataset('tau_xi', data=tau_xi) dset_D_xi = dset_ntfa.create_dataset('D_xi', data=D_xi) - dset_tau_theta = dset_ntfa.create_dataset('tau_theta', data=tau_theta) - dset_C_bar = dset_ntfa.create_dataset('C_bar', data=C_bar) + dset_D_theta = dset_ntfa.create_dataset('D_theta', data=D_theta) From 9690ceaada29083f2825bace64e2f21ec5ed3414 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Tue, 13 Jun 2023 23:47:56 +0200 Subject: [PATCH 17/30] Add hardening to material parameters --- material_parameters.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/material_parameters.py b/material_parameters.py index 9c59985..08d1659 100644 --- a/material_parameters.py +++ b/material_parameters.py @@ -7,6 +7,7 @@ import matplotlib.pyplot as plt import numpy as np import scipy.integrate as integrate +import utilities cm = 1 / 2.54 # centimeters in inches @@ -24,6 +25,7 @@ heat_capacity_cu = lambda x: 2.94929e+03 * x ** 0 + 2.30217e+00 * x ** 1 + -2.95302e-03 * x ** 2 + 1.47057e-06 * x ** 3 cte_cu = lambda x: 1.28170e-05 * x ** 0 + 8.23091e-09 * x ** 1 elastic_modulus_cu = lambda x: 1.35742e+08 * x ** 0 + 5.85757e+03 * x ** 1 + -8.16134e+01 * x ** 2 +hardening_cu = lambda x: 20e+06 * x ** 0 thermal_strain_cu = lambda x: integrate.quad(cte_cu, min_temperature, x)[0] * I2 shear_modulus_cu = lambda x: elastic_modulus_cu(x) / (2. * (1. + poisson_ratio_cu(x))) From cee36ba65fefbec1f5834bcd1190ceb99b4194bd Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Wed, 14 Jun 2023 00:11:56 +0200 Subject: [PATCH 18/30] Compute NTFA matrices --- eg0_affine_thermoelastic_solver.py | 29 --- eg1_approximation_of_mat_properties.py | 126 ---------- eg2_compare_approximations.py | 223 ----------------- eg3_hierarchical_sampling.py | 195 --------------- eg4_hierarchical_sampling_efficient.py | 252 -------------------- eg5_FFANN.py | 147 ------------ eg6_post_process_ann_vs_proposed.py | 122 ---------- eg7_staggered_model_interpolation.py | 81 ------- eg8_plot_localization.py | 153 ------------ eg9_compute_ntfa_matrices.py | 19 +- microstructures.py | 49 ++++ utilities.py | 317 ------------------------- 12 files changed, 60 insertions(+), 1653 deletions(-) delete mode 100644 eg0_affine_thermoelastic_solver.py delete mode 100644 eg1_approximation_of_mat_properties.py delete mode 100644 eg2_compare_approximations.py delete mode 100644 eg3_hierarchical_sampling.py delete mode 100644 eg4_hierarchical_sampling_efficient.py delete mode 100644 eg5_FFANN.py delete mode 100644 eg6_post_process_ann_vs_proposed.py delete mode 100644 eg7_staggered_model_interpolation.py delete mode 100644 eg8_plot_localization.py diff --git a/eg0_affine_thermoelastic_solver.py b/eg0_affine_thermoelastic_solver.py deleted file mode 100644 index e06b954..0000000 --- a/eg0_affine_thermoelastic_solver.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -Load all microstructures and try to reconstruct stress and strain fields and effective properties -""" - -from operator import itemgetter - -from microstructures import * -from utilities import verify_data, read_h5 - -for microstructure in microstructures[-2:]: - - file_name, data_path, temp1, temp2 = itemgetter('file_name', 'data_path', 'temp1', 'temp2')(microstructure) - - print(file_name, '\t', data_path) - - temperatures = np.linspace(temp1, temp2, 2) - - mesh, samples = read_h5(file_name, data_path, temperatures) - - # print(mesh.keys()) - # print(samples[0].keys()) - print('strain localication shape:', samples[0]['strain_localization'].shape) - print('material stiffness shape:', samples[0]['mat_stiffness'].shape) - print('plastic modes shape:', samples[0]['plastic_modes'].shape) - - for sample in samples: - verify_data(mesh, sample) - -print(f'{"done":-^50}') diff --git a/eg1_approximation_of_mat_properties.py b/eg1_approximation_of_mat_properties.py deleted file mode 100644 index 404e891..0000000 --- a/eg1_approximation_of_mat_properties.py +++ /dev/null @@ -1,126 +0,0 @@ -""" -Approximate material properties using various affine approaches -""" -import numpy.linalg as la - -from material_parameters import * -from optimize_alpha import naive, opt1, opt2, opt4 -from utilities import plot_and_save, cm -from matplotlib import rc -rc('text', usetex=True) - -temp1 = 300 -temp2 = 1300 -n_tests = 100 -test_temperatures = np.linspace(temp1, temp2, num=n_tests) -test_alphas = np.linspace(0, 1, num=n_tests) -n_approaches = 5 - -abs_err = lambda x, y: la.norm(x - y) -rel_err = lambda x, y: la.norm(x - y) * 100 / la.norm(y) -err_measure = abs_err - -for mat_id in range(2): - sampling_C = [[stiffness_cu(temp1), stiffness_cu(temp2)], [stiffness_wsc(temp1), stiffness_wsc(temp2)]] - sampling_eps = [[thermal_strain_cu(temp1), thermal_strain_cu(temp2)], [thermal_strain_wsc(temp1), thermal_strain_wsc(temp2)]] - max_eig_value, trace_eps, err_max_eig, err_trace_eps = [np.zeros((n_approaches, n_tests)) for _ in range(4)] - - for idx, alpha in enumerate(test_alphas): - print(f'{alpha = :.2f}') - temperature = test_temperatures[idx] - - interpolate_temp = lambda x1, x2: x1 + alpha * (x2 - x1) - - # reference values - ref_C = [stiffness_cu(temperature), stiffness_wsc(temperature)] - ref_eps = [thermal_strain_cu(temperature), thermal_strain_wsc(temperature)] - ref_max_eig_value = np.max(la.eigvalsh(ref_C[mat_id])) - ref_trace_eps = np.sum(ref_eps[mat_id][:3]) - - # interpolated quantities using the explicit temperature interpolation scheme - approx_C, approx_eps = naive(alpha, sampling_C, sampling_eps, ref_C, ref_eps) - naive_max_eig_value = np.max(la.eigvalsh(approx_C[mat_id])) - naive_trace_eps = np.sum(approx_eps[mat_id][:3]) - - # interpolated quantities using an implicit interpolation scheme with one DOF - approx_C, approx_eps = opt1(sampling_C, sampling_eps, ref_C, ref_eps) - opt1_max_eig_value = np.max(la.eigvalsh(approx_C[mat_id])) - opt1_trace_eps = np.sum(approx_eps[mat_id][:3]) - - # interpolated quantities using an implicit interpolation scheme with two DOF - approx_C, approx_eps = opt2(sampling_C, sampling_eps, ref_C, ref_eps) - opt2_max_eig_value = np.max(la.eigvalsh(approx_C[mat_id])) - opt2_trace_eps = np.sum(approx_eps[mat_id][:3]) - - # interpolated quantities using an implicit interpolation scheme with four DOF - approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - opt4_max_eig_value = np.max(la.eigvalsh(approx_C[mat_id])) - opt4_trace_eps = np.sum(approx_eps[mat_id][:3]) - - max_eig_value[0, idx] = ref_max_eig_value - max_eig_value[1, idx] = naive_max_eig_value - max_eig_value[2, idx] = opt1_max_eig_value - max_eig_value[3, idx] = opt2_max_eig_value - max_eig_value[4, idx] = opt4_max_eig_value - - trace_eps[0, idx] = ref_trace_eps - trace_eps[1, idx] = naive_trace_eps - trace_eps[2, idx] = opt1_trace_eps - trace_eps[3, idx] = opt2_trace_eps - trace_eps[4, idx] = opt4_trace_eps - - # err_max_eig[0, idx] = err_measure(ref_max_eig_value, ref_max_eig_value) - err_max_eig[0, idx] = err_measure(naive_max_eig_value, ref_max_eig_value) - err_max_eig[1, idx] = err_measure(opt1_max_eig_value, ref_max_eig_value) - err_max_eig[2, idx] = err_measure(opt2_max_eig_value, ref_max_eig_value) - err_max_eig[3, idx] = err_measure(opt4_max_eig_value, ref_max_eig_value) - - # err_trace_eps[0, idx] = err_measure(ref_trace_eps, ref_trace_eps) - err_trace_eps[0, idx] = err_measure(naive_trace_eps, ref_trace_eps) - err_trace_eps[1, idx] = err_measure(opt1_trace_eps, ref_trace_eps) - err_trace_eps[2, idx] = err_measure(opt2_trace_eps, ref_trace_eps) - err_trace_eps[3, idx] = err_measure(opt4_trace_eps, ref_trace_eps) - - err_max_eig /= np.max(max_eig_value) - max_eig_value /= np.max(max_eig_value) - err_trace_eps /= np.max(trace_eps) - trace_eps /= np.max(trace_eps) - - labels = ['R', 'O$_0$', 'O$_1$', 'O$_2$', 'O$_4$'] - markers = ['s', 'd', '+', 'x', 'o'] - colors = ['C0', 'C1', 'C2', 'C3', 'C4'] - - fig_name = f'eg1_max_eig{mat_id}' - xlabel = 'Temperature [K]' - ylabel = 'Normalized max($\lambda(\mathbb{C})$) [-]' - plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) - for idx in range(n_approaches): - plt.plot(test_temperatures, max_eig_value[idx], label=labels[idx], marker=markers[idx], color=colors[idx], markevery=6) - plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [None, None]) - - fig_name = f'eg1_tr_thermal_strain{mat_id}' - xlabel = 'Temperature [K]' - ylabel = r'Normalized tr($\boldsymbol{\varepsilon}_\uptheta$) [-]' - plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) - for idx in range(n_approaches): - plt.plot(test_temperatures, trace_eps[idx], label=labels[idx], marker=markers[idx], color=colors[idx], markevery=6) - plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [None, None]) - - labels = ['O$_0$', 'O$_1$', 'O$_2$', 'O$_4$'] - - fig_name = f'eg1_err_max_eig{mat_id}' - xlabel = 'Temperature [K]' - ylabel = 'Normalized absolute error max($\lambda(\mathbb{C})$) [-]' - plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) - for idx in range(n_approaches - 1): - plt.semilogy(test_temperatures, err_max_eig[idx], label=labels[idx], marker=markers[idx], color=colors[idx], markevery=6) - plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [1e-18, 1], loc='center left') - - fig_name = f'eg1_err_tr_thermal_strain{mat_id}' - xlabel = 'Temperature [K]' - ylabel = r'Normalized absolute error tr($\boldsymbol{\varepsilon}_\uptheta$) [-]' - plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) - for idx in range(n_approaches - 1): - plt.semilogy(test_temperatures, err_trace_eps[idx], label=labels[idx], marker=markers[idx], color=colors[idx], - markevery=6) - plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [1e-18, 1], loc='center left') diff --git a/eg2_compare_approximations.py b/eg2_compare_approximations.py deleted file mode 100644 index 25856e0..0000000 --- a/eg2_compare_approximations.py +++ /dev/null @@ -1,223 +0,0 @@ -""" -Test a straightforward implementation of all approaches -""" -from operator import itemgetter - -import numpy.linalg as la - -from interpolate_fluctuation_modes import interpolate_fluctuation_modes -from microstructures import * -from material_parameters import * -from optimize_alpha import opt1, opt2, opt4, naive -from utilities import read_h5, construct_stress_localization, volume_average, compute_residual_efficient -from matplotlib import rc -rc('text', usetex=True) - -np.random.seed(0) -file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[-1]) -print(file_name, '\t', data_path) - -n_loading_directions = 10 -n_tests = 100 -test_temperatures = np.linspace(temp1, temp2, num=n_tests) -test_alphas = np.linspace(0, 1, num=n_tests) - -mesh, ref = read_h5(file_name, data_path, test_temperatures) -mat_id = mesh['mat_id'] -n_gauss = mesh['n_gauss'] -strain_dof = mesh['strain_dof'] -global_gradient = mesh['global_gradient'] -n_gp = mesh['n_integration_points'] -n_modes = ref[0]['plastic_modes'].shape[-1] - -_, samples = read_h5(file_name, data_path, [temp1, temp2], get_mesh=False) - -strains = np.random.normal(size=(n_loading_directions, strain_dof)) -strains /= la.norm(strains, axis=1)[:, None] - -n_approaches = 5 -err_E, err_S, err_eff_S = [np.zeros((n_approaches, n_tests)) for _ in range(3)] -err_eff_stress, err_f = [np.zeros((n_approaches, n_tests * n_loading_directions)) for _ in range(2)] - -for idx, alpha in enumerate(test_alphas): - print(f'{alpha = :.2f}') - temperature = test_temperatures[idx] - - interpolate_temp = lambda x1, x2: x1 + alpha * (x2 - x1) - - E0 = samples[0]['strain_localization'] - E1 = samples[1]['strain_localization'] - E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) - - sampling_C = np.stack((samples[0]['mat_stiffness'], samples[1]['mat_stiffness'])).transpose([1, 0, 2, 3]) - sampling_eps = np.stack((samples[0]['mat_thermal_strain'], samples[1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) - - # reference values - Eref = ref[idx]['strain_localization'] - ref_C = ref[idx]['mat_stiffness'] - ref_eps = ref[idx]['mat_thermal_strain'] - ref_C_ = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) - ref_eps_ = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) - print(np.linalg.norm(ref_C - ref_C_), np.linalg.norm(ref_eps - ref_eps_)) - plastic_modes = ref[idx]['plastic_modes'] - normalization_factor_mech = ref[idx]['normalization_factor_mech'] - - Sref = construct_stress_localization(Eref, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - effSref = volume_average(Sref) - - # interpolated quantities using an explicit interpolation scheme with one DOF - approx_C, approx_eps = naive(alpha, sampling_C, sampling_eps, ref_C, ref_eps) - Enaive = interpolate_temp(E0, E1) - Snaive = construct_stress_localization(Enaive, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - effSnaive = volume_average(Snaive) - - # interpolated quantities using an explicit interpolation scheme with one DOF - Eopt0, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, - n_gp) - Sopt0 = construct_stress_localization(Eopt0, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - effSopt0 = volume_average(Sopt0) - - # interpolated quantities using an implicit interpolation scheme with one DOF - approx_C, approx_eps = opt1(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt1, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, - n_gp) - Sopt1 = construct_stress_localization(Eopt1, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - effSopt1 = volume_average(Sopt1) - - # interpolated quantities using an implicit interpolation scheme with two DOF - approx_C, approx_eps = opt2(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt2, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, - n_gp) - Sopt2 = construct_stress_localization(Eopt2, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - effSopt2 = volume_average(Sopt2) - - # interpolated quantities using an implicit interpolation scheme with four DOF - approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, - n_gp) - Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - effSopt4 = volume_average(Sopt4) - - err = lambda x, y: np.mean(la.norm(x - y, axis=(-1, -2)) / la.norm(y, axis=(-1, -2))) * 100 - err_vec = lambda x, y: np.mean(la.norm(x - y, axis=(-1)) / la.norm(y, axis=(-1))) * 100 - - err_E[:, idx] = [err(Enaive, Eref), err(Eopt0, Eref), err(Eopt1, Eref), err(Eopt2, Eref), err(Eopt4, Eref)] - err_S[:, idx] = [err(Snaive, Sref), err(Sopt0, Sref), err(Sopt1, Sref), err(Sopt2, Sref), err(Sopt4, Sref)] - err_eff_S[:, idx] = [err(effSnaive, effSref), err(effSopt0, effSref), err(effSopt1, effSref), \ - err(effSopt2, effSref), err(effSopt4, effSref)] - - for strain_idx, strain in enumerate(strains): - zeta = np.hstack((strain, 1, np.ones(plastic_modes.shape[-1]))) - - eff_stress_ref = effSref @ zeta - err_eff_stress[:, idx * n_loading_directions + strain_idx] = \ - [err_vec(effSnaive @ zeta, eff_stress_ref), err_vec(effSopt0 @ zeta, eff_stress_ref), \ - err_vec(effSopt1 @ zeta, eff_stress_ref), err_vec(effSopt2 @ zeta, eff_stress_ref), \ - err_vec(effSopt4 @ zeta, eff_stress_ref)] - - stress_naive = np.einsum('ijk,k', Snaive, zeta, optimize='optimal') - stress_opt0 = np.einsum('ijk,k', Sopt0, zeta, optimize='optimal') - stress_opt1 = np.einsum('ijk,k', Sopt1, zeta, optimize='optimal') - stress_opt2 = np.einsum('ijk,k', Sopt2, zeta, optimize='optimal') - stress_opt4 = np.einsum('ijk,k', Sopt4, zeta, optimize='optimal') - - residuals = compute_residual_efficient([stress_naive, stress_opt0, stress_opt1, stress_opt2, stress_opt4], - global_gradient) - - err_f[:, idx * n_loading_directions + strain_idx] = la.norm(residuals, np.inf, axis=0) / normalization_factor_mech * 100 - -np.savez_compressed('output/eg2', err_f=err_f, err_eff_S=err_eff_S, err_eff_stress=err_eff_stress, err_E=err_E, err_S=err_S, - n_loading_directions=n_loading_directions, n_approaches=n_approaches) -# %% -import numpy as np -import numpy.linalg as la -import matplotlib.pyplot as plt -from utilities import plot_and_save, cm, ecdf - -# loaded_qoi = np.load('output/eg2.npz') -# err_f = loaded_qoi['err_f'] -# err_eff_S = loaded_qoi['err_eff_S'] -# err_eff_stress = loaded_qoi['err_eff_stress'] -# err_E = loaded_qoi['err_E'] -# err_S = loaded_qoi['err_S'] -# n_loading_directions = loaded_qoi['n_loading_directions'] -# n_approaches = loaded_qoi['n_approaches'] -markevery = 8 * n_loading_directions - -xlabel = '$x$ [\%]' -labels = ['N', r'O$_0$', 'O$_1$', 'O$_2$', 'O$_4$'] -markers = ['s', 'd', '+', 'x', 'o'] -colors = ['C0', 'C1', 'C2', 'C3', 'C4'] - -fig_name = 'eg2_err_nodal_force' -ylabel = r'$P(e_\mathsf{f}2.2e}'.format}, linewidth=100): - print(f'{np.max(err_f,axis=1) = }') - print(f'{np.max(err_E,axis=1) = }') - print(f'{np.max(err_S,axis=1) = }') - print(f'{np.max(err_eff_S,axis=1) = }') - print(f'{np.max(err_eff_stress,axis=1) = }') diff --git a/eg3_hierarchical_sampling.py b/eg3_hierarchical_sampling.py deleted file mode 100644 index f28efe8..0000000 --- a/eg3_hierarchical_sampling.py +++ /dev/null @@ -1,195 +0,0 @@ -""" -Test hierarchical sampling on RVE with octahedral inclusion -""" -from operator import itemgetter - -import numpy.linalg as la - -from interpolate_fluctuation_modes import interpolate_fluctuation_modes -from microstructures import * -from optimize_alpha import opt4 -from utilities import read_h5, construct_stress_localization, volume_average, compute_residual_efficient, \ - compute_err_indicator_efficient -from matplotlib import rc -rc('text', usetex=False) - -np.random.seed(0) -file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[-1]) -print(file_name, '\t', data_path) - -n_loading_directions = 1 -n_hierarchical_levels = 2 -test_temperatures = np.linspace(temp1, temp2, num=n_tests) -test_alphas = np.linspace(0, 1, num=n_tests) - -mesh, ref = read_h5(file_name, data_path, test_temperatures) -mat_id = mesh['mat_id'] -n_gauss = mesh['n_gauss'] -strain_dof = mesh['strain_dof'] -global_gradient = mesh['global_gradient'] -n_gp = mesh['n_integration_points'] -n_phases = len(np.unique(mat_id)) -n_modes = ref[0]['strain_localization'].shape[-1] - -strains = np.random.normal(size=(n_loading_directions, strain_dof)) -strains /= la.norm(strains, axis=1)[:, None] - -err_nodal_force = np.zeros((n_hierarchical_levels, n_tests, n_loading_directions)) -err_indicators, err_eff_S, err_eff_C, err_eff_eps = [np.zeros((n_hierarchical_levels, n_tests)) for _ in range(4)] - -alpha_levels = [np.linspace(0, 1, num=2)] - -for level in range(n_hierarchical_levels): - print(f'\n --- {level = :.2f} --- \n') - alphas = alpha_levels[level] - interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) - temperatures = interpolate_temp(temp1, temp2, alphas) - _, samples = read_h5(file_name, data_path, temperatures) - for idx, alpha in enumerate(test_alphas): - print(f'{alpha = :.2f}') - temperature = test_temperatures[idx] - - upper_bound = np.searchsorted(alphas, alpha) - id1 = upper_bound if upper_bound > 0 else 1 - id0 = id1 - 1 - - E0 = samples[id0]['strain_localization'] - E1 = samples[id1]['strain_localization'] - E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) - - sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) - sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) - - # reference values - Eref = ref[idx]['strain_localization'] - ref_C = ref[idx]['mat_stiffness'] - ref_eps = ref[idx]['mat_thermal_strain'] - plastic_modes = ref[idx]['plastic_modes'] - normalization_factor_mech = ref[idx]['normalization_factor_mech'] - Sref = construct_stress_localization(Eref, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - effSref = volume_average(Sref) - # effSref = np.vstack((ref[idx]['eff_stiffness'], -ref[idx]['eff_stiffness'] @ ref[idx]['eff_thermal_strain'])).T - - # interpolated quantities using an implicit interpolation scheme with four DOF - approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, - n_gp) - Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - effSopt = volume_average(Sopt4) - - err_indicators[level, idx] = np.mean(np.max(np.abs(compute_err_indicator_efficient(Sopt4, global_gradient)), - axis=0)) / normalization_factor_mech * 100 - - for strain_idx, strain in enumerate(strains): - zeta = np.hstack((strain, 1, np.ones(plastic_modes.shape[-1]))) - stress_opt4 = np.einsum('ijk,k', Sopt4, zeta, optimize='optimal') - residual = compute_residual_efficient(stress_opt4, global_gradient) - - err_nodal_force[level, idx, strain_idx] = la.norm(residual, np.inf) / normalization_factor_mech * 100 - - err = lambda x, y: la.norm(x - y) * 100 / la.norm(y) - err_eff_S[level, idx] = err(effSopt, effSref) - - Capprox = effSopt[:6, :6] - Cref = effSref[:6, :6] - invL = la.inv(la.cholesky(Cref)) - err_eff_C[level, idx] = la.norm(invL @ Capprox @ invL.T - np.eye(6)) / la.norm(np.eye(6)) * 100 - - err_eff_eps[level, idx] = err(la.solve(Capprox, effSopt[:, 7]), la.solve(Cref, effSref[:, 7])) - - # max_err_idx = np.argmax(np.mean(err_nodal_force[level], axis=1)) - max_err_idx = np.argmax(err_indicators[level]) - alpha_levels.append(np.unique(np.sort(np.hstack((alphas, test_alphas[max_err_idx]))))) - print(f'{np.max(np.mean(err_nodal_force[level], axis=1)) = }') - print(f'{np.max(err_indicators[level]) = }') - -np.savez_compressed('output/eg3', n_hierarchical_levels=n_hierarchical_levels, test_temperatures=test_temperatures, - err_nodal_force=err_nodal_force, err_indicators=err_indicators, err_eff_S=err_eff_S, - alpha_levels=np.asarray(alpha_levels, dtype=object)) - -# %% -import numpy as np -import numpy.linalg as la -import matplotlib.pyplot as plt -from utilities import plot_and_save, cm - -# loaded_qoi = np.load('output/eg3.npz', allow_pickle=True) -# n_hierarchical_levels = loaded_qoi['n_hierarchical_levels'] -# test_temperatures = loaded_qoi['test_temperatures'] -# err_nodal_force = loaded_qoi['err_nodal_force'] -# err_indicators = loaded_qoi['err_indicators'] -# err_eff_S = loaded_qoi['err_eff_S'] -# alpha_levels = loaded_qoi['alpha_levels'] - -temp1 = test_temperatures[0] -temp2 = test_temperatures[-1] -interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) - -for level in range(n_hierarchical_levels): - print(f'alphas of level {level}: {alpha_levels[level]}') -print('\n') -for level in range(n_hierarchical_levels): - print(f'temperatures of level {level}: {interpolate_temp(temp1, temp2, alpha_levels[level])}') -print('\n') -for level in range(n_hierarchical_levels): - print(f'level {level}') - print(f'{np.max(np.mean(err_nodal_force[level], axis=1)) = }') - print(f'{np.max(err_indicators[level]) = }') - -xlabel = 'Temperature [K]' -markers = ['s', 'd', '+', 'x', 'o'] -colors = ['C0', 'C1', 'C2', 'C3', 'C4'] - -fig_name = 'eg3_hierarchical_sampling_err_nodal_force' -ylabel = 'Relative error $e_\mathsf{f}$ [\%]' -plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) -for level in range(n_hierarchical_levels): - plt.plot(test_temperatures, np.mean(err_nodal_force[level], axis=1), label=f'{level + 2} samples', marker=markers[level], - color=colors[level], markevery=8) -plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(np.mean(err_nodal_force, axis=-1))], loc='upper left') - -fig_name = 'eg3_hierarchical_sampling_err_indicator' -ylabel = 'Relative error $e_\mathsf{I}$ [\%]' -plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) -for level in range(n_hierarchical_levels): - plt.plot(test_temperatures, err_indicators[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], - markevery=8) -plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_indicators)], loc='upper left') - -fig_name = 'eg3_hierarchical_sampling_err_nodal_vs_indicator' -ylabel = 'Normalized error [-]' -err_indicators /= np.max(err_indicators) -err_nodal_force_mat = np.mean(err_nodal_force, axis=-1) -err_nodal_force_mat /= np.max(err_nodal_force_mat) -plt.figure(figsize=(10 * cm, 6 * cm), dpi=600) -for level in range(n_hierarchical_levels): - plt.plot(test_temperatures, err_nodal_force_mat[level], label=rf'$e_\mathsf f$ {level + 2} samples', marker=markers[level], - color=colors[level], linestyle='-', markevery=8) - plt.plot(test_temperatures, err_indicators[level], label=rf'$e_\mathsf I$ {level + 2} samples', marker=markers[level], - color=colors[level], linestyle=':', markevery=8) -plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_indicators)], loc='upper left') - -fig_name = 'eg3_hierarchical_sampling_err_eff_stress_localization' -ylabel = r'Relative error $e_{\overline{\mathsf{S}}}$ [\%]' -plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) -for level in range(n_hierarchical_levels): - plt.plot(test_temperatures, err_eff_S[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], - markevery=8) -plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_S)], loc='upper left') - -ylabel = r'Relative error $e_{\overline{\mathbb{C}}}$ [\%]' -fig_name = 'eg3_hierarchical_sampling_err_eff_stiffness' -plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) -for level in range(n_hierarchical_levels): - plt.plot(test_temperatures, err_eff_C[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], - markevery=8) -plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_C)], loc='upper left') - -ylabel = r'Relative error $e_{\overline{\boldmath{\varepsilon}}_{\uptheta}}$ [\%]' -fig_name = 'eg3_hierarchical_sampling_err_eff_thermal_strain' -plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) -for level in range(n_hierarchical_levels): - plt.plot(test_temperatures, err_eff_eps[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], - markevery=8) -plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_eps)], loc='upper left') diff --git a/eg4_hierarchical_sampling_efficient.py b/eg4_hierarchical_sampling_efficient.py deleted file mode 100644 index 8a67346..0000000 --- a/eg4_hierarchical_sampling_efficient.py +++ /dev/null @@ -1,252 +0,0 @@ -from operator import itemgetter - -import h5py -import numpy.linalg as la - -from interpolate_fluctuation_modes import update_affine_decomposition, effective_S, effective_stress_localization, \ - interpolate_fluctuation_modes, get_phi, transform_strain_localization -from microstructures import * -from optimize_alpha import opt4_alphas, opt4 -from utilities import read_h5, construct_stress_localization, compute_err_indicator_efficient, volume_average - -np.random.seed(0) -# np.set_printoptions(precision=3) - -for ms_id in [0]: - file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', - 'n_tests', - 'sampling_alphas')(microstructures[ms_id]) - print(file_name, '\t', data_path) - out_file = path(f'output/opt_{file_name.name}') - given_alpha_levels = True if sampling_alphas is not None else False - - # debuging options - # given_alpha_levels = False - # n_tests = 10 - - n_hierarchical_levels = len(sampling_alphas) if sampling_alphas is not None else 5 - test_temperatures = np.linspace(temp1, temp2, num=n_tests) - test_alphas = np.linspace(0, 1, num=n_tests) - - # read reference solutions - mesh, refs = read_h5(file_name, data_path, test_temperatures) - mat_id = mesh['mat_id'] - n_gauss = mesh['n_gauss'] - strain_dof = mesh['strain_dof'] - global_gradient = mesh['global_gradient'] - n_gp = mesh['n_integration_points'] - n_phases = len(np.unique(mat_id)) - N_modes = refs[0]['strain_localization'].shape[2] - 7 - - # extract temperature dependent data from the reference solutions - # such as: material stiffness and thermal strain at each temperature and for all phases - Erefs = np.zeros((n_tests, *refs[0]['strain_localization'].shape)) # n_tests x n_phases x 6 x 6 - ref_Cs = np.zeros((n_tests, *refs[0]['mat_stiffness'].shape)) # n_tests x n_phases x 6 x 6 - ref_epss = np.zeros((n_tests, *refs[0]['mat_thermal_strain'].shape)) # n_tests x n_phases x 6 x 1 - effSref = np.zeros((n_tests, strain_dof, N_modes + 7)) # n_tests x 6 x (N + 7) - normalization_factor_mech = np.zeros((n_tests)) - plastic_modes = refs[0]['plastic_modes'] # temperature independent - for idx, alpha in enumerate(test_alphas): - print(idx) - Erefs[idx] = refs[idx]['strain_localization'] - ref_Cs[idx] = refs[idx]['mat_stiffness'] - ref_epss[idx] = refs[idx]['mat_thermal_strain'] - normalization_factor_mech[idx] = refs[idx]['normalization_factor_mech'] - Sref = construct_stress_localization(Erefs[idx], ref_Cs[idx], ref_epss[idx], plastic_modes, mat_id, n_gauss, - strain_dof) - effSref[idx] = volume_average(Sref) - - err_indicators, err_eff_S, err_eff_C, err_eff_eps = [np.zeros((n_hierarchical_levels, n_tests)) for _ in range(4)] - interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) - err = lambda x, y: la.norm(x - y) / la.norm(y) * 100 - - # alpha_all_levels is initialized with the first level of two samples - alpha_all_levels = [np.linspace(0, 1, num=2)] if not given_alpha_levels else sampling_alphas - - file = h5py.File(out_file, 'w') - - for level in range(n_hierarchical_levels): - print(f'\n --- {level = :.2f} --- \n') - - # read sampling data given current sampling points. note that samples are reread in the next hierarchical level - # but as long as everything is stored is h5 & no solvers are called there's no need for optimizing performance here - alphas = alpha_all_levels[level] - temperatures = interpolate_temp(temp1, temp2, alphas) - n_samples = len(alphas) - _, samples = read_h5(file_name, data_path, temperatures, get_mesh=False) - # lists that contain quantities from sampling pairs - E01s, sampling_Cs, sampling_epss = [], [], [] - for id0 in range(n_samples - 1): - id1 = id0 + 1 - E0 = samples[id0]['strain_localization'] - E1 = samples[id1]['strain_localization'] - E01s.append(np.ascontiguousarray(np.concatenate((E0, E1), axis=-1))) - # n_samples of [n_phases x 2 x 6 x 6] - sampling_Cs.append(np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3])) - # n_samples of [n_phases x 2 x 6 x 1] - sampling_epss.append( - np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3])) - - # alphas_indexing will contain the id of each pair of samples needed to solve the problem at a specific temperature - # temperatures are determined by the values contained in tes_alphas - alphas_indexing = np.searchsorted(alphas, test_alphas) - 1 - alphas_indexing[0] = 0 - - current_sampling_id = None - K0, K1, F0, F1, F2, F3, S001, S101, S103, S002, S102, S104 = [None for _ in range(12)] - - for idx, alpha in enumerate(test_alphas): - print(f'{alpha = :.2f}') - - sampling_C = sampling_Cs[alphas_indexing[idx]] - sampling_eps = sampling_epss[alphas_indexing[idx]] - - # interpolated quantities using an implicit interpolation scheme with four DOF - alpha_C, alpha_eps = opt4_alphas(sampling_C, sampling_eps, ref_Cs[idx], ref_epss[idx]) - alpha_C_eps = alpha_C * alpha_eps - - # Assemble the linear system only when new samples are considered - if alphas_indexing[idx] != current_sampling_id: - current_sampling_id = alphas_indexing[idx] - - K0, K1, F0, F1, F2, F3, S001, S101, S103, S002, S102, S104 = update_affine_decomposition( - E01s[current_sampling_id], sampling_C, sampling_eps, plastic_modes, N_modes, n_phases, - n_gp, strain_dof, - mat_id, n_gauss) - - phi = get_phi(K0, K1, F0, F1, F2, F3, alpha_C, alpha_eps, alpha_C_eps) - - speed = 1 - # if speed == 0: - C, eps = ref_Cs[idx], ref_epss[idx] - # C, eps = opt4(sampling_C, sampling_eps, ref_Cs[idx], ref_epss[idx]) - _, effSopt = interpolate_fluctuation_modes(E01s[current_sampling_id], C, eps, plastic_modes, mat_id, n_gauss, - strain_dof, - N_modes, n_gp) - #elif speed == 1: - # TODO verify the result when plasticity is on - effSopt1 = effective_stress_localization(E01s[current_sampling_id], phi, ref_Cs[idx], ref_epss[idx], plastic_modes, - mat_id, - n_gauss, n_gp, strain_dof, N_modes) - #elif speed == 2: - # TODO verify the result when plasticity is on - # matches the result from interpolate_fluctuatioN_modes with a difference - # that depends on using ref_Cs[idx],ref_epss[idx] instead of alphas - effSopt2, phi2 = effective_S(phi, S001, S101, S103, S002, S102, S104, alpha_C, np.squeeze(alpha_eps, axis=-1), - np.squeeze(alpha_C_eps, axis=-1)) - #else: - # raise NotImplementedError() - print(np.linalg.norm(effSopt - effSopt1)) - - if not given_alpha_levels: - Eopt4 = transform_strain_localization(E01s[current_sampling_id], phi, n_gp, strain_dof, N_modes) - Sopt4 = construct_stress_localization(Eopt4, ref_Cs[idx], ref_epss[idx], plastic_modes, mat_id, n_gauss, - strain_dof) - # effSopt = volume_average(Sopt4) - err_indicators[level, - idx] = np.mean(np.max(np.abs(compute_err_indicator_efficient(Sopt4, global_gradient)), - axis=0)) / normalization_factor_mech[idx] * 100 - - err_eff_S[level, idx] = err(effSopt, effSref[idx]) - - Capprox = effSopt[:6, :6] - Cref = effSref[idx][:6, :6] - invL = la.inv(la.cholesky(Cref)) - - err_eff_C[level, idx] = la.norm(invL @ Capprox @ invL.T - np.eye(6)) / la.norm(np.eye(6)) * 100 - err_eff_eps[level, idx] = err(la.solve(Capprox, effSopt[:, 7]), la.solve(Cref, effSref[idx][:, 7])) - - # TODO remove dtype='f' - group = file.require_group(f'{data_path}_level{level}') - # group.attrs['sampling_strategy'] = "model description" - temperature = test_temperatures[idx] - dset_stiffness = group.require_dataset(f'eff_stiffness_{temperature:07.2f}', (6, 6), dtype='f') - dset_thermal_strain = group.require_dataset(f'eff_thermal_strain_{temperature:07.2f}', (6), dtype='f') - dset_stiffness[:] = Capprox.T - dset_thermal_strain[:] = la.solve(Capprox, effSopt[:, 7]) - - if not given_alpha_levels: - max_err_idx = np.argmax(err_indicators[level]) - alpha_all_levels.append(np.unique(np.sort(np.hstack((alphas, test_alphas[max_err_idx]))))) - - file.close() - idx = [idx for idx, microstructure in enumerate(microstructures) if file_name == microstructure['file_name']][0] - np.savez_compressed(f'output/eg4_{idx}', n_hierarchical_levels=n_hierarchical_levels, test_temperatures=test_temperatures, - err_indicators=err_indicators, err_eff_S=err_eff_S, err_eff_C=err_eff_C, err_eff_eps=err_eff_eps, - alpha_all_levels=np.asarray(alpha_all_levels, dtype=object)) - - # %% - import numpy as np - import numpy.linalg as la - import matplotlib.pyplot as plt - from utilities import plot_and_save, cm - from matplotlib.ticker import FormatStrFormatter - - # loaded_qoi = np.load(f'output/eg4_{idx}.npz', allow_pickle=True) - # n_hierarchical_levels = loaded_qoi['n_hierarchical_levels'] - # test_temperatures = loaded_qoi['test_temperatures'] - # err_indicators = loaded_qoi['err_indicators'] - # err_eff_S = loaded_qoi['err_eff_S'] - # err_eff_C = loaded_qoi['err_eff_C'] - # err_eff_eps = loaded_qoi['err_eff_eps'] - # alpha_all_levels = loaded_qoi['alpha_all_levels'] - - temp1 = test_temperatures[0] - temp2 = test_temperatures[-1] - interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) - - for level in range(n_hierarchical_levels): - print(f'alphas of level {level}: {alpha_all_levels[level]}') - print('\n') - for level in range(n_hierarchical_levels): - print(f'temperatures of level {level}: {interpolate_temp(temp1, temp2, alpha_all_levels[level])}') - print('\n') - for level in range(n_hierarchical_levels): - print(f'level {level}') - print(f'{np.max(err_indicators[level]) = }') - - xlabel = 'Temperature [K]' - styles = ['-', '-', '--', '-.', ':', ':', ':', ':'] - markers = ['s', 'd', '+', 'x', 'o'] - colors = ['C0', 'C1', 'C2', 'C3', 'C4'] - if not given_alpha_levels: - ylabel = 'Relative error $e_\mathsf{I}$ [\%]' - fig_name = f'eg4_{idx}_hierarchical_sampling_err_indicator' - plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) - for level in range(n_hierarchical_levels): - plt.plot(test_temperatures, err_indicators[level], label=f'{level + 2} samples', marker=markers[level], - color=colors[level], linestyle=styles[level], markevery=8) - plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) - plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_indicators)], loc='upper left') - - ylabel = 'Relative error $e_{\overline{\mathsf{S}}}$ [\%]' - fig_name = f'eg4_{idx}_hierarchical_sampling_err_eff_stress_localization' - plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) - for level in range(n_hierarchical_levels): - plt.plot(test_temperatures, err_eff_S[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], - linestyle=styles[level], markevery=8) - plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) - plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_S)], loc='upper left') - - ylabel = 'Relative error $e_{\overline{\mathbb{C}}}$ [\%]' - fig_name = f'eg4_{idx}_hierarchical_sampling_err_eff_stiffness' - plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) - for level in range(n_hierarchical_levels): - plt.plot(test_temperatures, err_eff_C[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], - linestyle=styles[level], markevery=8) - plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) - plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_C)], loc='upper left') - - ylabel = r'Relative error $e_{\overline{\boldmath{\varepsilon}}_{\uptheta}}$ [\%]' - fig_name = f'eg4_{idx}_hierarchical_sampling_err_eff_thermal_strain' - plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) - for level in range(n_hierarchical_levels): - plt.plot(test_temperatures, err_eff_eps[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], - linestyle=styles[level], markevery=8) - plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) - plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_eps)], loc='upper left') - - print(np.max(err_indicators)) - print(np.max(err_eff_S)) - print(np.max(err_eff_C)) - print(np.max(err_eff_eps)) diff --git a/eg5_FFANN.py b/eg5_FFANN.py deleted file mode 100644 index 3e9dbc1..0000000 --- a/eg5_FFANN.py +++ /dev/null @@ -1,147 +0,0 @@ -# %% -# # JEL_thermo-el-ROM: Machine Learned Model -# ### Imports: -from operator import itemgetter - -import h5py -import matplotlib.cm as colormap -import matplotlib.pyplot as plt -import torch -from torch import nn -from torch.utils.data import DataLoader, TensorDataset - -from microstructures import * -from utilities import read_h5 -from utilities_ann import cholesky, reverse_cholesky, hierarchical_sampling, RectFFModule, model_training, \ - plot_training_history - -torch.set_default_dtype(torch.float32) -# ### Load DNS data from HDF5 file: -for ms_id in [7, 8, 9]: - file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', - 'n_tests', - 'sampling_alphas')(microstructures[ms_id]) - # debuging options - # sampling_alphas = [sampling_alphas[-1]] - - print(file_name, '\t', data_path) - out_file = path(f'output/ann_{file_name.name}') - test_temperatures = np.linspace(temp1, temp2, num=n_tests) - test_alphas = np.linspace(0, 1, num=n_tests) - _, refs = read_h5(file_name, data_path, test_temperatures, get_mesh=False) - x = test_temperatures[:, None] - y = np.stack([np.hstack((cholesky(ref['eff_stiffness']), ref['eff_thermal_strain'])) for ref in refs]) - - # ### Data scaling: - # As sole input feature the temperature $\theta$ is used. - # The output features $y = [\mathrm{vec}(L), E] \in \mathbb{R}^{27}$ are given by the Cholesky decomposition $L$ of the Mandel notation $C = L L^\intercal$ of the fourth-order effective stiffness tensor $\mathbb{C}$ and the Mandel notation $E \in \mathbb{R}^6$ of the thermal strain tensor $\varepsilon_\theta$ that are obtained by the DNS. - # Since the different components of $y$ differ greatly in magnitude, each output feature is normalized with its absolute maximum value. - # Scaling - x = torch.FloatTensor(x / np.max(x, axis=0)) - y_normalization_factor = np.max(np.abs(y), axis=0) - y = torch.FloatTensor(y / y_normalization_factor) - dset = TensorDataset(x, y) - n_out_features = y.size()[1] - n_in_features = x.size()[1] - - file = h5py.File(out_file, 'w') - for level, sampling_alpha in enumerate(sampling_alphas): - # ### Data sampling: - # #### Bisection sampling: - # reproducibility - torch.manual_seed(1) - torch.use_deterministic_algorithms(True) - # Split in test and validation data - # train_data, val_data = bisection_sampling(dset, levels=3, samples_per_pos=1, validation=True) - # sampling_alphas = np.asarray([0, 0.41, 0.74, 0.9, 0.95, 1]) - train_data, val_data = hierarchical_sampling(dset, x[:, 0], sampling_alpha) - - # Create dataloaders - batch_size = len(train_data) - train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True) - val_loader = DataLoader(val_data, batch_size=len(val_data)) - # Create a PyTorch model for a Feedforward Artificial Neural Network (FFANN) with 3 hidden layers and 64 neurons per layer. - # `Tanh` is used as activation function in the hidden layers and the identity as activation function in the output layer. - model = RectFFModule(n_in_features, 64, 3, nn.Tanh(), nn.Identity(), n_out_features) - # print(model) - - # The MSE loss function is used for training. Using the "mechanical loss function", which is defined as - # $$\frac{||L_{pred} - L||_F}{||L||_F} + \frac{||\varepsilon_{\theta,pred} - \varepsilon_{\theta}||_F}{||\varepsilon_\theta||_F}$$ - # Here, using the Adam as optimizer leads to faster convergence than using Stochastic Gradient Descent (SGD). - loss_fn = nn.MSELoss(reduction='mean') - # loss_fn = mech_loss - optimizer = torch.optim.Adam(model.parameters(), lr=2e-4) - train_losses, val_losses, best_epoch = model_training(model, loss_fn, optimizer, train_loader, val_loader, - epochs=4000 * len(train_data), verbose=False) - - # The training history of the ANN is plotted in the figure below. - fig, ax = plt.subplots() - plot_training_history(ax, train_losses, val_losses, best_epoch) - y_pred = model(x) - - # The predictions of the ANN are compared to the ground truth in the figure below. - fig, ax = plt.subplots(1, 1, figsize=[4, 4]) - colors = colormap.rainbow(np.linspace(0, 1, n_out_features)) - for i in range(n_out_features): - ax.plot(test_temperatures, y[:, i], '-', color=colors[i], lw=1) - ax.plot(test_temperatures, y_pred[:, i].detach().numpy(), '--', color=colors[i], lw=2) - ax.set_title('normalized features') - ax.set_xlabel(r'Temperature $\theta$ [K]') - ax.set_ylabel(r'Scaled output feature [-]') - plt.grid('on') - plt.tight_layout() - plt.show(block=False) - - # Plot of the error - norm_error = np.linalg.norm(y - y_pred.detach(), axis=1) / np.linalg.norm(y, axis=1) * 100 - fig, ax = plt.subplots(1, 1, figsize=[4, 4]) - ax.plot(test_temperatures, norm_error, 'b-', label='0 levels') - ax.set_xlabel(r'Temperature [K]') - ax.set_ylabel(r'Relative error [\%]') - plt.grid('on') - plt.tight_layout() - plt.show(block=False) - print(f'{np.argmax(norm_error)/100 = :.2f}') - print(f'{len(train_data)} samples') - print(f'{len(val_data)} validations') - print(f'{np.max(norm_error) = :.2f} %') - - # %% - y_approx = y_pred.detach().numpy() * y_normalization_factor - errC = np.zeros(n_tests) - erreps = np.zeros(n_tests) - - group = file.require_group(f'{data_path}_level{level}') - # group.attrs['sampling_strategy'] = "model description" - for i, ref in enumerate(refs): - dset_stiffness = group.require_dataset(f'eff_stiffness_{test_temperatures[i]:07.2f}', (6, 6), dtype='f') - dset_thermal_strain = group.require_dataset(f'eff_thermal_strain_{test_temperatures[i]:07.2f}', (6), dtype='f') - - C = reverse_cholesky(y_approx[i, :21]) - eps = y_approx[i, 21:] - - dset_stiffness[:] = C.T - dset_thermal_strain[:] = eps - - Cref = np.asarray(ref['eff_stiffness'], dtype=float) - epsref = np.asarray(ref['eff_thermal_strain'], dtype=float) - invL = np.linalg.inv(np.linalg.cholesky(Cref)) - errC[i] = np.linalg.norm(invL @ C @ invL.T - np.eye(6)) / np.linalg.norm(np.eye(6)) * 100 - erreps[i] = np.linalg.norm(epsref - eps) / np.linalg.norm(epsref) * 100 - # erreps[i] = (epsref @ Cref @ epsref - eps @ Cref @ eps) / (epsref @ Cref @ epsref) * 100 - - ylabels = [ - 'Relative error $e_{\overline{\mathbb{C}}}$ [\%]', - r'Relative error $e_{\overline{\boldmath{\varepsilon}}_{\uptheta}}$ [\%]' - ] - for idx, err in enumerate([errC, erreps]): - fig, ax = plt.subplots(1, 1, figsize=[4, 4]) - ax.plot(test_temperatures, err, 'b-') - ax.set_xlabel(r'Temperature [K]') - ax.set_ylabel(ylabels[idx]) - plt.grid('on') - plt.tight_layout() - plt.show(block=False) - print(f'{np.max(err) = :.2f} %') - plt.close('all') - file.close() diff --git a/eg6_post_process_ann_vs_proposed.py b/eg6_post_process_ann_vs_proposed.py deleted file mode 100644 index f08bfef..0000000 --- a/eg6_post_process_ann_vs_proposed.py +++ /dev/null @@ -1,122 +0,0 @@ -# %% -from operator import itemgetter - -import h5py -import matplotlib.pyplot as plt -import numpy.linalg as la -from matplotlib.ticker import FormatStrFormatter - -from microstructures import * -from utilities import plot_and_save, cm - -n_hierarchical_levels = 5 -ms_id = 9 -file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[ms_id]) -print(file_name, '\t', data_path) -opt_file = path(f'output/opt_{file_name.name}') -ann_file = path(f'output/ann_{file_name.name}') - -test_temperatures = np.linspace(temp1, temp2, num=n_tests) - -refC = np.zeros((n_tests, 6, 6)) -ref_eps = np.zeros((n_tests, 6)) - -optC = np.zeros((n_tests, n_hierarchical_levels, 6, 6)) -opt_eps = np.zeros((n_tests, n_hierarchical_levels, 6)) - -annC = np.zeros((n_tests, n_hierarchical_levels, 6, 6)) -ann_eps = np.zeros((n_tests, n_hierarchical_levels, 6)) - -for level in range(n_hierarchical_levels): - with h5py.File(file_name, 'r') as file: - for idx, temperature in enumerate(test_temperatures): - refC[idx] = file[f'{data_path}/eff_stiffness_{temperature:07.2f}'][:] - ref_eps[idx] = file[f'{data_path}/eff_thermal_strain_{temperature:07.2f}'][:] - - with h5py.File(opt_file, 'r') as file: - for idx, temperature in enumerate(test_temperatures): - optC[idx, level] = file[f'{data_path}_level{level}/eff_stiffness_{temperature:07.2f}'][:] - opt_eps[idx, level] = -file[f'{data_path}_level{level}/eff_thermal_strain_{temperature:07.2f}'][:] - - with h5py.File(ann_file, 'r') as file: - for idx, temperature in enumerate(test_temperatures): - annC[idx, level] = file[f'{data_path}_level{level}/eff_stiffness_{temperature:07.2f}'][:] - ann_eps[idx, level] = file[f'{data_path}_level{level}/eff_thermal_strain_{temperature:07.2f}'][:] - -# %% -err_eff_C_opt = np.zeros((n_tests, n_hierarchical_levels)) -err_eff_eps_opt = np.zeros((n_tests, n_hierarchical_levels)) - -err_eff_C_ann = np.zeros((n_tests, n_hierarchical_levels)) -err_eff_eps_ann = np.zeros((n_tests, n_hierarchical_levels)) - -err = lambda x, y: la.norm(x - y) * 100 / la.norm(y) -err_energy = lambda x, y, C: (y @ C @ y - x @ C @ x) / (y @ C @ y) * 100 - -for level in range(n_hierarchical_levels): - for idx, temperature in enumerate(test_temperatures): - invL = la.inv(la.cholesky(refC[idx])) - - err_eff_C_opt[idx, level] = la.norm(invL @ optC[idx, level] @ invL.T - np.eye(6)) / la.norm(np.eye(6)) * 100 - err_eff_C_ann[idx, level] = la.norm(invL @ annC[idx, level] @ invL.T - np.eye(6)) / la.norm(np.eye(6)) * 100 - - err_eff_eps_opt[idx, level] = err(opt_eps[idx, level], ref_eps[idx]) - err_eff_eps_ann[idx, level] = err(ann_eps[idx, level], ref_eps[idx]) - - # err_eff_eps_opt[idx, level] = err_energy(opt_eps[idx, level], ref_eps[idx], refC[idx]) - # err_eff_eps_ann[idx, level] = err_energy(ann_eps[idx, level], ref_eps[idx], refC[idx]) - -# %% -level = 4 - -xlabel = 'Temperature [K]' -styles = ['-', '--', ':', '-.', ':', ':', ':'] -markers = ['s', 'd', '+', 'x', 'o'] -colors = ['C0', 'C1', 'C2', 'C3', 'C4'] - -ylabel = 'Relative error $e_{\overline{\mathbb{C}}}$ [\%]' -fig_name = f'eg5_{ms_id}_hierarchical_sampling_err_eff_stiffness' -fig, ax = plt.subplots(figsize=(6 * cm, 6 * cm), dpi=600) -# axins = ax.inset_axes([0.53, 0.42, 0.4, 0.3]) -axins = ax.inset_axes([0.23, 0.42, 0.4, 0.3]) -# for level in range(n_hierarchical_levels): -plt.plot(test_temperatures, err_eff_C_opt[:, level], label=f'O$_4$ {level + 2} samples', marker=markers[level], color=colors[1], - linestyle='--', markevery=8) -axins.plot(test_temperatures, err_eff_C_opt[:, level], label=f'O$_4$ {level + 2} samples', marker=markers[level], color=colors[1], - linestyle='--', markevery=8) -plt.plot(test_temperatures, err_eff_C_ann[:, level], label=f'ANN {level + 2} samples', marker=markers[level], color=colors[0], - linestyle='-', markevery=8) -axins.grid('on') -axins.grid(ls='--', color='gray', linewidth=0.5) -axins.set_xlim(temp1, temp2) -axins.set_ylim(0.0, 0.020) -axins.get_xaxis().set_visible(False) -ax.indicate_inset_zoom(axins, facecolor=(0.8, 0.8, 0.8, 0.6), edgecolor=(0.3, 0.3, 0.3, 0.3), lw=0.1) -plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) -# plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 3.5], loc='upper right') -# plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 1.5], loc='upper right') -plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 2.2], loc='upper right') - -# %% -ylabel = r'Relative error $e_{\overline{\boldmath{\varepsilon}}_{\uptheta}}$ [\%]' -fig_name = f'eg5_{ms_id}_hierarchical_sampling_err_eff_thermal_strain' -fig, ax = plt.subplots(figsize=(6 * cm, 6 * cm), dpi=600) -axins = ax.inset_axes([0.53, 0.42, 0.4, 0.3]) -# for level in range(n_hierarchical_levels): -plt.plot(test_temperatures, err_eff_eps_opt[:, level], label=f'O$_4$ {level + 2} samples', marker=markers[level], color=colors[1], - linestyle='--', markevery=8) -axins.plot(test_temperatures, err_eff_eps_opt[:, level], label=f'O$_4$ {level + 2} samples', marker=markers[level], - color=colors[1], linestyle='--', markevery=8) -plt.plot(test_temperatures, err_eff_eps_ann[:, level], label=f'ANN {level + 2} samples', marker=markers[level], color=colors[0], - linestyle='-', markevery=8) -axins.grid('on') -axins.grid(ls='--', color='gray', linewidth=0.5) -axins.set_xlim(temp1, temp2) -axins.set_ylim(0.0, 0.2) -axins.get_xaxis().set_visible(False) -ax.indicate_inset_zoom(axins, facecolor=(0.8, 0.8, 0.8, 0.6), edgecolor=(0.3, 0.3, 0.3, 0.3), lw=0.1) -plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) -# plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 15], loc='upper right') -# plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 4], loc='upper right') -plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 7], loc='upper right') diff --git a/eg7_staggered_model_interpolation.py b/eg7_staggered_model_interpolation.py deleted file mode 100644 index 92aedfa..0000000 --- a/eg7_staggered_model_interpolation.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Interpolate the homogenized response (i.e. effective C and effective eps) at arbitrary temperatures -based on the approximations in eg3_hierarchical_sampling.py or eg4_hierarchical_sampling_efficient.py -""" -# %% -from operator import itemgetter -import time -import h5py -from scipy import interpolate -from microstructures import * - -# Offline stage: Load precomputed optimal data -load_start = time.time() -ms_id = 6 -level = 4 -file_name, data_path, temp1, temp2, n_samples, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[ms_id]) -opt_file = path(f'output/opt_{file_name.name}') -print(f'Loading precomputed data from {file_name}\t{data_path}') - -sample_temperatures = np.linspace(temp1, temp2, num=n_samples) - -opt_C = np.zeros((n_samples, 6, 6)) -opt_eps = np.zeros((n_samples, 6)) - -try: - with h5py.File(opt_file, 'r') as file: - for idx, temperature in enumerate(sample_temperatures): - opt_C[idx] = file[f'{data_path}_level{level}/eff_stiffness_{temperature:07.2f}'][:] - # eg4_*.py saves (-1 * eff_thermal_strain) in the corresponding h5 file - opt_eps[idx] = -1.0 * file[f'{data_path}_level{level}/eff_thermal_strain_{temperature:07.2f}'][:] -except Exception: - print(f'Could not load precomputed data. Run eg4_*.py first for ms_id={ms_id}, level={level}.') - exit() - -load_time = time.time() - load_start -print(f'Loaded precomputed data at {n_samples} temperatures in {load_time:.5f} s') - -# %% -# Online stage: linear interpolation between sampled data -online_start = time.time() -n_tests = 1000 -test_temperatures = np.linspace(temp1, temp2, num=n_tests) - - -def staggered_model_online(test_temperatures, sample_temperatures, opt_C, opt_eps): - """Interpolate the effective stiffness C and the effective thermal expansion eps - at a list of temperatures in `test_temperatures` using linear interpolation - based on precomputed `opt_C` and `opt_eps` at `sample_temperatures`. - - Args: - test_temperatures (np.ndarray): array of temperatures with shape (N,) - sample_temperatures (np.ndarray): array of temperatures with shape (n,) - opt_C (np.ndarray): optimal C at n temperatures with shape (n,6,6) - opt_eps (np.ndarray): optimal eps at n temperatures with shape (n,6) - - Returns: - np.ndarray: array of interpolated C with shape (N,6,6) - np.ndarray: array of interpolated eps with shape (N,6) - """ - # Linear interpolation for C - interp_C = interpolate.interp1d(sample_temperatures, opt_C, axis=0) - approx_C = interp_C(test_temperatures) - # Linear interpolation for eps - interp_eps = interpolate.interp1d(sample_temperatures, opt_eps, axis=0) - approx_eps = interp_eps(test_temperatures) - return approx_C, approx_eps - - -approx_C, approx_eps = staggered_model_online(test_temperatures, sample_temperatures, opt_C, opt_eps) - -online_time = time.time() - online_start -print(f'Interpolated C and eps at {n_tests} temperatures in {online_time:.5f} s') - -# Print interpolated C and eps at a specific data point -idx = 123 -np.set_printoptions(precision=4) -print(f'Interpolated C at {test_temperatures[idx]:.4f} K:') -print(approx_C[idx]) -print(f'Interpolated eps at {test_temperatures[idx]:.4f} K:') -print(approx_eps[idx]) diff --git a/eg8_plot_localization.py b/eg8_plot_localization.py deleted file mode 100644 index c73e7f5..0000000 --- a/eg8_plot_localization.py +++ /dev/null @@ -1,153 +0,0 @@ -""" -Plot the strain localization operator E and stress localization operator S at different temperatures -""" -#%% -from operator import itemgetter - -import numpy.linalg as la -import matplotlib.pyplot as plt -from microstructures import * -from utilities import read_h5, construct_stress_localization - -################ - - - - stress_localization = np.empty_like(strain_localization) - strain_localization_transp = ... - I = np.eye(strain_dof) - for gp_id in prange(strain_localization.shape[0]): - phase_id = mat_id[gp_id // n_gauss] - stress_localization[gp_id] = strain_localization_transp[gp_id] @ mat_stiffness[phase_id] @ (plastic_modes - eigen_strains) - A = volume_average(stress_localization) - - D0 = volume_average(inner_product((plastic_modes - eigen_strains), eigen_strains)) - - K0 = -volume_average(inner_product(plastic_modes, K @ eigen_strains)) - K = k * K0 - - D = D0 + K - - R = volume_average(thermal_stresses @ (plastic_modes - eigen_strains)) / delta_theta - - -########### - -np.random.seed(0) -file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( - "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" -)(microstructures[7]) -print(file_name, "\t", data_path) - -test_temperatures = np.linspace(temp1, temp2, num=n_tests) -test_alphas = np.linspace(0, 1, num=n_tests) - -mesh, ref = read_h5(file_name, data_path, test_temperatures) -mat_id = mesh["mat_id"] -n_gauss = mesh["n_gauss"] -strain_dof = mesh["strain_dof"] -nodal_dof = mesh["nodal_dof"] -n_elements = mesh["n_elements"] -global_gradient = mesh["global_gradient"] -n_gp = mesh["n_integration_points"] -n_modes = ref[0]["strain_localization"].shape[-1] -disc = mesh["combo_discretisation"] - -# Lowest temperature -temp0 = ref[0]["temperature"] -E0 = ref[0]["strain_localization"] -C0 = ref[0]["mat_stiffness"] -eps0 = ref[0]["mat_thermal_strain"] -S0 = construct_stress_localization(E0, C0, eps0, mat_id, n_gauss, strain_dof) - -# First enrichment temperature -a = len(ref) // 2 -if sampling_alphas is not None: - alpha = sampling_alphas[1][1] - a = int(alpha * n_tests) -tempa = ref[a]["temperature"] -Ea = ref[a]["strain_localization"] -Ca = ref[a]["mat_stiffness"] -epsa = ref[a]["mat_thermal_strain"] -Sa = construct_stress_localization(Ea, Ca, epsa, mat_id, n_gauss, strain_dof) - -# Highest temperature -temp1 = ref[-1]["temperature"] -E1 = ref[-1]["strain_localization"] -C1 = ref[-1]["mat_stiffness"] -eps1 = ref[-1]["mat_thermal_strain"] -S1 = construct_stress_localization(E1, C1, eps1, mat_id, n_gauss, strain_dof) - -# %% - - -def plot_localization(ax, E, idx=0): - """Plots the effective total strain/stress norm (not the deviatoric part) - of a given localization operator `E` on the y-z-cross section at x=idx. - - Args: - ax: matplotlib axis - E (np.ndarray): localization operator with shape (nx*ny*nz*ngauss, 6, 7) - idx (int, optional): y-z-cross section index. Defaults to 0. - """ - assert E.ndim == nodal_dof - assert E.shape[0] == n_gp - assert E.shape[1] == strain_dof - # assert E.shape[2] == n_modes - E_r = E.reshape(*disc, n_gauss, strain_dof, n_modes) - E_ra = np.mean(E_r, axis=3) # average over gauss points - # compute the effective total strain norm (not the deviatoric part); - # account for Mandel notation, i.e. activation strain with all components being 1.0 - E_rai = np.einsum('ijklm,m', E_ra, np.asarray([1, 1, 1, np.sqrt(2), np.sqrt(2), np.sqrt(2), 1])) - effective_strain = np.sqrt(2/3) * la.norm(E_rai, axis=-1) - # plot y-z-cross section at x=idx - ax.imshow(effective_strain[idx, :, :], interpolation="gaussian") - - -# Plot strain localization operator E at different temperatures -fig, ax = plt.subplots(1, 3) -plot_localization(ax[0], E0, idx=0) -ax[0].set_title( - r"$\underline{\underline{E}}\;\mathrm{at}\;\theta=" - + f"{temp0:.2f}" - + r"\mathrm{K}$" -) -plot_localization(ax[1], Ea, idx=0) -ax[1].set_title( - r"$\underline{\underline{E}}\;\mathrm{at}\;\theta=" - + f"{tempa:.2f}" - + r"\mathrm{K}$" -) -plot_localization(ax[2], E1, idx=0) -ax[2].set_title( - r"$\underline{\underline{E}}\;\mathrm{at}\;\theta=" - + f"{temp1:.2f}" - + r"\mathrm{K}$" -) -plt.savefig("output/E.png", dpi=300) -plt.show() - -# Plot stress localization operator S at different temperatures -fig, ax = plt.subplots(1, 3) -plot_localization(ax[0], S0, idx=0) -ax[0].set_title( - r"$\underline{\underline{S}}\;\mathrm{at}\;\theta=" - + f"{temp0:.2f}" - + r"\mathrm{K}$" -) -plot_localization(ax[1], Sa, idx=0) -ax[1].set_title( - r"$\underline{\underline{S}}\;\mathrm{at}\;\theta=" - + f"{tempa:.2f}" - + r"\mathrm{K}$" -) -plot_localization(ax[2], S1, idx=0) -ax[2].set_title( - r"$\underline{\underline{S}}\;\mathrm{at}\;\theta=" - + f"{temp1:.2f}" - + r"\mathrm{K}$" -) -plt.savefig("output/S.png", dpi=300) -plt.show() - -# %% diff --git a/eg9_compute_ntfa_matrices.py b/eg9_compute_ntfa_matrices.py index 93a5cff..f24ba5a 100644 --- a/eg9_compute_ntfa_matrices.py +++ b/eg9_compute_ntfa_matrices.py @@ -8,10 +8,11 @@ import matplotlib.pyplot as plt import time from microstructures import * -from utilities import read_h5, read_snapshots, mode_identification, compute_tabular_data, save_tabular_data +from utilities import read_h5 +from ntfa import read_snapshots, mode_identification, compute_tabular_data, save_tabular_data np.random.seed(0) -for microstructure in microstructures[-2:]: +for microstructure in microstructures[-9:]: file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" )(microstructure) @@ -29,7 +30,7 @@ global_gradient = mesh["global_gradient"] n_gp = mesh["n_integration_points"] disc = mesh["combo_discretisation"] - vol_frac = mesh['volume_fraction'][0] + vol_frac0, vol_frac1 = mesh['volume_fraction'][0], mesh['volume_fraction'][1] # Mode identification @@ -38,13 +39,14 @@ print('plastic_snapshots.shape:', plastic_snapshots.shape) # Identification of plastic modes - r_min = 1e-8 - plastic_modes_svd = mode_identification(plastic_snapshots, vol_frac, r_min) + r_min = 1e-3 + plastic_modes_svd = mode_identification(plastic_snapshots, vol_frac0, r_min) print('plastic_modes_svd.shape:', plastic_modes_svd.shape) # Compare computed plastic modes with plastic modes from h5 file plastic_modes = samples[0]['plastic_modes'] - assert np.allclose(plastic_modes, plastic_modes_svd), 'Identified plastic modes do not match plastic modes in h5 file' + plastic_modes = plastic_modes_svd + # assert np.allclose(plastic_modes / np.sign(np.expand_dims(np.expand_dims(plastic_modes[0,0,:], axis=0), axis=0)), plastic_modes_svd), 'Identified plastic modes do not match plastic modes in h5 file' # Mode processing to compute system matrices @@ -52,7 +54,7 @@ temperatures = np.linspace(temp1, temp2, num=n_temp) start_time = time.time() # TODO: compute system matrices for multiple intermediate temperatures in an efficient way - C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta = compute_tabular_data(samples, mesh, temperatures) + C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1 = compute_tabular_data(samples, mesh, plastic_modes, temperatures) elapsed_time = time.time() - start_time print(f'Computed tabular data for {n_temp} temperatures in {elapsed_time}s') print('C_bar.shape:', C_bar.shape) @@ -61,9 +63,10 @@ print('tau_xi.shape:', tau_xi.shape) print('D_xi.shape:', D_xi.shape) print('D_theta.shape:', D_theta.shape) + print('A_bar/A0/A1 error:', np.linalg.norm(vol_frac0 * A0 + vol_frac1 * A1 - A_bar) / np.linalg.norm(A_bar)) # Save system matrices for multiple temperatures as tabular data - save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta) + save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1) # Tabular data is saved to the input h5 file and can be copied to a new h5 file using e.g. # h5copy -i input/file.h5 -o input/file_ntfa.h5 -s ms_1p/dset0_ntfa -d ms_1p/dset0_ntfa -p diff --git a/microstructures.py b/microstructures.py index fa1a01d..2f01430 100644 --- a/microstructures.py +++ b/microstructures.py @@ -134,6 +134,55 @@ 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None +}, { + 'data_path': '/ms_9p/dset0_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 10, + 'sampling_alphas': None +}, { + 'data_path': '/ms_9p/dset1_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 10, + 'sampling_alphas': None +}, { + 'data_path': '/ms_9p/dset2_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 10, + 'sampling_alphas': None +}, { + 'data_path': '/ms_9p/dset3_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 10, + 'sampling_alphas': None +}, { + 'data_path': '/ms_15p/dset0_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 10, + 'sampling_alphas': None +}, { + 'data_path': '/ms_15p/dset1_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 10, + 'sampling_alphas': None +}, { + 'data_path': '/ms_15p/dset2_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 10, + 'sampling_alphas': None }, { 'data_path': '/ms_1p/dset0_sim', 'file_name': path("input/simple_3d_rve_4x4x4_100samples.h5"), diff --git a/utilities.py b/utilities.py index 31d3c59..a760295 100644 --- a/utilities.py +++ b/utilities.py @@ -11,7 +11,6 @@ from optimize_alpha import opt4 from interpolate_fluctuation_modes import interpolate_fluctuation_modes from microstructures import * -from material_parameters import * plt.rcParams.update({ 'font.size': 8, @@ -472,319 +471,3 @@ def norm_2(a): :param b: array with same shape as b """ return np.sqrt(inner_product(a, a)) - - -def create_dummy_plastic_snapshots(n_integration_points, strain_dof, n_frames=100): - """ - TODO: remove when FANS can compute plastic snapshots - """ - # plastic_snapshots = np.random.rand(n_integration_points, strain_dof, n_frames) - plastic_snapshots = np.random.rand(n_integration_points, strain_dof)[:, :, np.newaxis] * np.random.rand(n_frames) \ - + 1e-2 * np.random.rand(n_integration_points, strain_dof, n_frames) - return plastic_snapshots - - -def create_dummy_plastic_modes(n_integration_points, strain_dof, N_modes): - """ - TODO: remove when FANS can compute plastic snapshots - """ - plastic_modes = np.random.rand(n_integration_points, strain_dof, N_modes) - return plastic_modes - - -def create_dummy_plastic_strain_localization(strain_localization, N_modes): - E_eps = strain_localization[:, :, :6] - E_xi = np.random.rand(*strain_localization.shape[:2], N_modes) - E_theta = np.expand_dims(strain_localization[:, :, -1], axis=2) - strain_localization = np.concatenate([E_eps, E_xi, E_theta], axis=2) - return strain_localization - - -def read_snapshots(file_name, data_path): - """ - Read an H5 file that contains responses of simulated microstructures - :param file_name: e.g. "input/simple_3d_rve_combo.h5" - :param data_path: the path to the simulation results within the h5 file, e.g. '/ms_1p/dset0_sim' - :return: - strain_snapshots: plastic strain snapshots eps_p - with shape (n_integration_points, strain_dof, n_frames) - """ - # TODO: read snapshots from H5 file. Because of the sheer amount of data it may be better to use a separate h5 file for the snapshots. - plastic_snapshots = None - with h5py.File(file_name, 'r') as file: - plastic_snapshots = np.transpose(file[f'{data_path}/plastic_strains'][:], (0, 2, 1)) - # For now, use dummy data: - # n_integration_points, strain_dof, n_frames = 512, 6, 100 - # plastic_snapshots = create_dummy_plastic_modes(n_integration_points, strain_dof, n_frames) - # TODO: Reorder snapshots as follows: | 1st strain path: last timestep to first timestep | 2nd strain path: last timestep to first timestep | ... - # or: reorder snapshots already in FANS? - return plastic_snapshots - - -def mode_identification_iterative(plastic_snapshots, vol_frac, r_min=1e-8): - """ - Identification of plastic strain modes µ using an iterative algorithm and renormalization - :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) - with shape (n_integration_points, strain_dof, n_frames) - :param r_min: stop criterion - :return: - plastic_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, n_modes) - """ - n_integration_points, strain_dof, n_frames = plastic_snapshots.shape - n_modes = 0 - plastic_modes = np.zeros((n_integration_points, strain_dof, n_modes)) - for i in range(n_frames): - eps_i = plastic_snapshots[:, :, i] - r = volume_average(inner_product(eps_i, eps_i)) # TODO: average only over Omega_p? - k = np.zeros(n_modes) # Coefficients k_j - for j in range(n_modes): - k[j] = volume_average(inner_product(eps_i, plastic_modes[:, :, j])) - r = r - k[j]**2 - if r < r_min: - break - if r > r_min: - n_modes = n_modes + 1 # increment number of modes - # Generate new strain mode: - plastic_mode = (eps_i - np.tensordot(k, plastic_modes, axes=(0,2))) / np.sqrt(r) - plastic_modes = np.concatenate([plastic_modes, np.expand_dims(plastic_mode, 2)], axis=2) - # Renormalize plastic modes - for i in range(n_modes): - weighting_factor = vol_frac / volume_average(norm_2(plastic_modes[:, :, i])) - plastic_modes[:, :, i] = plastic_modes[:, :, i] * weighting_factor * np.sign(plastic_modes[0, 0, i]) - return plastic_modes - - -def mode_identification(plastic_snapshots, vol_frac, r_min=1e-8): - """ - Identification of plastic strain modes µ using POD and renormalization - :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) - with shape (n_integration_points, strain_dof, n_frames) - :param r_min: stop criterion - :return: - plastic_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, n_modes) - """ - n_integration_points, strain_dof, n_frames = plastic_snapshots.shape - plastic_snapshots_rs = plastic_snapshots.transpose(1, 0, 2).reshape((strain_dof * n_integration_points, n_frames)) - u, s, v = np.linalg.svd(plastic_snapshots_rs, full_matrices=False) - s = s / s[0] - n_modes = np.argwhere(s > r_min).size - plastic_modes = u[:, :n_modes].reshape((strain_dof, n_integration_points, n_modes)).transpose(1, 0, 2) - # Renormalize plastic modes - for i in range(n_modes): - weighting_factor = vol_frac / volume_average(norm_2(plastic_modes[:, :, i])) - plastic_modes[:, :, i] = plastic_modes[:, :, i] * weighting_factor * np.sign(plastic_modes[0, 0, i]) - return plastic_modes - - -def compute_ntfa_matrices(strain_localization, stress_localization, plastic_modes, thermal_strain, mesh): - """ - Processing of the plastic strain modes µ to compute the matrices A_bar, D_xi, C_bar and the vector tau_theta - as tabular data at given temperatures - :param strain_localization: strain localization 3D array - with shape (n_integration_points, strain_dof, 7 + n_modes) - :param stress_localization: stress localization 3D array - with shape (n_integration_points, strain_dof, 7 + n_modes) - :param mat_stiffness: stiffness tensors of the phases - with shape (n_phases, strain_dof, strain_dof) - :param mat_id: material phase identification - with shape (n_elements,) - :param mesh: - :param plastic_modes: plastic strain modes µ - with shape (n_integration_points, strain_dof, N_modes) - :param eigen_strains: solutions of the auxiliary eigenstress problems eps_star - with shape (n_integration_points, strain_dof, N_modes) - :param ...: - :return: - C_bar with shape (strain_dof, strain_dof) - tau_theta with shape (strain_dof,) - A_bar with shape (strain_dof, strain_dof) - tau_xi with shape (n_modes,) - D_xi with shape (strain_dof, n_modes) - D_theta with shape (strain_dof, n_modes) - """ - strain_dof = mesh['strain_dof'] - mat_id = mesh['mat_id'] - n_modes = plastic_modes.shape[2] - - # slice strain localization operator E into E_eps, E_theta, E_xi - E_eps = strain_localization[:, :, :strain_dof] - E_theta = strain_localization[:, :, strain_dof] - E_xi = strain_localization[:, :, strain_dof + 1:] - - - # slice stress localization operator S into S_eps, S_theta, S_xi - S_eps = stress_localization[:, :, :strain_dof] - S_theta = stress_localization[:, :, strain_dof] - S_xi = stress_localization[:, :, strain_dof + 1:] - - I = np.eye(6) - # Compute C_bar via < (E_eps + I).T @ S_eps > - C_bar = volume_average((E_eps + I).transpose((0, 2, 1)) @ S_eps) - - # Compute tau_theta via < (E_eps + I).T @ S_theta > - tau_theta = volume_average(np.einsum('nij,nj->ni', (E_eps + I).transpose((0, 2, 1)), S_theta)) - - # Compute A_bar via < (E_eps + I).T @ S_eps > - A_bar = volume_average((E_eps + I).transpose((0, 2, 1)) @ S_xi) - - # Compute tau_xi via < (E_theta - P_theta).T @ S_xi > - tau_xi = volume_average(np.einsum('ni,nij->nj', E_theta - thermal_strain, S_xi)) - - # Compute D_xi via < (E_xi - P_xi).T @ S_xi > - D_xi = volume_average((E_xi - plastic_modes).transpose((0, 2, 1)) @ S_xi) - - # Compute D_theta via < (E_theta - P_theta).T @ S_theta > - D_theta = volume_average(np.einsum('ni,ni->n', E_theta - thermal_strain, S_theta)) - - return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta - - -def compute_tabular_data_for_ms(ms_id, temperatures): - """ - Perform `compute_tabular_data` for microstructure with id `ms_id` - """ - file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[ms_id]) - sample_temperatures = np.linspace(temp1, temp2, num=n_tests) - sample_alphas = np.linspace(0, 1, num=n_tests) - mesh, samples = read_h5(file_name, data_path, sample_temperatures) - return compute_tabular_data(samples, mesh, temperatures) - - -#@jit(nopython=True, cache=True, parallel=True, nogil=True) -def compute_tabular_data(samples, mesh, temperatures): - """ - """ - mat_id = mesh['mat_id'] - n_gauss = mesh['n_gauss'] - strain_dof = mesh['strain_dof'] - global_gradient = mesh['global_gradient'] - n_gp = mesh['n_integration_points'] - n_phases = len(np.unique(mat_id)) - n_modes = samples[0]['plastic_modes'].shape[-1] - n_temps = len(temperatures) - C_bar = np.zeros((strain_dof, strain_dof, n_temps)) - tau_theta = np.zeros((strain_dof, n_temps)) - A_bar = np.zeros((strain_dof, n_modes, n_temps)) - tau_xi = np.zeros((n_modes, n_temps)) - D_xi = np.zeros((n_modes, n_modes, n_temps)) - D_theta = np.zeros((n_temps)) - # interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) - # dns_temperatures = interpolate_temp(temp1, temp2, sample_alphas) - sample_temperatures = np.array([sample['temperature'] for sample in samples]) - temp1, temp2 = min(sample_temperatures), max(sample_temperatures) - sample_alphas = (sample_temperatures - temp1) / (temp2 - temp1) - plastic_modes = samples[0]['plastic_modes'] - for idx in prange(n_temps): - temperature = temperatures[idx] - ref_C = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) - ref_eps = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) - alpha = (temperature - temp1) / (temp2 - temp1) - upper_bound = np.searchsorted(sample_alphas, alpha) - if np.floor(alpha) == alpha: - # sample for given temperature exists, no need for interpolation - id = upper_bound - C, eps = ref_C, ref_eps - E = samples[id]['strain_localization'] - S = construct_stress_localization(E, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - else: - id1 = upper_bound if upper_bound > 0 else 1 - id0 = id1 - 1 - - E0 = samples[id0]['strain_localization'] - E1 = samples[id1]['strain_localization'] - E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) - - sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) - sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) - - # interpolated quantities using an implicit interpolation scheme with four DOF - C, eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - E, _ = interpolate_fluctuation_modes(E01, C, eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, n_gp) - S = construct_stress_localization(E, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - C_bar[:, :, idx], tau_theta[:, idx], A_bar[:, :, idx], tau_xi[:, idx], D_xi[:, :, idx], D_theta[idx] = \ - compute_ntfa_matrices(E, S, plastic_modes, eps[0,:,0], mesh) - return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta - - -@jit(nopython=True, cache=True, parallel=True, nogil=True) -def compute_tabular_data_efficient(samples, mesh, temperatures): - """ - WIP - mat_id = mesh['mat_id'] - n_gauss = mesh['n_gauss'] - strain_dof = mesh['strain_dof'] - global_gradient = mesh['global_gradient'] - n_gp = mesh['n_integration_points'] - n_phases = len(np.unique(mat_id)) - n_modes = samples[0]['strain_localization'].shape[-1] - n_temps = len(temperatures) - A_bar = np.zeros((strain_dof, n_modes - 7, n_temps)) - D_xi = np.zeros((n_modes - 7, n_modes - 7, n_temps)) - tau_theta = np.zeros((strain_dof, n_temps)) - C_bar = np.zeros((strain_dof, strain_dof, n_temps)) - # interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) - # dns_temperatures = interpolate_temp(temp1, temp2, sample_alphas) - sample_temperatures = np.array([sample['temperature'] for sample in samples]) - temp1, temp2 = min(sample_temperatures), max(sample_temperatures) - sample_alphas = (sample_temperatures - temp1) / (temp2 - temp1) - # for idx, temperature in enumerate(temperatures): - for idx in prange(n_temps): - temperature = temperatures[idx] - alpha = (temperature - temp1) / (temp2 - temp1) - upper_bound = np.searchsorted(sample_alphas, alpha) - id1 = upper_bound if upper_bound > 0 else 1 - id0 = id1 - 1 - - E0 = samples[id0]['strain_localization'] - E1 = samples[id1]['strain_localization'] - E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) - - sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) - sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) - plastic_modes = samples[id0]['plastic_modes'] # TODO: does exist? - # normalization_factor_mech = samples[idx]['normalization_factor_mech'] # TODO: does exist? - ref_C = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) - ref_eps = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) - - # interpolated quantities using an implicit interpolation scheme with four DOF - approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, - n_gp) - Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - # effSopt = volume_average(Sopt4) - A_bar[:,:,idx], D_xi[:,:,idx], tau_theta[:,idx], C_bar[:,:,idx] = compute_ntfa_matrices(Sopt4, plastic_modes, mesh) - return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta - """ - pass - - -def save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta): - """ - Save tabular data - :param file_name: e.g. "input/simple_3d_rve_combo.h5" - :param data_path: - :param temperatures: - :param C_bar: tabular data for C_bar with shape (strain_dof, strain_dof, n_temp) - :param tau_theta: tabular data for tau_theta with shape (strain_dof, n_temp) - :param A_bar: tabular data for A_bar with shape (strain_dof, strain_dof, n_temp) - :param tau_xi: tabular data for tau_xi with shape (n_modes, n_temp) - :param D_xi: tabular data for D_xi with shape (n_modes, n_modes, n_temp) - :param D_xi: tabular data for D_theta with shape (n_temp) - """ - with h5py.File(file_name, 'a') as file: - dset_sim = file[data_path] - dset = dset_sim.parent - ntfa_path = re.sub('_sim$', '_ntfa', dset_sim.name) - if ntfa_path in file: - # Delete h5 group with tabular data if it already exists - del file[ntfa_path] - dset_ntfa = dset.create_group(ntfa_path) - [dset_ntfa.attrs.create(key, value) for key, value in dset_sim.attrs.items()] - dset_temperatures = dset_ntfa.create_dataset('temperatures', data=temperatures) - dset_C_bar = dset_ntfa.create_dataset('C_bar', data=C_bar) - dset_tau_theta = dset_ntfa.create_dataset('tau_theta', data=tau_theta) - dset_A_bar = dset_ntfa.create_dataset('A_bar', data=A_bar) - dset_tau_xi = dset_ntfa.create_dataset('tau_xi', data=tau_xi) - dset_D_xi = dset_ntfa.create_dataset('D_xi', data=D_xi) - dset_D_theta = dset_ntfa.create_dataset('D_theta', data=D_theta) From 4b43c78ca2389d9270962bf52388c8cc80a29eb8 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Wed, 14 Jun 2023 00:12:22 +0200 Subject: [PATCH 19/30] Compute NTFA matrices --- eg00_affine_thermoelastic_solver.py | 29 ++ eg01_approximation_of_mat_properties.py | 126 ++++++++ eg02_compare_approximations.py | 223 ++++++++++++++ eg03_hierarchical_sampling.py | 195 ++++++++++++ eg04_hierarchical_sampling_efficient.py | 252 ++++++++++++++++ eg05_FFANN.py | 147 +++++++++ eg06_post_process_ann_vs_proposed.py | 122 ++++++++ eg07_staggered_model_interpolation.py | 81 +++++ eg08_plot_localization.py | 153 ++++++++++ eg10_compare_ntfa_matrices.py | 72 +++++ ntfa.py | 380 ++++++++++++++++++++++++ 11 files changed, 1780 insertions(+) create mode 100644 eg00_affine_thermoelastic_solver.py create mode 100644 eg01_approximation_of_mat_properties.py create mode 100644 eg02_compare_approximations.py create mode 100644 eg03_hierarchical_sampling.py create mode 100644 eg04_hierarchical_sampling_efficient.py create mode 100644 eg05_FFANN.py create mode 100644 eg06_post_process_ann_vs_proposed.py create mode 100644 eg07_staggered_model_interpolation.py create mode 100644 eg08_plot_localization.py create mode 100644 eg10_compare_ntfa_matrices.py create mode 100644 ntfa.py diff --git a/eg00_affine_thermoelastic_solver.py b/eg00_affine_thermoelastic_solver.py new file mode 100644 index 0000000..843c6f4 --- /dev/null +++ b/eg00_affine_thermoelastic_solver.py @@ -0,0 +1,29 @@ +""" +Load all microstructures and try to reconstruct stress and strain fields and effective properties +""" + +from operator import itemgetter + +from microstructures import * +from utilities import verify_data, read_h5 + +for microstructure in microstructures[-9:]: + + file_name, data_path, temp1, temp2 = itemgetter('file_name', 'data_path', 'temp1', 'temp2')(microstructure) + + print(file_name, '\t', data_path) + + temperatures = np.linspace(temp1, temp2, 2) + + mesh, samples = read_h5(file_name, data_path, temperatures) + + # print(mesh.keys()) + # print(samples[0].keys()) + print('strain localication shape:', samples[0]['strain_localization'].shape) + print('material stiffness shape:', samples[0]['mat_stiffness'].shape) + print('plastic modes shape:', samples[0]['plastic_modes'].shape) + + for sample in samples: + verify_data(mesh, sample) + +print(f'{"done":-^50}') diff --git a/eg01_approximation_of_mat_properties.py b/eg01_approximation_of_mat_properties.py new file mode 100644 index 0000000..404e891 --- /dev/null +++ b/eg01_approximation_of_mat_properties.py @@ -0,0 +1,126 @@ +""" +Approximate material properties using various affine approaches +""" +import numpy.linalg as la + +from material_parameters import * +from optimize_alpha import naive, opt1, opt2, opt4 +from utilities import plot_and_save, cm +from matplotlib import rc +rc('text', usetex=True) + +temp1 = 300 +temp2 = 1300 +n_tests = 100 +test_temperatures = np.linspace(temp1, temp2, num=n_tests) +test_alphas = np.linspace(0, 1, num=n_tests) +n_approaches = 5 + +abs_err = lambda x, y: la.norm(x - y) +rel_err = lambda x, y: la.norm(x - y) * 100 / la.norm(y) +err_measure = abs_err + +for mat_id in range(2): + sampling_C = [[stiffness_cu(temp1), stiffness_cu(temp2)], [stiffness_wsc(temp1), stiffness_wsc(temp2)]] + sampling_eps = [[thermal_strain_cu(temp1), thermal_strain_cu(temp2)], [thermal_strain_wsc(temp1), thermal_strain_wsc(temp2)]] + max_eig_value, trace_eps, err_max_eig, err_trace_eps = [np.zeros((n_approaches, n_tests)) for _ in range(4)] + + for idx, alpha in enumerate(test_alphas): + print(f'{alpha = :.2f}') + temperature = test_temperatures[idx] + + interpolate_temp = lambda x1, x2: x1 + alpha * (x2 - x1) + + # reference values + ref_C = [stiffness_cu(temperature), stiffness_wsc(temperature)] + ref_eps = [thermal_strain_cu(temperature), thermal_strain_wsc(temperature)] + ref_max_eig_value = np.max(la.eigvalsh(ref_C[mat_id])) + ref_trace_eps = np.sum(ref_eps[mat_id][:3]) + + # interpolated quantities using the explicit temperature interpolation scheme + approx_C, approx_eps = naive(alpha, sampling_C, sampling_eps, ref_C, ref_eps) + naive_max_eig_value = np.max(la.eigvalsh(approx_C[mat_id])) + naive_trace_eps = np.sum(approx_eps[mat_id][:3]) + + # interpolated quantities using an implicit interpolation scheme with one DOF + approx_C, approx_eps = opt1(sampling_C, sampling_eps, ref_C, ref_eps) + opt1_max_eig_value = np.max(la.eigvalsh(approx_C[mat_id])) + opt1_trace_eps = np.sum(approx_eps[mat_id][:3]) + + # interpolated quantities using an implicit interpolation scheme with two DOF + approx_C, approx_eps = opt2(sampling_C, sampling_eps, ref_C, ref_eps) + opt2_max_eig_value = np.max(la.eigvalsh(approx_C[mat_id])) + opt2_trace_eps = np.sum(approx_eps[mat_id][:3]) + + # interpolated quantities using an implicit interpolation scheme with four DOF + approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) + opt4_max_eig_value = np.max(la.eigvalsh(approx_C[mat_id])) + opt4_trace_eps = np.sum(approx_eps[mat_id][:3]) + + max_eig_value[0, idx] = ref_max_eig_value + max_eig_value[1, idx] = naive_max_eig_value + max_eig_value[2, idx] = opt1_max_eig_value + max_eig_value[3, idx] = opt2_max_eig_value + max_eig_value[4, idx] = opt4_max_eig_value + + trace_eps[0, idx] = ref_trace_eps + trace_eps[1, idx] = naive_trace_eps + trace_eps[2, idx] = opt1_trace_eps + trace_eps[3, idx] = opt2_trace_eps + trace_eps[4, idx] = opt4_trace_eps + + # err_max_eig[0, idx] = err_measure(ref_max_eig_value, ref_max_eig_value) + err_max_eig[0, idx] = err_measure(naive_max_eig_value, ref_max_eig_value) + err_max_eig[1, idx] = err_measure(opt1_max_eig_value, ref_max_eig_value) + err_max_eig[2, idx] = err_measure(opt2_max_eig_value, ref_max_eig_value) + err_max_eig[3, idx] = err_measure(opt4_max_eig_value, ref_max_eig_value) + + # err_trace_eps[0, idx] = err_measure(ref_trace_eps, ref_trace_eps) + err_trace_eps[0, idx] = err_measure(naive_trace_eps, ref_trace_eps) + err_trace_eps[1, idx] = err_measure(opt1_trace_eps, ref_trace_eps) + err_trace_eps[2, idx] = err_measure(opt2_trace_eps, ref_trace_eps) + err_trace_eps[3, idx] = err_measure(opt4_trace_eps, ref_trace_eps) + + err_max_eig /= np.max(max_eig_value) + max_eig_value /= np.max(max_eig_value) + err_trace_eps /= np.max(trace_eps) + trace_eps /= np.max(trace_eps) + + labels = ['R', 'O$_0$', 'O$_1$', 'O$_2$', 'O$_4$'] + markers = ['s', 'd', '+', 'x', 'o'] + colors = ['C0', 'C1', 'C2', 'C3', 'C4'] + + fig_name = f'eg1_max_eig{mat_id}' + xlabel = 'Temperature [K]' + ylabel = 'Normalized max($\lambda(\mathbb{C})$) [-]' + plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) + for idx in range(n_approaches): + plt.plot(test_temperatures, max_eig_value[idx], label=labels[idx], marker=markers[idx], color=colors[idx], markevery=6) + plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [None, None]) + + fig_name = f'eg1_tr_thermal_strain{mat_id}' + xlabel = 'Temperature [K]' + ylabel = r'Normalized tr($\boldsymbol{\varepsilon}_\uptheta$) [-]' + plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) + for idx in range(n_approaches): + plt.plot(test_temperatures, trace_eps[idx], label=labels[idx], marker=markers[idx], color=colors[idx], markevery=6) + plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [None, None]) + + labels = ['O$_0$', 'O$_1$', 'O$_2$', 'O$_4$'] + + fig_name = f'eg1_err_max_eig{mat_id}' + xlabel = 'Temperature [K]' + ylabel = 'Normalized absolute error max($\lambda(\mathbb{C})$) [-]' + plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) + for idx in range(n_approaches - 1): + plt.semilogy(test_temperatures, err_max_eig[idx], label=labels[idx], marker=markers[idx], color=colors[idx], markevery=6) + plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [1e-18, 1], loc='center left') + + fig_name = f'eg1_err_tr_thermal_strain{mat_id}' + xlabel = 'Temperature [K]' + ylabel = r'Normalized absolute error tr($\boldsymbol{\varepsilon}_\uptheta$) [-]' + plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) + for idx in range(n_approaches - 1): + plt.semilogy(test_temperatures, err_trace_eps[idx], label=labels[idx], marker=markers[idx], color=colors[idx], + markevery=6) + plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [1e-18, 1], loc='center left') diff --git a/eg02_compare_approximations.py b/eg02_compare_approximations.py new file mode 100644 index 0000000..e07d9ed --- /dev/null +++ b/eg02_compare_approximations.py @@ -0,0 +1,223 @@ +""" +Test a straightforward implementation of all approaches +""" +from operator import itemgetter + +import numpy.linalg as la + +from interpolate_fluctuation_modes import interpolate_fluctuation_modes +from microstructures import * +from material_parameters import * +from optimize_alpha import opt1, opt2, opt4, naive +from utilities import read_h5, construct_stress_localization, volume_average, compute_residual_efficient +from matplotlib import rc +rc('text', usetex=True) + +np.random.seed(0) +file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', + 'sampling_alphas')(microstructures[-8]) +print(file_name, '\t', data_path) + +n_loading_directions = 10 +n_tests = 10 +test_temperatures = np.linspace(temp1, temp2, num=n_tests) +test_alphas = np.linspace(0, 1, num=n_tests) + +mesh, ref = read_h5(file_name, data_path, test_temperatures) +mat_id = mesh['mat_id'] +n_gauss = mesh['n_gauss'] +strain_dof = mesh['strain_dof'] +global_gradient = mesh['global_gradient'] +n_gp = mesh['n_integration_points'] +n_modes = ref[0]['plastic_modes'].shape[-1] + +_, samples = read_h5(file_name, data_path, [temp1, temp2], get_mesh=False) + +strains = np.random.normal(size=(n_loading_directions, strain_dof)) +strains /= la.norm(strains, axis=1)[:, None] + +n_approaches = 5 +err_E, err_S, err_eff_S = [np.zeros((n_approaches, n_tests)) for _ in range(3)] +err_eff_stress, err_f = [np.zeros((n_approaches, n_tests * n_loading_directions)) for _ in range(2)] + +for idx, alpha in enumerate(test_alphas): + print(f'{alpha = :.2f}') + temperature = test_temperatures[idx] + + interpolate_temp = lambda x1, x2: x1 + alpha * (x2 - x1) + + E0 = samples[0]['strain_localization'] + E1 = samples[1]['strain_localization'] + E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) + + sampling_C = np.stack((samples[0]['mat_stiffness'], samples[1]['mat_stiffness'])).transpose([1, 0, 2, 3]) + sampling_eps = np.stack((samples[0]['mat_thermal_strain'], samples[1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) + + # reference values + Eref = ref[idx]['strain_localization'] + ref_C = ref[idx]['mat_stiffness'] + ref_eps = ref[idx]['mat_thermal_strain'] + ref_C_ = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) + ref_eps_ = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) + print(np.linalg.norm(ref_C - ref_C_), np.linalg.norm(ref_eps - ref_eps_)) + plastic_modes = ref[idx]['plastic_modes'] + normalization_factor_mech = ref[idx]['normalization_factor_mech'] + + Sref = construct_stress_localization(Eref, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + effSref = volume_average(Sref) + + # interpolated quantities using an explicit interpolation scheme with one DOF + approx_C, approx_eps = naive(alpha, sampling_C, sampling_eps, ref_C, ref_eps) + Enaive = interpolate_temp(E0, E1) + Snaive = construct_stress_localization(Enaive, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + effSnaive = volume_average(Snaive) + + # interpolated quantities using an explicit interpolation scheme with one DOF + Eopt0, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt0 = construct_stress_localization(Eopt0, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + effSopt0 = volume_average(Sopt0) + + # interpolated quantities using an implicit interpolation scheme with one DOF + approx_C, approx_eps = opt1(sampling_C, sampling_eps, ref_C, ref_eps) + Eopt1, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt1 = construct_stress_localization(Eopt1, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + effSopt1 = volume_average(Sopt1) + + # interpolated quantities using an implicit interpolation scheme with two DOF + approx_C, approx_eps = opt2(sampling_C, sampling_eps, ref_C, ref_eps) + Eopt2, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt2 = construct_stress_localization(Eopt2, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + effSopt2 = volume_average(Sopt2) + + # interpolated quantities using an implicit interpolation scheme with four DOF + approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) + Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + effSopt4 = volume_average(Sopt4) + + err = lambda x, y: np.mean(la.norm(x - y, axis=(-1, -2)) / la.norm(y, axis=(-1, -2))) * 100 + err_vec = lambda x, y: np.mean(la.norm(x - y, axis=(-1)) / la.norm(y, axis=(-1))) * 100 + + err_E[:, idx] = [err(Enaive, Eref), err(Eopt0, Eref), err(Eopt1, Eref), err(Eopt2, Eref), err(Eopt4, Eref)] + err_S[:, idx] = [err(Snaive, Sref), err(Sopt0, Sref), err(Sopt1, Sref), err(Sopt2, Sref), err(Sopt4, Sref)] + err_eff_S[:, idx] = [err(effSnaive, effSref), err(effSopt0, effSref), err(effSopt1, effSref), \ + err(effSopt2, effSref), err(effSopt4, effSref)] + + for strain_idx, strain in enumerate(strains): + zeta = np.hstack((strain, 1, np.ones(plastic_modes.shape[-1]))) + + eff_stress_ref = effSref @ zeta + err_eff_stress[:, idx * n_loading_directions + strain_idx] = \ + [err_vec(effSnaive @ zeta, eff_stress_ref), err_vec(effSopt0 @ zeta, eff_stress_ref), \ + err_vec(effSopt1 @ zeta, eff_stress_ref), err_vec(effSopt2 @ zeta, eff_stress_ref), \ + err_vec(effSopt4 @ zeta, eff_stress_ref)] + + stress_naive = np.einsum('ijk,k', Snaive, zeta, optimize='optimal') + stress_opt0 = np.einsum('ijk,k', Sopt0, zeta, optimize='optimal') + stress_opt1 = np.einsum('ijk,k', Sopt1, zeta, optimize='optimal') + stress_opt2 = np.einsum('ijk,k', Sopt2, zeta, optimize='optimal') + stress_opt4 = np.einsum('ijk,k', Sopt4, zeta, optimize='optimal') + + residuals = compute_residual_efficient([stress_naive, stress_opt0, stress_opt1, stress_opt2, stress_opt4], + global_gradient) + + err_f[:, idx * n_loading_directions + strain_idx] = la.norm(residuals, np.inf, axis=0) / normalization_factor_mech * 100 + +np.savez_compressed('output/eg2', err_f=err_f, err_eff_S=err_eff_S, err_eff_stress=err_eff_stress, err_E=err_E, err_S=err_S, + n_loading_directions=n_loading_directions, n_approaches=n_approaches) +# %% +import numpy as np +import numpy.linalg as la +import matplotlib.pyplot as plt +from utilities import plot_and_save, cm, ecdf + +# loaded_qoi = np.load('output/eg2.npz') +# err_f = loaded_qoi['err_f'] +# err_eff_S = loaded_qoi['err_eff_S'] +# err_eff_stress = loaded_qoi['err_eff_stress'] +# err_E = loaded_qoi['err_E'] +# err_S = loaded_qoi['err_S'] +# n_loading_directions = loaded_qoi['n_loading_directions'] +# n_approaches = loaded_qoi['n_approaches'] +markevery = 8 * n_loading_directions + +xlabel = '$x$ [\%]' +labels = ['N', r'O$_0$', 'O$_1$', 'O$_2$', 'O$_4$'] +markers = ['s', 'd', '+', 'x', 'o'] +colors = ['C0', 'C1', 'C2', 'C3', 'C4'] + +fig_name = 'eg2_err_nodal_force' +ylabel = r'$P(e_\mathsf{f}2.2e}'.format}, linewidth=100): + print(f'{np.max(err_f,axis=1) = }') + print(f'{np.max(err_E,axis=1) = }') + print(f'{np.max(err_S,axis=1) = }') + print(f'{np.max(err_eff_S,axis=1) = }') + print(f'{np.max(err_eff_stress,axis=1) = }') diff --git a/eg03_hierarchical_sampling.py b/eg03_hierarchical_sampling.py new file mode 100644 index 0000000..c5123e1 --- /dev/null +++ b/eg03_hierarchical_sampling.py @@ -0,0 +1,195 @@ +""" +Test hierarchical sampling on RVE with octahedral inclusion +""" +from operator import itemgetter + +import numpy.linalg as la + +from interpolate_fluctuation_modes import interpolate_fluctuation_modes +from microstructures import * +from optimize_alpha import opt4 +from utilities import read_h5, construct_stress_localization, volume_average, compute_residual_efficient, \ + compute_err_indicator_efficient +from matplotlib import rc +rc('text', usetex=True) + +np.random.seed(0) +file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', + 'sampling_alphas')(microstructures[-8]) +print(file_name, '\t', data_path) + +n_loading_directions = 1 +n_hierarchical_levels = 2 +test_temperatures = np.linspace(temp1, temp2, num=n_tests) +test_alphas = np.linspace(0, 1, num=n_tests) + +mesh, ref = read_h5(file_name, data_path, test_temperatures) +mat_id = mesh['mat_id'] +n_gauss = mesh['n_gauss'] +strain_dof = mesh['strain_dof'] +global_gradient = mesh['global_gradient'] +n_gp = mesh['n_integration_points'] +n_phases = len(np.unique(mat_id)) +n_modes = ref[0]['plastic_modes'].shape[-1] + +strains = np.random.normal(size=(n_loading_directions, strain_dof)) +strains /= la.norm(strains, axis=1)[:, None] + +err_nodal_force = np.zeros((n_hierarchical_levels, n_tests, n_loading_directions)) +err_indicators, err_eff_S, err_eff_C, err_eff_eps = [np.zeros((n_hierarchical_levels, n_tests)) for _ in range(4)] + +alpha_levels = [np.linspace(0, 1, num=2)] + +for level in range(n_hierarchical_levels): + print(f'\n --- {level = :.2f} --- \n') + alphas = alpha_levels[level] + interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) + temperatures = interpolate_temp(temp1, temp2, alphas) + _, samples = read_h5(file_name, data_path, temperatures) + for idx, alpha in enumerate(test_alphas): + print(f'{alpha = :.2f}') + temperature = test_temperatures[idx] + + upper_bound = np.searchsorted(alphas, alpha) + id1 = upper_bound if upper_bound > 0 else 1 + id0 = id1 - 1 + + E0 = samples[id0]['strain_localization'] + E1 = samples[id1]['strain_localization'] + E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) + + sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) + sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) + + # reference values + Eref = ref[idx]['strain_localization'] + ref_C = ref[idx]['mat_stiffness'] + ref_eps = ref[idx]['mat_thermal_strain'] + plastic_modes = ref[idx]['plastic_modes'] + normalization_factor_mech = ref[idx]['normalization_factor_mech'] + Sref = construct_stress_localization(Eref, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + effSref = volume_average(Sref) + # effSref = np.vstack((ref[idx]['eff_stiffness'], -ref[idx]['eff_stiffness'] @ ref[idx]['eff_thermal_strain'])).T + + # interpolated quantities using an implicit interpolation scheme with four DOF + approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) + Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + effSopt = volume_average(Sopt4) + + err_indicators[level, idx] = np.mean(np.max(np.abs(compute_err_indicator_efficient(Sopt4, global_gradient)), + axis=0)) / normalization_factor_mech * 100 + + for strain_idx, strain in enumerate(strains): + zeta = np.hstack((strain, 1, np.ones(plastic_modes.shape[-1]))) + stress_opt4 = np.einsum('ijk,k', Sopt4, zeta, optimize='optimal') + residual = compute_residual_efficient(stress_opt4, global_gradient) + + err_nodal_force[level, idx, strain_idx] = la.norm(residual, np.inf) / normalization_factor_mech * 100 + + err = lambda x, y: la.norm(x - y) * 100 / la.norm(y) + err_eff_S[level, idx] = err(effSopt, effSref) + + Capprox = effSopt[:6, :6] + Cref = effSref[:6, :6] + invL = la.inv(la.cholesky(Cref)) + err_eff_C[level, idx] = la.norm(invL @ Capprox @ invL.T - np.eye(6)) / la.norm(np.eye(6)) * 100 + + err_eff_eps[level, idx] = err(la.solve(Capprox, effSopt[:, 7]), la.solve(Cref, effSref[:, 7])) + + # max_err_idx = np.argmax(np.mean(err_nodal_force[level], axis=1)) + max_err_idx = np.argmax(err_indicators[level]) + alpha_levels.append(np.unique(np.sort(np.hstack((alphas, test_alphas[max_err_idx]))))) + print(f'{np.max(np.mean(err_nodal_force[level], axis=1)) = }') + print(f'{np.max(err_indicators[level]) = }') + +np.savez_compressed('output/eg3', n_hierarchical_levels=n_hierarchical_levels, test_temperatures=test_temperatures, + err_nodal_force=err_nodal_force, err_indicators=err_indicators, err_eff_S=err_eff_S, + alpha_levels=np.asarray(alpha_levels, dtype=object)) + +# %% +import numpy as np +import numpy.linalg as la +import matplotlib.pyplot as plt +from utilities import plot_and_save, cm + +# loaded_qoi = np.load('output/eg3.npz', allow_pickle=True) +# n_hierarchical_levels = loaded_qoi['n_hierarchical_levels'] +# test_temperatures = loaded_qoi['test_temperatures'] +# err_nodal_force = loaded_qoi['err_nodal_force'] +# err_indicators = loaded_qoi['err_indicators'] +# err_eff_S = loaded_qoi['err_eff_S'] +# alpha_levels = loaded_qoi['alpha_levels'] + +temp1 = test_temperatures[0] +temp2 = test_temperatures[-1] +interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) + +for level in range(n_hierarchical_levels): + print(f'alphas of level {level}: {alpha_levels[level]}') +print('\n') +for level in range(n_hierarchical_levels): + print(f'temperatures of level {level}: {interpolate_temp(temp1, temp2, alpha_levels[level])}') +print('\n') +for level in range(n_hierarchical_levels): + print(f'level {level}') + print(f'{np.max(np.mean(err_nodal_force[level], axis=1)) = }') + print(f'{np.max(err_indicators[level]) = }') + +xlabel = 'Temperature [K]' +markers = ['s', 'd', '+', 'x', 'o'] +colors = ['C0', 'C1', 'C2', 'C3', 'C4'] + +fig_name = 'eg3_hierarchical_sampling_err_nodal_force' +ylabel = 'Relative error $e_\mathsf{f}$ [\%]' +plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) +for level in range(n_hierarchical_levels): + plt.plot(test_temperatures, np.mean(err_nodal_force[level], axis=1), label=f'{level + 2} samples', marker=markers[level], + color=colors[level], markevery=8) +plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(np.mean(err_nodal_force, axis=-1))], loc='upper left') + +fig_name = 'eg3_hierarchical_sampling_err_indicator' +ylabel = 'Relative error $e_\mathsf{I}$ [\%]' +plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) +for level in range(n_hierarchical_levels): + plt.plot(test_temperatures, err_indicators[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], + markevery=8) +plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_indicators)], loc='upper left') + +fig_name = 'eg3_hierarchical_sampling_err_nodal_vs_indicator' +ylabel = 'Normalized error [-]' +err_indicators /= np.max(err_indicators) +err_nodal_force_mat = np.mean(err_nodal_force, axis=-1) +err_nodal_force_mat /= np.max(err_nodal_force_mat) +plt.figure(figsize=(10 * cm, 6 * cm), dpi=600) +for level in range(n_hierarchical_levels): + plt.plot(test_temperatures, err_nodal_force_mat[level], label=rf'$e_\mathsf f$ {level + 2} samples', marker=markers[level], + color=colors[level], linestyle='-', markevery=8) + plt.plot(test_temperatures, err_indicators[level], label=rf'$e_\mathsf I$ {level + 2} samples', marker=markers[level], + color=colors[level], linestyle=':', markevery=8) +plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_indicators)], loc='upper left') + +fig_name = 'eg3_hierarchical_sampling_err_eff_stress_localization' +ylabel = r'Relative error $e_{\overline{\mathsf{S}}}$ [\%]' +plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) +for level in range(n_hierarchical_levels): + plt.plot(test_temperatures, err_eff_S[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], + markevery=8) +plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_S)], loc='upper left') + +ylabel = r'Relative error $e_{\overline{\mathbb{C}}}$ [\%]' +fig_name = 'eg3_hierarchical_sampling_err_eff_stiffness' +plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) +for level in range(n_hierarchical_levels): + plt.plot(test_temperatures, err_eff_C[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], + markevery=8) +plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_C)], loc='upper left') + +ylabel = r'Relative error $e_{\overline{\boldmath{\varepsilon}}_{\uptheta}}$ [\%]' +fig_name = 'eg3_hierarchical_sampling_err_eff_thermal_strain' +plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) +for level in range(n_hierarchical_levels): + plt.plot(test_temperatures, err_eff_eps[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], + markevery=8) +plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_eps)], loc='upper left') diff --git a/eg04_hierarchical_sampling_efficient.py b/eg04_hierarchical_sampling_efficient.py new file mode 100644 index 0000000..8a67346 --- /dev/null +++ b/eg04_hierarchical_sampling_efficient.py @@ -0,0 +1,252 @@ +from operator import itemgetter + +import h5py +import numpy.linalg as la + +from interpolate_fluctuation_modes import update_affine_decomposition, effective_S, effective_stress_localization, \ + interpolate_fluctuation_modes, get_phi, transform_strain_localization +from microstructures import * +from optimize_alpha import opt4_alphas, opt4 +from utilities import read_h5, construct_stress_localization, compute_err_indicator_efficient, volume_average + +np.random.seed(0) +# np.set_printoptions(precision=3) + +for ms_id in [0]: + file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', + 'n_tests', + 'sampling_alphas')(microstructures[ms_id]) + print(file_name, '\t', data_path) + out_file = path(f'output/opt_{file_name.name}') + given_alpha_levels = True if sampling_alphas is not None else False + + # debuging options + # given_alpha_levels = False + # n_tests = 10 + + n_hierarchical_levels = len(sampling_alphas) if sampling_alphas is not None else 5 + test_temperatures = np.linspace(temp1, temp2, num=n_tests) + test_alphas = np.linspace(0, 1, num=n_tests) + + # read reference solutions + mesh, refs = read_h5(file_name, data_path, test_temperatures) + mat_id = mesh['mat_id'] + n_gauss = mesh['n_gauss'] + strain_dof = mesh['strain_dof'] + global_gradient = mesh['global_gradient'] + n_gp = mesh['n_integration_points'] + n_phases = len(np.unique(mat_id)) + N_modes = refs[0]['strain_localization'].shape[2] - 7 + + # extract temperature dependent data from the reference solutions + # such as: material stiffness and thermal strain at each temperature and for all phases + Erefs = np.zeros((n_tests, *refs[0]['strain_localization'].shape)) # n_tests x n_phases x 6 x 6 + ref_Cs = np.zeros((n_tests, *refs[0]['mat_stiffness'].shape)) # n_tests x n_phases x 6 x 6 + ref_epss = np.zeros((n_tests, *refs[0]['mat_thermal_strain'].shape)) # n_tests x n_phases x 6 x 1 + effSref = np.zeros((n_tests, strain_dof, N_modes + 7)) # n_tests x 6 x (N + 7) + normalization_factor_mech = np.zeros((n_tests)) + plastic_modes = refs[0]['plastic_modes'] # temperature independent + for idx, alpha in enumerate(test_alphas): + print(idx) + Erefs[idx] = refs[idx]['strain_localization'] + ref_Cs[idx] = refs[idx]['mat_stiffness'] + ref_epss[idx] = refs[idx]['mat_thermal_strain'] + normalization_factor_mech[idx] = refs[idx]['normalization_factor_mech'] + Sref = construct_stress_localization(Erefs[idx], ref_Cs[idx], ref_epss[idx], plastic_modes, mat_id, n_gauss, + strain_dof) + effSref[idx] = volume_average(Sref) + + err_indicators, err_eff_S, err_eff_C, err_eff_eps = [np.zeros((n_hierarchical_levels, n_tests)) for _ in range(4)] + interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) + err = lambda x, y: la.norm(x - y) / la.norm(y) * 100 + + # alpha_all_levels is initialized with the first level of two samples + alpha_all_levels = [np.linspace(0, 1, num=2)] if not given_alpha_levels else sampling_alphas + + file = h5py.File(out_file, 'w') + + for level in range(n_hierarchical_levels): + print(f'\n --- {level = :.2f} --- \n') + + # read sampling data given current sampling points. note that samples are reread in the next hierarchical level + # but as long as everything is stored is h5 & no solvers are called there's no need for optimizing performance here + alphas = alpha_all_levels[level] + temperatures = interpolate_temp(temp1, temp2, alphas) + n_samples = len(alphas) + _, samples = read_h5(file_name, data_path, temperatures, get_mesh=False) + # lists that contain quantities from sampling pairs + E01s, sampling_Cs, sampling_epss = [], [], [] + for id0 in range(n_samples - 1): + id1 = id0 + 1 + E0 = samples[id0]['strain_localization'] + E1 = samples[id1]['strain_localization'] + E01s.append(np.ascontiguousarray(np.concatenate((E0, E1), axis=-1))) + # n_samples of [n_phases x 2 x 6 x 6] + sampling_Cs.append(np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3])) + # n_samples of [n_phases x 2 x 6 x 1] + sampling_epss.append( + np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3])) + + # alphas_indexing will contain the id of each pair of samples needed to solve the problem at a specific temperature + # temperatures are determined by the values contained in tes_alphas + alphas_indexing = np.searchsorted(alphas, test_alphas) - 1 + alphas_indexing[0] = 0 + + current_sampling_id = None + K0, K1, F0, F1, F2, F3, S001, S101, S103, S002, S102, S104 = [None for _ in range(12)] + + for idx, alpha in enumerate(test_alphas): + print(f'{alpha = :.2f}') + + sampling_C = sampling_Cs[alphas_indexing[idx]] + sampling_eps = sampling_epss[alphas_indexing[idx]] + + # interpolated quantities using an implicit interpolation scheme with four DOF + alpha_C, alpha_eps = opt4_alphas(sampling_C, sampling_eps, ref_Cs[idx], ref_epss[idx]) + alpha_C_eps = alpha_C * alpha_eps + + # Assemble the linear system only when new samples are considered + if alphas_indexing[idx] != current_sampling_id: + current_sampling_id = alphas_indexing[idx] + + K0, K1, F0, F1, F2, F3, S001, S101, S103, S002, S102, S104 = update_affine_decomposition( + E01s[current_sampling_id], sampling_C, sampling_eps, plastic_modes, N_modes, n_phases, + n_gp, strain_dof, + mat_id, n_gauss) + + phi = get_phi(K0, K1, F0, F1, F2, F3, alpha_C, alpha_eps, alpha_C_eps) + + speed = 1 + # if speed == 0: + C, eps = ref_Cs[idx], ref_epss[idx] + # C, eps = opt4(sampling_C, sampling_eps, ref_Cs[idx], ref_epss[idx]) + _, effSopt = interpolate_fluctuation_modes(E01s[current_sampling_id], C, eps, plastic_modes, mat_id, n_gauss, + strain_dof, + N_modes, n_gp) + #elif speed == 1: + # TODO verify the result when plasticity is on + effSopt1 = effective_stress_localization(E01s[current_sampling_id], phi, ref_Cs[idx], ref_epss[idx], plastic_modes, + mat_id, + n_gauss, n_gp, strain_dof, N_modes) + #elif speed == 2: + # TODO verify the result when plasticity is on + # matches the result from interpolate_fluctuatioN_modes with a difference + # that depends on using ref_Cs[idx],ref_epss[idx] instead of alphas + effSopt2, phi2 = effective_S(phi, S001, S101, S103, S002, S102, S104, alpha_C, np.squeeze(alpha_eps, axis=-1), + np.squeeze(alpha_C_eps, axis=-1)) + #else: + # raise NotImplementedError() + print(np.linalg.norm(effSopt - effSopt1)) + + if not given_alpha_levels: + Eopt4 = transform_strain_localization(E01s[current_sampling_id], phi, n_gp, strain_dof, N_modes) + Sopt4 = construct_stress_localization(Eopt4, ref_Cs[idx], ref_epss[idx], plastic_modes, mat_id, n_gauss, + strain_dof) + # effSopt = volume_average(Sopt4) + err_indicators[level, + idx] = np.mean(np.max(np.abs(compute_err_indicator_efficient(Sopt4, global_gradient)), + axis=0)) / normalization_factor_mech[idx] * 100 + + err_eff_S[level, idx] = err(effSopt, effSref[idx]) + + Capprox = effSopt[:6, :6] + Cref = effSref[idx][:6, :6] + invL = la.inv(la.cholesky(Cref)) + + err_eff_C[level, idx] = la.norm(invL @ Capprox @ invL.T - np.eye(6)) / la.norm(np.eye(6)) * 100 + err_eff_eps[level, idx] = err(la.solve(Capprox, effSopt[:, 7]), la.solve(Cref, effSref[idx][:, 7])) + + # TODO remove dtype='f' + group = file.require_group(f'{data_path}_level{level}') + # group.attrs['sampling_strategy'] = "model description" + temperature = test_temperatures[idx] + dset_stiffness = group.require_dataset(f'eff_stiffness_{temperature:07.2f}', (6, 6), dtype='f') + dset_thermal_strain = group.require_dataset(f'eff_thermal_strain_{temperature:07.2f}', (6), dtype='f') + dset_stiffness[:] = Capprox.T + dset_thermal_strain[:] = la.solve(Capprox, effSopt[:, 7]) + + if not given_alpha_levels: + max_err_idx = np.argmax(err_indicators[level]) + alpha_all_levels.append(np.unique(np.sort(np.hstack((alphas, test_alphas[max_err_idx]))))) + + file.close() + idx = [idx for idx, microstructure in enumerate(microstructures) if file_name == microstructure['file_name']][0] + np.savez_compressed(f'output/eg4_{idx}', n_hierarchical_levels=n_hierarchical_levels, test_temperatures=test_temperatures, + err_indicators=err_indicators, err_eff_S=err_eff_S, err_eff_C=err_eff_C, err_eff_eps=err_eff_eps, + alpha_all_levels=np.asarray(alpha_all_levels, dtype=object)) + + # %% + import numpy as np + import numpy.linalg as la + import matplotlib.pyplot as plt + from utilities import plot_and_save, cm + from matplotlib.ticker import FormatStrFormatter + + # loaded_qoi = np.load(f'output/eg4_{idx}.npz', allow_pickle=True) + # n_hierarchical_levels = loaded_qoi['n_hierarchical_levels'] + # test_temperatures = loaded_qoi['test_temperatures'] + # err_indicators = loaded_qoi['err_indicators'] + # err_eff_S = loaded_qoi['err_eff_S'] + # err_eff_C = loaded_qoi['err_eff_C'] + # err_eff_eps = loaded_qoi['err_eff_eps'] + # alpha_all_levels = loaded_qoi['alpha_all_levels'] + + temp1 = test_temperatures[0] + temp2 = test_temperatures[-1] + interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) + + for level in range(n_hierarchical_levels): + print(f'alphas of level {level}: {alpha_all_levels[level]}') + print('\n') + for level in range(n_hierarchical_levels): + print(f'temperatures of level {level}: {interpolate_temp(temp1, temp2, alpha_all_levels[level])}') + print('\n') + for level in range(n_hierarchical_levels): + print(f'level {level}') + print(f'{np.max(err_indicators[level]) = }') + + xlabel = 'Temperature [K]' + styles = ['-', '-', '--', '-.', ':', ':', ':', ':'] + markers = ['s', 'd', '+', 'x', 'o'] + colors = ['C0', 'C1', 'C2', 'C3', 'C4'] + if not given_alpha_levels: + ylabel = 'Relative error $e_\mathsf{I}$ [\%]' + fig_name = f'eg4_{idx}_hierarchical_sampling_err_indicator' + plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) + for level in range(n_hierarchical_levels): + plt.plot(test_temperatures, err_indicators[level], label=f'{level + 2} samples', marker=markers[level], + color=colors[level], linestyle=styles[level], markevery=8) + plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) + plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_indicators)], loc='upper left') + + ylabel = 'Relative error $e_{\overline{\mathsf{S}}}$ [\%]' + fig_name = f'eg4_{idx}_hierarchical_sampling_err_eff_stress_localization' + plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) + for level in range(n_hierarchical_levels): + plt.plot(test_temperatures, err_eff_S[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], + linestyle=styles[level], markevery=8) + plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) + plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_S)], loc='upper left') + + ylabel = 'Relative error $e_{\overline{\mathbb{C}}}$ [\%]' + fig_name = f'eg4_{idx}_hierarchical_sampling_err_eff_stiffness' + plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) + for level in range(n_hierarchical_levels): + plt.plot(test_temperatures, err_eff_C[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], + linestyle=styles[level], markevery=8) + plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) + plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_C)], loc='upper left') + + ylabel = r'Relative error $e_{\overline{\boldmath{\varepsilon}}_{\uptheta}}$ [\%]' + fig_name = f'eg4_{idx}_hierarchical_sampling_err_eff_thermal_strain' + plt.figure(figsize=(6 * cm, 6 * cm), dpi=600) + for level in range(n_hierarchical_levels): + plt.plot(test_temperatures, err_eff_eps[level], label=f'{level + 2} samples', marker=markers[level], color=colors[level], + linestyle=styles[level], markevery=8) + plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) + plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, np.max(err_eff_eps)], loc='upper left') + + print(np.max(err_indicators)) + print(np.max(err_eff_S)) + print(np.max(err_eff_C)) + print(np.max(err_eff_eps)) diff --git a/eg05_FFANN.py b/eg05_FFANN.py new file mode 100644 index 0000000..3e9dbc1 --- /dev/null +++ b/eg05_FFANN.py @@ -0,0 +1,147 @@ +# %% +# # JEL_thermo-el-ROM: Machine Learned Model +# ### Imports: +from operator import itemgetter + +import h5py +import matplotlib.cm as colormap +import matplotlib.pyplot as plt +import torch +from torch import nn +from torch.utils.data import DataLoader, TensorDataset + +from microstructures import * +from utilities import read_h5 +from utilities_ann import cholesky, reverse_cholesky, hierarchical_sampling, RectFFModule, model_training, \ + plot_training_history + +torch.set_default_dtype(torch.float32) +# ### Load DNS data from HDF5 file: +for ms_id in [7, 8, 9]: + file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', + 'n_tests', + 'sampling_alphas')(microstructures[ms_id]) + # debuging options + # sampling_alphas = [sampling_alphas[-1]] + + print(file_name, '\t', data_path) + out_file = path(f'output/ann_{file_name.name}') + test_temperatures = np.linspace(temp1, temp2, num=n_tests) + test_alphas = np.linspace(0, 1, num=n_tests) + _, refs = read_h5(file_name, data_path, test_temperatures, get_mesh=False) + x = test_temperatures[:, None] + y = np.stack([np.hstack((cholesky(ref['eff_stiffness']), ref['eff_thermal_strain'])) for ref in refs]) + + # ### Data scaling: + # As sole input feature the temperature $\theta$ is used. + # The output features $y = [\mathrm{vec}(L), E] \in \mathbb{R}^{27}$ are given by the Cholesky decomposition $L$ of the Mandel notation $C = L L^\intercal$ of the fourth-order effective stiffness tensor $\mathbb{C}$ and the Mandel notation $E \in \mathbb{R}^6$ of the thermal strain tensor $\varepsilon_\theta$ that are obtained by the DNS. + # Since the different components of $y$ differ greatly in magnitude, each output feature is normalized with its absolute maximum value. + # Scaling + x = torch.FloatTensor(x / np.max(x, axis=0)) + y_normalization_factor = np.max(np.abs(y), axis=0) + y = torch.FloatTensor(y / y_normalization_factor) + dset = TensorDataset(x, y) + n_out_features = y.size()[1] + n_in_features = x.size()[1] + + file = h5py.File(out_file, 'w') + for level, sampling_alpha in enumerate(sampling_alphas): + # ### Data sampling: + # #### Bisection sampling: + # reproducibility + torch.manual_seed(1) + torch.use_deterministic_algorithms(True) + # Split in test and validation data + # train_data, val_data = bisection_sampling(dset, levels=3, samples_per_pos=1, validation=True) + # sampling_alphas = np.asarray([0, 0.41, 0.74, 0.9, 0.95, 1]) + train_data, val_data = hierarchical_sampling(dset, x[:, 0], sampling_alpha) + + # Create dataloaders + batch_size = len(train_data) + train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True) + val_loader = DataLoader(val_data, batch_size=len(val_data)) + # Create a PyTorch model for a Feedforward Artificial Neural Network (FFANN) with 3 hidden layers and 64 neurons per layer. + # `Tanh` is used as activation function in the hidden layers and the identity as activation function in the output layer. + model = RectFFModule(n_in_features, 64, 3, nn.Tanh(), nn.Identity(), n_out_features) + # print(model) + + # The MSE loss function is used for training. Using the "mechanical loss function", which is defined as + # $$\frac{||L_{pred} - L||_F}{||L||_F} + \frac{||\varepsilon_{\theta,pred} - \varepsilon_{\theta}||_F}{||\varepsilon_\theta||_F}$$ + # Here, using the Adam as optimizer leads to faster convergence than using Stochastic Gradient Descent (SGD). + loss_fn = nn.MSELoss(reduction='mean') + # loss_fn = mech_loss + optimizer = torch.optim.Adam(model.parameters(), lr=2e-4) + train_losses, val_losses, best_epoch = model_training(model, loss_fn, optimizer, train_loader, val_loader, + epochs=4000 * len(train_data), verbose=False) + + # The training history of the ANN is plotted in the figure below. + fig, ax = plt.subplots() + plot_training_history(ax, train_losses, val_losses, best_epoch) + y_pred = model(x) + + # The predictions of the ANN are compared to the ground truth in the figure below. + fig, ax = plt.subplots(1, 1, figsize=[4, 4]) + colors = colormap.rainbow(np.linspace(0, 1, n_out_features)) + for i in range(n_out_features): + ax.plot(test_temperatures, y[:, i], '-', color=colors[i], lw=1) + ax.plot(test_temperatures, y_pred[:, i].detach().numpy(), '--', color=colors[i], lw=2) + ax.set_title('normalized features') + ax.set_xlabel(r'Temperature $\theta$ [K]') + ax.set_ylabel(r'Scaled output feature [-]') + plt.grid('on') + plt.tight_layout() + plt.show(block=False) + + # Plot of the error + norm_error = np.linalg.norm(y - y_pred.detach(), axis=1) / np.linalg.norm(y, axis=1) * 100 + fig, ax = plt.subplots(1, 1, figsize=[4, 4]) + ax.plot(test_temperatures, norm_error, 'b-', label='0 levels') + ax.set_xlabel(r'Temperature [K]') + ax.set_ylabel(r'Relative error [\%]') + plt.grid('on') + plt.tight_layout() + plt.show(block=False) + print(f'{np.argmax(norm_error)/100 = :.2f}') + print(f'{len(train_data)} samples') + print(f'{len(val_data)} validations') + print(f'{np.max(norm_error) = :.2f} %') + + # %% + y_approx = y_pred.detach().numpy() * y_normalization_factor + errC = np.zeros(n_tests) + erreps = np.zeros(n_tests) + + group = file.require_group(f'{data_path}_level{level}') + # group.attrs['sampling_strategy'] = "model description" + for i, ref in enumerate(refs): + dset_stiffness = group.require_dataset(f'eff_stiffness_{test_temperatures[i]:07.2f}', (6, 6), dtype='f') + dset_thermal_strain = group.require_dataset(f'eff_thermal_strain_{test_temperatures[i]:07.2f}', (6), dtype='f') + + C = reverse_cholesky(y_approx[i, :21]) + eps = y_approx[i, 21:] + + dset_stiffness[:] = C.T + dset_thermal_strain[:] = eps + + Cref = np.asarray(ref['eff_stiffness'], dtype=float) + epsref = np.asarray(ref['eff_thermal_strain'], dtype=float) + invL = np.linalg.inv(np.linalg.cholesky(Cref)) + errC[i] = np.linalg.norm(invL @ C @ invL.T - np.eye(6)) / np.linalg.norm(np.eye(6)) * 100 + erreps[i] = np.linalg.norm(epsref - eps) / np.linalg.norm(epsref) * 100 + # erreps[i] = (epsref @ Cref @ epsref - eps @ Cref @ eps) / (epsref @ Cref @ epsref) * 100 + + ylabels = [ + 'Relative error $e_{\overline{\mathbb{C}}}$ [\%]', + r'Relative error $e_{\overline{\boldmath{\varepsilon}}_{\uptheta}}$ [\%]' + ] + for idx, err in enumerate([errC, erreps]): + fig, ax = plt.subplots(1, 1, figsize=[4, 4]) + ax.plot(test_temperatures, err, 'b-') + ax.set_xlabel(r'Temperature [K]') + ax.set_ylabel(ylabels[idx]) + plt.grid('on') + plt.tight_layout() + plt.show(block=False) + print(f'{np.max(err) = :.2f} %') + plt.close('all') + file.close() diff --git a/eg06_post_process_ann_vs_proposed.py b/eg06_post_process_ann_vs_proposed.py new file mode 100644 index 0000000..f08bfef --- /dev/null +++ b/eg06_post_process_ann_vs_proposed.py @@ -0,0 +1,122 @@ +# %% +from operator import itemgetter + +import h5py +import matplotlib.pyplot as plt +import numpy.linalg as la +from matplotlib.ticker import FormatStrFormatter + +from microstructures import * +from utilities import plot_and_save, cm + +n_hierarchical_levels = 5 +ms_id = 9 +file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', + 'sampling_alphas')(microstructures[ms_id]) +print(file_name, '\t', data_path) +opt_file = path(f'output/opt_{file_name.name}') +ann_file = path(f'output/ann_{file_name.name}') + +test_temperatures = np.linspace(temp1, temp2, num=n_tests) + +refC = np.zeros((n_tests, 6, 6)) +ref_eps = np.zeros((n_tests, 6)) + +optC = np.zeros((n_tests, n_hierarchical_levels, 6, 6)) +opt_eps = np.zeros((n_tests, n_hierarchical_levels, 6)) + +annC = np.zeros((n_tests, n_hierarchical_levels, 6, 6)) +ann_eps = np.zeros((n_tests, n_hierarchical_levels, 6)) + +for level in range(n_hierarchical_levels): + with h5py.File(file_name, 'r') as file: + for idx, temperature in enumerate(test_temperatures): + refC[idx] = file[f'{data_path}/eff_stiffness_{temperature:07.2f}'][:] + ref_eps[idx] = file[f'{data_path}/eff_thermal_strain_{temperature:07.2f}'][:] + + with h5py.File(opt_file, 'r') as file: + for idx, temperature in enumerate(test_temperatures): + optC[idx, level] = file[f'{data_path}_level{level}/eff_stiffness_{temperature:07.2f}'][:] + opt_eps[idx, level] = -file[f'{data_path}_level{level}/eff_thermal_strain_{temperature:07.2f}'][:] + + with h5py.File(ann_file, 'r') as file: + for idx, temperature in enumerate(test_temperatures): + annC[idx, level] = file[f'{data_path}_level{level}/eff_stiffness_{temperature:07.2f}'][:] + ann_eps[idx, level] = file[f'{data_path}_level{level}/eff_thermal_strain_{temperature:07.2f}'][:] + +# %% +err_eff_C_opt = np.zeros((n_tests, n_hierarchical_levels)) +err_eff_eps_opt = np.zeros((n_tests, n_hierarchical_levels)) + +err_eff_C_ann = np.zeros((n_tests, n_hierarchical_levels)) +err_eff_eps_ann = np.zeros((n_tests, n_hierarchical_levels)) + +err = lambda x, y: la.norm(x - y) * 100 / la.norm(y) +err_energy = lambda x, y, C: (y @ C @ y - x @ C @ x) / (y @ C @ y) * 100 + +for level in range(n_hierarchical_levels): + for idx, temperature in enumerate(test_temperatures): + invL = la.inv(la.cholesky(refC[idx])) + + err_eff_C_opt[idx, level] = la.norm(invL @ optC[idx, level] @ invL.T - np.eye(6)) / la.norm(np.eye(6)) * 100 + err_eff_C_ann[idx, level] = la.norm(invL @ annC[idx, level] @ invL.T - np.eye(6)) / la.norm(np.eye(6)) * 100 + + err_eff_eps_opt[idx, level] = err(opt_eps[idx, level], ref_eps[idx]) + err_eff_eps_ann[idx, level] = err(ann_eps[idx, level], ref_eps[idx]) + + # err_eff_eps_opt[idx, level] = err_energy(opt_eps[idx, level], ref_eps[idx], refC[idx]) + # err_eff_eps_ann[idx, level] = err_energy(ann_eps[idx, level], ref_eps[idx], refC[idx]) + +# %% +level = 4 + +xlabel = 'Temperature [K]' +styles = ['-', '--', ':', '-.', ':', ':', ':'] +markers = ['s', 'd', '+', 'x', 'o'] +colors = ['C0', 'C1', 'C2', 'C3', 'C4'] + +ylabel = 'Relative error $e_{\overline{\mathbb{C}}}$ [\%]' +fig_name = f'eg5_{ms_id}_hierarchical_sampling_err_eff_stiffness' +fig, ax = plt.subplots(figsize=(6 * cm, 6 * cm), dpi=600) +# axins = ax.inset_axes([0.53, 0.42, 0.4, 0.3]) +axins = ax.inset_axes([0.23, 0.42, 0.4, 0.3]) +# for level in range(n_hierarchical_levels): +plt.plot(test_temperatures, err_eff_C_opt[:, level], label=f'O$_4$ {level + 2} samples', marker=markers[level], color=colors[1], + linestyle='--', markevery=8) +axins.plot(test_temperatures, err_eff_C_opt[:, level], label=f'O$_4$ {level + 2} samples', marker=markers[level], color=colors[1], + linestyle='--', markevery=8) +plt.plot(test_temperatures, err_eff_C_ann[:, level], label=f'ANN {level + 2} samples', marker=markers[level], color=colors[0], + linestyle='-', markevery=8) +axins.grid('on') +axins.grid(ls='--', color='gray', linewidth=0.5) +axins.set_xlim(temp1, temp2) +axins.set_ylim(0.0, 0.020) +axins.get_xaxis().set_visible(False) +ax.indicate_inset_zoom(axins, facecolor=(0.8, 0.8, 0.8, 0.6), edgecolor=(0.3, 0.3, 0.3, 0.3), lw=0.1) +plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) +# plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 3.5], loc='upper right') +# plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 1.5], loc='upper right') +plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 2.2], loc='upper right') + +# %% +ylabel = r'Relative error $e_{\overline{\boldmath{\varepsilon}}_{\uptheta}}$ [\%]' +fig_name = f'eg5_{ms_id}_hierarchical_sampling_err_eff_thermal_strain' +fig, ax = plt.subplots(figsize=(6 * cm, 6 * cm), dpi=600) +axins = ax.inset_axes([0.53, 0.42, 0.4, 0.3]) +# for level in range(n_hierarchical_levels): +plt.plot(test_temperatures, err_eff_eps_opt[:, level], label=f'O$_4$ {level + 2} samples', marker=markers[level], color=colors[1], + linestyle='--', markevery=8) +axins.plot(test_temperatures, err_eff_eps_opt[:, level], label=f'O$_4$ {level + 2} samples', marker=markers[level], + color=colors[1], linestyle='--', markevery=8) +plt.plot(test_temperatures, err_eff_eps_ann[:, level], label=f'ANN {level + 2} samples', marker=markers[level], color=colors[0], + linestyle='-', markevery=8) +axins.grid('on') +axins.grid(ls='--', color='gray', linewidth=0.5) +axins.set_xlim(temp1, temp2) +axins.set_ylim(0.0, 0.2) +axins.get_xaxis().set_visible(False) +ax.indicate_inset_zoom(axins, facecolor=(0.8, 0.8, 0.8, 0.6), edgecolor=(0.3, 0.3, 0.3, 0.3), lw=0.1) +plt.gca().yaxis.set_major_formatter(FormatStrFormatter('%.2f')) +# plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 15], loc='upper right') +# plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 4], loc='upper right') +plot_and_save(xlabel, ylabel, fig_name, [temp1, temp2], [0, 7], loc='upper right') diff --git a/eg07_staggered_model_interpolation.py b/eg07_staggered_model_interpolation.py new file mode 100644 index 0000000..92aedfa --- /dev/null +++ b/eg07_staggered_model_interpolation.py @@ -0,0 +1,81 @@ +""" +Interpolate the homogenized response (i.e. effective C and effective eps) at arbitrary temperatures +based on the approximations in eg3_hierarchical_sampling.py or eg4_hierarchical_sampling_efficient.py +""" +# %% +from operator import itemgetter +import time +import h5py +from scipy import interpolate +from microstructures import * + +# Offline stage: Load precomputed optimal data +load_start = time.time() +ms_id = 6 +level = 4 +file_name, data_path, temp1, temp2, n_samples, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', + 'sampling_alphas')(microstructures[ms_id]) +opt_file = path(f'output/opt_{file_name.name}') +print(f'Loading precomputed data from {file_name}\t{data_path}') + +sample_temperatures = np.linspace(temp1, temp2, num=n_samples) + +opt_C = np.zeros((n_samples, 6, 6)) +opt_eps = np.zeros((n_samples, 6)) + +try: + with h5py.File(opt_file, 'r') as file: + for idx, temperature in enumerate(sample_temperatures): + opt_C[idx] = file[f'{data_path}_level{level}/eff_stiffness_{temperature:07.2f}'][:] + # eg4_*.py saves (-1 * eff_thermal_strain) in the corresponding h5 file + opt_eps[idx] = -1.0 * file[f'{data_path}_level{level}/eff_thermal_strain_{temperature:07.2f}'][:] +except Exception: + print(f'Could not load precomputed data. Run eg4_*.py first for ms_id={ms_id}, level={level}.') + exit() + +load_time = time.time() - load_start +print(f'Loaded precomputed data at {n_samples} temperatures in {load_time:.5f} s') + +# %% +# Online stage: linear interpolation between sampled data +online_start = time.time() +n_tests = 1000 +test_temperatures = np.linspace(temp1, temp2, num=n_tests) + + +def staggered_model_online(test_temperatures, sample_temperatures, opt_C, opt_eps): + """Interpolate the effective stiffness C and the effective thermal expansion eps + at a list of temperatures in `test_temperatures` using linear interpolation + based on precomputed `opt_C` and `opt_eps` at `sample_temperatures`. + + Args: + test_temperatures (np.ndarray): array of temperatures with shape (N,) + sample_temperatures (np.ndarray): array of temperatures with shape (n,) + opt_C (np.ndarray): optimal C at n temperatures with shape (n,6,6) + opt_eps (np.ndarray): optimal eps at n temperatures with shape (n,6) + + Returns: + np.ndarray: array of interpolated C with shape (N,6,6) + np.ndarray: array of interpolated eps with shape (N,6) + """ + # Linear interpolation for C + interp_C = interpolate.interp1d(sample_temperatures, opt_C, axis=0) + approx_C = interp_C(test_temperatures) + # Linear interpolation for eps + interp_eps = interpolate.interp1d(sample_temperatures, opt_eps, axis=0) + approx_eps = interp_eps(test_temperatures) + return approx_C, approx_eps + + +approx_C, approx_eps = staggered_model_online(test_temperatures, sample_temperatures, opt_C, opt_eps) + +online_time = time.time() - online_start +print(f'Interpolated C and eps at {n_tests} temperatures in {online_time:.5f} s') + +# Print interpolated C and eps at a specific data point +idx = 123 +np.set_printoptions(precision=4) +print(f'Interpolated C at {test_temperatures[idx]:.4f} K:') +print(approx_C[idx]) +print(f'Interpolated eps at {test_temperatures[idx]:.4f} K:') +print(approx_eps[idx]) diff --git a/eg08_plot_localization.py b/eg08_plot_localization.py new file mode 100644 index 0000000..c73e7f5 --- /dev/null +++ b/eg08_plot_localization.py @@ -0,0 +1,153 @@ +""" +Plot the strain localization operator E and stress localization operator S at different temperatures +""" +#%% +from operator import itemgetter + +import numpy.linalg as la +import matplotlib.pyplot as plt +from microstructures import * +from utilities import read_h5, construct_stress_localization + +################ + + + + stress_localization = np.empty_like(strain_localization) + strain_localization_transp = ... + I = np.eye(strain_dof) + for gp_id in prange(strain_localization.shape[0]): + phase_id = mat_id[gp_id // n_gauss] + stress_localization[gp_id] = strain_localization_transp[gp_id] @ mat_stiffness[phase_id] @ (plastic_modes - eigen_strains) + A = volume_average(stress_localization) + + D0 = volume_average(inner_product((plastic_modes - eigen_strains), eigen_strains)) + + K0 = -volume_average(inner_product(plastic_modes, K @ eigen_strains)) + K = k * K0 + + D = D0 + K + + R = volume_average(thermal_stresses @ (plastic_modes - eigen_strains)) / delta_theta + + +########### + +np.random.seed(0) +file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( + "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" +)(microstructures[7]) +print(file_name, "\t", data_path) + +test_temperatures = np.linspace(temp1, temp2, num=n_tests) +test_alphas = np.linspace(0, 1, num=n_tests) + +mesh, ref = read_h5(file_name, data_path, test_temperatures) +mat_id = mesh["mat_id"] +n_gauss = mesh["n_gauss"] +strain_dof = mesh["strain_dof"] +nodal_dof = mesh["nodal_dof"] +n_elements = mesh["n_elements"] +global_gradient = mesh["global_gradient"] +n_gp = mesh["n_integration_points"] +n_modes = ref[0]["strain_localization"].shape[-1] +disc = mesh["combo_discretisation"] + +# Lowest temperature +temp0 = ref[0]["temperature"] +E0 = ref[0]["strain_localization"] +C0 = ref[0]["mat_stiffness"] +eps0 = ref[0]["mat_thermal_strain"] +S0 = construct_stress_localization(E0, C0, eps0, mat_id, n_gauss, strain_dof) + +# First enrichment temperature +a = len(ref) // 2 +if sampling_alphas is not None: + alpha = sampling_alphas[1][1] + a = int(alpha * n_tests) +tempa = ref[a]["temperature"] +Ea = ref[a]["strain_localization"] +Ca = ref[a]["mat_stiffness"] +epsa = ref[a]["mat_thermal_strain"] +Sa = construct_stress_localization(Ea, Ca, epsa, mat_id, n_gauss, strain_dof) + +# Highest temperature +temp1 = ref[-1]["temperature"] +E1 = ref[-1]["strain_localization"] +C1 = ref[-1]["mat_stiffness"] +eps1 = ref[-1]["mat_thermal_strain"] +S1 = construct_stress_localization(E1, C1, eps1, mat_id, n_gauss, strain_dof) + +# %% + + +def plot_localization(ax, E, idx=0): + """Plots the effective total strain/stress norm (not the deviatoric part) + of a given localization operator `E` on the y-z-cross section at x=idx. + + Args: + ax: matplotlib axis + E (np.ndarray): localization operator with shape (nx*ny*nz*ngauss, 6, 7) + idx (int, optional): y-z-cross section index. Defaults to 0. + """ + assert E.ndim == nodal_dof + assert E.shape[0] == n_gp + assert E.shape[1] == strain_dof + # assert E.shape[2] == n_modes + E_r = E.reshape(*disc, n_gauss, strain_dof, n_modes) + E_ra = np.mean(E_r, axis=3) # average over gauss points + # compute the effective total strain norm (not the deviatoric part); + # account for Mandel notation, i.e. activation strain with all components being 1.0 + E_rai = np.einsum('ijklm,m', E_ra, np.asarray([1, 1, 1, np.sqrt(2), np.sqrt(2), np.sqrt(2), 1])) + effective_strain = np.sqrt(2/3) * la.norm(E_rai, axis=-1) + # plot y-z-cross section at x=idx + ax.imshow(effective_strain[idx, :, :], interpolation="gaussian") + + +# Plot strain localization operator E at different temperatures +fig, ax = plt.subplots(1, 3) +plot_localization(ax[0], E0, idx=0) +ax[0].set_title( + r"$\underline{\underline{E}}\;\mathrm{at}\;\theta=" + + f"{temp0:.2f}" + + r"\mathrm{K}$" +) +plot_localization(ax[1], Ea, idx=0) +ax[1].set_title( + r"$\underline{\underline{E}}\;\mathrm{at}\;\theta=" + + f"{tempa:.2f}" + + r"\mathrm{K}$" +) +plot_localization(ax[2], E1, idx=0) +ax[2].set_title( + r"$\underline{\underline{E}}\;\mathrm{at}\;\theta=" + + f"{temp1:.2f}" + + r"\mathrm{K}$" +) +plt.savefig("output/E.png", dpi=300) +plt.show() + +# Plot stress localization operator S at different temperatures +fig, ax = plt.subplots(1, 3) +plot_localization(ax[0], S0, idx=0) +ax[0].set_title( + r"$\underline{\underline{S}}\;\mathrm{at}\;\theta=" + + f"{temp0:.2f}" + + r"\mathrm{K}$" +) +plot_localization(ax[1], Sa, idx=0) +ax[1].set_title( + r"$\underline{\underline{S}}\;\mathrm{at}\;\theta=" + + f"{tempa:.2f}" + + r"\mathrm{K}$" +) +plot_localization(ax[2], S1, idx=0) +ax[2].set_title( + r"$\underline{\underline{S}}\;\mathrm{at}\;\theta=" + + f"{temp1:.2f}" + + r"\mathrm{K}$" +) +plt.savefig("output/S.png", dpi=300) +plt.show() + +# %% diff --git a/eg10_compare_ntfa_matrices.py b/eg10_compare_ntfa_matrices.py new file mode 100644 index 0000000..b6525c3 --- /dev/null +++ b/eg10_compare_ntfa_matrices.py @@ -0,0 +1,72 @@ +""" +Demo code for plastic mode identification and processing, i.e. computation of the system matrices +""" +#%% +from operator import itemgetter + +import numpy.linalg as la +import matplotlib.pyplot as plt +import time +from microstructures import * +from utilities import read_h5 +from ntfa import read_snapshots, mode_identification, compute_tabular_data, save_tabular_data + +np.random.seed(0) +for microstructure in microstructures[-8:]: + file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( + "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" + )(microstructure) + print(file_name, "\t", data_path) + + sample_temperatures = np.linspace(temp1, temp2, num=n_tests) + + mesh, samples = read_h5(file_name, data_path, sample_temperatures) + mat_id = mesh["mat_id"] + n_gauss = mesh["n_gauss"] + strain_dof = mesh["strain_dof"] + nodal_dof = mesh["nodal_dof"] + n_elements = mesh["n_elements"] + n_integration_points = mesh["n_integration_points"] + global_gradient = mesh["global_gradient"] + n_gp = mesh["n_integration_points"] + disc = mesh["combo_discretisation"] + vol_frac = mesh['volume_fraction'][0] + + # Mode identification + + # Read plastic snapshots from h5 file + plastic_snapshots = read_snapshots(file_name, data_path) + print('plastic_snapshots.shape:', plastic_snapshots.shape) + + # Identification of plastic modes + r_min = 1e-8 + # plastic_modes_svd = mode_identification(plastic_snapshots, vol_frac, r_min) + # print('plastic_modes_svd.shape:', plastic_modes_svd.shape) + + # Compare computed plastic modes with plastic modes from h5 file + plastic_modes = samples[0]['plastic_modes'] + # assert np.allclose(plastic_modes / np.sign(np.expand_dims(np.expand_dims(plastic_modes[0,0,:], axis=0), axis=0)), plastic_modes_svd), 'Identified plastic modes do not match plastic modes in h5 file' + + # Mode processing to compute system matrices + + n_temp = 1000 + temperatures = np.linspace(temp1, temp2, num=n_temp) + start_time = time.time() + # TODO: compute system matrices for multiple intermediate temperatures in an efficient way + C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta = compute_tabular_data(samples, mesh, temperatures) + elapsed_time = time.time() - start_time + print(f'Computed tabular data for {n_temp} temperatures in {elapsed_time}s') + print('C_bar.shape:', C_bar.shape) + print('tau_theta.shape:', tau_theta.shape) + print('A_bar.shape:', A_bar.shape) + print('tau_xi.shape:', tau_xi.shape) + print('D_xi.shape:', D_xi.shape) + print('D_theta.shape:', D_theta.shape) + + # Save system matrices for multiple temperatures as tabular data + save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta) + # Tabular data is saved to the input h5 file and can be copied to a new h5 file using e.g. + # h5copy -i input/file.h5 -o input/file_ntfa.h5 -s ms_1p/dset0_ntfa -d ms_1p/dset0_ntfa -p + +#%% Compare interpolated NTFA matrices with exact NTFA matrices +# TODO: compute errors diff --git a/ntfa.py b/ntfa.py new file mode 100644 index 0000000..6976496 --- /dev/null +++ b/ntfa.py @@ -0,0 +1,380 @@ +""" +NTFA +""" +import numpy as np +import h5py +from utilities import * +from material_parameters import * + +def read_snapshots(file_name, data_path): + """ + Read an H5 file that contains responses of simulated microstructures + :param file_name: e.g. "input/simple_3d_rve_combo.h5" + :param data_path: the path to the simulation results within the h5 file, e.g. '/ms_1p/dset0_sim' + :return: + strain_snapshots: plastic strain snapshots eps_p + with shape (n_integration_points, strain_dof, n_frames) + """ + # TODO: read snapshots from H5 file. Because of the sheer amount of data it may be better to use a separate h5 file for the snapshots. + plastic_snapshots = None + with h5py.File(file_name, 'r') as file: + plastic_snapshots = np.transpose(file[f'{data_path}/plastic_strains'][:], (0, 2, 1)) + # For now, use dummy data: + # n_integration_points, strain_dof, n_frames = 512, 6, 100 + # plastic_snapshots = create_dummy_plastic_modes(n_integration_points, strain_dof, n_frames) + # TODO: Reorder snapshots as follows: | 1st strain path: last timestep to first timestep | 2nd strain path: last timestep to first timestep | ... + # or: reorder snapshots already in FANS? + return plastic_snapshots + + +def mode_identification_iterative(plastic_snapshots, vol_frac, r_min=1e-8): + """ + Identification of plastic strain modes µ using an iterative algorithm and renormalization + :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) + with shape (n_integration_points, strain_dof, n_frames) + :param r_min: stop criterion + :return: + plastic_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, n_modes) + """ + n_integration_points, strain_dof, n_frames = plastic_snapshots.shape + n_modes = 0 + plastic_modes = np.zeros((n_integration_points, strain_dof, n_modes)) + for i in range(n_frames): + eps_i = plastic_snapshots[:, :, i] + r = volume_average(inner_product(eps_i, eps_i)) # TODO: average only over Omega_p? + k = np.zeros(n_modes) # Coefficients k_j + for j in range(n_modes): + k[j] = volume_average(inner_product(eps_i, plastic_modes[:, :, j])) + r = r - k[j]**2 + if r < r_min: + break + if r > r_min: + n_modes = n_modes + 1 # increment number of modes + # Generate new strain mode: + plastic_mode = (eps_i - np.tensordot(k, plastic_modes, axes=(0,2))) / np.sqrt(r) + plastic_modes = np.concatenate([plastic_modes, np.expand_dims(plastic_mode, 2)], axis=2) + # Renormalize plastic modes + for i in range(n_modes): + weighting_factor = vol_frac / volume_average(norm_2(plastic_modes[:, :, i])) + plastic_modes[:, :, i] = plastic_modes[:, :, i] * weighting_factor * np.sign(plastic_modes[0, 0, i]) + return plastic_modes + + +def mode_identification(plastic_snapshots, vol_frac, r_min=1e-8): + """ + Identification of plastic strain modes µ using POD and renormalization + :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) + with shape (n_integration_points, strain_dof, n_frames) + :param r_min: stop criterion + :return: + plastic_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, n_modes) + """ + n_integration_points, strain_dof, n_frames = plastic_snapshots.shape + plastic_snapshots_rs = plastic_snapshots.transpose(1, 0, 2).reshape((strain_dof * n_integration_points, n_frames)) + u, s, v = np.linalg.svd(plastic_snapshots_rs, full_matrices=False) + s = s / s[0] + n_modes = np.argwhere(s > r_min).size + plastic_modes = u[:, :n_modes].reshape((strain_dof, n_integration_points, n_modes)).transpose(1, 0, 2) + # Renormalize plastic modes + for i in range(n_modes): + weighting_factor = vol_frac / volume_average(norm_2(plastic_modes[:, :, i])) + plastic_modes[:, :, i] = plastic_modes[:, :, i] * weighting_factor * np.sign(plastic_modes[0, 0, i]) + return plastic_modes + + +def compute_ntfa_matrices(strain_localization, stress_localization, plastic_modes, thermal_strain, mesh): + """ + Processing of the plastic strain modes µ to compute the matrices A_bar, D_xi, C_bar and the vector tau_theta + as tabular data at given temperatures + :param strain_localization: strain localization 3D array + with shape (n_integration_points, strain_dof, 7 + n_modes) + :param stress_localization: stress localization 3D array + with shape (n_integration_points, strain_dof, 7 + n_modes) + :param mat_stiffness: stiffness tensors of the phases + with shape (n_phases, strain_dof, strain_dof) + :param mat_id: material phase identification + with shape (n_elements,) + :param mesh: + :param plastic_modes: plastic strain modes µ + with shape (n_integration_points, strain_dof, N_modes) + :param eigen_strains: solutions of the auxiliary eigenstress problems eps_star + with shape (n_integration_points, strain_dof, N_modes) + :param ...: + :return: + C_bar with shape (strain_dof, strain_dof) + tau_theta with shape (strain_dof,) + A_bar with shape (strain_dof, strain_dof) + tau_xi with shape (n_modes,) + D_xi with shape (strain_dof, n_modes) + D_theta with shape (strain_dof, n_modes) + """ + strain_dof = mesh['strain_dof'] + mat_id = mesh['mat_id'] + n_modes = plastic_modes.shape[2] + + # slice strain localization operator E into E_eps, E_theta, E_xi + E_eps = strain_localization[:, :, :strain_dof] + E_theta = strain_localization[:, :, strain_dof] + E_xi = strain_localization[:, :, strain_dof + 1:] + + + # slice stress localization operator S into S_eps, S_theta, S_xi + S_eps = stress_localization[:, :, :strain_dof] + S_theta = stress_localization[:, :, strain_dof] + S_xi = stress_localization[:, :, strain_dof + 1:] + + I = np.eye(6) + # Compute C_bar via < (E_eps + I).T @ S_eps > + C_bar = volume_average((E_eps + I).transpose((0, 2, 1)) @ S_eps) + + # Compute tau_theta via < (E_eps + I).T @ S_theta > + tau_theta = volume_average(np.einsum('nij,nj->ni', (E_eps + I).transpose((0, 2, 1)), S_theta)) + + # Compute A_bar via < (E_eps + I).T @ S_eps > + A_bar = volume_average((E_eps + I).transpose((0, 2, 1)) @ S_xi) + + # Compute tau_xi via < (E_theta - P_theta).T @ S_xi > + tau_xi = volume_average(np.einsum('ni,nij->nj', E_theta - thermal_strain, S_xi)) + + # Compute D_xi via < (E_xi - P_xi).T @ S_xi > + D_xi = volume_average((E_xi - plastic_modes).transpose((0, 2, 1)) @ S_xi) + + # Compute D_theta via < (E_theta - P_theta).T @ S_theta > + D_theta = volume_average(np.einsum('ni,ni->n', E_theta - thermal_strain, S_theta)) + + return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta + + +def compute_phase_average_stresses(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, zeta, mesh): + combo_strain_loc0, combo_strain_loc1 = None, None + stress_localization0, stress_localization1, combo_stress_loc0, combo_stress_loc1 = construct_stress_localization_phases( + strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, combo_strain_loc0, combo_strain_loc1, mesh) + + combo_stress0 = np.einsum('ijk,k', combo_stress_loc0, zeta, optimize='optimal') if combo_stress_loc0 is not None else None + combo_stress1 = np.einsum('ijk,k', combo_stress_loc1, zeta, optimize='optimal') if combo_stress_loc1 is not None else None + + stress0 = np.einsum('ijk,k', stress_localization0, zeta, optimize='optimal') + stress1 = np.einsum('ijk,k', stress_localization1, zeta, optimize='optimal') + average_stress_0, average_stress_1 = volume_average_phases(stress0, stress1, combo_stress0, combo_stress1, mesh) + return average_stress_0, average_stress_1 + + +def compute_phase_average_stress_localizations(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mesh): + assert mesh['vox_type'] == 'normal', 'For now, only normal voxels are supported' + combo_strain_loc0, combo_strain_loc1 = None, None + stress_localization0, stress_localization1, _, _ = construct_stress_localization_phases( + strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, combo_strain_loc0, combo_strain_loc1, mesh) + average_stress_localization0, average_stress_localization1 = volume_average(stress_localization0), volume_average(stress_localization1) + return average_stress_localization0, average_stress_localization1 + + +def compute_tabular_data_for_ms(ms_id, temperatures): + """ + Perform `compute_tabular_data` for microstructure with id `ms_id` + :param ms_id: + :param temperatures: + """ + file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', + 'sampling_alphas')(microstructures[ms_id]) + sample_temperatures = np.linspace(temp1, temp2, num=n_tests) + sample_alphas = np.linspace(0, 1, num=n_tests) + mesh, samples = read_h5(file_name, data_path, sample_temperatures) + return compute_tabular_data(samples, mesh, temperatures) + + +#@jit(nopython=True, cache=True, parallel=True, nogil=True) +def compute_tabular_data(samples, mesh, temperatures): + """ + Compute tabular data for a given list of temperatures + :param samples: + :param mesh: + :param temperatures: + :return: + C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1 + """ + assert mesh['vox_type'] == 'normal', 'For now, only normal voxels are supported' + mat_id = mesh['mat_id'] + n_gauss = mesh['n_gauss'] + strain_dof = mesh['strain_dof'] + global_gradient = mesh['global_gradient'] + n_gp = mesh['n_integration_points'] + n_phases = len(np.unique(mat_id)) + n_modes = samples[0]['plastic_modes'].shape[-1] + n_temps = len(temperatures) + C_bar = np.zeros((strain_dof, strain_dof, n_temps)) + tau_theta = np.zeros((strain_dof, n_temps)) + A_bar = np.zeros((strain_dof, n_modes, n_temps)) + tau_xi = np.zeros((n_modes, n_temps)) + D_xi = np.zeros((n_modes, n_modes, n_temps)) + D_theta = np.zeros((n_temps)) + C0 = np.zeros((strain_dof, strain_dof, n_temps)) + C1 = np.zeros((strain_dof, strain_dof, n_temps)) + A0 = np.zeros((strain_dof, n_modes, n_temps)) + A1 = np.zeros((strain_dof, n_modes, n_temps)) + vol_frac0 = mesh['volume_fraction'][0] + vol_frac1 = mesh['volume_fraction'][1] + plastic_modes = samples[0]['plastic_modes'] + # interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) + # dns_temperatures = interpolate_temp(temp1, temp2, sample_alphas) + sample_temperatures = np.array([sample['temperature'] for sample in samples]) + temp1, temp2 = min(sample_temperatures), max(sample_temperatures) + sample_alphas = (sample_temperatures - temp1) / (temp2 - temp1) + for idx in prange(n_temps): + temperature = temperatures[idx] + ref_C = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) + ref_eps = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) + alpha = (temperature - temp1) / (temp2 - temp1) + upper_bound = np.searchsorted(sample_alphas, alpha) + if np.floor(alpha) == alpha: + # sample for given temperature exists, no need for interpolation + id = upper_bound + C, eps = ref_C, ref_eps + E = samples[id]['strain_localization'] + S = construct_stress_localization(E, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + else: + id1 = upper_bound if upper_bound > 0 else 1 + id0 = id1 - 1 + + E0 = samples[id0]['strain_localization'] + E1 = samples[id1]['strain_localization'] + E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) + + sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) + sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) + + # interpolated quantities using an implicit interpolation scheme with four DOF + C, eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) + E, _ = interpolate_fluctuation_modes(E01, C, eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, n_gp) + S = construct_stress_localization(E, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + + # Compute NTFA matrices + C_bar[:, :, idx], tau_theta[:, idx], A_bar[:, :, idx], tau_xi[:, idx], D_xi[:, :, idx], D_theta[idx] = \ + compute_ntfa_matrices(E, S, plastic_modes, eps[0,:,0], mesh) + + # Compute phase average stresses + A0_full, A1_full = compute_phase_average_stress_localizations(E, ref_C, ref_eps, plastic_modes, mesh) + A0[:, :, idx], A1[:, :, idx] = A0_full[:, strain_dof + 1:], A1_full[:, strain_dof + 1:] + + # Save phase-wise stiffness tensors + C0[:, :, idx], C1[:, :, idx] = ref_C[0, :, :], ref_C[1, :, :] + return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1 + + +@jit(nopython=True, cache=True, parallel=True, nogil=True) +def compute_tabular_data_efficient(samples, mesh, temperatures): + """ + WIP + mat_id = mesh['mat_id'] + n_gauss = mesh['n_gauss'] + strain_dof = mesh['strain_dof'] + global_gradient = mesh['global_gradient'] + n_gp = mesh['n_integration_points'] + n_phases = len(np.unique(mat_id)) + n_modes = samples[0]['strain_localization'].shape[-1] + n_temps = len(temperatures) + A_bar = np.zeros((strain_dof, n_modes - 7, n_temps)) + D_xi = np.zeros((n_modes - 7, n_modes - 7, n_temps)) + tau_theta = np.zeros((strain_dof, n_temps)) + C_bar = np.zeros((strain_dof, strain_dof, n_temps)) + # interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) + # dns_temperatures = interpolate_temp(temp1, temp2, sample_alphas) + sample_temperatures = np.array([sample['temperature'] for sample in samples]) + temp1, temp2 = min(sample_temperatures), max(sample_temperatures) + sample_alphas = (sample_temperatures - temp1) / (temp2 - temp1) + # for idx, temperature in enumerate(temperatures): + for idx in prange(n_temps): + temperature = temperatures[idx] + alpha = (temperature - temp1) / (temp2 - temp1) + upper_bound = np.searchsorted(sample_alphas, alpha) + id1 = upper_bound if upper_bound > 0 else 1 + id0 = id1 - 1 + + E0 = samples[id0]['strain_localization'] + E1 = samples[id1]['strain_localization'] + E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) + + sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) + sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) + plastic_modes = samples[id0]['plastic_modes'] # TODO: does exist? + # normalization_factor_mech = samples[idx]['normalization_factor_mech'] # TODO: does exist? + ref_C = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) + ref_eps = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) + + # interpolated quantities using an implicit interpolation scheme with four DOF + approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) + Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, + n_gp) + Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) + # effSopt = volume_average(Sopt4) + A_bar[:,:,idx], D_xi[:,:,idx], tau_theta[:,idx], C_bar[:,:,idx] = compute_ntfa_matrices(Sopt4, plastic_modes, mesh) + return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta + """ + pass + + +def save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1): + """ + Save tabular data + :param file_name: e.g. "input/simple_3d_rve_combo.h5" + :param data_path: + :param temperatures: + :param C_bar: tabular data for C_bar with shape (strain_dof, strain_dof, n_temp) + :param tau_theta: tabular data for tau_theta with shape (strain_dof, n_temp) + :param A_bar: tabular data for A_bar with shape (strain_dof, n_modes, n_temp) + :param tau_xi: tabular data for tau_xi with shape (n_modes, n_temp) + :param D_xi: tabular data for D_xi with shape (n_modes, n_modes, n_temp) + :param D_theta: tabular data for D_theta with shape (n_temp) + :param A0: tabular data for A0 with shape (strain_dof, n_modes, n_temp) + :param A1: tabular data for A1 with shape (strain_dof, n_modes, n_temp) + :param C0: tabular data for C0 with shape (strain_dof, strain_dof, n_temp) + :param C1: tabular data for C1 with shape (strain_dof, strain_dof, n_temp) + """ + with h5py.File(file_name, 'a') as file: + dset_sim = file[data_path] + dset = dset_sim.parent + ntfa_path = re.sub('_sim$', '_ntfa', dset_sim.name) + if ntfa_path in file: + # Delete h5 group with tabular data if it already exists + del file[ntfa_path] + dset_ntfa = dset.create_group(ntfa_path) + [dset_ntfa.attrs.create(key, value) for key, value in dset_sim.attrs.items()] + dset_temperatures = dset_ntfa.create_dataset('temperatures', data=temperatures) + dset_C_bar = dset_ntfa.create_dataset('C_bar', data=C_bar) + dset_tau_theta = dset_ntfa.create_dataset('tau_theta', data=tau_theta) + dset_A_bar = dset_ntfa.create_dataset('A_bar', data=A_bar) + dset_tau_xi = dset_ntfa.create_dataset('tau_xi', data=tau_xi) + dset_D_xi = dset_ntfa.create_dataset('D_xi', data=D_xi) + dset_D_theta = dset_ntfa.create_dataset('D_theta', data=D_theta) + dset_A0 = dset_ntfa.create_dataset('A0', data=A0) + dset_A1 = dset_ntfa.create_dataset('A1', data=A1) + dset_C0 = dset_ntfa.create_dataset('C0', data=C0) + dset_C1 = dset_ntfa.create_dataset('C1', data=C1) + +""" +TO BE REMOVED: +""" + +def create_dummy_plastic_snapshots(n_integration_points, strain_dof, n_frames=100): + """ + TODO: remove when FANS can compute plastic snapshots + """ + # plastic_snapshots = np.random.rand(n_integration_points, strain_dof, n_frames) + plastic_snapshots = np.random.rand(n_integration_points, strain_dof)[:, :, np.newaxis] * np.random.rand(n_frames) \ + + 1e-2 * np.random.rand(n_integration_points, strain_dof, n_frames) + return plastic_snapshots + + +def create_dummy_plastic_modes(n_integration_points, strain_dof, N_modes): + """ + TODO: remove when FANS can compute plastic snapshots + """ + plastic_modes = np.random.rand(n_integration_points, strain_dof, N_modes) + return plastic_modes + + +def create_dummy_plastic_strain_localization(strain_localization, N_modes): + E_eps = strain_localization[:, :, :6] + E_xi = np.random.rand(*strain_localization.shape[:2], N_modes) + E_theta = np.expand_dims(strain_localization[:, :, -1], axis=2) + strain_localization = np.concatenate([E_eps, E_xi, E_theta], axis=2) + return strain_localization From 149493e9786218893fe0ce505a0b04b42825d9f6 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Thu, 15 Jun 2023 16:27:03 +0200 Subject: [PATCH 20/30] Use analytic expression for thermal strain --- material_parameters.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/material_parameters.py b/material_parameters.py index 08d1659..0128d6d 100644 --- a/material_parameters.py +++ b/material_parameters.py @@ -27,7 +27,8 @@ elastic_modulus_cu = lambda x: 1.35742e+08 * x ** 0 + 5.85757e+03 * x ** 1 + -8.16134e+01 * x ** 2 hardening_cu = lambda x: 20e+06 * x ** 0 -thermal_strain_cu = lambda x: integrate.quad(cte_cu, min_temperature, x)[0] * I2 +# thermal_strain_cu = lambda x: integrate.quad(cte_cu, min_temperature, x)[0] * I2 +thermal_strain_cu = lambda x: (1.28170e-05 * (x - min_temperature) + 8.23091e-09 * 0.5 * (x ** 2 - min_temperature ** 2)) * I2 shear_modulus_cu = lambda x: elastic_modulus_cu(x) / (2. * (1. + poisson_ratio_cu(x))) bulk_modulus_cu = lambda x: elastic_modulus_cu(x) / (3. * (1. - 2. * poisson_ratio_cu(x))) stiffness_cu = lambda x: bulk_modulus_cu(x) * IxI + 2. * shear_modulus_cu(x) * P2 @@ -38,7 +39,8 @@ cte_wsc = lambda x: 5.07893e-06 * x ** 0 + 5.67524e-10 * x ** 1 elastic_modulus_wsc = lambda x: 4.13295e+08 * x ** 0 + -7.83159e+03 * x ** 1 + -3.65909e+01 * x ** 2 + 5.48782e-03 * x ** 3 -thermal_strain_wsc = lambda x: integrate.quad(cte_wsc, min_temperature, x)[0] * I2 +# thermal_strain_wsc = lambda x: integrate.quad(cte_wsc, min_temperature, x)[0] * I2 +thermal_strain_wsc = lambda x: (5.07893e-06 * (x - min_temperature) + 5.67524e-10 * 0.5 * (x ** 2 - min_temperature ** 2)) * I2 shear_modulus_wsc = lambda x: elastic_modulus_wsc(x) / (2. * (1. + poisson_ratio_wsc(x))) bulk_modulus_wsc = lambda x: elastic_modulus_wsc(x) / (3. * (1. - 2. * poisson_ratio_wsc(x))) stiffness_wsc = lambda x: bulk_modulus_wsc(x) * IxI + 2. * shear_modulus_wsc(x) * P2 From 6187b63ac26923df69a5b8fffdb0bc0df83bd814 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Fri, 16 Jun 2023 00:43:12 +0200 Subject: [PATCH 21/30] Extend tabular data computation --- eg09_compute_ntfa_matrices.py | 74 ++++++++++ eg10_compare_ntfa_matrices.py | 83 ++++------- microstructures.py | 271 +++++++++++++++++++++------------- ntfa.py | 44 +++++- 4 files changed, 306 insertions(+), 166 deletions(-) create mode 100644 eg09_compute_ntfa_matrices.py diff --git a/eg09_compute_ntfa_matrices.py b/eg09_compute_ntfa_matrices.py new file mode 100644 index 0000000..cf3f0b3 --- /dev/null +++ b/eg09_compute_ntfa_matrices.py @@ -0,0 +1,74 @@ +""" +Demo code for plastic mode identification and processing, i.e. computation of the system matrices +""" +#%% +from operator import itemgetter + +import numpy.linalg as la +import matplotlib.pyplot as plt +import time +from microstructures import * +from utilities import read_h5 +from ntfa import read_snapshots, mode_identification, compute_tabular_data, save_tabular_data + +np.random.seed(0) +for microstructure in microstructures[-8:]: + file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( + "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" + )(microstructure) + print(file_name, "\t", data_path) + + sample_temperatures = np.linspace(temp1, temp2, num=n_tests) + + mesh, samples = read_h5(file_name, data_path, sample_temperatures) + mat_id = mesh["mat_id"] + n_gauss = mesh["n_gauss"] + strain_dof = mesh["strain_dof"] + nodal_dof = mesh["nodal_dof"] + n_elements = mesh["n_elements"] + n_integration_points = mesh["n_integration_points"] + global_gradient = mesh["global_gradient"] + n_gp = mesh["n_integration_points"] + disc = mesh["combo_discretisation"] + vol_frac0, vol_frac1 = mesh['volume_fraction'][0], mesh['volume_fraction'][1] + + # Mode identification + + # Read plastic snapshots from h5 file + plastic_snapshots = read_snapshots(file_name, data_path) + print('plastic_snapshots.shape:', plastic_snapshots.shape) + + # Identification of plastic modes + r_min = 1e-3 + plastic_modes_svd = mode_identification(plastic_snapshots, vol_frac0, r_min) + print('plastic_modes_svd.shape:', plastic_modes_svd.shape) + + # Compare computed plastic modes with plastic modes from h5 file + plastic_modes = samples[0]['plastic_modes'] + plastic_modes = plastic_modes_svd + # assert np.allclose(plastic_modes / np.sign(np.expand_dims(np.expand_dims(plastic_modes[0,0,:], axis=0), axis=0)), plastic_modes_svd), 'Identified plastic modes do not match plastic modes in h5 file' + + # Mode processing to compute system matrices + + n_temp = 1000 + temperatures = np.linspace(temp1, temp2, num=n_temp) + start_time = time.time() + # TODO: compute system matrices for multiple intermediate temperatures in an efficient way + C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1 = compute_tabular_data(samples, mesh, temperatures) + elapsed_time = time.time() - start_time + print(f'Computed tabular data for {n_temp} temperatures in {elapsed_time}s') + print('C_bar.shape:', C_bar.shape) + print('tau_theta.shape:', tau_theta.shape) + print('A_bar.shape:', A_bar.shape) + print('tau_xi.shape:', tau_xi.shape) + print('D_xi.shape:', D_xi.shape) + print('D_theta.shape:', D_theta.shape) + print('A_bar/A0/A1 error:', np.linalg.norm(vol_frac0 * A0[:, strain_dof + 1:] + vol_frac1 * A1[:, strain_dof + 1:] - A_bar) / np.linalg.norm(A_bar)) + + # Save system matrices for multiple temperatures as tabular data + save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1) + # Tabular data is saved to the input h5 file and can be copied to a new h5 file using e.g. + # h5copy -i input/file.h5 -o input/file_ntfa.h5 -s ms_1p/dset0_ntfa -d ms_1p/dset0_ntfa -p + +#%% Compare interpolated NTFA matrices with exact NTFA matrices +# TODO: compute errors diff --git a/eg10_compare_ntfa_matrices.py b/eg10_compare_ntfa_matrices.py index b6525c3..0cae4df 100644 --- a/eg10_compare_ntfa_matrices.py +++ b/eg10_compare_ntfa_matrices.py @@ -9,64 +9,33 @@ import time from microstructures import * from utilities import read_h5 -from ntfa import read_snapshots, mode_identification, compute_tabular_data, save_tabular_data +from ntfa import read_tabular_data -np.random.seed(0) -for microstructure in microstructures[-8:]: - file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( +file_name_10, data_path_10, temp1_10, temp2_10, n_tests_10, sampling_alphas_10 = itemgetter( "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" - )(microstructure) - print(file_name, "\t", data_path) +)(microstructures[0]) - sample_temperatures = np.linspace(temp1, temp2, num=n_tests) +temperatures_10, C_bar_10, tau_theta_10, A_bar_10, tau_xi_10, D_xi_10, D_theta_10, A0_10, A1_10, C0_10, C1_10 = \ + read_tabular_data(file_name_10, data_path_10) - mesh, samples = read_h5(file_name, data_path, sample_temperatures) - mat_id = mesh["mat_id"] - n_gauss = mesh["n_gauss"] - strain_dof = mesh["strain_dof"] - nodal_dof = mesh["nodal_dof"] - n_elements = mesh["n_elements"] - n_integration_points = mesh["n_integration_points"] - global_gradient = mesh["global_gradient"] - n_gp = mesh["n_integration_points"] - disc = mesh["combo_discretisation"] - vol_frac = mesh['volume_fraction'][0] - - # Mode identification - - # Read plastic snapshots from h5 file - plastic_snapshots = read_snapshots(file_name, data_path) - print('plastic_snapshots.shape:', plastic_snapshots.shape) - - # Identification of plastic modes - r_min = 1e-8 - # plastic_modes_svd = mode_identification(plastic_snapshots, vol_frac, r_min) - # print('plastic_modes_svd.shape:', plastic_modes_svd.shape) - - # Compare computed plastic modes with plastic modes from h5 file - plastic_modes = samples[0]['plastic_modes'] - # assert np.allclose(plastic_modes / np.sign(np.expand_dims(np.expand_dims(plastic_modes[0,0,:], axis=0), axis=0)), plastic_modes_svd), 'Identified plastic modes do not match plastic modes in h5 file' - - # Mode processing to compute system matrices - - n_temp = 1000 - temperatures = np.linspace(temp1, temp2, num=n_temp) - start_time = time.time() - # TODO: compute system matrices for multiple intermediate temperatures in an efficient way - C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta = compute_tabular_data(samples, mesh, temperatures) - elapsed_time = time.time() - start_time - print(f'Computed tabular data for {n_temp} temperatures in {elapsed_time}s') - print('C_bar.shape:', C_bar.shape) - print('tau_theta.shape:', tau_theta.shape) - print('A_bar.shape:', A_bar.shape) - print('tau_xi.shape:', tau_xi.shape) - print('D_xi.shape:', D_xi.shape) - print('D_theta.shape:', D_theta.shape) - - # Save system matrices for multiple temperatures as tabular data - save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta) - # Tabular data is saved to the input h5 file and can be copied to a new h5 file using e.g. - # h5copy -i input/file.h5 -o input/file_ntfa.h5 -s ms_1p/dset0_ntfa -d ms_1p/dset0_ntfa -p - -#%% Compare interpolated NTFA matrices with exact NTFA matrices -# TODO: compute errors +file_name_100, data_path_100, temp1_100, temp2_100, n_tests_100, sampling_alphas_100 = itemgetter( + "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" +)(microstructures[-1]) + +temperatures_100, C_bar_100, tau_theta_100, A_bar_100, tau_xi_100, D_xi_100, D_theta_100, A0_100, A1_100, C0_100, C1_100 = \ + read_tabular_data(file_name_100, data_path_100) + +C_bar_diff = C_bar_10 - C_bar_100 +tau_theta_diff = tau_theta_10 - tau_theta_100 +# A_bar_diff +# tau_xi_diff +# D_xi_diff +D_theta_diff = tau_theta_10 - tau_theta_100 +# A0_diff +# A1_diff +C0_diff = C0_10 - C0_100 +C1_10 = C1_10 - C1_100 +print('C_bar error:', np.linalg.norm(C_bar_diff, axis=(0,1)) / np.linalg.norm(C_bar_100, axis=(0,1))) +print('tau_theta error:', np.linalg.norm(tau_theta_diff, axis=0) / np.linalg.norm(tau_theta_100, axis=0)) +print('D_theta error:', np.linalg.norm(D_theta_diff, axis=0) / np.linalg.norm(D_theta_100, axis=0)) +print(C_bar_10.shape, C_bar_100.shape) \ No newline at end of file diff --git a/microstructures.py b/microstructures.py index 2f01430..8a53677 100644 --- a/microstructures.py +++ b/microstructures.py @@ -2,192 +2,251 @@ import numpy as np -microstructures = [{ +microstructures = [ +# { +# 'data_path': '/ms_1p/dset0_sim', +# 'file_name': path("input/striped_normal_4x4x4.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 100, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_1p/dset0_sim', +# 'file_name': path("input/sphere_normal_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_1p/dset0_sim', +# 'file_name': path("input/sphere_normal_32x32x32_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_1p/dset0_sim', +# 'file_name': path("input/sphere_combo_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_1p/dset0_sim', +# 'file_name': path("input/octahedron_normal_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_1p/dset0_sim', +# 'file_name': path("input/octahedron_combo_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': +# '/ms_1p/dset0_sim', +# 'file_name': +# path("input/octahedron_combo_32x32x32.h5"), +# 'temp1': +# 300, +# 'temp2': +# 1300, +# 'n_tests': +# 100, +# 'sampling_alphas': +# np.asarray([ +# np.asarray([0., 1.]), +# np.asarray([0., 0.82828283, 1.]), +# np.asarray([0., 0.82828283, 0.93939394, 1.]), +# np.asarray([0., 0.60606061, 0.82828283, 0.93939394, 1.]), +# np.asarray([0., 0.60606061, 0.82828283, 0.93939394, 0.97979798, 1.]) +# ], dtype=object) +# }, { +# 'data_path': +# '/image_data/dset_0_sim', +# 'file_name': +# path("input/random_rve_vol20.h5"), +# 'temp1': +# 300, +# 'temp2': +# 1300, +# 'n_tests': +# 100, +# 'sampling_alphas': +# np.asarray([ +# np.asarray([0., 1.]), +# np.asarray([0., 0.85858586, 1.]), +# np.asarray([0., 0.85858586, 0.94949495, 1.]), +# np.asarray([0., 0.66666667, 0.85858586, 0.94949495, 1.]), +# np.asarray([0., 0.66666667, 0.85858586, 0.94949495, 0.97979798, 1.]) +# ], dtype=object) +# }, { +# 'data_path': +# '/image_data/dset_0_sim', +# 'file_name': +# path("input/random_rve_vol40.h5"), +# 'temp1': +# 300, +# 'temp2': +# 1300, +# 'n_tests': +# 100, +# 'sampling_alphas': +# np.asarray([ +# np.asarray([0., 1.]), +# np.asarray([0., 0.8989899, 1.]), +# np.asarray([0., 0.8989899, 0.96969697, 1.]), +# np.asarray([0., 0.71717172, 0.8989899, 0.96969697, 1.]), +# np.asarray([0., 0.51515152, 0.71717172, 0.8989899, 0.96969697, 1.]) +# ], dtype=object) +# }, { +# 'data_path': +# '/image_data/dset_0_sim', +# 'file_name': +# path('input/random_rve_vol60.h5'), +# 'temp1': +# 300, +# 'temp2': +# 1300, +# 'n_tests': +# 100, +# 'sampling_alphas': +# np.asarray([ +# np.asarray([0., 1.]), +# np.asarray([0., 0.8989899, 1.]), +# np.asarray([0., 0.72727273, 0.8989899, 1.]), +# np.asarray([0., 0.72727273, 0.8989899, 0.96969697, 1.]), +# np.asarray([0., 0.52525253, 0.72727273, 0.8989899, 0.96969697, 1.]) +# ], dtype=object) +# }, +# { +# 'data_path': '/ms_1p/dset0_sim', +# 'file_name': path("input/striped_normal_4x4x4_plastic.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, +{ 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/striped_normal_4x4x4.h5"), + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), 'temp1': 300, 'temp2': 1300, - 'n_tests': 100, + 'n_tests': 10, 'sampling_alphas': None }, { - 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/sphere_normal_16x16x16_10samples.h5"), + 'data_path': '/ms_9p/dset0_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { - 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/sphere_normal_32x32x32_10samples.h5"), + 'data_path': '/ms_9p/dset1_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { - 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/sphere_combo_16x16x16_10samples.h5"), + 'data_path': '/ms_9p/dset2_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { - 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/octahedron_normal_16x16x16_10samples.h5"), + 'data_path': '/ms_9p/dset3_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { - 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/octahedron_combo_16x16x16_10samples.h5"), + 'data_path': '/ms_15p/dset0_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { - 'data_path': - '/ms_1p/dset0_sim', - 'file_name': - path("input/octahedron_combo_32x32x32.h5"), - 'temp1': - 300, - 'temp2': - 1300, - 'n_tests': - 100, - 'sampling_alphas': - np.asarray([ - np.asarray([0., 1.]), - np.asarray([0., 0.82828283, 1.]), - np.asarray([0., 0.82828283, 0.93939394, 1.]), - np.asarray([0., 0.60606061, 0.82828283, 0.93939394, 1.]), - np.asarray([0., 0.60606061, 0.82828283, 0.93939394, 0.97979798, 1.]) - ], dtype=object) -}, { - 'data_path': - '/image_data/dset_0_sim', - 'file_name': - path("input/random_rve_vol20.h5"), - 'temp1': - 300, - 'temp2': - 1300, - 'n_tests': - 100, - 'sampling_alphas': - np.asarray([ - np.asarray([0., 1.]), - np.asarray([0., 0.85858586, 1.]), - np.asarray([0., 0.85858586, 0.94949495, 1.]), - np.asarray([0., 0.66666667, 0.85858586, 0.94949495, 1.]), - np.asarray([0., 0.66666667, 0.85858586, 0.94949495, 0.97979798, 1.]) - ], dtype=object) -}, { - 'data_path': - '/image_data/dset_0_sim', - 'file_name': - path("input/random_rve_vol40.h5"), - 'temp1': - 300, - 'temp2': - 1300, - 'n_tests': - 100, - 'sampling_alphas': - np.asarray([ - np.asarray([0., 1.]), - np.asarray([0., 0.8989899, 1.]), - np.asarray([0., 0.8989899, 0.96969697, 1.]), - np.asarray([0., 0.71717172, 0.8989899, 0.96969697, 1.]), - np.asarray([0., 0.51515152, 0.71717172, 0.8989899, 0.96969697, 1.]) - ], dtype=object) -}, { - 'data_path': - '/image_data/dset_0_sim', - 'file_name': - path('input/random_rve_vol60.h5'), - 'temp1': - 300, - 'temp2': - 1300, - 'n_tests': - 100, - 'sampling_alphas': - np.asarray([ - np.asarray([0., 1.]), - np.asarray([0., 0.8989899, 1.]), - np.asarray([0., 0.72727273, 0.8989899, 1.]), - np.asarray([0., 0.72727273, 0.8989899, 0.96969697, 1.]), - np.asarray([0., 0.52525253, 0.72727273, 0.8989899, 0.96969697, 1.]) - ], dtype=object) -}, { - 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/striped_normal_4x4x4_plastic.h5"), + 'data_path': '/ms_15p/dset1_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 10, + 'sampling_alphas': None +},{ + 'data_path': '/ms_15p/dset2_sim', + 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'file_name': path("input/simple_3d_rve_4x4x4_100samples.h5"), + 'temp1': 300, + 'temp2': 1300, + 'n_tests': 100, + 'sampling_alphas': None +},{ + 'data_path': '/ms_1p/dset0_sim', + 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { 'data_path': '/ms_9p/dset0_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { 'data_path': '/ms_9p/dset1_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { 'data_path': '/ms_9p/dset2_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { 'data_path': '/ms_9p/dset3_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { 'data_path': '/ms_15p/dset0_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { 'data_path': '/ms_15p/dset1_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None }, { 'data_path': '/ms_15p/dset2_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), + 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), 'temp1': 300, 'temp2': 1300, 'n_tests': 10, 'sampling_alphas': None -}, { - 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_100samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 100, - 'sampling_alphas': None }] diff --git a/ntfa.py b/ntfa.py index 6976496..61d18a3 100644 --- a/ntfa.py +++ b/ntfa.py @@ -209,8 +209,8 @@ def compute_tabular_data(samples, mesh, temperatures): D_theta = np.zeros((n_temps)) C0 = np.zeros((strain_dof, strain_dof, n_temps)) C1 = np.zeros((strain_dof, strain_dof, n_temps)) - A0 = np.zeros((strain_dof, n_modes, n_temps)) - A1 = np.zeros((strain_dof, n_modes, n_temps)) + A0 = np.zeros((strain_dof, 7 + n_modes, n_temps)) + A1 = np.zeros((strain_dof, 7 + n_modes, n_temps)) vol_frac0 = mesh['volume_fraction'][0] vol_frac1 = mesh['volume_fraction'][1] plastic_modes = samples[0]['plastic_modes'] @@ -253,7 +253,7 @@ def compute_tabular_data(samples, mesh, temperatures): # Compute phase average stresses A0_full, A1_full = compute_phase_average_stress_localizations(E, ref_C, ref_eps, plastic_modes, mesh) - A0[:, :, idx], A1[:, :, idx] = A0_full[:, strain_dof + 1:], A1_full[:, strain_dof + 1:] + A0[:, :, idx], A1[:, :, idx] = A0_full, A1_full # Save phase-wise stiffness tensors C0[:, :, idx], C1[:, :, idx] = ref_C[0, :, :], ref_C[1, :, :] @@ -350,6 +350,44 @@ def save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_ba dset_C0 = dset_ntfa.create_dataset('C0', data=C0) dset_C1 = dset_ntfa.create_dataset('C1', data=C1) + +def read_tabular_data(file_name, data_path): + """ + Save tabular data + :param file_name: e.g. "input/simple_3d_rve_combo.h5" + :param data_path: + :return: + temperatures: + C_bar: tabular data for C_bar with shape (strain_dof, strain_dof, n_temp) + tau_theta: tabular data for tau_theta with shape (strain_dof, n_temp) + A_bar: tabular data for A_bar with shape (strain_dof, n_modes, n_temp) + tau_xi: tabular data for tau_xi with shape (n_modes, n_temp) + D_xi: tabular data for D_xi with shape (n_modes, n_modes, n_temp) + D_theta: tabular data for D_theta with shape (n_temp) + A0: tabular data for A0 with shape (strain_dof, n_modes, n_temp) + A1: tabular data for A1 with shape (strain_dof, n_modes, n_temp) + C0: tabular data for C0 with shape (strain_dof, strain_dof, n_temp) + C1: tabular data for C1 with shape (strain_dof, strain_dof, n_temp) + """ + with h5py.File(file_name, 'r') as file: + if '_ntfa' in data_path: + ntfa_path = data_path + else: + ntfa_path = re.sub('_sim$', '_ntfa', data_path) + dset_ntfa = file[ntfa_path] + temperatures = dset_ntfa['temperatures'][:] + C_bar = dset_ntfa['C_bar'][:] + tau_theta = dset_ntfa['tau_theta'][:] + A_bar = dset_ntfa['A_bar'][:] + tau_xi = dset_ntfa['tau_xi'][:] + D_xi = dset_ntfa['D_xi'][:] + D_theta = dset_ntfa['D_theta'][:] + A0 = dset_ntfa['A0'][:] + A1 = dset_ntfa['A1'][:] + C0 = dset_ntfa['C0'][:] + C1 = dset_ntfa['C1'][:] + return temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1 + """ TO BE REMOVED: """ From 91fd0cf59eca7303e802a462327fc297b8e20fce Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Mon, 10 Jul 2023 08:52:37 +0200 Subject: [PATCH 22/30] Tabular data test case --- eg09_compute_ntfa_matrices.py | 2 +- eg9_compute_ntfa_matrices.py | 74 ---------- microstructures.py | 247 +++++++++++++++++++++------------- 3 files changed, 157 insertions(+), 166 deletions(-) delete mode 100644 eg9_compute_ntfa_matrices.py diff --git a/eg09_compute_ntfa_matrices.py b/eg09_compute_ntfa_matrices.py index cf3f0b3..20e0b52 100644 --- a/eg09_compute_ntfa_matrices.py +++ b/eg09_compute_ntfa_matrices.py @@ -12,7 +12,7 @@ from ntfa import read_snapshots, mode_identification, compute_tabular_data, save_tabular_data np.random.seed(0) -for microstructure in microstructures[-8:]: +for microstructure in microstructures[:]: file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" )(microstructure) diff --git a/eg9_compute_ntfa_matrices.py b/eg9_compute_ntfa_matrices.py deleted file mode 100644 index f24ba5a..0000000 --- a/eg9_compute_ntfa_matrices.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -Demo code for plastic mode identification and processing, i.e. computation of the system matrices -""" -#%% -from operator import itemgetter - -import numpy.linalg as la -import matplotlib.pyplot as plt -import time -from microstructures import * -from utilities import read_h5 -from ntfa import read_snapshots, mode_identification, compute_tabular_data, save_tabular_data - -np.random.seed(0) -for microstructure in microstructures[-9:]: - file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( - "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" - )(microstructure) - print(file_name, "\t", data_path) - - sample_temperatures = np.linspace(temp1, temp2, num=n_tests) - - mesh, samples = read_h5(file_name, data_path, sample_temperatures) - mat_id = mesh["mat_id"] - n_gauss = mesh["n_gauss"] - strain_dof = mesh["strain_dof"] - nodal_dof = mesh["nodal_dof"] - n_elements = mesh["n_elements"] - n_integration_points = mesh["n_integration_points"] - global_gradient = mesh["global_gradient"] - n_gp = mesh["n_integration_points"] - disc = mesh["combo_discretisation"] - vol_frac0, vol_frac1 = mesh['volume_fraction'][0], mesh['volume_fraction'][1] - - # Mode identification - - # Read plastic snapshots from h5 file - plastic_snapshots = read_snapshots(file_name, data_path) - print('plastic_snapshots.shape:', plastic_snapshots.shape) - - # Identification of plastic modes - r_min = 1e-3 - plastic_modes_svd = mode_identification(plastic_snapshots, vol_frac0, r_min) - print('plastic_modes_svd.shape:', plastic_modes_svd.shape) - - # Compare computed plastic modes with plastic modes from h5 file - plastic_modes = samples[0]['plastic_modes'] - plastic_modes = plastic_modes_svd - # assert np.allclose(plastic_modes / np.sign(np.expand_dims(np.expand_dims(plastic_modes[0,0,:], axis=0), axis=0)), plastic_modes_svd), 'Identified plastic modes do not match plastic modes in h5 file' - - # Mode processing to compute system matrices - - n_temp = 1000 - temperatures = np.linspace(temp1, temp2, num=n_temp) - start_time = time.time() - # TODO: compute system matrices for multiple intermediate temperatures in an efficient way - C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1 = compute_tabular_data(samples, mesh, plastic_modes, temperatures) - elapsed_time = time.time() - start_time - print(f'Computed tabular data for {n_temp} temperatures in {elapsed_time}s') - print('C_bar.shape:', C_bar.shape) - print('tau_theta.shape:', tau_theta.shape) - print('A_bar.shape:', A_bar.shape) - print('tau_xi.shape:', tau_xi.shape) - print('D_xi.shape:', D_xi.shape) - print('D_theta.shape:', D_theta.shape) - print('A_bar/A0/A1 error:', np.linalg.norm(vol_frac0 * A0 + vol_frac1 * A1 - A_bar) / np.linalg.norm(A_bar)) - - # Save system matrices for multiple temperatures as tabular data - save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1) - # Tabular data is saved to the input h5 file and can be copied to a new h5 file using e.g. - # h5copy -i input/file.h5 -o input/file_ntfa.h5 -s ms_1p/dset0_ntfa -d ms_1p/dset0_ntfa -p - -#%% Compare interpolated NTFA matrices with exact NTFA matrices -# TODO: compute errors diff --git a/microstructures.py b/microstructures.py index 8a53677..8624349 100644 --- a/microstructures.py +++ b/microstructures.py @@ -130,123 +130,188 @@ # 'n_tests': 10, # 'sampling_alphas': None # }, +# { +# 'data_path': '/ms_1p/dset0_sim', +# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_9p/dset0_sim', +# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_9p/dset1_sim', +# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_9p/dset2_sim', +# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_9p/dset3_sim', +# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_15p/dset0_sim', +# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_15p/dset1_sim', +# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# },{ +# 'data_path': '/ms_15p/dset2_sim', +# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_1p/dset0_sim', +# 'file_name': path("input/simple_3d_rve_4x4x4_100samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 100, +# 'sampling_alphas': None +# },{ +# 'data_path': '/ms_1p/dset0_sim', +# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_9p/dset0_sim', +# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_9p/dset1_sim', +# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_9p/dset2_sim', +# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_9p/dset3_sim', +# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_15p/dset0_sim', +# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_15p/dset1_sim', +# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { +# 'data_path': '/ms_15p/dset2_sim', +# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, { 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 10, - 'sampling_alphas': None -}, { - 'data_path': '/ms_9p/dset0_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 10, - 'sampling_alphas': None -}, { - 'data_path': '/ms_9p/dset1_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 10, - 'sampling_alphas': None -}, { - 'data_path': '/ms_9p/dset2_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 10, - 'sampling_alphas': None -}, { - 'data_path': '/ms_9p/dset3_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 10, - 'sampling_alphas': None -}, { - 'data_path': '/ms_15p/dset0_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 10, - 'sampling_alphas': None -}, { - 'data_path': '/ms_15p/dset1_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 10, - 'sampling_alphas': None -},{ - 'data_path': '/ms_15p/dset2_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 10, - 'sampling_alphas': None -}, { - 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/simple_3d_rve_4x4x4_100samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 100, - 'sampling_alphas': None -},{ - 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), + 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), 'temp1': 300, 'temp2': 1300, - 'n_tests': 10, + 'n_tests': 2, 'sampling_alphas': None -}, { +}, +{ 'data_path': '/ms_9p/dset0_sim', - 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), + 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), 'temp1': 300, 'temp2': 1300, - 'n_tests': 10, + 'n_tests': 2, 'sampling_alphas': None -}, { +}, +{ 'data_path': '/ms_9p/dset1_sim', - 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), + 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), 'temp1': 300, 'temp2': 1300, - 'n_tests': 10, + 'n_tests': 2, 'sampling_alphas': None -}, { +}, +{ 'data_path': '/ms_9p/dset2_sim', - 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), + 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), 'temp1': 300, 'temp2': 1300, - 'n_tests': 10, + 'n_tests': 2, 'sampling_alphas': None -}, { - 'data_path': '/ms_9p/dset3_sim', - 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 10, - 'sampling_alphas': None -}, { +}, +# { +# 'data_path': '/ms_9p/dset3_sim', +# 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), +# 'temp1': 300, +# 'temp2': 1300, +# 'n_tests': 10, +# 'sampling_alphas': None +# }, +{ 'data_path': '/ms_15p/dset0_sim', - 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), + 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), 'temp1': 300, 'temp2': 1300, - 'n_tests': 10, + 'n_tests': 2, 'sampling_alphas': None -}, { +}, +{ 'data_path': '/ms_15p/dset1_sim', - 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), + 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), 'temp1': 300, 'temp2': 1300, - 'n_tests': 10, + 'n_tests': 2, 'sampling_alphas': None -}, { +}, +{ 'data_path': '/ms_15p/dset2_sim', - 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), + 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), 'temp1': 300, 'temp2': 1300, - 'n_tests': 10, + 'n_tests': 2, 'sampling_alphas': None -}] +} +] From 36212b0ef99798ae5f0f3a5a88354096c6fd6c64 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Sun, 16 Jul 2023 02:49:39 +0200 Subject: [PATCH 23/30] Bugfix in computation of ntfa system matrices --- ntfa.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ntfa.py b/ntfa.py index 61d18a3..8302c02 100644 --- a/ntfa.py +++ b/ntfa.py @@ -82,7 +82,7 @@ def mode_identification(plastic_snapshots, vol_frac, r_min=1e-8): return plastic_modes -def compute_ntfa_matrices(strain_localization, stress_localization, plastic_modes, thermal_strain, mesh): +def compute_ntfa_matrices(strain_localization, stress_localization, plastic_modes, mat_thermal_strain, mesh): """ Processing of the plastic strain modes µ to compute the matrices A_bar, D_xi, C_bar and the vector tau_theta as tabular data at given temperatures @@ -106,11 +106,13 @@ def compute_ntfa_matrices(strain_localization, stress_localization, plastic_mode A_bar with shape (strain_dof, strain_dof) tau_xi with shape (n_modes,) D_xi with shape (strain_dof, n_modes) - D_theta with shape (strain_dof, n_modes) + D_theta with shape (1,) """ strain_dof = mesh['strain_dof'] mat_id = mesh['mat_id'] n_modes = plastic_modes.shape[2] + n_gp = mesh['n_integration_points'] + n_gauss = mesh['n_gauss'] # slice strain localization operator E into E_eps, E_theta, E_xi E_eps = strain_localization[:, :, :strain_dof] @@ -134,13 +136,21 @@ def compute_ntfa_matrices(strain_localization, stress_localization, plastic_mode A_bar = volume_average((E_eps + I).transpose((0, 2, 1)) @ S_xi) # Compute tau_xi via < (E_theta - P_theta).T @ S_xi > - tau_xi = volume_average(np.einsum('ni,nij->nj', E_theta - thermal_strain, S_xi)) + # Account for the phase-wise thermal strain by an explicit summation over all integration points + tau_xi = np.zeros((1, n_modes)) + for gp_id in prange(n_gp): + phase_id = mat_id[gp_id // n_gauss] + tau_xi += (E_theta[gp_id] - mat_thermal_strain[phase_id].T) @ S_xi[gp_id] / n_gp # Compute D_xi via < (E_xi - P_xi).T @ S_xi > D_xi = volume_average((E_xi - plastic_modes).transpose((0, 2, 1)) @ S_xi) # Compute D_theta via < (E_theta - P_theta).T @ S_theta > - D_theta = volume_average(np.einsum('ni,ni->n', E_theta - thermal_strain, S_theta)) + # Account for the phase-wise thermal strain by an explicit summation over all integration points + D_theta = 0. + for gp_id in prange(n_gp): + phase_id = mat_id[gp_id // n_gauss] + D_theta += (E_theta[gp_id] - mat_thermal_strain[phase_id].T) @ S_theta[gp_id] / n_gp return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta @@ -249,7 +259,7 @@ def compute_tabular_data(samples, mesh, temperatures): # Compute NTFA matrices C_bar[:, :, idx], tau_theta[:, idx], A_bar[:, :, idx], tau_xi[:, idx], D_xi[:, :, idx], D_theta[idx] = \ - compute_ntfa_matrices(E, S, plastic_modes, eps[0,:,0], mesh) + compute_ntfa_matrices(E, S, plastic_modes, eps, mesh) # Compute phase average stresses A0_full, A1_full = compute_phase_average_stress_localizations(E, ref_C, ref_eps, plastic_modes, mesh) From c96a415edd3d87b522fd83dd2f1d6df031fce930 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Sun, 16 Jul 2023 12:11:57 +0200 Subject: [PATCH 24/30] Bugfix in ntfa matrices, code cleanup --- eg09_compute_ntfa_matrices.py | 4 ++-- ntfa.py | 14 ++++---------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/eg09_compute_ntfa_matrices.py b/eg09_compute_ntfa_matrices.py index 20e0b52..ccd2ed2 100644 --- a/eg09_compute_ntfa_matrices.py +++ b/eg09_compute_ntfa_matrices.py @@ -12,7 +12,7 @@ from ntfa import read_snapshots, mode_identification, compute_tabular_data, save_tabular_data np.random.seed(0) -for microstructure in microstructures[:]: +for microstructure in microstructures: file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( "file_name", "data_path", "temp1", "temp2", "n_tests", "sampling_alphas" )(microstructure) @@ -46,7 +46,7 @@ # Compare computed plastic modes with plastic modes from h5 file plastic_modes = samples[0]['plastic_modes'] plastic_modes = plastic_modes_svd - # assert np.allclose(plastic_modes / np.sign(np.expand_dims(np.expand_dims(plastic_modes[0,0,:], axis=0), axis=0)), plastic_modes_svd), 'Identified plastic modes do not match plastic modes in h5 file' + assert np.allclose(plastic_modes / np.sign(np.expand_dims(np.expand_dims(plastic_modes[0,0,:], axis=0), axis=0)), plastic_modes_svd), 'Identified plastic modes do not match plastic modes in h5 file' # Mode processing to compute system matrices diff --git a/ntfa.py b/ntfa.py index 8302c02..6ea848a 100644 --- a/ntfa.py +++ b/ntfa.py @@ -206,9 +206,7 @@ def compute_tabular_data(samples, mesh, temperatures): mat_id = mesh['mat_id'] n_gauss = mesh['n_gauss'] strain_dof = mesh['strain_dof'] - global_gradient = mesh['global_gradient'] n_gp = mesh['n_integration_points'] - n_phases = len(np.unique(mat_id)) n_modes = samples[0]['plastic_modes'].shape[-1] n_temps = len(temperatures) C_bar = np.zeros((strain_dof, strain_dof, n_temps)) @@ -221,11 +219,7 @@ def compute_tabular_data(samples, mesh, temperatures): C1 = np.zeros((strain_dof, strain_dof, n_temps)) A0 = np.zeros((strain_dof, 7 + n_modes, n_temps)) A1 = np.zeros((strain_dof, 7 + n_modes, n_temps)) - vol_frac0 = mesh['volume_fraction'][0] - vol_frac1 = mesh['volume_fraction'][1] plastic_modes = samples[0]['plastic_modes'] - # interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) - # dns_temperatures = interpolate_temp(temp1, temp2, sample_alphas) sample_temperatures = np.array([sample['temperature'] for sample in samples]) temp1, temp2 = min(sample_temperatures), max(sample_temperatures) sample_alphas = (sample_temperatures - temp1) / (temp2 - temp1) @@ -238,7 +232,7 @@ def compute_tabular_data(samples, mesh, temperatures): if np.floor(alpha) == alpha: # sample for given temperature exists, no need for interpolation id = upper_bound - C, eps = ref_C, ref_eps + approx_C, approx_eps = ref_C, ref_eps E = samples[id]['strain_localization'] S = construct_stress_localization(E, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) else: @@ -253,13 +247,13 @@ def compute_tabular_data(samples, mesh, temperatures): sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) # interpolated quantities using an implicit interpolation scheme with four DOF - C, eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - E, _ = interpolate_fluctuation_modes(E01, C, eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, n_gp) + approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) + E, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, n_gp) S = construct_stress_localization(E, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) # Compute NTFA matrices C_bar[:, :, idx], tau_theta[:, idx], A_bar[:, :, idx], tau_xi[:, idx], D_xi[:, :, idx], D_theta[idx] = \ - compute_ntfa_matrices(E, S, plastic_modes, eps, mesh) + compute_ntfa_matrices(E, S, plastic_modes, ref_eps, mesh) # Compute phase average stresses A0_full, A1_full = compute_phase_average_stress_localizations(E, ref_C, ref_eps, plastic_modes, mesh) From cf287383404753f8d8084c54c9c34137b4b89f36 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Sun, 16 Jul 2023 12:51:46 +0200 Subject: [PATCH 25/30] Documentation --- ntfa.py | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/ntfa.py b/ntfa.py index 6ea848a..b3123ba 100644 --- a/ntfa.py +++ b/ntfa.py @@ -5,6 +5,7 @@ import h5py from utilities import * from material_parameters import * +from tqdm import tqdm def read_snapshots(file_name, data_path): """ @@ -84,22 +85,17 @@ def mode_identification(plastic_snapshots, vol_frac, r_min=1e-8): def compute_ntfa_matrices(strain_localization, stress_localization, plastic_modes, mat_thermal_strain, mesh): """ - Processing of the plastic strain modes µ to compute the matrices A_bar, D_xi, C_bar and the vector tau_theta - as tabular data at given temperatures + Compute the ntfa matrices C_bar, A_bar, D_xi, the vectors tau_theta, tau_xi and the scalar D_theta + for given strain_localization, stress_localization, plastic_modes and mat_thermal_strain :param strain_localization: strain localization 3D array with shape (n_integration_points, strain_dof, 7 + n_modes) :param stress_localization: stress localization 3D array with shape (n_integration_points, strain_dof, 7 + n_modes) - :param mat_stiffness: stiffness tensors of the phases - with shape (n_phases, strain_dof, strain_dof) - :param mat_id: material phase identification - with shape (n_elements,) - :param mesh: - :param plastic_modes: plastic strain modes µ - with shape (n_integration_points, strain_dof, N_modes) - :param eigen_strains: solutions of the auxiliary eigenstress problems eps_star - with shape (n_integration_points, strain_dof, N_modes) - :param ...: + :param plastic_modes: plastic strain modes + with shape (n_integration_points, strain_dof, n_modes) + :param mat_thermal_strain: thermal strains of the phases + with shape (n_phases, strain_dof, 1) + :param mesh: dict with mesh information :return: C_bar with shape (strain_dof, strain_dof) tau_theta with shape (strain_dof,) @@ -113,19 +109,18 @@ def compute_ntfa_matrices(strain_localization, stress_localization, plastic_mode n_modes = plastic_modes.shape[2] n_gp = mesh['n_integration_points'] n_gauss = mesh['n_gauss'] + I = np.eye(6) # slice strain localization operator E into E_eps, E_theta, E_xi E_eps = strain_localization[:, :, :strain_dof] E_theta = strain_localization[:, :, strain_dof] E_xi = strain_localization[:, :, strain_dof + 1:] - # slice stress localization operator S into S_eps, S_theta, S_xi S_eps = stress_localization[:, :, :strain_dof] S_theta = stress_localization[:, :, strain_dof] S_xi = stress_localization[:, :, strain_dof + 1:] - I = np.eye(6) # Compute C_bar via < (E_eps + I).T @ S_eps > C_bar = volume_average((E_eps + I).transpose((0, 2, 1)) @ S_eps) @@ -140,7 +135,7 @@ def compute_ntfa_matrices(strain_localization, stress_localization, plastic_mode tau_xi = np.zeros((1, n_modes)) for gp_id in prange(n_gp): phase_id = mat_id[gp_id // n_gauss] - tau_xi += (E_theta[gp_id] - mat_thermal_strain[phase_id].T) @ S_xi[gp_id] / n_gp + tau_xi += (np.expand_dims(E_theta[gp_id], axis=1) - mat_thermal_strain[phase_id]).T @ S_xi[gp_id] / n_gp # Compute D_xi via < (E_xi - P_xi).T @ S_xi > D_xi = volume_average((E_xi - plastic_modes).transpose((0, 2, 1)) @ S_xi) @@ -150,9 +145,9 @@ def compute_ntfa_matrices(strain_localization, stress_localization, plastic_mode D_theta = 0. for gp_id in prange(n_gp): phase_id = mat_id[gp_id // n_gauss] - D_theta += (E_theta[gp_id] - mat_thermal_strain[phase_id].T) @ S_theta[gp_id] / n_gp + D_theta += (np.expand_dims(E_theta[gp_id], axis=1) - mat_thermal_strain[phase_id]).T @ S_theta[gp_id] / n_gp - return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta + return C_bar, tau_theta.ravel(), A_bar, tau_xi.ravel(), D_xi, D_theta def compute_phase_average_stresses(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, zeta, mesh): @@ -223,7 +218,7 @@ def compute_tabular_data(samples, mesh, temperatures): sample_temperatures = np.array([sample['temperature'] for sample in samples]) temp1, temp2 = min(sample_temperatures), max(sample_temperatures) sample_alphas = (sample_temperatures - temp1) / (temp2 - temp1) - for idx in prange(n_temps): + for idx in tqdm(range(n_temps)): temperature = temperatures[idx] ref_C = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) ref_eps = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) From 2b83e2620a1b635e3d865b5cbe31fa619e30ddc0 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Fri, 25 Oct 2024 15:28:40 +0200 Subject: [PATCH 26/30] Documentation --- ntfa.py | 173 ++++++++++++----------------------------------- requirements.txt | 3 +- 2 files changed, 47 insertions(+), 129 deletions(-) diff --git a/ntfa.py b/ntfa.py index b3123ba..3b434ce 100644 --- a/ntfa.py +++ b/ntfa.py @@ -1,5 +1,6 @@ """ -NTFA +Extension of the AdaptiveThermoMechROM for plastic models using the Nonuniform Transformation Field Analysis (NTFA) +For further information, see https://github.com/DataAnalyticsEngineering/ThermoNTFA """ import numpy as np import h5py @@ -7,63 +8,27 @@ from material_parameters import * from tqdm import tqdm + def read_snapshots(file_name, data_path): """ Read an H5 file that contains responses of simulated microstructures + :param file_name: e.g. "input/simple_3d_rve_combo.h5" :param data_path: the path to the simulation results within the h5 file, e.g. '/ms_1p/dset0_sim' :return: strain_snapshots: plastic strain snapshots eps_p with shape (n_integration_points, strain_dof, n_frames) """ - # TODO: read snapshots from H5 file. Because of the sheer amount of data it may be better to use a separate h5 file for the snapshots. plastic_snapshots = None with h5py.File(file_name, 'r') as file: plastic_snapshots = np.transpose(file[f'{data_path}/plastic_strains'][:], (0, 2, 1)) - # For now, use dummy data: - # n_integration_points, strain_dof, n_frames = 512, 6, 100 - # plastic_snapshots = create_dummy_plastic_modes(n_integration_points, strain_dof, n_frames) - # TODO: Reorder snapshots as follows: | 1st strain path: last timestep to first timestep | 2nd strain path: last timestep to first timestep | ... - # or: reorder snapshots already in FANS? return plastic_snapshots -def mode_identification_iterative(plastic_snapshots, vol_frac, r_min=1e-8): - """ - Identification of plastic strain modes µ using an iterative algorithm and renormalization - :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) - with shape (n_integration_points, strain_dof, n_frames) - :param r_min: stop criterion - :return: - plastic_modes: plastic strain modes µ with shape (n_integration_points, strain_dof, n_modes) - """ - n_integration_points, strain_dof, n_frames = plastic_snapshots.shape - n_modes = 0 - plastic_modes = np.zeros((n_integration_points, strain_dof, n_modes)) - for i in range(n_frames): - eps_i = plastic_snapshots[:, :, i] - r = volume_average(inner_product(eps_i, eps_i)) # TODO: average only over Omega_p? - k = np.zeros(n_modes) # Coefficients k_j - for j in range(n_modes): - k[j] = volume_average(inner_product(eps_i, plastic_modes[:, :, j])) - r = r - k[j]**2 - if r < r_min: - break - if r > r_min: - n_modes = n_modes + 1 # increment number of modes - # Generate new strain mode: - plastic_mode = (eps_i - np.tensordot(k, plastic_modes, axes=(0,2))) / np.sqrt(r) - plastic_modes = np.concatenate([plastic_modes, np.expand_dims(plastic_mode, 2)], axis=2) - # Renormalize plastic modes - for i in range(n_modes): - weighting_factor = vol_frac / volume_average(norm_2(plastic_modes[:, :, i])) - plastic_modes[:, :, i] = plastic_modes[:, :, i] * weighting_factor * np.sign(plastic_modes[0, 0, i]) - return plastic_modes - - def mode_identification(plastic_snapshots, vol_frac, r_min=1e-8): """ Identification of plastic strain modes µ using POD and renormalization + :param strain_snapshots: plastic strain snapshots eps_p (ordered as described in `read_snapshots`) with shape (n_integration_points, strain_dof, n_frames) :param r_min: stop criterion @@ -76,7 +41,8 @@ def mode_identification(plastic_snapshots, vol_frac, r_min=1e-8): s = s / s[0] n_modes = np.argwhere(s > r_min).size plastic_modes = u[:, :n_modes].reshape((strain_dof, n_integration_points, n_modes)).transpose(1, 0, 2) - # Renormalize plastic modes + + # Renormalize plastic modes (sign convention can differ between different implementations) for i in range(n_modes): weighting_factor = vol_frac / volume_average(norm_2(plastic_modes[:, :, i])) plastic_modes[:, :, i] = plastic_modes[:, :, i] * weighting_factor * np.sign(plastic_modes[0, 0, i]) @@ -87,6 +53,7 @@ def compute_ntfa_matrices(strain_localization, stress_localization, plastic_mode """ Compute the ntfa matrices C_bar, A_bar, D_xi, the vectors tau_theta, tau_xi and the scalar D_theta for given strain_localization, stress_localization, plastic_modes and mat_thermal_strain + :param strain_localization: strain localization 3D array with shape (n_integration_points, strain_dof, 7 + n_modes) :param stress_localization: stress localization 3D array @@ -151,6 +118,20 @@ def compute_ntfa_matrices(strain_localization, stress_localization, plastic_mode def compute_phase_average_stresses(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, zeta, mesh): + """ + Compute the phase-wise average of the stresses in the individual phases of the composite material + + :param strain_localization: strain localization 3D array + with shape (n_integration_points, strain_dof, 7 + n_modes) + :param mat_stiffness: stiffness tensor of the phases + with shape (n_phases, 6, 6) + :param mat_thermal_strain: thermal strains of the phases + with shape (n_phases, strain_dof, 1) + :param plastic_modes: plastic strain modes + with shape (n_integration_points, strain_dof, n_modes) + :param zeta: mode activation coefficients + :param mesh: dict with mesh information + """ combo_strain_loc0, combo_strain_loc1 = None, None stress_localization0, stress_localization1, combo_stress_loc0, combo_stress_loc1 = construct_stress_localization_phases( strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, combo_strain_loc0, combo_strain_loc1, mesh) @@ -165,6 +146,19 @@ def compute_phase_average_stresses(strain_localization, mat_stiffness, mat_therm def compute_phase_average_stress_localizations(strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, mesh): + """ + Compute the phase-wise average of the stress localizations in the individual phases of the composite material + + :param strain_localization: strain localization 3D array + with shape (n_integration_points, strain_dof, 7 + n_modes) + :param mat_stiffness: stiffness tensor of the phases + with shape (n_phases, 6, 6) + :param mat_thermal_strain: thermal strains of the phases + with shape (n_phases, strain_dof, 1) + :param plastic_modes: plastic strain modes + with shape (n_integration_points, strain_dof, n_modes) + :param mesh: dict with mesh information + """ assert mesh['vox_type'] == 'normal', 'For now, only normal voxels are supported' combo_strain_loc0, combo_strain_loc1 = None, None stress_localization0, stress_localization1, _, _ = construct_stress_localization_phases( @@ -175,9 +169,10 @@ def compute_phase_average_stress_localizations(strain_localization, mat_stiffnes def compute_tabular_data_for_ms(ms_id, temperatures): """ - Perform `compute_tabular_data` for microstructure with id `ms_id` - :param ms_id: - :param temperatures: + Perform `compute_tabular_data` for the microstructure with id `ms_id` + + :param ms_id: id of the microstructure + :param temperatures: list of sampling temperatures """ file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', 'sampling_alphas')(microstructures[ms_id]) @@ -191,9 +186,10 @@ def compute_tabular_data_for_ms(ms_id, temperatures): def compute_tabular_data(samples, mesh, temperatures): """ Compute tabular data for a given list of temperatures + :param samples: - :param mesh: - :param temperatures: + :param mesh: dict with mesh information + :param temperatures: list of sampling temperatures :return: C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1 """ @@ -259,61 +255,10 @@ def compute_tabular_data(samples, mesh, temperatures): return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1 -@jit(nopython=True, cache=True, parallel=True, nogil=True) -def compute_tabular_data_efficient(samples, mesh, temperatures): - """ - WIP - mat_id = mesh['mat_id'] - n_gauss = mesh['n_gauss'] - strain_dof = mesh['strain_dof'] - global_gradient = mesh['global_gradient'] - n_gp = mesh['n_integration_points'] - n_phases = len(np.unique(mat_id)) - n_modes = samples[0]['strain_localization'].shape[-1] - n_temps = len(temperatures) - A_bar = np.zeros((strain_dof, n_modes - 7, n_temps)) - D_xi = np.zeros((n_modes - 7, n_modes - 7, n_temps)) - tau_theta = np.zeros((strain_dof, n_temps)) - C_bar = np.zeros((strain_dof, strain_dof, n_temps)) - # interpolate_temp = lambda x1, x2, alpha: x1 + alpha * (x2 - x1) - # dns_temperatures = interpolate_temp(temp1, temp2, sample_alphas) - sample_temperatures = np.array([sample['temperature'] for sample in samples]) - temp1, temp2 = min(sample_temperatures), max(sample_temperatures) - sample_alphas = (sample_temperatures - temp1) / (temp2 - temp1) - # for idx, temperature in enumerate(temperatures): - for idx in prange(n_temps): - temperature = temperatures[idx] - alpha = (temperature - temp1) / (temp2 - temp1) - upper_bound = np.searchsorted(sample_alphas, alpha) - id1 = upper_bound if upper_bound > 0 else 1 - id0 = id1 - 1 - - E0 = samples[id0]['strain_localization'] - E1 = samples[id1]['strain_localization'] - E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) - - sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) - sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) - plastic_modes = samples[id0]['plastic_modes'] # TODO: does exist? - # normalization_factor_mech = samples[idx]['normalization_factor_mech'] # TODO: does exist? - ref_C = np.stack(([stiffness_cu(temperature), stiffness_wsc(temperature)])) - ref_eps = np.expand_dims(np.stack(([thermal_strain_cu(temperature), thermal_strain_wsc(temperature)])), axis=2) - - # interpolated quantities using an implicit interpolation scheme with four DOF - approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - Eopt4, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, - n_gp) - Sopt4 = construct_stress_localization(Eopt4, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) - # effSopt = volume_average(Sopt4) - A_bar[:,:,idx], D_xi[:,:,idx], tau_theta[:,idx], C_bar[:,:,idx] = compute_ntfa_matrices(Sopt4, plastic_modes, mesh) - return C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta - """ - pass - - def save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1): """ Save tabular data + :param file_name: e.g. "input/simple_3d_rve_combo.h5" :param data_path: :param temperatures: @@ -352,7 +297,8 @@ def save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_ba def read_tabular_data(file_name, data_path): """ - Save tabular data + Read tabular data + :param file_name: e.g. "input/simple_3d_rve_combo.h5" :param data_path: :return: @@ -386,32 +332,3 @@ def read_tabular_data(file_name, data_path): C0 = dset_ntfa['C0'][:] C1 = dset_ntfa['C1'][:] return temperatures, C_bar, tau_theta, A_bar, tau_xi, D_xi, D_theta, A0, A1, C0, C1 - -""" -TO BE REMOVED: -""" - -def create_dummy_plastic_snapshots(n_integration_points, strain_dof, n_frames=100): - """ - TODO: remove when FANS can compute plastic snapshots - """ - # plastic_snapshots = np.random.rand(n_integration_points, strain_dof, n_frames) - plastic_snapshots = np.random.rand(n_integration_points, strain_dof)[:, :, np.newaxis] * np.random.rand(n_frames) \ - + 1e-2 * np.random.rand(n_integration_points, strain_dof, n_frames) - return plastic_snapshots - - -def create_dummy_plastic_modes(n_integration_points, strain_dof, N_modes): - """ - TODO: remove when FANS can compute plastic snapshots - """ - plastic_modes = np.random.rand(n_integration_points, strain_dof, N_modes) - return plastic_modes - - -def create_dummy_plastic_strain_localization(strain_localization, N_modes): - E_eps = strain_localization[:, :, :6] - E_xi = np.random.rand(*strain_localization.shape[:2], N_modes) - E_theta = np.expand_dims(strain_localization[:, :, -1], axis=2) - strain_localization = np.concatenate([E_eps, E_xi, E_theta], axis=2) - return strain_localization diff --git a/requirements.txt b/requirements.txt index 9fc7e79..9a59936 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,4 +8,5 @@ torch~=1.13.1 sympy~=1.11.1 numba~=0.56.4 pytest~=7.2.1 -latex~=0.7.0 \ No newline at end of file +latex~=0.7.0 +tqdm~=4.66.5 \ No newline at end of file From 0e0ab8108add03a95d2b291857bbc1aa7ba7d2d1 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Fri, 25 Oct 2024 18:23:59 +0200 Subject: [PATCH 27/30] Code cleanup --- ntfa.py | 65 +++++++++++++++++++++++++++++----------------------- utilities.py | 4 ---- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/ntfa.py b/ntfa.py index 3b434ce..410c904 100644 --- a/ntfa.py +++ b/ntfa.py @@ -4,8 +4,14 @@ """ import numpy as np import h5py -from utilities import * -from material_parameters import * +import re +from operator import itemgetter +from utilities import read_h5, construct_stress_localization, construct_stress_localization_phases, \ + volume_average, volume_average_phases, norm_2 +from material_parameters import stiffness_cu, stiffness_wsc, thermal_strain_cu, thermal_strain_wsc +from interpolate_fluctuation_modes import interpolate_fluctuation_modes +from optimize_alpha import opt4 +from microstructures import microstructures from tqdm import tqdm @@ -16,7 +22,7 @@ def read_snapshots(file_name, data_path): :param file_name: e.g. "input/simple_3d_rve_combo.h5" :param data_path: the path to the simulation results within the h5 file, e.g. '/ms_1p/dset0_sim' :return: - strain_snapshots: plastic strain snapshots eps_p + strain_snapshots: plastic strain snapshots eps_p with shape (n_integration_points, strain_dof, n_frames) """ plastic_snapshots = None @@ -76,8 +82,8 @@ def compute_ntfa_matrices(strain_localization, stress_localization, plastic_mode n_modes = plastic_modes.shape[2] n_gp = mesh['n_integration_points'] n_gauss = mesh['n_gauss'] - I = np.eye(6) - + I2 = np.eye(6) + # slice strain localization operator E into E_eps, E_theta, E_xi E_eps = strain_localization[:, :, :strain_dof] E_theta = strain_localization[:, :, strain_dof] @@ -89,18 +95,18 @@ def compute_ntfa_matrices(strain_localization, stress_localization, plastic_mode S_xi = stress_localization[:, :, strain_dof + 1:] # Compute C_bar via < (E_eps + I).T @ S_eps > - C_bar = volume_average((E_eps + I).transpose((0, 2, 1)) @ S_eps) + C_bar = volume_average((E_eps + I2).transpose((0, 2, 1)) @ S_eps) # Compute tau_theta via < (E_eps + I).T @ S_theta > - tau_theta = volume_average(np.einsum('nij,nj->ni', (E_eps + I).transpose((0, 2, 1)), S_theta)) + tau_theta = volume_average(np.einsum('nij,nj->ni', (E_eps + I2).transpose((0, 2, 1)), S_theta)) # Compute A_bar via < (E_eps + I).T @ S_eps > - A_bar = volume_average((E_eps + I).transpose((0, 2, 1)) @ S_xi) + A_bar = volume_average((E_eps + I2).transpose((0, 2, 1)) @ S_xi) # Compute tau_xi via < (E_theta - P_theta).T @ S_xi > # Account for the phase-wise thermal strain by an explicit summation over all integration points tau_xi = np.zeros((1, n_modes)) - for gp_id in prange(n_gp): + for gp_id in range(n_gp): phase_id = mat_id[gp_id // n_gauss] tau_xi += (np.expand_dims(E_theta[gp_id], axis=1) - mat_thermal_strain[phase_id]).T @ S_xi[gp_id] / n_gp @@ -110,7 +116,7 @@ def compute_ntfa_matrices(strain_localization, stress_localization, plastic_mode # Compute D_theta via < (E_theta - P_theta).T @ S_theta > # Account for the phase-wise thermal strain by an explicit summation over all integration points D_theta = 0. - for gp_id in prange(n_gp): + for gp_id in range(n_gp): phase_id = mat_id[gp_id // n_gauss] D_theta += (np.expand_dims(E_theta[gp_id], axis=1) - mat_thermal_strain[phase_id]).T @ S_theta[gp_id] / n_gp @@ -163,7 +169,8 @@ def compute_phase_average_stress_localizations(strain_localization, mat_stiffnes combo_strain_loc0, combo_strain_loc1 = None, None stress_localization0, stress_localization1, _, _ = construct_stress_localization_phases( strain_localization, mat_stiffness, mat_thermal_strain, plastic_modes, combo_strain_loc0, combo_strain_loc1, mesh) - average_stress_localization0, average_stress_localization1 = volume_average(stress_localization0), volume_average(stress_localization1) + average_stress_localization0, average_stress_localization1 = \ + volume_average(stress_localization0), volume_average(stress_localization1) return average_stress_localization0, average_stress_localization1 @@ -174,15 +181,13 @@ def compute_tabular_data_for_ms(ms_id, temperatures): :param ms_id: id of the microstructure :param temperatures: list of sampling temperatures """ - file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[ms_id]) + file_name, data_path, temp1, temp2, n_tests, sampling_alphas = \ + itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', 'sampling_alphas')(microstructures[ms_id]) sample_temperatures = np.linspace(temp1, temp2, num=n_tests) - sample_alphas = np.linspace(0, 1, num=n_tests) mesh, samples = read_h5(file_name, data_path, sample_temperatures) return compute_tabular_data(samples, mesh, temperatures) -#@jit(nopython=True, cache=True, parallel=True, nogil=True) def compute_tabular_data(samples, mesh, temperatures): """ Compute tabular data for a given list of temperatures @@ -235,17 +240,19 @@ def compute_tabular_data(samples, mesh, temperatures): E01 = np.ascontiguousarray(np.concatenate((E0, E1), axis=-1)) sampling_C = np.stack((samples[id0]['mat_stiffness'], samples[id1]['mat_stiffness'])).transpose([1, 0, 2, 3]) - sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) + sampling_eps = np.stack((samples[id0]['mat_thermal_strain'], + samples[id1]['mat_thermal_strain'])).transpose([1, 0, 2, 3]) # interpolated quantities using an implicit interpolation scheme with four DOF approx_C, approx_eps = opt4(sampling_C, sampling_eps, ref_C, ref_eps) - E, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, n_gauss, strain_dof, n_modes, n_gp) + E, _ = interpolate_fluctuation_modes(E01, approx_C, approx_eps, plastic_modes, mat_id, + n_gauss, strain_dof, n_modes, n_gp) S = construct_stress_localization(E, ref_C, ref_eps, plastic_modes, mat_id, n_gauss, strain_dof) # Compute NTFA matrices C_bar[:, :, idx], tau_theta[:, idx], A_bar[:, :, idx], tau_xi[:, idx], D_xi[:, :, idx], D_theta[idx] = \ compute_ntfa_matrices(E, S, plastic_modes, ref_eps, mesh) - + # Compute phase average stresses A0_full, A1_full = compute_phase_average_stress_localizations(E, ref_C, ref_eps, plastic_modes, mesh) A0[:, :, idx], A1[:, :, idx] = A0_full, A1_full @@ -282,17 +289,17 @@ def save_tabular_data(file_name, data_path, temperatures, C_bar, tau_theta, A_ba del file[ntfa_path] dset_ntfa = dset.create_group(ntfa_path) [dset_ntfa.attrs.create(key, value) for key, value in dset_sim.attrs.items()] - dset_temperatures = dset_ntfa.create_dataset('temperatures', data=temperatures) - dset_C_bar = dset_ntfa.create_dataset('C_bar', data=C_bar) - dset_tau_theta = dset_ntfa.create_dataset('tau_theta', data=tau_theta) - dset_A_bar = dset_ntfa.create_dataset('A_bar', data=A_bar) - dset_tau_xi = dset_ntfa.create_dataset('tau_xi', data=tau_xi) - dset_D_xi = dset_ntfa.create_dataset('D_xi', data=D_xi) - dset_D_theta = dset_ntfa.create_dataset('D_theta', data=D_theta) - dset_A0 = dset_ntfa.create_dataset('A0', data=A0) - dset_A1 = dset_ntfa.create_dataset('A1', data=A1) - dset_C0 = dset_ntfa.create_dataset('C0', data=C0) - dset_C1 = dset_ntfa.create_dataset('C1', data=C1) + dset_ntfa.create_dataset('temperatures', data=temperatures) + dset_ntfa.create_dataset('C_bar', data=C_bar) + dset_ntfa.create_dataset('tau_theta', data=tau_theta) + dset_ntfa.create_dataset('A_bar', data=A_bar) + dset_ntfa.create_dataset('tau_xi', data=tau_xi) + dset_ntfa.create_dataset('D_xi', data=D_xi) + dset_ntfa.create_dataset('D_theta', data=D_theta) + dset_ntfa.create_dataset('A0', data=A0) + dset_ntfa.create_dataset('A1', data=A1) + dset_ntfa.create_dataset('C0', data=C0) + dset_ntfa.create_dataset('C1', data=C1) def read_tabular_data(file_name, data_path): diff --git a/utilities.py b/utilities.py index a760295..b9c56fc 100644 --- a/utilities.py +++ b/utilities.py @@ -1,5 +1,4 @@ import contextlib -import re import h5py import matplotlib.pyplot as plt import numpy as np @@ -7,9 +6,6 @@ import scipy.sparse from numba import jit, prange from sympy import symbols, lambdify, Array -from operator import itemgetter -from optimize_alpha import opt4 -from interpolate_fluctuation_modes import interpolate_fluctuation_modes from microstructures import * plt.rcParams.update({ From 64d2bf6720b0bf13e72c821c83ae1fba0e37a399 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Fri, 25 Oct 2024 18:29:55 +0200 Subject: [PATCH 28/30] Code cleanup --- eg08_plot_localization.py | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/eg08_plot_localization.py b/eg08_plot_localization.py index c73e7f5..2075f34 100644 --- a/eg08_plot_localization.py +++ b/eg08_plot_localization.py @@ -3,35 +3,12 @@ """ #%% from operator import itemgetter - +import numpy as np import numpy.linalg as la import matplotlib.pyplot as plt from microstructures import * from utilities import read_h5, construct_stress_localization -################ - - - - stress_localization = np.empty_like(strain_localization) - strain_localization_transp = ... - I = np.eye(strain_dof) - for gp_id in prange(strain_localization.shape[0]): - phase_id = mat_id[gp_id // n_gauss] - stress_localization[gp_id] = strain_localization_transp[gp_id] @ mat_stiffness[phase_id] @ (plastic_modes - eigen_strains) - A = volume_average(stress_localization) - - D0 = volume_average(inner_product((plastic_modes - eigen_strains), eigen_strains)) - - K0 = -volume_average(inner_product(plastic_modes, K @ eigen_strains)) - K = k * K0 - - D = D0 + K - - R = volume_average(thermal_stresses @ (plastic_modes - eigen_strains)) / delta_theta - - -########### np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter( From 82cc834e07601b20fcdf525656658e030df46f99 Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Fri, 25 Oct 2024 18:30:35 +0200 Subject: [PATCH 29/30] Code cleanup --- eg09_compute_ntfa_matrices.py | 3 --- eg10_compare_ntfa_matrices.py | 5 ----- 2 files changed, 8 deletions(-) diff --git a/eg09_compute_ntfa_matrices.py b/eg09_compute_ntfa_matrices.py index ccd2ed2..9f8bc1e 100644 --- a/eg09_compute_ntfa_matrices.py +++ b/eg09_compute_ntfa_matrices.py @@ -3,9 +3,6 @@ """ #%% from operator import itemgetter - -import numpy.linalg as la -import matplotlib.pyplot as plt import time from microstructures import * from utilities import read_h5 diff --git a/eg10_compare_ntfa_matrices.py b/eg10_compare_ntfa_matrices.py index 0cae4df..9418746 100644 --- a/eg10_compare_ntfa_matrices.py +++ b/eg10_compare_ntfa_matrices.py @@ -3,12 +3,7 @@ """ #%% from operator import itemgetter - -import numpy.linalg as la -import matplotlib.pyplot as plt -import time from microstructures import * -from utilities import read_h5 from ntfa import read_tabular_data file_name_10, data_path_10, temp1_10, temp2_10, n_tests_10, sampling_alphas_10 = itemgetter( From 187c884352074f59ffaef1bd53815b34be9b863c Mon Sep 17 00:00:00 2001 From: Julius Herb Date: Mon, 9 Dec 2024 13:40:25 +0100 Subject: [PATCH 30/30] Update examples --- eg00_affine_thermoelastic_solver.py | 0 eg01_approximation_of_mat_properties.py | 0 eg02_compare_approximations.py | 2 +- eg03_hierarchical_sampling.py | 4 +- eg04_hierarchical_sampling_efficient.py | 0 eg05_FFANN.py | 0 eg06_post_process_ann_vs_proposed.py | 0 eg07_staggered_model_interpolation.py | 2 +- eg08_plot_localization.py | 0 eg09_compute_ntfa_matrices.py | 0 eg10_compare_ntfa_matrices.py | 0 interpolate_fluctuation_modes.py | 0 material_parameters.py | 0 microstructures.py | 305 +----------------------- ntfa.py | 0 optimize_alpha.py | 0 utilities.py | 0 utilities_ann.py | 0 18 files changed, 9 insertions(+), 304 deletions(-) mode change 100644 => 100755 eg00_affine_thermoelastic_solver.py mode change 100644 => 100755 eg01_approximation_of_mat_properties.py mode change 100644 => 100755 eg02_compare_approximations.py mode change 100644 => 100755 eg03_hierarchical_sampling.py mode change 100644 => 100755 eg04_hierarchical_sampling_efficient.py mode change 100644 => 100755 eg05_FFANN.py mode change 100644 => 100755 eg06_post_process_ann_vs_proposed.py mode change 100644 => 100755 eg07_staggered_model_interpolation.py mode change 100644 => 100755 eg08_plot_localization.py mode change 100644 => 100755 eg09_compute_ntfa_matrices.py mode change 100644 => 100755 eg10_compare_ntfa_matrices.py mode change 100644 => 100755 interpolate_fluctuation_modes.py mode change 100644 => 100755 material_parameters.py mode change 100644 => 100755 microstructures.py mode change 100644 => 100755 ntfa.py mode change 100644 => 100755 optimize_alpha.py mode change 100644 => 100755 utilities.py mode change 100644 => 100755 utilities_ann.py diff --git a/eg00_affine_thermoelastic_solver.py b/eg00_affine_thermoelastic_solver.py old mode 100644 new mode 100755 diff --git a/eg01_approximation_of_mat_properties.py b/eg01_approximation_of_mat_properties.py old mode 100644 new mode 100755 diff --git a/eg02_compare_approximations.py b/eg02_compare_approximations.py old mode 100644 new mode 100755 index e07d9ed..a04fbfc --- a/eg02_compare_approximations.py +++ b/eg02_compare_approximations.py @@ -15,7 +15,7 @@ np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[-8]) + 'sampling_alphas')(microstructures[0]) print(file_name, '\t', data_path) n_loading_directions = 10 diff --git a/eg03_hierarchical_sampling.py b/eg03_hierarchical_sampling.py old mode 100644 new mode 100755 index c5123e1..d5847e1 --- a/eg03_hierarchical_sampling.py +++ b/eg03_hierarchical_sampling.py @@ -15,11 +15,11 @@ np.random.seed(0) file_name, data_path, temp1, temp2, n_tests, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', - 'sampling_alphas')(microstructures[-8]) + 'sampling_alphas')(microstructures[0]) print(file_name, '\t', data_path) n_loading_directions = 1 -n_hierarchical_levels = 2 +n_hierarchical_levels = 5 test_temperatures = np.linspace(temp1, temp2, num=n_tests) test_alphas = np.linspace(0, 1, num=n_tests) diff --git a/eg04_hierarchical_sampling_efficient.py b/eg04_hierarchical_sampling_efficient.py old mode 100644 new mode 100755 diff --git a/eg05_FFANN.py b/eg05_FFANN.py old mode 100644 new mode 100755 diff --git a/eg06_post_process_ann_vs_proposed.py b/eg06_post_process_ann_vs_proposed.py old mode 100644 new mode 100755 diff --git a/eg07_staggered_model_interpolation.py b/eg07_staggered_model_interpolation.py old mode 100644 new mode 100755 index 92aedfa..f87a893 --- a/eg07_staggered_model_interpolation.py +++ b/eg07_staggered_model_interpolation.py @@ -11,7 +11,7 @@ # Offline stage: Load precomputed optimal data load_start = time.time() -ms_id = 6 +ms_id = 0 level = 4 file_name, data_path, temp1, temp2, n_samples, sampling_alphas = itemgetter('file_name', 'data_path', 'temp1', 'temp2', 'n_tests', 'sampling_alphas')(microstructures[ms_id]) diff --git a/eg08_plot_localization.py b/eg08_plot_localization.py old mode 100644 new mode 100755 diff --git a/eg09_compute_ntfa_matrices.py b/eg09_compute_ntfa_matrices.py old mode 100644 new mode 100755 diff --git a/eg10_compare_ntfa_matrices.py b/eg10_compare_ntfa_matrices.py old mode 100644 new mode 100755 diff --git a/interpolate_fluctuation_modes.py b/interpolate_fluctuation_modes.py old mode 100644 new mode 100755 diff --git a/material_parameters.py b/material_parameters.py old mode 100644 new mode 100755 diff --git a/microstructures.py b/microstructures.py old mode 100644 new mode 100755 index 8624349..5d20ae8 --- a/microstructures.py +++ b/microstructures.py @@ -3,315 +3,20 @@ import numpy as np microstructures = [ -# { -# 'data_path': '/ms_1p/dset0_sim', -# 'file_name': path("input/striped_normal_4x4x4.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 100, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_1p/dset0_sim', -# 'file_name': path("input/sphere_normal_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_1p/dset0_sim', -# 'file_name': path("input/sphere_normal_32x32x32_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_1p/dset0_sim', -# 'file_name': path("input/sphere_combo_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_1p/dset0_sim', -# 'file_name': path("input/octahedron_normal_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_1p/dset0_sim', -# 'file_name': path("input/octahedron_combo_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': -# '/ms_1p/dset0_sim', -# 'file_name': -# path("input/octahedron_combo_32x32x32.h5"), -# 'temp1': -# 300, -# 'temp2': -# 1300, -# 'n_tests': -# 100, -# 'sampling_alphas': -# np.asarray([ -# np.asarray([0., 1.]), -# np.asarray([0., 0.82828283, 1.]), -# np.asarray([0., 0.82828283, 0.93939394, 1.]), -# np.asarray([0., 0.60606061, 0.82828283, 0.93939394, 1.]), -# np.asarray([0., 0.60606061, 0.82828283, 0.93939394, 0.97979798, 1.]) -# ], dtype=object) -# }, { -# 'data_path': -# '/image_data/dset_0_sim', -# 'file_name': -# path("input/random_rve_vol20.h5"), -# 'temp1': -# 300, -# 'temp2': -# 1300, -# 'n_tests': -# 100, -# 'sampling_alphas': -# np.asarray([ -# np.asarray([0., 1.]), -# np.asarray([0., 0.85858586, 1.]), -# np.asarray([0., 0.85858586, 0.94949495, 1.]), -# np.asarray([0., 0.66666667, 0.85858586, 0.94949495, 1.]), -# np.asarray([0., 0.66666667, 0.85858586, 0.94949495, 0.97979798, 1.]) -# ], dtype=object) -# }, { -# 'data_path': -# '/image_data/dset_0_sim', -# 'file_name': -# path("input/random_rve_vol40.h5"), -# 'temp1': -# 300, -# 'temp2': -# 1300, -# 'n_tests': -# 100, -# 'sampling_alphas': -# np.asarray([ -# np.asarray([0., 1.]), -# np.asarray([0., 0.8989899, 1.]), -# np.asarray([0., 0.8989899, 0.96969697, 1.]), -# np.asarray([0., 0.71717172, 0.8989899, 0.96969697, 1.]), -# np.asarray([0., 0.51515152, 0.71717172, 0.8989899, 0.96969697, 1.]) -# ], dtype=object) -# }, { -# 'data_path': -# '/image_data/dset_0_sim', -# 'file_name': -# path('input/random_rve_vol60.h5'), -# 'temp1': -# 300, -# 'temp2': -# 1300, -# 'n_tests': -# 100, -# 'sampling_alphas': -# np.asarray([ -# np.asarray([0., 1.]), -# np.asarray([0., 0.8989899, 1.]), -# np.asarray([0., 0.72727273, 0.8989899, 1.]), -# np.asarray([0., 0.72727273, 0.8989899, 0.96969697, 1.]), -# np.asarray([0., 0.52525253, 0.72727273, 0.8989899, 0.96969697, 1.]) -# ], dtype=object) -# }, -# { -# 'data_path': '/ms_1p/dset0_sim', -# 'file_name': path("input/striped_normal_4x4x4_plastic.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, -# { -# 'data_path': '/ms_1p/dset0_sim', -# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_9p/dset0_sim', -# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_9p/dset1_sim', -# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_9p/dset2_sim', -# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_9p/dset3_sim', -# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_15p/dset0_sim', -# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_15p/dset1_sim', -# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# },{ -# 'data_path': '/ms_15p/dset2_sim', -# 'file_name': path("input/simple_3d_rve_4x4x4_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_1p/dset0_sim', -# 'file_name': path("input/simple_3d_rve_4x4x4_100samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 100, -# 'sampling_alphas': None -# },{ -# 'data_path': '/ms_1p/dset0_sim', -# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_9p/dset0_sim', -# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_9p/dset1_sim', -# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_9p/dset2_sim', -# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_9p/dset3_sim', -# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_15p/dset0_sim', -# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_15p/dset1_sim', -# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, { -# 'data_path': '/ms_15p/dset2_sim', -# 'file_name': path("input/simple_3d_rve_16x16x16_10samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, -{ - 'data_path': '/ms_1p/dset0_sim', - 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 2, - 'sampling_alphas': None -}, { 'data_path': '/ms_9p/dset0_sim', - 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), + 'file_name': path("input/rve_thermoplastic_6loadings_10samples.h5"), 'temp1': 300, 'temp2': 1300, - 'n_tests': 2, + 'n_tests': 10, 'sampling_alphas': None }, { - 'data_path': '/ms_9p/dset1_sim', - 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 2, - 'sampling_alphas': None -}, -{ - 'data_path': '/ms_9p/dset2_sim', - 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 2, - 'sampling_alphas': None -}, -# { -# 'data_path': '/ms_9p/dset3_sim', -# 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), -# 'temp1': 300, -# 'temp2': 1300, -# 'n_tests': 10, -# 'sampling_alphas': None -# }, -{ - 'data_path': '/ms_15p/dset0_sim', - 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 2, - 'sampling_alphas': None -}, -{ - 'data_path': '/ms_15p/dset1_sim', - 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), + 'data_path': '/ms_9p/dset0_sim', + 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_100samples_fix.h5"), 'temp1': 300, 'temp2': 1300, - 'n_tests': 2, + 'n_tests': 100, 'sampling_alphas': None }, -{ - 'data_path': '/ms_15p/dset2_sim', - 'file_name': path("input/simple_3d_rve_B1-B6_16x16x16_2samples.h5"), - 'temp1': 300, - 'temp2': 1300, - 'n_tests': 2, - 'sampling_alphas': None -} ] diff --git a/ntfa.py b/ntfa.py old mode 100644 new mode 100755 diff --git a/optimize_alpha.py b/optimize_alpha.py old mode 100644 new mode 100755 diff --git a/utilities.py b/utilities.py old mode 100644 new mode 100755 diff --git a/utilities_ann.py b/utilities_ann.py old mode 100644 new mode 100755