# Impakt -- Project Status

**Date:** 2026-04-10
**Version:** 0.1.0
**Tests:** 181 passing
**Source:** ~11,000 lines (py+js+css+html) | ~2,150 lines tests
**Tooling:** uv (Python 3.12.12), hatchling build backend

---

## Quick Start

```bash
cd /Users/noise/Code/impakt
uv sync --dev          # install all dependencies
uv run pytest tests/   # run all 181 tests
uv run impakt info tests/mme_data/3239         # show test metadata
uv run impakt serve tests/mme_data/3239        # launch web UI on :8050
```

Scripting:
```python
from impakt import Session
s = Session.open("tests/mme_data/3239")
s.plot("11HEAD0000H3ACXP", "11HEAD0000H3ACYP", "11HEAD0000H3ACZP", cfc=1000)
```

---

## Repository Layout

```
impakt/
  pyproject.toml                # PEP 621 + uv dependency-groups
  uv.lock                      # lockfile
  .gitignore
  README.md                    # Architecture docs with 16 Mermaid diagrams
  BRAINSTORM.md                # 80+ feature ideas
  docs/
    STATUS.md                  # <-- you are here
  src/impakt/
    __init__.py                # exports Session, Template
    channel/                   # Data model layer
      code.py                  #   ISO channel code parser (14-char + 16-char auto-detect)
      model.py                 #   Channel, ChannelGroup, TestData, TestMetadata
      group.py                 #   Auto-grouping utilities
      lookup.py                #   ISO naming lookup tables (150+ entries)
    io/                        # I/O layer
      reader.py                #   ReaderProtocol, ReaderRegistry
      mme.py                   #   MMEReader (real ISO 13499 + synthetic INI)
    transform/                 # Signal processing
      base.py                  #   Transform protocol, TransformChain
      cfc.py                   #   SAE J211 CFC filter (60/180/600/1000)
      align.py                 #   X-align (time-zero), Y-align (offset)
      resultant.py             #   Vector magnitude from X/Y/Z
      math_expr.py             #   Free-form math expressions
      resample.py              #   Trim, Resample
    criteria/                  # Injury criteria
      base.py                  #   CriterionResult, InjuryCriterion protocol
      hic.py                   #   HIC15, HIC36
      clip3ms.py               #   3ms chest clip
      nij.py                   #   Nij (4 modes, per-dummy intercepts)
      chest.py                 #   Chest deflection, Viscous criterion
      femur.py                 #   Femur load
      tibia.py                 #   Tibia index
    protocol/                  # Rating protocols
      base.py                  #   ProtocolResult, BodyRegionScore, Color, Rating
      euro_ncap.py             #   Euro NCAP (color/points/stars, versioned)
      us_ncap.py               #   US NCAP (injury probability/stars)
      iihs.py                  #   IIHS (G/A/M/P)
    plot/                      # Visualization engine
      engine.py                #   PlotEngine (Plotly), cursor_values()
      spec.py                  #   PlotSpec, ChannelRef, Corridor, CursorValues
      cursor.py                #   Dual X-cursor logic
      export.py                #   PNG/SVG/PDF/HTML export
    template/                  # Templates & sessions
      model.py                 #   TemplateSpec, SessionState (YAML serializable)
      library.py               #   TemplateLibrary (~/.impakt/templates/)
      session.py               #   SessionManager (.impakt/ per test)
    report/                    # Report generation
      engine.py                #   PDF/HTML via WeasyPrint + Jinja2
      templates/               #   3 Jinja2 HTML templates
        plot_sheet.html
        injury_summary.html
        protocol_report.html
    web/                       # Dash web application
      app.py                   #   App factory: create_app(), serve()
      state.py                 #   AppState: multi-test state, templates, sessions, corridors
      layout.py                #   Top-level layout: Data tab + Analysis tab
      components/              #   Reusable layout components
        header.py              #     Navbar, test info panel, open/overlay modals
        channel_grid.py        #     Flat sortable DataTable with wildcard filter + facets
        channel_values.py      #     Combined cursor + statistics table (live hover values)
        transforms.py          #     CFC/align/resultant controls + per-channel overrides
        plot_grid.py           #     Multi-pane plot area (1x1, 2x1, 1x2, 2x2, 3x1)
        criteria.py            #     Auto-compute criteria, protocol scoring, results display
        corridors.py           #     Corridor upload (CSV) and management
        templates.py           #     Template library browser, save/apply/delete
        math_builder.py        #     Math expression builder with variable binding
        report.py              #     Export panel (PNG/SVG/PDF, CSV, protocol report)
      callbacks/               #   Feature-specific callback modules
        __init__.py            #     Registration hub: register_callbacks()
        channel_callbacks.py   #     Selection, filtering, badges, per-channel overrides
        plot_callbacks.py      #     Plot rendering, transform pipeline, corridor display
        cursor_callbacks.py    #     Channel values table (live hover + X1/X2)
        criteria_callbacks.py  #     Compute All button, protocol scoring
        template_callbacks.py  #     Apply/save/delete templates, session auto-save
        corridor_callbacks.py  #     CSV upload, corridor state management
        math_callbacks.py      #     Expression evaluation, derived channel injection
        file_callbacks.py      #     Open test / add overlay modals
        export_callbacks.py    #     CSV export, report generation
      assets/                  #   Browser-side static files
        style.css              #     Custom CSS (compact layout, splitter, scrollbars)
        splitter.js            #     Draggable panel splitter (pure JS, no deps)
        cursor_tracker.js      #     Live cursor tracking (mousemove -> pixel-to-data-X)
    plugin/                    # Plugin system
      registry.py              #   PluginRegistry, discovery (entrypoints + dir)
    script/                    # Scripting API + CLI
      api.py                   #   Session, ChannelHandle, TransformProxy, Template
      cli.py                   #   argparse CLI (serve/info/channels/evaluate)
  tests/
    conftest.py                # Synthetic channel fixtures
    test_integration.py        # Full pipeline against synthetic MME fixture
    test_real_mme.py           # 46 tests against 5 real ISO 13499 datasets
    test_channel/              # ChannelCode parser, Channel model, TestData
    test_criteria/             # HIC, Nij
    test_io/                   # MMEReader
    test_protocol/             # Euro NCAP scoring
    test_transform/            # CFC filter, alignment
    test_web/                  # AppState, app creation, channel grid, channel values, P2 features
    fixtures/
      generate_mme.py          # Synthetic MME generator (26 channels, half-sine)
      sample_mme/              # Generated synthetic test data
    mme_data/                  # REAL ISO 13499 test data (5 datasets)
      3239/                    #   NHTSA/Calspan, VW Passat frontal, 133 channels
      AK3T02FO/                #   BASt, frontal 40% offset, 97 channels
      AK3T02SI/                #   BASt, side impact, 97 channels
      VW1FGS15/                #   Volkswagen, pedestrian headform, 10 channels
      98_7707/                 #   UTAC, vehicle-to-vehicle (metadata only)
      *.pdf, *.doc             #   ISO/TS 13499 reference documents
```

