Portable runtime contract

The portable runtime composes the MATLAB-independent WaveVortexKernel with integration, field evaluation, observing-system adapters, and NetCDF persistence. MATLAB/MEX, NetCDF, FFTW, and Apple APIs remain outside the numerical core. The concise user workflow and compatibility comparison live under Compiled execution.

The move-only WVModel façade owns that composition, while WVModelState owns evolving canonical coefficients and explicit observer state. The façade delegates to the contracts below; it does not introduce another numerical, output, or persistence implementation. Both the standalone runner and production MEX right-hand-side path use this owner.

Source API v1

wave-vortex-portable-source-api-v1, version 1.0, is the stable source-level extension and embedding contract. Its documented surface comprises the source-API identity constants; explicit extension-catalog construction and capability lookup; the WVObservingSystem, WVOutputSchedule, and WVForcing implementation boundaries and their construction records; data-only observation schemas and batches; output-configuration compilation; the move-only WVModel façade; and runWaveVortex(). Declarations under PortableRuntime/src, legacy MATLAB-encoding adapters, detail namespaces, and public-looking declarations not documented as extension or embedding points are implementation details rather than part of this compatibility promise.

Compatibility is source-only. An application selects one WaveVortexModel checkout, compiles the runtime, its statically linked extensions, and the runner together, and recompiles all of them whenever that source selection changes. Version 1 preserves the documented source surface; an incompatible documented change requires a new source-API major version. There is no cross-compiler, cross-build, or cross-commit binary ABI, dynamic plug-in discovery, separately loadable extension module, or distributed runtime binary.

Source-API versioning is independent of persisted and scientific data contracts. Every data contract is matched exactly at its own boundary:

Boundary Independent version
MATLAB/C++ pair envelope wave-vortex-portable-pair-v1 plus the exact type identity and positive pair contract version
Portable observer graph portable-observers-v1 and its exact schema version
Output schedule Exact schedule type identity and contract version, plus exact configuration, payload-schema identity/version, and typed cursor
Observation persistence Each WVObservationSchema identifier and version, repeated exactly by its batches
Run request wave-vortex-run-request-v1 or wave-vortex-run-request-v2 and its exact schema version
Compiled numerical kernel Its own compiled-kernel contract version

Changing one of these data versions does not implicitly change or relax another and does not by itself change the C++ source-API version. Unsupported, missing, malformed, or version-mismatched records fail during construction or semantic preflight.

Barotropic QG qualification record

PortableRuntime/qualification/barotropic-qg-v1.json is the compact, machine-readable coverage record for the MATLAB–C++–MATLAB QG boundary. It identifies the writer-authored request path, grid and integration matrix, supported forcing and observer identities, output policies, transactional rejection cases, numerical limits, provider requirements, and the exact MATLAB and C++ gates that enforce them. It deliberately records no raw timing or benchmark samples.

Qualification requires compact A0 ownership throughout the state, no dummy Ap or Am families, no retained full Hermitian spectrum, exact provider identity with no fallback, and balanced native FFTW plan and planning-buffer lifetimes. Reference and native providers use the same persisted model graph. The reference end-to-end matrix compares MATLAB and C++ coefficients and fields at \(10^{-12}\) relative error or better, compares energy and enstrophy, exercises exact and dense output, restores the C++ result with WVModel.modelFromFile, and continues it in MATLAB. Native FFTW qualification adds the pinned 3.3.11 library identity and plan-cleanup proof.

WVNarrowBandGeostrophicForcing is numerically resolved by the QG fixed-amplitude implementation, but its persistence schema is intentionally wider than that numerical subset. The frozen record preserves r, k_r, k_f, j_f, u_rms, and initialPV alongside the selected compact A0 indices and values so MATLAB restoration retains the concrete forcing object and its provenance. Older source-linked records that contain only selected amplitudes remain decodable because the provenance fields are optional at the C++ source boundary; MATLAB-authored records always provide them.

The portable reference runtime and source-linked consumers are qualified on Ubuntu with GCC or Clang and on macOS with AppleClang. The locally built optimized FFTW runner is limited to Apple silicon. The WaveVortexModel portable source set does not currently compile under MSVC, so Windows source-linked runners are outside source API v1.

