#[allow(unused_imports)]
use super::functions::*;
#[allow(unused_imports)]
use super::functions_2::*;
use std::f64::consts::PI;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
pub struct CtodCriterion {
pub ctod_critical: f64,
pub young_modulus: f64,
pub poisson_ratio: f64,
pub yield_stress: f64,
}
#[allow(dead_code)]
impl CtodCriterion {
pub fn new(
ctod_critical: f64,
young_modulus: f64,
poisson_ratio: f64,
yield_stress: f64,
) -> Self {
Self {
ctod_critical,
young_modulus,
poisson_ratio,
yield_stress,
}
}
pub fn structural_steel() -> Self {
Self::new(0.1e-3, 200.0e9, 0.3, 355.0e6)
}
pub fn compute_plastic_zone_size(&self, k_i: f64, plane_strain: bool) -> f64 {
let factor = if plane_strain {
1.0 / (6.0 * PI)
} else {
1.0 / (2.0 * PI)
};
factor * (k_i / self.yield_stress).powi(2)
}
pub fn compute_dugdale_plastic_zone(&self, half_crack: f64, applied_stress: f64) -> f64 {
let arg = PI * applied_stress / (2.0 * self.yield_stress);
if arg.abs() >= PI / 2.0 - 1e-6 {
return f64::INFINITY;
}
half_crack * (1.0 / arg.cos() - 1.0)
}
pub fn is_critical(&self, ctod: f64) -> bool {
ctod >= self.ctod_critical
}
pub fn ctod_from_sif(&self, k_i: f64, plane_strain: bool) -> f64 {
let e_prime = if plane_strain {
self.young_modulus / (1.0 - self.poisson_ratio * self.poisson_ratio)
} else {
self.young_modulus
};
k_i * k_i / (e_prime * self.yield_stress)
}
pub fn critical_sif(&self, plane_strain: bool) -> f64 {
let e_prime = if plane_strain {
self.young_modulus / (1.0 - self.poisson_ratio * self.poisson_ratio)
} else {
self.young_modulus
};
(self.ctod_critical * e_prime * self.yield_stress).sqrt()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct PhaseFieldParams {
pub gc: f64,
pub l0: f64,
pub e: f64,
pub nu: f64,
}
impl PhaseFieldParams {
pub fn new(gc: f64, l0: f64, e: f64, nu: f64) -> Self {
Self { gc, l0, e, nu }
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct GtnParams {
pub q1: f64,
pub q2: f64,
pub q3: f64,
pub f0: f64,
pub fc: f64,
pub ff: f64,
pub fn_void: f64,
pub sn: f64,
pub en: f64,
pub sigma_y: f64,
pub e: f64,
pub nu: f64,
}
impl GtnParams {
pub fn steel() -> Self {
Self {
q1: 1.5,
q2: 1.0,
q3: 2.25,
f0: 0.001,
fc: 0.15,
ff: 0.25,
fn_void: 0.04,
sn: 0.1,
en: 0.3,
sigma_y: 250.0e6,
e: 200.0e9,
nu: 0.3,
}
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
pub struct GriffithCriterion {
pub g_critical: f64,
pub young_modulus: f64,
pub poisson_ratio: f64,
pub shear_modulus: f64,
}
#[allow(dead_code)]
impl GriffithCriterion {
pub fn new(g_critical: f64, young_modulus: f64, poisson_ratio: f64) -> Self {
let shear_modulus = young_modulus / (2.0 * (1.0 + poisson_ratio));
Self {
g_critical,
young_modulus,
poisson_ratio,
shear_modulus,
}
}
pub fn steel() -> Self {
Self::new(100.0, 200.0e9, 0.3)
}
pub fn effective_modulus(&self, plane_strain: bool) -> f64 {
if plane_strain {
self.young_modulus / (1.0 - self.poisson_ratio * self.poisson_ratio)
} else {
self.young_modulus
}
}
pub fn compute_energy_release_rate_mode_i(&self, k_i: f64, plane_strain: bool) -> f64 {
let e_prime = self.effective_modulus(plane_strain);
k_i * k_i / e_prime
}
pub fn compute_energy_release_rate(
&self,
k_i: f64,
k_ii: f64,
k_iii: f64,
plane_strain: bool,
) -> f64 {
let e_prime = self.effective_modulus(plane_strain);
let g_mode1 = k_i * k_i / e_prime;
let g_mode2 = k_ii * k_ii / e_prime;
let g_mode3 = k_iii * k_iii / (2.0 * self.shear_modulus);
g_mode1 + g_mode2 + g_mode3
}
pub fn is_critical(&self, k_i: f64, k_ii: f64, k_iii: f64, plane_strain: bool) -> bool {
self.compute_energy_release_rate(k_i, k_ii, k_iii, plane_strain) >= self.g_critical
}
pub fn critical_sif(&self, plane_strain: bool) -> f64 {
let e_prime = self.effective_modulus(plane_strain);
(self.g_critical * e_prime).sqrt()
}
pub fn critical_crack_length(&self, stress: f64, plane_strain: bool) -> f64 {
let e_prime = self.effective_modulus(plane_strain);
if stress.abs() < f64::EPSILON {
return f64::INFINITY;
}
self.g_critical * e_prime / (PI * stress * stress)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct RCurve {
pub k_init: f64,
pub k_plateau: f64,
pub delta_a_char: f64,
}
#[allow(dead_code)]
impl RCurve {
pub fn new(k_init: f64, k_plateau: f64, delta_a_char: f64) -> Self {
Self {
k_init,
k_plateau,
delta_a_char,
}
}
pub fn resistance(&self, delta_a: f64) -> f64 {
if delta_a <= 0.0 {
return self.k_init;
}
self.k_init + (self.k_plateau - self.k_init) * (1.0 - (-delta_a / self.delta_a_char).exp())
}
pub fn is_stable(&self, k_applied: f64, delta_a: f64) -> bool {
k_applied <= self.resistance(delta_a)
}
pub fn critical_extension(&self, k0: f64, dk_da: f64) -> Option<f64> {
let delta_k = self.k_plateau - self.k_init;
if delta_k <= 0.0 || dk_da <= 0.0 {
if k0 >= self.k_init {
return Some(0.0);
}
return None;
}
let slope_init = delta_k / self.delta_a_char;
if dk_da >= slope_init {
return Some(0.0);
}
let delta_a_crit = -self.delta_a_char * (dk_da / slope_init).ln();
let k_r = self.resistance(delta_a_crit);
let k_app = k0 + dk_da * delta_a_crit;
if k_app >= k_r {
Some(delta_a_crit)
} else {
None
}
}
}
impl RCurve {
pub fn compute_stable_crack_growth(
&self,
k0: f64,
dk_da: f64,
delta_a_max: f64,
n_steps: usize,
) -> Vec<(f64, f64, f64)> {
if n_steps == 0 || delta_a_max <= 0.0 {
return Vec::new();
}
let step = delta_a_max / n_steps as f64;
let mut result = Vec::with_capacity(n_steps + 1);
for i in 0..=n_steps {
let da = i as f64 * step;
let k_app = k0 + dk_da * da;
let k_r = self.resistance(da);
result.push((da, k_app, k_r));
if k_app > k_r + 1e-6 * k_r {
break;
}
}
result
}
pub fn initiation_load(&self) -> f64 {
self.k_init
}
pub fn instability_load(&self, dk_da: f64) -> Option<f64> {
let delta_a = self.critical_extension(self.k_init, dk_da)?;
Some(self.k_init + dk_da * delta_a)
}
}