|
| 1 | +--- |
| 2 | +layout: page |
| 3 | +title: Unit Tests |
| 4 | +parent_section: Developer Documentation |
| 5 | +--- |
| 6 | + |
| 7 | +# Unit Tests |
| 8 | + |
| 9 | +Unit tests verify internal correctness of HydroChrono and its integration with Project Chrono at the C++ level. They are self-contained (no external data files required) and typically run in under a second. |
| 10 | + |
| 11 | +## Running unit tests |
| 12 | + |
| 13 | +```powershell |
| 14 | +ctest -C Release -L unit --test-dir build |
| 15 | +``` |
| 16 | + |
| 17 | +Useful flags: |
| 18 | + |
| 19 | +| Flag | Description | |
| 20 | +|------|-------------| |
| 21 | +| `-V` | Verbose — show full test output (matrix dumps, signatures) | |
| 22 | +| `--output-on-failure` | Only show output when a test fails | |
| 23 | +| `-R <pattern>` | Run only tests matching a name pattern | |
| 24 | + |
| 25 | +Example with verbose output: |
| 26 | +```powershell |
| 27 | +ctest -C Release -L unit --test-dir build -V |
| 28 | +``` |
| 29 | + |
| 30 | +## Test: added-mass assembly (`test_added_mass_determinism`) |
| 31 | + |
| 32 | +Verifies that Chrono's `ChLoadHydrodynamics` correctly assembles a cross-coupled added-mass matrix for a multi-body system. |
| 33 | + |
| 34 | +### What it does |
| 35 | + |
| 36 | +1. **Constructs** a fully dense, symmetric positive-definite 18×18 added-mass matrix for 3 bodies, with non-trivial off-diagonal coupling between all body pairs and all 6 DOFs |
| 37 | +2. **Passes** the per-body 6×18 row blocks to `ChLoadHydrodynamics` (the same path HydroChrono uses at runtime) |
| 38 | +3. **Extracts** the assembled system mass matrix from Chrono, subtracts body inertia, and asserts it matches the original input |
| 39 | +4. **Runs 12 independent trials** with fresh system instances and heap perturbation between them, asserting bit-identical velocity results across all trials |
| 40 | +5. **Confirms** the added mass is actively influencing the dynamics (non-trivial velocity change after one timestep) |
| 41 | +6. **Sweeps across Chrono solver types** and reports a summary table showing which solvers correctly preserve the full added-mass matrix and produce consistent dynamics |
| 42 | + |
| 43 | +### What it catches |
| 44 | + |
| 45 | +- Incorrect scatter of added-mass blocks into the system matrix (e.g., wrong row/column placement) |
| 46 | +- Ordering sensitivity from internal container changes (e.g., `unordered_map` vs `vector`) |
| 47 | +- Non-deterministic behaviour across independent system instances |
| 48 | +- Silent corruption of off-diagonal cross-coupling terms |
| 49 | +- Solver-specific issues with added-mass handling (e.g., solvers that cannot handle stiffness/damping matrices, or iterative solvers with convergence differences) |
| 50 | + |
| 51 | +### Solver sweep |
| 52 | + |
| 53 | +The test runs the same added-mass assembly and single-step dynamics with every available Chrono solver type and prints a summary table: |
| 54 | + |
| 55 | +| Column | Meaning | |
| 56 | +|--------|---------| |
| 57 | +| Assembly | Whether the extracted added-mass matrix matches the input | |
| 58 | +| NaN/Inf | Whether velocities contain invalid values | |
| 59 | +| Dynamics | Whether post-step velocities match the SPARSE_QR reference | |
| 60 | + |
| 61 | +The solver sweep is **informational only** — it does not affect the test PASS/FAIL status. Some solvers may not support this problem type (e.g., PSOR rejects systems with stiffness/damping matrices) or may converge to slightly different results (e.g., APGD). The table makes these differences visible without false positives. |
| 62 | + |
| 63 | +### Reference results |
| 64 | + |
| 65 | +The table below summarises the results observed when the test was last run. Run the test with `-V` to regenerate it against your current Chrono build. |
| 66 | + |
| 67 | +| Solver | Assembly | NaN/Inf | Dynamics | Notes | |
| 68 | +|--------|----------|---------|----------|-------| |
| 69 | +| SPARSE_QR | MATCH | clean | MATCH | Reference solver used by HydroChrono | |
| 70 | +| SPARSE_LU | MATCH | clean | MATCH | | |
| 71 | +| MINRES | MATCH | clean | MATCH | | |
| 72 | +| GMRES | MATCH | clean | MATCH | | |
| 73 | +| BICGSTAB | MATCH | clean | MATCH | | |
| 74 | +| PSOR | ERROR | — | — | Cannot handle stiffness/damping matrices | |
| 75 | +| BARZILAIBORWEIN | MATCH | clean | MATCH | | |
| 76 | +| APGD | MATCH | clean | diff ~6.7e-3 | Assembly correct; iterative convergence differs slightly | |
| 77 | + |
| 78 | +**Key takeaways:** |
| 79 | + |
| 80 | +- **Assembly is solver-independent.** Every solver that can run produces an added-mass matrix that matches the input exactly, including all off-diagonal cross-coupling terms. Choosing a different solver does not lose structural information from the mass matrix. |
| 81 | +- **PSOR is incompatible.** `ChLoadHydrodynamics` contributes stiffness/damping matrices that PSOR cannot handle. This is a Chrono limitation, not an assembly issue. HydroChrono should never be configured to use PSOR. |
| 82 | +- **APGD assembles correctly but converges differently.** The ~6.7e-3 velocity difference is a convergence characteristic of the iterative APGD solver, not a mass-matrix problem. If tighter agreement is needed, use a direct solver. |
| 83 | +- **All other solvers (direct and iterative) produce bit-identical dynamics.** |
| 84 | + |
| 85 | +### Verbose output |
| 86 | + |
| 87 | +When run with `-V`, the test prints the input blocks, the assembled matrix extracted from Chrono, eigenvalues, post-step velocity signatures, and the solver sweep summary table — making it straightforward to visually inspect what went into the solver and what came out. |
0 commit comments