Bootstrap: docker From: debian:trixie %labels Author ATGC %post export DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \ build-essential wget git autoconf automake libtool openmpi-bin libopenmpi-dev \ bc dos2unix r-base-core ca-certificates unzip cd /opt wget https://github.com/stephaneguindon/phyml/archive/refs/tags/v3.3.20250515.tar.gz tar xvf v3.3.20250515.tar.gz cd phyml-3.3.20250515 sh ./autogen.sh && ./configure --enable-phyml-mpi && make clean && make V=1 cp src/phyml-mpi /usr/local/bin/ cd /opt git clone --depth 1 https://gite.lirmm.fr/atgc/sms.git cd sms ZIP_FILE="$(find tarball -maxdepth 1 -name 'sms-*.zip' -print -quit)" if [[ -z "${ZIP_FILE}" ]]; then echo "Unable to locate SMS tarball in sms/tarball" >&2 exit 1 fi unzip -q "${ZIP_FILE}" ZIP_DIR="$(basename "${ZIP_FILE}" .zip)" rm -rf sources/phyml-src mv "${ZIP_DIR}/phyml-src" sources/ rm -rf "${ZIP_DIR}" cd sources make sed -i 's|^PHYMLBIN=.*|PHYMLBIN="/usr/local/bin/phyml-mpi"|' sms.cfg chmod +x *.sh cat <<'EOF' >/usr/local/bin/phyml-wrapper #!/bin/bash set -euo pipefail SMS_ROOT="/opt/sms/sources" SMS_GAMMA_CATEGORIES=4 SMS_FREE_RATE_CATEGORIES=4 PHYML_BIN="phyml-mpi" SMS_MODE=0 SMS_CRITERION="" declare -a PHYML_ARGS=() while [[ $# -gt 0 ]]; do case "$1" in --sms) SMS_MODE=1 shift if [[ $# -gt 0 ]]; then SMS_CRITERION="$(echo "$1" | tr '[:lower:]' '[:upper:]')" shift fi ;; *) PHYML_ARGS+=("$1") shift ;; esac done if [[ ${SMS_MODE} -eq 0 ]]; then exec "${PHYML_BIN}" "${PHYML_ARGS[@]}" fi if [[ -z "${SMS_CRITERION}" ]]; then SMS_CRITERION="BIC" fi INPUT_FILE="" DATA_TYPE="" for (( idx=0; idx<${#PHYML_ARGS[@]}; idx++ )); do arg="${PHYML_ARGS[$idx]}" case "${arg}" in -i) if (( idx + 1 < ${#PHYML_ARGS[@]} )); then INPUT_FILE="${PHYML_ARGS[$((idx + 1))]}" fi ;; -d) if (( idx + 1 < ${#PHYML_ARGS[@]} )); then DATA_TYPE="${PHYML_ARGS[$((idx + 1))]}" fi ;; esac done if [[ -z "${INPUT_FILE}" || -z "${DATA_TYPE}" ]]; then echo "SMS wrapper error: missing alignment (-i) or data type (-d)." >&2 exit 1 fi SMS_DIR="sms_workspace" SMS_CSV="${SMS_DIR}/sms_results.csv" rm -rf "${SMS_DIR}" mkdir -p "${SMS_DIR}" echo "[phyml-wrapper] Running SMS (criterion=${SMS_CRITERION})" >&2 if ! "${SMS_ROOT}/sms.sh" -i "${INPUT_FILE}" -d "${DATA_TYPE}" -c "${SMS_CRITERION}" -o "${SMS_DIR}" -p "${SMS_CSV}"; then echo "SMS execution failed." >&2 exit 1 fi if [[ ! -f "${SMS_CSV}" ]]; then echo "SMS results file not found at ${SMS_CSV}" >&2 exit 1 fi cp "${SMS_CSV}" "sms_results.csv" if [[ -f "${SMS_DIR}/sms.log" ]]; then cp "${SMS_DIR}/sms.log" "sms.log" fi BEST_LINE="$(tail -n +2 "${SMS_CSV}" | head -n 1)" if [[ -z "${BEST_LINE}" ]]; then echo "SMS results are empty." >&2 exit 1 fi BEST_MODEL="$(echo "${BEST_LINE}" | cut -d ';' -f 1 | tr -d '[:space:]\r')" BEST_DECORATION_RAW="$(echo "${BEST_LINE}" | cut -d ';' -f 2 | tr -d '\r')" BEST_DECORATION="$(echo "${BEST_DECORATION_RAW}" | tr -d ' \"')" if [[ -z "${BEST_MODEL}" ]]; then echo "Unable to parse best model from SMS results." >&2 exit 1 fi echo "[phyml-wrapper] SMS selected model: ${BEST_MODEL} ${BEST_DECORATION}" >&2 declare -a SMS_MODEL_ARGS=() case "${BEST_MODEL}" in HKY85|JC69|K80|K2P|F81|F84|TN93|GTR) SMS_MODEL_ARGS+=("-m" "${BEST_MODEL}") ;; SYM) SMS_MODEL_ARGS+=("-m" "012345") ;; *) MATRIX_PATH="${SMS_ROOT}/matrix/${BEST_MODEL}.mt" if [[ -f "${MATRIX_PATH}" ]]; then SMS_MODEL_ARGS+=("-m" "custom" "--aa_rate_file" "${MATRIX_PATH}") else SMS_MODEL_ARGS+=("-m" "${BEST_MODEL}") fi ;; esac declare -a SMS_FREQ_ARGS=() if [[ "${DATA_TYPE}" == "nt" ]]; then SMS_FREQ_ARGS+=("-f" "e") else if [[ "${BEST_DECORATION}" == *"+F"* ]]; then SMS_FREQ_ARGS+=("-f" "e") else SMS_FREQ_ARGS+=("-f" "m") fi fi DECO_SANITIZED="${BEST_DECORATION//\'/}" DECO_SANITIZED="${DECO_SANITIZED// /}" DECO_SANITIZED="${DECO_SANITIZED//$'\r'/}" DECO_SANITIZED="${DECO_SANITIZED//$'\n'/}" DECO_SANITIZED="${DECO_SANITIZED//+F/}" declare -a SMS_VAR_ARGS=() case "${DECO_SANITIZED}" in "") ;; "+G") SMS_VAR_ARGS+=("-c" "${SMS_GAMMA_CATEGORIES}" "-a" "e") ;; "+I") SMS_VAR_ARGS+=("-v" "e") ;; "+R") SMS_VAR_ARGS+=("--freerates" "-c" "${SMS_FREE_RATE_CATEGORIES}") ;; "+G+I"|"+I+G") SMS_VAR_ARGS+=("-c" "${SMS_GAMMA_CATEGORIES}" "-a" "e" "-v" "e") ;; "+R+I"|"+I+R") SMS_VAR_ARGS+=("--freerates" "-c" "${SMS_FREE_RATE_CATEGORIES}" "-v" "e") ;; *) echo "[phyml-wrapper] Warning: unhandled SMS decoration '${DECO_SANITIZED}', proceeding without extra rate options." >&2 ;; esac FINAL_ARGS=("${PHYML_ARGS[@]}" "${SMS_MODEL_ARGS[@]}" "${SMS_FREQ_ARGS[@]}" "${SMS_VAR_ARGS[@]}") exec "${PHYML_BIN}" "${FINAL_ARGS[@]}" EOF chmod +x /usr/local/bin/phyml-wrapper apt-get clean && rm -rf /var/lib/apt/lists/* %environment export PATH=/usr/local/bin:$PATH %runscript exec /usr/local/bin/phyml-wrapper "$@"