solprop GUI: design#

Status: the design of the front end being built, in solprop’s repository as the gui/ distribution solprop-gui (decision D2). First drafted on 2026-10-31 in a separate repository, revised the same day after the design review of section 18 (response in section 19), and on 2026-11-01 after the solprop proposals it rests on were accepted. Moved here on 2026-11-02, when those proposals had been delivered; section 21 records where what solprop delivered differs from the text, and the text has been corrected where it matters to the build. Two throwaway prototypes (NiceGUI and Qt, both around prop_capillary) preceded it; they are not kept in the repository. Planned work is in GitHub issues: a tracking issue for the front end and one issue per milestone of section 16.

Starting work on the GUI? Read section 0, then section 21. Much of this design depends on solprop’s recipes and front-end hooks, and what solprop delivers takes precedence over the names used here. The rules for working on the package are gui/AGENTS.md.

This document describes what the application is, how it looks and behaves page by page, how it maps onto solprop, which changes to solprop would make it simpler and better, and the options for its process architecture. Section 14 lists the open questions; answers become decisions in section 2.

Contents

  1. What solprop provides: SEP 40, 41 and 42

  2. Purpose and principles

  3. Decisions so far

  4. Users and the work they do

  5. Core concepts: recipe, run, workspace

  6. The main window

  7. Step 1: Geometry

  8. Step 2: Medium, and the waveguide explorer

  9. Step 3: Nonlinearity

  10. Step 4: Input fields and the grid

  11. Step 5: Propagate

  12. Step 6: Results

  13. Cross-cutting design: parameters, validation, help, files, scans

  14. Architecture and implementation options

  15. Open questions

  16. Changes proposed to solprop

  17. Phasing

  18. Lessons from the prototypes

  19. Design review, 2026-10-31

  20. Response to the design review

  21. Changes from the second SEP 41 review

  22. What solprop delivered, and what changed here


0. What solprop provides: SEP 40, 41 and 42#

The GUI holds presentation only, and solprop holds the physics, the defaults and the rules (section 1). Three solprop Enhancement Proposals provide what that needs, and all three are Final:

Proposal

What it gives the GUI

Implementation pull request

Tracking issue

SEP 42, Resuming by what matters to the run

Refusals that name what changed; ADR-066 has since replaced its comparison with an exact hash

LupoLab/solprop#336

LupoLab/solprop#142

SEP 40, Transverse absorbing boundaries for free-space propagation

The free-space edge: no real-space collar by default (collar_fraction 0), a collar on request with its design check

LupoLab/solprop#71

LupoLab/solprop#124

SEP 41, Recipes, and the hooks a front end needs

The recipe, and changes S1–S18: metadata, validation, observer, stop, previews and the rest

LupoLab/solprop#376

LupoLab/solprop#143

Section 21 lists where the delivered interface differs from what this design assumed, and the solprop changes the GUI still needs, with the milestone that needs each.

Planned work is in GitHub issues (solprop’s ADR-062). Search solprop’s open issues before reporting something as missing or planning a change to solprop. Finished-run extension, which this design would like one day, is LupoLab/solprop#141.

Finding out what was actually done. The three files are under docs/dev/seps/archive/: sep-0040-transverse-absorbing-boundaries.md, sep-0041-recipes-and-front-ends.md and sep-0042-tolerant-resume.md. For each one:

  1. Read the header. Status says how far it got (Accepted, In progress, Final), Implementation names the branch and Manual pages names the pages that document it.

  2. Read Part II, the implementation record. Part I is frozen at acceptance, so a change made during implementation appears only here: each phase’s report lists what was delivered, deviations, decisions, limitations and open questions.

  3. Read Part III for why things are as they are: the reviews, the responses to them and the maintainer’s decisions.

  4. Check the code and the manual, which win over everything. Start with solprop.recipe, solprop.capabilities, solprop.output.resumability and solprop’s CHANGELOG.md.

When they differ, solprop wins. Every solprop name in this document (Recipe.pin_roots, PlaneView, resumability) is what the accepted proposals said on 2026-11-01. Where the delivered interface differs, correct this document rather than working around solprop, and add a row to section 21 saying what changed. If the GUI seems to need a rule or a default of its own, that is a sign something belongs in solprop.

Numbering. S1–S18 are SEP 41’s changes, listed in section 15, and the same labels appear in that SEP. Section 3’s user scenarios use the same S numbers, so “Serves S1, S3” at the head of a page means scenarios, and “S17” or “SEP 41 S17” elsewhere means a change.

Where each is used.

Solprop item

Used in sections

SEP phase

S1 recipe, paths, examples

4, 5.2, 8.2, 12.5

SEP 41 phase 1; object routes in phase 4

S1 pins, S7 design solvers

7.5, 13.3

SEP 41 phase 5

S2 recipe in the output, resume from a file

4, 11.1, 13.1

SEP 41 phase 2

S3 plane observer

10.2, 13.1

SEP 41 phase 3

S4 scan progress

12.7

SEP 41 phase 3

S5 mode launch, S6 displacement and tilt

9.2

SEP 41 phase 4

S8 capabilities, S9 metadata, S10 validation

8.3, 9.3, 12.1, 12.3

SEP 41 phases 1 and 5

S11 cost estimate

10.1

SEP 41 phase 3

S12 load_spectrum

9.1

SEP 41 phase 1

S13 geometry drawings, S14 keyword gaps

6.2, 15

SEP 41 phase 6

S16 result capabilities

11.1, 11.3

SEP 41 phase 3

S17 stop flag, resumability

4, 10.1, 10.2, 13.1

SEP 41 phase 2

S18 previews

7.4, 9.2, 13.3

SEP 41 phase 4

Refusals that name what changed

4, 13.1

SEP 42 phase 1, ADR-066

What each milestone of section 16 needs from the three proposals, all delivered; the further solprop changes each needs are in 21.2.

Milestone

Needs

M1 Lifecycle

SEP 42 phase 1; SEP 41 phases 1–3

M2 Explorer

SEP 41 phases 4 and 5 (previews and pins)

M3 Guided routes

SEP 41 phase 4

M4 Results depth

SEP 41 phase 3

M5 Free space

SEP 41 phase 4

M6 Scans

SEP 41 phase 3; SEP 42 phase 2

1. Purpose and principles#

The GUI should let someone set up, run and understand a solprop simulation without writing Python, and let an expert do the same faster than a script would, while never becoming a dead end: everything made in the GUI can leave it as a recipe file or a Python script, and every result file solprop writes can be opened in it.

Principles, in priority order:

  1. solprop does the physics; the GUI does none. Every number the GUI shows comes from a public solprop call. The GUI holds no dispersion formulas, compatibility rules or defaults of its own; where it needs one that solprop doesn’t expose, the fix is a solprop change (section 15), not a copy in the GUI.

  2. Same machine first. The local desktop experience must not be compromised by remote ambitions. Remote use, in the short term, is the exported recipe or script run on the remote machine by hand.

  3. The setup is a document. A setup is a recipe (TOML) that can be saved, diffed, versioned, reopened, run headless and turned into a Python script. Results files carry the recipe that made them.

  4. Never block the window. Anything that can take more than ~50 ms (importing solprop, solving for a pressure, building a mode set, running) happens in another process. The window stays responsive at all times.

  5. Layered disclosure. Each page shows the few choices that matter to a newcomer, with defaults that are solprop’s own; an “Advanced” section on each page reveals the rest. No choice is ever hidden from an expert.

  6. Explain everything where it appears. Every control has a tooltip; every page has a help button; every warning says what to do about it.

  7. Honest about cost and validity. Before a run the GUI shows what it will cost (grid size, memory, rough time); during it, the boundary monitor and step statistics; after it, solprop’s warnings — never silently.

Non-goals (for now): editing arbitrary Python responses or callables in the GUI; a general plotting package; running on remote machines from the GUI (section 13 keeps the door open); replacing scripts for production campaigns.

2. Decisions so far#

#

Decision

Source

D1

Qt for Python (PySide6) with pyqtgraph for interactive plots; matplotlib (solprop’s own solprop.plotting) for publication figures. NiceGUI is not pursued.

prototype comparison, 2026-10-31

D2

A separate distribution, solprop-gui (import package solprop_gui), built from gui/ in solprop’s repository as a uv workspace member, as solprop-native is from native/. solprop’s gui extra pins it to solprop’s version and it pins solprop to its own, so the two are developed, tested and released together and cannot drift. Not a subpackage of solprop, whose repository-wide structural checks (the module list, the structure figures, the API reference, the import-time type hook, the 100 % coverage shards) would otherwise take in every Qt module.

2026-10-31; revised 2026-11-02 (was a separate repository)

D3

Designed for both newcomers and experts through layered pages (principle 5).

2026-10-31

D4

Parameter scans are designed in now (data model, results browser) and built after single runs.

2026-10-31

D5

A TOML recipe is the saved form of a setup, embedded in every results file; “Export as Python” produces an equivalent plain solprop script.

2026-10-31

D6

Same machine first; remote work stays scripted in the short term.

2026-10-31

D7

solprop’s API and way of working may change to help the GUI (nothing is public yet, so without aliases).

2026-10-31

D8

The recipe lives in solprop (solprop.recipe, change S1): its format, builders, Python export and solprop run; the GUI adds only presentation. Q1 closed.

2026-10-31

D9

This design is a living page under docs/dev/gui/, not a SEP; the work is a tracking issue and one issue, branch and pull request per milestone of section 16. A change to solprop the GUI needs follows solprop’s own rules (an issue, or a SEP for a major change).

2026-11-02

D10

Questions Q3–Q12 of section 14 are decided as recommended there.

2026-11-02

D11

