Skip to content

Add tomographic and 3x2pt covariance realspace measurement#256

Open
LisaGoh wants to merge 14 commits into
feature/sp_validation-extend-to-tomographyfrom
feature/tomo-real-space
Open

Add tomographic and 3x2pt covariance realspace measurement#256
LisaGoh wants to merge 14 commits into
feature/sp_validation-extend-to-tomographyfrom
feature/tomo-real-space

Conversation

@LisaGoh

@LisaGoh LisaGoh commented Jul 10, 2026

Copy link
Copy Markdown
Member

Hello, I've updated the Snakemake workflow to run on OneCovariance for the real space probe, and included tomographic and 3x2pt formats! I've also taken the liberty to clean up the common.py script >.<

I've ran the covariance workflow and it works, now we just have to decide what kind of format we want our nz distributions to be (I've assumed a single file with i columns, i being the number of tomographic bins), and how we want to specify the area and sigma_e (I've assumed a comma-separated string).

The output is compatible with the previous Cosmocov-processed file. I'll update the Cosmosis fitting script as a next step in the other issue!

@LisaGoh LisaGoh linked an issue Jul 10, 2026 that may be closed by this pull request
@LisaGoh LisaGoh self-assigned this Jul 10, 2026
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

ruff is clean — nothing to fix here.

@LisaGoh
LisaGoh force-pushed the feature/tomo-real-space branch from d235788 to 00a0f6b Compare July 10, 2026 16:17
On a PR whose head branch lives in this repo, the lint gate now applies
ruff's own fixes (`ruff format` + `check --fix-only`), commits them as the
github-actions bot, and pushes them back to the PR branch, then re-lints the
fixed tree in the same run and gates on the residual. Fully clean -> green
with an "autofix pushed" comment; unsafe/judgement lint that survives ->
red, comment lists only the residual. Fork PRs and develop pushes keep their
existing report-only behaviour.

Safe under pull_request_target: only ruff (static, never executes PR code)
runs over the untrusted tree, and only ruff's own diff is pushed. Push uses
the workflow token explicitly (checkout keeps persist-credentials: false);
adds contents: write. A GITHUB_TOKEN push doesn't retrigger the workflow, so
the pass/fail is decided in this run rather than by a rerun that never comes.


Claude-Session: https://claude.ai/code/session_01AAwoWLvWvNdt18RZJR2mek

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@cailmdaley

Copy link
Copy Markdown
Collaborator

thank you Lisa this looks great, please continue to take liberties! review incoming.

for the n(z) format, i'm proposing we migrate to SACC (see #241 for motivation, #246 for what this would mean for the OneCovariance interface). but i think it's fine to go ahead with what you've assumed for now so this PR can be merged quickly, and we can do the switch to SACC later.

@cailmdaley cailmdaley left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Lisa — this is a really nice move. The CosmoCov→OneCovariance swap is much cleaner than the old block/cat/process chain, and the COV_BASE_TEMPLATE consolidation plus workflow.source_path fix are genuine improvements to common.py, liberties happily taken. A few things to sort before merge, one of which I think breaks the workflow as-is:

Blocker: build_redshift_path is deleted but still called. workflow/rules/inference.smk line 66 and (worse) line 138 still call build_redshift_path — line 138 is evaluated at parse time, so any snakemake invocation on this branch should die with a NameError, not just covariance targets. Simplest fix: keep build_redshift_path as it was (it's exactly build_redshift_dir(version) + build_redshift_path_lens(version, blind)) alongside the new helpers, or update inference.smk in this PR. (If the covariance run worked for you, I suspect it was against a locally-edited inference.smk — worth double-checking what state that was in.)

Personal-path defaults — let's fix the pattern, not the username. To be fair, the previous defaults were no more neutral: they were Cail's personal tree. Rather than swapping one username for another, let's use this PR to drop personal defaults entirely — make COSMO_VAL / COSMO_INFERENCE / CAT_CONFIG required (env var or config key, loud error if unset), so each of us sets our own and the repo carries nobody's paths. Happy for that to be a small follow-up if you'd rather keep this PR focused. The one that genuinely needs reverting here is COSMOLOGY_PARAMS — inline comment explains why (it's about the generating rule, not whose disk).

Rest is inline — mostly small. On n(z) formats and area/sigma_e specification: as in my comment above, fine to keep your assumed formats for now and revisit with the SACC migration (#241/#246).

— Fable on behalf of Cail

Comment thread workflow/common.py Outdated
os.environ.get(
"COSMO_VAL", "/n17data/cdaley/unions/code/sp_validation/cosmo_val/output"
"COSMO_VAL",
"/n23data1/n06data/lgoh/scratch/UNIONS/sp_validation/results/cosmo_val",

@cailmdaley cailmdaley Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than these defaults carrying anyone's personal tree (the old values were Cail's, so this is a fix-the-pattern note, not a revert request): suggest requiring COSMO_VAL / COSMO_INFERENCE / CAT_CONFIG explicitly — env var or config key, loud error if unset — so each of us sets our own and the repo carries nobody's paths. Fine as a small follow-up if you'd rather keep this PR focused.

Comment thread workflow/common.py Outdated
# Regenerate with: snakemake results/cosmology/planck18.json
# Resolved relative to the run directory at configure() time.
COSMOLOGY_PARAMS = "results/cosmology/planck18.json"
COSMOLOGY_PARAMS = "/n23data1/n06data/lgoh/scratch/UNIONS/sp_validation/results/cosmology/planck18.json"

@cailmdaley cailmdaley Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one does need to stay relative (independent of the defaults question above): the cosmology_params rule generates this file at the relative path results/cosmology/planck18.json in the run directory, so pointing the constant at an absolute path decouples the reader from the generator — the rule would write one file and everything else would read another.

Comment thread workflow/common.py Outdated
base_version = re.sub(r"_ecut\d+", "", base_version)
if "v1.4.11" in base_version:
base_version = "SP_v1.4.6"
return f"nz_{base_version}_{blind}_source.txt" # TO DO: check lens and source file format

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three copies of the same version-normalization regex block now — worth one _nz_base_version(version) helper that the three functions share.

Also a naming/semantics check to resolve with the TO-DO: in the ini, zlens_file gets build_redshift_path_lens (the existing source-galaxy n(z)) and zclust_file gets ..._source.txt. OneCov's zlens is the lensing source sample and zclust the clustering lens sample — so a file suffixed _source feeding zclust reads inverted. If the intent is _lens.txt for the clustering sample, let's fix the suffix before anyone generates files against this convention.

Minor: build_redshift_dir returns a trailing-slash dir which the rule then passes through os.path.dirname, and the _lens/_source helpers return bare filenames that go through os.path.basename. Both round-trips can go — return dir and filenames and use them directly.

Comment thread workflow/rules/covariance.smk Outdated
cov_th = config[base_version]["cov_th"]
return cov_th["A"], cov_th["n_e"], cov_th["sigma_e"]

if config["probe_3x2pt"] == "wl":

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branches on the global config["probe_3x2pt"] while everything else in the rule branches on the {probe} wildcard — if they disagree (config says 3x2pt, someone requests a wl target, or vice versa) you get an ini with mismatched survey-spec lines. Suggest get_cat_params(version, probe) taking the wildcard, and dropping the global key entirely: then covariance_3x2pt (line 391) can just say probe="3x2pt", which also fixes the slightly bewildering probe_3x2pt: wl in the test config.

Comment thread workflow/rules/covariance.smk Outdated
small_k_damping_for1h = damped

[misc]
num_cores = 8

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded 8 here has to match threads: 8 on covariance_onecov by hand (the ini is written by a different rule, so {threads} can't be used directly). Worth a single shared constant (e.g. ONECOV_CORES = 8) used by both, so they can't drift.

Comment thread workflow/rules/covariance.smk Outdated
rules.covariance_ini_onecov.output,
output:
str(COSMO_INFERENCE / "data/covariance/covariance_{version}_{blind}_{gaussian}_minsep={min_sep}_maxsep={max_sep}_nbins={nbins}{mask_suffix}/cov_tmp_ssss_{block_pm}_cov_Ntheta{nbins}_Ntomo1_{block_i}")
# Matches `[output settings] file = cov_tmp_onecov.dat` in the ini.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment — the ini's file = is now the full covariance base name, not cov_tmp_onecov.dat.

Comment thread workflow/rules/covariance.smk Outdated
)
GLASS_MOCK_COV_DIR = config.get("glass_mocks", {}).get(
"covariance_dir",
"/automnt/n17data/cdaley/unions/pure_eb/results/covariance/glass_mock_v1.4.6",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making this config-overridable is a nice touch. The default uses the deprecated pure_eb/ compat symlink though — canonical path is now /automnt/n17data/cdaley/unions/analyses/shear_2d/bmodes_2d/results/covariance/glass_mock_v1.4.6.

Comment thread workflow/rules/covariance.smk Outdated


def fiducial_covariance_outputs(mask_suffix=""):
def fiducial_covariance_outputs(mask_suffix="", probe=DEFAULT_PROBE):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probe=DEFAULT_PROBE binds the default at function-definition time — it happens to work because configure() runs before the includes, but it's fragile ordering. Safer: probe=None and resolve inside (which is also the pattern covariance_base already uses). Relatedly, DEFAULT_PROBE = "wl" hardcoded inside configure() could just be a module-level constant, or read from config if we ever want a non-wl default.

cailmdaley and others added 9 commits July 11, 2026 13:53
The .felt store is relocated to a private ~/loom felt tree and symlinked in
per-checkout; .felt is now gitignored so fiber notes no longer ride into this
shared repo. History is left intact. The symlink is machine-local, not committed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWKwfzFoW9n7UaZQ96aW2A
…ll image from lock (#266)

* felt: fork-implementation — #243 green, #253 rework under fix; fork PRs reviewed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KpaRHk3QwN13myduQ3hJyf

* felt: fork-implementation — constitution absorbs #241 re-rulings (one-file layout, per-part blinding at birth)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KpaRHk3QwN13myduQ3hJyf

* deps: declare cosmo_numba + numba, adopt committed uv.lock, install image from lock

Make sp_validation's environment reproducible so an image build can never
re-resolve numpy past numba's ceiling — the drift that silently upgraded numpy
to 2.5 and broke numba/ngmix.

- Declare cosmo-numba (aguinot/cosmo-numba@main; not on PyPI) — the numba
  B-mode kernels b_modes.py imports. main carries numpy-2 FFT support via its
  rocket-fft dep and declares its own deps, so numba's numpy window reaches the
  resolver. Also pin numba directly: the one load-bearing constraint, made
  visible and resilient to cosmo-numba's dep metadata (which has emptied out
  between refs).
- Declare the other imported-but-undeclared deps the audit found: matplotlib,
  pandas, pyyaml (core, src/); fitsio (glass extra); a new `workflow` extra for
  snakemake + mpi4py. cv_runner and unions_wl left undeclared (no resolvable
  source) with a NOTE.
- requires-python and ruff target -> 3.12 (the container's Python; cosmo-numba's
  floor).
- Commit uv.lock (un-ignored) as the SSOT; scope it to Linux via [tool.uv].
  numpy resolves to 2.4.6, inside numba 0.66's <2.5 window.
- Dockerfile installs from the lock: `uv sync --frozen --inexact` into the base
  image's /app/.venv (--inexact keeps the ShapePipe stack). Drops the ad-hoc
  snakemake layer and the cs_util `--upgrade` workaround — the lock pins
  cs_util 0.2.2 (with cs_util.size), decoupling us from the base image's cs_util.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vtw1qcgTrQ6YuMvxwYzNup

* felt: uv-lock-cosmo-numba — @main resolution, install model, cosmo-numba gotcha finding

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vtw1qcgTrQ6YuMvxwYzNup

* test: don't load base image's stale pytest-pydocstyle/pycodestyle plugins

uv sync installs a newer pytest than the base ShapePipe image's
pytest-pydocstyle/pytest-pycodestyle (>=2.4) expect; their pytest_collect_file
hooks use the removed `path` arg and crash collection. sp_validation lints with
ruff, so disable both via addopts (`-p no:`).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vtw1qcgTrQ6YuMvxwYzNup

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* refactor(masks): single shared mask-condition grammar (closes #181 scope)

Two independently-written YAML mask-condition evaluators had diverged:
Mask.apply() (numexpr, kinds equal/not_equal/greater_equal/smaller_equal/
range) and cosmo_inference/scripts/masking.py's local apply_condition
(plain numpy, kinds equal/not_equal/greater_equal/greater/less_equal/
less/range). Unify to one grammar in sp_validation.masks.apply_condition,
plain numpy (single-comparison numexpr gains are marginal; this drops a
dependency from the shared path). Mask.apply() now delegates to it.
cosmo_inference/scripts/masking.py imports the shared function instead of
carrying its own copy. "smaller_equal" is kept as an alias for
"less_equal" so existing calibration configs (mask_v1.X.{3,9,10,11}.yaml)
keep working unchanged.

Add src/sp_validation/tests/test_masks.py covering every kind, the
smaller_equal alias, the ValueError on unknown kind, and an equivalence
check between Mask.apply() and calling apply_condition directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GPnbTHcheLscjVjnPdC6AH

* build: drop numexpr (last consumer was Mask.apply, now plain numpy)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GPnbTHcheLscjVjnPdC6AH

* refactor: move masking.py to scripts/ (general use beyond inference)

Per Lisa's review suggestion on #230. The script-relative output default
no longer made sense after the move, so --output-dir is now required;
no other behavior change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015HXggJ6p6JCiZcm9kpLc33

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* first commit

* Fix ruff lint/format issues in papers/realspace files

* added back the chain_postprocessing.py script using cs_util functionalities

* fix: resolve ruff lint issues in chain_postprocessing.py

* bug in imports

* ruff linter check

* Fix Ruff formatting in cosmosis fitting script

* changes after review

* Refactor hz_integrand to a named function

* Fix ruff W293: remove trailing whitespace from blank lines in k_analysis.py

* ruff format pass over the 5 drifted files

Formatter drift (quotes, operator spacing, blank lines) accumulated from
per-line lint fixes; one `ruff format` pass settles it. Both `ruff check .`
and `ruff format --check .` now clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Cail Daley <cail.daley@cea.fr>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@LisaGoh
LisaGoh changed the base branch from develop to feature/sp_validation-extend-to-tomography July 24, 2026 15:38
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.

Tomographic real space measurement

2 participants