Repository navigation
v2.5.8
This release closes the GUI to other machines and other sites, and fixes
results that 2.5.7 could get wrong without a warning. Off loopback the GUI
serves only the watched run's results, text from a study is shown as text, a
reply from the Agent alone no longer starts a run, and a page on another site
can no longer drive the GUI. A molecule away from the protein is measured in
its nearest periodic copy; the correlation time no longer misses a slow mode,
so standard errors and withheld verdicts can differ from 2.5.7's where frames
alternate; interaction rows are named by chain; a ligand's pose is matched
atom for atom; a stated cutoff is kept; and umbrella studies, which 2.5.7
refused, run again. Some studies that ran under 2.5.7 now stop with a reason:
a ligand whose net charge cannot be read, a ligand pose the structure holds and
cannot give, and an ion whose alternate locations tie. For services that run
FastMDXplora for other people, the GUI can be served behind a proxy that signs
people in, each release is published as a Docker image, and fastmdx resume
carries a stopped study on to its end. AmberTools is now a declared
dependency, and Windows is no longer supported.
fastmdx resume carries a stopped study on to its end
A study stopped part-way, by a restart, a time limit or a GPU taken back, is
finished by one command. fastmdx resume STUDY reads how far it got and does
what is left, once: nothing if it finished; the analyses and report if
production did; the rest of production from the last sealed checkpoint if it
had begun; the whole study again if it had not. It refuses a study still
running and one that stopped with a refusal, unless the refusal is marked worth
retrying, and it does not discard production it cannot continue. Running it
twice does the work once, so a service can run it whenever a job restarts;
--json prints the outcome for a program. The help for
checkpoint_interval_steps and the runner's notes no longer say there is no
resume.
A Docker image with each release
Each release is published as ghcr.io/aai-research-lab/fastmdxplora:<version>,
beside the Apptainer image on the release page, for services that run
FastMDXplora in containers. It is written from container/fastmdx.def by
container/docker_from_def.py, so the installation and the checks that fail a
bad build are the Apptainer image's own, and a study gives the same answer in
either. It runs as a user that is not root, with /workspace as its home and
working folder. See docs/hosting.md.
The GUI can be served to other people
fastmdx gui --hosted serves the GUI behind a proxy that signs people in.
It answers only requests carrying the proxy's secret (read from
FASTMDX_PROXY_SECRET), only under the names given with --allowed-host, and
only inside --workspace: every path a request names is read there, one
outside it is refused, and answers show paths as ~/..., never the server's
layout. It refuses to start without a secret, a name, or with the top of the
file system as its workspace. Nothing changes without --hosted. See
docs/hosting.md.
Python continues a study as the command line does
simulation.resume_from naming a study directory was a continuation only on
the command line. From Python the same config went to the batch layer, which
refused it for naming no system. FastMDXplora(config=...).explore() now
extends the study in place as fastmdx explore does, with duration_ns the
total and extra_ns an amount more, returns one result for the study, and a
dry run says what it would run. A segment that fails is reported as a failed
simulation rather than as a join that could not be made.
A ligand pose the structure holds and cannot give is refused
With ligand_pose: auto, a structure holding a residue of the ligand's name
whose pose could not be taken fell back to the supplied file's coordinates:
a different atom count, bonds that do not match, fewer copies than ligands,
or a structure that would not read. On a complex that starts the ligand away
from its site, the seventeen-Angstrom failure, with a log line to say so.
Setup now refuses (setup.ligand.pose_unavailable) and says to use
ligand_pose: file where the file's pose is the one meant. The file's pose
still stands where the structure holds no residue of that name, or where
there is no structure at all.
One segment number is one folder
segment-1 and segment-001 were both segment one. The join held
whichever listed later and a continuation resumed from whichever it met
first. Two readers also rebuilt a segment's folder from its number as
segment-NNN, so a folder named segment-1 was counted and never read: its
production was left out of what was done, and a killed one's frames were not
trimmed. Two folders with one number are refused
(simulation.resume.segment_named_twice) with both named, and every reader
uses the folder it found.
The Agent is told one thing, whichever way it is asked
- Attempts. The command line gave the Agent three attempts in all and
its help called them corrections, which would be four; the browser and
Python gave four. It is three in all, the first included, everywhere. - Continuing a study. The prompt told the Agent to continue a study by
naming it inresume_from, withduration_nsthe total production it
should end with. The browser's run status handed it the raw checkpoint
form instead, withduration_nsthe amount more, which ran as a separate
study and joined nothing. The browser now offers the study form. A config
continuing a study is run inside that study, its segments joined and its
analyses rerun, and the GUI watches the study while it does: it had
watched a new, empty folder and marked the run failed. The config is kept
under the workspace'scontinuations/, so the study's own record of how
it was started is not replaced.
The records and pages say what happened
- The methods said each heterogen decision was recorded in
setup_parameters.json; it was only logged. The decisions, with their
reasons and copies, are now written there asheterogen_decisions, and the
sentence appears only where they are. - The report's settings list said "Production MD was performed" of a study
that ran none (duration_ns: 0). - The GUI showed studies that finished as failed. Every study was held to
a prepared system in its ownsetup/and a finished simulation, so an
analysis of a supplied trajectory, a setup-only study, a run given
setup_fromand a study of several runs failed on exit; a run the GUI
adopted was judged by a Manifeststatusthat does not exist. A study is
now held to the phases it recorded, and a failure names the phase or the
runs that failed. - A slide deck that could not be written was said at debug level and
recorded nowhere. It is recorded innot_produced.jsonbeside a missing
PDF, each entry with the codereport.format.unavailable.
Each sugar and each ion is judged by its own bonds
A free sugar was discarded as a glycan when another copy of its name was on
an asparagine. Whether a sugar belonged to a glycan was decided per residue
name, and an inner sugar counted as glycan whenever the structure was
glycosylated anywhere, so a NAG in an active site beside a glycosylated
asparagine, or a lactose bonded only to itself, was removed without a
question. The glycan is now followed from the protein, sugar by sugar,
through the LINK records; a component with glycan copies and free copies
stops and names both. An ion LINKed only to a water was kept as
"coordinated by the protein", 30 A from it: a LINK now counts only to a
partner that stays in the system, and the reason names it. An NMR entry's
heterogens were counted once per model, so a zinc read as twenty atoms and
setup asked for an SDF; only the first model, the one prepared, is read.
Present in 2.5.6 and 2.5.7.
A moved study still finds the system it simulated, and only that one
A run given setup_from recorded the prepared system by path alone, as it
was typed. Moving or copying the study, or fetching it to another machine,
left re-analysis, the report and replica comparison unable to find it, and a
different prepared system at the old path was used without a word: its
ligand chemistry and atom count described atoms the run never simulated. The
run now records the system as given, as resolved, relative to itself and by
the SHA-256 of its system.xml, finds it relative to the run first, and
refuses a system whose content differs (analysis.data.not_this_system). A
campaign's manifest lists members relative to the campaign, and aggregation
and the comparison report read them that way. The GUI and the cross-tool
comparison read the setup record of the system a run simulated rather than
the run's own setup/, which a run given setup_from does not have. Present
in 2.5.6 and 2.5.7.
A ligand's pose is taken atom for atom
With the pose taken from the structure, the supplied file's heavy atoms took
the crystal positions in the order the two files happened to list them. Only
the count was checked, so two files listing the atoms differently put atoms
on each other's places: a C-C bond of 1.5 A came out at 3.0 and 4.5 A with no
error, since the clash check measures the ligand against the protein, not
against itself. Each atom now goes to the crystal atom of the same element
bonded to the same neighbours, the crystal's bonds read from its geometry;
where symmetry allows more than one answer, the one that fits the supplied
geometry best is taken. A residue whose atoms cannot be matched that way is
not used as the pose: ligand_pose: structure refuses, auto keeps the
file's coordinates and says why. Present in 2.5.6 and 2.5.7.
duration_ns: 0 equilibrates and stops
duration_ns is the production length, so zero now means no production: the
study is set up, minimised and equilibrated, and ends there. The runner read
zero as unset and ran the default 2 ns, while the cost estimate counted none.
The analysis phase of such a study is recorded as skipped, with the reason,
rather than as completed, and the methods paragraph says no production was
run instead of describing coordinates that were never written.
A ligand charge that cannot be read is refused
A supplied ligand whose net charge could not be read went ahead as
"unknown", and a stated ligand_net_charge went into the record unchecked.
Formal charges in an SDF or MOL2 are whole numbers, so failing to sum them
means the file was not read as the chemistry it describes, and the check that
refuses a stated charge the file contradicts was skipped in exactly that case.
Setup now refuses with setup.chemistry.charge_undetermined and says to check
the file's hydrogens and formal charges. Present in 2.5.6 and 2.5.7.
A stated zero equilibration is zero
npt_duration_ns: 0 ran a nanosecond of NPT and recorded NVT. The runner
read a zero equilibration length as unset and ran the default, while the
ensemble resolver, the cost estimate and the run's record read it as no stage:
the record said constant-volume production of a run that produced at constant
pressure. nvt_duration_ns: 0 ran the default 500 ps the same way. A stated
zero is now zero everywhere, as npt_steps: 0 always was. Present in 2.5.6 and
2.5.7.
Re-analysing an older run keeps the version that produced it
A Manifest merged onto one from before phases recorded their version lost
it. Re-analysing a 2.5.4 run under 2.5.7 left "version": "2.5.7", no
versions_seen, and nothing saying the trajectory came from 2.5.4. A phase
carried over without produced_by now gets {"version": <the version that wrote the Manifest it was in>, "inferred": true}, and versions_seen keeps
every version recorded before, including one whose phases have all been
re-run since.
An interaction is counted for the chain it happened in
pl_interactions added the same residue of two chains together. Its
residue rows and pair rows were named by residue name and number alone, so on
a dimer the frames in which a ligand touched SER45 of either chain were one
row with one occupancy, and 184 and 184A of one chain merged the same way.
Rows are now named by chain where there are several (A:SER45) and by
insertion code (GLY184A), as pl_contacts already named them, from one
helper for both. A single chain without insertion codes reads as before.
Present in 2.5.6 and 2.5.7.
Frames that alternate no longer read as independent
A slow correlation under a fast, alternating one was invisible. The
statistical inefficiency summed the autocorrelation lag by lag and stopped at
the first lag that was not positive. A stiff restraint sampled more slowly
than the mode it restrains makes consecutive frames anti-correlated, so the
sum stopped at lag one and every frame counted as independent: on a series
whose true inefficiency is 120 it returned 1.0, and the halving test then
called the correlation resolved. 21 of the 35 windows of the benzamidine
unbinding study reported a correlation time they could not have measured. The
sum now runs over adjacent pairs of lags (Geyer's initial positive sequence),
which recovers the slow part and gives the same answer as before where
nothing alternates. Standard errors, block lengths and the resolved verdict
all follow. The message withholding an error now quotes the replica
calibration: one run's error was about ten times smaller than the spread of
ten replicas. Present in 2.5.6 and 2.5.7.
A molecule away from the protein is measured beside it
A ligand that had left the pocket could be measured a box length away.
Loading a trajectory made every solute molecule an anchor, and an anchor
stays in whichever periodic copy the engine wrote it. The radius of gyration,
SASA or RMSD of a selection holding such a ligand was then measured from the
wrong copy: on the T4 unbound control, 150 of 2,000 frames, the radius of
gyration of protein and benzene off by up to 0.028 nm. The protein and nucleic
chains now anchor, and every other solute molecule is moved to the copy
nearest them, searched exactly, in any box shape. A bound ligand is unchanged.
Present in 2.5.6 and 2.5.7. The choice of anchors also works on the older
MDTraj that Python 3.10 installs, where asking whether a residue is nucleic
raises, and if the placement fails the molecules are still made whole.
Off loopback, only the run's results leave the machine
2.5.7 bound beyond loopback served the Agent's conversations, and with no
run open, text files under the folder the GUI was started in.
The conversation routes are refused off loopback, but 2.5.7 keeps a study's
conversations inside it, at agent/conversations/, and /artifacts/,
/api/file-text and the file list served everything in the study. With no
run open, /api/file-text read under the workspace, which is wherever
fastmdx gui was typed; from a home folder that reached the API key
the Agent stores in ~/.config/fastmdxplora/model.json. 2.5.6 had neither.
Off loopback every GET is now refused unless it is listed, as every POST
already was; the list is what watching a run needs. Files are served there
only from the run being watched, only from a folder FastMDXplora wrote, and
never a hidden file or the Agent's conversations, which the file list no
longer offers on loopback either. The Files preview reads the run being
watched, never the workspace. A viewer off loopback can no longer have the
preview or the playback rebuilt, or ask for more frames than the server was
started with. A dashboard on loopback, the default, was not exposed.
Text from a study is shown as text
A name in a study could run script in the GUI. The report page and the
Files preview rendered Markdown with its raw HTML, and a link could be
javascript:. A report quotes the names a structure file and a config
give, and the preview renders any .md in a study, so a name carrying
<img onerror=...> ran as the GUI, which can start runs and read the
Agent's conversations; the overview loads the report, so opening the study
was enough. A link in the Agent's reply could close its own attribute and
add a handler. An HTML file in a study was shown in an unsandboxed frame,
with the GUI's standing.
Raw HTML in Markdown is now shown as written, and a link or image goes only
to the web, to mail or within the study; the PDF is rendered the same way,
so a name cannot have WeasyPrint fetch or attach a local file. A reply's
link ends at a quote. HTML, SVG and XML files from a study are served, and
framed, in a sandbox of their own: their scripts run and cannot reach the
GUI. The report's interactive page, opened from the GUI, therefore no
longer remembers its card sizes between visits. Present in 2.5.6 and 2.5.7.
A model's reply alone does not start a run
In the GUI's Agent, DO: run in a reply pressed Run. The only rule
against acting unasked was in the prompt, and the model reads the files a
person attaches, so a file could tell it to start work on the machine. The
server now reads the person's own message: a plain instruction, such as run
it or go ahead, runs as before, and any other DO: run asks Run the study
above? Say yes. and waits, as a stop always has. Present in 2.5.6 and 2.5.7.
A page on another site cannot drive the GUI
Any website open in the person's browser could use the GUI on loopback.
A browser sends requests to 127.0.0.1 for any page, and the server
answered whatever reached it: a form posted as text/plain could switch the
served folder, store a model and key, or start a run, and a name made to
resolve to 127.0.0.1 let a page read the answers, conversations included.
On loopback the server now answers only to a loopback name, and it refuses a
POST whose Origin is not its own and an API request the browser marks as
cross-site. Scripts and curl, which send no Origin, are answered as
before. Present in 2.5.6 and 2.5.7.
A ligand is given its charges on a fresh install
A fresh conda-forge install of 2.5.7 could not parameterize any ligand.
A ligand parameterized with an OpenFF or GAFF small-molecule force field,
which includes the default stack, takes AM1-BCC partial charges, and the
OpenFF toolkit computes them by calling AmberTools' sqm. conda-forge's
openff-toolkit no longer depends on AmberTools and FastMDXplora never
declared it, so a new environment had nothing to compute them with. Setup
repaired and solvated a protein-ligand system and then failed with the
toolkit's own error, "No registered toolkits can provide the capability
assign_partial_charges", which names neither the charge model nor the
package that was missing.
AmberTools is now a run dependency of the conda-forge package, and is in
environment.yml and the container image, whose build charges a small
molecule and fails if it cannot. fastmdx info reports AM1-BCC charges,
naming AmberTools or OpenEye where one will compute them and
conda install -c conda-forge ambertools where nothing will; info --json
carries the same row, so fastmdx remote counts a machine without it as not
ready and adds AmberTools to that environment. Where nothing can compute the
charges, setup refuses as soon as it knows the study has a ligand, before
PDBFixer or solvation, with setup.environment.charges_unavailable and the
install command. A study without a ligand is unaffected. From PyPI,
AmberTools has to come from conda-forge alongside the OpenFF toolkit.
AmberTools is found without activating the environment
The OpenFF toolkit looks for AmberTools on PATH, once, when it is first
imported. Running the environment's Python by its full path, as a script, a
batch job or a command sent over ssh does, left the environment's own
programs off PATH, so AmberTools was installed and a ligand still could not
be given charges. Importing FastMDXplora now puts the directory holding the
running interpreter's programs at the end of PATH when it is missing.
Windows is no longer supported
Continuous integration, the package metadata and the documentation now cover
Linux and macOS only, because AmberTools, which every ligand needs for its
charges, has no Windows build. The classifiers name Linux and macOS in place
of "OS Independent", the Windows legs are gone from the test matrix, and the
installation guide says Windows is not supported. fastmdx info states the
platform, and on Windows says plainly that it is not supported; nothing
refuses to run there.
An umbrella study runs again
2.5.7 refused every umbrella study before it started, saying "from is
missing". Each window was checked as though a person had written it, after
the study had been expanded into windows that carry a centre and an index in
place of the study's from, to and n_windows. The study is still checked
as it was written, before it is expanded; the windows made from it are not
checked a second time. Present in 2.5.7 only.
An occupancy tie is decided by one rule
An ion written at two alternate locations of one residue took the first
where they tied, and the higher however slight the lead, while the same tie
between two residues, or between a ligand's conformations, stopped setup. It
now stops too, and a lead of less than 0.10 is a tie for all three. The
0.10 tolerance was compared in floating point, so occupancies of 0.55 and
0.45 resolved while 0.60 and 0.50 tied; both differ by 0.10, and both now
resolve. Present in 2.5.6 and 2.5.7.
A stated cutoff or switch is kept
nonbonded_cutoff_nm: 1.0 written in a config was ignored for CHARMM36. The
schema handed over 1.0 nm and a switching function whether or not anybody wrote
them, so setup could not tell a stated 1.0 nm from silence: the run used the
force field's 1.2 nm, and a stated use_switching_function was replaced by the
force field's either way, each with only a log line. The record kept the
schema's 1.0 nm, so the methods paragraph of a CHARMM36 run cut off at 1.2 said
1.0. Both settings now default to unset: the force field decides only then,
what it decided is recorded in setup_parameters.json and
resolved_config.yml, and a stated value is kept even where it equals the
force field's own. The GUI offers the switch as default, on or off rather than
a checkbox that read "off" for a run that switched. Present in 2.5.6 and
2.5.7.
The banner shows a Python study's own setup
The run's opening banner read its setup values only from a config named on the
command line, so a study given from Python announced pH 7.4 and the automatic
force field while it prepared at the pH and with the force field it was given.