Skip to content

SpringSaLaD: user documentation, and a tutorial translated from the standalone guide - #2073

Merged
jcschaff merged 8 commits into
masterfrom
feat/springsalad-docs
Sep 7, 2026
Merged

jcschaff merged 8 commits into
masterfrom
feat/springsalad-docs

Conversation

@jcschaff

@jcschaff jcschaff commented Sep 7, 2026

Copy link
Copy Markdown
Member

vcell.org/webstart/SpringSaLaD/SpringSaLaDUsersGuideAndTutorial.pdf is the odd one out in
the tutorial set. Every other document there describes a VCell workflow that has drifted.
This one describes a different program — a standalone pair of jars, SpringSalad.jar
and LangevinNoVis01.jar, with its own "Langevin Dynamics System Setup" GUI, which tells
the reader to install Java 8 and double-click a jar.

VCell has absorbed the whole of that capability — a SpringSaLaD application on an
ordinary rule-based physiology, the Langevin solver, a Molecular Structures editor
and a 3D Trajectory viewer — and had no user-facing documentation for any of it.
What the help tree had was four scaffolds, all four hidden behind commented-out TOC
entries (#2060).

This PR writes the documentation, unhides it, and adds a verified tutorial script that
translates the standalone guide into the VCell workflow.

The documentation — six pages, all now in the TOC

They were not finished pages waiting for a release. Three had an empty <operations>
section
— the part that tells a reader what to do — and SpringSaLaDTheory.xml was 484
bytes reading "Some text here", "Another paragraph", "Yet another paragraph...".

Page State
SpringSaLaDTheory rewritten from scratch — molecules as spheres joined by stiff springs, what a site carries, the five reaction subtypes, when SpringSaLaD is and is not the right tool
LangevinApp <operations> written — creating the application, the geometry it builds for you, how to resize the box and move the membrane, every Langevin solver option beside the standalone program's name for it
SSSpeciesSpecifications <operations> written — sites, anchors, links, initial conditions, and the ordering rule below
SSReactionsSpecifications <operations> written — the five subtypes and their templates, and the two explanations below
SSResults new — the 3D Trajectory viewer, and how View Data differs between one run and several
SSImportExport new — the .ssld format and what survives a round trip

Two explanations worth calling out

Both are errors a reader meets before they meet the concept.

"The forward rate Kf is too large." The Kf you write down is the macroscopically
observable
rate, and it already contains two steps in series: finding a partner, and
reacting once collided. Their reciprocals add, so the observable rate can never exceed the
purely diffusion-limited one. The solver does not want Kf — it wants the intrinsic rate,
the part conditional on a collision, because collisions are something it simulates rather
than assumes — and it recovers that from Kf and the diffusion limit. If Kf exceeds the
limit, no positive intrinsic rate exists: the model is asking for something physically
impossible rather than merely fast. Raise the diffusion coefficients or radii of the
participating sites, or lower Kf.

The transition condition changes name on the way in, and two of three land on a
different word for the same thing: SpringSaLaD's None (no condition) is VCell's
Any, and its Free (must be unbound) is VCell's Unbound. VCell's own source calls
the terminology "very confusing", because the enum carries three names per value — the
RBM bond type, the table label, and the .lngv name. A reader who picks the label matching
the document gets the wrong condition two times out of three.

The tutorial — springsalad-mapk.sh

Part 1 builds the document's toy model of receptor kinase activation — extracellular
ligand, transmembrane receptor kinase, intracellular substrate — entirely through tables.
0 errors, 0 warnings, asserted from the Problems tab.

The thing worth knowing, and the reason the model comes out right with nothing to correct:
the order of the sites decides which side of the membrane they are on.
SpeciesContextSpec assigns each site a compartment by where it sits relative to the
reserved Anchor site — before it is Extracellular, after it is Intracellular — lays them
out along z in that order, and links them in a chain. So writing the receptor as
RK(B~State0~State1,Anchor~Anchor,K~Off~On) — outside, membrane, inside — is the whole of
the standalone program's 3D-editor section: correct compartments, correct z ordering, and
two springs meeting at the anchor. Written with Anchor first, both domains land inside
the cell and every one of those has to be undone by hand, which is how the first draft
went.

Part 2 does not build the reactions, and cannot — reaction rules have no textual route
(#2068), and .ssld does not rescue it, since that format is the standalone program's
own save file. So it opens a model that already has them: aaa-aSpringSaLaD-Good, a
published model kept in this repo as a test fixture, whose nine rules are one of every
subtype
. It reads each subtype and transition condition back out, runs the Langevin
solver locally with the bundled langevin_x64, and drives the 3D Trajectory viewer
to its last frame.

Bugs found by building it

One is fixed here; three are filed.

  • Fixed (f3b1dc16d4) — a site's Y or Z could not be set to a value equal to its X.
    All three coordinate setters in MolecularTypeSpecsTableModel guarded on
    c.getX() != res; only the X one was right, so Y and Z edits were silently discarded —
    no error, no change, the old value still in the cell. SpringSaLaD molecules are routinely
    laid out along an axis with x = 0, so "put this site at z = 0" never worked. Negative
    control before fixing: z=7 took, z=0 was ignored, z=5 took.
  • SpringSaLaD: exporting an application with no reactions reports success and writes a 0-byte file #2070 — exporting a reaction-less SpringSaLaD application reports "Export saved as
    <path>"
    and leaves a 0-byte file. Three defects stacked: isLangevin() decides
    from the first ParticleJumpProcess, so a model with no reactions is classified
    non-Langevin; LangevinLngvWriter throws; SpringSaLaDExporter.getDocumentAsString
    swallows it in a catch-all returning null; the caller NPEs and still reports success.
  • SpringSaLaD: auto-generated _tot observables land in the wrong structure, and there is no way to move one #2071 — auto-generated _tot observables land in getStructure(0), which for an
    anchored molecule is a standing warning with no remedy but deletion, since the
    Structure column is read-only. Rebuilding one through New > In Membrane swaps it for a
    different warning, because addObservable seeds an empty species pattern that setting
    the definition does not consume. Neither path reaches a clean model.
  • SpringSaLaD: the reserved Anchor site defaults to DARK_GRAY, which is nearly invisible in the trajectory viewer #2072 — the reserved Anchor site defaults to DARK_GRAY, and the trajectory viewer
    draws on black. Every membrane molecule has an anchor, so this is not an unusual
    configuration — it is every membrane molecule in every SpringSaLaD model. The canvas has
    a visible() floor for this, but it only catches near-black; DARK_GRAY (64,64,64) sails
    past it and then loses most of that to the sphere shading.

Changes to production code

Outside the two debug-bridge files, every change is a setName call plus one rename.
setName is an identifier for lookup and affects nothing at runtime.

  • AddLinkButton, DeleteLinkButton, AddStructuralSiteButton,
    DeleteStructuralSiteButton, FirstSiteList, SecondSiteList, AnchorAllButton,
    AnchorOnlyButton, and AnchorStructureCheckBox_<structure> — the last built one per
    structure, so naming it by the structure is the only thing that stays true when
    structures are renamed or reordered.
  • One rename: ModelProcessSpecsPanel's table, ScrollPaneTableReactionSpecsTable.
    It was one of eight tables sharing that name, which made it unaddressable —
    quickstart.sh already worked around it by matching on column headers, and says so in a
    comment that this PR corrects.

The bridge itself is behind -Dvcell.debugBridge=true and ships inert. It gains one verb,
slider, because the trajectory viewer is driven by one and "look at the last frame" is
the single most useful thing a script can say about a result.

Files under vcell-client are CRLF, including TOC.xml; every edit preserves that, and
there is no whitespace-only churn in the diff.

Verification

  • springsalad-mapk.sh exits 0 from a clean client — Problems tab empty, every field
    read back and checked, all seven subtype/condition pairs correct, the Langevin solver run
    locally, and the viewer stepped from frame 1 / 201 t = 0.000 to
    frame 201 / 201 t = 0.02000.
  • DocumentCompiler runs clean over the whole help tree: no error names any of the six
    pages, no unreferenced-image warning names any of the new images. It reports the same
    six errors before and after this branch — four oversized images, and WarningsList /
    SimResultsDataRange unreferenced — none of them touched here.
  • The three pre-existing bridge scenarios still pass (smoke, detach-window,
    detach-window-recorded), and quickstart.sh still reports the same verdict after the
    table rename: 5 claims hold, 3 stale, with the Fast-checkbox check still finding its
    table.
  • mvn test -pl vcell-client -Dgroups=Fast: 37 run, 0 failures, 0 errors.

Images

SS_trajectory.png and SS_solver.png are new, both captured from a real local run.
SS_species.png is replaced — the 2024 one shows a Molecular Structures panel that no
longer exists, with X/Y/Z and Color as fields below the table and Links as a plain list;
they are table columns now, and Links has a Length column. SS_general.png and
SS_reactions.png are still accurate and are kept.

Closes #2060.

🤖 Generated with Claude Code

https://claude.ai/code/session_019HAnpFxkzf9LmxBayDSANf

jcschaff and others added 8 commits September 7, 2026 13:46
All three coordinate setters in the SpringSaLaD site table guarded on
c.getX() != res. Only the X one was correct, so an edit to Y or Z was
silently discarded whenever the new value happened to equal that site's X --
no error, no change, the old value still in the cell.

That is not a rare corner. SpringSaLaD molecules are routinely laid out along
an axis with x = 0, so "set this site's z to 0" never worked, which is one of
the first things anyone building a linear molecule wants to do.

Demonstrated on a site with X=0 before fixing: z=7 took, z=0 was ignored,
z=5 took.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HAnpFxkzf9LmxBayDSANf
…ell editor

Some columns are neither text nor checkbox: they hold a model OBJECT and their
editor is a combo box of the values legal there. The SpringSaLaD site table's
Location column is the clearest case -- it declares Structure.class and its
model does `if (aValue instanceof Structure)` and otherwise returns, so a
String changed nothing and reported nothing.

The editor already holds the legal values, so the string a caller would read
off the screen can be turned back into the object the model wants. Columns
whose editor is not a combo box keep the String, which is what those models
expect -- including the Expression-typed coordinate and radius columns right
next door, which parse text.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HAnpFxkzf9LmxBayDSANf
…ring()

selectList matches on the rendered text, but the /tree dump printed
String.valueOf(model.getElementAt(i)). Where a renderer shows something else,
the dump named items that could not then be selected -- the SpringSaLaD Add
Link dialog is exactly that: its lists render a site's name while toString()
gives "name~state", so "Anchor~Anchor" appeared in the dump and
list <path> "Anchor~Anchor" silently selected nothing.

Same defect the table row text had before, and the same fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HAnpFxkzf9LmxBayDSANf
setName additions only, plus one rename. Nothing looked any of these up by
name, so nothing changes at runtime; they are identifiers for anything that
has to address the SpringSaLaD editors from outside.

  AddLinkButton, DeleteLinkButton, AddStructuralSiteButton,
  DeleteStructuralSiteButton   - MolecularStructuresPanel
  FirstSiteList, SecondSiteList                 - AddLinkPanel
  AnchorAllButton, AnchorOnlyButton,
  AnchorStructureCheckBox_<structure>           - MolecularTypePropertiesPanel

The anchor checkboxes are built one per structure, so naming them by the
structure they stand for is the only thing that stays true when structures are
renamed or reordered.

The rename is ModelProcessSpecsPanel's table: "ScrollPaneTable" ->
"ReactionSpecsTable". It was one of eight tables sharing that name, which made
it unaddressable - quickstart.sh already works around it by matching on the
column headers instead, and says so in a comment.

Files under vcell-client are CRLF; the additions preserve that.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HAnpFxkzf9LmxBayDSANf
The SpringSaLaD trajectory viewer is driven by one. Its frame slider is the
time axis of a finished run, and "look at the last frame" is the single most
useful thing a script can say about a result - a trajectory at t=0 is the
initial condition, which is the one moment that tells you nothing.

A drag cannot be synthesised usefully, because the knob's pixel position is a
function of the slider's own geometry, so the value is set on the model, which
fires the same ChangeEvent a drag would.

Takes an integer, or min/max, or -1 meaning the maximum - the same "-1 is the
end" convention readcell already uses for the last row of a results table.
Values outside the range are clamped rather than refused: a caller asking for
frame 10000 of a 201-frame run means the end.

Not recorded by UiRecorder, which does not observe sliders at all - a human
dragging one is not captured either, so nothing is lost that was there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HAnpFxkzf9LmxBayDSANf
SpringSaLaDUsersGuideAndTutorial.pdf is not an outdated VCell tutorial. It
describes a DIFFERENT PROGRAM - a standalone pair of jars with its own
"Langevin Dynamics System Setup" GUI, which tells the reader to install Java 8
and double-click a jar - and VCell has since absorbed that capability as the
SpringSaLaD application and the Langevin solver. So this script is a
translation rather than a re-enactment, and the storyline carries the
noun-by-noun mapping: site types to molecular components, "Set as 2D" to the
Is 2D column, the cube with a membrane at z=0 to a 3D analytic geometry, the
Simulation Manager to the Simulations tab, the 3D Viewer to the 3D Trajectory
tab, and the plain-text system file to .ssld.

PART 1 builds the document's toy model of receptor kinase activation - an
extracellular ligand, a transmembrane receptor kinase, an intracellular
substrate - entirely through tables. 0 errors, 0 warnings.

The thing worth knowing, and the reason the model comes out right with nothing
to correct: THE ORDER OF THE SITES DECIDES WHICH SIDE OF THE MEMBRANE THEY ARE
ON. SpeciesContextSpec assigns each site a compartment by where it sits
relative to the reserved Anchor site - before it is Extracellular, after it is
Intracellular - lays them out along z in that order, and links them in a
chain. So writing the receptor as RK(B~State0~State1,Anchor~Anchor,K~Off~On),
outside/membrane/inside, is the whole of the standalone program's 3D editor
section: correct compartments, correct z ordering, and two springs meeting at
the anchor. Written with Anchor first, both domains land inside the cell and
every one of those has to be undone by hand, which is how the first draft of
this script went.

PART 2 does not build the reactions, and cannot: reaction rules have no
textual route (BioModelEditorReactionTableModel.isCellEditable allows the BNGL
column only for a ReactionStep, and the rule editor is a single anonymous
custom-painted component with zero children - issue #2068). .ssld does not
rescue it either: that format is the standalone program's own save file, so
writing one by hand means writing the whole system, and learning it by
exporting first hits #2070.

So Part 2 opens a model that already has them - aaa-aSpringSaLaD-Good, a
published model kept in this repo as a test fixture, whose nine rules are one
of every subtype - reads each subtype and transition condition back out, runs
the Langevin solver locally with the bundled langevin_x64, and drives the 3D
Trajectory viewer to its last frame.

Three bugs found on the way, all filed:

- #2070 exporting a reaction-less SpringSaLaD application reports "Export
  saved as <path>" and leaves a 0-byte file.
- #2071 auto-generated _tot observables land in getStructure(0), which for an
  anchored molecule is a standing warning with no remedy but deletion - and
  rebuilding one through New > In Membrane swaps it for a different warning.
- #2072 the reserved Anchor site defaults to DARK_GRAY and the viewer draws on
  black. Every membrane molecule has an anchor, so the script gives every site
  a light colour and says why.

A fourth was fixed rather than filed, in f3b1dc1.

Also corrects a comment in quickstart.sh that this branch made stale: the
Specifications > Reaction table is no longer one of eight called
"ScrollPaneTable". The check still matches on column headers, because that is
what it was verified against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HAnpFxkzf9LmxBayDSANf
VCell has had a SpringSaLaD application, a Langevin solver, a Molecular
Structures editor and a 3D trajectory viewer for some time, and no user-facing
documentation for any of it. What the help tree had was four scaffolds, all
four hidden behind commented-out TOC entries (issue #2060).

They were not finished pages waiting for a release. Three had an EMPTY
<operations> section - the part that says what to do - and SpringSaLaDTheory
was 484 bytes reading "Some text here", "Another paragraph", "Yet another
paragraph...". So there was nothing provisional to protect.

Six pages now, all in the TOC:

- SpringSaLaDTheory, rewritten from scratch: molecules as spheres joined by
  stiff springs, what a site carries, the five reaction subtypes, and when
  SpringSaLaD is and is not the right tool.
- LangevinApp: creating the application, the geometry it builds for you, how
  to resize the box and move the membrane (two independent edits - the extent
  and the Intracellular expression), and every Langevin solver option against
  the standalone program's name for it.
- SSSpeciesSpecifications: sites, anchors, links, initial conditions, and the
  rule that decides everything - site order relative to Anchor is what puts a
  site inside or outside the cell.
- SSReactionsSpecifications: the five subtypes and their templates, the
  reversibility rules, and two things a reader will otherwise hit blind (below).
- SSResults, new: the 3D Trajectory viewer, and how View Data differs between
  a single trajectory and multiple runs.
- SSImportExport, new: the .ssld format, what does and does not survive a round
  trip, and why an application with no reactions cannot be exported.

Two explanations worth calling out, because both are errors a reader meets
before they meet the concept:

"The forward rate Kf is too large." The Kf you write down is the
MACROSCOPICALLY OBSERVABLE rate, and it already contains two steps in series:
finding a partner, and reacting once collided. Their reciprocals add, so the
observable rate can never exceed the purely diffusion-limited one. The solver
does not want Kf - it wants the INTRINSIC rate, the part conditional on a
collision, because collisions are something it simulates rather than assumes -
and it recovers that from Kf and the diffusion limit. If Kf exceeds the limit
no positive intrinsic rate exists, and the model is asking for something
physically impossible rather than merely fast. Fix by raising the diffusion
coefficients or radii of the participating sites, or by lowering Kf.

The transition condition changes name on the way in, and two of three land on
a different word for the same thing: SpringSaLaD's "None" (no condition) is
VCell's "Any", and its "Free" (must be unbound) is VCell's "Unbound". VCell's
own source calls the terminology "very confusing", because the enum carries
three names per value. A reader who picks the label matching the document gets
the wrong condition two times out of three.

Images: SS_trajectory.png and SS_solver.png are new, both captured from a real
local run. SS_species.png is REPLACED - the 2024 one shows a Molecular
Structures panel that no longer exists, with X/Y/Z and Color as fields below
the table and Links as a plain list; they are table columns now, and Links has
a Length column. SS_general.png and SS_reactions.png are still accurate and
are kept.

Verified: DocumentCompiler runs clean over the tree - no error names any of
the six pages, no unreferenced-image warning names any of the new images. The
seven errors it does report are all pre-existing (four oversized images, and
WarningsList / SimResultsDataRange unreferenced), none of them touched here.

TOC.xml is CRLF and was patched in binary mode.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HAnpFxkzf9LmxBayDSANf
A SpringSaLaD site's z runs from outside to inside - an extracellular site
sits at a smaller z than the anchor, an intracellular one at a larger z. The
geometry's Intracellular expression runs the other way, "z < number", and a
reader who takes both for the same frame will try to reconcile two numbers
that have nothing to do with each other.

They do not: the solver is told both a site's compartment and its offset
within its molecule, and places the molecule accordingly. Says so, and cites
the standalone tutorial's own wording for the convention.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HAnpFxkzf9LmxBayDSANf
@jcschaff
jcschaff merged commit 3988a67 into master Sep 7, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SpringSaLaD help pages exist but are unreachable: four TOC entries are commented out

1 participant