Skip to content

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 = forward
  • liftDir (0 0 1) → +Z = up
  • pitchAxis (0 1 0) → +Y = lateral
  • Inlet U (30 0 0) → freestream in +X

Ground boundary condition: moving wallfixedValue (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:

final = chrono_quat * yaw_quat

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 = +a raises the mesh by a metres in replay
  • cgHeight = +a lowers the mesh by a metres in replay
  • chassis_yaw_deg does not change Chrono's pitch or roll sign in replay
  • chassis_z_offset_m overrides 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