Skip to main content

phyz_format/
domain.rs

1//! Domain specifications for different physics solvers.
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Type of physics domain.
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
8#[serde(rename_all = "kebab-case")]
9pub enum DomainType {
10    /// Rigid body dynamics.
11    RigidBodyDynamics,
12    /// Convex collision detection.
13    ConvexCollision,
14    /// Material Point Method particles.
15    Mpm,
16    /// Electromagnetic FDTD.
17    Electromagnetic,
18    /// Molecular dynamics.
19    MolecularDynamics,
20    /// Quantum field theory (lattice gauge).
21    QuantumFieldTheory,
22    /// Gravitational N-body + GR.
23    Gravity,
24    /// Lattice Boltzmann Method.
25    LatticeBoltzmann,
26}
27
28/// Generic domain specification.
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct Domain {
31    /// Type of domain.
32    #[serde(rename = "type")]
33    pub domain_type: DomainType,
34
35    /// Domain-specific configuration.
36    #[serde(flatten)]
37    pub config: HashMap<String, serde_json::Value>,
38}
39
40/// Rigid body domain specification.
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct RigidBodyDomain {
43    /// Body definitions.
44    pub bodies: Vec<BodySpec>,
45    /// Joint definitions.
46    pub joints: Vec<JointSpec>,
47}
48
49/// Body specification.
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct BodySpec {
52    /// Body name.
53    pub name: String,
54    /// Mass (kg).
55    pub mass: f64,
56    /// Inertia matrix [Ixx, Iyy, Izz, Ixy, Ixz, Iyz].
57    pub inertia: [f64; 6],
58    /// Center of mass offset [x, y, z].
59    #[serde(default)]
60    pub center_of_mass: [f64; 3],
61}
62
63/// Joint specification.
64#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct JointSpec {
66    /// Joint type.
67    #[serde(rename = "type")]
68    pub joint_type: JointTypeSpec,
69    /// Parent body name.
70    pub parent: String,
71    /// Child body name.
72    pub child: String,
73    /// Joint axis (for revolute/prismatic).
74    #[serde(default)]
75    pub axis: [f64; 3],
76    /// Position of joint in parent frame.
77    #[serde(default)]
78    pub position: [f64; 3],
79    /// Orientation of joint in parent frame (quaternion [w, x, y, z]).
80    #[serde(default = "default_quaternion")]
81    pub orientation: [f64; 4],
82    /// Joint limits [lower, upper].
83    #[serde(default)]
84    pub limits: Option<[f64; 2]>,
85    /// Joint damping.
86    #[serde(default)]
87    pub damping: f64,
88}
89
90fn default_quaternion() -> [f64; 4] {
91    [1.0, 0.0, 0.0, 0.0]
92}
93
94/// Joint type specification.
95#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
96#[serde(rename_all = "lowercase")]
97pub enum JointTypeSpec {
98    /// Free 6-DOF joint.
99    Free,
100    /// Revolute (hinge) joint.
101    Revolute,
102    /// Prismatic (slider) joint.
103    Prismatic,
104    /// Spherical (ball) joint.
105    Spherical,
106    /// Fixed joint.
107    Fixed,
108}
109
110/// Collision domain specification.
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct CollisionDomain {
113    /// Collision geometries.
114    pub geometries: Vec<GeometrySpec>,
115}
116
117/// Geometry specification.
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct GeometrySpec {
120    /// Body this geometry is attached to.
121    pub body: String,
122    /// Shape type.
123    pub shape: ShapeType,
124    /// Shape-specific parameters.
125    #[serde(flatten)]
126    pub params: HashMap<String, serde_json::Value>,
127}
128
129/// Collision shape types.
130#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
131#[serde(rename_all = "lowercase")]
132pub enum ShapeType {
133    /// Box shape.
134    Box,
135    /// Sphere shape.
136    Sphere,
137    /// Capsule shape.
138    Capsule,
139    /// Cylinder shape.
140    Cylinder,
141    /// Convex mesh.
142    Mesh,
143}
144
145/// Particle domain specification.
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct ParticleDomain {
148    /// Material type.
149    pub material: String,
150    /// Number of particles.
151    pub particles: usize,
152    /// Grid resolution [nx, ny, nz].
153    pub grid_resolution: [usize; 3],
154}
155
156#[cfg(test)]
157mod tests {
158    use super::*;
159
160    #[test]
161    fn test_domain_type_serialization() {
162        let domain_type = DomainType::RigidBodyDynamics;
163        let json = serde_json::to_string(&domain_type).unwrap();
164        assert_eq!(json, "\"rigid-body-dynamics\"");
165
166        let parsed: DomainType = serde_json::from_str(&json).unwrap();
167        assert_eq!(parsed, domain_type);
168    }
169
170    #[test]
171    fn test_body_spec_serialization() {
172        let body = BodySpec {
173            name: "torso".to_string(),
174            mass: 1.0,
175            inertia: [1.0, 1.0, 1.0, 0.0, 0.0, 0.0],
176            center_of_mass: [0.0, 0.0, 0.0],
177        };
178
179        let json = serde_json::to_string(&body).unwrap();
180        let parsed: BodySpec = serde_json::from_str(&json).unwrap();
181
182        assert_eq!(parsed.name, "torso");
183        assert_eq!(parsed.mass, 1.0);
184    }
185
186    #[test]
187    fn test_joint_spec_serialization() {
188        let joint = JointSpec {
189            joint_type: JointTypeSpec::Revolute,
190            parent: "world".to_string(),
191            child: "link1".to_string(),
192            axis: [0.0, 0.0, 1.0],
193            position: [0.0, 0.0, 0.0],
194            orientation: [1.0, 0.0, 0.0, 0.0],
195            limits: Some([-3.14, 3.14]),
196            damping: 0.1,
197        };
198
199        let json = serde_json::to_string(&joint).unwrap();
200        let parsed: JointSpec = serde_json::from_str(&json).unwrap();
201
202        assert_eq!(parsed.joint_type, JointTypeSpec::Revolute);
203        assert_eq!(parsed.parent, "world");
204    }
205}