Skip to content

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
juliusgh committed Oct 25, 2024
1 parent cf28738 commit 2b83e26
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 129 deletions.
173 changes: 45 additions & 128 deletions ntfa.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,34 @@
"""
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
from utilities import *
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
Expand All @@ -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])
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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(
Expand All @@ -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])
Expand All @@ -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
"""
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ torch~=1.13.1
sympy~=1.11.1
numba~=0.56.4
pytest~=7.2.1
latex~=0.7.0
latex~=0.7.0
tqdm~=4.66.5

0 comments on commit 2b83e26

Please sign in to comment.