Skip to content

Release v2.11.4

Choose a tag to compare

@github-actions github-actions released this 26 Sep 13:13
· 46 commits to main since this release

Added

  • A file of your own that replaces a packaged one now says so. pfs.checkout
    searches the user library, then the user cache, then what htpolynet ships, and took
    the first hit silently. Overriding a packaged file is supported and often the point;
    the trap is that a copy taken from an older version keeps that version's settings for
    as long as it stays on the search path, and nothing said which file a run actually
    used.

    Found the hard way. A study's npt.mdp, copied from 2.6.2 and edited in one place,
    stayed on its path across four upgrades. From 2.7.0 the packaged file sets
    lincs_order = 8, because at dt = 0.002 GROMACS' default of 4 is marginal --- it
    was fatal on one chemistry in 7 of 7 builds, with exit codes 1 and 139. The stale
    copy reverted every run to order 4, and the instability that produced was written up
    for weeks as a property of the systems being built.

    This bears on the 2.11.3 notes below. "Eleven of twenty builds died in the
    anneal" is the rate from builds carrying that stale mdp, so it overstates what the
    unrelaxed final batch alone causes. The defect and the remedy are unaffected: the
    bond energies entering the anneal are single-point energies of the structure and owe
    nothing to integration settings, and the paired seed test showed the settle helping
    even at LINCS order 4. Only the headline failure rate is in doubt.

  • A ring cure now refuses a ring that would close around an existing bond. CURE
    tests every candidate bond for piercing an existing ring; the ring cure has the
    converse problem and tested nothing at all --- ringcontroller.py had no reference to
    bondtest, pierces_ring or BTRC. A triazine could therefore form around a
    monomer that was already there and thread it permanently.

    That is what the stretched monomers were. Over ten finished builds, six carried a
    threaded triazine, and the threading bonds are the same bonds found stretched past
    2 A: 15 stretched, 13 threading, none threading without being stretched. 10 of 11
    were pre-existing monomer backbone bonds. It explains why those bonds sit on monomers
    that took no part in the ring, why a 160 ps anneal left them unchanged to two
    decimals, and why they hold roughly 700 kT without being thermal --- escaping a
    topological trap needs a bond to break, not a barrier to be crossed.

    The test runs after the closure ladder and before the bonds are formed, which is
    where the question is unambiguous: the loop is down to nearly its final size, so what
    is inside it is what the triazine will enclose. It treats the loop as a triangle fan
    from its centroid rather than as a plane, and images every coordinate against an
    anchor atom, since a centroid of raw wrapped positions gives false positives across a
    periodic boundary.

    ring_cure.prefilter_threaded_candidates applies the same test at candidate time as
    well, to avoid spending a ladder on a ring that is already threaded. It is off by
    default
    , because a candidate loop is three groups a search radius apart: a formed
    triazine's circumscribed radius is about 1.37 A and near enough rigid across 233 of
    them, while the candidate loop encloses roughly nine times that area at a 1.0 nm
    search radius and over twenty at 1.6 nm, which is where late iterations run.
    Threading would carry through the shrink if nothing moved, but the ladder runs six
    stages of NVT at 600 K, so a bond inside the candidate loop need not still be inside
    at closure. Set ring_cure.reject_threaded_rings: false to reproduce the old
    behavior entirely.

    Measured across three arms, same image, no mdp override. Filtered builds came out
    clean 6 of 6; unfiltered builds carried a pierced triazine in 2 of 4 --- 4, 2, 0 and 0
    piercings, a mean of 1.5 each. There is no conversion cost: 0.971 to 0.983 in 21 to
    23 iterations against 0.971 to 0.979 in 20 to 22 without it.

    The closure-time test declined 2, 10 and 1 candidates across three builds, a mean of
    4.3 against those 1.5 piercings. Same order of magnitude with overlapping
    distributions, and that is as much as the data supports: at three builds against four
    the smallest two-sided Mann-Whitney p obtainable is 0.057, so the observed 0.47 is no
    more evidence of agreement than of excess. The two are not the same quantity either
    --- a declined candidate is one that would have threaded, and the alternative
    select_disjoint takes instead may itself thread and be declined in turn, so declines
    bound the piercings prevented rather than counting them.

    The candidate-time prefilter is a different matter: it discarded 1216 to 4385
    candidates per build to catch what the closure test catches in single digits, and both
    arms finished equally clean --- which is why it stays off by default.