The quality bar is split by layer: model, registry, service and help meet solprop’s standard in full, 100 % coverage included; ui and views are typed, documented and linted the same way and tested by pytest-qt smoke tests and offscreen screenshots, outside the coverage measure.

2026-11-02

3. Users and the work they do#

The design is checked against these scenarios; each later section names the ones it serves.

  • S1 — A student reproduces a textbook effect. Resonant dispersive-wave emission in a helium-filled capillary: pick the capillary, gas, pressure, a 10 fs pulse, run for a minute, watch the dispersive wave appear, read off its wavelength and energy.

  • S2 — An experimentalist designs a fibre. No propagation at all: what pressure puts the zero-dispersion wavelength at 450 nm in a 75 µm-core antiresonant fibre, what is the loss there, what is the soliton order at 30 µJ? Export the dispersion curve as CSV for a paper figure. (The waveguide explorer, section 7.4, used on its own.)

  • S3 — An expert sets up a multimode run, then leaves. Configure a 4-mode capillary run with a pressure gradient and Raman in N₂, check the cost estimate, export the recipe, run it on the workstation or cluster with a script, later open the results file in the GUI.

  • S4 — Anyone revisits an old result. Open a results file (from the GUI or from a script), browse planes, make a spectrogram at the fibre output, compress the pulse, export a figure.

  • S5 — Teaching and demos. A lecturer changes the energy live in front of a class and re-runs a short simulation; the display must be legible on a projector.

  • S6 — A free-space filament. A radially symmetric beam focused into argon: waist, focus position, pressure, Kerr plus plasma; watch fluence and on-axis spectrum evolve.

  • S7 — A scan (later). Energy × pressure grid of the S1 setup, then a map of dispersive-wave energy over the grid, clicking any point to open its run.

4. Core concepts: recipe, run, workspace#

  • Recipe. The complete, declarative description of one simulation: route (which solprop entry point), geometry, medium, nonlinear model, input fields, grid, numerics and output choices. Values are what the user typed (with units), with pins stated as their targets, not resolved solprop objects. A recipe is a TOML file (section 12.5). It is the GUI’s model: every page edits part of the current recipe, and nothing else holds setup state.

  • Authored and resolved. Following solprop’s improvements and reproducing an old run are different needs. The authored recipe keeps only what the user set, with units and pins, so it follows new defaults. The resolved recipe that solprop stores beside it in every results file freezes what rebuilds the run: what the user set, every solved pin, the noise seed, the data files and the defaults solprop can write back and still get the same run. “Open setup from this run” shows the resolved values; adopting the current defaults or re-solving the pins is a separate, explicit action (“Update to current solprop”), which lists what would change. A frozen setup can still be refused at resume if the materials data or the physics differ; solprop names the fields that changed (ADR-066).

  • Run. One execution of a recipe revision: a results file (solprop HDF5) with both recipes embedded, a log, and two separate states. The execution state is the GUI’s: queued, starting, running, stopping, stopped, complete, failed, worker lost. The outcome is solprop’s RunOutcome.status (running, complete, budget exhausted, failed), which has no “stopped”. Whether a run can be resumed is never assumed from either: it is asked of solprop (resumability, SEP 41 S17), which gives the mode (resume=True, from an interpolated plane, or forced, for a file already forced) or the reason it cannot (no checkpoint before a failure, no work left, another output schema, a writer still alive), and whether the file can be rebuilt from itself. A changed grid, a wider time window included, is always a new run.

  • Workspace. A folder the user picks (default ~/solprop-runs), holding one folder per run: <date>-<title>/ with run.h5, recipe.toml, run.log and a thumbnail. The GUI keeps an index for fast browsing but the folder is the truth: copying a run folder elsewhere loses nothing.

  • Project file. Just a recipe saved by the user wherever they like (“Save setup as…”). Opening a results file offers “Open setup from this run”, which loads its embedded recipe as a new, unsaved project.

5. The main window#

5.1 Layout#

┌──────────────────────────────────────────────────────────────────────────────────┐
│ File  Edit  View  Run  Tools  Help                     rdw-helium.toml  (edited) │
├──────────────────────────────────────────────────────────────────────────────────┤
│  ① Geometry ✓ ── ② Medium ✓ ── ③ Nonlinearity ✓ ── ④ Input ⚠ ── ⑤ Run ── ⑥ Results │
├────────────────────────────────────────────────────────┬─────────────────────────┤
│ Input fields                              [?] [Advanced]│ Summary            [⇥]  │
│                                                        │ route   capillary,      │
│                                                        │         4 HE₁ₘ modes    │
│              (page content)                            │ λ₀      800 nm          │
│                                                        │ β₂(λ₀)  … fs²/m         │
│                                                        │ ZDW     … nm            │
│                                                        │ N       …               │
│                                                        │ L_fiss  … cm            │
│                                                        │ I_peak  … W/cm²         │
│                                                        │ grid    2¹³ × 4 modes   │
│                                                        │ memory  ≈ … MB          │
├────────────────────────────────────────────────────────┴─────────────────────────┤
│ ⚠ Pulse 2 lies within 10 fs of the time-window edge.        [Widen window] [Why?] │
└──────────────────────────────────────────────────────────────────────────────────┘
  • Step bar. Six steps, always visible, each with a status badge: ✓ valid, ⚠ valid with warnings, ✗ invalid, ○ untouched. Steps are not a forced sequence: once a geometry is chosen, any step can be visited in any order. “Next” and “Back” buttons exist for newcomers. On a narrow window the labels collapse to numbers and icons.

  • Page. Each page has a title, a help button [?], and an [Advanced] toggle that reveals the expert controls (remembered per page).

  • Summary dock (right). Live derived numbers for the current recipe, computed by solprop (tools.capillary_params, soliton_params, zdw, the grid’s own size, the cost estimate): dispersion and soliton figures for guided routes; Rayleigh range, critical power and peak intensity for free space. It answers “what will this do?” while the user types, which is most of the value of a GUI over a script. Collapsible to an icon rail. The same dock can show the help page instead (section 12.4).

  • Message bar (bottom). The most important current warning or error with one-click fixes where solprop can suggest one, and a “Why?” link to the relevant help. The full list is in a Messages panel (View menu).

  • Show code (View menu). A dock with the live Python equivalent of the current recipe, updated as the user types. This is the bridge from GUI to scripts, and teaches the API by example.

5.2 Start screen#

Shown when no project is open: New simulation, Open setup…, Open results…, Waveguide explorer, Examples (solprop’s own example recipes, Recipe.examples(): RDW in a capillary, soliton self-compression, filament, …), and a list of recent setups and runs. New simulation starts from one of these examples for the chosen geometry.

5.3 Small screens#

The design target is a 13-inch laptop (1280 × 800 logical pixels) without scrolling the main controls; it must remain usable at 1024 × 700 and look good on a 4K monitor and a projector (S5).

  • The summary dock collapses to a rail; the step bar to icons.

  • Setup pages are single-column forms grouped into collapsible sections; plots on setup pages (pulse preview, dispersion) sit beside the form when there is room and below it when there isn’t.

  • The run and results pages use dock areas with saved layouts (section 11.2), so a small screen shows one large view with the others as tabs.

  • Fonts and plot line widths follow the system scale; a “Presentation” toggle (View menu) enlarges everything for S5.

6. Step 1: Geometry#

Serves S1–S7. The choice here fixes the route — which solprop entry point builds the simulation — and so decides which options exist on the later pages.

6.1 Selection#

Two levels. First a family: Hollow-core waveguide, Solid-core fibre, Free space. Then a description within it, shown as cards. Each card has an icon, a one-line “use it for” text (taken from the guide’s model-selection table), a cost hint and a newcomer/expert marker.

Hollow-core waveguide
┌────────────────┐ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│  (icon)        │ │  (icon)        │ │  (icon)        │ │  (icon)        │
│ Capillary,     │ │ Capillary,     │ │ Capillary,     │ │ Antiresonant   │
│ mode-averaged  │ │ multimode      │ │ full transverse│ │ fibre          │
│ fastest        │ │ HE₁ₘ, radial   │ │ HE/TE/TM       │ │ tube lattice   │
└────────────────┘ └────────────────┘ └────────────────┘ └────────────────┘
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ Rectangular    │ │ Hollow slab    │ │ Slab, resolved │  expert ▸
│ hollow guide   │ │ (per width)    │ │ in y           │
└────────────────┘ └────────────────┘ └────────────────┘

Card

solprop route

Notes

Capillary, mode-averaged

prop_capillary(mode_average=True)

The newcomer default.

Capillary, multimode (radial)

prop_capillary(modes=N)

HE₁ₘ modes on a radial rule.

Capillary, full transverse

prop_capillary with an azimuthal rule (n_theta), or prop_waveguide with Marcatili modes

Expert.

Capillary with coherent wall

prop_capillary(wall=CoherentWall())

Expert; shown as an option of the capillary cards.

Antiresonant fibre

prop_capillary(lattice=TubeLattice(...))

Lattice set by tube count, wall thickness, gap or diameter ratio.

Rectangular hollow guide

prop_waveguide([RectMode…])

Hollow slab

prop_waveguide([SlabMode…])

Values per unit width (J/m, W/m); the GUI labels units accordingly.

Slab resolved in y

prop_planar(PlanarGrid…)

Expert.

Fibre, GNLSE with Taylor dispersion

prop_gnlse(gamma, betas=…)

The textbook model.

Step-index fibre

prop_gnlse(fibre=StepIndexMode(...))

Core radius, NA or core/cladding glasses.

Fibre from a table

prop_gnlse(fibre=IndexTable…)

n_eff (and A_eff, loss) loaded from a file.

General modal (vector)

prop_waveguide((), provider=ModalGuide…)

Expert: step-index or graded-index vector guides with material regions.

Free space, radial

prop_radial