Integration boundaries

WVIntegrationStateLayout freezes a transform identity, its spatial dimensions, an ordered set of named coefficient families with their natural spectral ranks, and zero or more typed observer-owned blocks. This allocation-light description is resolved before state-sized storage is created. The constant-stratification adapter declares equal rank-2 Ap, Am, and A0 families and preserves the stabilized WVState views. The Barotropic QG numerical system declares one rank-1 A0[Nkl] family. Transform-neutral consumers use ordered WVCoefficientFamilyView values, so that system allocates, advances, interpolates, and checkpoints only A0; it has no dummy Ap or Am arrays and no state-sized compatibility copy.

WVIntegrationSystem owns the transform-selected right-hand-side evaluation, constraints, error scaling, and optional field-evaluation service. WVTimeIntegrator advances accepted state. WVDenseOutput evaluates state inside an accepted step from that method’s Runge–Kutta data. RK4 and adaptive RK3(2) pack exactly the coefficient elements described by the layout, and their component policy follows the declared family order before additional state blocks. Output scheduling consumes only these interfaces: adding another integrator must not add method branches to the output driver, and adding another coefficient rank or state block must not change an integrator.

The transform boundary is closed and source-linked. Selecting a transform chooses its immutable configuration, coefficient-family/rank description, numerical kernel, integration system, field service, and persistence adapter during preflight. It does not introduce dynamic discovery, a native C++ transform-authoring API, or a binary ABI. WVBarotropicQGIntegrationSystem provides a real one-family numerical implementation, including allocation-light decoding of its persisted geometry and physical parameters, resolved stable QG forcing, constraints, energy-scaled tolerances, generic RK4/RK23/RK45/RK78 integration, field evaluation, observers, output, and restart. The same generic WVModel, integrators, output driver, CLI, and run-request paths consume either resolved system without a constant-stratification side pointer, opportunistic downcast, or transform-name dispatch.

The runtime supplies classical fixed RK4 plus three adaptive methods named for their MATLAB counterparts: adaptive-rk23 uses Bogacki–Shampine with a third-order accepted solution and second-order embedded estimate, adaptive-rk45 uses Dormand–Prince with a fifth-order accepted solution and fourth-order embedded estimate, and adaptive-rk78 uses Verner’s most-efficient pair with an eighth-order accepted solution and seventh-order embedded estimate. A shared internal adaptive driver owns error-policy construction and tolerance hashing, componentwise error scaling, accepted/rejected retry, step bounds, restart preparation, constraints, diagnostics, and metrics. Each concrete method retains its own explicit tableau, controller exponent and rejection policy, safe derivative-reuse behavior, continuous-extension boundary, and compile-time workspace schedule. RK23 uses five state-equivalent stage/work buffers. RK45 uses seven and reuses its stage-2 derivative buffer for the stage-7 FSAL derivative after the former’s last use. Endpoint-only RK78 uses 11: one accepted-state/stage buffer, f1, a buffer reused for f2, f3, and f5, a buffer reused for f4 and f13, and f6 through f12. Enabling dense output retains f1 and f6 through f12 and reuses the dead f2/f3/f5 buffer for the exact accepted-step initial state without adding base workspace. The first interior request lazily allocates four method-owned buffers, computes f14 through f17, and caches them for the accepted step; later samples reuse the cache. Endpoint requests bypass this work, rejected attempts cannot expose an interpolant, and the lazy buffers are destroyed before the next step. Interpolation writes only to the caller’s nonaliasing output state, constraints are applied to that view, and the accepted integration state remains immutable. Maximum live storage is 15 state-equivalent method buffers only while the extension cache exists. No generic stage array, runtime tableau lookup, per-element method dispatch, or abstraction-owned state-sized copy is present.

All adaptive methods use componentwise scale max(absTol, relTol*max(abs(y),abs(ynew))), MATLAB’s method-specific accepted/rejected step factors, a bounded maximum step, and derivative reuse only when constraints preserve the accepted endpoint. Coefficient tolerances use the model-wide requested scale; particle, tracer, and other observing-system blocks retain their declared absolute tolerances without an additional global factor. Rejected attempts do not mutate accepted state or emit output. Interpolated output never becomes accepted state, and method-owned dense history is marked active only when the output contract requests it. Reports separate exact persistent, maximum-live workspace, dense-history, error-policy, and diagnostic storage; they also include state-equivalent counts and stage-buffer last-use records.

