4SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
13PETSC_PREFIX="${HOME}/software"
14PETSC_ARCH="arch-linux-c-debug"
16VENV_DIR="${REPO_ROOT}/.picurv-venv"
17SHELL_RC="${HOME}/.bashrc"
21Usage: scripts/bootstrap_install.sh [options]
23Automates local PICurv setup:
241) installs base system dependencies (Debian/Ubuntu),
252) creates a managed Python virtual environment by default,
263) optionally installs PETSc with DMSwarm,
274) verifies PETSc + DMSwarm visibility,
285) builds PICurv binaries.
31 --install-petsc Build/install PETSc from source.
32 --petsc-version <ver> PETSc version tag (default: 3.20.3).
33 --petsc-prefix <dir> Parent directory for PETSc source/build.
34 --petsc-arch <arch> PETSc arch name (default: arch-linux-c-debug).
35 --python-bin <path> Python interpreter to seed the venv or use directly.
36 --venv-dir <dir> Managed venv path (default: .picurv-venv).
37 --no-venv Use the selected Python directly.
38 --with-plotting Also install matplotlib for sweep plot generation.
39 --install-shell-hook Add an idempotent source line to ~/.bashrc.
40 --shell-rc <path> Shell startup file for --install-shell-hook.
41 --skip-system-deps Skip apt package installation.
42 -h, --help Show this help.
45 scripts/bootstrap_install.sh
46 scripts/bootstrap_install.sh --install-petsc
47 scripts/bootstrap_install.sh --install-shell-hook
48 scripts/bootstrap_install.sh --no-venv
53 printf '[INFO] %s\n' "$*"
57 printf '[ERROR] %s\n' "$*" >&2
62 command -v "$1" >/dev/null 2>&1 || die "Required command '$1' is missing."
67 if [[ "${path}" = /* ]]; then
68 printf '%s\n' "${path}"
70 printf '%s/%s\n' "${REPO_ROOT}" "${path}"
74python_version_label() {
75 "$1" -c 'import sys; print(".".join(str(part) for part in sys.version_info[:3]))'
78python_is_supported_seed() {
79 "$1" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)'
82python_runtime_library_dirs() {
86 resolved_python="$(command -v "${python_bin}" || printf '%s' "${python_bin}")"
87 "${python_bin}" - <<'PY'
91for key in ("LIBDIR", "LIBPL"):
92 value = sysconfig.get_config_var(key)
93 if value and os.path.isdir(value):
94 print(os.path.realpath(value))
96 if command -v ldd >/dev/null 2>&1 && [[ -x "${resolved_python}" ]]; then
97 ldd "${resolved_python}" 2>/dev/null | awk '
99 /^[[:space:]]*\// { path = $1 }
101 sub(/\/[^\/]+$/, "", path)
109write_python_env_file() {
110 local python_bin="$1"
111 local env_file="${REPO_ROOT}/.picurv-python-env"
115 python_runtime_library_dirs "${python_bin}" \
116 | awk '$0 !~ "^/(lib|lib64|usr/lib|usr/lib64)(/|$)"' \
117 | awk 'NF && !seen[$0]++' \
121 printf '# Generated by scripts/bootstrap_install.sh. Do not commit.\n'
122 printf 'PICURV_PYTHON_LD_LIBRARY_PATH=%q\n' "${runtime_dirs}"
126install_shell_hook() {
128 local hook_path="${REPO_ROOT}/etc/picurv.sh"
129 local begin_marker="# >>> PICurv shell setup >>>"
130 local end_marker="# <<< PICurv shell setup <<<"
133 mkdir -p "$(dirname "${rc_path}")"
135 tmp_path="$(mktemp "${rc_path}.picurv.XXXXXX")"
136 awk -v begin="${begin_marker}" -v end="${end_marker}" '
137 $0 == begin {skip = 1; next}
138 $0 == end {skip = 0; next}
140 ' "${rc_path}" > "${tmp_path}"
142 printf '%s\n' "${begin_marker}"
143 printf 'source %q\n' "${hook_path}"
144 printf '%s\n' "${end_marker}"
146 mv "${tmp_path}" "${rc_path}"
149while [[ $# -gt 0 ]]; do
151 --install-petsc) INSTALL_PETSC=1; shift ;;
152 --skip-system-deps) SKIP_SYSTEM_DEPS=1; shift ;;
153 --petsc-version) PETSC_VERSION="${2:?missing value for --petsc-version}"; shift 2 ;;
154 --petsc-prefix) PETSC_PREFIX="${2:?missing value for --petsc-prefix}"; shift 2 ;;
155 --petsc-arch) PETSC_ARCH="${2:?missing value for --petsc-arch}"; shift 2 ;;
156 --python-bin) PYTHON_BIN="${2:?missing value for --python-bin}"; shift 2 ;;
157 --venv-dir) VENV_DIR="$(absolute_path "${2:?missing value for --venv-dir}")"; shift 2 ;;
158 --no-venv) USE_VENV=0; shift ;;
159 --with-plotting) WITH_PLOTTING=1; shift ;;
160 --install-shell-hook) INSTALL_SHELL_HOOK=1; shift ;;
161 --shell-rc) SHELL_RC="$(absolute_path "${2:?missing value for --shell-rc}")"; shift 2 ;;
162 -h|--help) usage; exit 0 ;;
163 *) die "Unknown option: $1" ;;
167if [[ -z "${PYTHON_BIN}" ]]; then
168 if command -v python3.12 >/dev/null 2>&1; then
169 PYTHON_BIN="python3.12"
170 elif command -v python3.11 >/dev/null 2>&1; then
171 PYTHON_BIN="python3.11"
172 elif command -v python3.10 >/dev/null 2>&1; then
173 PYTHON_BIN="python3.10"
179require_cmd "${PYTHON_BIN}"
182if [[ "${SKIP_SYSTEM_DEPS}" -eq 0 ]]; then
184 log "Installing base system dependencies (Debian/Ubuntu)..."
186 sudo apt-get install -y \
187 build-essential gfortran mpich git make pkg-config \
188 libx11-dev python3 python3-pip python3-venv
191PYTHON_VERSION="$(python_version_label "${PYTHON_BIN}")"
192log "Selected Python seed: ${PYTHON_BIN} (${PYTHON_VERSION})"
194if [[ "${USE_VENV}" -eq 1 ]]; then
195 if ! python_is_supported_seed "${PYTHON_BIN}"; then
196 die "Managed venv installs require Python 3.10+; selected ${PYTHON_BIN} is ${PYTHON_VERSION}. Load a newer Python module, pass --python-bin, or use --no-venv."
198 log "Creating/updating managed Python environment at ${VENV_DIR}..."
199 "${PYTHON_BIN}" -m venv "${VENV_DIR}"
200 CLI_PYTHON="${VENV_DIR}/bin/python"
201 env -u PYTHONPATH PYTHONNOUSERSITE=1 "${CLI_PYTHON}" -m pip install --upgrade pip
202 PYTHON_PACKAGES=(pyyaml numpy)
203 if [[ "${WITH_PLOTTING}" -eq 1 ]]; then
204 PYTHON_PACKAGES+=(matplotlib)
206 log "Installing Python dependencies into managed venv: ${PYTHON_PACKAGES[*]}"
207 env -u PYTHONPATH PYTHONNOUSERSITE=1 "${CLI_PYTHON}" -m pip install "${PYTHON_PACKAGES[@]}"
209 CLI_PYTHON="${PYTHON_BIN}"
210 log "Installing Python dependencies with site-managed Python: ${CLI_PYTHON}"
211 "${CLI_PYTHON}" -m pip install --upgrade pip
212 PYTHON_PACKAGES=(pyyaml numpy)
213 if [[ "${WITH_PLOTTING}" -eq 1 ]]; then
214 PYTHON_PACKAGES+=(matplotlib)
216 "${CLI_PYTHON}" -m pip install "${PYTHON_PACKAGES[@]}"
219printf '%s\n' "$(command -v "${CLI_PYTHON}" || printf '%s' "${CLI_PYTHON}")" > "${REPO_ROOT}/.picurv-python"
220write_python_env_file "${CLI_PYTHON}"
222if [[ "${INSTALL_PETSC}" -eq 1 ]]; then
224 PETSC_SRC="${PETSC_PREFIX}/petsc-${PETSC_VERSION}"
225 mkdir -p "${PETSC_PREFIX}"
227 if [[ ! -d "${PETSC_SRC}" ]]; then
228 log "Cloning PETSc v${PETSC_VERSION} into ${PETSC_SRC}..."
229 git clone -b "v${PETSC_VERSION}" https://gitlab.com/petsc/petsc.git "${PETSC_SRC}"
231 log "Using existing PETSc source at ${PETSC_SRC}."
234 log "Configuring PETSc with DMSwarm support..."
235 pushd "${PETSC_SRC}" >/dev/null
236 ./configure --PETSC_ARCH="${PETSC_ARCH}" \
237 --with-cc=mpicc --with-cxx=mpicxx --with-fc=mpif90 \
238 --download-fblaslapack --download-metis --download-parmetis \
239 --with-dmswarm=1 --with-debugging=1
244 export PETSC_DIR="${PETSC_SRC}"
245 export PETSC_ARCH="${PETSC_ARCH}"
248if [[ -z "${PETSC_DIR:-}" ]]; then
249 die "PETSC_DIR must be set (or use --install-petsc)."
252PETSC_DMSWARM_HEADER="${PETSC_DIR}/include/petscdmswarm.h"
253PETSC_CONF_CANDIDATES=("${PETSC_DIR}/include/petscconf.h")
254if [[ -n "${PETSC_ARCH:-}" ]]; then
255 PETSC_CONF_CANDIDATES=("${PETSC_DIR}/${PETSC_ARCH}/include/petscconf.h" "${PETSC_CONF_CANDIDATES[@]}")
258for candidate in "${PETSC_CONF_CANDIDATES[@]}"; do
259 if [[ -f "${candidate}" ]]; then
260 PETSC_CONF="${candidate}"
264[[ -n "${PETSC_CONF}" ]] || die "PETSc config not found. Checked: ${PETSC_CONF_CANDIDATES[*]}"
265[[ -f "${PETSC_DMSWARM_HEADER}" ]] || die "DMSwarm header not found: ${PETSC_DMSWARM_HEADER}"
267log "Verified PETSc config (${PETSC_CONF}) and DMSwarm header."
269log "Building PICurv binaries..."
271"${CLI_PYTHON}" ./scripts/picurv build
273[[ -x "${REPO_ROOT}/bin/simulator" ]] || die "Missing binary: bin/simulator"
274[[ -x "${REPO_ROOT}/bin/postprocessor" ]] || die "Missing binary: bin/postprocessor"
275[[ -x "${REPO_ROOT}/bin/picurv" ]] || die "Missing binary: bin/picurv"
277log "Bootstrap complete."
278log "PICurv Python: ${CLI_PYTHON}"
279if [[ "${INSTALL_SHELL_HOOK}" -eq 1 ]]; then
280 install_shell_hook "${SHELL_RC}"
281 log "Installed PICurv shell hook in ${SHELL_RC}."
282 log "Reload with: source ${SHELL_RC}"
284 log "To add picurv to your PATH, run:"
285 log " echo 'source ${REPO_ROOT}/etc/picurv.sh' >> ~/.bashrc && source ~/.bashrc"
286 log "Or rerun bootstrap with: --install-shell-hook"
288log "Then verify with: picurv --help"