velxio/frontend/src/simulation/spice
davidmonterocrespo24 8db973675a feat(sim): Phase 1c F1 — NgSpiceNodeAdapter runs real WASM in Node tests
Loads the vendored ngspice-interactive WASM directly in the Vitest
Node process, no Web Worker required.  Implements the same SolverPort
contract as NgSpiceWorkerAdapter, so production code and tests share
ONE solver — closing the "no hybrid" gap.

loadNgSpiceForNode (Node-only loader):
- Reads ngspice-lib.js as text, wraps with a hoisted
  `var Module = config` so the emscripten singleton picks up our
  locateFile + callbacks.
- Re-wires Module.onRuntimeInitialized to copy closure-local FS /
  HEAP* into Module._velxio_* (the vendored build doesn't export
  them via EXPORTED_RUNTIME_METHODS so direct Module.FS triggers an
  abort accessor).

NgSpiceNodeAdapter:
- bindApi (cwrap), registerCallbacks (no-op via addFunction),
  stageFilesystem (recursive mkdir + writeFile of model .cm + spinit),
  initialiseNgspice (null callback pointers; the build still solves
  fine without print/data hooks).
- loadCircuit writes the netlist to /circuit.spc on the FS and
  issues `source /circuit.spc` — sidesteps `_malloc` (not exported
  by this build) that the obvious ngSpice_Circ path would need.
- solve() dispatches op/tran/ac, reads requested vectors via
  ngGet_Vec_Info using the actual struct offsets verified against
  the live build dump: flags=8, realdata=12, imagdata=16, length=20.
- alterSource issues `alter` for incremental re-solves.

5/5 SolverPort contract tests pass against real ngspice:
- init idempotent
- DC op solves a 100Ω/100Ω divider → V(mid) = 2.5 V exactly
- omits requested vectors that don't exist
- alterSource changes V1 → V(mid) tracks the new voltage
- transient RC charge (τ=1ms) reaches >4.5V after 5τ

Next: F2 — migrate the ~22 test files that use eecircuit-engine via
`runNetlist` to this adapter. After F2, F3 deletes eecircuit-engine
and `SpiceEngine.ts` for good.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 20:49:39 +02:00
..
adapters feat(sim): Phase 1c F1 — NgSpiceNodeAdapter runs real WASM in Node tests 2026-05-15 20:49:39 +02:00
models feat(sim): Phase 2.2 — vendor LM358 macro-model subckt (asset only) 2026-05-15 17:28:46 +02:00
ports feat(sim): Phase 1c A2+A3 — NgSpiceWorkerAdapter + FakeSolverAdapter 2026-05-15 19:21:46 +02:00
wasm feat(sim/spice): vendor ngspice+XSpice WASM and add NgSpiceInteractive client (Phase 1a) 2026-05-15 16:14:50 +02:00
CircuitScheduler.ts
…
CircuitSimulationService.ts feat(sim): Phase 1c D1+D2 — MCU edges drive scheduler.alterSource + republish 2026-05-15 20:26:09 +02:00
MixedModeScheduler.ts feat(sim): Phase 1c B1+B2+B3 — CircuitSimulationService (orchestrator) 2026-05-15 19:28:26 +02:00
NetlistBuilder.ts feat(sim): Phase 1c B1+B2+B3 — CircuitSimulationService (orchestrator) 2026-05-15 19:28:26 +02:00
SpiceEngine.lazy.ts
…
SpiceEngine.ts
…
boardPinGroups.ts
…
componentToSpice.ts feat(sim): Phase 2.2 — vendor LM358 macro-model subckt (asset only) 2026-05-15 17:28:46 +02:00
connectAnalogInputsToMcu.ts feat(sim): Phase 1c C1+C2 — extract ADC/waveform bridge to solver-agnostic module 2026-05-15 20:20:49 +02:00
connectLegacySolverToMixedMode.ts feat(sim): Phase 1b continued, step 4 — bridge legacy solver into MixedModeScheduler 2026-05-15 17:15:24 +02:00
connectMcuEdgesToService.ts feat(sim): Phase 1c D1+D2 — MCU edges drive scheduler.alterSource + republish 2026-05-15 20:26:09 +02:00
connectMixedModeSchedulerToStore.ts feat(sim): Phase 1c step 1 — feature-flagged WASM-driven connector 2026-05-15 18:53:36 +02:00
probes.ts
…
storeAdapter.ts
…
subscribeToStore.ts feat(sim): Phase 1c C1+C2 — extract ADC/waveform bridge to solver-agnostic module 2026-05-15 20:20:49 +02:00
types.ts feat(sim): Phase 4 — opt-in wire resistance (length_cm) 2026-05-15 18:31:28 +02:00
unionFind.ts
…
valueParser.ts
…
waveformStats.ts
…