Observers and fields

WVExtensionCatalogBuilder is the only mutable extension-registration boundary. Its strongly typed observer, output-schedule, and forcing operations bind an exact identity and version to the corresponding typed factory contract; the runtime does not use one universal factory abstraction. The public v1 observer registration has exactly five inputs, in order: type identity, contract version, factory, optional data-only configuration resolver, and optional data-only output-plan resolver. Legacy operation callbacks and persistence metadata are private compatibility machinery and are not registration inputs. Duplicate or incomplete registration invalidates the builder, mutation after freezing fails, and the builder can freeze only once. addBuiltInExtensions() installs every built-in through the same source-linked path.

Freezing produces an immutable std::shared_ptr<const WVExtensionCatalog> with separate WVObserverCatalog, WVOutputScheduleCatalog, and WVForcingCatalog subcatalogs. The caller supplies this catalog explicitly to inspection, semantic resolution, graph compilation, descriptor construction, WVModel, MEX handles, and runner entry points. Those objects retain shared ownership for as long as resolved implementations depend on it. Destroying the builder or the caller’s original pointer therefore cannot invalidate a live runtime, and independent catalogs may coexist in one process without interference. There is no process-global mutable registry or implicit sealing event.

Raw NetCDF inspection reconstructs owning data-only records without invoking an extension factory or constructing a runtime implementation. It selects restart metadata and validates committed fixed and ragged payloads and dynamic-state availability with 4,096-element scratch, but defers coefficient and observer-state materialization until the complete output graph and destination policy pass semantic preflight. Each observer registration supplies a data-only output-plan resolver so preflight can compare the provider’s exact schema with the canonical persisted schema before constructing providers or state-sized storage. Observer descriptor construction then creates one distinct immutable resolved observer for every record, even when records share a stateless factory, and freezes a declarative execution plan on that instance. Observation persistence crosses the separate data-only WVObservationSchema/WVObservationBatch boundary: the sink, graph reader, output evaluator, output driver, and integrator do not branch on observer class or kind. The five qualified MATLAB observers use this same boundary without changing their fixed-shape NetCDF encoding.

The catalog is intentionally a native source API rather than a third-party binary plug-in ABI. A new observer can reuse the existing coefficient, full-grid field, mooring, particle, or tracer behavior without editing the runtime subsystems. A genuinely new state or output behavior first requires a new shared contract implementation, after which an observer resolves that behavior declaratively. Source-link the adapter, add it to a builder before freezing, and pass the resulting catalog explicitly into every runtime owner that needs it. The paired-implementation guide records AlongTrackSimulator as the real external catalog-composition proof.

Portable observers and forcings follow the paired MATLAB and C++ implementation contract. MATLAB remains authoritative, while the runtime accepts only an exact versioned C++ match resolved during preflight.

The forcing subcatalog maps each of the seven qualified MATLAB forcing identities and exact contract versions to a strongly typed source-linked C++ WVForcing factory. A resolved forcing owns immutable typed configuration and derived operators and is called once per forcing stage or coefficient-constraint pass, never once per mode or grid point. The frozen schedule retains MATLAB-compatible names, ordering, and persistence, while generic named-value schemas keep the NetCDF reader and writer independent of forcing classes. Duplicate, missing, version-mismatched, malformed, or unavailable entries fail during builder validation or semantic preflight before integration.

Spatial forcing implementations borrow the shared reconstructed physical fields, clear one shared spatial-tendency buffer, and project that tendency through coarse execution-context operations. Linear and quadratic bottom friction both use this path. Constant-stratification descriptors expose the bottom quadrature weight \(L_z/[2(N_z-1)]\), so portable linear drag derives \(r_\mathrm{scaled}=2(N_z-1)r\) from the persisted rate \(r\) without retaining another state-sized field or reconstructing velocity twice.