Cylindrical symmetry.

Free space, Cartesian

prop_free(FreeGrid…)

Full x–y.

Free space, line

prop_free(LineGrid…)

x only, per metre of y.

The list is data, not code: a route registry (section 13.3) describes each card, so a new solprop route is one entry.

6.2 Icons and the live cross-section#

solprop’s guide already has to-scale cross-section figures of every geometry, generated by docs/guide/figures/geometries.py from solprop’s own modes and node rules (capillary_radial.svg, antiresonant.svg, radial_free.svg, and so on). They are the right source for the cards, with two problems: they use CSS custom properties and a prefers-color-scheme media query, which Qt’s SVG renderer (SVG Tiny 1.2) ignores; and at 560 px wide they are figures, not icons.

Proposal: move the drawing code into solprop (solprop.plotting.geometry, section 15, S13) with two outputs — a simplified thumbnail and a detailed figure — and a palette argument so the GUI can render light or dark versions directly. The bigger win is that the GUI can then draw the user’s actual geometry to scale on the geometry page: the real core radius, tube lattice, quadrature nodes and absorbing collar, updating as they type. Until then a build script resolves the CSS variables into two static palettes.

6.3 Geometry parameters#

Below the cards, the parameters of the chosen geometry: length; core radius (or half widths, gap); lattice parameters; cladding material (advanced); number of modes and the transverse rule (n_r, n_theta, radial_rule; advanced); Marcatili model “full”/”reduced” and the loss switch (advanced).

z-profiles. Any parameter solprop accepts as a ZProfile (radius for a taper, half widths, and on later pages pressure, temperature, preionisation) gets a small profile button beside its field: constant (default), linear, piecewise (table of z, value), or from file. The field then shows a sparkline of the profile; clicking it opens a profile editor (a table and a plot with draggable points). The same editor is used everywhere (section 12.2).

Changing geometry later. Choosing a different card keeps every value that still applies (gas, pulse, grid) and lists the ones that will be dropped, with an undo.

7. Step 2: Medium, and the waveguide explorer#

Serves S1, S2, S3, S6.

7.1 Gas fills#

  • Species: a dropdown from solprop’s own list ([g.value for g in Gas]: Air, He, Ne, Ar, Kr, Xe, N₂, H₂, D₂, O₂, CH₄, SF₆, N₂O), displayed with subscripts; Air expands to its components.

  • Mixture: “Add component” turns the single species into a table of species and mole fractions (gas={species: fraction}), or of partial pressures (Mixture.partial_pressures) in advanced mode.

  • Pressure (bar, as in solprop): constant; gradient ((p_in, p_out) → PressureGradient.two_point); stages (z and pressure table → from_stages); or from gas flow: chamber pressures and positions → gasflow.steady_fill, with flow_report shown beside it (throughput, mass flow, Reynolds and Knudsen numbers per stage, choked ends). Advanced: pressure_floor, vacuum_end.

  • Temperature (K, default 293.15): constant or profile.

  • Material model policy (advanced): MaterialSelection — linear, electronic, Raman and ionisation policies — with “recommended” defaults. These live with the medium because they choose data, not physics; the nonlinear page links here.

7.2 Solid media#

For solid-core routes: core and cladding glass from glass_names() (silica, CaF₂, MgF₂, BK7, sapphire, BaF₂; the ordinary/extraordinary axis where needed), or a constant complex index. For GNLSE with Taylor dispersion there is no medium as such: the page becomes a table of β₂, β₃, … (with units fs²/mm etc.) and γ or n₂, plus loss in dB/m.

7.3 Free-space media#

SpatialMedium: a gas (with pressure, and a pressure profile on the radial route only), a glass, or a constant index.

7.4 The waveguide explorer#

S2 says this page is often the whole job. The explorer is a panel on the medium page and also a standalone tool (start screen, Tools menu) that opens with its own small geometry and medium form.

┌ Explorer ───────────────────────────────────────────────────────────────────────┐
│ Plot: [β₂ (GVD) ▾]  vs [wavelength ▾]   modes: [HE₁₁ ☑ HE₁₂ ☑ HE₁₃ ☐]    [Export]│
│ ┌──────────────────────────────────────────────┐  Sweep: [pressure ▾] 0.2–5 bar │
│ │                                              │         5 curves, coloured     │
│ │       (curves; hover readout; drag λ₀)       │  Mark:  ZDW ☑  λ₀ ☑  RDW ☑     │
│ │                                              │                               │
│ └──────────────────────────────────────────────┘  At λ₀ = 800 nm:               │
│                                                   n_eff, β₁, β₂, β₃, loss,      │
│                                                   A_eff, γ  (table, copyable)   │
└─────────────────────────────────────────────────────────────────────────────────┘
  • Quantities, from solprop.modes.base and tools: n_eff − 1, β₁ (group index or group delay), β₂ (GVD, also as dispersion parameter D), β₃, loss (dB/m, loss length, transmission over the length), A_eff, γ, ZDW; also as functions of z for tapers and gradients.

  • Axes: wavelength, frequency, photon energy; linear or log; units selectable.

  • Sweeps: overlay curves for a list of one parameter (pressure, radius, gas, mode order), or show a 2-D map (ZDW vs pressure and radius).

  • Markers: ZDW, pump wavelength, phase-matched RDW wavelength (tools.lambda_rdw_all), phase-mismatch curves (phase_mismatch).

  • Readouts: a table at the pump wavelength, and the soliton figures for the pulse of step 4 if one is defined (soliton_params: N, L_D, L_NL, L_fiss, critical power).

  • Export: CSV of every curve, figure as PNG/SVG/PDF, “Copy as Python”.

7.5 Pinning a parameter to a target#

The brainstorm asks to “fix the ZDW to a specific wavelength”. The general form: a parameter can be pinned to a target instead of set directly. The pressure field gets a mode switch: set | from ZDW | from RDW wavelength | from soliton order. Pinned, it shows the target as the input and the solved value read-only beside it, re-solved whenever an input it depends on changes (in the background; the field shows a spinner). The semantics are solprop’s ([pins], SEP 41 S1), so the GUI, solprop run and the Python export agree:

  • the pin holds its target, its search range and which root to take (lowest, highest or a chosen one); when solprop finds several roots the field offers them, and when it finds none the field shows the attainable range as the error;

  • pins resolve after the literal values, in two fixed stages: at most one pin on a parameter of the guide or fill, then the pins on pulses, which read it, so no cycle can be written. A pressure gradient cannot be pinned;

  • a scan re-solves the pins at every point;

  • the resolved value goes into the resolved recipe of every run.

Pin

solprop solver

Pressure from ZDW

tools.pressure_zdw(radius, gas, zdw_wavelength, …)

Pressure from RDW wavelength

tools.pressure_rdw(radius, gas, target_wavelength, wavelength, …)

Radius from ZDW

tools.radius_zdw (S7)

Energy from soliton order

tools.solve_parameter(…, SolitonOrder(…)) (S7)

Any of these, on any guided route

tools.solve_parameter(build, …) (S7)

The authored recipe stores the pin, the resolved recipe the solved value, so a saved setup still shows the intent and a run reproduces exactly. A design that sets two values at once (tools.capillary_design, pressure and energy from a ZDW and a soliton order) is not a pin: the page offers it as a design tool that writes both values as literals.

8. Step 3: Nonlinearity#

Serves S1, S3, S6.

8.1 Layout#

One row per physical effect, each with an on/off switch, a short description, and its options in an expandable area:

Field representation   (•) Full field (carrier-resolved)   ( ) Envelope        [?]
─────────────────────────────────────────────────────────────────────────────────
☑ Kerr effect            third-harmonic terms: [auto ▾]   model: [recommended ▾]
☑ Photoionisation & plasma  rate: He → PPT (recommended)  integration: [band ▾]
    preionisation: [0]
☐ Raman                  (no Raman-active species in He — not available)
☐ TDSE atomic response   (research; helium, capillary only)                expert
  • Field representation (envelope= on the modal routes): full field is solprop’s default; envelope is faster for narrow-band problems. The choice changes which options exist (THG defaults to off and envelope plasma to cycle-averaged), so it sits at the top.

  • Kerr: on/off (kerr); third harmonic (thg, default “auto” = full field only); model (MaterialSelection.electronic: recommended, carrier-kerr, symmetric-kerr, gas-polynomial — the last two the dispersive Kerr evaluators); kerr_form for the general modal route.

  • Plasma: on/off (plasma, default on for the full field); rate model per species (recommended, or a comparison model: ppt_ilkov, ppt_larochelle, … for atoms, MO-ADK variants for molecules), shown with the status solprop reports (“recommended”, “comparison”, “untested”); preionisation (number or profile, per species); integration (“band” or “trapezoid”, advanced); ionisation_field_range (advanced).

  • Raman: auto (solprop’s rule: on for N₂, O₂, H₂, D₂, CH₄, SF₆), off, on, or per species with MolecularOptions (rotation, vibration, temperature, J range; advanced). For GNLSE: on/off and fraction (silica).

  • TDSE (expert, capillary, helium only): model SAE/haCC, Kerr model, device; enabling it locks the options solprop refuses alongside it (plasma, Raman, THG, preionisation) and sets the backend it needs.

8.2 One set of switches on every route#

The modal routes take keyword switches; the free-space routes take an explicit list of response objects. The GUI shows the same switches everywhere and the recipe stores the switches; for radial, Cartesian and planar routes the builder calls nonlinear.mixtures.responses_for(mixture, kerr=…, plasma=…, raman=…, envelope=…). On free-space routes solprop’s own default is linear (no responses), and the GUI keeps it: it has no defaults of its own (principle 1). New setups start from solprop’s example recipes (Recipe.example, SEP 41 S1), so the filament starting point with Kerr and plasma on is a named solprop example the user chose, shown as such on the start screen and in the page header.

