Repository navigation
Releases: rubendahan/conatus
Release list
Conatus 0.1.2
A correction release for the findings of an external review of 0.1.1 and of a review of its
documentation. Each fix has a test against an independent reference value. Upgrading is
recommended: some results of 0.1.1 were wrong (see Correctness). Results that can differ from
0.1.1: large finite eigenvalues of dense QZ, parametric pencils with small parameter terms,
contour results with close roots, critical(over=) and the Hopf curves of continue_codim2.
Security
- Local Studio: the session cookie is
cn_session_<port>with--localand__Host-cn_session
over HTTPS, and each session is bound to theHostit was opened at. The cookie was valid when
replayed from any port of 127.0.0.1. On plain HTTP, another service on the same host name and
port can still read it; the Studio guide says so. - Telemetry spools, Studio audit logs and token files are created 0600 in 0700 directories,
whatever the umask; they took the umask's mode. Run records and outputs keep the umask's mode. hub serve --local --state hub_stateuses the directory given; the explicit spelling of the
default was replaced by a temporary directory.
Correctness
- Dense QZ (
solve_dense,m.eigenvalues(method="dense")): with a nonsingularMevery
eigenvalue is finite and returned;L = -diag(1, 1e13),M = Ilost 1e13 as infinite. The
rank ofMis measured onMas given, so a row of rounding noise whereMhas a zero row
does not makeMlook nonsingular (its infinite eigenvalue was returned as a finite value near
1e17). The log states the rank and names the pairs it cannot classify. - Parametric pencils (
m.parametric): a coefficient entry is discarded only at rounding level
for that entry; a whole matrix 1e-14 times the pencil's largest entry was deleted as
"identically zero" (eigenvalue 1e-14 r read 0 at r = 1e14). An evaluation where the discarded
entries could matter is refused. continue_codim2(kind="hopf")stops at the Bogdanov–Takens point (κ = ω² = 0) and keeps only
points whose Jacobian has the pair ±iω; it continued into real-saddle points. Tutorial 10, its
figure and its checks are corrected.cn.contour.beyn: close distinct roots (0.2 and 0.2000001) are returned separately, each
counted on its own square; they were one root "of multiplicity 2" at their mean.
multiplicityis the number of eigenvalues in a square of half-sideenclosure(new field)
around each value.cn.contour.beyn(counted=...)refuses a count of another operator (it evaluatesdet Tagain
at points the count recorded); it accepted any count of the same box.cn.contour.countis described as a test on samples of the boundary. For a functionT(z)
with poles, a zero and a pole on opposite sides of the boundary, closer to it than a step, are
not seen;count_method,explain()and the newCountResult.scopeand
poles_by_constructionsay so. The contour results no longer use the word "certified".BeynResult.residual_definitionstates the scale of the residuals; the guide's formula for a
functionT(z)was not the one computed.critical(over=)computes the neutral value atover_pointspoints of the interval (default
9) and refines every local minimum of that scan; one bounded Brent search could return a higher
local minimum as the critical value. The log lists the minima found, and a point where the
pencil is refused is logged as unchecked.- The run cache refuses a function whose code reads a value chosen at run time (
getattr,
vars,os.environ,open,np.load, ...); such a read kept the cache key, and a changed
configuration returned the old value.
Checks that reported success without measuring it
verify()measures the right and left residuals of the vectors the mode holds when it is
called; it printed the residual stored bytrack(), so a mode whose vector had been changed
still passed. A zero vector, or a vector of the wrong size, is not a pass. A point where the
parametric pencil is refused is reported as a failed check instead of an exception.resolution_reportisokonly when every variable of the plan was measured; an empty or
partial state is reported as not measured (complete,unmeasured). An array of the wrong
shape is refused with the expected shape instead of anIndexError.python -m conatus agent checkchecks the argument values ofSimulation.runand
IVPSolver.runat the stop (run(steps=-1)was reported ok); the newvalidatedfield says
whether the values of the stopped call were checked.- The acceptance scripts shipped with the package check the mathematical requirement of each
case, and their runner counts a script that crashes or prints no result as a failure. uncertainty(...).explain()prints tuple resolutions such asN=[(8, 8), (12, 12), (16, 16)]
(it raisedTypeError).
Documentation and website
- The home page and the README start with one complete calculation, the critical Reynolds number
of plane Poiseuille flow, shown with its recorded output. The site and the documentation share
one navigation and one getting-started route. - The code shown on the guide and tutorial pages runs when copied in order, and the outputs shown
are what it prints; a test runs every page. - Tutorial figures redrawn: tables where a plot carried little information, captions computed
from the plotted data, values below the axis floor drawn as upper limits. - Wording: claims are stated with their scope and threshold, without slogans; the time-stepper
orders are given per scheme; the pages no longer compare Conatus with other codes. - The Validation page lists published values and closed forms; the values are labelled as
reported by the author, since their run records are not public. - Pages no longer cite examples or test files that the package does not ship; the deprecation
versions and the release status are read from the package. SHA256SUMSlists bare file names, sosha256sum -c SHA256SUMSworks in the directory that
holds the downloaded wheels.
Known limitations
- Unchanged from 0.1.1 (see below).
- A contour count for a user function
T(z)with poles is a test on samples, not a proof. - Local Studio over plain HTTP: another service on the same host name and port can replay the
session cookie. - Dense QZ: a pencil whose
Mis singular and which also has finite eigenvalues larger than
about 1e12 times the scale of the pencil can have pairs that cannot be classified; they are
kept as finite and named in the log.
Conatus 0.1.1
A correction release: every finding of an external review of 0.1.0, and of our own audits of
security, input validation, shared state, invariance and assurances (checks that
reported success without measuring it), is fixed, each with a test. Upgrading is
recommended: some results of 0.1.0 were wrong (see Correctness). Changes that can alter a result
you computed with 0.1.0: the default dealiasing grid of some models, complex fields, the modes
kept by the eigenvalue filter, and the random draws of Lyapunov spectra (all below).
Added
- Conatus Studio, local:
python -m conatus studioserves live runs, telemetry and controls on
your machine (pip install "conatus[studio]"; on a cluster, a batch job and an ssh tunnel). It
is experimental (see below); a hosted hub is not part of this release. - An interface for AI agents:
python -m conatus agent(info,explain <name>,
check <script.py>), withAGENTS.mdat the root of the repository. - Eigenvalues in a region of the complex plane:
m.eigenvalues(N, ..., region=cn.box(re=(a, b), im=(c, d)))returns every eigenvalue of the
discretised problem in the box, withres.countcertified by the argument principle (computed
from the sparse LU, never the determinant itself) and the eigenvalues from Beyn's
contour-integral method, each validated by its residual.cn.contour.countand
cn.contour.beyndo the same for a pencil, a Floquet-Hill operator or a functionz -> T(z)
(nonlinear eigenproblems). - Experimental features are marked:
cn.errors.ExperimentalWarning, once per process, on the
first use of a feature that is shipped and tested but not promised (the Studio,
a spherical shell larger than 64 × 48 × 48,ShootingRPO,PipeTravellingWave); the guide
page "Experimental features" lists them. - One-line
reprof simulations, solvers andNewtonKrylovHookstep; the under-resolved warning
of an eigenvalue states the accuracy to expect (about sqrt(tail) relative, an order of
magnitude, not a bound).
Deprecated
conatus.expertexports only the names the guide documents. Any other name written as
conatus.expert.<name>still works, with aDeprecationWarningnaming the module to import it
from, and stops working in 0.3. The Studio protocol moved toconatus.telemetry, the BibTeX
strings toconatus.methods.BIBTEX.- The
__all__of the public modules lists documented names only; the other names stay
importable at the same path.
Security
run.reproduce()of a decorated call no longer imports and calls themodule:functionnamed by
a run record that another account can write (the record, its run directory orruns/not owned
by you, or writable by group or others): a typedOptionErrornames the two ways out (fn=,
chmod go-w). New run directories are created without group/other write whatever the umask, so
your own records are never refused; a deliberately group-writable shared registry needsfn=.from_dedalusrefuses private and dunder names ofdedalus.public(d3.__dict__,d3.tr,
d3.__reduce_ex__) and attributes of the distributor outside a whitelist: they handed the
script the translator's own interpreter.- Run records redact the value of credential-like command-line options (
--token X,
--api-key=X) ininvocation.argv. - File names in the run registry (
Registry.run_dir,Run.file_path,save_file) cannot leave
the run directory; a forged inline array in a record (shape not matching its values, too long,
negative dimension, non-numeric dtype) is refused; temporary.npznames are random
(mkstemp); the adjoint journal refuses file names that are not its own generation files.
Correctness (wrong results now fixed)
Simulation and models:
- A field declared complex is solved in a complex system (its imaginary part was dropped).
- The default dealiasing factor counts spatially varying given fields as factors of a product
(U*u*uis cubic: factor 2, not 3/2), and a function of given fields alone (exp(G),1/G) as
one factor (exp(G)*u**3: 5/2);explain()states the condition (fields truncated at N modes)
instead of a universal "exact (alias-free)". This changes the default grid of a model whose
equations multiply given fields with a total degree of 3 or more (printed byexplain()); pass
dealias=3/2to keep the 0.1.0 grid. plan.solve(data)with new data for a coefficient of the operator (qinq*u = f) rebuilds
the operator instead of changing only the right-hand side, and the residual is that of the
updated problem (mapped, Cartesian, polar and spherical plans). Data are compared by value (an
array changed in place is new data); the last rebuilt plan is reused when the same coefficient
is passed again.- Integrals on a sine/cosine axis (
walls(a, b, basis="sincos")) are over the physical interval
[a, b], exact for both parities, inevaluate(), the dye diagnostics and equations (they were
over the doubled period). EmbeddedError(adapt=True)rejects a step whose error estimate exceedstoland retries it with
a smallerdt(the step used to be kept, only the nextdtchanged);ConvergenceErrorwhen
tolcannot be met atdt_min.- SBDF3 and SBDF4 with the default
startup="lower_order"converge at order 2, and now say so:
solver.effective_orderandexplain()give the effective order,
scheme_description(name, effective=)gives the formal and the effective order;
startup="rk443"keeps the nominal order. - A failing model declaration (
equations,at,given,dye,define,function,
eigenvalue) leaves the model unchanged, so the corrected call works. - User functions (
m.function) work on the sphere; tensor boundary conditions keep their rows
whatever their scale. - A user function name belongs to its model: another model, or a re-run notebook cell, can declare
its owng. - No false "under-resolved" warning for a field exactly represented on very few modes.
sim.particles: splitting a run into severalrun()calls no longer lowers the order.- Ensembles stop exactly at
max_steps; counts, indices and labels are never truncated;
Ensemble.states()and velocity snapshots are copies. - Checks that reported success without having measured it now say what they found: NaN or
infinite data makeresolution_reportandestimate_modessay "non-finite" (an all-NaN field
was "all resolved") and give a NaN or infinite CFL;verify()measures the tail of every
component of a vector unknown and fails a tail it could not measure;critical(over=)says
when the minimum sits at an end ofover;time_averageflags an unreliable batch-means error;
NaN residuals are kept, never shown as small.
Analysis:
- Floquet–Hill operators: a singular intermediate block no longer gives NaN (a pivoted banded LU
takes over), andsolvechecks its backward error. - Generalized eigenvalue filtering is invariant under a scaling of the equations.
uncertainty(): the spatial error uses the actual resolution increments;trustedrequires
scheme_orderand a consistent refinement.max_growth()compares the ends of the interval; aCertifiedRootis never certified when
unconverged.- POD reports the fraction of the total energy; the low-level optimal response is the propagated
state. - Continuation of boundary-value problems converges at the fold of a uniform state (the residual
scale includes the parameter terms). from_dedalus:**optionsin calls are expanded, a problem's ownnamespace={...}resolves its
equations, NumPy keywords in initial data are kept, andcompleteis true only without
unsupported or approximated lines.DedalusTranslation.to_script()writes a runnable program (it
replays the translation and runs it).
Results that changed silently with unchecked inputs (now refused with a typed error naming the fix):
ncc_cutoff=nanreduced every non-constant coefficient to its mean;P.least_stable(re=...)on
a pencil inReused the declared Re;time_parameter=naming no parameter froze the forcing;
the CFL step of a 1D scalar velocity was computed from its first grid value; a complexMin
generalized_eigenvalueswas cast to float; switches given as text were truthy
(complex="no"was True); 2D or complex series incn.time_averagewere flattened or cast;
decreasing snapshot times gave a negativedt;Decimalparameter values compiled as complex;
a shift-invertn_modesabove the pencil size was clipped.plan.paramswrites are checked, and a change after the group matrices were assembled is
refused (the cached groups kept the old value).- A model that declares
titself and uses it in a time-dependent model gets a
DefaultChoiceWarning(itssin(t)is constant).
State shared between calls:
- A solver keeps at most
FACTOR_CACHE_SIZE(16) factorizations, least recently used dropped
first: an adaptive step (EmbeddedError(adapt=True)) or a search over the period kept one more
set per step until memory ran out (CPU Cartesian, polar, spherical and batched solvers). - Package sources (or the compiled core) changed after
import conatusare declared by
provenance.code_state()(changed_since_import, not reproducible, "restart the interpreter"),
and such a run is never a cache source or a cache hit: the hashes named the files on disk, not
the code that ran. The change is judged by the content of the modules the process imported
(sha256 recorded at import), not by modification times: an immediate edit or a deleted module is
seen, atouchor a checkout back to the same text is not a change. diagnostics.Grid.weights()andcell_volumes(),sim.coordinate("theta")on the sphere,
sim.coeffs()on a mapped domain,EVPMode.grid/coeffs/coordinateand
PipeTravellingWave.phireturn the caller's own arrays (an in-place edit changed later
inte...
Conatus 0.1.0
First public release 🎉
Install (CPU): pip install conatus
GPU (beta): download the +cu12 wheel matching your Python below, then
pip install "./conatus-0.1.0+cu12-cp312-....whl[gpu]" and check with python -m conatus doctor.
Built for A100 (sm_80) and L40S (sm_89), needs a driver supporting CUDA 12.9.
Linux x86-64, CPython 3.11, 3.12 and 3.13. Checksums in SHA256SUMS.