diff --git a/CHANGELOG.md b/CHANGELOG.md index 78f4774..062a38d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ history, so they summarise each release rather than list every change. The ### Added +- `tests/mnh_coupled.bash` goes from a bare Linux machine to a coupled + ForeFire + Meso-NH run: it downloads and builds Meso-NH 6.0.1, builds + ForeFire with MPI, links them and runs `tests/mnh_real_nested`. With + `--compare ` it runs the case on both builds and reports the output + files that differ beyond run-to-run noise. ([#266]) - A User Guide page introduces Meso-NH coupling, the supplied cases and the live 3D viewer. - A User Guide page lists the propagation and flux models that have a published reference, with a link to it and how to select each model. @@ -352,3 +357,4 @@ repository stays easy to return to. [#265]: https://github.com/forefireAPI/forefire/issues/265 [#242]: https://github.com/forefireAPI/forefire/pull/242 [#270]: https://github.com/forefireAPI/forefire/pull/270 +[#266]: https://github.com/forefireAPI/forefire/issues/266 diff --git a/docs/mnh/coupledMNHInstall.md b/docs/mnh/coupledMNHInstall.md index 6833dff..1e78a35 100644 --- a/docs/mnh/coupledMNHInstall.md +++ b/docs/mnh/coupledMNHInstall.md @@ -3,125 +3,122 @@ [Meso-NH](https://mesonh.cnrs.fr) is the French atmospheric research model (CNRS / Météo-France). Coupled runs load ForeFire as a shared library: at every step Meso-NH sends wind to the fire and receives heat and vapour fluxes -back. This guide sets the coupling up from scratch and shows how to check -that a change to ForeFire does not alter coupled results. +back. Tested on Ubuntu 24.04 (WSL) with GCC/gfortran 13.3, OpenMPI 4.1.6 and Meso-NH 6.0.1. macOS notes, from an older Meso-NH 5.7 setup, are at the end. -## 1. Prerequisites +## 1. Run the script -```bash -sudo apt install build-essential gfortran openmpi-bin libopenmpi-dev \ - cmake git git-lfs libnetcdf-dev libnetcdf-c++4-dev netcdf-bin -``` - -Use Bash, not Ksh, for everything below. Meso-NH's profile reads -`SRC_MESONH` before defining it, so do not run with `set -u`. - -## 2. Get and build Meso-NH - -The 6.0.1 release is on [Zenodo](https://zenodo.org/records/21395048). The -[CNRS GitLab](https://src.koda.cnrs.fr/mesonh/mesonh-code) also works when it -is reachable (it needs Git LFS). Official instructions: -[download](https://mesonh.readthedocs.io/en/mnh-6-0/getting_started/download.html), -[compile](https://mesonh.readthedocs.io/en/mnh-6-0/getting_started/compile.html). +From a ForeFire clone, in Bash: ```bash -mkdir -p ~/mesonh -tar xzf mnh601.tar.gz -C ~/mesonh -cd ~/mesonh/mesonh-code-PACK-MNH-V6-0-1/src -export ARCH=LXgfortran VER_MPI=MPIAUTO OPTLEVEL=O2 -./configure -. ../conf/profile_mesonh-LXgfortran-R8I4-MNH-V6-0-1-MPIAUTO-O2 -make -j 12 -make installmaster +tests/mnh_coupled.bash ``` -The build takes about 15 minutes on 12 cores. Load the profile in every new -shell before running a case: it sets `SRC_MESONH` and `XYZ`, which the test -scripts use. +It goes from a bare Linux machine to a finished coupled run, and skips +whatever is already done, so running it again is cheap: -## 3. Build ForeFire and link it +1. Checks the prerequisites and, if any are missing, prints the + `sudo apt install` line for them. It never runs `sudo` itself. +2. Downloads Meso-NH 6.0.1 from [Zenodo](https://zenodo.org/records/21395048) + (190 MB) and checks its MD5. `--tarball FILE` uses a copy you already have. +3. Builds Meso-NH: about 15 minutes on 12 cores. +4. Builds the ForeFire library with MPI, from the clone the script is in. +5. Links it as `$SRC_MESONH/exe/libForeFire.so`. +6. Runs `tests/mnh_real_nested` in a fresh copy: Pedrógão Grande 2017, two + nested domains, 4 MPI processes, about 7 minutes. -MPI is on by default in a plain CMake build. Check that the configure output -says MPI was found: without it the coupled run does not work. A warning that -the Git LFS check failed for files under `tests/runff` does not matter here; -the `mnh_*` files must be listed as OK. +To watch the run in 3D (terrain, fire front, plume, wind), open + while it runs (it loads three.js from a +CDN, so the browser needs internet; use one tab at a time). -```bash -git clone https://github.com/forefireAPI/forefire.git -cd forefire -git lfs pull -cmake -S . -B build -cmake --build build -j 4 -``` +Everything goes under `~/forefire-mnh` (`--workdir` or `FF_MNH_WORKDIR` to +change it), about 10 GB: Meso-NH, the ForeFire builds, `logs/` and one +directory per run under `runs/`. `--help` lists the options. -This produces `lib/libforefireL.so`. Meso-NH opens -`$SRC_MESONH/exe/libForeFire.so` at run time, so link it there: +The packages it asks for on Ubuntu: ```bash -ln -sf "$PWD/lib/libforefireL.so" "$SRC_MESONH/exe/libForeFire.so" +sudo apt install build-essential gfortran openmpi-bin libopenmpi-dev \ + cmake git git-lfs curl libnetcdf-dev libnetcdf-c++4-dev ``` -## 4. Run a coupled case - -Two cases ship with ForeFire: - -| Case | What it is | -| --- | --- | -| `tests/mnh_real_nested` | Pedrógão Grande 2017, two nested domains, 4 MPI processes, 1200 s of simulation (about 7 min) | -| `tests/mnh_ideal` | Idealised relief, single domain, a few seconds; needs `ncgen` (from `netcdf-bin`) | +## 2. Check that a change does not alter coupled results ```bash -cd tests/mnh_real_nested -bash clean.bash -bash run.bash +tests/mnh_coupled.bash --compare my-branch ``` -`run.bash` only checks that `ForeFire/Outputs/ForeFire.0.nc` exists and is -larger than 15 kB. It does not compare against `ForeFire.0.nc.ref`, and the -grid size depends on the Meso-NH version (680×680 on 6.0.1, 666×666 reported -on 6.1). A meaningful check is the comparison in section 5. - -`mnh_real_nested/ForeFire/Init.ff` starts -`listenHTTP[host=127.0.0.1:8080]`, so port 8080 must be free. - -To watch the run in 3D (terrain, fire front, plume, wind), export -`FOREFIREHOME=/path/to/forefire` before `run.bash` and open - while it runs (it loads three.js from a -CDN, so the browser needs internet). The page sends commands that run -alongside the time step, so leave it closed for the comparison in section 5; -use one tab at a time. - -## 5. Check that a change does not alter coupled results +`--compare` takes a branch, tag or commit of the same clone, or a directory +with another ForeFire source tree. The script builds both, runs the case four +times (this clone, the other one, this clone, the other one), switching the +`libForeFire.so` link before each run, and compares byte for byte the files +in `ForeFire/Outputs`, `MODEL1`, `MODEL2` and the `RUN12.*.FIRE.*.nc` files. +It takes about 30 minutes and exits non-zero on a real difference. Leave +`mnh3d.html` closed during `--compare`, as it sends commands that run +alongside the time step. -Run the same case with ForeFire built from `dev` and from the branch under -review, and compare the outputs byte for byte. - -1. Build both versions with the same options, each in its own worktree - (`git worktree add ../ff-pr `). -2. Make a clean copy of the case for each run. -3. Run `dev`, branch, `dev`, branch, switching the `libForeFire.so` link - before each run. -4. Compare with `cmp` the files in `ForeFire/Outputs`, `MODEL1`, `MODEL2` and - the `RUN12.*.FIRE.*.nc` files. - -Two runs of the same build already differ in a few places, so the second -`dev` run is what separates noise from a real change: +Two runs of the same build already differ in a few places, so the second run +of this clone is what separates noise from a real change: - `RUN12.*.FIRE.*.nc`: 7 to 9 bytes, the timestamp in the `history` attribute and the HDF5 header checksum. - `MODEL*/output.*.air_density`: meaningless values (NaN, ±10¹⁰) that change on every run. This comes from Meso-NH, not from ForeFire. -Everything else must be identical. A file that differs between `dev` and the -branch, but not between the two `dev` runs, is a real difference. +Everything else must be identical. A file that differs between the two +builds, but not between the two runs of this clone, is a real difference. +A file that differs between the two runs of this clone and is not in the list +above is reported as unexpected noise. + +## 3. What the script relies on + +What follows explains the setup for anyone doing it by hand or debugging it. +Official Meso-NH instructions: +[download](https://mesonh.readthedocs.io/en/mnh-6-0/getting_started/download.html), +[compile](https://mesonh.readthedocs.io/en/mnh-6-0/getting_started/compile.html). +The [CNRS GitLab](https://src.koda.cnrs.fr/mesonh/mesonh-code) also has the +sources when it is reachable (it needs Git LFS). + +- **Meso-NH build.** `ARCH=LXgfortran VER_MPI=MPIAUTO OPTLEVEL=O2 ./configure` + in `src/`, then load the profile it writes in `conf/`, then `make` and + `make installmaster`. The profile sets `SRC_MESONH` and `XYZ`, which the + test cases use, so load it in every new shell before running one by hand. + It reads `SRC_MESONH` before defining it, so do not use `set -u` around it. +- **ForeFire build.** `cmake -S . -B build -DFOREFIRE_ENABLE_MPI=ON`. The + configuration summary must say `MPI .......... ON`: without MPI the coupled + run does not work. Whatever the build directory, CMake writes + `lib/libforefireL.so` into the source tree, so two builds of one tree + overwrite each other's library. The script copies it to + `forefire//libforefireL.so` in its work directory before linking. +- **The link.** Meso-NH opens `$SRC_MESONH/exe/libForeFire.so` at run time: + + ```bash + ln -sf /path/to/libforefireL.so "$SRC_MESONH/exe/libForeFire.so" + ``` + +- **Case data.** The `mnh_*` inputs are in Git LFS. If they are short text + stubs, the script runs `git lfs pull` for the case. +- **Port 8080.** `mnh_real_nested/ForeFire/Init.ff` starts + `listenHTTP[host=127.0.0.1:8080]`, so the port must be free; the script + stops if it is not. With `FOREFIREHOME` set to the ForeFire clone, which + the script does, that server also serves the pages in `tools/htdocs`. +- **What `run.bash` checks.** Only that `ForeFire/Outputs/ForeFire.0.nc` + exists and is larger than 15 kB. It does not compare against + `ForeFire.0.nc.ref`, and the grid size depends on the Meso-NH version + (680×680 on 6.0.1, 666×666 reported on 6.1). The comparison in section 2 + is the meaningful check. + +The other coupled case, `tests/mnh_ideal` (idealised relief, single domain, a +few seconds), is not run by the script. With the profile loaded and the link +in place: `cd tests/mnh_ideal && bash clean.bash && bash run.bash`. It needs +`ncgen`, from `netcdf-bin`. ## macOS notes (Meso-NH 5.7) -These come from an earlier setup on Apple Silicon with macOS Ventura and -Meso-NH 5.7. They may no longer apply to 6.x. +The script targets Linux. These notes come from an earlier setup on Apple +Silicon with macOS Ventura and Meso-NH 5.7. They may no longer apply to 6.x. Install `gcc`, `gfortran` and `open-mpi` with Homebrew. On 5.7, also `export MNH_FOREFIRE=1.0` before `./configure`. The library is diff --git a/tests/README.md b/tests/README.md index fd64c24..855fc5b 100644 --- a/tests/README.md +++ b/tests/README.md @@ -30,8 +30,10 @@ ctest --test-dir build --output-on-failure * The test fixtures are stored in **Git LFS**. `git lfs pull` if the `.nc` files look like short text stubs. -* *(optional)* **Meso-NH**, for the `mnh_*` tests only. Setup and the `dev` × PR - check: [`docs/mnh/coupledMNHInstall.md`](../docs/mnh/coupledMNHInstall.md). +* *(optional)* **Meso-NH**, for the `mnh_*` tests only. `mnh_coupled.bash` + builds it, links ForeFire and runs `mnh_real_nested`; with `--compare` it + runs the `dev` × PR check. See + [`docs/mnh/coupledMNHInstall.md`](../docs/mnh/coupledMNHInstall.md). ```bash # sets SRC_MESONH and XYZ, which the mnh_* scripts use diff --git a/tests/mnh_coupled.bash b/tests/mnh_coupled.bash new file mode 100755 index 0000000..8cd0d4c --- /dev/null +++ b/tests/mnh_coupled.bash @@ -0,0 +1,340 @@ +#!/usr/bin/env bash +# From a bare Linux machine to a running ForeFire + Meso-NH coupled case. +# Run with --help for usage. Each step is skipped when already done. + +# No `set -u`: Meso-NH's profile reads SRC_MESONH before defining it. +set -eo pipefail + +usage() { + cat <<'EOF' +Usage: tests/mnh_coupled.bash [options] + +Builds Meso-NH 6.0.1 and ForeFire (with MPI), links them, and runs the +tests/mnh_real_nested case (Pedrógão Grande, 4 MPI processes, about 7 min). +Steps that are already done are skipped, so running it again is cheap. + +Options: + --workdir DIR where Meso-NH, the ForeFire builds and the runs go + (default: $FF_MNH_WORKDIR or ~/forefire-mnh) + --tarball FILE use this Meso-NH 6.0.1 tarball instead of downloading it + (default: $MNH_TARBALL) + --jobs N parallel build jobs (default: all cores) + --compare REF instead of a single run, build a second ForeFire from REF + (a branch, tag or commit of this repository, or a directory + with a ForeFire source tree), run this tree, REF, this tree, + REF, and compare the outputs byte for byte. Exits 1 if a + file differs between the two builds but not between the + two runs of this tree. + -h, --help show this help + +Needs Bash, about 10 GB of disk and port 8080 free (the case starts +ForeFire's HTTP server there). Never runs sudo: missing packages are listed +with the apt command to install them. +EOF +} + +# --- settings ----------------------------------------------------------------- + +REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +CASE="tests/mnh_real_nested" +PORT=8080 + +MNH_NAME="mesonh-code-PACK-MNH-V6-0-1" +MNH_URL="https://zenodo.org/records/21395048/files/$MNH_NAME.tar.gz?download=1" +MNH_MD5="ed745f20435d5c0afbfc269b29513da5" # published by Zenodo + +WORKDIR="${FF_MNH_WORKDIR:-$HOME/forefire-mnh}" +TARBALL="${MNH_TARBALL:-}" +JOBS="$(nproc 2>/dev/null || echo 4)" +COMPARE="" + +while [ $# -gt 0 ]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --tarball) TARBALL="$2"; shift 2 ;; + --jobs) JOBS="$2"; shift 2 ;; + --compare) COMPARE="$2"; shift 2 ;; + -h|--help) usage; exit 0 ;; + *) echo "Unknown option: $1 (see --help)" >&2; exit 2 ;; + esac +done + +mkdir -p "$WORKDIR/logs" +WORKDIR="$(cd "$WORKDIR" && pwd)" +LOGS="$WORKDIR/logs" +MNH_DIR="$WORKDIR/$MNH_NAME" + +# --- helpers ------------------------------------------------------------------ + +die() { printf '\nerror: %s\n' "$*" >&2; exit 1; } + +TIMINGS=() +STEP_NAME="" STEP_START=0 +step() { + step_done + STEP_NAME="$1" STEP_START=$SECONDS + printf '\n==> %s\n' "$1" +} +step_done() { + [ -n "$STEP_NAME" ] || return 0 + local s=$((SECONDS - STEP_START)) + TIMINGS+=("$(printf '%4dm%02ds %s' $((s / 60)) $((s % 60)) "$STEP_NAME")") + STEP_NAME="" +} +print_timings() { + step_done + printf '\nTime per step:\n' + printf ' %s\n' "${TIMINGS[@]}" +} + +# Run a command with its output in a log file; show the end of it on failure. +logged() { + local log="$1"; shift + echo " log: $log" + if ! "$@" >"$log" 2>&1; then + tail -n 30 "$log" >&2 + die "failed: $* (full log: $log)" + fi +} + +md5_ok() { [ "$(md5sum "$1" | cut -d' ' -f1)" = "$MNH_MD5" ]; } + +port_busy() { (exec 3<>"/dev/tcp/127.0.0.1/$PORT") 2>/dev/null; } + +# --- 1. prerequisites --------------------------------------------------------- + +check_prerequisites() { + step "1. Prerequisites" + local missing=() pair + for pair in gcc:build-essential g++:build-essential make:build-essential \ + gfortran:gfortran mpicc:libopenmpi-dev mpif90:libopenmpi-dev \ + mpiexec:openmpi-bin cmake:cmake git:git git-lfs:git-lfs \ + curl:curl nc-config:libnetcdf-dev ncxx4-config:libnetcdf-c++4-dev; do + command -v "${pair%%:*}" >/dev/null || missing+=("${pair#*:}") + done + if [ ${#missing[@]} -gt 0 ]; then + echo "Missing packages. Install them with:" + echo " sudo apt install $(printf '%s\n' "${missing[@]}" | sort -u | tr '\n' ' ')" + die "prerequisites missing" + fi + echo " all found" +} + +# --- 2. Meso-NH sources ------------------------------------------------------- + +get_mesonh() { + step "2. Meso-NH 6.0.1 tarball" + if [ -n "$TARBALL" ]; then + [ -f "$TARBALL" ] || die "tarball not found: $TARBALL" + md5_ok "$TARBALL" || die "$TARBALL is not the Zenodo 6.0.1 tarball (MD5 mismatch)" + echo " using $TARBALL (checksum OK)" + return + fi + TARBALL="$WORKDIR/$MNH_NAME.tar.gz" + if [ -f "$TARBALL" ] && md5_ok "$TARBALL"; then + echo " already downloaded: $TARBALL" + return + fi + echo " downloading from Zenodo (190 MB)" + curl -fL --retry 3 -o "$TARBALL.part" "$MNH_URL" + md5_ok "$TARBALL.part" || die "downloaded file has the wrong MD5; try again" + mv "$TARBALL.part" "$TARBALL" +} + +# --- 3. Meso-NH build --------------------------------------------------------- + +load_mesonh_profile() { + local profile + profile="$(ls "$MNH_DIR"/conf/profile_mesonh-LXgfortran-*-MPIAUTO-O2 2>/dev/null | head -n 1)" + [ -n "$profile" ] || die "no Meso-NH profile in $MNH_DIR/conf" + # The profile warns when SRC_MESONH is already set, and does not expect -e. + unset SRC_MESONH XYZ + set +e + . "$profile" >/dev/null + set -e + [ -n "$SRC_MESONH" ] && [ -n "$XYZ" ] || die "loading $profile did not set SRC_MESONH and XYZ" +} + +build_mesonh() { + step "3. Meso-NH build" + if [ ! -f "$MNH_DIR/.extracted" ]; then + echo " extracting into $WORKDIR" + rm -rf "$MNH_DIR" + tar xzf "$TARBALL" -C "$WORKDIR" + touch "$MNH_DIR/.extracted" + fi + if ! ls "$MNH_DIR"/conf/profile_mesonh-LXgfortran-*-MPIAUTO-O2 >/dev/null 2>&1; then + echo " configure" + (cd "$MNH_DIR/src" && export ARCH=LXgfortran VER_MPI=MPIAUTO OPTLEVEL=O2 && + logged "$LOGS/mesonh-configure.log" ./configure) + fi + load_mesonh_profile + if [ -x "$SRC_MESONH/exe/MESONH$XYZ" ]; then + echo " already built: $SRC_MESONH/exe/MESONH$XYZ" + return + fi + echo " make -j $JOBS (about 15 min on 12 cores)" + (cd "$SRC_MESONH/src" && logged "$LOGS/mesonh-make.log" make -j "$JOBS" && + logged "$LOGS/mesonh-install.log" make installmaster) +} + +# --- 4. ForeFire build -------------------------------------------------------- + +# build_forefire SRC NAME: builds the ForeFire library of source tree SRC and +# copies it to $WORKDIR/forefire/NAME/libforefireL.so. +build_forefire() { + local src="$1" dest="$WORKDIR/forefire/$2" + echo " $src -> $dest" + mkdir -p "$dest" + logged "$dest/cmake.log" cmake -S "$src" -B "$dest/build" \ + -DFOREFIRE_ENABLE_MPI=ON -DFOREFIRE_CHECK_LFS=OFF + grep -q 'MPI \.* ON' "$dest/cmake.log" || die "CMake did not find MPI (see $dest/cmake.log)" + # CMake writes the library into SRC/lib whatever the build directory. + # Removing it forces a relink from this build directory, and the copy keeps + # it safe from the next build of the same tree. + rm -f "$src/lib/libforefireL.so" + logged "$dest/build.log" cmake --build "$dest/build" --target forefireL -j "$JOBS" + cp "$src/lib/libforefireL.so" "$dest/libforefireL.so" +} + +# --- 5. link ------------------------------------------------------------------ + +link_forefire() { + ln -sfn "$1" "$SRC_MESONH/exe/libForeFire.so" + echo " $SRC_MESONH/exe/libForeFire.so -> $1" +} + +# --- 6. run ------------------------------------------------------------------- + +# The case's NetCDF inputs are in Git LFS; a clone without it has text stubs. +is_lfs_stub() { head -c 200 "$1" | grep -q 'git-lfs.github.com/spec'; } + +check_case_data() { + local probe="$REPO/$CASE/RUN12.1.PRUN1.004.nc" + if is_lfs_stub "$probe"; then + echo " fetching the case's Git LFS files" + git -C "$REPO" lfs pull --include "$CASE/**" + ! is_lfs_stub "$probe" || die "$probe is still a Git LFS stub" + fi + echo " case data present" +} + +# run_case DIR FOREFIREHOME: fresh copy of the case in DIR, then run.bash. +run_case() { + local dir="$1" home="$2" + rm -rf "$dir" + mkdir -p "$(dirname "$dir")" + cp -r "$REPO/$CASE" "$dir" + (cd "$dir" && bash clean.bash) + port_busy && die "port $PORT is in use; stop whatever listens there and run again" + echo " running in $dir (about 7 min), log: $dir/run.log" + if ! (cd "$dir" && FOREFIREHOME="$home" bash run.bash) >"$dir/run.log" 2>&1; then + tail -n 30 "$dir/run.log" >&2 + die "run failed (full log: $dir/run.log)" + fi + echo " ForeFire.0.nc: $(wc -c <"$dir/ForeFire/Outputs/ForeFire.0.nc") bytes" +} + +# --- 7. comparison ------------------------------------------------------------ + +# Files that differ between two runs of the same build. +known_noise() { + case "$1" in + RUN12.*.FIRE.*.nc|MODEL*/output.*.air_density) return 0 ;; + *) return 1 ;; + esac +} + +# Source tree for --compare: a directory as given, or REF exported from git. +compare_source() { + local ref="$1" commit dest="$WORKDIR/src/compare" + if [ -d "$ref" ]; then + (cd "$ref" && pwd) + return + fi + commit="$(git -C "$REPO" rev-parse --verify --quiet "$ref^{commit}" || + git -C "$REPO" rev-parse --verify --quiet "origin/$ref^{commit}")" || + die "--compare $ref: not a directory, nor a branch, tag or commit of $REPO" + if [ "$(cat "$dest/.commit" 2>/dev/null)" != "$commit" ]; then + rm -rf "$dest" + mkdir -p "$dest" + git -C "$REPO" archive "$commit" | tar x -C "$dest" + echo "$commit" >"$dest/.commit" + fi + echo "$dest" +} + +same() { cmp -s "$1" "$2"; } + +compare_runs() { + local a1="$1/this-1" b1="$1/other-1" a2="$1/this-2" b2="$1/other-2" + local f files real=0 noise=0 unexpected=0 identical=0 + files="$(for d in "$a1" "$b1"; do + (cd "$d" && find ForeFire/Outputs MODEL1 MODEL2 -type f && ls RUN12.*.FIRE.*.nc) + done 2>/dev/null | sort -u)" || true + printf '\n' + while IFS= read -r f; do + [ -n "$f" ] || continue + if [ ! -f "$a1/$f" ] || [ ! -f "$b1/$f" ]; then + echo " REAL $f (only in one of the two builds' outputs)" + real=$((real + 1)) + elif same "$a1/$f" "$b1/$f" && same "$a2/$f" "$b2/$f"; then + identical=$((identical + 1)) + elif ! same "$a1/$f" "$a2/$f"; then + if known_noise "$f"; then + noise=$((noise + 1)) + else + echo " NOISE? $f (differs between the two runs of this tree too; not in the known list)" + unexpected=$((unexpected + 1)) + fi + else + echo " REAL $f" + real=$((real + 1)) + fi + done <<< "$files" + printf '\n %d identical, %d known noise, %d unexpected noise, %d real differences\n' \ + "$identical" "$noise" "$unexpected" "$real" + [ "$real" -eq 0 ] +} + +# --- main --------------------------------------------------------------------- + +echo "ForeFire: $REPO" +echo "Work dir: $WORKDIR" +trap 'print_timings' EXIT + +check_prerequisites +get_mesonh +build_mesonh + +step "4. ForeFire build (MPI)" +build_forefire "$REPO" this +if [ -n "$COMPARE" ]; then + OTHER_SRC="$(compare_source "$COMPARE")" + build_forefire "$OTHER_SRC" other +fi + +step "5. Link and case data" +link_forefire "$WORKDIR/forefire/this/libforefireL.so" +check_case_data + +RUN_ID="$(date +%Y%m%d-%H%M%S)" +if [ -z "$COMPARE" ]; then + step "6. Run $CASE" + echo " To watch it in 3D, open http://localhost:$PORT/mnh3d.html while it runs" + run_case "$WORKDIR/runs/$RUN_ID" "$REPO" + echo " done: $WORKDIR/runs/$RUN_ID" + exit 0 +fi + +step "7. Compare this tree with $COMPARE" +echo " Four runs of about 7 min each. Keep the 3D page closed: it sends commands to the run." +ROOT="$WORKDIR/runs/compare-$RUN_ID" +for run in this-1 other-1 this-2 other-2; do + if [ "${run%-*}" = this ]; then src="$REPO"; else src="$OTHER_SRC"; fi + link_forefire "$WORKDIR/forefire/${run%-*}/libforefireL.so" + run_case "$ROOT/$run" "$src" +done +# Leave Meso-NH linked to this tree, as after a plain run. +link_forefire "$WORKDIR/forefire/this/libforefireL.so" +compare_runs "$ROOT"