The Barotropic QG forcing implementation resolves nonlinear PV advection, adaptive damping, fixed amplitude and narrow-band fixed-amplitude records, linear and quadratic bottom friction, and beta-plane PV advection before integration. It preserves stage, priority, and original-ordinal ordering and calls only coarse QG operations. One RHS-scoped workspace record tracks reuse while all numerical arrays remain in the kernel’s bounded 4H+5R scratch; there is no forcing-owned array workspace or persistent full-Hermitian spectrum. Fixed amplitudes are restored only through the accepted-state constraint boundary, so rejected adaptive trials cannot mutate accepted compact A0. Pseudo-topographic wave generation and closures reserved for later parity work fail before FFT plans or state storage are allocated.

The #281 same-host control used the native Apple-silicon FFTW provider at 256 by 256 (j=1, antialiasing enabled), three fresh process pairs, two warmups, and seven timed nonlinear RHS evaluations per process against #280 commit e5061a6c. The median paired routing overhead was +0.020%; exact retained system storage increased by 387 bytes (0.0063%), while compact state, 4H+5R scratch, three plans, and zero persistent full-Hermitian storage were unchanged. This control measures forcing-route overhead only and is not the earlier native-versus-direct-DFT provider/oracle comparison.

WVObservingSystem::prepareOccurrence() is the coarse event boundary for event-dependent observation geometry. The immutable resolved observer receives the scheduled trigger time, schedule ordinal, a construction-resolved payload, and read-only observer state, then fills an evaluator-owned WVObserverOccurrenceWorkspace by numeric position-set and value slots. That workspace carries sample-time metadata, coordinates, logical extents, identifiers, and nested ragged relationships without mixing observation geometry into integrated observer state. Zero-length position sets and values are valid when their schema relationships remain consistent.

WVFieldEvaluationService::createEventPlan() resolves field identities, dependency masks, interpolation operations, output types, implementation calls, and position-set slots during construction. prepareEventGeometry() compiles occurrence-scoped coordinate and extent views into retry-stable interpolation geometry. evaluateEvent() samples one prepared occurrence, while evaluateEventBatch() unions compatible primitive dependencies across coincident occurrences, reconstructs them once, and retains separate interpolation for each geometry. Both paths support every portable field whose catalog metadata permits position sampling, including derived horizontal fields such as ssh, ssu, and ssv. The central service owns primitive reconstruction, derived-field evaluation, interpolation, and scratch; an observer does not request a whole field for private interpolation. These APIs use concrete resolved plans, so virtual calls occur at observer, event, field, or stage granularity rather than per sample or depth bin.

Version 1 evaluates exactly one model or dense-output state at the occurrence’s scheduled trigger time. Per-sample times may be persisted as coordinates or metadata, but they do not cause additional state interpolation within the occurrence. Multi-state occurrence sampling is explicitly deferred.

The event path crosses the data-only WVObservationSchema/WVObservationBatch boundary. An event batch carries construction-resolved variable ordinals, and its fixed, event-variable, fixed-by-variable, state-coupled, zero-length, and nested-ragged layouts are validated before output mutation. The five behavior-named providers that prove these layouts remain test-only; real ADCP, glider, profiling-float, satellite, shipboard, and additional mooring policies are not part of the runtime.

WVFieldEvaluationService also owns transform plans and bounded scratch shared by fixed observers. Particle and tracer tendencies consume the same per-RHS velocity context produced for nonlinear advection, so the runtime does not independently reconstruct or differentiate equivalent quantities. The Barotropic QG adapter resolves full-grid and periodic position-sampled u, v, eta, pi, psi, qgpv, zeta_z, and ssh, plus scalar energy and uvMax, using MATLAB-compatible linear or spline interpolation. Its XY particles and rank-2 tracers are integrated as explicit state blocks; unsupported vertical particles and rank-3 tracers fail during resolved-system construction.

Output and restart

