From 43fca84e7458c6d359339301ad78cad8e59b80c4 Mon Sep 17 00:00:00 2001 From: jscgh Date: Thu, 26 Mar 2026 14:39:49 +1100 Subject: [PATCH 01/14] Add portable config env overrides --- .env.example | 35 +++++++++++++++++++++++++++++++++++ form.yml.erb | 2 +- submit.yml.erb | 37 +++++++++++++++++++++++++++++-------- template/after.sh.erb | 11 ++++++++--- template/script.sh.erb | 38 ++++++++++++++++++++++---------------- 5 files changed, 95 insertions(+), 28 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4b8a4df --- /dev/null +++ b/.env.example @@ -0,0 +1,35 @@ +# Copy this file to `template/.env` and adjust values for your site. +# Existing unprefixed variables are still supported; these prefixed names are the +# portable interface for this app. + +# Open OnDemand / scheduler settings +PFOLD_CLUSTER=katana +PFOLD_QUEUE=submission +PFOLD_SCRIPT_FILE=/srv/scratch/sbf-pipelines/proteinfold/bin/start-alphafold2.sh +PFOLD_EMAIL_DOMAIN=@ad.unsw.edu.au +# PFOLD_EMAIL=user@example.edu +PFOLD_NATIVE_DEFAULT=-A kod_proteinfold;-l select=1:ncpus=2:mem=4gb;-l walltime=48:00:00 +PFOLD_NATIVE_GPU=-l select=1:mwacgpu200=gpu-mwac:ncpus=8:ngpus=1:mem=124gb;-l walltime=12:00:00 + +# Pipeline locations +PFOLD_RUN_ENVIRONMENT=prod +PFOLD_PROJECT_ROOT=/srv/scratch/sbf-pipelines/proteinfold +PFOLD_DB_PATH=/srv/scratch/sbf-pipelines/proteinfold/dbs +PFOLD_BRANCH=master +PFOLD_REPOSITORY=Australian-Structural-Biology-Computing/proteinfold +# PFOLD_NEXTFLOW_CONFIG=/srv/scratch/sbf-pipelines/proteinfold/kod_proteinfold-prod.config + +# Runtime directories +PFOLD_BASE_OUT_DIR=/srv/scratch/${USER}/proteinfold_output +PFOLD_BASE_DEBUGDIR=/srv/scratch/sbf/debug +PFOLD_BASE_NXF_WORK=/srv/scratch/${USER}/.proteinfold/work +PFOLD_DEBUGGROUP=sbf +PFOLD_RESULTS_URL_BASE=/pun/sys/dashboard/files/fs + +# Container caches +# APPTAINER_CACHEDIR=/srv/scratch/${USER}/.images +# SINGULARITY_CACHEDIR=/srv/scratch/${USER}/.images +# PFOLD_NXF_APPTAINER_CACHEDIR=/srv/scratch/${USER}/.images +# PFOLD_NXF_SINGULARITY_CACHEDIR=/srv/scratch/${USER}/.images +# PFOLD_NXF_APPTAINER_LIBRARYDIR=/srv/scratch/sbf-pipelines/proteinfold/singularity +# PFOLD_NXF_SINGULARITY_LIBRARYDIR=/srv/scratch/sbf-pipelines/proteinfold/singularity diff --git a/form.yml.erb b/form.yml.erb index beaf2db..ba10ea7 100644 --- a/form.yml.erb +++ b/form.yml.erb @@ -13,7 +13,7 @@ form: - citation_request - katana_citation -cluster: "katana" +cluster: "<%= ENV.fetch('PFOLD_CLUSTER', 'katana') %>" attributes: data_warning: diff --git a/submit.yml.erb b/submit.yml.erb index 6f1d23d..07e9636 100644 --- a/submit.yml.erb +++ b/submit.yml.erb @@ -1,7 +1,27 @@ +<% +cluster_name = ENV.fetch("PFOLD_CLUSTER", "katana") +queue_name = ENV.fetch("PFOLD_QUEUE", "submission") +script_path = ENV.fetch("PFOLD_SCRIPT_FILE", "/srv/scratch/sbf-pipelines/proteinfold/bin/start-alphafold2.sh") +default_native = ENV.fetch("PFOLD_NATIVE_DEFAULT", "-A kod_proteinfold;-l select=1:ncpus=2:mem=4gb;-l walltime=48:00:00") +gpu_native = ENV.fetch("PFOLD_NATIVE_GPU", "-l select=1:mwacgpu200=gpu-mwac:ncpus=8:ngpus=1:mem=124gb;-l walltime=12:00:00") + +def parse_native(val) + val.split(/\s*;\s*/).reject(&:empty?) +end + +native_default_list = parse_native(default_native) +native_gpu_list = parse_native(gpu_native) + +email_default = ENV["PFOLD_EMAIL"] || "#{ENV['USER']}#{ENV.fetch('PFOLD_EMAIL_DOMAIN', '@ad.unsw.edu.au')}" +email_selected = (defined?(email) && email && !email.strip.empty?) ? email : email_default +%> + +cluster: "<%= cluster_name %>" + batch_connect: template: "basic" - queue_name: "submission" - script_file: "/srv/scratch/sbf-pipelines/proteinfold/bin/start-alphafold2.sh" + queue_name: "<%= queue_name %>" + script_file: "<%= script_path %>" conn_params: - base_out_dir - results_url_base @@ -13,15 +33,16 @@ script: native: # ColabFold local DBs are only available locally on certain nodes. This is an example method for catching local ColabFold runs <% if (af_method == "colabfold" || af_method == "boltz") && msa_server == "local" %> - - "-l select=1:mwacgpu200=gpu-mwac:ncpus=8:ngpus=1:mem=124gb" - - "-l walltime=12:00:00" + <% native_gpu_list.each do |entry| %> + - "<%= entry %>" + <% end %> - "-N <%= (run_name || 'kod_proteinfold').gsub(' ', '_') %>" <% else %> - - "-A kod_proteinfold" - - "-l select=1:ncpus=2:mem=4gb" - - "-l walltime=48:00:00" + <% native_default_list.each do |entry| %> + - "<%= entry %>" + <% end %> - "-N <%= (run_name || 'kod_proteinfold').gsub(' ', '_') %>" <% end %> email: - - "<%= ENV['USER'] %>@ad.unsw.edu.au" + - "<%= email_selected %>" email_on_terminated: "<%= email_on_terminated %>" diff --git a/template/after.sh.erb b/template/after.sh.erb index bca756a..6e4b974 100644 --- a/template/after.sh.erb +++ b/template/after.sh.erb @@ -1,9 +1,14 @@ -source .env +ENV_FILE=".env" +if [ -f "$ENV_FILE" ]; then + set -a + . "$ENV_FILE" + set +a +fi RUN_DIR=$(echo "<%= context.run_name %>" | sed "s#[^A-Za-z0-9]#_#g") -BASE_OUT_DIR="${BASE_OUT_DIR:-/srv/scratch/${USER}/proteinfold_output}" +BASE_OUT_DIR="${BASE_OUT_DIR:-${PFOLD_BASE_OUT_DIR:-/srv/scratch/${USER}/proteinfold_output}}" OUT_DIR="${BASE_OUT_DIR}/${RUN_DIR}" -RESULTS_URL_BASE="${RESULTS_URL_BASE:-/pun/sys/dashboard/files/fs}" +RESULTS_URL_BASE="${RESULTS_URL_BASE:-${PFOLD_RESULTS_URL_BASE:-/pun/sys/dashboard/files/fs}}" ln -s "$OUT_DIR" 2>/dev/null || true diff --git a/template/script.sh.erb b/template/script.sh.erb index 93a6504..ddf3ecb 100755 --- a/template/script.sh.erb +++ b/template/script.sh.erb @@ -1,13 +1,19 @@ #!/bin/bash -source .env -# Set defaults to prod if .env is not found -RUN_ENVIRONMENT=${RUN_ENVIRONMENT:-prod} -PROJECT_ROOT=${PROJECT_ROOT:-/srv/scratch/sbf-pipelines/proteinfold} -DB_PATH=${DB_PATH:-/srv/scratch/sbf-pipelines/proteinfold/dbs} -BRANCH=${BRANCH:-master} -REPOSITORY=${REPOSITORY:-Australian-Structural-Biology-Computing/proteinfold} -DEBUGGROUP=${DEBUGGROUP:-sbf} +ENV_FILE=".env" +if [ -f "$ENV_FILE" ]; then + set -a + . "$ENV_FILE" + set +a +fi + +RUN_ENVIRONMENT=${RUN_ENVIRONMENT:-${PFOLD_RUN_ENVIRONMENT:-prod}} +PROJECT_ROOT=${PROJECT_ROOT:-${PFOLD_PROJECT_ROOT:-/srv/scratch/sbf-pipelines/proteinfold}} +DB_PATH=${DB_PATH:-${PFOLD_DB_PATH:-/srv/scratch/sbf-pipelines/proteinfold/dbs}} +BRANCH=${BRANCH:-${PFOLD_BRANCH:-master}} +REPOSITORY=${REPOSITORY:-${PFOLD_REPOSITORY:-Australian-Structural-Biology-Computing/proteinfold}} +DEBUGGROUP=${DEBUGGROUP:-${PFOLD_DEBUGGROUP:-sbf}} +NEXTFLOW_CONFIG=${NEXTFLOW_CONFIG:-${PFOLD_NEXTFLOW_CONFIG:-${PROJECT_ROOT}/kod_proteinfold-${RUN_ENVIRONMENT}.config}} set -xo pipefail set -eE @@ -16,13 +22,13 @@ set -eE NOW=$(date +%Y%m%d_%H%M%S) RUNNAME="${NOW}_${USER}" -BASE_DEBUGDIR=${BASE_DEBUGDIR:-"/srv/scratch/sbf/debug"} +BASE_DEBUGDIR=${BASE_DEBUGDIR:-${PFOLD_BASE_DEBUGDIR:-"/srv/scratch/sbf/debug"}} DEBUGDIR="${BASE_DEBUGDIR}/${RUNNAME}" -BASE_NXF_WORK=${BASE_NXF_WORK:-"/srv/scratch/${USER}/.proteinfold/work"} +BASE_NXF_WORK=${BASE_NXF_WORK:-${PFOLD_BASE_NXF_WORK:-"/srv/scratch/${USER}/.proteinfold/work"}} export NXF_WORK="${BASE_NXF_WORK}/${RUNNAME}" -BASE_OUT_DIR=${BASE_OUT_DIR:-"/srv/scratch/${USER}/proteinfold_output"} +BASE_OUT_DIR=${BASE_OUT_DIR:-${PFOLD_BASE_OUT_DIR:-"/srv/scratch/${USER}/proteinfold_output"}} RUN_DIR=$(echo "<%= context.run_name %>" | sed "s#[^A-Za-z0-9]#_#g") OUT_DIR="${BASE_OUT_DIR}/${RUN_DIR}" mkdir -p "${OUT_DIR}" @@ -51,10 +57,10 @@ export APPTAINER_CACHEDIR="${APPTAINER_CACHEDIR:-/srv/scratch/${USER}/.images}" export SINGULARITY_CACHEDIR="${SINGULARITY_CACHEDIR:-/srv/scratch/${USER}/.images}" # Nextflow variables, checks libraryDir and if image is not found downloads to cache -export NXF_APPTAINER_CACHEDIR="${NXF_APPTAINER_CACHEDIR:-/srv/scratch/${USER}/.images}" -export NXF_SINGULARITY_CACHEDIR="${NXF_SINGULARITY_CACHEDIR:-/srv/scratch/${USER}/.images}" -export NXF_APPTAINER_LIBRARYDIR="${NXF_APPTAINER_LIBRARYDIR:-/srv/scratch/sbf-pipelines/proteinfold/singularity}" -export NXF_SINGULARITY_LIBRARYDIR="${NXF_SINGULARITY_LIBRARYDIR:-/srv/scratch/sbf-pipelines/proteinfold/singularity}" +export NXF_APPTAINER_CACHEDIR="${NXF_APPTAINER_CACHEDIR:-${PFOLD_NXF_APPTAINER_CACHEDIR:-/srv/scratch/${USER}/.images}}" +export NXF_SINGULARITY_CACHEDIR="${NXF_SINGULARITY_CACHEDIR:-${PFOLD_NXF_SINGULARITY_CACHEDIR:-/srv/scratch/${USER}/.images}}" +export NXF_APPTAINER_LIBRARYDIR="${NXF_APPTAINER_LIBRARYDIR:-${PFOLD_NXF_APPTAINER_LIBRARYDIR:-/srv/scratch/sbf-pipelines/proteinfold/singularity}}" +export NXF_SINGULARITY_LIBRARYDIR="${NXF_SINGULARITY_LIBRARYDIR:-${PFOLD_NXF_SINGULARITY_LIBRARYDIR:-/srv/scratch/sbf-pipelines/proteinfold/singularity}}" export PROTEINFOLD_VERSION="2.0.0dev" @@ -289,7 +295,7 @@ fi [[ "<%= context.af_method %>" == "rosettafold_all_atom" ]] && PROT_MODE="rosettafold_all_atom" && ARGS="${ARGS} --rosettafold_all_atom_db ${DB_PATH}" [[ "<%= context.af_method %>" == "helixfold3" ]] && PROT_MODE="helixfold3" && ARGS="${ARGS} --helixfold3_db ${DB_PATH}" -nextflow -c "${PROJECT_ROOT}/kod_proteinfold-${RUN_ENVIRONMENT}.config" run ${REPOSITORY} -r ${BRANCH} -latest \ +nextflow -c "${NEXTFLOW_CONFIG}" run ${REPOSITORY} -r ${BRANCH} -latest \ --input "${SAMPLESHEET}" \ --outdir "${OUT_DIR}" \ --mode "${PROT_MODE}" \ From 2a433f3c187ca71feab01ce57e393e6c0dee96a3 Mon Sep 17 00:00:00 2001 From: jscgh Date: Thu, 26 Mar 2026 14:43:30 +1100 Subject: [PATCH 02/14] Remove site-specific result URL assumptions --- README.md | 66 ++++++++++++++++------------------------------ completed.html.erb | 6 ++--- info.html.erb | 6 ++--- view.html.erb | 6 ++--- 4 files changed, 31 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 017eb02..6ec5223 100644 --- a/README.md +++ b/README.md @@ -33,51 +33,29 @@ To deploy ProteinFold on your own Open OnDemand instance: git clone https://github.com/Australian-Structural-Biology-Computing/ood-proteinfold.git /var/www/ood/apps/sys/kod-proteinfold ``` -2. **Edit files to match institutional settings**: - - Update `submit.yml.erb` with your facility-specific settings. - - Change the cluster in `form.yml.erb` to match your HPC. - - Create `kod_proteinfold-${RUN_ENVIRONMENT}.config` files for proteinfold-specific nextflow configurations. Or remove this line from `script.sh.erb` if not needed. - - Create a `template/.env` file to change any of these default parameters: +2. **Configure for your site**: + - Copy `.env.example` to `template/.env`. + - Adjust the environment variables in `template/.env` for your cluster, queue, paths, email defaults, and output locations. + - If needed, set `PFOLD_NEXTFLOW_CONFIG` to your institutional Nextflow config file instead of editing `script.sh.erb`. ``` -# Example .env for ood-proteinfold - -# Base output directory for all runs (job-specific OUT_DIR set at runtime) -BASE_OUT_DIR=/srv/scratch/${USER}/proteinfold_output - -# Environment name (e.g., prod, dev) -RUN_ENVIRONMENT=prod - -# Project root: location of Nextflow configs and samplesheet-utils environment -PROJECT_ROOT=/srv/scratch/sbf-pipelines/proteinfold - -# Database path for structure prediction modules -DB_PATH=/srv/scratch/sbf-pipelines/proteinfold/dbs - -# Git branch to use for proteinfold -BRANCH=master - -# Repository path for using alternative versions of proteinfold -REPOSITORY=Australian-Structural-Biology-Computing/proteinfold - -# Debug group for permissions on debug files -DEBUGGROUP=sbf-pipelines - -# Base debug directory (job-specific DEBUGDIR set at runtime) -BASE_DEBUGDIR=/srv/scratch/sbf/debug - -# Nextflow work directory base (job-specific NXF_WORK set at runtime) -BASE_NXF_WORK=/srv/scratch/${USER}/.proteinfold/work - -# Apptainer/Singularity blob cache directories (set here or via your institutional Nextflow config, e.g. https://github.com/Australian-Structural-Biology-Computing/unsw_katana) -# APPTAINER_CACHEDIR=/srv/scratch/${USER}/.images -# SINGULARITY_CACHEDIR=/srv/scratch/${USER}/.images - -# Nextflow Apptainer/Singularity image cache/library directories (set here or via institutional Nextflow config, e.g. https://github.com/nf-core/configs/blob/master/conf/pipeline/proteinfold/unsw_katana.config) -# NXF_APPTAINER_CACHEDIR=/srv/scratch/${USER}/.images -# NXF_SINGULARITY_CACHEDIR=/srv/scratch/${USER}/.images -# NXF_APPTAINER_LIBRARYDIR=/srv/scratch/sbf-pipelines/proteinfold/singularity -# NXF_SINGULARITY_LIBRARYDIR=/srv/scratch/sbf-pipelines/proteinfold/singularity +# Example template/.env for ood-proteinfold + +PFOLD_CLUSTER=katana +PFOLD_QUEUE=submission +PFOLD_SCRIPT_FILE=/srv/scratch/sbf-pipelines/proteinfold/bin/start-alphafold2.sh +PFOLD_EMAIL_DOMAIN=@example.edu +PFOLD_NATIVE_DEFAULT=-A my_project;-l select=1:ncpus=2:mem=4gb;-l walltime=48:00:00 +PFOLD_NATIVE_GPU=-l select=1:ncpus=8:ngpus=1:mem=124gb;-l walltime=12:00:00 +PFOLD_RUN_ENVIRONMENT=prod +PFOLD_PROJECT_ROOT=/apps/proteinfold +PFOLD_DB_PATH=/data/proteinfold/dbs +PFOLD_BRANCH=master +PFOLD_REPOSITORY=Australian-Structural-Biology-Computing/proteinfold +PFOLD_NEXTFLOW_CONFIG=/apps/proteinfold/kod_proteinfold-prod.config +PFOLD_BASE_OUT_DIR=/scratch/${USER}/proteinfold_output +PFOLD_BASE_NXF_WORK=/scratch/${USER}/.proteinfold/work +PFOLD_RESULTS_URL_BASE=/pun/sys/dashboard/files/fs ``` ### Python Environment for samplesheet-utils @@ -91,7 +69,7 @@ source ${PROJECT_ROOT}/${RUN_ENVIRONMENT}/venv/bin/activate pip install samplesheet-utils==1.1.2 ``` -Update the paths in `.env` if your environment is elsewhere. +Prefer changing `template/.env` over editing the app templates directly so upgrades stay easy to rebase across institutions. ## Citation diff --git a/completed.html.erb b/completed.html.erb index 130adc1..813b3ee 100644 --- a/completed.html.erb +++ b/completed.html.erb @@ -69,8 +69,8 @@ def sanitize_live_log(text) compact.join("\n").strip end -base_out_dir = (connect.respond_to?(:base_out_dir) && !connect.base_out_dir.blank?) ? connect.base_out_dir : "/srv/scratch/#{connect.user}/proteinfold_output" -results_url_base = (connect.respond_to?(:results_url_base) && !connect.results_url_base.blank?) ? connect.results_url_base : "/pun/sys/dashboard/files/fs" +base_out_dir = (connect.respond_to?(:base_out_dir) && !connect.base_out_dir.blank?) ? connect.base_out_dir : (ENV["PFOLD_BASE_OUT_DIR"] || "/srv/scratch/#{connect.user}/proteinfold_output") +results_url_base = (connect.respond_to?(:results_url_base) && !connect.results_url_base.blank?) ? connect.results_url_base : (ENV["PFOLD_RESULTS_URL_BASE"] || "/pun/sys/dashboard/files/fs") session_output_dir = (connect.respond_to?(:session_output_dir) && !connect.session_output_dir.blank?) ? connect.session_output_dir : nil log_dir = session_output_dir || File.join(base_out_dir, connect.run_dir) live_log_path = File.join(log_dir, "live_log.log") @@ -82,7 +82,7 @@ summary_log_label = File.file?(output_log_path) ? "output.log" : "live_log.log" log_text = sanitize_live_log(tail_text(live_log_path)) %>
-
Log: <%= summary_log_label %>
+
Log: <%= summary_log_label %>
<% if log_text && !log_text.empty? %>
<%= ERB::Util.html_escape(log_text) %>