Fixed

  • A ring cure ran at constant volume from first ring to last, so it could not
    densify.
    Every ring-cure stage was NVT — the relaxation after each iteration, the
    closure ladder, and the settle — with no constant-pressure step anywhere. Measured
    over 22 iterations of a 233-triazine build, the box stayed at 5.241 nm to four
    decimals and the density at 1155.9 kg/m3 from the first ring to the last, with the
    entire volume change deferred to a single postcure NPT. CURE's density climbs
    through its cure, roughly 1085 to 1170, because its relaxation stages run NPT above
    Tg and are deliberately "the only above-Tg constant-pressure time in a cure".

    Cure shrinkage cannot be reproduced at fixed volume by construction — Snow measures
    0.0324 ml/g for BADCy — and a network that forms in a box which cannot respond
    accumulates internal stress with nowhere to put it, which is a plausible route to the
    stretched bonds recorded in ROADMAP.md.

    ring_cure.relax now mirrors CURE's relax.equilibration exactly --- minimization,
    NVT at 600 K, then NPT at 600 K and 1 bar --- rather than CURE's much longer
    per-iteration equilibration. The whole sequence is above Tg, not just the
    constant-pressure stage: relaxing at 300 K in between two 600 K closure ladders cooled
    the network and would have put a cold, less mobile configuration under the barostat,
    which is a good way to measure no densification and wrongly conclude the stage does
    not work. The closure ladder itself stays constant-volume on purpose: NPT while
    restraints are actively pulling groups together is not a stable combination.

  • A ring cure had no cold equilibration, so once it could move, its box only grew.
    Adding the constant-pressure relax stage above let the box respond, but relax ends
    hot. Measured with relax alone over a full build, the box expands thermally for six
    iterations to +27.9% in volume, then comes back down as the network forms: peak to
    minimum is -7.49% in volume and +71.9 kg/m3. The two legs nearly cancel, so the net
    is near zero and the path length is 0.4104 nm --- a frozen box captures none of it.

    That descending leg is not a measurement of cure shrinkage: 2 ps at 600 K does not
    equilibrate, so it mixes in residual thermal relaxation, and it spans conversion 0.55
    to 0.971. It costs iterations too --- search_radius is an absolute length and does
    not scale with the box, so an expanded box encloses fewer groups per sphere, and the
    hot-only arm needed 25 iterations against 22 for the same conversion. A cure is not only shrinkage --- the hot stages enlarge
    the box and a cold stage pulls it back, and on the pairwise route the box travels
    three to nine times further in length than it ends up moving.

    ring_cure now has an equilibrate stage identical in shape and in defaults to
    CURE.equilibrate --- NPT, 300 K, 1 bar, 50000 steps of 2 fs --- run once per
    iteration after relax, through the same code path the pairwise cure uses, so it
    picks up that route's box logging and density series rather than reimplementing them.
    The per-iteration shape of the two cures is now the same.

    It is also the expensive stage, roughly 99 s against a 280 s iteration. Whether
    100 ps is the right number for either route has never been measured; ROADMAP.md
    sketches the study.

  • Three ring_cure settings could not be set at all, because they were missing from
    the schema, and ycleptic rejects an unknown key outright rather than ignoring it.
    ring_cure.relax and ring_cure.closure.equilibration were never exposed, and
    closure.max_accept — added in 2.11.1 — was written into CURE's drag block by
    mistake, where a config could set it and nothing would read it. All three now sit
    where they belong, and a test asserts that every key the controller honors appears in
    the schema with a matching default.

Changed

  • The installation page now says not to install htpolynet from conda-forge. The
    package published there is several releases behind and cannot currently be updated:
    htpolynet depends on ycleptic, which is not yet available on conda-forge, so the
    feedstock's automatic version bumps produce a package that cannot import and none has
    been published. What is on conda-forge does install and run, so nothing warns a user
    that they have an old htpolynet.

    The conda-only recipe now installs Python and the MD binaries from conda-forge and
    htpolynet itself from PyPI. The warning is scoped to the htpolynet package alone
    --- conda-forge remains the recommended source for AmberTools and Gromacs --- and it
    gives the two commands to check the current state rather than asking the reader to
    trust a page that may itself be stale. The container remains the recommendation, and
    the page now says outright that it requires no installation at all.

Added

  • A build now says so when it hands on a bond that is not a bond any more. At the
    end of a ring cure and again in the final data, any bond longer than 0.2 nm is
    reported, the worst named by atom and residue. Lengths use the minimum-image
    convention, so a bond across a periodic boundary is not counted.

    This exists because such a bond is otherwise silent: the topology is valid, every
    molecule is neutral, and the run completes. htpolynet-study measured a C-C at 3.20 A
    in two of five final structures, unchanged to two decimals by a 160 ps anneal. Ring
    bonds always relaxed; these did not, because they are held by network tension rather
    than by thermal motion — a monomer stretched between parts of the network that a ring
    closure pulled apart, in a ring it was not itself part of.

    This is detection and not a fix; ROADMAP.md has the mechanism and why no remedy has
    been chosen. Anything computed from a structure carrying such a bond inherits it.