Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/integration-tests-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Integration Tests

# The CloudSC corpus tests parse a multi-thousand-block SDFG and compile it, which is far too
# slow for the per-push ``General Tests`` matrix -- they carry the ``long`` marker that matrix
# excludes, so without this workflow nothing runs them. Kept to a single Python version: the
# job is bound by the parse and the C++ compile, not by anything version-specific.

on:
push:
branches: [ main, ci-fix ]
pull_request:
branches: [ main, ci-fix ]
merge_group:
branches: [ main, ci-fix ]
workflow_dispatch:

concurrency:
group: ${{github.workflow}}-${{github.ref}}
cancel-in-progress: true

jobs:
cloudsc-e2e:
if: "!contains(github.event.pull_request.labels.*.name, 'no-ci')"
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.14']

steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
# Make dependency setup faster
echo 'set man-db/auto-update false' | sudo debconf-communicate >/dev/null
sudo dpkg-reconfigure man-db
# Install dependencies
sudo apt-get update
sudo apt-get install -y libyaml-dev cmake libblas-dev libopenblas-dev liblapacke-dev
pip install -e ".[testing]"

- name: CloudSC corpus tests
run: |
export NOSTATUSBAR=1
export DACE_cache=unique
# The tests build with ``simplify=False`` and apply simplification as an explicit step,
# so the automatic heuristic must not have run first.
export DACE_optimizer_automatic_simplification=0
# Ask the installed package where it lives instead of assuming the job's directory.
ROOT=$(python -c 'import pathlib, dace; print(pathlib.Path(dace.__file__).resolve().parents[1])')
# No xdist: the SDFG is parsed once per process and memoized, so a worker per test would
# pay the multi-minute parse again instead of sharing one.
pytest --tb=short --timeout_method thread --timeout=3600 \
"$ROOT/tests/corpus/cloudsc_regression_test.py" \
"$ROOT/tests/passes/constant_propagation_on_cloudsc_test.py"
Empty file added tests/corpus/__init__.py
Empty file.
24 changes: 24 additions & 0 deletions tests/corpus/cloudsc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# CloudSC test corpus

The ECMWF `dwarf-p-cloudsc` cloud microphysics kernel, inlined into a single `dace.program`
(`cloudsc.py`). It is callback-free, so `cloudsc_py.to_sdfg()` builds standalone. The result is a
large, wide, deeply nested SDFG (thousands of blocks, nested loop regions many levels deep), which
makes it useful as a scaling test for whole-SDFG analyses and passes.

`generate_data_for_cloudsc.py` provides:

- `build_cloudsc_sdfg(simplify=False)` — the parsed SDFG. The parse takes minutes, so it is memoized
per process in `PARSED_CLOUDSC` and every caller gets a deepcopy: an SDFG is mutable and every
consumer transforms it, so handing out the memoized object would leak one test's edits into the
next. Nothing is written to disk, and under pytest-xdist each worker pays the parse once.
- `generate_cloudsc_inputs(sdfg, seed)` — a physically realistic input set. The physical constants
and the per-array `[min, max]` ranges are the values from the dwarf's `config-files/input.h5`,
mirrored here so nothing external is needed. Random inputs would sit on every threshold in the
kernel, where a harmless floating-point reassociation flips a branch and looks like a bug.
- `run_and_compare(reference, candidate)` — drives both SDFGs on the same inputs and compares every
output array. With the default IEEE build (`-O0`, no fast-math, no FP contraction) and sequential
schedules, a value-preserving transformation reproduces the reference bit-for-bit, hence the
`1e-15` default tolerance.

The grid is small (`klev = klon = 32`) so a compiled run is quick; the input ranges are bounds, not
vertical profiles, so they stay valid at any size.
Empty file.
Loading