diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index cbcf2828..1004ac47 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -5,3 +5,4 @@ add_subdirectory(poisson) add_subdirectory(linelast) add_subdirectory(stokes) +add_subdirectory(steady_ns) diff --git a/examples/steady_ns/.gitignore b/examples/steady_ns/.gitignore new file mode 100644 index 00000000..7e4f7895 --- /dev/null +++ b/examples/steady_ns/.gitignore @@ -0,0 +1,7 @@ +basis/ +configs/ +logs/ +meshes/ +results/ +rom/ +snapshots/ diff --git a/examples/steady_ns/CMakeLists.txt b/examples/steady_ns/CMakeLists.txt new file mode 100644 index 00000000..aadc6333 --- /dev/null +++ b/examples/steady_ns/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright 2026 Lawrence Livermore National Security, LLC. +# SPDX-License-Identifier: MIT + +set(STEADY_NS_EXAMPLE_FILES + README.md + generate_configs.py + prepare_meshes.sh + report_results.py + steady_ns.yml + submit_workflow.sh) + +foreach(example_file IN LISTS STEADY_NS_EXAMPLE_FILES) + configure_file(${example_file} ${example_file} COPYONLY) +endforeach() + +file(COPY jobs DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + diff --git a/examples/steady_ns/README.md b/examples/steady_ns/README.md new file mode 100644 index 00000000..f283c25e --- /dev/null +++ b/examples/steady_ns/README.md @@ -0,0 +1,15 @@ +# Steady Navier--Stokes paper workflow + +This reproduces the paper's representative 16x16, Re=25 tensorial-ROM case. It uses five component types, 2,000 random 2x2 training arrays (five jobs of 400), and 40 velocity, pressure, and supremizer modes per component. Meshes and HDF5 configurations are generated at run time and are not stored in the repository. + +Install and build on Dane, then run from the configured build example: + +```bash +./script/install_dane.bash +cd build/examples/steady_ns +./submit_workflow.sh +``` + +The submission chain runs mesh/configuration generation, sampling, `train_rom` POD and supremizer training, tensorial operator construction, a 16x16 FOM solve, and the dependent ROM comparison. If `train_rom` writes the POD bases but reaches its wall-time limit during supremizer enrichment, resume that step with `sbatch jobs/03_auxiliary.sbatch`; this fallback job is not part of the normal chain. Jobs use the paper/legacy Dane settings (`pbatch`, account `sosu`; one 2 GB single-thread task for online runs; 5 nodes and 36 MPI ranks for POD training). Override Slurm options when needed, for example `./submit_workflow.sh --account=my_account`. + +Outputs are under `snapshots/`, `basis/`, `rom/`, and `results/`; logs are under `logs/`. After completion, `python3 report_results.py` prints FOM/ROM times and velocity/pressure relative errors. Each `jobs/*.sbatch` file may also be submitted separately. diff --git a/examples/steady_ns/generate_configs.py b/examples/steady_ns/generate_configs.py new file mode 100755 index 00000000..cce3225a --- /dev/null +++ b/examples/steady_ns/generate_configs.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +"""Generate the component catalog, training meshes, and paper 16x16 mesh.""" + +import argparse +import os +import sys +from pathlib import Path + + +def find_utilities(start: Path) -> Path: + configured_root = os.environ.get("SCALEUPROM_ROOT") + if configured_root: + candidate = Path(configured_root) / "utils" / "python" + if (candidate / "box_channel_config.py").is_file(): + return candidate + for parent in (start, *start.parents): + candidate = parent / "utils" / "python" + if (candidate / "box_channel_config.py").is_file(): + return candidate + raise FileNotFoundError("cannot locate scaleupROM/utils/python") + + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(find_utilities(HERE))) + +from box_channel_config import BoxChannelConfig # noqa: E402 +from config import Empty, ObjectInSpace # noqa: E402 + + +def components(): + return [ + Empty(), + ObjectInSpace("square-circle"), + ObjectInSpace("square-square"), + ObjectInSpace("square-triangle"), + ObjectInSpace("square-star"), + ] + + +def add_components(config): + for component in components(): + config.addComponent(component) + + +def write_component_catalog(path: Path): + catalog = BoxChannelConfig(1, 5) + add_components(catalog) + + # Register every oriented component/face pairing. BuildROM uses this + # compact configuration to construct all reusable component operators. + for component1 in catalog.comps: + for displacement, face1 in component1.face_map.items(): + opposite = tuple(-value for value in displacement) + for component2 in catalog.comps: + if opposite in component2.face_map: + catalog.appendRefPort( + component1.name, + component2.name, + face1, + component2.face_map[opposite], + ) + + for component_index in range(len(catalog.comps)): + catalog.addMesh(component_index, 0) + catalog.close() + catalog.save(str(path)) + + +# Component ordering extracted from the 16x16 configuration used by the paper. +# 0=empty, 1=circle, 2=square, 3=triangle, 4=star. +PAPER_16X16_COMPONENTS = [ + 1, 1, 3, 0, 2, 1, 4, 1, 2, 4, 0, 2, 4, 1, 4, 2, + 0, 4, 1, 2, 4, 0, 3, 3, 0, 1, 3, 0, 0, 1, 3, 1, + 0, 3, 4, 0, 1, 1, 1, 2, 1, 4, 0, 4, 1, 4, 4, 3, + 1, 4, 0, 0, 3, 3, 0, 3, 4, 0, 0, 4, 2, 1, 0, 2, + 0, 1, 4, 1, 0, 3, 3, 1, 3, 4, 4, 3, 4, 3, 1, 0, + 3, 3, 0, 2, 0, 2, 0, 0, 2, 1, 0, 2, 3, 3, 1, 1, + 3, 4, 2, 2, 4, 2, 0, 2, 3, 2, 0, 2, 0, 0, 3, 0, + 2, 4, 3, 1, 4, 1, 2, 3, 3, 1, 1, 4, 1, 1, 4, 3, + 3, 2, 3, 4, 4, 0, 0, 1, 2, 1, 2, 3, 1, 2, 1, 0, + 1, 1, 1, 0, 0, 2, 0, 4, 4, 4, 3, 2, 4, 3, 0, 2, + 0, 0, 1, 1, 0, 4, 0, 3, 0, 3, 3, 3, 4, 0, 2, 4, + 3, 4, 4, 3, 4, 4, 3, 1, 4, 2, 1, 0, 4, 3, 4, 0, + 1, 0, 3, 4, 2, 2, 2, 4, 4, 2, 3, 3, 1, 0, 2, 0, + 3, 1, 2, 0, 0, 4, 1, 0, 1, 0, 4, 1, 1, 1, 0, 4, + 1, 4, 0, 0, 1, 3, 3, 4, 2, 2, 3, 0, 0, 2, 1, 3, + 4, 3, 1, 4, 4, 1, 2, 0, 2, 4, 4, 1, 0, 3, 4, 3, +] + + +def write_paper_target(path: Path): + target = BoxChannelConfig(16, 16) + add_components(target) + for component_index in PAPER_16X16_COMPONENTS: + target.addMesh(component_index, 0) + target.close() + target.save(str(path)) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--output", type=Path, default=HERE / "configs") + args = parser.parse_args() + + output = args.output.resolve() + training = output / "training" + training.mkdir(parents=True, exist_ok=True) + + write_component_catalog(output / "component_catalog.h5") + + samples = BoxChannelConfig(2, 2) + add_components(samples) + samples.prefix = str(training / "box-channel.config") + count = samples.GenerateAllConfigs(0) + if count != 625: + raise RuntimeError(f"expected 625 training configurations, generated {count}") + + write_paper_target(output / "paper.16x16.h5") + print(f"Generated {count} training configurations and {output / 'paper.16x16.h5'}") + + +if __name__ == "__main__": + main() diff --git a/examples/steady_ns/jobs/00_mesh.sbatch b/examples/steady_ns/jobs/00_mesh.sbatch new file mode 100755 index 00000000..ad2d12ad --- /dev/null +++ b/examples/steady_ns/jobs/00_mesh.sbatch @@ -0,0 +1,17 @@ +#!/bin/bash +#SBATCH --job-name=ns-mesh +#SBATCH --nodes=1 +#SBATCH --ntasks=1 +#SBATCH --cpus-per-task=1 +#SBATCH --mem=2G +#SBATCH --time=00:30:00 +#SBATCH --partition=pbatch +#SBATCH --account=genddfem +#SBATCH --output=logs/%x-%j.out + +set -euo pipefail +example_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) +cd "${example_dir}" +mkdir -p logs +./prepare_meshes.sh + diff --git a/examples/steady_ns/jobs/01_samples.sbatch b/examples/steady_ns/jobs/01_samples.sbatch new file mode 100755 index 00000000..df07e6e6 --- /dev/null +++ b/examples/steady_ns/jobs/01_samples.sbatch @@ -0,0 +1,27 @@ +#!/bin/bash +#SBATCH --job-name=ns-samples +#SBATCH --array=1-5 +#SBATCH --nodes=1 +#SBATCH --ntasks=1 +#SBATCH --cpus-per-task=1 +#SBATCH --mem=2G +#SBATCH --time=24:00:00 +#SBATCH --partition=pbatch +#SBATCH --account=genddfem +#SBATCH --output=logs/%x-%A_%a.out + +# shellcheck source=jobs/common.bash +source "$(dirname -- "${BASH_SOURCE[0]}")/common.bash" + +batch_id=${SLURM_ARRAY_TASK_ID:-${1:-}} +if [[ -z ${batch_id} || ${batch_id} -lt 1 || ${batch_id} -gt 5 ]]; then + echo "Batch index must be in [1, 5]." >&2 + exit 2 +fi + +mkdir -p "snapshots/batch-${batch_id}" +# RandomSampleGenerator seeds from wall time. Offset simultaneous array tasks +# so that independent batches cannot receive the same one-second seed. +sleep $((5 * batch_id)) +"${MAIN_BIN}" -i steady_ns.yml -f \ + "main/mode=sample_generation:main/use_rom=false:sample_generation/file_path/prefix=snapshots/batch-${batch_id}/steady_ns" diff --git a/examples/steady_ns/jobs/02_basis.sbatch b/examples/steady_ns/jobs/02_basis.sbatch new file mode 100755 index 00000000..fa746673 --- /dev/null +++ b/examples/steady_ns/jobs/02_basis.sbatch @@ -0,0 +1,16 @@ +#!/bin/bash +#SBATCH --job-name=ns-basis +#SBATCH --nodes=5 +#SBATCH --ntasks=36 +#SBATCH --cpus-per-task=1 +#SBATCH --mem-per-cpu=2G +#SBATCH --time=24:00:00 +#SBATCH --partition=pbatch +#SBATCH --account=genddfem +#SBATCH --output=logs/%x-%j.out + +# shellcheck source=jobs/common.bash +source "$(dirname -- "${BASH_SOURCE[0]}")/common.bash" + +srun --ntasks=36 "${MAIN_BIN}" -i steady_ns.yml -f \ + "main/mode=train_rom:main/use_rom=true" diff --git a/examples/steady_ns/jobs/03_auxiliary.sbatch b/examples/steady_ns/jobs/03_auxiliary.sbatch new file mode 100755 index 00000000..d620b698 --- /dev/null +++ b/examples/steady_ns/jobs/03_auxiliary.sbatch @@ -0,0 +1,17 @@ +#!/bin/bash +# Manual recovery only: train_rom normally calls aux_train_rom itself. +#SBATCH --job-name=ns-supremizer +#SBATCH --nodes=1 +#SBATCH --ntasks=1 +#SBATCH --cpus-per-task=1 +#SBATCH --mem=2G +#SBATCH --time=02:00:00 +#SBATCH --partition=pbatch +#SBATCH --account=genddfem +#SBATCH --output=logs/%x-%j.out + +# shellcheck source=jobs/common.bash +source "$(dirname -- "${BASH_SOURCE[0]}")/common.bash" + +"${MAIN_BIN}" -i steady_ns.yml -f \ + "main/mode=aux_train_rom:main/use_rom=true:basis/number_of_basis=40:basis/number_of_supremizer=40" diff --git a/examples/steady_ns/jobs/04_build_rom.sbatch b/examples/steady_ns/jobs/04_build_rom.sbatch new file mode 100755 index 00000000..d63e0f1a --- /dev/null +++ b/examples/steady_ns/jobs/04_build_rom.sbatch @@ -0,0 +1,16 @@ +#!/bin/bash +#SBATCH --job-name=ns-build +#SBATCH --nodes=1 +#SBATCH --ntasks=1 +#SBATCH --cpus-per-task=1 +#SBATCH --mem=2G +#SBATCH --time=02:00:00 +#SBATCH --partition=pbatch +#SBATCH --account=genddfem +#SBATCH --output=logs/%x-%j.out + +# shellcheck source=jobs/common.bash +source "$(dirname -- "${BASH_SOURCE[0]}")/common.bash" + +"${MAIN_BIN}" -i steady_ns.yml -f \ + "main/mode=build_rom:main/use_rom=true:basis/number_of_basis=40:basis/number_of_supremizer=40:model_reduction/nonlinear_handling=tensor:model_reduction/save_operator/prefix=rom/steady_ns_nb40" diff --git a/examples/steady_ns/jobs/05_fom_16x16.sbatch b/examples/steady_ns/jobs/05_fom_16x16.sbatch new file mode 100755 index 00000000..2bf1e5ab --- /dev/null +++ b/examples/steady_ns/jobs/05_fom_16x16.sbatch @@ -0,0 +1,17 @@ +#!/bin/bash +#SBATCH --job-name=ns-fom-16 +#SBATCH --nodes=1 +#SBATCH --ntasks=1 +#SBATCH --cpus-per-task=1 +#SBATCH --mem=2G +#SBATCH --time=02:00:00 +#SBATCH --partition=pbatch +#SBATCH --account=genddfem +#SBATCH --output=logs/%x-%j.out + +# shellcheck source=jobs/common.bash +source "$(dirname -- "${BASH_SOURCE[0]}")/common.bash" + +mkdir -p results/paraview/fom +"${MAIN_BIN}" -i steady_ns.yml -o results/fom_timings.h5 -f \ + "main/mode=single_run:main/use_rom=false:mesh/component-wise/global_config=configs/paper.16x16.h5:model_reduction/compare_solution/enabled=false:save_solution/enabled=true:save_solution/file_path/prefix=results/fom_solution:visualization/enabled=true:visualization/file_path/prefix=results/paraview/fom/steady_ns" diff --git a/examples/steady_ns/jobs/06_rom_compare_16x16.sbatch b/examples/steady_ns/jobs/06_rom_compare_16x16.sbatch new file mode 100755 index 00000000..54028645 --- /dev/null +++ b/examples/steady_ns/jobs/06_rom_compare_16x16.sbatch @@ -0,0 +1,19 @@ +#!/bin/bash +#SBATCH --job-name=ns-rom-16 +#SBATCH --nodes=1 +#SBATCH --ntasks=1 +#SBATCH --cpus-per-task=1 +#SBATCH --mem=2G +#SBATCH --time=02:00:00 +#SBATCH --partition=pbatch +#SBATCH --account=genddfem +#SBATCH --output=logs/%x-%j.out + +# shellcheck source=jobs/common.bash +source "$(dirname -- "${BASH_SOURCE[0]}")/common.bash" + +mkdir -p results/paraview/rom +"${MAIN_BIN}" -i steady_ns.yml -o results/rom_vs_fom.h5 -f \ + "main/mode=single_run:main/use_rom=true:mesh/component-wise/global_config=configs/paper.16x16.h5:basis/number_of_basis=40:basis/number_of_supremizer=40:model_reduction/nonlinear_handling=tensor:model_reduction/save_operator/prefix=rom/steady_ns_nb40:model_reduction/compare_solution/enabled=true:model_reduction/compare_solution/load_solution=true:model_reduction/compare_solution/fom_solution_file=results/fom_solution.h5:save_solution/enabled=false:visualization/enabled=true:visualization/file_path/prefix=results/paraview/rom/steady_ns" + +python3 report_results.py diff --git a/examples/steady_ns/jobs/common.bash b/examples/steady_ns/jobs/common.bash new file mode 100644 index 00000000..672e4704 --- /dev/null +++ b/examples/steady_ns/jobs/common.bash @@ -0,0 +1,19 @@ +set -euo pipefail + +EXAMPLE_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) +cd "${EXAMPLE_DIR}" + +if [[ -n ${SCALEUPROM_MAIN:-} ]]; then + MAIN_BIN=${SCALEUPROM_MAIN} +elif [[ -x ../../bin/main ]]; then + MAIN_BIN=../../bin/main +elif [[ -x ../../build/bin/main ]]; then + MAIN_BIN=../../build/bin/main +else + echo "Cannot find the scaleupROM main executable; set SCALEUPROM_MAIN." >&2 + exit 1 +fi + +export OMP_NUM_THREADS=1 +mkdir -p logs results rom basis snapshots + diff --git a/examples/steady_ns/prepare_meshes.sh b/examples/steady_ns/prepare_meshes.sh new file mode 100755 index 00000000..53815ecf --- /dev/null +++ b/examples/steady_ns/prepare_meshes.sh @@ -0,0 +1,43 @@ +#!/bin/bash +set -euo pipefail + +example_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) + +repo_root=${SCALEUPROM_ROOT:-} +if [[ -z ${repo_root} ]]; then + search_dir=${example_dir} + while [[ ${search_dir} != / ]]; do + if [[ -d ${search_dir}/utils/python && -d ${search_dir}/examples/stokes/meshes ]]; then + repo_root=${search_dir} + break + fi + search_dir=$(dirname -- "${search_dir}") + done +fi + +if [[ -z ${repo_root} ]]; then + echo "Could not locate the scaleupROM source root." >&2 + exit 1 +fi + +converter=${SCALEUPROM_GMSH2MFEM:-${repo_root}/build/utils/gmsh2mfem} +if [[ ! -x ${converter} ]]; then + echo "Missing ${converter}; build scaleupROM before preparing this example." >&2 + exit 1 +fi + +cd "${example_dir}" +mkdir -p meshes configs + +for mesh in square-circle.msh.mfem square-square.msh.mfem \ + square-triangle.msh.mfem square-star.msh.mfem; do + cp "${repo_root}/examples/stokes/meshes/${mesh}" "meshes/${mesh}" +done + +# Promote the linear triangular empty-cell mesh to the exact cubic mesh used +# by the paper. gmsh2mfem appends ".mfem" to its input name. +cp "${repo_root}/test/meshes/square.tri.mesh" meshes/square.tri.mesh +"${converter}" -m meshes/square.tri.mesh -o 3 +mv meshes/square.tri.mesh.mfem meshes/square.tri-elem.mesh + +python3 generate_configs.py --output configs diff --git a/examples/steady_ns/report_results.py b/examples/steady_ns/report_results.py new file mode 100755 index 00000000..87e65efe --- /dev/null +++ b/examples/steady_ns/report_results.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +"""Print the timing and relative-error datasets from the 16x16 runs.""" + +from pathlib import Path + +import h5py +import numpy as np + + +def scalar(handle, key): + return float(np.asarray(handle[key][()]).reshape(-1)[0]) + + +results = Path(__file__).resolve().parent / "results" +with h5py.File(results / "fom_timings.h5", "r") as fom: + fom_assemble = scalar(fom, "fom_assemble") + fom_solve = scalar(fom, "fom_solve") + +with h5py.File(results / "rom_vs_fom.h5", "r") as rom: + rom_assemble = scalar(rom, "rom_assemble") + rom_solve = scalar(rom, "rom_solve") + error = np.asarray(rom["rel_error"][()]).reshape(-1) + +print(f"FOM assembly: {fom_assemble:.6g} s") +print(f"FOM solve: {fom_solve:.6g} s") +print(f"ROM assembly: {rom_assemble:.6g} s") +print(f"ROM solve: {rom_solve:.6g} s") +print(f"Velocity relative error: {error[0]:.6%}") +print(f"Pressure relative error: {error[1]:.6%}") + diff --git a/examples/steady_ns/steady_ns.yml b/examples/steady_ns/steady_ns.yml new file mode 100644 index 00000000..d389f6e4 --- /dev/null +++ b/examples/steady_ns/steady_ns.yml @@ -0,0 +1,201 @@ +main: + mode: single_run + use_rom: true + solver: steady-ns + +navier-stokes: + operator-type: base + +mesh: + type: component-wise + uniform_refinement: 1 + component-wise: + vertex_gap_threshold: 1.0e-9 + global_config: configs/component_catalog.h5 + components: + - name: empty + file: meshes/square.tri-elem.mesh + - name: square-circle + file: meshes/square-circle.msh.mfem + - name: square-square + file: meshes/square-square.msh.mfem + - name: square-triangle + file: meshes/square-triangle.msh.mfem + - name: square-star + file: meshes/square-star.msh.mfem + +domain-decomposition: + type: interior_penalty + +discretization: + order: 2 + full-discrete-galerkin: false + +solver: + direct_solve: true + print_level: 1 + max_iter: 100 + absolute_tolerance: 1.0e-10 + relative_tolerance: 1.0e-10 + +rom_solver: + print_level: 1 + max_iter: 100 + use_restart: false + absolute_tolerance: 1.0e-10 + relative_tolerance: 1.0e-10 + +visualization: + enabled: false + unified_paraview: false + visualize_error: true + file_path: + prefix: results/paraview/steady_ns + +save_solution: + enabled: false + file_path: + prefix: results/fom_solution + +parameterized_problem: + name: flow_past_array + +single_run: + choose_from_random_sample: false + flow_past_array: + nu: 0.04 + u0_x: 1.5 + u0_y: -0.8 + du_x: 0.0 + du_y: 0.0 + +sample_generation: + maximum_number_of_snapshots: 25000 + type: random + random_sample_generator: + number_of_samples: 400 + report_frequency: 10 + file_path: + prefix: snapshots/batch-1/steady_ns + parameters: + - key: mesh/component-wise/global_config + type: filename + minimum: 0 + maximum: 624 + format: configs/training/box-channel.config-%05d.h5 + - key: single_run/flow_past_array/u0_x + type: double + minimum: -1.0 + maximum: 1.0 + - key: single_run/flow_past_array/u0_y + type: double + minimum: -1.0 + maximum: 1.0 + - key: single_run/flow_past_array/du_x + type: double + minimum: -0.1 + maximum: 0.1 + - key: single_run/flow_past_array/du_y + type: double + minimum: -0.1 + maximum: 0.1 + - key: single_run/flow_past_array/offsets_x + type: double + minimum: 0.0 + maximum: 1.0 + - key: single_run/flow_past_array/offsets_y + type: double + minimum: 0.0 + maximum: 1.0 + - key: single_run/flow_past_array/k_u_x + type: double + minimum: -0.5 + maximum: 0.5 + - key: single_run/flow_past_array/k_u_y + type: double + minimum: -0.5 + maximum: 0.5 + - key: single_run/flow_past_array/k_v_x + type: double + minimum: -0.5 + maximum: 0.5 + - key: single_run/flow_past_array/k_v_y + type: double + minimum: -0.5 + maximum: 0.5 + +basis: + prefix: basis/steady_ns + number_of_basis: 40 + number_of_supremizer: 40 + tags: + - name: empty_vel + snapshot_format: + minimum: 1 + maximum: 5 + format: snapshots/batch-%d/steady_ns_sample_empty_vel_snapshot + - name: empty_pres + snapshot_format: + minimum: 1 + maximum: 5 + format: snapshots/batch-%d/steady_ns_sample_empty_pres_snapshot + - name: square-circle_vel + snapshot_format: + minimum: 1 + maximum: 5 + format: snapshots/batch-%d/steady_ns_sample_square-circle_vel_snapshot + - name: square-circle_pres + snapshot_format: + minimum: 1 + maximum: 5 + format: snapshots/batch-%d/steady_ns_sample_square-circle_pres_snapshot + - name: square-square_vel + snapshot_format: + minimum: 1 + maximum: 5 + format: snapshots/batch-%d/steady_ns_sample_square-square_vel_snapshot + - name: square-square_pres + snapshot_format: + minimum: 1 + maximum: 5 + format: snapshots/batch-%d/steady_ns_sample_square-square_pres_snapshot + - name: square-triangle_vel + snapshot_format: + minimum: 1 + maximum: 5 + format: snapshots/batch-%d/steady_ns_sample_square-triangle_vel_snapshot + - name: square-triangle_pres + snapshot_format: + minimum: 1 + maximum: 5 + format: snapshots/batch-%d/steady_ns_sample_square-triangle_pres_snapshot + - name: square-star_vel + snapshot_format: + minimum: 1 + maximum: 5 + format: snapshots/batch-%d/steady_ns_sample_square-star_vel_snapshot + - name: square-star_pres + snapshot_format: + minimum: 1 + maximum: 5 + format: snapshots/batch-%d/steady_ns_sample_square-star_pres_snapshot + svd: + save_spectrum: true + update_right_sv: false + visualization: + enabled: false + prefix: results/paraview/basis/steady_ns + +model_reduction: + separate_variable_basis: true + linear_solver_type: direct + linear_system_type: us + nonlinear_handling: tensor + subdomain_training: universal + save_operator: + level: component + prefix: rom/steady_ns_nb40 + compare_solution: + enabled: true + load_solution: true + fom_solution_file: results/fom_solution.h5 diff --git a/examples/steady_ns/submit_workflow.sh b/examples/steady_ns/submit_workflow.sh new file mode 100755 index 00000000..2c7e7158 --- /dev/null +++ b/examples/steady_ns/submit_workflow.sh @@ -0,0 +1,34 @@ +#!/bin/bash +set -euo pipefail + +example_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +cd "${example_dir}" +mkdir -p logs + +extra_sbatch_args=("$@") + +submit() { + local dependency=$1 + local script=$2 + local result + local args=(--parsable) + if [[ -n ${dependency} ]]; then + args+=("--dependency=afterok:${dependency}") + fi + result=$(sbatch "${args[@]}" "${extra_sbatch_args[@]}" "${script}") + printf '%s' "${result%%;*}" +} + +mesh_id=$(submit "" jobs/00_mesh.sbatch) +samples_id=$(submit "${mesh_id}" jobs/01_samples.sbatch) +basis_id=$(submit "${samples_id}" jobs/02_basis.sbatch) +build_id=$(submit "${basis_id}" jobs/04_build_rom.sbatch) +fom_id=$(submit "${mesh_id}" jobs/05_fom_16x16.sbatch) +rom_id=$(submit "${build_id}:${fom_id}" jobs/06_rom_compare_16x16.sbatch) + +printf 'mesh: %s\n' "${mesh_id}" +printf 'samples: %s\n' "${samples_id}" +printf 'basis: %s\n' "${basis_id}" +printf 'ROM build: %s\n' "${build_id}" +printf '16x16 FOM: %s\n' "${fom_id}" +printf '16x16 ROM: %s\n' "${rom_id}"