WVOutputPlan represents explicit, evenly spaced, or source-linked algorithmic schedules independently of the integration method. It retains immutable group schedules rather than enumerating a complete future window. WVOutputScheduleContinuation is the complete per-group execution cursor; WVOutputDestinationProgress independently records the sink’s committed record count, time-last evidence, full typed cursor, and committed and physical ragged-axis offsets. WVOutputDriver owns one bounded continuation and cached occurrence per group, finds the next exact timestamp with a simple group scan, validates exact state-layout compatibility, stages failed routes for retry, and commits a proposed cursor only after its route succeeds. Its delivery-record view contains only the latest selected event, including retry attempts; cumulative history is aggregated in metrics, so retained storage does not grow with the event-window length. WVModel retains that driver across a failed delivery and synchronizes its checkpoint time to the retained accepted state, so the next call replays only the failed route. Exact coincident timestamps share one state evaluation; tolerance-based timestamp merging is not used.

Legacy evenly spaced files retain their original scalar schedule variables. A new schedule declares WVOutputSchedulePayloadSchema when it is constructed; this resolves each field’s name, finite-real/integer/Boolean type, shape, aligned byte offset, and numeric slot. WVOutputSchedulePayload then carries the occurrence values in fixed 4 KiB storage without heap allocation or named lookup. WVPortableTypedRecord remains the construction, serialization, and cursor representation, and text remains construction metadata only. State-triggered schedules remain explicitly unsupported.

WVObservationOccurrenceIdentity is separate from destination route identity. During the prepared-event lifetime it borrows the immutable resolved-observer and logical group/schedule records together with the exact typed cursor, resolved payload schema, and bounded payload. Semantic comparison is therefore allocation-free and value-exact across independently compiled or resumed plans; scalar cursor, payload, geometry, and field-plan fingerprints remain diagnostics rather than exact keys. The evaluator mints a collision-free source-owner/generation/slot token as the authoritative in-flight cache key used by the evaluator and sink. The evaluator retains the occurrence workspace, prepared geometry, evaluated fields, and batch until every destination route that consumes it succeeds. The sink tracks successful file/group commits separately, so retry neither rebuilds the occurrence nor repeats a successful route. Coincident groups share only when their complete semantic occurrence, geometry, and field-plan keys are compatible. Retained storage is bounded by immutable configuration plus currently in-flight occurrence workspaces rather than a future event sequence.

Developer-facing WVModelOutputFile and WVModelOutputGroup builders provide MATLAB-shaped output configuration without changing this runtime boundary. WVModelOutputConfiguration::build() converts and consumes the mutable builders, then calls the same authoritative WVModelOutputConfiguration::compile() entry used by restored NetCDF records. Compilation preserves the complete file, group, observer, schema, state-block, schedule, and typed-cursor records. Its immutable descriptor is the sole graph shared by the output plan, evaluator, and sink; those consumers retain references or shared descriptor ownership rather than copying a second route graph. Create, transactional replace, and compatible append are graph-wide policies implemented by the existing NetCDF sink.

WVModelOutputNetCDFSink writes MATLAB-compatible records transactionally: payload variables precede the time commit, incomplete records are rejected, and dynamic particle or tracer state is restored with the canonical coefficients. Every documented create, replace, or append factory requires the compiled output plan and runs source capability plus complete graph preflight before discovering schemas or touching a destination. Checkpoint inspection resolves and validates the transform identity before reading its configuration, coefficient ranks, or state variables; the selected adapter exposes that small description before read() allocates coefficient storage. The constant-stratification adapter preserves the legacy Ap/Am/A0 encoding, while the QG adapter writes only compact A0[t,kl]; a fields-only QG group containing an Eulerian field named A0 is not reinterpreted as coefficient restart state. Create and replace begin with empty destination progress while retaining the selected source continuation. Append validates every destination read-only, including graph and schema equality, record counts, time-last markers, exact typed schedule cursors, numeric and Boolean fill values, and committed versus physical ragged offsets; valid empty text values use the time-last and ragged-offset transaction markers as completeness evidence because NetCDF’s string fill value is also empty. Only the fully accepted set is reopened for mutation. Plans, mappings, derived operators, caches, integrator history, and scratch are never checkpoint data.

WVModel::createFromModelOutputFiles() treats the complete reconstructed sibling-file record as the model boundary. Raw inspection remains data-only; its allocation-light semantic preflight then uses the supplied catalog to resolve the dynamics mode, frozen forcing order, complete observer configurations and dependencies, declared schemas, schedule configurations and continuation cursors, destination progress, and integration layout before numerical execution. Full-model continuation uses the same descriptor for the integration system, observer evaluation, output plan, and sink. Destination remapping changes paths by stable file identifier only. The reduced coefficient-only reader remains available for the explicit legacy workflow.

