Coordinate System & Sign Conventions¶
Every value Arxyne displays — targets, results, benchmarks — is in Arxyne coordinates. This is the single source of truth.
Arxyne coordinate system¶
| Axis | Direction | Aerodynamic meaning |
|---|---|---|
| +X | Forward | Drag opposes −X |
| +Y | Starboard (right) | Lateral forces |
| +Z | Up | Lift acts in +Z (positive = upward) |
| Origin | Vehicle centreline, ground plane |
Right-hand rule for all rotations: - Yaw about +Z: positive = turning left - Pitch about +Y: positive = nose down - Roll about +X: positive = driver-left side rises
Force sign conventions¶
| Coefficient | Definition | Positive means |
|---|---|---|
| Cd | Drag force / (q∞ × Aref) | Drag resists forward motion (always positive for a bluff body in forward flow) |
| Cl | Lift force / (q∞ × Aref) | Net upward force |
| CmPitch | Pitching moment / (q∞ × Aref × Lref) | Nose-up tendency |
All product targets in design_intent.usda (targetCd, targetCl,
targetCmPitch) are in Arxyne coordinates.
Solver sign conventions — solver responsibility¶
Solvers declare their internal coordinate convention in their manifest
(coordinate_system block). The binding layer maps solver-internal
conventions to Arxyne coordinates at the KPI level — drag sign, lift
sign, moment sign are normalised through this mapping.
If a solver reports wrong signs, the solver is broken. Arxyne does not detect or correct sign errors at runtime. The solver author owns force computation correctness. Arxyne trusts the manifest mapping.
Solvers expose their convention via MCP:
{
"coordinate_system": {
"convention": "cfd",
"mapping": {
"x": "streamwise",
"y": "spanwise",
"z": "vertical"
}
}
}
What Arxyne does NOT do¶
- No sign-flip correction factors between solvers
- No per-solver force remapping
- No
abs()on coefficients — signed values carry physical meaning - No manual validation of solver integrations
Appendix — Solver Integration Details¶
The following is reference documentation for solver authors and Arxyne maintainers. Users do not need this to run simulations.
OpenFOAM¶
Arxyne's OpenFOAM cases use ISO-aligned configuration:
dragDir (1 0 0)→ +X = forwardliftDir (0 0 1)→ +Z = uppitchAxis (0 1 0)→ +Y = lateral- Inlet
U (30 0 0)→ freestream in +X
Ground boundary condition: moving wall — fixedValue (30 0 0) on the
ground patch. Eliminates the ground boundary layer, matching wind tunnel
practice with a moving belt.
XLB (Lattice Boltzmann)¶
XLB uses an ISO-aligned lattice coordinate system:
- +X = streamwise (flow direction)
- +Y = spanwise / lateral
- +Z = vertical (up)
Forces are computed via MomentumTransfer(bc, grid) returning (Fx, Fy, Fz):
_fx = force[0] # drag (streamwise, X)
_fz = force[2] # lift (vertical, Z)
Cd = _fx / (U² × A_cross)
Cl = _fz / (U² × A_cross)
Cd formula: XLB's MomentumTransfer (Mei 2002 + Caiazzo 2008) already
accounts for the ½ dynamic-pressure factor internally. No extra ×2 in the
Cd/Cl formula — validated against Ahmed body experimental Cd=0.295 with
5.8% error (XLB Cd=0.278).
STL orientation: The solver normalises vertices (subtracts min per axis),
then shifts to grid_x/4 from the inlet. The nose (lowest raw X) sits at
x=0 in mesh coords, closest to the inlet — flow hits the nose first
regardless of authored STL direction.
Ground boundary condition: Stationary no-slip — FullwayBounceBackBC.
Moving ground BCs (RegularizedBC, EquilibriumBC) diverge on uniform
grids at automotive Re — the thin shear layer between moving floor and
stationary body underside can't be resolved without adaptive mesh refinement.
Parked until multi-res is unblocked on Blackwell GPUs.
Known Cl difference vs OpenFOAM: OF's moving ground reduces the underbody boundary layer, strengthening ground effect. XLB's stationary ground allows a boundary layer to grow under the car. Expect Cl to differ between solvers; Cd should be closer (drag is dominated by pressure on front/rear faces).
Chrono (Dynamics)¶
Chrono::Vehicle uses ISO 8855:2011 natively — no coordinate mapping needed.
Quaternion storage: GetRot() returns (e0, e1, e2, e3) mapping to
(w, x, y, z). No reordering required between Chrono and USD.
DrivAerML STL orientation¶
The DrivAerML STL authors the nose at −X. The solver normalises vertices
so the nose sits at the upstream edge of the domain — flow hits the nose
first regardless. chassis_yaw_deg is a replay/visualisation concern
(aligns the mesh in the USD viewer), not a solver concern. The platform
does not pass it to the solver.
OpenUSD / Omniverse¶
USD defaults to Y-up. Every Arxyne product stage overrides this with
upAxis = "Z" in root metadata. Right-handed throughout.
Frame reference table¶
| Frame | Up | Forward | Lateral | Notes |
|---|---|---|---|---|
| World (USD/Chrono) | +Z | +X | +Y | ISO 8855:2011. Gravity −Z. |
| OpenFOAM cases | +Z | +X | +Y | ISO-aligned via controlDict |
| XLB lattice | +Z | +X | +Y | ISO-aligned |
| Chrono body-local | +Z | +X | +Y | Native ISO |
| DrivAerML STL (raw) | +Z | −X | +Y | Normalised to +X by solver |
| Ahmed body STL | +Z | +X | +Y | Standard authoring |
| ARX Type-X STL | +Z | n/a | ±Y | Wing, no heading correction |
| Omniverse viewer | +Z | +X | +Y | Matches world |
Rotation sign conventions (all components)¶
| Rotation | Axis | Positive direction | Positive meaning |
|---|---|---|---|
| Yaw | +Z | Counter-clockwise from above | Turning left |
| Pitch | +Y | +X rotates toward −Z | Nose down |
| Roll | +X | +Y rotates toward +Z | Driver-left side rises |
Verified: +θ about +Y applied to (+1,0,0) → (cosθ, 0, −sinθ) — nose down.
Quaternion storage (all components)¶
| Producer | Order | Notes |
|---|---|---|
Chrono GetRot() |
(e0, e1, e2, e3) | Maps to (w, x, y, z) |
USD Gf.Quatd |
(real, imag) | Quatd(w, Vec3d(x, y, z)) |
xformOp:orient |
(w, x, y, z) | Stored as quatd tuple |
No reordering needed — every producer and consumer uses w-first.
chassis_yaw_deg (replay only)¶
A static Z rotation that aligns the authored STL's nose with +X forward in the replay viewer. Solver behaviour is unaffected.
| Product | Value | Why |
|---|---|---|
drivaer-notchback |
180.0 | DrivAerML nose at −X |
ahmed |
0.0 | Nose at +X already |
onera-m6 |
0.0 | Wing, no heading correction |
Applied as right-multiplication per trajectory sample:
Right-mult preserves pitch and roll signs. See
test_yaw_180_preserves_pitch_sign for the invariant test.
Camera frame¶
Camera offset is in Chrono's semantic frame: (−6, 0, 1.5) = "6 m behind,
1.5 m up". The trajectory quat carries the yaw correction, so the camera
offset is counter-rotated to keep "behind" behind.
Position offsets¶
| Offset | Source | Effect |
|---|---|---|
x_offset_m, y_offset_m |
Wheel patch axle midpoint | Shifts STL origin to axle midpoint (Chrono chassis origin) |
z_offset_m |
cgHeight + arxyne:replay:z_trim_m |
Drops mesh from CoM frame to tyre-contact |
cgHeight is the physical CoM height (drives dynamics). arxyne:replay:z_trim_m
is replay-only visual tuning — does not affect dynamics.
Invariants (tested)¶
z_trim = +araises the mesh byametres in replaycgHeight = +alowers the mesh byametres in replaychassis_yaw_degdoes not change Chrono's pitch or roll sign in replaychassis_z_offset_moverrides the auto formula- Trajectory positions stay in Chrono world frame (only orient is yaw-baked)
Glossary¶
| Term | Meaning |
|---|---|
| Authored frame | Coordinate frame the STL was exported in |
| Body-local / body-X | Chrono chassis reference frame |
| World frame | USD/Chrono world coordinates. +Z up |
| Left-mult (A·B) | Apply B first, then A. Axis of B is in A-rotated frame |
| Right-mult (A·B) | Apply B first in A's local frame. Preserves B-axis signs |