#[derive(Debug, Clone)]
pub struct ShellVibrationSolver {
pub young_modulus: f64,
pub poisson_ratio: f64,
pub density: f64,
pub thickness: f64,
pub radius: f64,
pub length: f64,
}
impl ShellVibrationSolver {
pub fn new(
young_modulus: f64,
poisson_ratio: f64,
density: f64,
thickness: f64,
radius: f64,
length: f64,
) -> Self {
Self {
young_modulus,
poisson_ratio,
density,
thickness,
radius,
length,
}
}
pub fn ring_frequency_mode(&self, n: u32) -> f64 {
let n = n as f64;
let e = self.young_modulus;
let nu = self.poisson_ratio;
let rho = self.density;
let r = self.radius;
let h = self.thickness;
let c = e / (rho * (1.0 - nu * nu));
let omega_sq = c * (h * h) / (12.0 * r * r * r * r) * n * n * (n * n - 1.0) * (n * n - 1.0)
/ (n * n + 1.0);
omega_sq.abs().sqrt()
}
pub fn breathing_frequency(&self) -> f64 {
let c_l = (self.young_modulus
/ (self.density * (1.0 - self.poisson_ratio * self.poisson_ratio)))
.sqrt();
c_l / self.radius
}
pub fn longitudinal_frequency(&self, m: u32) -> f64 {
let c_l = (self.young_modulus / self.density).sqrt();
m as f64 * std::f64::consts::PI / self.length * c_l
}
}
pub struct ShellGeometry {
pub r1: f64,
pub r2: f64,
pub thickness: f64,
}
impl ShellGeometry {
pub fn new(r1: f64, r2: f64, thickness: f64) -> Self {
Self { r1, r2, thickness }
}
}
#[derive(Debug, Clone)]
pub struct CompositeLaminate {
pub plies: Vec<PlyLayer>,
pub angles: Vec<f64>,
}
impl CompositeLaminate {
pub fn new(plies: Vec<PlyLayer>, angles: Vec<f64>) -> Self {
assert_eq!(plies.len(), angles.len());
Self { plies, angles }
}
pub fn total_thickness(&self) -> f64 {
self.plies.iter().map(|p| p.thickness).sum()
}
pub fn abd_matrix(&self) -> [[f64; 6]; 6] {
let n = self.plies.len();
let total_h = self.total_thickness();
let mut z = vec![0.0_f64; n + 1];
z[0] = -total_h / 2.0;
for k in 0..n {
z[k + 1] = z[k] + self.plies[k].thickness;
}
let mut a = [[0.0_f64; 3]; 3];
let mut b = [[0.0_f64; 3]; 3];
let mut d = [[0.0_f64; 3]; 3];
for k in 0..n {
let q = self.plies[k].q_matrix_global(self.angles[k]);
let zk = z[k];
let zk1 = z[k + 1];
let dz1 = zk1 - zk;
let dz2 = (zk1 * zk1 - zk * zk) / 2.0;
let dz3 = (zk1 * zk1 * zk1 - zk * zk * zk) / 3.0;
for i in 0..3 {
for j in 0..3 {
a[i][j] += q[i][j] * dz1;
b[i][j] += q[i][j] * dz2;
d[i][j] += q[i][j] * dz3;
}
}
}
let mut abd = [[0.0_f64; 6]; 6];
for i in 0..3 {
for j in 0..3 {
abd[i][j] = a[i][j];
abd[i][j + 3] = b[i][j];
abd[i + 3][j] = b[i][j];
abd[i + 3][j + 3] = d[i][j];
}
}
abd
}
}
pub struct ShellElement {
pub young_modulus: f64,
pub poisson_ratio: f64,
pub thickness: f64,
}
impl ShellElement {
pub fn new(young_modulus: f64, poisson_ratio: f64, thickness: f64) -> Self {
Self {
young_modulus,
poisson_ratio,
thickness,
}
}
pub fn compute_membrane_forces(&self, nodes: &[[f64; 2]; 3], disp: &[f64; 6]) -> [f64; 3] {
let e = self.young_modulus;
let nu = self.poisson_ratio;
let t = self.thickness;
let (x0, y0) = (nodes[0][0], nodes[0][1]);
let (x1, y1) = (nodes[1][0], nodes[1][1]);
let (x2, y2) = (nodes[2][0], nodes[2][1]);
let two_a = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0);
if two_a.abs() < 1e-30 {
return [0.0; 3];
}
let b = [
[
(y1 - y2) / two_a,
0.0,
(y2 - y0) / two_a,
0.0,
(y0 - y1) / two_a,
0.0,
],
[
0.0,
(x2 - x1) / two_a,
0.0,
(x0 - x2) / two_a,
0.0,
(x1 - x0) / two_a,
],
[
(x2 - x1) / two_a,
(y1 - y2) / two_a,
(x0 - x2) / two_a,
(y2 - y0) / two_a,
(x1 - x0) / two_a,
(y0 - y1) / two_a,
],
];
let mut eps = [0.0_f64; 3];
for i in 0..3 {
for j in 0..6 {
eps[i] += b[i][j] * disp[j];
}
}
let c_fac = e / (1.0 - nu * nu);
let c = [
[c_fac, c_fac * nu, 0.0],
[c_fac * nu, c_fac, 0.0],
[0.0, 0.0, c_fac * (1.0 - nu) / 2.0],
];
let mut sigma = [0.0_f64; 3];
for i in 0..3 {
for j in 0..3 {
sigma[i] += c[i][j] * eps[j];
}
}
[sigma[0] * t, sigma[1] * t, sigma[2] * t]
}
pub fn compute_buckling_load(&self, nodes: &[[f64; 2]; 3]) -> f64 {
let t = self.thickness;
let e = self.young_modulus;
let nu = self.poisson_ratio;
let d = e * t * t * t / (12.0 * (1.0 - nu * nu));
let sides = [
((nodes[1][0] - nodes[0][0]).powi(2) + (nodes[1][1] - nodes[0][1]).powi(2)).sqrt(),
((nodes[2][0] - nodes[1][0]).powi(2) + (nodes[2][1] - nodes[1][1]).powi(2)).sqrt(),
((nodes[0][0] - nodes[2][0]).powi(2) + (nodes[0][1] - nodes[2][1]).powi(2)).sqrt(),
];
let b = sides
.iter()
.cloned()
.fold(f64::NEG_INFINITY, f64::max)
.max(1e-30);
4.0 * std::f64::consts::PI * std::f64::consts::PI * d / (b * b)
}
pub fn compute_large_deflection_correction(
&self,
nodes: &[[f64; 2]; 3],
disp: &[f64; 9],
) -> [f64; 9] {
let (x0, y0) = (nodes[0][0], nodes[0][1]);
let (x1, y1) = (nodes[1][0], nodes[1][1]);
let (x2, y2) = (nodes[2][0], nodes[2][1]);
let two_a = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0);
if two_a.abs() < 1e-30 {
return [0.0; 9];
}
let area = two_a.abs() / 2.0;
let dndx = [(y1 - y2) / two_a, (y2 - y0) / two_a, (y0 - y1) / two_a];
let dndy = [(x2 - x1) / two_a, (x0 - x2) / two_a, (x1 - x0) / two_a];
let w = [disp[0], disp[3], disp[6]];
let dw_dx: f64 = (0..3).map(|i| dndx[i] * w[i]).sum();
let dw_dy: f64 = (0..3).map(|i| dndy[i] * w[i]).sum();
let e = self.young_modulus;
let nu = self.poisson_ratio;
let t = self.thickness;
let c_fac = e * t / (1.0 - nu * nu);
let eps_xx_nl = 0.5 * dw_dx * dw_dx;
let eps_yy_nl = 0.5 * dw_dy * dw_dy;
let eps_xy_nl = dw_dx * dw_dy;
let nx = c_fac * (eps_xx_nl + nu * eps_yy_nl);
let ny = c_fac * (nu * eps_xx_nl + eps_yy_nl);
let nxy = c_fac * (1.0 - nu) / 2.0 * eps_xy_nl;
let mut f_corr = [0.0_f64; 9];
for i in 0..3 {
let fi = area
* (nx * dndx[i] * dw_dx
+ ny * dndy[i] * dw_dy
+ nxy * (dndx[i] * dw_dy + dndy[i] * dw_dx));
f_corr[i * 3] = fi;
}
f_corr
}
}
pub struct RectPlateElement {
pub params: PlateParams,
pub a: f64,
pub b: f64,
pub node_positions: [[f64; 2]; 4],
}
impl RectPlateElement {
pub fn new(params: PlateParams, a: f64, b: f64) -> Self {
let node_positions = [[-a, -b], [a, -b], [a, b], [-a, b]];
Self {
params,
a,
b,
node_positions,
}
}
pub fn stiffness_matrix_12x12(&self) -> Vec<Vec<f64>> {
let d = self.params.flexural_rigidity();
let a = self.a;
let b = self.b;
let a2 = a * a;
let b2 = b * b;
let kw = d * (2.0 * b / (a2 * a) + 2.0 * a / (b2 * b));
let ktx = d * (2.0 * b / a);
let kty = d * (2.0 * a / b);
let mut k = vec![vec![0.0f64; 12]; 12];
for node in 0..4 {
let base = node * 3;
k[base][base] = kw;
k[base + 1][base + 1] = ktx;
k[base + 2][base + 2] = kty;
}
k
}
pub fn consistent_mass_matrix(&self, rho: f64) -> Vec<Vec<f64>> {
let h = self.params.thickness;
let a = self.a;
let b = self.b;
let area = (2.0 * a) * (2.0 * b);
let mw = rho * h * area / 4.0;
let mr = rho * h * area / 4.0 * (a * a + b * b) / 12.0;
let mut m = vec![vec![0.0f64; 12]; 12];
for node in 0..4 {
let base = node * 3;
m[base][base] = mw;
m[base + 1][base + 1] = mr;
m[base + 2][base + 2] = mr;
}
m
}
}
pub struct FlatShellElement {
pub young_modulus: f64,
pub poisson_ratio: f64,
pub density: f64,
pub thickness: f64,
}
impl FlatShellElement {
pub fn new(young_modulus: f64, poisson_ratio: f64, density: f64, thickness: f64) -> Self {
Self {
young_modulus,
poisson_ratio,
density,
thickness,
}
}
pub fn stiffness_triangle(&self, nodes: &[[f64; 2]; 3]) -> Vec<Vec<f64>> {
let k_mem = self.membrane_stiffness(nodes);
let k_bend = self.bending_stiffness(nodes);
let mut k = vec![vec![0.0_f64; 18]; 18];
let mem_map = [0, 1, 6, 7, 12, 13];
for i in 0..6 {
for j in 0..6 {
k[mem_map[i]][mem_map[j]] += k_mem[i][j];
}
}
let bend_map = [2, 3, 4, 8, 9, 10, 14, 15, 16];
for i in 0..9 {
for j in 0..9 {
k[bend_map[i]][bend_map[j]] += k_bend[i][j];
}
}
let area = {
let (x0, y0) = (nodes[0][0], nodes[0][1]);
let (x1, y1) = (nodes[1][0], nodes[1][1]);
let (x2, y2) = (nodes[2][0], nodes[2][1]);
0.5 * ((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)).abs()
};
let drill_stiff = self.young_modulus * self.thickness * area * 1e-6;
k[5][5] += drill_stiff;
k[11][11] += drill_stiff;
k[17][17] += drill_stiff;
k
}
fn membrane_stiffness(&self, nodes: &[[f64; 2]; 3]) -> [[f64; 6]; 6] {
let elem = MembraneTriangle::new(self.thickness, self.young_modulus, self.poisson_ratio);
elem.stiffness_2d(nodes)
}
fn bending_stiffness(&self, nodes: &[[f64; 2]; 3]) -> [[f64; 9]; 9] {
let plate = KirchhoffPlate::new(
self.thickness,
self.young_modulus,
self.poisson_ratio,
self.density,
);
let d_mat = plate.constitutive_matrix();
let (x0, y0) = (nodes[0][0], nodes[0][1]);
let (x1, y1) = (nodes[1][0], nodes[1][1]);
let (x2, y2) = (nodes[2][0], nodes[2][1]);
let area = 0.5 * ((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)).abs();
if area < 1e-15 {
return [[0.0; 9]; 9];
}
let two_a = 2.0 * area;
let b1x = (y1 - y2) / two_a;
let b2x = (y2 - y0) / two_a;
let b3x = (y0 - y1) / two_a;
let b1y = (x2 - x1) / two_a;
let b2y = (x0 - x2) / two_a;
let b3y = (x1 - x0) / two_a;
let b_bend = [
[0.0, 0.0, b1x, 0.0, 0.0, b2x, 0.0, 0.0, b3x],
[0.0, -b1y, 0.0, 0.0, -b2y, 0.0, 0.0, -b3y, 0.0],
[0.0, -b1x, b1y, 0.0, -b2x, b2y, 0.0, -b3x, b3y],
];
let mut db = [[0.0_f64; 9]; 3];
for i in 0..3 {
for j in 0..9 {
for l in 0..3 {
db[i][j] += d_mat[i][l] * b_bend[l][j];
}
}
}
let mut k_bend = [[0.0_f64; 9]; 9];
for i in 0..9 {
for j in 0..9 {
let mut val = 0.0;
for l in 0..3 {
val += b_bend[l][i] * db[l][j];
}
k_bend[i][j] = area * val;
}
}
k_bend
}
}
pub struct MembraneTriangle {
pub thickness: f64,
pub young_modulus: f64,
pub poisson_ratio: f64,
}
impl MembraneTriangle {
pub fn new(thickness: f64, e: f64, nu: f64) -> Self {
Self {
thickness,
young_modulus: e,
poisson_ratio: nu,
}
}
pub fn constitutive_matrix(&self) -> [[f64; 3]; 3] {
let e = self.young_modulus;
let nu = self.poisson_ratio;
let c = e / (1.0 - nu * nu);
[
[c, c * nu, 0.0],
[c * nu, c, 0.0],
[0.0, 0.0, c * (1.0 - nu) / 2.0],
]
}
pub fn stiffness_2d(&self, nodes: &[[f64; 2]; 3]) -> [[f64; 6]; 6] {
let area = Self::area(nodes);
if area.abs() < 1e-15 {
return [[0.0; 6]; 6];
}
let x0 = nodes[0][0];
let y0 = nodes[0][1];
let x1 = nodes[1][0];
let y1 = nodes[1][1];
let x2 = nodes[2][0];
let y2 = nodes[2][1];
let two_a = 2.0 * area;
let dn0dx = (y1 - y2) / two_a;
let dn0dy = (x2 - x1) / two_a;
let dn1dx = (y2 - y0) / two_a;
let dn1dy = (x0 - x2) / two_a;
let dn2dx = (y0 - y1) / two_a;
let dn2dy = (x1 - x0) / two_a;
let bmat = [
[dn0dx, 0.0, dn1dx, 0.0, dn2dx, 0.0],
[0.0, dn0dy, 0.0, dn1dy, 0.0, dn2dy],
[dn0dy, dn0dx, dn1dy, dn1dx, dn2dy, dn2dx],
];
let d = self.constitutive_matrix();
let mut db = [[0.0f64; 6]; 3];
for i in 0..3 {
for j in 0..6 {
for l in 0..3 {
db[i][j] += d[i][l] * bmat[l][j];
}
}
}
let mut k = [[0.0f64; 6]; 6];
let ta = self.thickness * area;
for i in 0..6 {
for j in 0..6 {
let mut sum = 0.0;
for l in 0..3 {
sum += bmat[l][i] * db[l][j];
}
k[i][j] = ta * sum;
}
}
k
}
pub fn area(nodes: &[[f64; 2]; 3]) -> f64 {
let (x0, y0) = (nodes[0][0], nodes[0][1]);
let (x1, y1) = (nodes[1][0], nodes[1][1]);
let (x2, y2) = (nodes[2][0], nodes[2][1]);
0.5 * ((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)).abs()
}
}
pub struct MindlinShell {
pub thickness: f64,
pub young_modulus: f64,
pub poisson_ratio: f64,
pub shear_correction: f64,
}
impl MindlinShell {
pub fn new(thickness: f64, e: f64, nu: f64) -> Self {
Self {
thickness,
young_modulus: e,
poisson_ratio: nu,
shear_correction: 5.0 / 6.0,
}
}
pub fn shear_modulus(&self) -> f64 {
self.young_modulus / (2.0 * (1.0 + self.poisson_ratio))
}
pub fn shear_stiffness(&self) -> f64 {
self.shear_correction * self.shear_modulus() * self.thickness
}
pub fn bending_matrix(&self) -> [[f64; 3]; 3] {
let t = self.thickness;
let e = self.young_modulus;
let nu = self.poisson_ratio;
let d = e * t * t * t / (12.0 * (1.0 - nu * nu));
[
[d, d * nu, 0.0],
[d * nu, d, 0.0],
[0.0, 0.0, d * (1.0 - nu) / 2.0],
]
}
pub fn shear_matrix(&self) -> [[f64; 2]; 2] {
let ks = self.shear_stiffness();
[[ks, 0.0], [0.0, ks]]
}
pub fn is_thin(&self, span: f64) -> bool {
self.thickness / span < 0.05
}
}
pub struct KirchhoffPlate {
pub thickness: f64,
pub young_modulus: f64,
pub poisson_ratio: f64,
pub density: f64,
}
impl KirchhoffPlate {
pub fn new(thickness: f64, e: f64, nu: f64, density: f64) -> Self {
Self {
thickness,
young_modulus: e,
poisson_ratio: nu,
density,
}
}
pub fn flexural_rigidity(&self) -> f64 {
let t = self.thickness;
self.young_modulus * t * t * t / (12.0 * (1.0 - self.poisson_ratio * self.poisson_ratio))
}
pub fn constitutive_matrix(&self) -> [[f64; 3]; 3] {
let d = self.flexural_rigidity();
let nu = self.poisson_ratio;
[
[d, d * nu, 0.0],
[d * nu, d, 0.0],
[0.0, 0.0, d * (1.0 - nu) / 2.0],
]
}
pub fn rectangular_stiffness(&self, a: f64, b: f64) -> [[f64; 12]; 12] {
let d = self.flexural_rigidity();
let nu = self.poisson_ratio;
let a2 = a * a;
let b2 = b * b;
let gp = [-f64::sqrt(3.0 / 5.0), 0.0, f64::sqrt(3.0 / 5.0)];
let gw = [5.0 / 9.0, 8.0 / 9.0, 5.0 / 9.0];
let hermite_val = |xi: f64, which: usize| -> f64 {
match which {
0 => 0.25 * (2.0 - 3.0 * xi + xi * xi * xi),
1 => 0.25 * (1.0 - xi - xi * xi + xi * xi * xi),
2 => 0.25 * (2.0 + 3.0 * xi - xi * xi * xi),
3 => 0.25 * (-1.0 - xi + xi * xi + xi * xi * xi),
_ => 0.0,
}
};
let hermite_d1 = |xi: f64, which: usize| -> f64 {
match which {
0 => 0.25 * (-3.0 + 3.0 * xi * xi),
1 => 0.25 * (-1.0 - 2.0 * xi + 3.0 * xi * xi),
2 => 0.25 * (3.0 - 3.0 * xi * xi),
3 => 0.25 * (-1.0 + 2.0 * xi + 3.0 * xi * xi),
_ => 0.0,
}
};
let hermite_d2 = |xi: f64, which: usize| -> f64 {
match which {
0 => 3.0 * xi / 2.0,
1 => (3.0 * xi - 1.0) / 2.0,
2 => -3.0 * xi / 2.0,
3 => (3.0 * xi + 1.0) / 2.0,
_ => 0.0,
}
};
let dof_desc: [(usize, f64, usize, f64); 12] = [
(0, 1.0, 0, 1.0),
(0, 1.0, 1, b),
(1, a, 0, 1.0),
(2, 1.0, 0, 1.0),
(2, 1.0, 1, b),
(3, a, 0, 1.0),
(2, 1.0, 2, 1.0),
(2, 1.0, 3, b),
(3, a, 2, 1.0),
(0, 1.0, 2, 1.0),
(0, 1.0, 3, b),
(1, a, 2, 1.0),
];
let mut k = [[0.0f64; 12]; 12];
for i in 0..12 {
let (xi_b_i, sx_i, eta_b_i, sy_i) = dof_desc[i];
for j in 0..12 {
let (xi_b_j, sx_j, eta_b_j, sy_j) = dof_desc[j];
let mut val = 0.0;
for (ig, &xi) in gp.iter().enumerate() {
for (jg, &eta) in gp.iter().enumerate() {
let w = gw[ig] * gw[jg];
let d2ni_dx2 = sx_i
* (4.0 / a2)
* hermite_d2(xi, xi_b_i)
* sy_i
* hermite_val(eta, eta_b_i);
let d2ni_dy2 = sx_i
* hermite_val(xi, xi_b_i)
* sy_i
* (4.0 / b2)
* hermite_d2(eta, eta_b_i);
let d2ni_dxy = sx_i
* (2.0 / a)
* hermite_d1(xi, xi_b_i)
* sy_i
* (2.0 / b)
* hermite_d1(eta, eta_b_i);
let d2nj_dx2 = sx_j
* (4.0 / a2)
* hermite_d2(xi, xi_b_j)
* sy_j
* hermite_val(eta, eta_b_j);
let d2nj_dy2 = sx_j
* hermite_val(xi, xi_b_j)
* sy_j
* (4.0 / b2)
* hermite_d2(eta, eta_b_j);
let d2nj_dxy = sx_j
* (2.0 / a)
* hermite_d1(xi, xi_b_j)
* sy_j
* (2.0 / b)
* hermite_d1(eta, eta_b_j);
let integrand = d
* (d2ni_dx2 * d2nj_dx2
+ d2ni_dy2 * d2nj_dy2
+ nu * (d2ni_dx2 * d2nj_dy2 + d2ni_dy2 * d2nj_dx2)
+ 2.0 * (1.0 - nu) * d2ni_dxy * d2nj_dxy);
val += w * integrand * (a * b / 4.0);
}
}
k[i][j] = val;
}
}
k
}
pub fn rectangular_mass(&self, a: f64, b: f64) -> [[f64; 12]; 12] {
let rho_t = self.density * self.thickness;
let gp = [-f64::sqrt(3.0 / 5.0), 0.0, f64::sqrt(3.0 / 5.0)];
let gw = [5.0 / 9.0, 8.0 / 9.0, 5.0 / 9.0];
let hermite_val = |xi: f64, which: usize| -> f64 {
match which {
0 => 0.25 * (2.0 - 3.0 * xi + xi * xi * xi),
1 => 0.25 * (1.0 - xi - xi * xi + xi * xi * xi),
2 => 0.25 * (2.0 + 3.0 * xi - xi * xi * xi),
3 => 0.25 * (-1.0 - xi + xi * xi + xi * xi * xi),
_ => 0.0,
}
};
let dof_desc: [(usize, f64, usize, f64); 12] = [
(0, 1.0, 0, 1.0),
(0, 1.0, 1, b),
(1, a, 0, 1.0),
(2, 1.0, 0, 1.0),
(2, 1.0, 1, b),
(3, a, 0, 1.0),
(2, 1.0, 2, 1.0),
(2, 1.0, 3, b),
(3, a, 2, 1.0),
(0, 1.0, 2, 1.0),
(0, 1.0, 3, b),
(1, a, 2, 1.0),
];
let mut m = [[0.0f64; 12]; 12];
for i in 0..12 {
let (xi_b_i, sx_i, eta_b_i, sy_i) = dof_desc[i];
for j in 0..12 {
let (xi_b_j, sx_j, eta_b_j, sy_j) = dof_desc[j];
let mut val = 0.0;
for (ig, &xi) in gp.iter().enumerate() {
for (jg, &eta) in gp.iter().enumerate() {
let w = gw[ig] * gw[jg];
let ni = sx_i * hermite_val(xi, xi_b_i) * sy_i * hermite_val(eta, eta_b_i);
let nj = sx_j * hermite_val(xi, xi_b_j) * sy_j * hermite_val(eta, eta_b_j);
val += w * rho_t * ni * nj * (a * b / 4.0);
}
}
m[i][j] = val;
}
}
m
}
pub fn natural_frequency_ss(&self, m: u32, n: u32, a: f64, b: f64) -> f64 {
let d = self.flexural_rigidity();
let mf = m as f64;
let nf = n as f64;
std::f64::consts::PI
* std::f64::consts::PI
* f64::sqrt(d / (self.density * self.thickness))
* ((mf / a).powi(2) + (nf / b).powi(2))
}
}
pub struct MindlinElement {
pub params: MindlinParams,
pub size: [f64; 2],
}
impl MindlinElement {
pub fn new(params: MindlinParams, size: [f64; 2]) -> Self {
Self { params, size }
}
}
#[derive(Debug, Clone)]
pub struct SandwichPlate {
pub face_e: f64,
pub face_nu: f64,
pub face_thickness: f64,
pub core_g: f64,
pub core_nu: f64,
pub core_thickness: f64,
}
impl SandwichPlate {
pub fn new(
face_e: f64,
face_nu: f64,
face_thickness: f64,
core_g: f64,
core_nu: f64,
core_thickness: f64,
) -> Self {
Self {
face_e,
face_nu,
face_thickness,
core_g,
core_nu,
core_thickness,
}
}
pub fn total_thickness(&self) -> f64 {
2.0 * self.face_thickness + self.core_thickness
}
pub fn effective_flexural_rigidity(&self) -> f64 {
let d = (self.core_thickness + self.face_thickness) / 2.0;
self.face_e * self.face_thickness * d * d / (1.0 - self.face_nu * self.face_nu)
}
pub fn transverse_shear_stiffness(&self) -> f64 {
self.core_g * self.core_thickness
}
pub fn face_membrane_stiffness(&self) -> f64 {
self.face_e * self.face_thickness / (1.0 - self.face_nu * self.face_nu)
}
pub fn wrinkling_stress(&self, core_e: f64) -> f64 {
0.5 * (self.face_e * core_e * self.core_g).powf(1.0 / 3.0)
}
}
pub struct MindlinParams {
pub e: f64,
pub nu: f64,
pub thickness: f64,
pub shear_correction_factor: f64,
}
impl MindlinParams {
pub fn new(e: f64, nu: f64, thickness: f64, shear_correction_factor: f64) -> Self {
Self {
e,
nu,
thickness,
shear_correction_factor,
}
}
pub fn shear_stiffness(&self) -> f64 {
let g = self.e / (2.0 * (1.0 + self.nu));
self.shear_correction_factor * g * self.thickness
}
}
#[derive(Debug, Clone)]
pub struct CylindricalShellElement {
pub young_modulus: f64,
pub poisson_ratio: f64,
pub density: f64,
pub thickness: f64,
pub length: f64,
pub radius: f64,
}
impl CylindricalShellElement {
pub fn new(
young_modulus: f64,
poisson_ratio: f64,
density: f64,
thickness: f64,
length: f64,
radius: f64,
) -> Self {
Self {
young_modulus,
poisson_ratio,
density,
thickness,
length,
radius,
}
}
pub fn ring_frequency(&self) -> f64 {
let c_l = (self.young_modulus / (self.density * (1.0 - self.poisson_ratio.powi(2)))).sqrt();
c_l / self.radius
}
pub fn critical_pressure_external(&self) -> f64 {
let t = self.thickness;
let r = self.radius;
let e = self.young_modulus;
let nu = self.poisson_ratio;
2.0 * e / (1.0 - nu * nu) * (t / (2.0 * r)).powi(3)
}
pub fn hoop_stress_internal_pressure(&self, p: f64) -> f64 {
p * self.radius / self.thickness
}
pub fn axial_stress_closed_end(&self, p: f64) -> f64 {
p * self.radius / (2.0 * self.thickness)
}
pub fn axial_buckling_load(&self) -> f64 {
let e = self.young_modulus;
let nu = self.poisson_ratio;
let t = self.thickness;
let r = self.radius;
e * t / (r * (3.0 * (1.0 - nu * nu)).sqrt())
}
pub fn slenderness(&self) -> f64 {
self.length / self.radius
}
}
pub struct OrthotropicPlate {
pub e1: f64,
pub e2: f64,
pub g12: f64,
pub nu12: f64,
pub thickness: f64,
}
impl OrthotropicPlate {
pub fn new(e1: f64, e2: f64, g12: f64, nu12: f64, thickness: f64) -> Self {
Self {
e1,
e2,
g12,
nu12,
thickness,
}
}
pub fn rigidities(&self) -> (f64, f64, f64, f64) {
let h = self.thickness;
let nu21 = self.nu12 * self.e2 / self.e1;
let denom = 1.0 - self.nu12 * nu21;
let h3_12 = h * h * h / 12.0;
let dx = self.e1 * h3_12 / denom;
let dy = self.e2 * h3_12 / denom;
let dxy = self.g12 * h3_12;
let dnu = self.nu12 * dy;
(dx, dy, dxy, dnu)
}
pub fn natural_frequency_ss(&self, m: u32, n: u32, a: f64, b: f64, rho: f64) -> f64 {
let (dx, dy, dxy, dnu) = self.rigidities();
let mf = m as f64;
let nf = n as f64;
let pi2 = std::f64::consts::PI * std::f64::consts::PI;
let alpha = mf / a;
let beta = nf / b;
let num = dx * alpha.powi(4)
+ 2.0 * (dnu + 2.0 * dxy) * alpha * alpha * beta * beta
+ dy * beta.powi(4);
let rho_h = rho * self.thickness;
pi2 * (num / rho_h).sqrt()
}
}
pub struct PlateParams {
pub e: f64,
pub nu: f64,
pub thickness: f64,
}
impl PlateParams {
pub fn new(e: f64, nu: f64, thickness: f64) -> Self {
Self { e, nu, thickness }
}
pub fn flexural_rigidity(&self) -> f64 {
let h = self.thickness;
self.e * h * h * h / (12.0 * (1.0 - self.nu * self.nu))
}
pub fn bending_stiffness_matrix(&self) -> [[f64; 3]; 3] {
let d = self.flexural_rigidity();
let nu = self.nu;
[
[d, d * nu, 0.0],
[d * nu, d, 0.0],
[0.0, 0.0, d * (1.0 - nu) / 2.0],
]
}
}
#[derive(Debug, Clone)]
pub struct PlyLayer {
pub e1: f64,
pub e2: f64,
pub g12: f64,
pub nu12: f64,
pub thickness: f64,
}
impl PlyLayer {
pub fn new(e1: f64, e2: f64, g12: f64, nu12: f64, thickness: f64) -> Self {
Self {
e1,
e2,
g12,
nu12,
thickness,
}
}
pub fn q_matrix(&self) -> [[f64; 3]; 3] {
let nu21 = self.nu12 * self.e2 / self.e1;
let denom = 1.0 - self.nu12 * nu21;
let q11 = self.e1 / denom;
let q22 = self.e2 / denom;
let q12 = self.nu12 * self.e2 / denom;
let q66 = self.g12;
[[q11, q12, 0.0], [q12, q22, 0.0], [0.0, 0.0, q66]]
}
pub fn q_matrix_global(&self, theta: f64) -> [[f64; 3]; 3] {
let q = self.q_matrix();
let c = theta.cos();
let s = theta.sin();
let c2 = c * c;
let s2 = s * s;
let c4 = c2 * c2;
let s4 = s2 * s2;
let c2s2 = c2 * s2;
let q11 = q[0][0];
let q22 = q[1][1];
let q12 = q[0][1];
let q66 = q[2][2];
[
[
q11 * c4 + 2.0 * (q12 + 2.0 * q66) * c2s2 + q22 * s4,
(q11 + q22 - 4.0 * q66) * c2s2 + q12 * (c4 + s4),
(q11 - q12 - 2.0 * q66) * s * c.powi(3) - (q22 - q12 - 2.0 * q66) * c * s.powi(3),
],
[
(q11 + q22 - 4.0 * q66) * c2s2 + q12 * (c4 + s4),
q11 * s4 + 2.0 * (q12 + 2.0 * q66) * c2s2 + q22 * c4,
(q11 - q12 - 2.0 * q66) * c * s.powi(3) - (q22 - q12 - 2.0 * q66) * s * c.powi(3),
],
[
(q11 - q12 - 2.0 * q66) * s * c.powi(3) - (q22 - q12 - 2.0 * q66) * c * s.powi(3),
(q11 - q12 - 2.0 * q66) * c * s.powi(3) - (q22 - q12 - 2.0 * q66) * s * c.powi(3),
(q11 + q22 - 2.0 * q12 - 2.0 * q66) * c2s2 + q66 * (c4 + s4),
],
]
}
}
#[derive(Debug, Clone)]
pub struct ConicalShell {
pub young_modulus: f64,
pub poisson_ratio: f64,
pub density: f64,
pub thickness: f64,
pub half_angle: f64,
pub r0: f64,
}
impl ConicalShell {
pub fn new(
young_modulus: f64,
poisson_ratio: f64,
density: f64,
thickness: f64,
half_angle: f64,
r0: f64,
) -> Self {
Self {
young_modulus,
poisson_ratio,
density,
thickness,
half_angle,
r0,
}
}
pub fn slant_length(&self, s1: f64, s2: f64) -> f64 {
(s2 - s1).abs()
}
pub fn mean_radius_at(&self, s: f64) -> f64 {
self.r0 + s * self.half_angle.sin()
}
pub fn meridional_stress_pressure(&self, p: f64, s: f64) -> f64 {
let r = self.mean_radius_at(s);
p * r / (2.0 * self.thickness * self.half_angle.cos())
}
pub fn hoop_stress_pressure(&self, p: f64, s: f64) -> f64 {
let r = self.mean_radius_at(s);
p * r / (self.thickness * self.half_angle.cos())
}
}