Skip to main content

oxiphysics_python/world_api/
materials.rs

1// Copyright 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3
4//! Materials Library.
5
6#![allow(missing_docs)]
7
8// ===========================================================================
9// Materials Library
10// ===========================================================================
11
12/// Classification of material behaviour.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14#[allow(dead_code)]
15pub enum MaterialClass {
16    /// Linear-elastic (Hookean) material.
17    Elastic,
18    /// Elasto-plastic material (von Mises yield criterion).
19    Plastic,
20    /// Viscous fluid material.
21    Viscous,
22}
23
24/// A material definition holding both elastic and optional plastic properties.
25#[derive(Debug, Clone)]
26#[allow(dead_code)]
27pub struct PyMaterial {
28    /// Human-readable name.
29    pub name: String,
30    /// Classification.
31    pub class: MaterialClass,
32    /// Young's modulus (Pa).
33    pub young_modulus: f64,
34    /// Poisson's ratio (dimensionless, -1 < ν < 0.5).
35    pub poisson_ratio: f64,
36    /// Mass density (kg/m^3).
37    pub density: f64,
38    /// Yield stress for plastic materials (Pa); ignored for elastic.
39    pub yield_stress: Option<f64>,
40    /// Isotropic hardening modulus (Pa); used after yield.
41    pub hardening_modulus: Option<f64>,
42    /// Dynamic viscosity (Pa·s) for viscous fluids.
43    pub viscosity: Option<f64>,
44}
45
46impl PyMaterial {
47    /// Create a generic elastic material.
48    pub fn elastic(name: &str, young: f64, poisson: f64, density: f64) -> Self {
49        Self {
50            name: name.to_owned(),
51            class: MaterialClass::Elastic,
52            young_modulus: young,
53            poisson_ratio: poisson,
54            density,
55            yield_stress: None,
56            hardening_modulus: None,
57            viscosity: None,
58        }
59    }
60
61    /// Create an elasto-plastic material.
62    pub fn plastic(
63        name: &str,
64        young: f64,
65        poisson: f64,
66        density: f64,
67        yield_stress: f64,
68        hardening: f64,
69    ) -> Self {
70        Self {
71            name: name.to_owned(),
72            class: MaterialClass::Plastic,
73            young_modulus: young,
74            poisson_ratio: poisson,
75            density,
76            yield_stress: Some(yield_stress),
77            hardening_modulus: Some(hardening),
78            viscosity: None,
79        }
80    }
81
82    /// Create a viscous fluid material.
83    pub fn viscous_fluid(name: &str, density: f64, viscosity: f64) -> Self {
84        Self {
85            name: name.to_owned(),
86            class: MaterialClass::Viscous,
87            young_modulus: 0.0,
88            poisson_ratio: 0.0,
89            density,
90            yield_stress: None,
91            hardening_modulus: None,
92            viscosity: Some(viscosity),
93        }
94    }
95
96    /// Return steel (structural carbon steel, approximate).
97    pub fn steel() -> Self {
98        Self::elastic("Steel", 200.0e9, 0.3, 7850.0)
99    }
100
101    /// Return aluminium alloy 6061.
102    pub fn aluminium() -> Self {
103        Self::elastic("Aluminium 6061", 69.0e9, 0.33, 2700.0)
104    }
105
106    /// Return natural rubber (vulcanised, approximate).
107    ///
108    /// Very low Young's modulus (~0.05 GPa) and near-incompressible (ν≈0.49).
109    pub fn rubber() -> Self {
110        Self::elastic("Natural Rubber", 0.05e9, 0.49, 920.0)
111    }
112
113    /// Return concrete (normal-weight, approximate).
114    pub fn concrete() -> Self {
115        Self::elastic("Concrete", 30.0e9, 0.2, 2400.0)
116    }
117
118    /// Return titanium alloy Ti-6Al-4V.
119    pub fn titanium() -> Self {
120        Self::elastic("Titanium Ti-6Al-4V", 114.0e9, 0.34, 4430.0)
121    }
122
123    /// Return water at 20 °C.
124    pub fn water() -> Self {
125        Self::viscous_fluid("Water (20°C)", 998.2, 1.002e-3)
126    }
127
128    /// Return air at standard conditions.
129    pub fn air() -> Self {
130        Self::viscous_fluid("Air (20°C, 1 atm)", 1.204, 1.81e-5)
131    }
132
133    /// Shear modulus G = E / (2(1 + ν)).
134    pub fn shear_modulus(&self) -> f64 {
135        self.young_modulus / (2.0 * (1.0 + self.poisson_ratio))
136    }
137
138    /// Bulk modulus K = E / (3(1 - 2ν)).
139    pub fn bulk_modulus(&self) -> f64 {
140        self.young_modulus / (3.0 * (1.0 - 2.0 * self.poisson_ratio))
141    }
142
143    /// Lamé's first parameter λ.
144    pub fn lame_lambda(&self) -> f64 {
145        let e = self.young_modulus;
146        let nu = self.poisson_ratio;
147        e * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))
148    }
149
150    /// Speed of sound (longitudinal, P-wave) in the material.
151    pub fn p_wave_speed(&self) -> f64 {
152        let k = self.bulk_modulus();
153        let g = self.shear_modulus();
154        let m_modulus = k + 4.0 / 3.0 * g;
155        if self.density > 0.0 {
156            (m_modulus / self.density).sqrt()
157        } else {
158            0.0
159        }
160    }
161}