squid_n_core/section_shape/
material.rs1use super::constants::{GAMMA_CONCRETE, KAPPA_RC};
7
8pub fn concrete_young_modulus(fc: f64) -> f64 {
11 concrete_young_modulus_gamma(fc, GAMMA_CONCRETE)
12}
13
14pub fn concrete_young_modulus_gamma(fc: f64, gamma_kn_m3: f64) -> f64 {
17 if fc <= 0.0 {
18 return 0.0;
19 }
20 3.35e4 * (gamma_kn_m3 / 24.0).powi(2) * (fc / 60.0).powf(1.0 / 3.0)
21}
22
23pub fn wall_shear_shape_factor_isection(d_total: f64, dc_each: f64, bc: f64, t: f64) -> f64 {
53 if !(d_total.is_finite() && dc_each.is_finite() && bc.is_finite() && t.is_finite())
54 || d_total <= 0.0
55 || t <= 0.0
56 || bc <= 0.0
57 {
58 return KAPPA_RC;
59 }
60 let c = d_total / 2.0;
61 let dc = dc_each.clamp(0.0, c);
63 let a = c - dc; if dc <= 0.0 || bc <= t {
66 return KAPPA_RC;
67 }
68 let width = |y: f64| -> f64 {
69 if y.abs() > a {
70 bc
71 } else {
72 t
73 }
74 };
75 let area = 2.0 * dc * bc + 2.0 * a * t;
77 let i = bc * d_total.powi(3) / 12.0 - (bc - t) * (2.0 * a).powi(3) / 12.0;
78 if i <= 0.0 || area <= 0.0 {
79 return KAPPA_RC;
80 }
81 let q_of = |y: f64| -> f64 {
83 if y >= a {
84 bc * (c * c - y * y) / 2.0
86 } else {
87 bc * (c * c - a * a) / 2.0 + t * (a * a - y * y) / 2.0
88 }
89 };
90 let integrate = |lo: f64, hi: f64, n: usize| -> f64 {
93 if hi <= lo {
94 return 0.0;
95 }
96 let n = if n.is_multiple_of(2) { n } else { n + 1 };
97 let dx = (hi - lo) / n as f64;
98 let mut s = 0.0;
99 for k in 0..=n {
100 let y = lo + dx * k as f64;
101 let yy = y.clamp(lo + dx * 1e-9, hi - dx * 1e-9);
103 let v = q_of(y).powi(2) / width(yy);
104 let w = if k == 0 || k == n {
105 1.0
106 } else if k % 2 == 1 {
107 4.0
108 } else {
109 2.0
110 };
111 s += w * v;
112 }
113 s * dx / 3.0
114 };
115 let integral = 2.0 * (integrate(0.0, a, 200) + integrate(a, c, 200));
116 let kappa = area / (i * i) * integral;
117 if kappa.is_finite() && kappa >= 1.0 {
118 kappa
119 } else {
120 KAPPA_RC
121 }
122}
123
124pub fn wall_shear_shape_factor(xi: f64, eta: f64) -> f64 {
125 let xi = xi.clamp(0.0, 1.0);
126 let eta = eta.clamp(1e-6, 1.0);
127 let denom = 5.0 * (1.0 - xi.powi(3) * (1.0 - eta)).powi(2);
128 if denom <= 1e-12 {
129 return KAPPA_RC;
130 }
131 let bracket =
132 eta + xi * (1.0 - eta) * ((15.0 / 8.0) * (1.0 - xi * xi).powi(2) - xi.powi(4) * eta);
133 let k = 3.0 * (1.0 + xi) / denom * bracket;
134 if k.is_finite() && k > 0.0 {
135 k
136 } else {
137 KAPPA_RC
138 }
139}
140
141#[cfg(test)]
142mod isection_kappa_tests {
143 use super::*;
144
145 #[test]
147 fn test_kappa_uniform_rectangle_is_12() {
148 assert!((wall_shear_shape_factor_isection(4000.0, 0.0, 150.0, 150.0) - 1.2).abs() < 1e-9);
149 assert!((wall_shear_shape_factor_isection(4000.0, 600.0, 150.0, 150.0) - 1.2).abs() < 1e-9);
150 }
151
152 #[test]
155 fn test_kappa_increases_with_flange_size() {
156 let t = 150.0;
157 let k300 = wall_shear_shape_factor_isection(4000.0, 300.0, 300.0, t);
158 let k600 = wall_shear_shape_factor_isection(4000.0, 600.0, 600.0, t);
159 let k900 = wall_shear_shape_factor_isection(4000.0, 900.0, 900.0, t);
160 assert!(k300 > 1.2, "k300={}", k300);
161 assert!(k600 > k300, "k600={} k300={}", k600, k300);
162 assert!(k900 > k600, "k900={} k600={}", k900, k600);
163 }
164
165 #[test]
168 fn test_shear_area_is_between_web_and_gross() {
169 let (d, dc, bc, t) = (4000.0, 600.0, 600.0, 150.0_f64);
170 let kappa = wall_shear_shape_factor_isection(d, dc, bc, t);
171 let area = 2.0 * dc * bc + 2.0 * (d / 2.0 - dc) * t;
172 let web = 2.0 * (d / 2.0 - dc) * t;
173 let as_shear = area / kappa;
174 assert!(as_shear <= area, "As={} > A={}", as_shear, area);
175 assert!(as_shear >= web * 0.8, "As={} << Aweb={}", as_shear, web);
176 }
177
178 #[test]
180 fn test_kappa_degenerate_inputs() {
181 assert!((wall_shear_shape_factor_isection(0.0, 100.0, 300.0, 150.0) - 1.2).abs() < 1e-12);
182 assert!((wall_shear_shape_factor_isection(4000.0, 100.0, 300.0, 0.0) - 1.2).abs() < 1e-12);
183 }
184}