The command-line mutation policy is separate from the restart mode. Coefficient-only output requires safe create or authorized replace. Complete-model requests may create or transactionally replace a complete destination set, or append to a complete compatible set. Path aliases, incompatible append graphs, and existing create destinations are rejected before integration.

NetCDF and run-request boundary

The standalone CLI consumes a MATLAB-authored NetCDF bundle plus exact wave-vortex-run-request-v1 or wave-vortex-run-request-v2 JSON. NetCDF remains the only scientific configuration and restart representation. The decoder first reads the schema identity and version, routes to a dedicated v1 or v2 decoder, and publishes one typed construction-time integration request. It is confined to the CLI and produces paths, integration settings, destination policy, and execution settings; it never constructs an observer, forcing, or output schedule. Version 1 remains unchanged and selects fixed RK4 or adaptive-rk23. Version 2 adds mutually exclusive explicit-step and CFL-selected RK4 forms and adaptive-rk23, adaptive-rk45, and adaptive-rk78; each adaptive setting may be explicit, while omitted settings resolve independently to the standard MATLAB defaults. The runner resolves the enum once before integration, and no runtime method string lookup or fallback remains in the step path. RK78 uses the same method-neutral output driver, observer evaluation, transactional retry, and restart persistence as the other methods; no RK78 branch was added to those contracts.

Validation proceeds in dependency order: strict version-specific JSON decoding, typed integration-policy validation, data-only sibling-file inspection, transform capability and catalog-backed paired implementation and forcing validation, integrator bounds, destination remapping, and immutable output-configuration compilation. Unknown fields, mixed explicit/CFL controls, adaptive controls on RK4, CFL controls on adaptive methods, invalid or nonfinite numbers, unsupported methods, and unavailable transform capabilities fail before FFT-provider construction, state-sized allocation, advancement, or destination mutation. Only after those allocation-light checks succeed may the CLI construct the FFT provider and WVModelState. Native-provider construction failure reports the source build command and performs no reference fallback. The prepared WVModelOutputConfiguration is moved into WVModel, so request handling does not retain or rebuild a second output graph. Library and test clients may call the reusable runWaveVortex(argc,argv,catalog) entry point with their own frozen catalog; the executable main constructs the built-in catalog and delegates to it.

WVModel.writePortableRunRequest is the MATLAB authoring boundary for these exact schemas. It resolves the root transform identity once and dispatches to explicit constant-stratification and Barotropic QG metadata adapters. The constant-stratification adapter preserves the established complete Ap/Am/A0 contract and deterministic output. The QG adapter validates x/y, physical scalars, j, antialiasing, model version, sibling compatibility, and compact A0 metadata. Compact QG state counts as restart state only when its output group declares WVCoefficients; an Eulerian A0 field without that observer declaration is not a checkpoint. The writer performs schema-specific option validation, reads only NetCDF metadata, root coordinates, and scalar transform configuration, preserves source order, sorts dynamic destination keys, emits release-independent UTF-8 JSON, and re-parses the staged document before a same-directory atomic replacement. It retains no cache or model-sized state and is absent from decode, preflight, provider construction, integration, and output execution. Its hidden failure-injection entry point exists only to prove that validation, encoding, temporary-file, replacement, and cleanup failures preserve an existing request byte for byte.

For v2, omission is represented rather than materialized by the MATLAB writer. The C++ decoder resolves omitted method, relative tolerance, absolute-tolerance scale, provider, and threads to adaptive-rk78, 1e-3, 1e-6, native FFTW, and bounded hardware concurrency. After model state restoration and restart preparation, the numerical system evaluates CFL 0.5 candidates for an omitted initial step and the runtime chooses their minimum, bounded by the default maximum step of one tenth of the positive continuation interval. Reports retain null requested values alongside active values, candidates, effective bounds, provider identity, and actual thread count. These are standard WVModel defaults, not recovery of unpersisted custom session settings. Explicit fields override the corresponding defaults independently, while v1 decoding, reports, errors, and the legacy positional CLI remain unchanged.