8.3 Unavailable options#

Options that can’t be combined are disabled, not hidden, with a tooltip saying why (“Plasma forbids third-harmonic terms”, “Envelope plasma needs the envelope representation”, “No Raman-active species in this fill”). These rules belong to solprop (principle 1): the GUI asks solprop’s capability query (S8) rather than encoding them. S8 lists only the combination rules (route × keyword × species); rules that depend on values come from Recipe.check() (section 12.3).

9. Step 4: Input fields and the grid#

Serves S1, S3, S5, S6.

9.1 Pulses#

A list of pulses (one by default; “Add pulse” for pump–probe or two-colour), each a compact card:

  • Shape: Gaussian (super-Gaussian order m advanced), sech², or from data.

  • Wavelength; duration as FWHM (or width for sech, advanced); energy or peak power (a switch); delay t0.

  • Phase: CEP, GD, GDD, TOD, … as a short table (Taylor coefficients about the pulse’s own wavelength), with units fs, fs², fs³.

  • From data: an import dialog for spectra (wavelength or frequency, intensity, optional phase) or temporal fields, from CSV/TXT with column picking and a preview, building DataPulse.from_spectral_density or DataPulse.from_time. Common formats (two-column spectra, FROG/SPIDER retrievals) are proposed as solprop loaders (S12) so scripts get them too.

  • CW (advanced): CWPulse for seeding.

A preview plot beside the list shows |E(t)|² and the spectrum of every pulse and their sum, on the simulation’s actual grid, with the window edges drawn, so a pulse that doesn’t fit is visible before the run.

9.2 Where the light goes in#

  • Modal routes: today the keyword routes put the pulse in the lowest mode, or in the mode channel= names. The design has a launch table, per pulse (a pump and a seed may go into different modes): a share and a phase per mode, labelled as solprop labels the modes (HE1,1, with the parity where both polarisations exist). It needs solprop change S5; until then it shows “fundamental mode” and explains. On Marcatili-type bases the shares are energy fractions. On a general modal basis the modes are not flux-orthogonal, so solprop normalises the total energy through the flux metric and the table labels the shares “coordinate shares, not an energy split”.

  • General modal: the launch table, or a free-space beam coupled in (incident=SpatialPulse, coupling=CouplingModel(...)); the two exclude each other.

  • Free space: beam waist (1/e² intensity radius), super-Gaussian order, focus position as a distance before or after the waist (propz), polarisation (jones). Cartesian: displacement and tilt (today only through coupling.Alignment; S6 puts them on the beam, with Alignment’s names; the tilt is a pure angle at every frequency). Planar: waist_x, offset_x. A preview shows the beam cross-section on the transverse grid (Recipe.preview_input, S18).

9.3 The grid#

Below the pulses, because the pulses determine it:

  • Wavelength range (λmin, λmax) and time window, with an Auto button that asks solprop for a suggestion from the pulses and the route (S10 covers the suggestion).

  • Transverse grid (free space: radius and points; planar: y extent and points).

  • Advanced: ffac, fft_size, collar fraction, a ready-made grid.

  • The resulting grid size, sample spacing and memory appear in the summary dock and update immediately.

9.4 Noise#

noise (solprop’s default, off, input, modified) and the seed, advanced, with the default explained in the tooltip.

10. Step 5: Propagate#

Serves S1, S3, S5, S6.

10.1 Before the run#

The run page opens on a pre-flight panel:

  • A compact read-only summary of the recipe by step, each line linking back to its page.

  • Cost estimate from solprop (S11): grid points, modes or transverse nodes, memory, and a rough time based on similar past runs in the workspace.

  • Numerics (advanced): backend (from backends.registry.available(): auto, native, numba_cpu, numpy_ref, mlx), precision, tolerance (rtol, with the route’s default shown), integrator (Multistep, Runge–Kutta, low-storage), save planes (n_save or a spacing), statistics (StatsSpec, with the route’s default set ticked), threads (SOLPROP_THREADS), boundary check and absorber, snapshots.

  • Output: run title and workspace folder (defaults filled in).

  • Run and, for an existing run of the same recipe that solprop reports resumable (resumability), Resume; otherwise the reason is shown.

10.2 During the run#

┌ Run: rdw-helium-4 ──────────────── 37 % ▕████████░░░░░░░░░░▏ z 0.37 / 1.00 m  ETA 0:42 ┐
│ [■ Stop]  [⏸ Detach]   steps 1 204 (17 rejected)   step size ▁▂▃▅▅▃▂   boundary ● ok │
├──────────────────────────────────────┬───────────────────────────────────────────────┤
│ Spectrum vs z (dB)                   │ Power vs z                                    │
│   (image fills in plane by plane;    │                                               │
│    z marker; hover readout)          │                                               │
├──────────────────────────────────────┴───────────────────────────────────────────────┤
│ Spectrum at z │ Power at z │ Energy / peak power / FWHM vs z │ per-mode energy │ Log │
└──────────────────────────────────────────────────────────────────────────────────────┘
  • Live maps as in the Qt prototype: spectral density in dB on a wavelength (or frequency) axis and power in time, filling in at most four times a second whatever the run’s speed. Each is a view specification (section 12.8), so its normalisation and reduction are stated, not implied. Clicking or dragging the z marker shows any saved plane while the run continues; “follow” mode tracks the newest plane.

  • Route-specific live views: per-mode energy and the mode sum toggle for multimode runs; for free space, fluence and beam radius vs z, on-axis spectrum vs z and the r–t intensity at the current plane.

  • Statistics strip: whatever StatsSpec asked for, plotted against z as the planes arrive (energy, peak power, FWHM, electron density, …), plus step size and rejections from the step history.

  • Boundary monitor lamp: green until the monitor speaks, amber on BoundaryWarning, red on BoundaryError, which the worker catches like any other warning or error. The suggested fix is “Widen the time window and rerun”: a wider window is a new grid, so a new run, and resuming cannot recover light the old edge has already affected (it was the first failure met in the prototype).

  • Log: solprop’s log and warnings, filterable.

  • Stop sends a stop request on the worker’s control pipe; the worker sets solprop’s stop flag (S17), which takes effect within one step or trial on every platform (on Windows a signal would terminate the worker outright). The run writes its state and run returns normally. The execution state is stopping until the worker reports, then stopped, and the Resume button follows resumability. If the worker hasn’t stopped after a grace period the GUI offers to kill it; afterwards it asks resumability before calling the file resumable, since a killed run may have no restart state.

  • Detach (if the architecture supports it, section 13) lets the run continue after the window closes; reopening the run re-attaches.

10.3 Several runs#

The run page shows one run; a Runs panel (left, collapsible) lists runs in the workspace with status, so several can run at once (each with a thread budget the user can see; the GUI warns before oversubscribing the machine) and a finished one opens in Results with a click. A simple queue (“run these one after another”) falls out of the same panel.

11. Step 6: Results#

Serves S1, S4, S5; scans (S7) in 12.7.

11.1 Opening results#

The results page opens any solprop results file of a supported output schema, not only GUI runs: it needs only solprop’s Output interface (open_file). If the file carries a recipe, the setup pages can be restored from it (the resolved values, section 4); if not (a scripted run), the setup pages show the run metadata read-only.

What a file can show depends on what it stores, not on its route. The GUI asks solprop (capabilities.output, SEP 41 S16) and offers only the views whose inputs and physical meaning are available: which planes kept fields and which only statistics; whether a quantity is a physical flux or a coordinate quantity, and its unit (per unit width on slab and line routes); whether general modal reconstruction has its guide and reference tables; which operations solprop refuses, with the reason, shown on the disabled view.

11.2 Layout: a plane navigator and docked views#

  • Left: run information (title, status, recipe summary, wall time, warnings) and the plane navigator: a z slider with the planes marked, the current plane’s z, and mode selection (sum, a mode, several).

  • Centre: views in docks. Each view follows the current plane unless pinned. Saved layouts suit the common tasks and small screens:

    • Overview: the two maps plus spectrum and power at the current plane (the prototype’s layout).

    • Plane: spectrum, power, phase and spectrogram at one plane.

    • Statistics: every recorded statistic against z.

    • Modal or Spatial: per-mode content, or r–λ, r–t and far-field views.

    • Compare: two or more runs overlaid. Layouts are QDockWidget states; users can make and name their own.

11.3 The views#

View

solprop call

Offered when (from S16)

Spectrum vs z map (λ, f, ω; dB range)

processing.fields.get_spectral_density per plane

fields kept; labelled coordinate on spatial files

Power (or field, |E|²) vs z map

get_power, get_field

fields kept; labelled as above

Spectrum at plane (lin/log, resolution, bandpass)

get_spectral_density

the plane kept its field

Power, field, envelope at plane

get_power, get_field(kind=…)

the plane kept its field

Spectral and temporal phase

get_phase

the plane kept its field

Spectrogram (gate width, ranges)

plotting.spectrograms.spectrogram data

the plane kept its field

Energy, peak power, FWHM, … vs z

