Skip to content
Draft
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
28 changes: 28 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copy this file to `template/.env` and adjust values for your site.
# Runtime settings
OOD_RESULTS_URL_BASE=/pun/sys/dashboard/files/fs
PFOLD_SCRIPT_FILE=/path/to/proteinfold/bin/start-alphafold2.sh
PFOLD_NATIVE_DEFAULT="-A your_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"

# Pipeline locations
PFOLD_RUN_ENVIRONMENT=prod
PFOLD_PROJECT_ROOT=/path/to/proteinfold
PFOLD_DB_PATH=/path/to/proteinfold/dbs
PFOLD_BRANCH=2.0.0
PFOLD_REPOSITORY=nf-core/proteinfold
PFOLD_NEXTFLOW_CONFIG=/path/to/proteinfold/nextflow.config

# Runtime directories
PFOLD_BASE_OUT_DIR=/path/to/output/proteinfold_output
PFOLD_BASE_DEBUGDIR=/path/to/debug
PFOLD_BASE_NXF_WORK=/path/to/work/proteinfold
PFOLD_DEBUGGROUP=your_group

# Container caches
APPTAINER_CACHEDIR=/path/to/cache/apptainer
SINGULARITY_CACHEDIR=/path/to/cache/singularity
NXF_APPTAINER_CACHEDIR=/path/to/cache/apptainer
NXF_SINGULARITY_CACHEDIR=/path/to/cache/singularity
NXF_APPTAINER_LIBRARYDIR=/path/to/library/apptainer
NXF_SINGULARITY_LIBRARYDIR=/path/to/library/singularity
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.env
template/.env
70 changes: 26 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,51 +33,27 @@ 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 runtime environment variables in `template/.env` for paths, caches, output locations, and other job-time settings.
- Adjust the portal-side defaults at the top of the ERB files for cluster, queue, and other pre-submit settings.
- 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_SCRIPT_FILE=/path/to/proteinfold/bin/start-alphafold2.sh
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/site.config
PFOLD_BASE_OUT_DIR=/scratch/${USER}/proteinfold_output
PFOLD_BASE_NXF_WORK=/scratch/${USER}/.proteinfold/work
OOD_RESULTS_URL_BASE=/pun/sys/dashboard/files/fs
```

### Python Environment for samplesheet-utils
Expand All @@ -91,7 +67,13 @@ 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.

Portal rendering and job runtime are configured differently:
- portal-side defaults live at the top of `form.yml.erb`, `submit.yml.erb`, `info.html.erb`, `completed.html.erb`, and `view.html.erb`
- runtime config lives in `template/.env`, which is intentionally gitignored

For CI/CD, prefer generating `template/.env` during deployment from site-managed config or secrets rather than committing a real site config file to the repository.

## Citation

Expand Down
9 changes: 6 additions & 3 deletions completed.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<% if !connect.user.blank? %>
<%
portal_default_base_out_dir = "/srv/scratch/#{connect.user}/proteinfold_output"
portal_default_results_url_base = "/pun/sys/dashboard/files/fs"

def file_url(base, path)
encoded_path = path.to_s.split("/").reject(&:empty?).map { |segment| ERB::Util.url_encode(segment) }.join("/")
"#{base}/#{encoded_path}"
Expand Down Expand Up @@ -69,8 +72,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 : portal_default_base_out_dir
results_url_base = (connect.respond_to?(:results_url_base) && !connect.results_url_base.blank?) ? connect.results_url_base : portal_default_results_url_base
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")
Expand All @@ -82,7 +85,7 @@ summary_log_label = File.file?(output_log_path) ? "output.log" : "live_log.log"
log_text = sanitize_live_log(tail_text(live_log_path))
%>
<div class="ood-completed-log-card">
<div><b>Log</b>: <a target="_blank" rel="noopener" href="https://kod.restech.unsw.edu.au<%= summary_log_url %>"><%= summary_log_label %></a></div>
<div><b>Log</b>: <a target="_blank" rel="noopener" href="<%= summary_log_url %>"><%= summary_log_label %></a></div>
<% if log_text && !log_text.empty? %>
<pre class="ood-completed-log" style="margin-top: 0.75rem !important; height: 7rem !important; max-height: 7rem !important; overflow: auto !important; padding: 1rem !important; background: #0f172a !important; color: #f8fafc !important; border: 1px solid #334155 !important; border-radius: 0.5rem !important; white-space: pre-wrap !important; font: 0.9rem/1.45 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, monospace !important;"><%= ERB::Util.html_escape(log_text) %></pre>
<script>
Expand Down
8 changes: 6 additions & 2 deletions form.yml.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
<%
portal_default_cluster = "katana"
%>

form:
- data_warning
- samplesheet
Expand All @@ -13,7 +17,7 @@ form:
- citation_request
- katana_citation

cluster: "katana"
cluster: "<%= portal_default_cluster %>"

attributes:
data_warning:
Expand All @@ -32,7 +36,7 @@ attributes:
class: "d-none"
label: "Input Options"
help: |
• <b>Directory:</b> <code>/srv/scratch/z3141592/my_experiment/</code>
• <b>Directory:</b> <code>/path/to/my_experiment/</code>
<br>• <b>Single file:</b> <code>protein.fasta</code>, <code>protein.yaml</code>, or <code>samplesheet.csv</code>
<br>• <b>Sequence:</b> <code>NLYIQWLKDGGPSSGRPPPS</code> or <code>NLYIQWLKDGGPSSGRPPPS:MKTVRQERLKSDHELFRTHT</code>
<br>📖 <a href="https://unsw.sharepoint.com/sites/StructuralBiologyFacility-UserDocumentation/SitePages/ProteinFold-User-Guide.aspx?ga=1#preparing-your-inputs">User Guide</a> for advanced options.
Expand Down
9 changes: 6 additions & 3 deletions info.html.erb
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<% if !connect.user.blank? %>
<%
portal_default_base_out_dir = "/srv/scratch/#{connect.user}/proteinfold_output"
portal_default_results_url_base = "/pun/sys/dashboard/files/fs"

def file_url(base, path)
encoded_path = path.to_s.split("/").reject(&:empty?).map { |segment| ERB::Util.url_encode(segment) }.join("/")
"#{base}/#{encoded_path}"
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 : portal_default_base_out_dir
results_url_base = (connect.respond_to?(:results_url_base) && !connect.results_url_base.blank?) ? connect.results_url_base : portal_default_results_url_base
%>
<b>Results</b>: <a target="_blank" rel="noopener" href="https://kod.restech.unsw.edu.au<%= file_url(results_url_base, File.join(base_out_dir, connect.run_dir)) %>"><%= connect.run_dir %></a>
<b>Results</b>: <a target="_blank" rel="noopener" href="<%= file_url(results_url_base, File.join(base_out_dir, connect.run_dir)) %>"><%= connect.run_dir %></a>
<% end %>
44 changes: 36 additions & 8 deletions submit.yml.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,34 @@
<%
portal_default_cluster = "katana"
portal_default_queue = "submission"
portal_default_script_path = "/srv/scratch/sbf-pipelines/proteinfold/bin/start-alphafold2.sh"
portal_default_native = "-A kod_proteinfold;-l select=1:ncpus=2:mem=4gb;-l walltime=48:00:00"
portal_default_gpu_native = "-l select=1:mwacgpu200=gpu-mwac:ncpus=8:ngpus=1:mem=124gb;-l walltime=12:00:00"
portal_default_email_domain = "@ad.unsw.edu.au"

cluster_name = portal_default_cluster
queue_name = portal_default_queue
script_path = portal_default_script_path
default_native = portal_default_native
gpu_native = portal_default_gpu_native

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['USER']}#{portal_default_email_domain}"
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
Expand All @@ -13,15 +40,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 %>"
22 changes: 19 additions & 3 deletions template/after.sh.erb
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
source .env
ENV_FILE=".env"
if [ -f "$ENV_FILE" ]; then
set -a
. "$ENV_FILE"
set +a
fi

require_var() {
local name="$1"
if [ -z "${!name:-}" ]; then
echo "ERROR: Required config variable '$name' is not set. Define it in template/.env or the environment." >&2
exit 1
fi
}

require_var PFOLD_BASE_OUT_DIR
require_var OOD_RESULTS_URL_BASE

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}}"
OUT_DIR="${BASE_OUT_DIR}/${RUN_DIR}"
RESULTS_URL_BASE="${RESULTS_URL_BASE:-/pun/sys/dashboard/files/fs}"
RESULTS_URL_BASE="${RESULTS_URL_BASE:-${OOD_RESULTS_URL_BASE}}"

ln -s "$OUT_DIR" 2>/dev/null || true

Expand Down
71 changes: 51 additions & 20 deletions template/script.sh.erb
Original file line number Diff line number Diff line change
@@ -1,13 +1,44 @@
#!/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

require_var() {
local name="$1"
if [ -z "${!name:-}" ]; then
echo "ERROR: Required config variable '$name' is not set. Define it in template/.env or the environment." >&2
exit 1
fi
}

require_var PFOLD_RUN_ENVIRONMENT
require_var PFOLD_PROJECT_ROOT
require_var PFOLD_DB_PATH
require_var PFOLD_BRANCH
require_var PFOLD_REPOSITORY
require_var PFOLD_DEBUGGROUP
require_var PFOLD_NEXTFLOW_CONFIG
require_var PFOLD_BASE_DEBUGDIR
require_var PFOLD_BASE_NXF_WORK
require_var PFOLD_BASE_OUT_DIR
require_var APPTAINER_CACHEDIR
require_var SINGULARITY_CACHEDIR
require_var NXF_APPTAINER_CACHEDIR
require_var NXF_SINGULARITY_CACHEDIR
require_var NXF_APPTAINER_LIBRARYDIR
require_var NXF_SINGULARITY_LIBRARYDIR

RUN_ENVIRONMENT=${RUN_ENVIRONMENT:-${PFOLD_RUN_ENVIRONMENT}}
PROJECT_ROOT=${PROJECT_ROOT:-${PFOLD_PROJECT_ROOT}}
DB_PATH=${DB_PATH:-${PFOLD_DB_PATH}}
BRANCH=${BRANCH:-${PFOLD_BRANCH}}
REPOSITORY=${REPOSITORY:-${PFOLD_REPOSITORY}}
DEBUGGROUP=${DEBUGGROUP:-${PFOLD_DEBUGGROUP}}
NEXTFLOW_CONFIG=${NEXTFLOW_CONFIG:-${PFOLD_NEXTFLOW_CONFIG}}

set -xo pipefail
set -eE
Expand All @@ -16,13 +47,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}}
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}}
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}}
RUN_DIR=$(echo "<%= context.run_name %>" | sed "s#[^A-Za-z0-9]#_#g")
OUT_DIR="${BASE_OUT_DIR}/${RUN_DIR}"
mkdir -p "${OUT_DIR}"
Expand All @@ -47,14 +78,14 @@ VERSION_SAMPLESHEET_UTILS="1.3.4"
source "${PROJECT_ROOT}/${RUN_ENVIRONMENT}/venv/bin/activate"

# Native environment cacheDir used for caching blobs during image pulls
export APPTAINER_CACHEDIR="${APPTAINER_CACHEDIR:-/srv/scratch/${USER}/.images}"
export SINGULARITY_CACHEDIR="${SINGULARITY_CACHEDIR:-/srv/scratch/${USER}/.images}"
export APPTAINER_CACHEDIR="${APPTAINER_CACHEDIR}"
export SINGULARITY_CACHEDIR="${SINGULARITY_CACHEDIR}"

# 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}"
export NXF_SINGULARITY_CACHEDIR="${NXF_SINGULARITY_CACHEDIR}"
export NXF_APPTAINER_LIBRARYDIR="${NXF_APPTAINER_LIBRARYDIR}"
export NXF_SINGULARITY_LIBRARYDIR="${NXF_SINGULARITY_LIBRARYDIR}"

export PROTEINFOLD_VERSION="2.0.0dev"

Expand Down Expand Up @@ -215,15 +246,15 @@ fi

if [ "${MODE}" == "FASTA_INPUT" ];
then
mkdir fasta
mkdir -p fasta
cp "${user_input}" ./fasta/
create-samplesheet --directory "./fasta" --suffix "${prot_mode}" ${OUTPUT_FORMAT}
SAMPLESHEET="$(pwd)/samplesheet.csv"
fi

if [ "${MODE}" == "DIRECTORY" ];
then
mkdir fasta
mkdir -p fasta
working_dir=$(pwd)
cd "${user_input}"
for filename in *
Expand Down Expand Up @@ -289,7 +320,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}" \
Expand Down
Loading