For v2 fixed-step CFL selection and adaptive default-initial-step resolution, the resolved numerical system computes its transform-specific quantities once from the restored segment-start state. Constant stratification reconstructs u, v, and w into one exact transient three-field workspace, combines effective horizontal resolution with uvMax, includes the MATLAB 3/2 dz/w restriction, and obtains the oscillatory restriction from the highest active wave frequency. Barotropic QG uses its compact field kernel for uvMax, reports no vertical or oscillatory restriction, and retains no CFL workspace. The CLI sees only method-neutral candidates, selects once, preserves the existing final partial step, and reports candidates, selection, transient maximum-live bytes, and evaluation time. The integrator and output driver do not contain transform-name branches and do not recompute CFL during stages or output.

Destination remapping is keyed by stable file identifier. Any nonempty remap is complete. Create and replace destinations cannot alias source files; append targets must already contain the same complete graph and independently compatible continuation and destination progress. NetCDF definition, transaction handling, destination progress, and payload writing remain owned by WVModelOutputNetCDFSink.

The vendored nlohmann/json header is pinned to 3.11.3 and used only by the CLI decoder. It adds no runtime binary dependency and does not enter the portable numerical library.

Extension checklist

For a new integrator:

  1. Implement WVTimeIntegrator and return an accepted-step object with method-derived dense output.
  2. Use WVIntegrationSystem for all state blocks, constraints, and error scaling.
  3. Prove rejected-step immutability and method-neutral output delivery.

For a new integrated observer:

  1. Define its immutable record and dynamic state blocks.
  2. Construct WVObserverFactoryRegistration with exactly the type identity, contract version, factory, configuration resolver, and output-plan resolver, then add it through WVExtensionCatalogBuilder before freezing.
  3. Consume shared field services rather than rebuilding transforms or derivatives.
  4. Add a test-only adapter that proves validation, evaluation, persistence, restoration, and restart continuation without another subsystem switch.

For event-dependent observation geometry:

  1. Declare the observer’s payload requirement, position sets, values, and occurrence field channels in its immutable WVObserverOutputPlan; declare the matching schedule payload schema in the schedule factory.
  2. Fill only the evaluator-owned WVObserverOccurrenceWorkspace in prepareOccurrence() using resolved slots and the single trigger-time state.
  3. Request fields through the construction-resolved event plan and assemble a data-only batch from resolved values; do not call NetCDF or perform private reconstruction or interpolation.
  4. Prove invalid payload, geometry, extent, and ragged input fails before mutation, and prove exact retry identity, compatible reuse, zero-length handling, and bounded short/long-window storage.

For a paired forcing:

  1. Keep the MATLAB forcing as the authoritative scientific implementation and return its exact versioned immutable contract.
  2. Add the MATLAB identity and version through the forcing operation on WVExtensionCatalogBuilder, with a construction-time factory, persistence schema, and coarse execution contract, before freezing the catalog.
  3. Convert the generic persistence record once into immutable typed configuration and derived operators; resolve stage, priority, tendency, constraints, and restart behavior during preflight.
  4. Prove numerical and persistence equivalence without adding class-name dispatch to the forcing engine or integrator.

For every extension, freeze the builder and pass the immutable catalog explicitly through inspection, compilation, model construction, MEX ownership, or runWaveVortex() as applicable. Prove catalog-lifetime and multi-catalog isolation in addition to numerical and persistence behavior.

For a new sink, implement guarded preflight and transactional route delivery without inspecting the integration method.

Explicit exclusions

Source API v1 does not execute arbitrary MATLAB subclasses in C++, dynamically discover extensions, provide a stable binary ABI, distribute compiled runtime or extension products, support real state-triggered schedules, or evaluate more than one model state within one observation occurrence. Variable-stratification execution, three-dimensional Barotropic QG particles or tracers, real ADCP, glider, profiling-float, satellite, shipboard, and additional mooring implementations require separately qualified contracts. Windows/MSVC source-linked builds are unsupported. These exclusions fail explicitly; the runtime does not silently fall back to MATLAB or a reduced checkpoint workflow.


This site uses Just the Docs, a documentation theme for Jekyll.