stats/* datasets; processing.time

the statistic was recorded

Step size and rejections vs z

step_history/*

always

Mode energies vs z, modal spectra

modes= selections; processing.modal for general modal

modal; general modal with its tables

r–t, r–λ, fluence, beam radius, far field

spatial stats and accessors

free space

Pulse compression (transform limit; Taylor, material, chirped mirrors, gratings, prisms; CEP)

processing.compression.*

not spatial or general modal (solprop refuses)

Coherence (g₁₂) over an ensemble

processing.coherence.g12_of

ensembles, scans

A mode sum, a physical intensity and a coordinate intensity are not interchangeable, and the labels say which is shown. On a modal file get_power gives \(|b(t)|^2\) summed over the selected modes, which differs from the broadband Poynting flux of the recorded temporal statistics; where both appear on one page the help explains the difference.

Interactive views are pyqtgraph with the prototype’s hover readouts, a crosshair, and linked axes (the spectrum at a plane shares its λ axis with the map). Every view has Copy as Python, giving the solprop processing and plotting calls that reproduce it.

11.4 Export#

  • Figures: “Export figure” renders the view with matplotlib through solprop.plotting (prop_2d, spec_1d, time_1d, spectrogram, stats) in solprop’s style, as PNG, SVG or PDF at a chosen size and DPI, so exported figures match scripted ones. A quick screenshot export of the pyqtgraph view is also there.

  • Data: a line as CSV; a map as CSV, NPZ or HDF5; the current plane’s field as a solprop FieldPlane (processing.planes.field_plane) for coupling into another run. Quantitative exports are computed from the file at full resolution through the view’s specification, never from the reduced arrays on screen.

  • Run: the run folder is self-contained; “Reveal in Finder/Explorer” and “Copy path”.

12. Cross-cutting design#

12.1 Parameters: one registry#

Every parameter the GUI shows has one registry entry: recipe key, label, symbol, unit and display unit, solprop keyword it maps to, default (read from solprop, never duplicated), range, newcomer/advanced, tooltip text and help anchor. Pages are built from the registry; the recipe schema, the tooltips, the “Show code” output and the tests all come from it. A test checks that every registry entry maps to a real keyword of the route’s solprop function, catching drift when solprop changes.

Because the recipe lives in solprop (D8), the keyword, unit, default, range and doc anchor live there too (with S9); the GUI’s registry adds only presentation: label, display unit, grouping, newcomer/advanced and the GUI’s own tooltip wording.

12.2 Quantity input#

Fields accept numbers with units and SI prefixes (“125 µm”, “0.125 mm”, “1.5 bar”, “7.5 fs”, “275 uJ”, “2e14 W/cm^2”) and display in a chosen unit; the tooltip shows the value in SI. Arithmetic is not needed. Profiles (6.3) use the same fields in their tables. A small parser of our own is enough; pint is an option if it grows.

12.3 Validation in three layers#

  1. Field: type, unit, dimension, range — instant, in the widget, from solprop’s metadata (S9).

  2. Combinations: options that can’t be combined — instant, from solprop’s combination rules (S8).

  3. solprop: Recipe.check() in the kernel after each pause in typing. It reports every metadata-level issue, then builds and translates (about 0.1 s), so value rules such as a pulse inside the window or energy or peak power come from solprop, not from a copy. Each issue names its parameter path (S10), so the GUI puts the message next to the field, warnings included. Step badges come from this layer, so ✓ means solprop accepts the setup.

12.4 Tooltips and help#

  • Tooltips on every control: a sentence or two, the symbol and unit, the default and where it comes from, the solprop keyword (for the script-minded), and “More…” opening the help.

  • Help button on every page and dialog opens the help dock with a short page written for the GUI (“What this page sets, what to choose and why”), linking to the solprop guide for depth: the geometry page to guide/setup/model-selection and spatial-decompositions, the medium page to guide/media/materials and mixtures, the nonlinear page to media/nonlinear, ionisation, raman, and so on.

  • The guide pages open from the bundled HTML of the installed solprop version when present, otherwise from the online documentation.

  • A GUI user guide (in this repository’s docs) walks through S1 and S2 with screenshots, generated by an offscreen script so they stay current.

12.5 Recipe files (TOML)#

The format is solprop’s (D8), defined by SEP 41 (S1). Its keys are the route’s own keywords, all in one [build] table; execution settings go in [execution]; pins and scans have their own tables. The grouping the GUI shows comes from solprop’s metadata, not the file. A sketch of what the GUI writes:

[recipe]
format = 1
route = "capillary"
title = "RDW in a helium capillary"
solprop = "0.2.0"                     # version that wrote it

[build]
radius = "125 um"
length = "1 m"
mode_average = true
gas = "He"
temperature = "293.15 K"
plasma = true
wavelength = "800 nm"
fwhm = "7.5 fs"
energy = "275 uJ"
wavelength_limits = ["100 nm", "1500 nm"]
trange = "200 fs"

[execution]
fields = "planes"
field_planes = [0, -1]

[pins]
pressure = { target = "zdw", wavelength = "600 nm", search = ["0.1 bar", "10 bar"], root = "lowest" }
  • Only what the user set is written; defaults stay implicit so a recipe follows solprop’s improvements. Each run file holds this authored recipe and the resolved one (section 4). A hand-written recipe opened and left unedited saves verbatim; an edited one is written canonically, without comments.

  • Every value has a parameter path (pressure, pulses[1].energy, launch["HE1,1:even"].share), used for edits, messages, scans and pins alike.

  • "none" spells None only where the default is something else (noise, boundary_check); elsewhere the key is left out. Callables and types outside solprop’s registry cannot be held (the Python export is the way out, Q9). Objects are tables with a type, and a recipe is one-way: there is no capturing a Python call that built objects.

  • Values are quantity strings (12.2) or plain SI numbers (open question Q2); solprop converts them exactly and checks their dimension.

  • Data a recipe refers to (a measured spectrum, an n_eff table) is copied next to it and referred to by a relative path, and its hash recorded.

  • format is versioned; the loader upgrades old formats.

  • Python export writes a plain solprop script with the route’s keyword call (prop_capillary(radius=125e-6, …)), any pin’s solver call before it, and a comment per non-default choice, so it runs wherever solprop is installed (Recipe.to_python()). solprop run recipe.toml (or python -m solprop run) is the headless equivalent for scripts and clusters.

12.6 Edit, undo, persistence#

Every change is an undoable command (Qt’s QUndoStack) on the recipe; the title bar shows unsaved changes; autosave keeps a recovery copy. Window layout, last workspace, units and recent files persist with QSettings. Light and dark themes follow the system.

12.7 Scans (designed now, built later)#

  • Setup: any numeric field, nested ones included (a second pulse’s energy, a profile knot), gets a “scan” toggle in its context menu that turns it into a list or range (linear, log, explicit) over its parameter path. Pins re-solve at every point. A Scan section on the run page shows the variables, the grid shape and the total cost, the retention choice (fields: none, chosen planes, all) and reductions (energy in a band, spectrum in a band, peak power, …, from processing.scans).

  • Run: Recipe.scan() gives the Scan, a picklable builder (passing each point’s seed) and the keywords for run_scan(..., executor=Local() | Pool(workers)), the retention choice among them. Live progress needs solprop change S4 (today the scan reports finished points only).

  • Results: a scan browser shows any reduction as a map over two scan variables (or lines over one), with the others as sliders; clicking a point opens that point’s run in the normal results page (when its fields were retained).

  • Data model: a scan is a recipe plus a [scan] table of variables, so the recipe format must allow it from format 1.

12.8 View specifications#

A display product has a scientific meaning, and the GUI states it once. Each view is a view specification shared by the pyqtgraph view, the matplotlib export and “Copy as Python”: the quantity and its unit, the selection (modes, planes, window), the normalisation and its reference (a spectrum in dB is relative to a stated reference; in compare mode several runs share one, so energy differences stay visible), any filtering, and the reduction used for display.

  • Display reductions are labelled as such. A strided power trace can miss a narrow peak, so strided reductions keep each bin’s maximum, and the view says the trace is reduced.

  • Hover values on a reduced view read the authoritative value from the file on demand where the plane is stored, and say “display value” where it is not.

  • Quantitative exports and “Copy as Python” are computed from the file, never from display arrays.

  • Reductions with a scientific claim (energy in a band, a peak, a width) are solprop’s (processing), tested there to preserve what they claim.

13. Architecture and implementation options#

13.1 Constraints from solprop#

  • import solprop itself is lazy (about 30 ms), but building anything is not: importing solprop.recipe loads the driver, the backends and h5py (about 0.5 s warm, several seconds cold), and numba compilation and FFTW planning add more on a first run. None of this may happen in the window’s process; the light parts it may use are listed in 13.5.

  • A run uses all the cores it is given (numba, FFTW, OpenMP, native threads); a run in the GUI process would fight the GUI for the GIL and the cores.

  • Stopping today is a signal: solprop’s handlers turn SIGINT into KeyboardInterrupt and SIGTERM into RunTerminated (a signal arriving while a plane is being committed waits for the commit to finish), and the run then writes its state. The handlers are installed only in a main thread, and on Windows os.kill with SIGINT terminates the process outright. So the run needs its own process, and the GUI stops it through solprop’s portable stop flag (S17) set from the worker’s control thread.

  • Results files have no SWMR: a writer holds a lock sidecar, and another process can’t safely read a file being written. Live data must therefore be streamed from the process that runs the simulation, through solprop’s plane observer (S3), which gives read-only, lazy access to each committed plane. An observer that raises is detached by solprop and the run continues, but the worker still catches its own pipe errors.

  • Resume needs a Simulation rebuilt in Python with the file’s configuration hash (ADR-066): solprop rebuilds it from the resolved recipe in the file (S2), so the GUI needs no state of its own to resume. resumability(file, gate=True) shows what differs before one is tried.

13.2 The options#

A. Integrated. solprop runs in a thread of the GUI process. Simplest to write, but violates every constraint above: GIL contention freezes the UI, a crash in native code takes the GUI down with the user’s unsaved setup, and stopping cleanly is awkward. Rejected.

B. A worker process per run (what the prototypes do). The GUI spawns a child per run; the child builds the simulation from the recipe, writes the HDF5 file, and streams reduced rows over a pipe.

  • Good: robust, isolates crashes, clean stop, uses all cores, simple; works today.

  • Limits: the run dies with the GUI; the GUI still needs solprop in some process for the explorer, validation and previews — a second, long-lived child (a kernel) is needed anyway.

C. A local server. A long-lived background process (solprop service) owns runs, the explorer computations and validation; the GUI is a client over a local socket.

  • Good: runs survive the GUI closing and re-attach with full history; several windows (or a notebook) can watch the same run; one warm solprop import serves every request; the same protocol later works over an SSH tunnel to a workstation, which is the remote story.

  • Costs: a protocol to design and version; service lifecycle (start on demand, stop when idle, find a running one, recover from a crashed one); local security (a socket only the user can open, a token); more moving parts to debug.

13.3 Recommendation: B now, shaped as C#

Build the GUI against a service interface — a small set of request and event messages — and implement it first in-process-tree: a service object in the GUI process that manages a long-lived kernel child (warm solprop for explorer, validation, previews) and one worker child per run, over multiprocessing pipes. Moving to C later means running the same service code as a separate process and changing the transport, not the GUI.

 GUI process (Qt, no solprop)                 children (solprop)
 ┌──────────────────────────┐   requests    ┌──────────────────────────────┐
 │ pages, plots, recipe     │ ────────────▶ │ kernel: validate, preview,    │
 │ model, undo              │ ◀──────────── │ explore, solve pins, estimate │
 │        │                 │   replies     └──────────────────────────────┘
 │  service client          │               ┌──────────────────────────────┐
 │  (one interface;         │ ◀──events──── │ worker per run: build from    │
 │   transport: pipes now,  │ ───control──▶ │ recipe, run, write HDF5,      │
 │   socket later)          │               │ stream reduced rows + stats   │
 └──────────────────────────┘               └──────────────────────────────┘

Messages (sketch):

Request (GUI → service)

Reply or events

validate(recipe)

errors and warnings with parameter paths

summarise(recipe)

the summary dock’s numbers

explore(geometry, medium, quantities, axis, sweep)

arrays

solve_pin(recipe, pin)

every root and the chosen value, or the attainable range (Recipe.pin_roots)

preview_input(recipe)

pulse and beam arrays on the grid

estimate(recipe)

sizes, memory, rough time

start_run(recipe, folder)

started, progress, plane, stats, warning (the boundary lamp’s among them), log, then finished / stopped / failed (with traceback)

stop(run), kill(run), resume(run)

as above

resumability(file)

the resume mode, or the reason there is none

subscribe(run, views, from_plane)

plane events from that plane on, reduced for the requested views

list_runs()

run summaries

Every request carries an id and the recipe revision it was made for, and every reply and event carries them back. Kernel requests are latest wins: typing in a field cancels the stale validation or summary request it superseded, and because a numerical call already running in the kernel may not stop, the client also drops any reply whose revision is not the current one. start_run captures one immutable, validated revision; editing the setup afterwards never changes a running run.

Bounded work and reliable endings. Every queue between the processes is bounded. Replaceable messages (progress, the latest preview of a view) are coalesced: an undelivered one is replaced by its successor, so a slow client never blocks the worker and never sees a backlog. Terminal events (finished, stopped, failed, errors) are never coalesced or dropped. The worker’s observer only reduces the plane and enqueues; sending happens on another thread, and a broken pipe marks the client disconnected without touching the run (solprop’s observer policy is the second line of defence).

Reduction in the worker. Each live view subscribes to a reduced product (the spectral density on the display’s λ grid in dB, power cropped and reduced to the time window with each bin’s maximum kept, per-mode energies, on-axis spectrum, …), computed in the worker’s plane observer from the plane solprop hands it, to the view’s specification (12.8). A plane of the prototype’s view is a few kB; a 201-plane run a few MB in total — cheap over a pipe or a local socket. The worker keeps every reduced row it has made in memory, so subscribing from_plane=0 replays history from there, without reading the file being written; this is what makes re-attaching (and option C) work. A view whose specification changes during a run is filled from the new rows on, and from the file once the run ends.

Detach. Runs that outlive the window need worker discovery, control ownership and re-attachment, which only option C gives properly. A sidecar of reduced rows (B+) preserves display history but solves none of those, so it is not built unless detach is needed before C (Q4).

Threads. The service gives each worker a thread budget (SOLPROP_THREADS), shows it, and warns when concurrent runs would oversubscribe the machine. The kernel runs with one or two threads.

13.4 Remote, later#

The recommended route needs no new design: the same service runs on the workstation and the GUI connects through an SSH tunnel, or (for clusters) the service submits workers with solprop’s Slurm executor. Until then, remote work is “Export recipe” or “Export as Python”, run by hand, then “Open results”.

13.5 Code structure#

gui/                      the distribution solprop-gui (D2)
  pyproject.toml          its metadata and tool configuration; hatch_build.py pins solprop
  AGENTS.md               the rules for working on it
  src/solprop_gui/
    model/      the editable recipe model over solprop.recipe (undo, dirty state, pins)
    registry/   routes and parameters (presentation over solprop's metadata)
    service/    the service interface; kernel and worker processes; transports
    ui/         main window, step pages, docks, widgets (quantity field, profile editor)
    views/      pyqtgraph views and their matplotlib export counterparts
    help/       page help text and the map to solprop guide pages
    app.py      the solprop-gui command
  tests/

Rules, enforced by gui/tests/test_layers.py:

  • model, registry, service and help import no Qt.

  • The window’s process imports from solprop only solprop.recipe.quantity, paths, document and errors (the quantity parser and writer, parameter paths and the TOML document, light once solprop.recipe imports lazily, section 21). Metadata, capabilities, checks and previews come from the kernel as plain data, which also keeps option C open. Only service imports the rest of solprop, and only its child processes run it.

  • Nothing imports a private solprop name.

Tooling follows solprop’s (uv, ruff, basedpyright, pytest, numpy-style docstrings, GPL-3.0-or-later with REUSE headers), and the quality bar is D11’s. Tests: model and recipe tests without Qt; pytest-qt for widgets; recipe round trips (recipe → build → solprop metadata equals the direct keyword call’s); exported scripts run for ten steps; offscreen screenshot tests of each page. CI runs them as the gui job on Linux, macOS and Windows for every change to gui/ or to solprop itself.

13.6 Distribution#

First pip install "solprop[gui]" (or pip install solprop-gui, or uv tool install solprop-gui), giving a solprop-gui command; it pulls PySide6 (its Essentials distribution) and pyqtgraph, and solprop at the same version; add native for the native backend. It is released with solprop from the same tag; its publication to PyPI waits for a first usable milestone. Standalone bundles (PyInstaller, Briefcase, or a conda constructor installer) come later; the native backend, numba caches and FFTW make them a separate piece of work, best done with solprop’s release packaging.

14. Open questions#

All are decided: Q1 by D8, Q2 by SEP 41 as recommended, and Q3–Q12 as recommended on 2026-11-02 (D10).

#

Question

Decision

Q1

~~Does the recipe live in solprop or only in the GUI?~~

Decided: solprop (D8).

Q2

Recipe values: quantity strings (“125 um”) or plain SI numbers?

Accept both; write quantity strings for readability.

Q3

Process model: B shaped as C (13.3), or straight to C?

B shaped as C.

Q4

Must runs survive closing the GUI in the first release?

Not required; detach comes with option C (13.3), not a B+ sidecar.

Q5

Which routes come first?

Capillary (all three descriptions) and GNLSE, then antiresonant and step-index, then free-space radial, then the rest.

Q6

Help: bundled guide HTML, online, or both?

Both, bundled preferred.

Q7

Name of the application and command.

solprop-gui / solprop-gui; open to better.

Q8

Minimum screen size.

1280 × 800, usable at 1024 × 700.

Q9

Should the GUI ever accept Python snippets (a custom pulse shape, a custom response)?

No; “Export as Python” is the way out.

Q10

Compare-runs in the first release?

Yes, simple overlays of lines; maps later.

Q11

Expose GPU backends (mlx on Apple silicon, device builds)?

Yes, in Advanced, with the precision rule enforced.

Q12

Accessibility targets (keyboard-only use, screen readers)?

Keyboard-complete from the start; screen readers best effort through Qt.

15. Changes proposed to solprop#

D7 allows changing solprop to suit the GUI. These are ordered by value; each would also help script users.

All of them were proposed together in solprop’s SEP 41, Recipes, and the hooks a front end needs, accepted on 2026-11-01 and Final on 2026-11-02. This section is kept as it was proposed; section 21 says where the delivery differs. It rests on SEP 42. The Python interface changes are additive. The SEP refined them:

  • recipe keys are the Simulation.from_* keywords, in one [build] table, with an [execution] table, and parameter paths and pins in format 1; the guide’s example recipes ship in the package (Recipe.example);

  • the recipe is stored as written and as resolved, without an output-schema change;

  • the plane observer is lazy and cannot fail a run, and boundary warnings need no hook of their own;

  • SEP 41 lands after SEP 42, whose comparison decides every resume;

  • S14 adds missing keywords and documents deliberate differences instead of renaming;

  • S15 is documentation only.

Three further changes come from the reviews:

#

Change

Why

S16

Result capabilities: what a results file can give, physical or coordinate, with units and refusals.

Results views offered by what the file stores (11.1).

S17

A portable stop flag and a resumability query.

Stop on every platform; Resume offered only when solprop says it works (4, 10.2).

S18

Previews: Recipe.modes() and Recipe.preview_input().

The explorer and the input preview without building a run (7.4, 9.1).

The original table follows.

#

Change

Why

Size

S1

A recipe module: solprop.recipe with a versioned TOML format covering every route; Recipe.load, Recipe.build() -> Simulation, Recipe.to_python(), and solprop run recipe.toml.

The GUI becomes thin; scripts, clusters and the GUI share one description; physics defaults and rules stay in solprop. Accepted in principle (D8).

Large; its own SEP.

S2

Record the recipe in the output at run start, and resume from a file alone (solprop resume run.h5).

Results reopen their setup; stopped runs resume from the GUI or the shell without the original script. Today the call’s arguments are not recorded and configuration is not reconstructible.

Medium, after S1.

S3

A plane observer: a documented reporter extension that receives read access to the just-saved plane (today plane() gets z and a summary, and reading the output there works but isn’t promised).

Live views stream from a supported hook.

Small.

S4

Progress for scans: a reporter for run_scan (point started/finished, per-point progress).

Live scan progress; today points run with progress off.

Small.

S5

Mode launch on modal routes: a keyword giving energy fraction and phase per mode.

Multimode inputs without building raw arrays.

Small–medium.

S6

Offset and tilt on free-space beams (SpatialPulse), not only through coupling.Alignment.

A beam’s position is an input, not a coupling step.

Small.

S7

Design solvers for any mode: radius from ZDW; pressure from ZDW or RDW for antiresonant, rectangular and slab modes.

Pinned parameters (7.5) on every guided route.

Medium.

S8

A capability query: per route, the allowed options and their incompatibilities; per species, the ionisation models with status and whether Raman exists.

The GUI disables options with solprop’s reasons instead of copying its rules.

Medium.

S9

Machine-readable parameter metadata: unit, range and doc anchor per keyword (e.g. Annotated types or a table beside each interface function).

Tooltips, units and validation without a hand-written copy.

Medium; overlaps S1.

S10

Structured validation: DriverError (and friends) carry the parameter name; a check() that builds and translates, stopping before the backend; grid suggestions from pulses.

Errors next to the right field; Auto grid.

Small–medium.

S11

A cost estimate: Simulation.estimate() → array sizes, memory, and a step-cost figure.

The pre-flight panel and the scan cost.

Small–medium.

S12

Measured-pulse loaders: two-column spectra, FROG/SPIDER retrievals → DataPulse.

Inputs from experiments, in the GUI and in scripts.

Small.

S13

Geometry drawing in the library: move the guide’s cross-section figures into solprop.plotting.geometry, with thumbnails and an explicit palette.

Icons and a live to-scale drawing of the user’s geometry.

Medium.

S14

Harmonise route defaults and keywords: integrators and tolerances differ by route (Multistep at 1e-6 for capillaries, Runge–Kutta at 1e-7 for GNLSE, 1e-5 for waveguides, 1e-4 free space); some keywords exist on one route only (polarisation_taper, interpolate_planes, step_planes).

Where differences are deliberate the GUI shows them as route defaults; where accidental, fix them.

Review first.

S15

Writer-lock sidecars: each run leaves a .writer.lock file beside its HDF5 file after it finishes (seen in the prototype’s runs/).

Either remove it when uncontended or document it; the GUI hides it either way.

Small.

16. Phasing#

Each milestone is an issue, a branch and a pull request (D9), and each waits for the solprop changes section 21 names for it.

Milestone

Content

M0 (done)

Prototypes: NiceGUI and Qt run-and-watch for prop_capillary.

Scaffold (done)

The gui/ distribution in solprop’s repository: packaging and the gui extra, the layer rules and their tests, the gui CI job, this page.

M1 Lifecycle

On the capillary, mode-averaged, only: main window, step bar, summary dock, service with kernel and worker, and the whole run lifecycle end to end — edit, validate, save, export, run, stop, reopen, resume and a simple compare of two runs — with the Overview results layout. It needs the lazy solprop.recipe (21.2). This exercises the architecture more than more forms would.

M2 Explorer

The waveguide explorer, standalone and in the medium page; pinned pressure; multimode capillary.

M3 Guided routes

Antiresonant, full-transverse capillary, GNLSE (Taylor, step-index, tables), rectangular, slab.

M4 Results depth

All views of 11.3 under result capabilities, view specifications and export through solprop.plotting, richer compare.

M5 Free space

Radial, Cartesian, line; spatial views.

M6 Scans

Scan setup, runs, scan browser.

M7 Service out of process

Option C, re-attach, then SSH-tunnel remote.

M8 Distribution

Standalone installers.

17. Lessons from the prototypes#

  • Qt over NiceGUI (D1): the Qt prototype felt like an application, needed no browser stack, and its plots were faster; NiceGUI’s attraction (remote viewing) is better met by option C later.

  • Streaming reduced rows works. A child process sends one row per saved plane (spectrum in dB, cropped power, energy) and the GUI redraws at most four times a second; a fast run never floods the window and a slow one updates as soon as a plane lands.

  • pyqtgraph needs its readouts written (about 70 lines for value boxes on maps and dots on curves), after which they are fully under our control.

  • Matplotlib on demand (prop_2d in a separate window) is a good complement for publication-style figures and needs no reimplementation.

  • solprop’s failures are physics messages. The first “failure” met was BoundaryError (light reaching the time-window edge in a long run). The GUI must present such errors as advice with a fix (“widen the window and rerun”), keep the planes reached, and offer resume only where solprop says it is possible.

  • Stopping by SIGINT is clean on macOS and Linux: solprop finishes the plane, the partial output is saved, and the file stays consistent. It is not portable (Windows terminates the process), hence S17.

18. Design review, 2026-10-31#

Reviewer: Codex (AI). Reviewed this design alongside solprop SEP 41, including its existing AI review, and the relevant solprop source, manual and tests at revision c4cb347. Recommendation: keep the overall architecture, but resolve the contracts below before treating the design as settled. The separation of physics from presentation, document-based setup, Python export, standalone explorer and worker per run are sound. These findings are review comments, not adopted changes to sections 1–17. (The response, with the changes since made, is section 19.)

18.1 Findings#

  1. G1 — major: result capabilities must depend on the stored data and its physical basis (sections 11.1–11.3). The views table marks get_spectral_density, get_power and compression as available on all routes. Solprop’s docs/guide/results/processing.md explicitly warns that the first two accept spatial files but do not return physical energies or powers there; compression refuses spatial and general modal outputs. General modal reconstruction also requires the matching guide and reference tables, which an arbitrary results file need not contain. Recommendation: query result capabilities separately from setup capabilities, accounting for the basis, retained fields, recorded statistics and available references. Open every supported file, but offer only views whose inputs and physical interpretation are available. Label the quantity and measure, including per-unit-width quantities. Ordinary modal get_power reconstructs |b(t)|², which is distinct from the broadband Poynting flux used by recorded temporal statistics; explain that distinction where it matters. Do not assume a mode sum, physical intensity and coordinate intensity are interchangeable.

  2. G2 — major: widening the time window requires a new run, not ordinary resume (sections 4, 10.2 and 17). Changing the window changes the grid and the resume identity. The boundary monitor’s suggested action should be “Widen the window and rerun”. Continuing from a saved field on another grid would be a separately defined remapping operation with provenance and accuracy requirements; it cannot recover light already affected by the old boundary. More generally, a failed run is not necessarily resumable: construction may fail before a checkpoint exists, an interpolated checkpoint requires an explicit policy, and a killed field-free run may have no restart state. Recommendation: determine resume availability from the file and compatibility checks, with a reason when it is unavailable.

  3. G3 — major: distinguish an authored recipe from an immutable run definition (sections 4 and 12.5). Following new defaults and reconstructing an old run are different requirements. Keep the authored recipe, with omissions, units and pins, alongside a resolved definition that freezes effective defaults, solved values, seed and referenced input data. “Open setup from this run” should initially show what ran; adopting current defaults or re-solving constraints is a subsequent explicit action. A simulation changed after recipe construction must not retain misleading recipe provenance. This agrees with SEP 41 review R7. Freezing parameters does not remove the need to check material and environment compatibility.

  4. G4 — major: pins and nested scan targets need a recipe contract (sections 7.5 and 12.7). SEP 41’s keyword-based format does not yet define the pin’s target, solver and resolved value promised here. Define when a pin re-solves, the selected root and search domain, what happens when a target becomes unreachable, and how pins interact with scans and dependent pins. Likewise, “any numeric field” includes a second pulse’s energy or a profile knot, beyond a scan of top-level route keywords. Recommendation: define canonical nested parameter paths and pin semantics before publishing recipe format 1, so these do not become GUI-only scientific setup state. Headless execution and Python export must preserve the chosen interpretation.

  5. G5 — major: the service protocol needs bounded work and revision identities (sections 13.3 and 17). Redrawing four times a second does not bound the message queue, the cost of reducing every plane, or time blocked writing to a slow client. Cancelling an obsolete request does not necessarily interrupt a numerical library call already running in the kernel. Recommendation: bound queues; coalesce replaceable progress and preview updates; reliably deliver completion and errors; attach request IDs and recipe revisions to replies; and reject stale replies even when cancellation fails. Run captures one immutable validated revision. Specify how the writer services historical-plane requests during propagation. Define what happens when an observer or transport fails: a disconnected viewer must not accidentally fail a simulation through an uncaught pipe exception.

  6. G6 — major: stopping needs a portable contract and a separate execution state (sections 4, 10.2 and 13). The prototype uses os.kill(pid, signal.SIGINT). On Windows this is an unconditional termination, not the intended graceful interrupt; the special console-control events have different requirements (Python’s os.kill documentation). Recommendation: define a platform-independent stop request, backed by a tested platform mechanism or a cooperative solprop hook respecting commit boundaries. Keep queued, starting, stopping, disconnected and worker-lost states separate from solprop’s scientific outcome. RunOutcome.status currently has no stopped value. Force-kill requires recovery inspection before describing a file as resumable; n_saved alone does not establish that a restart state exists.

  7. G7 — major: a display product needs an explicit scientific meaning (sections 11.3–11.4 and 13.3). A spectrum in dB needs a reference; independent per-run normalization can conceal energy differences in compare mode. Straight striding can miss narrow temporal peaks. Reduced or clipped arrays cannot also promise full-resolution hover values and quantitative exports. Recommendation: share a view specification between pyqtgraph, Matplotlib export and Copy as Python: quantity, units, selection, normalization, reference, filtering and reduction. Identify display approximations and calculate quantitative exports from the authoritative data. Put scientific reductions in solprop, with checks that they preserve the features and quantities they claim to represent.

  8. G8 — implementation priority: prove the complete run lifecycle early (section 16). The first small capillary milestone should exercise edit, validate, save, export, run, stop, reopen, resume and compare. Bring basic recovery and reopening forward from M4, before broad route coverage: these operations exercise the architecture more thoroughly than additional forms.

  9. G9 — minor: make the free-space nonlinear default an explicit preset (section 8.2). A GUI-only Kerr-on default contradicts principle 1. If this is the intended starting problem, express it as a named solprop recipe preset and show that choice.

  10. G10 — implementation priority: defer B+ unless detach is needed early (section 13.3). A sidecar can preserve selected display history, but does not by itself solve worker discovery, control ownership, additional subscriptions or reattachment. Retain the service interface, but avoid treating a sidecar as the complete lifecycle design for runs that outlive the window.

18.2 Additional SEP 41 findings and an update#

These points supplement the existing SEP review; the recipe vocabulary, explicit None, resolved defaults, field-free observer behaviour and phase-merging policy already have findings there.

  • Launch energy fractions need a basis restriction or a metric-aware definition (S5). On a nonorthogonal general modal basis, physical energy includes cross terms and coordinate energies are not additive. Normalizing fractions to one is insufficient. Restrict the convenience to bases where that interpretation is valid, or define amplitudes and normalize through the actual flux metric.

  • Use the project’s numerical comparison policy (section 7). Ordinary resumed versus uninterrupted runs require an accuracy envelope, not a rounding-only bound; independent observer and non-observer runs do not require bitwise agreement. Copying an observed plane and reading that same stored plane remains an exact structural comparison.

  • The unseeded-noise resume part of R3 is addressed at the inspected revision. Simulation._adopt_recorded_seed now reuses the file’s seed when the caller supplied none. Independent recipe-equivalence tests still need controlled seeds, and resolved provenance remains necessary. Preserve the earlier review as historical evidence, with this update alongside it.

Evidence and limits. This was a read-only design review against the documents, relevant source and existing tests; no simulations or test suite were run for the review. The Windows signal behaviour was checked against Python’s documentation.

19. Response to the design review#

Each finding was checked against solprop at main after its 0.1.0 release preparation, and all ten are taken. The solprop side of G1, G3, G4 and G6 is in the revised SEP 41 (its response answers the same points as C1–C5 and R7); this section says where the design changed.

#

Response

Where

G1

Taken. Views are offered by what the file stores, through solprop’s result capabilities (SEP 41 S16): fields kept per plane, physical flux or coordinate quantity with its unit, available references, refused operations with reasons. The views table now says when each view is offered, and the modal |b(t)|² versus Poynting-flux distinction is stated.

11.1, 11.3, 15

G2

Taken. The boundary fix is “widen the window and rerun”; a changed grid is always a new run; resume is offered only when solprop’s resumability says so, with the reason otherwise. The design’s earlier “widen the time window and resume” was wrong.

4, 10.1, 10.2, 17

G3

Taken. Authored and resolved recipes are separate; “Open setup from this run” shows what ran, and adopting current defaults is an explicit action. solprop writes no recipe for a simulation changed after it was built.

4, 11.1, 12.5

G4

Taken, in solprop. Parameter paths and [pins] (target, search range, root choice, dependency order, cycles refused, re-solved per scan point) are part of recipe format 1 in SEP 41.

7.5, 12.5, 12.7

G5

Taken. Request ids and recipe revisions on every message; stale replies dropped even when cancellation fails; a run captures one immutable revision; bounded queues with coalesced replaceable updates and reliable terminal events; history replayed from the worker’s own reduced rows; transport failures isolated from the run.

13.3

G6

Taken. Stop goes through solprop’s portable stop flag (SEP 41 S17); the GUI’s execution states are separate from RunOutcome.status; a killed run is described as resumable only after resumability.

4, 10.2, 13.1

G7

Taken. A view specification shared by the live view, the export and “Copy as Python”; references for dB stated and shared in compare mode; max-keeping reductions; quantitative exports and scientific reductions computed from the file by solprop.

10.2, 11.4, 12.8

G8

Taken. M1 is now the whole lifecycle on one capillary description; resume and a simple compare move from M4 to M1.

16

G9

Taken. The GUI has no free-space default of its own; new setups start from solprop’s example recipes (added to SEP 41 S1 as Recipe.example), so Kerr and plasma on in the filament example is solprop’s named choice.

8.2

G10

Taken. B+ is dropped as the detach design; detach comes with option C.

13.3, Q4

The §18.2 notes on SEP 41 (launch normalisation on general bases, the comparison classes, the R3 update) are answered in the SEP’s response as C3, R19 and R3, and the launch table of 9.2 follows them.

20. Changes from the second SEP 41 review#

SEP 41’s revision after its supplementary review (G1–G25) changed these parts of this design: the recipe has one [build] table (12.5); the resolved recipe holds what rebuilds the run and not every default (4); a two-value design is a tool and not a pin (7.5); pins resolve in two fixed stages (7.5); the boundary lamp reads warnings, with no observer hook (10.2); run returns when its stop flag stops it (10.2); and resumability also says whether a file can be rebuilt and, on request, whether the gate passes (4, 13.1).

21. What solprop delivered, and what changed here#

Checked on 2026-11-02 against SEP 41’s implementation record (Part II) and its code as merged to main at Final.

21.1 Differences from this design#

Here

Delivered

What the GUI does

A stopped run (4, 10.2)

Simulation.run(stop=) returns when its own flag stops it; the outcome’s status is failed, with “StopRequested: stopped by the caller’s stop flag”

The execution state stopped comes from the GUI’s own flag and the clean return, never from the outcome

A live drawing with quadrature nodes (6.2)

S13 narrowed to outlines: plotting.geometry.outline() gives the cross-section as shapes in metres, each with its region; draw() and thumbnail() paint with Matplotlib and an explicit Palette (LIGHT, DARK)

The kernel sends outline()’s shapes as data and the window paints them; thumbnails are rendered by the kernel and cached per solprop version; no nodes are drawn

Explorer quantities n_eff, β₁, β₂, β₃, γ, D, loss, A_eff (7.4)

Recipe.modes(z) gives each mode’s label, β, β₂, loss, effective area and zero-dispersion wavelength

The rest comes from solprop (21.2, M2), not from differentiating in the GUI

Pins on any guided route (7.5)

Recipe pins on the capillary (with or without a lattice) only: zdw and rdw set radius or a constant pressure, soliton_order sets a pulse’s energy or peak_power; refused on the object routes; a pin on one of pulses is exported as its solved value

Pin switches appear only where solprop’s capabilities offer them

TDSE row (8.1)

A TDSE response is not registered in recipes

Shown disabled, pointing to “Export as Python”

Data pulses from FROG or SPIDER retrievals and temporal fields (9.1)

load_spectrum reads three columns, frequency in Hz, power and phase (SEP 41 Q5); a TimeDataPulse from a file is not registered

Spectral import only, until a temporal loader is registered

The launch table (9.2)

launch, a mapping or a list of mappings, labels such as HE1,1:even, addressed as launch["HE1,1"].share

As designed, with solprop’s labels

Auto grid, the collar (9.3)

solprop.grid.suggest, a stated heuristic; on free space collar_fraction defaults to 0 and spatial_absorber is a table or false (SEP 40)

Auto is labelled as solprop’s starting suggestion; the collar is an opt-in under Advanced

The cost estimate in the summary dock (10.1)

Simulation.estimate() builds the backend and times warm-up trial steps (seconds): memory, output size, the right-hand side’s cost and the calls per step, with no total time

Timing runs on request from the pre-flight panel; a live memory figure needs a size-only estimate (21.2); the rough time uses similar runs in the workspace or says it is unknown

One registry, its metadata from S9 (12.1)

S9 covers the keywords of the gnlse, capillary and waveguide routes and the execution settings; a registered type (Factory) carries units only

Forms for pulse lists, grids, profiles and every free-space table have no summaries, levels or defaults from solprop until 21.2’s P2

The geometry cards (6.1)

No example recipe on the waveguide or radial routes; metal claddings, IndexTable, mode or table objects as the GNLSE fibre, providers and CustomPulse are not registered; a slab set’s per-width units are not in the metadata

A card with no recipe form is shown disabled, with the reason

get_power on spatial files (11.3)

Not physical there yet

The view is offered only where capabilities.output says so

Units (12.5)

ionisation_field_range (V/m) and loss_db_per_m (dB/m) take plain numbers in their stated units

The quantity field also takes a plain number in a stated unit

21.2 What the GUI still needs from solprop#

Change

Needed by

P1

solprop.recipe imports lazily, so its quantity parser and writer, parameter paths and document load without the driver

M1

P2

Per-keyword metadata for registered types: summary, level, default, range, manual anchor and display unit, held to the signatures as S9’s is

M3, M5

P3

A size-only estimate (shape, memory, output size) that builds no backend

M1, if not already possible

P4

ModeSetPreview gains n_eff, β₁, β₃ and γ

M2

—

A waveguide example (#402); metal claddings in recipes (#403); a slab set’s per-width units in the metadata (#404)

M3

—

A radial example (#405)

M5

—

get_power on a spatial output (#406)

M4

—

Registering TimeDataPulse from a file and a TDSE response

after M3