---

## What Works

### All modules fully implemented and tested:

| Module | Status | Notes |
|---|---|---|
| **Channel code parser** | Complete | Auto-detects 14-char (no dummy) vs 16-char (with dummy H3/P3/PC). |
| **Channel model** | Complete | Immutable channels, auto-grouping X/Y/Z, resultant computation. |
| **MME reader** | Complete | Real ISO 13499 (.mme + .chn index + .NNN data files) + simplified INI. Tested against 5 real datasets. |
| **CFC filtering** | Complete | SAE J211 compliant. 4th-order Butterworth, zero-phase. All 4 CFC classes. |
| **Alignment transforms** | Complete | X-align (manual/threshold/trigger), Y-align (baseline window). |
| **Resultant** | Complete | From ChannelGroup or arbitrary channels. |
| **Math expressions** | Complete | Safe eval with numpy functions. |
| **HIC** | Complete | HIC15/HIC36, cumulative integration, optimal window search. |
| **3ms clip** | Complete | Cumulative exceedance method. |
| **Nij** | Complete | 4 modes (NTE/NTF/NCE/NCF), per-dummy intercepts. |
| **Chest deflection** | Complete | Peak sternal displacement with unit/sanity validation. |
| **Viscous criterion** | Complete | V(t)*C(t) with chest depth per dummy type. |
| **Femur load** | Complete | Left/right, unit conversion. |
| **Tibia index** | Complete | M/Mc + F/Fc with intercepts. |
| **Euro NCAP** | Complete | Sliding-scale color/points, percentage to stars. Versioned thresholds. |
| **US NCAP** | Complete | Logistic injury risk functions, combined probability, star rating. |
| **IIHS** | Complete | G/A/M/P per body region, worst-case overall. |
| **Plot engine** | Complete | Plotly rendering, corridors, cursor values, export. |
| **Template model** | Complete | YAML serialize/deserialize, library manager, session persistence. |
| **Report engine** | Complete | HTML+WeasyPrint PDF, 3 Jinja2 templates. |
| **Plugin registry** | Complete | Entry point + directory + API discovery. |
| **CLI** | Complete | `impakt serve/info/channels/evaluate`. |
| **Web UI** | **Functional** | See details below. |

### Web UI -- Current State

Fully functional for daily crash test analysis:

