[us-commits] [ehb54/ultrascan3] 7da8a3: somo/grpy: raise the shell-reduction error floor t...

emre brookes noreply at github.com
Mon Aug 17 20:40:58 MDT 2026


  Branch: refs/heads/ehb54-issue-980
  Home:   https://github.com/ehb54/ultrascan3
  Commit: 7da8a315fa7ef14a7830927cdef90989f72fc445
      https://github.com/ehb54/ultrascan3/commit/7da8a315fa7ef14a7830927cdef90989f72fc445
  Author: Emre Brookes <emre.brookes at umontana.edu>
  Date:   2026-08-15 (Sat, 15 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_shell.hpp

  Log Message:
  -----------
  somo/grpy: raise the shell-reduction error floor to 0.75 of the raw gap

The estimate is max(safety * Richardson remainder, floor * raw inter-rung gap).
Validating the full 23-model grid with all five observables -- the previous
multi-observable grid ran only 12 of the 23 models, so eleven never had intrinsic
viscosity or rotational diffusion checked -- exposed two evaluations that passed
the estimator's stop test yet missed the requested tolerance (2GD1 intrinsic
viscosity at 1%: estimate 0.859%, true error 1.066%), plus eleven more that were
compliant but undercovered.

Tolerance compliance is a subset of estimator coverage: the ladder stops when the
estimate falls below the tolerance, so an estimate that covers the true error
makes stopping imply compliance. Verified on the grid -- no row missed its
tolerance while covered, and all 235 reduced rows converged.

Raising the floor rather than `safety` is deliberate. The two terms are combined
with max(), so while the floor binds the safety factor does nothing: with a
doubling ladder and the order at k_max = 3 the remainder is gap/7, and
safety * gap/7 stays under 0.5 * gap for any safety <= 3.5. Measured on the same
grid, safety = 2.0 fixed neither failure and drove the median case to retain every
bead, because it inflates the estimate for the well-behaved majority where the
floor is slack. The floor acts only on the high-observed-order rows that fail.

At 0.75 the grid is clean: 200/200 reduced evaluations inside their tolerance and
all 200 covered, worst case spending 55.3% of the allowed budget (was 106.6%), for
4.6 percentage points more beads retained on average.

floor_frac is exposed on ShellOptions rather than left hardcoded, alongside k_min,
k_max and safety. Measuring it required patching a private copy of this header,
and a second copy of an estimator is what makes validation results unattributable.

