Add explicit fixed-mode projectors for native convergence #8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Cosmology Q-R2 resolution ladder | |
| on: | |
| push: | |
| branches: | |
| - dark-sector-stability-architecture | |
| paths: | |
| - 'dark_sector_architecture/qualification/fourier_resolution.py' | |
| - 'dark_sector_architecture/qualification/run_qr2_resolution_pair.py' | |
| - 'dark_sector_architecture/qualification/latfield_hdf5.py' | |
| - 'dark_sector_architecture/qualification/weak_field_tensors.py' | |
| - 'dark_sector_architecture/qualification/modal_convergence.py' | |
| - '.github/workflows/cosmology-q-r2-resolution-pair.yml' | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: cosmology-q-r2-resolution-ladder | |
| cancel-in-progress: true | |
| jobs: | |
| q-r2-pair: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| env: | |
| GEVOLUTION_SHA: 0cca42e51a824002ae4fb602cbd79d671e8ffe60 | |
| LATFIELD2_SHA: 2d8c737ab6adc965a1d2718c209f5085af27b09c | |
| TEMPLATE_BLOB: d4de9a5400ef58f6a0181fbe61f18056b233a425 | |
| SEED: 424242 | |
| BOXSIZE: 64.0 | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: dark-sector-stability-architecture | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Install build and analysis dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential \ | |
| openmpi-bin \ | |
| libopenmpi-dev \ | |
| libfftw3-dev \ | |
| libgsl-dev \ | |
| libhdf5-dev | |
| python -m pip install --upgrade pip | |
| python -m pip install numpy h5py | |
| - name: Fetch pinned gevolution and canonical CPU LATfield2 | |
| run: | | |
| git clone https://github.com/gevolution-code/gevolution-1.3.git gevolution | |
| git -C gevolution checkout "$GEVOLUTION_SHA" | |
| git clone https://gitlab.uzh.ch/julian.adamek/LATfield2.git LATfield2 | |
| git -C LATfield2 checkout "$LATFIELD2_SHA" | |
| printf 'gevolution=%s\nLATfield2=%s\n' \ | |
| "$(git -C gevolution rev-parse HEAD)" \ | |
| "$(git -C LATfield2 rev-parse HEAD)" \ | |
| | tee qr2_upstream_revisions.txt | |
| - name: Fetch and verify canonical sc1 particle template | |
| run: | | |
| curl -L --fail --silent --show-error \ | |
| https://raw.githubusercontent.com/gevolution-code/gevolution-1.2/df8a930732aae1bafa32fd839ee70728bb10773a/sc1_crystal.dat \ | |
| -o gevolution/qr2_template.dat | |
| test "$(git hash-object gevolution/qr2_template.dat)" = "$TEMPLATE_BLOB" | |
| - name: Compile gevolution with velocity output | |
| working-directory: gevolution | |
| run: | | |
| make clean | |
| make -j2 \ | |
| INCLUDE="-I../LATfield2 -I/usr/include/hdf5/serial" \ | |
| LIB="-lfftw3 -lm -L/usr/lib/x86_64-linux-gnu/hdf5/serial -lhdf5 -lgsl -lgslcblas" \ | |
| DGEVOLUTION="-DPHINONLINEAR -DBENCHMARK -DEXACT_OUTPUT_REDSHIFTS -DVELOCITY" | |
| test -x gevolution | |
| - name: Build matched N8 and N16 settings | |
| run: | | |
| python - <<'PY' | |
| from pathlib import Path | |
| base = Path( | |
| "dark_sector_architecture/qualification/gevolution_modal_pilot.ini" | |
| ).read_text() | |
| def settings(n, tiling, tag): | |
| text = base | |
| replacements = { | |
| "template file = pilot_template.dat": "template file = qr2_template.dat", | |
| "tiling factor = 2": f"tiling factor = {tiling}", | |
| "Ngrid = 8": f"Ngrid = {n}", | |
| "output path = ../pilot_output/": f"output path = ../qr2_{tag}_output/", | |
| "generic file base = modalpilot": f"generic file base = qr2_{tag}", | |
| "snapshot file base = modalpilot_snap": f"snapshot file base = qr2_{tag}_snap", | |
| "Pk file base = modalpilot_pk": f"Pk file base = qr2_{tag}_pk", | |
| } | |
| for old, new in replacements.items(): | |
| if old not in text: | |
| raise SystemExit(f"missing expected settings token: {old}") | |
| text = text.replace(old, new, 1) | |
| return text | |
| Path("gevolution/qr2_n8.ini").write_text(settings(8, 2, "n8")) | |
| Path("gevolution/qr2_n16.ini").write_text(settings(16, 4, "n16")) | |
| Path("gevolution/qr2_n32.ini").write_text(settings(32, 8, "n32")) | |
| PY | |
| cat gevolution/qr2_n8.ini | |
| cat gevolution/qr2_n16.ini | |
| cat gevolution/qr2_n32.ini | |
| - name: Run matched N8 development member | |
| run: | | |
| set -o pipefail | |
| rm -rf qr2_n8_output | |
| mkdir -p qr2_n8_output | |
| cd gevolution | |
| mpirun --oversubscribe -np 4 ./gevolution -n 2 -m 2 -s qr2_n8.ini \ | |
| | tee ../qr2_n8.log | |
| - name: Run matched N16 development member | |
| run: | | |
| set -o pipefail | |
| rm -rf qr2_n16_output | |
| mkdir -p qr2_n16_output | |
| cd gevolution | |
| mpirun --oversubscribe -np 4 ./gevolution -n 2 -m 2 -s qr2_n16.ini \ | |
| | tee ../qr2_n16.log | |
| - name: Run matched N32 development member | |
| run: | | |
| set -o pipefail | |
| rm -rf qr2_n32_output | |
| mkdir -p qr2_n32_output | |
| cd gevolution | |
| mpirun --oversubscribe -np 4 ./gevolution -n 2 -m 2 -s qr2_n32.ini \ | |
| | tee ../qr2_n32.log | |
| - name: Verify matched output epochs and required fields | |
| run: | | |
| python - <<'PY' | |
| import re | |
| from pathlib import Path | |
| pattern = re.compile(r"writing snapshot at z = ([0-9eE+.-]+)") | |
| values = {} | |
| for tag in ("n8", "n16", "n32"): | |
| text = Path(f"qr2_{tag}.log").read_text() | |
| match = pattern.search(text) | |
| if match is None: | |
| raise SystemExit(f"no snapshot redshift found for {tag}") | |
| values[tag] = float(match.group(1)) | |
| for token in ("_phi.h5", "_v.h5"): | |
| files = list(Path(f"qr2_{tag}_output").glob(f"*{token}")) | |
| if not files: | |
| raise SystemExit(f"missing {tag} {token}") | |
| print("snapshot redshifts:", values) | |
| if max(values.values()) - min(values.values()) > 1e-12: | |
| raise SystemExit(f"output epochs do not match: {values}") | |
| Path("qr2_output_epoch.txt").write_text( | |
| f'{values["n8"]:.17g}\n' | |
| ) | |
| PY | |
| - name: Measure N8-N16 phase compatibility and resolution difference | |
| run: | | |
| low_phi="$(find qr2_n8_output -type f -name '*_phi.h5' | head -n 1)" | |
| low_v="$(find qr2_n8_output -type f -name '*_v.h5' | head -n 1)" | |
| high_phi="$(find qr2_n16_output -type f -name '*_phi.h5' | head -n 1)" | |
| high_v="$(find qr2_n16_output -type f -name '*_v.h5' | head -n 1)" | |
| python dark_sector_architecture/qualification/run_qr2_resolution_pair.py \ | |
| --low-phi "$low_phi" \ | |
| --low-velocity "$low_v" \ | |
| --high-phi "$high_phi" \ | |
| --high-velocity "$high_v" \ | |
| --boxsize "$BOXSIZE" \ | |
| --output dark_sector_architecture/qualification/results/q_r2_n8_n16_resolution_pair.json | |
| - name: Measure N16-N32 phase compatibility and resolution difference | |
| run: | | |
| low_phi="$(find qr2_n16_output -type f -name '*_phi.h5' | head -n 1)" | |
| low_v="$(find qr2_n16_output -type f -name '*_v.h5' | head -n 1)" | |
| high_phi="$(find qr2_n32_output -type f -name '*_phi.h5' | head -n 1)" | |
| high_v="$(find qr2_n32_output -type f -name '*_v.h5' | head -n 1)" | |
| python dark_sector_architecture/qualification/run_qr2_resolution_pair.py \ | |
| --low-phi "$low_phi" \ | |
| --low-velocity "$low_v" \ | |
| --high-phi "$high_phi" \ | |
| --high-velocity "$high_v" \ | |
| --boxsize "$BOXSIZE" \ | |
| --output dark_sector_architecture/qualification/results/q_r2_n16_n32_resolution_pair.json | |
| - name: Add run provenance | |
| run: | | |
| python - <<'PY' | |
| import json | |
| from pathlib import Path | |
| epoch = float(Path("qr2_output_epoch.txt").read_text()) | |
| pairs = [ | |
| ("q_r2_n8_n16_resolution_pair.json", 8, 16, 2, 4, 512, 4096), | |
| ("q_r2_n16_n32_resolution_pair.json", 16, 32, 4, 8, 4096, 32768), | |
| ] | |
| root = Path("dark_sector_architecture/qualification/results") | |
| for filename, low_n, high_n, low_tiling, high_tiling, low_p, high_p in pairs: | |
| path = root / filename | |
| data = json.loads(path.read_text()) | |
| data["pair_definition"] = { | |
| "seed": 424242, | |
| "template_source": "gevolution-code/gevolution-1.2/sc1_crystal.dat", | |
| "template_blob": "d4de9a5400ef58f6a0181fbe61f18056b233a425", | |
| "gevolution_sha": "0cca42e51a824002ae4fb602cbd79d671e8ffe60", | |
| "latfield2_sha": "2d8c737ab6adc965a1d2718c209f5085af27b09c", | |
| "low_grid": low_n, | |
| "high_grid": high_n, | |
| "low_tiling": low_tiling, | |
| "high_tiling": high_tiling, | |
| "low_particles": low_p, | |
| "high_particles": high_p, | |
| "requested_snapshot_redshift": 99.0, | |
| "actual_snapshot_redshift": epoch, | |
| } | |
| path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n") | |
| PY | |
| - name: Upload paired-resolution artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: cosmology-q-r2-resolution-ladder | |
| path: | | |
| qr2_upstream_revisions.txt | |
| gevolution/qr2_n8.ini | |
| gevolution/qr2_n16.ini | |
| gevolution/qr2_n32.ini | |
| qr2_n8.log | |
| qr2_n16.log | |
| qr2_n32.log | |
| qr2_output_epoch.txt | |
| qr2_n8_output/*_phi.h5 | |
| qr2_n8_output/*_v.h5 | |
| qr2_n16_output/*_phi.h5 | |
| qr2_n16_output/*_v.h5 | |
| qr2_n32_output/*_phi.h5 | |
| qr2_n32_output/*_v.h5 | |
| dark_sector_architecture/qualification/results/q_r2_n8_n16_resolution_pair.json | |
| dark_sector_architecture/qualification/results/q_r2_n16_n32_resolution_pair.json | |
| if-no-files-found: error | |
| - name: Persist paired-resolution report | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add \ | |
| dark_sector_architecture/qualification/results/q_r2_n8_n16_resolution_pair.json \ | |
| dark_sector_architecture/qualification/results/q_r2_n16_n32_resolution_pair.json | |
| if git diff --cached --quiet; then | |
| echo "Q-R2 report unchanged." | |
| exit 0 | |
| fi | |
| git commit -m "Persist Q-R2 resolution ladder" | |
| git fetch origin dark-sector-stability-architecture | |
| git rebase origin/dark-sector-stability-architecture | |
| git push origin HEAD:dark-sector-stability-architecture |