**Data Tab:**
- **Left panel** (resizable via draggable splitter): channel grid + transform controls
- **Channel grid**: flat sortable DataTable (#, ISO Code, Description, Unit, Min, Max), wildcard filter bar, facet dropdowns (body region, measurement, direction), multi-select with selection persisted across filtering, selected rows colored with plot trace colors (tinted background + left border)
- **Transform controls**: global CFC filter, Y-align, X-align (manual/threshold), resultant toggle, per-channel CFC overrides
- **Plot area** (fills remaining width): no legend (info in tables), tight margins, compact axis labels, X1/X2 vertical reference lines
- **Channel Values table** (directly below plot, minimal gap): combined statistics + cursor in one table. Columns: #, ISO Code, Description, Unit, Min, @Time, Max, @Time, X1, X2, Cursor. `table-layout: fixed` with percentage widths — Description fills remaining space. Rows colored with same plot trace colors. Cursor column updates live on mouse hover via custom JS tracker.

**Analysis Tab:**
- **Injury Criteria**: auto-detect channels by ISO naming, compute HIC15/3ms clip/Nij/chest defl/femur/tibia, protocol scoring (Euro NCAP/US NCAP/IIHS) with color-coded results and star ratings
- **Math Expression Builder**: formula input, 3 variable bindings (a/b/c mapped to channel dropdowns), result injected into test data and auto-plotted
- **Template Management**: library browser, apply (resolves channel patterns + sets CFC), save current view as template, delete, session auto-save
- **Corridors**: CSV upload (time/lower/upper), rendered as filled band on plot
- **Export**: CSV of plotted data (with transforms), PNG/SVG/PDF buttons, protocol report generation

**Consistent Color System:**
Every selected channel has a stable color index (position in selection order). The same color appears in:
- Plot traces
- Channel grid rows (tinted background + solid left border)
- Selected badges (colored dot)
- Channel Values table rows (tinted background + solid left border)

### Key design decisions:

1. **Immutable channels** -- transforms return new Channel objects; raw data never modified.
2. **`.impakt/` subfolder** -- session state stored alongside test data.
3. **Template/session split** -- templates are global recipes; sessions are per-test instances.
4. **AppState is server-side** -- numpy arrays stay in Python memory; Dash stores hold only lightweight keys.
5. **Channel keys use `test_id::channel_name`** -- enables multi-test overlay.
6. **Custom JS cursor tracking** -- bypasses Plotly's hover system with raw mousemove + pixel-to-data conversion.
7. **table-layout: fixed** on Channel Values -- percentage widths respected, Description column fills remaining space.
8. **Browser cache prevention** -- meta tags with Cache-Control: no-cache to prevent stale layout issues during development.
9. **Separate single-output callbacks** for DataTable properties -- avoids Dash KeyError when DataTable internally requests individual properties.

---

## Next Steps (Priority 3)

1. **Annotations** -- text on plots, measurement lines, highlight regions
2. **Comparison mode** -- side-by-side tests, delta plots, synced cursors
3. **Report builder** -- drag-and-drop report composer, PDF preview
4. **Keyboard shortcuts** -- Ctrl+O, Ctrl+S, 1-9 pane switch, F fullscreen, R reset zoom
5. **Consider Python/WASM frontend** -- NiceGUI or Solara for pure-Python UI (no JS)

---

## Test Data Available

| Dataset | Lab | Type | Channels | Good for testing |
|---|---|---|---|---|
| `fixtures/sample_mme/` | Synthetic | Frontal barrier | 26 | Unit tests, known values |
| `mme_data/3239/` | NHTSA/Calspan | Frontal barrier (VW Passat) | 133 | Full pipeline, real data |
| `mme_data/AK3T02FO/` | BASt | Frontal 40% offset | 97 | Multi-occupant |
| `mme_data/AK3T02SI/` | BASt | Side impact | 97 | Side impact protocols |
| `mme_data/VW1FGS15/` | Volkswagen | Pedestrian headform | 10 | Impactor codes (D0) |
| `mme_data/98_7707/` | UTAC | Vehicle-to-vehicle | 0 | Metadata-only |

---

## Dependencies

Core: numpy, scipy, plotly, dash, dash-bootstrap-components, pandas, pyyaml, jinja2, weasyprint, pydantic
Dev: pytest, pytest-cov, ruff, mypy
Optional: nptdms (for future TDMS reader plugin)

---

## Known Issues / Technical Debt

1. **VehicleInfo.year parsed as 0** for real MME data (.mme format embeds year in vehicle name string).
2. **Speed displayed as raw float** (55.900001530350906 km/h) -- should round.
3. **DataTable deprecation warning** -- Dash recommends migrating to dash-ag-grid.
4. **Cursor poll interval (80ms)** -- slight latency in cursor grid updates.
5. **Chest deflection auto-detect** skips DS channels with peak > 150mm to avoid steering column displacement.
6. **Dead files** -- `cursors.py` and `inspector.py` were replaced by `channel_values.py` and deleted; `inspector_callbacks.py` deleted. If old `.pyc` files cause issues, run `find src -name __pycache__ -type d | xargs rm -rf`.