The file's own MEASURED note claimed 92/92 and 252/252; both were wrong (seven
observables counted, three research-only; and the narrow model grid). Corrected to
what this code actually returns -- the finest rung, not the extrapolation.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>


  Commit: 69e372e6764e086a32759607f45e67c2831da51f
      https://github.com/ehb54/ultrascan3/commit/69e372e6764e086a32759607f45e67c2831da51f
  Author: emre brookes <ehb54 at users.noreply.github.com>
  Date:   2026-08-15 (Sat, 15 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_shell.hpp

  Log Message:
  -----------
  Merge pull request #515 from ehb54/ehb54-984-floor

somo/grpy: raise the shell-reduction error floor to 0.75 of the raw gap


  Commit: 6274fe15b2945427c5b165214cc1ac603a418673
      https://github.com/ehb54/ultrascan3/commit/6274fe15b2945427c5b165214cc1ac603a418673
  Author: Emre Brookes <emre.brookes at umontana.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_exposure.hpp
    M us_somo/develop/grpy/grpy_shell.hpp

  Log Message:
  -----------
  somo/grpy: raise the exposure quadrature to 512 points per bead

The exposure point pattern is generated once in the coordinate frame and applied to
every bead by translation and scaling, so it does not rotate with the structure. A
rigid rotation therefore changes 34-77% of bead exposures by a few of the K sample
points and changes the ranking. A translation-only control is completely inert and
the unreduced result is invariant to zero parts per million, so this is the
quadrature, not arithmetic.

The effect reaches the answer almost entirely through the stopping decision, not
through which beads are kept: where the ladder stops at the same rung in every frame
the reported value moves by at most 0.075%, and where the orientation flips the rung
by one it moves by up to 1.043% -- a ratio of roughly fourteen, replicated on two
independent grids.

Measured over twelve rigid motions of six models, matched but for K: at 64, one case
of eighteen changed its stopping rung and the frame-to-frame spread reached 0.23%; at
512, no case changes rung and the spread falls to 0.016%. Retained beads are unchanged
(mean 31.5% vs 31.3%), and compliance and coverage are perfect at both values, so the
finer quadrature costs only exposure time -- about 3% of the ladder, exposure being
milliseconds against a solve of seconds.

This does not make selection frame-independent; subsets still differ in nearly every
frame. It makes the delivered result about 14x less sensitive to orientation, which is
what matters to a user who reorients their coordinates and reruns.

The low-level exposure() default stays 64 and is now annotated as such: every
production caller passes K explicitly, and the shipped value is ShellOptions::K.

This changes which beads are selected, so all frozen validation figures must be
regenerated and the freeze tag moved.

Fixes ehb54/ultrascan-tickets#984

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>


  Commit: e993002a13ba1a428967d55ca1f1d4f17d85997c
      https://github.com/ehb54/ultrascan3/commit/e993002a13ba1a428967d55ca1f1d4f17d85997c
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_api.hpp
    M us_somo/develop/grpy/linalg.hpp

  Log Message:
  -----------
  somo/grpy: report bad input and failed allocation instead of aborting

Running GRPY in-process removed the isolation the subprocess gave it, but the
module still failed like standalone code.

linalg.hpp
- The in-core calloc return was unchecked, so a failed allocation was followed
  by tile accesses through a null pointer. These are exactly the sizes that
  fail: this allocation is the memory wall the tiling exists for.
- Out-of-core setup called std::abort() when the backing file could not be
  created, sized or mapped, so an unwritable or full directory killed SOMO and
  any unsaved work with it. Now closes and unlinks the partial file and throws,
  naming the path and the errno.
- Both raise the new la::Error. Also widen the tile row offset before the
  multiply (roff()): i * b was computed in int and only then converted to
  Eigen::Index, which is what CodeQL flags at the six middleRows() calls.

grpy_api.hpp
- read_native_file() accepted every failure silently: a missing file, a
  truncated file or a non-numeric field all produced zeros, which became N == 0
  or zero-radius beads and surfaced much later as a division by radius or a
  quietly meaningless result. It now validates the open, every scalar field,
  the declared bead count and each bead line, and rejects a non-finite
  coordinate or a radius that is not positive -- naming the file and line.

Reported-by: aaron-auc
(cherry picked from commit 1e489e741362fe17744b1b4c8dd70ab6688d94ca)


  Commit: e792f3dc8b2869ee86152a418da23c2d6e7399c6
      https://github.com/ehb54/ultrascan3/commit/e792f3dc8b2869ee86152a418da23c2d6e7399c6
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_grpy.cpp

  Log Message:
  -----------
  somo/grpy: add a failure boundary, and let Stop reach the solve

Two defects that both come from the move to an in-process solver.

A failure boundary. As a subprocess a GRPY failure was isolated -- the process
died, SOMO read a non-zero exit and carried on. In-process there is nothing
between a throw and the application: a failed allocation, an unreadable input
or a bad out-of-core path would terminate SOMO and lose the session. The parse
and the whole compute now run inside a try; the catch reports the error and
restores the interface exactly as the pre-flight memory guard does when it
refuses a model, and in gui_script mode fails properly to stderr with a
non-zero exit rather than reporting success. The body is left at its existing
indentation so the diff shows the boundary and nothing else.

Stop. sopt.should_stop was installed inside 'if ( sopt.enabled )', so it existed
only for a shell-reduced run. With shell reduction off -- the default, and now
the only configuration -- nothing was installed and Stop could not reach the
solve at all: the progress callback's 'if ( stopFlag ) return;' suppresses
repaints but does not end the computation, so a long model ran to completion
looking hung. Install it for every run.

This does not make Stop instant. A solve already running still finishes, since
the factor has no interior abort; with a ladder, Stop takes effect between rungs
and saves nearly all of what remained. Said plainly in the comment rather than
implied.

Reported-by: aaron-auc
(cherry picked from commit 876a76a1fd47c75e70def12fab87b0fff40f1dce)


  Commit: 9f4a2289b2bfe3abb412a4681fc795235555326e
      https://github.com/ehb54/ultrascan3/commit/9f4a2289b2bfe3abb412a4681fc795235555326e
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_other.cpp

  Log Message:
  -----------
  somo: don't let Close act during a running GRPY solve

The GRPY solve runs synchronously on the GUI thread and calls processEvents()
to keep the interface responsive, which also leaves Close live. Taking it would
hide the window, clear the temporary directories and ask the application to quit
while the solve was still running over those files -- SOMO appearing closed
while it went on computing.

closeEvent() now treats Close as a Stop request while grpy_running: it sets
stopFlag, says that the current model must finish first because the solve cannot
be interrupted part-way, and ignores the event. Closing again once it has
stopped behaves normally.

Reported-by: aaron-auc
(cherry picked from commit 5bf6554af39173167c0b78fb1307373d4329f15e)


  Commit: 6325fd38e1a75ebc8fedf76bb823483a0b458f2b
      https://github.com/ehb54/ultrascan3/commit/6325fd38e1a75ebc8fedf76bb823483a0b458f2b
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_core.hpp

  Log Message:
  -----------
  somo/grpy: record the GRPY provenance, copyright and citation

grpy_core.hpp describes itself as a faithful translation of GRPY.f but recorded
neither its author, nor its license, nor the paper to cite.  Add all three:
Copyright (C) 2017 Pawel Jan Zuk, GPLv3 per the GRPY.f header, and Zuk,
Cichocki & Szymczak, Biophys. J. 115:782-800 (2018).

The note deliberately stops short of asserting a licensing outcome.  The
original is GPLv3, UltraScan is LGPLv3, and a translation is a derivative work,
so compatibility is a project-level decision that a source header cannot settle.

Reported-by: aaron-auc


  Commit: 33ba190d5897186add8ed98246c862283eb3769f
      https://github.com/ehb54/ultrascan3/commit/33ba190d5897186add8ed98246c862283eb3769f
  Author: emre brookes <ehb54 at users.noreply.github.com>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_api.hpp
    M us_somo/develop/grpy/grpy_core.hpp
    M us_somo/develop/grpy/linalg.hpp
    M us_somo/develop/src/us_hydrodyn_grpy.cpp
    M us_somo/develop/src/us_hydrodyn_other.cpp

  Log Message:
  -----------
  Merge pull request #520 from ehb54/ehb54-issue-1009-somo-review-fixes

somo/grpy: crash safety, working Stop, and GRPY provenance


  Commit: 46d85c64e1e4ea677ea916e4ae3e671982390b2c
      https://github.com/ehb54/ultrascan3/commit/46d85c64e1e4ea677ea916e4ae3e671982390b2c
  Author: emre brookes <ehb54 at users.noreply.github.com>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_exposure.hpp
    M us_somo/develop/grpy/grpy_shell.hpp

  Log Message:
  -----------
  Merge pull request #518 from ehb54/ehb54-984-quadrature

somo/grpy: raise the exposure quadrature to 512 points per bead


  Commit: f2400a74b8885d98bdf610c9f96559a0f599f0a8
      https://github.com/ehb54/ultrascan3/commit/f2400a74b8885d98bdf610c9f96559a0f599f0a8
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_api.hpp
    M us_somo/develop/grpy/grpy_exposure.hpp
    M us_somo/develop/grpy/grpy_shell.hpp
    A us_somo/develop/grpy/grpy_types.hpp
    M us_somo/develop/grpy/tests/test_shell.cpp
    M us_somo/develop/libus_somo.pro
    M us_somo/develop/src/us_hydrodyn_grpy.cpp

  Log Message:
  -----------
  somo/grpy: reach the solver through an injected function

The shell reduction and the exposure ranking are original work; the solver they drive is
a translation of GPLv3 GRPY.f. This separates the two so the latter can move to its own
program (ehb54/grpy-cpp) and be called rather than linked.

grpy_shell.hpp and grpy_exposure.hpp no longer name a solver, include grpy_core.hpp or
use Eigen. They take grpy::SolveFn -- one bead list in, Results out -- which SOMO will
implement by running the external GRPY program, once per rung. At most five rungs per
model, against O((11N)^3) where the last rung alone is ~7/8 of the work, so the extra
invocations cost nothing measurable.

New grpy_types.hpp holds the value types both sides exchange (Bead, PhysParams, Options,
Results, ProgressFn, Obs) plus the SolveFn injection point. It is plain data with nothing
translated from GRPY.f, so it stays with UltraScan; grpy_api.hpp now includes it instead
of defining the same types.

full_rg2() is computed here from the definition -- the volume-weighted second moment of a
union of uniform spheres, with each sphere's own (3/5)a^2 term -- rather than calling into
the core. Rg is pinned to the full model across rungs, so the ladder needs it even though
no rung computes the whole structure.

The call site is transitional: it still solves in process, through a lambda that wraps
grpy::Solver, so this commit changes no results. Replacing that lambda with a run of the
external program is the next step, after which grpy_api.hpp and grpy_core.hpp leave the
tree and nothing shipped links GPLv3 code.

Verified: the whole grpy module test suite passes, including test_shell driving the ladder
through the injection point; a translation unit including only grpy_shell.hpp compiles and
runs the ladder with neither the core nor Eigen present; and us_hydrodyn_grpy.cpp compiles
against the real Qt flags.

Refs ehb54/ultrascan-tickets#1012


  Commit: 291a7c7fc6935b8efc7d4ca493a4154e49beb6d5
      https://github.com/ehb54/ultrascan3/commit/291a7c7fc6935b8efc7d4ca493a4154e49beb6d5
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/grpy/grpy_process.hpp
    M us_somo/develop/grpy/tests/run.sh
    A us_somo/develop/grpy/tests/test_process.cpp
    M us_somo/develop/libus_somo.pro
    M us_somo/develop/src/us_hydrodyn_grpy.cpp

  Log Message:
  -----------
  somo/grpy: run GRPY as a program again, not as linked code

Implements the injection point from the previous commit: grpy::ProcessSolver runs the GRPY
program on a bead list and returns its results, and the shell reduction calls it once per
rung. Nothing GPLv3-derived is invoked here through anything but a process boundary.

The contract is the one SOMO used before the in-process port -- run it with '-e <file>',
read the report from stdout, scrape the carriage-return-separated 'NN% TASK:' banner for
progress -- so the program's command line is still the one the Fortran GRPY published. The
controls added since (precision, out-of-core, thread count) are passed as environment
variables rather than as new flags, which is what keeps that true.

A rung that uses every bead runs on the .grpy file SOMO already wrote, so the ordinary
unreduced calculation reads exactly the file the user sees, as it always has. Only a
reduced rung gets a temporary file, and it is removed however the run ends.

The binary lookup is the one the external path used before, minus the Docker/container
branch, which is not coming back: bin/GRPY_{osx10.11,linux64,win64.exe}, which add_to_bin
still ships and linux.pl still installs.

read_grpy_input() reads the .grpy file written by us_hydrodyn_write.cpp. It is written
against our own writer rather than translated from the Fortran reader, so the last thing
the call site needed from grpy_api.hpp is gone.

Out of process restores two things the in-process port had given up: a failure kills a
child rather than the session, and Stop ends a solve that is ALREADY RUNNING -- the
in-process factorization had no interior abort, so Stop only took effect between models.
That arrives as grpy::Stopped and is handled as a stop, not as a failure.

New test_process.cpp drives all of it with a fake GRPY program that replays a real golden
report and the real banner: parsing, progress, a non-zero exit, a missing program, and the
mid-solve kill. 19 checks, all passing, and the whole module suite still passes.

Caught by that test: the sedimentation label contains '(1. - (vbar*rho))', so taking the
first number after the label parsed 1.0 as the sedimentation coefficient. The value is
identified by its exponent, not by its position.

Refs ehb54/ultrascan-tickets#1012


  Commit: ef313a163394648ac403e382068e2fdbbe10759d
      https://github.com/ehb54/ultrascan3/commit/ef313a163394648ac403e382068e2fdbbe10759d
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    R us_somo/develop/grpy/INTEGRATION.md
    M us_somo/develop/grpy/README.md
    R us_somo/develop/grpy/grpy_api.hpp
    R us_somo/develop/grpy/grpy_core.hpp
    R us_somo/develop/grpy/grpy_report.hpp
    R us_somo/develop/grpy/linalg.hpp
    R us_somo/develop/grpy/parallel_qt.hpp
    R us_somo/develop/grpy/parallel_std.hpp
    R us_somo/develop/grpy/tests/qt_proof.cpp
    M us_somo/develop/grpy/tests/run.sh
    R us_somo/develop/grpy/tests/test_api.cpp
    R us_somo/develop/grpy/tests/test_assemble.cpp
    R us_somo/develop/grpy/tests/test_linalg.cpp
    R us_somo/develop/grpy/tests/test_ooc.cpp
    M us_somo/develop/grpy/tests/test_shell.cpp
    R us_somo/develop/grpy/tests/test_threaded.cpp
    M us_somo/develop/libus_somo.pro
    M us_somo/develop/src/us_hydrodyn_grpy.cpp

  Log Message:
  -----------
  somo/grpy: remove the GRPY-derived solver from the tree

This is the commit that resolves the licence conflict: the GPLv3-derived translation is no
longer present in an LGPLv3 repository, and no shipped binary can link it.

Deleted: grpy_core.hpp and grpy_report.hpp (translations of GRPY.f), grpy_api.hpp (its
readers and display formulas), and linalg.hpp / parallel_std.hpp / parallel_qt.hpp, which
existed to serve them. All of it now lives in ehb54/grpy-cpp, where it is GPLv3 and is
validated against the original Fortran by its own golden tests.

What remains in grpy/ is original work: the exposure ranking, the self-validating shell
reduction, the value types, and the process boundary. It is Eigen-free and QtConcurrent-
free as a result, so libus_somo.pro drops 'QT += concurrent'.

test_shell now drives the ladder with an ANALYTIC model instead of the real solver, which
is a stronger test rather than a weaker one: each observable approaches the full-model
value at a known rate, so the true error of every rung is known exactly and the reported
bar can be checked for actually bounding it. The model derives mass and Rg from the beads
it is given, exactly as the solver did, so the ladder's pinning of both to full-model
values is still what those tests exercise -- a model that echoed them back could not tell
a pinned value from an unpinned one.

Deleted with their subject: test_api, test_linalg, test_assemble, test_threaded, test_ooc
and qt_proof, which tested the solver, its linear algebra and its threading. Their
successors live in grpy-cpp.

Also updated the module README, removed INTEGRATION.md (it documented an integration that
no longer exists), and corrected the comments and messages that still described GRPY as
running in process.

Fixes ehb54/ultrascan-tickets#1012


  Commit: b5ce2aef6cda513b72da78eaa2bc4512e70dfcb5
      https://github.com/ehb54/ultrascan3/commit/b5ce2aef6cda513b72da78eaa2bc4512e70dfcb5
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/add_to_bin/GRPY_linux64
    M us_somo/add_to_bin/GRPY_osx10.11
    M us_somo/add_to_bin/GRPY_win64.exe

  Log Message:
  -----------
  somo/grpy: ship the C++ GRPY binaries in add_to_bin

Replaces the Fortran GRPY binaries with builds of ehb54/grpy-cpp, under the same names, so
the lookup, add_to_bin and linux.pl all keep working untouched. Without this the branch
calls the program it always called and none of the port's work reaches a user.

  GRPY_osx10.11    universal x86_64 + arm64, ad-hoc signed. The Fortran binary was x86_64
                   only, so every Apple Silicon Mac was running GRPY under Rosetta.
  GRPY_linux64     fully static, as its predecessor was: no glibc floor. Threading checked
                   under -static (67.1 s on 1 thread vs 2.81 s on 32 at 1200 beads).
  GRPY_win64.exe   cross-compiled with mingw-w64, imports only KERNEL32 and the UCRT stubs.

The macOS and Linux binaries pass the full golden suite against the original Fortran output
at worst relative error 0.00e+00. THE WINDOWS BINARY HAS NOT BEEN RUN -- no Windows machine
or wine was reachable from any build host -- so it needs a smoke test on Windows before
this branch ships. Everything else about it is verified statically only.

What a user gets that the Fortran binaries could not give: threading, single precision,
out-of-core, and native arm64.

Refs ehb54/ultrascan-tickets#1012


  Commit: 1c8f71ee1670dd0bb052e04232baea6b3a3c3b74
      https://github.com/ehb54/ultrascan3/commit/1c8f71ee1670dd0bb052e04232baea6b3a3c3b74
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_process.hpp
    M us_somo/develop/grpy/grpy_shell.hpp
    M us_somo/develop/grpy/grpy_types.hpp
    M us_somo/develop/grpy/tests/test_shell.cpp
    M us_somo/somo/doc/manual/somo/somo_hydro.html
    M us_somo/somo/doc/manual/somo/somo_misc.html

  Log Message:
  -----------
  somo/grpy: keep the finished rungs when Stop lands mid-calculation, and correct the manual

Updating the manual turned up a regression rather than just stale prose. somo_hydro.html
promises that a stopped shell reduction 'keeps the result and error estimate obtained so
far'. That held while GRPY ran in process, because it could only be stopped between rungs.
A separate program can be killed the instant Stop is pressed -- which is the improvement --
but the exception was propagating straight past the ladder, discarding every rung that had
already completed. The promise in the manual was no longer true of the code.

ShellSolver now treats a stop during a rung exactly as it treats one between rungs: the
ladder ends where it stands, reports itself as not converged, and keeps its result and its
error bar. Only a stop before the first rung has finished leaves nothing to report, and
that one still propagates. grpy::Stopped moved from grpy_process.hpp to grpy_types.hpp so
the ladder can catch it without acquiring a Qt dependency.

Two tests pin it: a solver that stops during the third rung must leave two usable rungs
with a bar, and one that stops immediately must propagate.

Manual:
  * somo_misc.html said GRPY is 'built directly into US-SOMO and runs multi-core
    in-process'. It is again a separate multi-core program, which US-SOMO installs and
    runs; no Docker image and no checkbox, as before. The historical sentence about the
    original external and Docker versions is left as it stands, being history.
  * somo_hydro.html said Stop ends the series 'at the end of the calculation currently in
    progress'. It now ends immediately, per the change above.

Refs ehb54/ultrascan-tickets#1012


  Commit: 9bab116da50524c7a78a4b952a1feb6ac11322de
      https://github.com/ehb54/ultrascan3/commit/9bab116da50524c7a78a4b952a1feb6ac11322de
  Author: emre brookes <ehb54 at users.noreply.github.com>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/add_to_bin/GRPY_linux64
    M us_somo/add_to_bin/GRPY_osx10.11
    M us_somo/add_to_bin/GRPY_win64.exe
    R us_somo/develop/grpy/INTEGRATION.md
    M us_somo/develop/grpy/README.md
    R us_somo/develop/grpy/grpy_api.hpp
    R us_somo/develop/grpy/grpy_core.hpp
    M us_somo/develop/grpy/grpy_exposure.hpp
    A us_somo/develop/grpy/grpy_process.hpp
    R us_somo/develop/grpy/grpy_report.hpp
    M us_somo/develop/grpy/grpy_shell.hpp
    A us_somo/develop/grpy/grpy_types.hpp
    R us_somo/develop/grpy/linalg.hpp
    R us_somo/develop/grpy/parallel_qt.hpp
    R us_somo/develop/grpy/parallel_std.hpp
    R us_somo/develop/grpy/tests/qt_proof.cpp
    M us_somo/develop/grpy/tests/run.sh
    R us_somo/develop/grpy/tests/test_api.cpp
    R us_somo/develop/grpy/tests/test_assemble.cpp
    R us_somo/develop/grpy/tests/test_linalg.cpp
    R us_somo/develop/grpy/tests/test_ooc.cpp
    A us_somo/develop/grpy/tests/test_process.cpp
    M us_somo/develop/grpy/tests/test_shell.cpp
    R us_somo/develop/grpy/tests/test_threaded.cpp
    M us_somo/develop/libus_somo.pro
    M us_somo/develop/src/us_hydrodyn_grpy.cpp
    M us_somo/somo/doc/manual/somo/somo_hydro.html
    M us_somo/somo/doc/manual/somo/somo_misc.html

  Log Message:
  -----------
  Merge pull request #521 from ehb54/ehb54-issue-1012

SOMO: call GRPY as a separate program instead of linking it


  Commit: c31acc956f81b382da75a9af2366c7753ab4610b
      https://github.com/ehb54/ultrascan3/commit/c31acc956f81b382da75a9af2366c7753ab4610b
  Author: Emre Brookes <emre.brookes at umontana.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_process.hpp
    M us_somo/develop/grpy/tests/test_process.cpp

  Log Message:
  -----------
  somo/grpy: ask the solver for its high-precision report

The GRPY program's default report is the Fortran's own ES11.3 -- four significant
figures. That is right for a drop-in replacement a human reads, and wrong for a
caller that DIFFERENCES successive results, which is exactly what the shell
reduction does: the error estimate is built from the gap between consecutive rungs
and from the ratio of two such gaps, so a relative quantisation of ~1e-4 in the
parsed values lands directly on the reported bar.

Measured over 266 reduced evaluations, by rounding recorded full-precision rung
values through %11.3E and re-running the estimator on both:

  reported estimate   median 2.5% different, up to 17.6%
  observed order k    shifts by up to 0.26
  floor activation    changes which term governs in 14 cases
  stopping decision   flips in 2 cases

Coverage happened to survive on that corpus -- the minimum margin fell only from
1.131x to 1.119x, and no evaluation lost coverage -- so this is not a correctness
fix. But none of that movement should exist. It is an output format leaking into a
numerical result, and into the delivered value too, which was being truncated to
four significant figures.

The program already supports this: GRPY_HP switches the report to %24.15E. Nothing
changes for anyone running the program directly, since the default is untouched and
the drop-in behaviour is preserved.

The parser finds values by their exponent rather than by column, so it is indifferent
to the field width. Tests assert that rather than leaving it to inspection: a
%24.15E report round-trips a double to better than 1e-12, and the legacy ES11.3
report still parses, since an older binary on PATH would still emit it.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>


  Commit: 71440862d4921b0f98d8d656e0ac7a5ce7ffff4a
      https://github.com/ehb54/ultrascan3/commit/71440862d4921b0f98d8d656e0ac7a5ce7ffff4a
  Author: emre brookes <ehb54 at users.noreply.github.com>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/grpy/grpy_process.hpp
    M us_somo/develop/grpy/tests/test_process.cpp

  Log Message:
  -----------
  Merge pull request #522 from ehb54/ehb54-grpy-hp

somo/grpy: ask the solver for its high-precision report


  Commit: 0014b768829a25581c10d8a28af52bf56e6332a2
      https://github.com/ehb54/ultrascan3/commit/0014b768829a25581c10d8a28af52bf56e6332a2
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/Makefile
    A us_somo/develop/perceiver/tests/residue_variants.cpp

  Log Message:
  -----------
  perceiver: residue_variants, per-residue psv with the ionization separated

Mattia's question (2026-08-13): the D&Z additivity scheme reproduces C&E
well for non-ionizable residues, so what do the ionizable ones look like
computed in a FIXED protonation state, with the electrostriction left out?

That is not the shipped calculation minus a constant. The increment table
distinguishes the protonation states itself -- a 1st ammonium N is 12.2
against an amine's 4.0 -- so setting the state moves the atomic sum as well
as the mass, which is why this is worth computing rather than deriving by
hand.

Emits three columns per residue: as-is (as perceived), neutral side chain,
and ionized side chain, the last two without the -6.8/-6.7 electrostriction.
The decrement is removed by reconstructing from the exposed components
rather than by adding a flag, so us_hydrodyn_psv is untouched. Output ends
with override tokens ready to paste into protein_psv.

PSV_DETAIL=<res> dumps one residue term by term -- atom, hybrid, nH, charge,
increment -- so a disagreement with Mattia's spreadsheet can be localised to
an increment instead of argued about as a total. That mode is what traced
the HIS gap to a single cell and confirmed the PRO ring-N reading.

Test-only: no change to the perceiver, the psv engine, or the GUI.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>


  Commit: 1ca39c9a00cd6d0480198d290247d956d1b8013f
      https://github.com/ehb54/ultrascan3/commit/1ca39c9a00cd6d0480198d290247d956d1b8013f
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/perceiver/data/ref/cctbx_LICENSE.txt
    M us_somo/develop/perceiver/data/ref/it1992.cpp
    M us_somo/develop/perceiver/tests/regression.cpp

  Log Message:
  -----------
  Merge remote-tracking branch 'origin/ehb54-issue-980' into ehb54-issue-980


  Commit: 7e06936167e1506e62850ad4a75a2fdab4a1aa2b
      https://github.com/ehb54/ultrascan3/commit/7e06936167e1506e62850ad4a75a2fdab4a1aa2b
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/add_to_bin/GRPY_linux64
    M us_somo/add_to_bin/GRPY_osx10.11
    M us_somo/add_to_bin/GRPY_win64.exe
    R us_somo/develop/grpy/INTEGRATION.md
    M us_somo/develop/grpy/README.md
    R us_somo/develop/grpy/grpy_api.hpp
    R us_somo/develop/grpy/grpy_core.hpp
    M us_somo/develop/grpy/grpy_exposure.hpp
    A us_somo/develop/grpy/grpy_process.hpp
    R us_somo/develop/grpy/grpy_report.hpp
    M us_somo/develop/grpy/grpy_shell.hpp
    A us_somo/develop/grpy/grpy_types.hpp
    R us_somo/develop/grpy/linalg.hpp
    R us_somo/develop/grpy/parallel_qt.hpp
    R us_somo/develop/grpy/parallel_std.hpp
    R us_somo/develop/grpy/tests/qt_proof.cpp
    M us_somo/develop/grpy/tests/run.sh
    R us_somo/develop/grpy/tests/test_api.cpp
    R us_somo/develop/grpy/tests/test_assemble.cpp
    R us_somo/develop/grpy/tests/test_linalg.cpp
    R us_somo/develop/grpy/tests/test_ooc.cpp
    A us_somo/develop/grpy/tests/test_process.cpp
    M us_somo/develop/grpy/tests/test_shell.cpp
    R us_somo/develop/grpy/tests/test_threaded.cpp
    M us_somo/develop/libus_somo.pro
    M us_somo/develop/src/us_hydrodyn_grpy.cpp
    M us_somo/develop/src/us_hydrodyn_other.cpp
    M us_somo/somo/doc/manual/somo/somo_hydro.html
    M us_somo/somo/doc/manual/somo/somo_misc.html

  Log Message:
  -----------
  Merge remote-tracking branch 'origin/somo-dev' into ehb54-issue-980


Compare: https://github.com/ehb54/ultrascan3/compare/a93e298c3472...7e06936167e1

To unsubscribe from these emails, change your notification settings at https://github.com/ehb54/ultrascan3/settings/notifications


More information about the us-commits mailing list