1use serde::Serialize;
39
40use crate::material::{Density, Material};
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
44#[serde(rename_all = "snake_case")]
45pub enum Basis {
46 Published,
48 Derived,
50 Maximum,
52 Vendor,
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
58pub struct BuiltinMaterial {
59 pub id: &'static str,
61 pub name: &'static str,
63 pub density: Density,
65 pub source: &'static str,
67 pub url: &'static str,
69 pub basis: Basis,
71}
72
73impl BuiltinMaterial {
74 pub fn material(&self) -> Material {
76 Material {
77 name: self.name.to_owned(),
78 density: self.density,
79 }
80 }
81}
82
83const fn wood(g12: f64) -> Density {
85 Density::Bulk {
86 kg_m3: 1000.0 * g12 * 1.12,
87 }
88}
89
90const fn bulk(kg_m3: f64) -> Density {
91 Density::Bulk { kg_m3 }
92}
93
94const fn surface(kg_m2: f64) -> Density {
95 Density::Surface { kg_m2 }
96}
97
98const fn line(kg_m: f64) -> Density {
99 Density::Line { kg_m }
100}
101
102const WOOD_HANDBOOK: &str = "https://www.fpl.fs.usda.gov/documnts/fplgtr/fpl_gtr190.pdf";
103const WOOD_TABLE: &str =
104 "Forest Products Laboratory, Wood Handbook, FPL-GTR-190 (2010), Table 5-3a";
105
106pub const BUILTIN: &[BuiltinMaterial] = &[
108 BuiltinMaterial {
110 id: "cardboard",
111 name: "Cardboard (spiral kraft tube)",
112 density: bulk(790.0),
113 source: "LOC Precision cardboard airframe weights and sizes (3.0 x 3.1 x 34 in, 7.8 oz; 5.38 x 5.54 x 24 in, 15 oz; 5.38 x 5.54 x 34 in, 20.4 oz): 828, 788, 756 kg/m3, mean",
114 url: "https://locprecision.com/products.json",
115 basis: Basis::Derived,
116 },
117 BuiltinMaterial {
118 id: "kraft_phenolic",
119 name: "Kraft phenolic tube",
120 density: bulk(950.0),
121 source: "Public Missiles phenolic tubing weight table, PT-1.1 to PT-7.5 (909 to 974 kg/m3), as published in LOC Precision's product data",
122 url: "https://locprecision.com/products.json",
123 basis: Basis::Derived,
124 },
125 BuiltinMaterial {
126 id: "blue_tube",
127 name: "Blue Tube 2.0 (vulcanized fibre)",
128 density: bulk(1250.0),
129 source: "Always Ready Rocketry, BTRSData.zip, MATERIAL.CSV: Vulcanized Fiber, 1.25 g/cm3",
130 url: "http://alwaysreadyrocketry.com/Downloads/BTRSData.zip",
131 basis: Basis::Published,
132 },
133 BuiltinMaterial {
134 id: "quantum_tube",
135 name: "Quantum tube",
136 density: bulk(1090.0),
137 source: "Public Missiles Quantum Airframe Tubing weight table, QT-2.1 to QT-3.9 (1051 to 1173 kg/m3, walls approximate), mean, as published in LOC Precision's product data",
138 url: "https://locprecision.com/products.json",
139 basis: Basis::Derived,
140 },
141 BuiltinMaterial {
143 id: "fiberglass_g10",
144 name: "Fiberglass laminate (G10/FR-4)",
145 density: bulk(1800.0),
146 source: "Norplex-Micarta NP130 (NEMA LI 1 grade FR-4) data sheet, 2022, p. 1: specific gravity (ASTM D792) 1.80",
147 url: "https://www.norplex-micarta.com/",
148 basis: Basis::Published,
149 },
150 BuiltinMaterial {
151 id: "fiberglass_filament_wound",
152 name: "Filament-wound E-glass/epoxy (G12)",
153 density: bulk(1990.0),
154 source: "Comptec Inc., filament wound technical data: density 0.072 lb/in3; consistent with MIL-HDBK-17 rule of mixtures at 59% fibre (E-glass 2.54 g/cm3)",
155 url: "https://comptecinc.com/filament-wound-technical-data/",
156 basis: Basis::Published,
157 },
158 BuiltinMaterial {
159 id: "carbon_fiber",
160 name: "Carbon fibre/epoxy laminate",
161 density: bulk(1580.0),
162 source: "Hexcel HexPly 8552 product data sheet (AS4 unidirectional, 57.4% fibre volume): nominal laminate density 1.58 g/cm3",
163 url: "https://www.hexcel.com/",
164 basis: Basis::Published,
165 },
166 BuiltinMaterial {
168 id: "aluminum_6061",
169 name: "Aluminium 6061",
170 density: bulk(2700.0),
171 source: "Kaiser Aluminum, 6061 Sheet, Coil and Plate data sheet, rev. 05/06: 2.70 Mg/m3",
172 url: "https://online.kaiseraluminum.com/depot/PublicProductInformation/Document/1015/Kaiser_Aluminum_6061_Sheet_Coil_and_Plate.pdf",
173 basis: Basis::Published,
174 },
175 BuiltinMaterial {
176 id: "aluminum_7075",
177 name: "Aluminium 7075",
178 density: bulk(2800.0),
179 source: "Kaiser Aluminum, 7075 Sheet, Coil and Plate data sheet, rev. 05/06: 2.80 Mg/m3",
180 url: "https://online.kaiseraluminum.com/depot/PublicProductInformation/Document/1017/Kaiser_Aluminum_7075_Sheet_Coil_and_Plate.pdf",
181 basis: Basis::Published,
182 },
183 BuiltinMaterial {
184 id: "steel",
185 name: "Steel (plain carbon)",
186 density: bulk(7850.0),
187 source: "MIL-HDBK-5J (2003), Table 2.2.1.0(b), AISI 1025, p. 2-8: 0.284 lb/in3 (7847 to 7875 kg/m3 at the printed rounding)",
188 url: "https://everyspec.com/MIL-HDBK/MIL-HDBK-0001-0099/download.php?spec=MIL_HDBK_5J.139.pdf",
189 basis: Basis::Published,
190 },
191 BuiltinMaterial {
192 id: "titanium_6al4v",
193 name: "Titanium Ti-6Al-4V",
194 density: bulk(4430.0),
195 source: "TIMET, TIMETAL 6-4 properties, p. 1: 0.160 lb/in3 (4.43 g/cm3)",
196 url: "https://www.timet.com/assets/local/documents/technicalmanuals/TIMETAL_6-4_Properties.pdf",
197 basis: Basis::Published,
198 },
199 BuiltinMaterial {
200 id: "brass",
201 name: "Brass (C36000)",
202 density: bulk(8500.0),
203 source: "Copper Development Association, alloy C36000: specific gravity 8.5",
204 url: "https://alloys.copper.org/alloy/C36000",
205 basis: Basis::Published,
206 },
207 BuiltinMaterial {
209 id: "balsa",
210 name: "Balsa",
211 density: bulk(180.0),
212 source: "Forest Products Laboratory, Wood Handbook, FPL-GTR-190 (2010), p. 2-21: about 180 kg/m3 when dry, often as little as 100",
213 url: WOOD_HANDBOOK,
214 basis: Basis::Published,
215 },
216 BuiltinMaterial {
217 id: "basswood",
218 name: "Basswood (American)",
219 density: wood(0.37),
220 source: WOOD_TABLE,
221 url: WOOD_HANDBOOK,
222 basis: Basis::Derived,
223 },
224 BuiltinMaterial {
225 id: "birch",
226 name: "Birch (yellow)",
227 density: wood(0.62),
228 source: WOOD_TABLE,
229 url: WOOD_HANDBOOK,
230 basis: Basis::Derived,
231 },
232 BuiltinMaterial {
233 id: "spruce",
234 name: "Spruce (Sitka)",
235 density: wood(0.40),
236 source: WOOD_TABLE,
237 url: WOOD_HANDBOOK,
238 basis: Basis::Derived,
239 },
240 BuiltinMaterial {
241 id: "pine",
242 name: "Pine (eastern white)",
243 density: wood(0.35),
244 source: WOOD_TABLE,
245 url: WOOD_HANDBOOK,
246 basis: Basis::Derived,
247 },
248 BuiltinMaterial {
249 id: "maple",
250 name: "Maple (sugar)",
251 density: wood(0.63),
252 source: WOOD_TABLE,
253 url: WOOD_HANDBOOK,
254 basis: Basis::Derived,
255 },
256 BuiltinMaterial {
257 id: "oak",
258 name: "Oak (northern red)",
259 density: wood(0.63),
260 source: WOOD_TABLE,
261 url: WOOD_HANDBOOK,
262 basis: Basis::Derived,
263 },
264 BuiltinMaterial {
265 id: "birch_plywood",
266 name: "Birch plywood",
267 density: bulk(680.0),
268 source: "Riga Wood, Plywood Handbook (2022), section 3.2, p. 62: birch plywood density (EN 323, 20 C and 65% RH), 680 kg/m3 +-50",
269 url: "https://www.finieris.com/wp-content/uploads/2024/04/Riga-Wood_Plywood-Handbook_2022-1.pdf",
270 basis: Basis::Published,
271 },
272 BuiltinMaterial {
274 id: "pla",
275 name: "PLA",
276 density: bulk(1240.0),
277 source: "NatureWorks, Ingeo 4043D technical data sheet, p. 1: density 1.24 g/cc (ASTM D1505)",
278 url: "https://natureworksllc.com/getContentAsset/64260fd8-bfe0-49a4-af38-3dfdc4ef7f5c/53ffd608-340f-457b-b656-6b8cc0000bd4/TechnicalDataSheet_4043D_films.pdf?language=en",
279 basis: Basis::Published,
280 },
281 BuiltinMaterial {
282 id: "abs",
283 name: "ABS",
284 density: bulk(1040.0),
285 source: "SABIC, Cycolac MG47 technical data sheet, p. 1: density 1.04 g/cm3 (ISO 1183)",
286 url: "https://pc-api-public.sabic.com/api/v1/services/DocumentInfoService/?id=9ac7102f-8df7-e611-819b-06b69393ae39&language=en",
287 basis: Basis::Published,
288 },
289 BuiltinMaterial {
290 id: "petg",
291 name: "PETG",
292 density: bulk(1270.0),
293 source: "Eastman, Eastar 6763 technical data sheet (2021): density 1.27 g/cm3 (ISO 1183)",
294 url: "https://productcatalog.eastman.com/tds/ProdDatasheet.aspx?product=71040786&pn=eastar-6763-copolyester",
295 basis: Basis::Published,
296 },
297 BuiltinMaterial {
298 id: "nylon",
299 name: "Nylon 6/6",
300 density: bulk(1140.0),
301 source: "Celanese, Zytel 101L NC010 data sheet (2023), p. 3: density 1140 kg/m3 (ISO 1183)",
302 url: "https://quickparts.com/wp-content/uploads/2023/04/zytel%C2%AE-101l-nc010-gb.pdf",
303 basis: Basis::Published,
304 },
305 BuiltinMaterial {
306 id: "polycarbonate",
307 name: "Polycarbonate",
308 density: bulk(1200.0),
309 source: "Covestro, Makrolon 2405 ISO data sheet (2015), p. 3: density 1200 kg/m3 (ISO 1183-1)",
310 url: "https://www.okw.com/en/PC/RW_Makrolon_2405_en.pdf",
311 basis: Basis::Published,
312 },
313 BuiltinMaterial {
314 id: "acrylic",
315 name: "Acrylic (PMMA)",
316 density: bulk(1190.0),
317 source: "Roehm, ACRYLITE cast sheet physical properties (1235G, 2024), p. 6: specific gravity 1.19 (ASTM D792)",
318 url: "https://www.acrylite.co/files/content/acrylite.co/documents/product-information/ACRYLITE-cast-Physical-Properties.pdf",
319 basis: Basis::Published,
320 },
321 BuiltinMaterial {
322 id: "acetal",
323 name: "Acetal (POM, Delrin)",
324 density: bulk(1420.0),
325 source: "Delrin 100P NC010 data sheet, p. 1: density 1.42 g/cm3 (ISO 1183)",
326 url: "https://quickparts.com/wp-content/uploads/2023/05/QP-Materials-Delrin-100P-NC010.pdf",
327 basis: Basis::Published,
328 },
329 BuiltinMaterial {
330 id: "polystyrene",
331 name: "Polystyrene",
332 density: bulk(1040.0),
333 source: "AmSty, STYRON 685D product information (2015), p. 1: specific gravity 1.04 (ASTM D792)",
334 url: "https://amsty.com/images/documents/gpps/styron685d-tech-en.pdf",
335 basis: Basis::Published,
336 },
337 BuiltinMaterial {
338 id: "pvc",
339 name: "PVC (rigid)",
340 density: bulk(1400.0),
341 source: "Charlotte Pipe, PVC Schedule 40 DWV submittal, p. 5: specific gravity 1.40 (ASTM D792)",
342 url: "https://www.charlottepipe.com/uploads/documents/technical/SUB-PAC-PVC-DWV.pdf",
343 basis: Basis::Published,
344 },
345 BuiltinMaterial {
346 id: "hdpe",
347 name: "Polyethylene (HDPE)",
348 density: bulk(955.0),
349 source: "Chevron Phillips, Marlex HHM 5502BN technical data sheet (2020), p. 1: density 0.955 g/cm3 (ASTM D1505)",
350 url: "https://www.cpchem.com/sites/default/files/2020-10/TDS%20-%20Marlex%C2%AE%20HHM%205502BN%20Polyethylene.pdf",
351 basis: Basis::Published,
352 },
353 BuiltinMaterial {
354 id: "epoxy",
355 name: "Epoxy (cured laminating resin)",
356 density: bulk(1180.0),
357 source: "Gougeon Brothers, West System 105/205 technical data sheet (2014), p. 1: cured specific gravity 1.18",
358 url: "https://www.westsystem.com/app/uploads/2022/09/105_205-207-Combined.pdf",
359 basis: Basis::Published,
360 },
361 BuiltinMaterial {
362 id: "depron",
363 name: "Depron foam (3 mm)",
364 density: bulk(40.0),
365 source: "Depron insulation tiles technical data sheet (2013): foam density 40 kg/m3 at 3 mm (DIN EN ISO 845)",
366 url: "https://www.depron-daemmplatte.de/site/assets/files/1044/pdb-depron-d_mmplatte_gb_20160301.pdf",
367 basis: Basis::Published,
368 },
369 BuiltinMaterial {
370 id: "paper_bulk",
371 name: "Paper (office, bulk)",
372 density: bulk(755.0),
373 source: "HP Office paper product data sheet (2023), p. 1: 80 g/m2 (ISO 536) at 106 um (ISO 534)",
374 url: "https://hp-papers.eu/wp-content/uploads/2024/01/HP-Office-Product-Data-Sheet-EN-301023.pdf",
375 basis: Basis::Derived,
376 },
377 BuiltinMaterial {
379 id: "ripstop_nylon",
380 name: "Ripstop nylon (1.1 oz/yd2)",
381 density: surface(1.1 * 0.033_905_7),
382 source: "MIL-C-7020H (1992), Table I, p. 5, types I and Ia: 1.1 oz/yd2 maximum",
383 url: "http://www.arbitrarytechnology.com/rigging/milspecs/mil-c-7020_cloth-nylon-parachute-ripstop.pdf",
384 basis: Basis::Maximum,
385 },
386 BuiltinMaterial {
387 id: "ripstop_nylon_heavy",
388 name: "Ripstop nylon (1.6 oz/yd2)",
389 density: surface(1.6 * 0.033_905_7),
390 source: "MIL-C-7020H (1992), Table I, p. 5, types III and IIIa: 1.6 oz/yd2 maximum",
391 url: "http://www.arbitrarytechnology.com/rigging/milspecs/mil-c-7020_cloth-nylon-parachute-ripstop.pdf",
392 basis: Basis::Maximum,
393 },
394 BuiltinMaterial {
395 id: "silnylon",
396 name: "Silicone-coated nylon",
397 density: surface(0.042),
398 source: "Ripstop by the Roll, 1.1 oz silnylon listing: finished weight about 42 g/m2",
399 url: "https://ripstopbytheroll.com/products/1-1-oz-silnylon",
400 basis: Basis::Vendor,
401 },
402 BuiltinMaterial {
403 id: "mylar",
404 name: "Mylar (polyester film, 1 mil)",
405 density: surface(1390.0 * 25.4e-6),
406 source: "DuPont Teijin Films, Mylar physical-thermal properties H-37232-3 (2003), Table 1: density 1.390 g/cm3 (ASTM D1505), at 25.4 um",
407 url: "https://stenbacka.fi/wp-content/uploads/sites/3/2016/07/mylar_a_fysikaaliset_ominaisuudet.pdf",
408 basis: Basis::Derived,
409 },
410 BuiltinMaterial {
411 id: "polyethylene_film",
412 name: "Polyethylene film (LDPE, 1 mil)",
413 density: surface(925.0 * 25.4e-6),
414 source: "Dow LDPE 352E data sheet (2011): specific gravity 0.925 (ASTM D792), at 25.4 um",
415 url: "https://stavianchem.com/sites/default/files/product-specs/352E.pdf",
416 basis: Basis::Derived,
417 },
418 BuiltinMaterial {
419 id: "paper",
420 name: "Paper (office, 80 g/m2)",
421 density: surface(0.080),
422 source: "HP Office paper product data sheet (2023), p. 1: 80 g/m2 (ISO 536)",
423 url: "https://hp-papers.eu/wp-content/uploads/2024/01/HP-Office-Product-Data-Sheet-EN-301023.pdf",
424 basis: Basis::Published,
425 },
426 BuiltinMaterial {
427 id: "nomex_cloth",
428 name: "Nomex cloth (6 oz/yd2)",
429 density: surface(6.0 * 0.033_905_7),
430 source: "MIL-C-83429B (1990), Table III, p. 7: 4.7 to 6.0 oz/yd2 for the aramid cloth types; 6.0 taken",
431 url: "https://everyspec.com/MIL-SPECS/MIL-SPECS-MIL-C/download.php?spec=MIL-C-83429B.015471.PDF",
432 basis: Basis::Maximum,
433 },
434 BuiltinMaterial {
436 id: "nylon_cord_type_i",
437 name: "Nylon cord, type I (shroud line)",
438 density: line(1.488_164 / 950.0),
439 source: "MIL-C-5040H (1994), Table II, p. 6, type I: at least 950 ft/lb",
440 url: "https://everyspec.com/MIL-SPECS/MIL-SPECS-MIL-C/download.php?spec=MIL-C-5040H.031090.pdf",
441 basis: Basis::Maximum,
442 },
443 BuiltinMaterial {
444 id: "paracord_type_iii",
445 name: "Nylon cord, type III (550 paracord)",
446 density: line(1.488_164 / 225.0),
447 source: "MIL-C-5040H (1994), Table II, p. 6, type III: at least 225 ft/lb",
448 url: "https://everyspec.com/MIL-SPECS/MIL-SPECS-MIL-C/download.php?spec=MIL-C-5040H.031090.pdf",
449 basis: Basis::Maximum,
450 },
451 BuiltinMaterial {
452 id: "tubular_nylon_half_inch",
453 name: "Tubular nylon webbing, 1/2 in",
454 density: line(0.50 * 0.031_003_4),
455 source: "MIL-W-5625K (1991), Table I, p. 4: 1/2 in, 0.50 oz/yd maximum",
456 url: "https://everyspec.com/MIL-SPECS/MIL-SPECS-MIL-W/download.php?spec=MIL-W-5625K.014723.pdf",
457 basis: Basis::Maximum,
458 },
459 BuiltinMaterial {
460 id: "tubular_nylon_9_16_inch",
461 name: "Tubular nylon webbing, 9/16 in",
462 density: line(0.60 * 0.031_003_4),
463 source: "MIL-W-5625K (1991), Table I, p. 4: 9/16 in, 0.60 oz/yd maximum",
464 url: "https://everyspec.com/MIL-SPECS/MIL-SPECS-MIL-W/download.php?spec=MIL-W-5625K.014723.pdf",
465 basis: Basis::Maximum,
466 },
467 BuiltinMaterial {
468 id: "tubular_nylon_1_inch",
469 name: "Tubular nylon webbing, 1 in",
470 density: line(1.70 * 0.031_003_4),
471 source: "MIL-W-5625K (1991), Table I, p. 4: 1 in, 1.70 oz/yd maximum",
472 url: "https://everyspec.com/MIL-SPECS/MIL-SPECS-MIL-W/download.php?spec=MIL-W-5625K.014723.pdf",
473 basis: Basis::Maximum,
474 },
475 BuiltinMaterial {
476 id: "kevlar_cord_eighth_inch",
477 name: "Kevlar cord, 1/8 in",
478 density: line(1.43e-3 / 0.3048),
479 source: "Giant Leap Rocketry, Weights and Measures (2017), p. 3: 1/8 in Kevlar, 1.43 g/ft",
480 url: "https://cdn.shopify.com/s/files/1/0518/3809/1436/files/GLRWeightsMeasures_r1.pdf",
481 basis: Basis::Vendor,
482 },
483 BuiltinMaterial {
484 id: "kevlar_cord_quarter_inch",
485 name: "Kevlar cord, 1/4 in",
486 density: line(2.95e-3 / 0.3048),
487 source: "Giant Leap Rocketry, Weights and Measures (2017), p. 3: 1/4 in Kevlar, 2.95 g/ft",
488 url: "https://cdn.shopify.com/s/files/1/0518/3809/1436/files/GLRWeightsMeasures_r1.pdf",
489 basis: Basis::Vendor,
490 },
491 BuiltinMaterial {
492 id: "elastic_cord_quarter_inch",
493 name: "Elastic shock cord (bungee), 1/4 in",
494 density: line(2.4 * 0.453_592_37 / 30.48),
495 source: "MIL-C-5651D (1985), Table III, p. 16: 1/4 in, 2.4 lb/100 ft",
496 url: "https://everyspec.com/MIL-SPECS/MIL-SPECS-MIL-C/download.php?spec=MIL-C-5651D.013946.pdf",
497 basis: Basis::Published,
498 },
499 BuiltinMaterial {
500 id: "kevlar_thread",
501 name: "Kevlar thread (Tex 80)",
502 density: line(0.496_055 / 5000.0),
503 source: "A-A-55220 (1995), Table I, p. 2: Tex 80, at least 5000 yd/lb",
504 url: "https://everyspec.com/COMML_ITEM_DESC/A-A-55000_A-A-55999/download.php?spec=A-A-55220.012789.PDF",
505 basis: Basis::Maximum,
506 },
507];
508
509pub fn find(id: &str) -> Option<&'static BuiltinMaterial> {
511 BUILTIN.iter().find(|m| m.id == id)
512}
513
514#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
516pub struct BuiltinShearModulus {
517 pub id: &'static str,
519 pub shear_modulus_pa: f64,
521 pub source: &'static str,
523 pub url: &'static str,
525 pub basis: Basis,
527}
528
529const PSI_PA: f64 = 6_894.757;
531
532const fn msi(value: f64) -> f64 {
534 value * 1e6 * PSI_PA
535}
536
537const fn wood_shear(g_lt_over_e_l: f64, e_bend_mpa: f64) -> f64 {
539 g_lt_over_e_l * 1.10 * e_bend_mpa * 1e6
540}
541
542const fn isotropic_shear(e_pa: f64, poisson: f64) -> f64 {
544 e_pa / (2.0 * (1.0 + poisson))
545}
546
547const MIL_HDBK_5J: &str =
548 "https://everyspec.com/MIL-HDBK/MIL-HDBK-0001-0099/download.php?spec=MIL_HDBK_5J.139.pdf";
549
550pub const SHEAR_MODULI: &[BuiltinShearModulus] = &[
552 BuiltinShearModulus {
553 id: "aluminum_6061",
554 shear_modulus_pa: msi(3.8),
555 source: "MIL-HDBK-5J (2003), Table 3.6.2.0(b1), 6061 sheet T4 to T62, p. 3-264: \
556 G 3.8 x 10^3 ksi",
557 url: MIL_HDBK_5J,
558 basis: Basis::Published,
559 },
560 BuiltinShearModulus {
561 id: "aluminum_7075",
562 shear_modulus_pa: msi(3.9),
563 source: "MIL-HDBK-5J (2003), Table 3.7.6.0(b1), 7075-T6 sheet and T651 plate, p. 3-371: \
564 G 3.9 x 10^3 ksi",
565 url: MIL_HDBK_5J,
566 basis: Basis::Published,
567 },
568 BuiltinShearModulus {
569 id: "steel",
570 shear_modulus_pa: msi(11.0),
571 source: "MIL-HDBK-5J (2003), Table 2.2.1.0(b), AISI 1025, p. 2-8: G 11.0 x 10^3 ksi",
572 url: MIL_HDBK_5J,
573 basis: Basis::Published,
574 },
575 BuiltinShearModulus {
576 id: "titanium_6al4v",
577 shear_modulus_pa: msi(6.2),
578 source: "MIL-HDBK-5J (2003), Table 5.4.1.0(b), Ti-6Al-4V annealed, p. 5-53: G 6.2 x 10^3 \
579 ksi; TIMET's TIMETAL 6-4 properties (p. 15) give 6.2 and 6.66 x 10^6 psi",
580 url: MIL_HDBK_5J,
581 basis: Basis::Published,
582 },
583 BuiltinShearModulus {
584 id: "carbon_fiber",
585 shear_modulus_pa: msi(0.70),
586 source: "NCAMP NCP-RP-2010-008 Rev D (2011), Hexcel 8552 AS4 unitape, Table 3-3, p. 37: \
587 in-plane shear modulus G12 0.70 Msi, room temperature dry",
588 url: "https://www.wichita.edu/industry_and_defense/NIAR/Research/hexcel-8552/AS4-Unitape-3.pdf",
589 basis: Basis::Published,
590 },
591 BuiltinShearModulus {
592 id: "balsa",
593 shear_modulus_pa: wood_shear(0.037, 3_400.0),
594 source: concat!(
595 "Forest Products Laboratory, Wood Handbook, FPL-GTR-190 (2010), Table 5-1, p. 5-2 ",
596 "(G_LT/E_L 0.037) and Table 5-5a, p. 5-18 (modulus of elasticity 3,400 MPa at 12%)"
597 ),
598 url: WOOD_HANDBOOK,
599 basis: Basis::Derived,
600 },
601 BuiltinShearModulus {
602 id: "basswood",
603 shear_modulus_pa: wood_shear(0.046, 10_100.0),
604 source: concat!(
605 "Forest Products Laboratory, Wood Handbook, FPL-GTR-190 (2010), Table 5-1, p. 5-2 ",
606 "(G_LT/E_L 0.046) and Table 5-3a, p. 5-4 (modulus of elasticity 10,100 MPa at 12%)"
607 ),
608 url: WOOD_HANDBOOK,
609 basis: Basis::Derived,
610 },
611 BuiltinShearModulus {
612 id: "birch",
613 shear_modulus_pa: wood_shear(0.068, 13_900.0),
614 source: concat!(
615 "Forest Products Laboratory, Wood Handbook, FPL-GTR-190 (2010), Table 5-1, p. 5-2 ",
616 "(G_LT/E_L 0.068) and Table 5-3a, p. 5-4 (modulus of elasticity 13,900 MPa at 12%)"
617 ),
618 url: WOOD_HANDBOOK,
619 basis: Basis::Derived,
620 },
621 BuiltinShearModulus {
622 id: "spruce",
623 shear_modulus_pa: wood_shear(0.061, 10_800.0),
624 source: concat!(
625 "Forest Products Laboratory, Wood Handbook, FPL-GTR-190 (2010), Table 5-1, p. 5-2 ",
626 "(G_LT/E_L 0.061) and Table 5-3a, p. 5-8 (modulus of elasticity 10,800 MPa at 12%)"
627 ),
628 url: WOOD_HANDBOOK,
629 basis: Basis::Derived,
630 },
631 BuiltinShearModulus {
632 id: "maple",
633 shear_modulus_pa: wood_shear(0.063, 12_600.0),
634 source: concat!(
635 "Forest Products Laboratory, Wood Handbook, FPL-GTR-190 (2010), Table 5-1, p. 5-2 ",
636 "(G_LT/E_L 0.063) and Table 5-3a, p. 5-5 (modulus of elasticity 12,600 MPa at 12%)"
637 ),
638 url: WOOD_HANDBOOK,
639 basis: Basis::Derived,
640 },
641 BuiltinShearModulus {
642 id: "oak",
643 shear_modulus_pa: wood_shear(0.081, 12_500.0),
644 source: concat!(
645 "Forest Products Laboratory, Wood Handbook, FPL-GTR-190 (2010), Table 5-1, p. 5-2 ",
646 "(red oak, G_LT/E_L 0.081) and Table 5-3a, p. 5-5 (northern red, modulus of ",
647 "elasticity 12,500 MPa at 12%)"
648 ),
649 url: WOOD_HANDBOOK,
650 basis: Basis::Derived,
651 },
652 BuiltinShearModulus {
653 id: "birch_plywood",
654 shear_modulus_pa: 750e6,
655 source: "Riga Wood, Plywood Handbook (2022), Table 4.11, p. 89: mean modulus of rigidity \
656 in panel shear (EN 789) 750 N/mm2, every thickness, both directions",
657 url: "https://www.finieris.com/wp-content/uploads/2024/04/Riga-Wood_Plywood-Handbook_2022-1.pdf",
658 basis: Basis::Published,
659 },
660 BuiltinShearModulus {
661 id: "nylon",
662 shear_modulus_pa: isotropic_shear(1_400e6, 0.43),
663 source: "Celanese, Zytel 101L NC010 data sheet (2023): conditioned tensile modulus \
664 1400 MPa (p. 1) and Poisson's ratio 0.43 (p. 2)",
665 url: "https://quickparts.com/wp-content/uploads/2023/04/zytel%C2%AE-101l-nc010-gb.pdf",
666 basis: Basis::Derived,
667 },
668 BuiltinShearModulus {
669 id: "acetal",
670 shear_modulus_pa: isotropic_shear(421_000.0 * PSI_PA, 0.37),
671 source: "Delrin 100P NC010 data sheet: tensile modulus 421000 psi (p. 1) and Poisson's \
672 ratio 0.37 (p. 2)",
673 url: "https://quickparts.com/wp-content/uploads/2023/05/QP-Materials-Delrin-100P-NC010.pdf",
674 basis: Basis::Derived,
675 },
676];
677
678pub fn shear_modulus(id: &str) -> Option<&'static BuiltinShearModulus> {
680 SHEAR_MODULI.iter().find(|m| m.id == id)
681}
682
683pub fn shear_modulus_of(material: &Material) -> Option<&'static BuiltinShearModulus> {
686 let builtin = BUILTIN
687 .iter()
688 .find(|m| m.name == material.name && m.density == material.density)?;
689 shear_modulus(builtin.id)
690}
691
692#[cfg(test)]
693mod tests {
694 use std::collections::BTreeSet;
695
696 use super::*;
697
698 #[test]
699 fn every_entry_has_a_unique_id_a_source_and_a_positive_density() {
700 let mut ids = BTreeSet::new();
701 for m in BUILTIN {
702 assert!(ids.insert(m.id), "duplicate id {}", m.id);
703 assert!(
704 m.id.bytes()
705 .all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'_'),
706 "{}",
707 m.id
708 );
709 assert!(!m.name.is_empty() && m.source.len() > 20, "{}", m.id);
710 assert!(m.url.starts_with("http"), "{}", m.id);
711 let value = match m.density {
712 Density::Bulk { kg_m3 } => kg_m3,
713 Density::Surface { kg_m2 } => kg_m2,
714 Density::Line { kg_m } => kg_m,
715 };
716 assert!(value.is_finite() && value > 0.0, "{}", m.id);
717 }
718 assert_eq!(BUILTIN.len(), 49);
719 }
720
721 #[test]
722 fn conversions_reproduce_the_sources() {
723 let kg_m3 = |id: &str| find(id).unwrap().material().bulk_kg_m3("test").unwrap();
724 let kg_m2 = |id: &str| find(id).unwrap().material().surface_kg_m2("test").unwrap();
725 let kg_m = |id: &str| find(id).unwrap().material().line_kg_m("test").unwrap();
726 let Density::Bulk { kg_m3: ash } = wood(0.605) else {
728 unreachable!()
729 };
730 assert_eq!(ash.round(), 678.0);
731 assert!((kg_m3("basswood") - 414.4).abs() < 1e-9);
732 assert!((kg_m3("spruce") - 448.0).abs() < 1e-9);
733 assert!((kg_m2("ripstop_nylon") - 0.037_296).abs() < 1e-6);
736 assert!((kg_m("paracord_type_iii") - 0.006_614).abs() < 1e-6);
737 assert!((kg_m("kevlar_cord_quarter_inch") - 0.009_678).abs() < 1e-6);
738 assert!((kg_m("elastic_cord_quarter_inch") - 0.035_72).abs() < 1e-5);
739 assert!((kg_m2("mylar") - 0.035_306).abs() < 1e-6);
740 assert!(find("unobtainium").is_none());
741 }
742
743 #[test]
744 fn every_shear_modulus_belongs_to_a_bulk_material_and_has_a_source() {
745 let mut ids = BTreeSet::new();
746 for m in SHEAR_MODULI {
747 assert!(ids.insert(m.id), "duplicate id {}", m.id);
748 let material = find(m.id).unwrap_or_else(|| panic!("no material {}", m.id));
749 assert!(matches!(material.density, Density::Bulk { .. }), "{}", m.id);
750 assert!(m.source.len() > 20 && m.url.starts_with("http"), "{}", m.id);
751 assert!(
752 m.shear_modulus_pa.is_finite() && m.shear_modulus_pa > 0.0,
753 "{}",
754 m.id
755 );
756 }
757 assert_eq!(SHEAR_MODULI.len(), 14);
758 for none in ["fiberglass_g10", "pine", "polycarbonate"] {
759 assert!(shear_modulus(none).is_none(), "{none}");
760 }
761 let plywood = find("birch_plywood").unwrap().material();
763 assert_eq!(shear_modulus_of(&plywood).unwrap().id, "birch_plywood");
764 assert!(shear_modulus_of(&Material::bulk("Birch plywood (mine)", 680.0)).is_none());
765 assert!(shear_modulus_of(&Material::bulk("Birch plywood", 500.0)).is_none());
766 let names: BTreeSet<_> = BUILTIN.iter().map(|m| m.name).collect();
767 assert_eq!(names.len(), BUILTIN.len(), "built-in names must be unique");
768 assert!(shear_modulus_of(&find("fiberglass_g10").unwrap().material()).is_none());
769 }
770
771 #[test]
772 fn shear_moduli_reproduce_the_sources() {
773 let gpa = |id: &str| shear_modulus(id).unwrap().shear_modulus_pa / 1e9;
774 assert!((gpa("aluminum_6061") - 26.200_077).abs() < 1e-6);
776 assert!((gpa("aluminum_7075") - 26.889_552).abs() < 1e-6);
777 assert!((gpa("steel") - 75.842_327).abs() < 1e-6);
778 assert!((gpa("titanium_6al4v") - 42.747_493).abs() < 1e-6);
779 assert!((gpa("carbon_fiber") - 4.826_330).abs() < 1e-6);
780 assert!((gpa("basswood") - 0.511_06).abs() < 1e-9);
782 assert!((gpa("balsa") - 0.138_38).abs() < 1e-9);
783 assert!((gpa("nylon") - 0.489_510).abs() < 1e-6);
785 assert!((gpa("acetal") - 1.059_377).abs() < 1e-6);
786 assert!((gpa("birch_plywood") - 0.75).abs() < 1e-12);
787 }
788}