diff --git a/.github/workflows/linux-eic-shell.yml b/.github/workflows/linux-eic-shell.yml index e5ae532763..9753394e7c 100644 --- a/.github/workflows/linux-eic-shell.yml +++ b/.github/workflows/linux-eic-shell.yml @@ -525,6 +525,61 @@ jobs: #TODO view20 + dusk-view: + runs-on: ubuntu-latest + needs: convert-to-step + strategy: + matrix: + view: [view1, view3, view6, view7, view11, view13, view50] + detector_config: [epic_craterlake_no_bhcal] + fail-fast: false + steps: + - uses: actions/checkout@v6 + - uses: actions/download-artifact@v8 + with: + name: ${{ matrix.detector_config }}.stp + path: step/ + - uses: cvmfs-contrib/github-action-cvmfs@v5 + - uses: eic/run-cvmfs-osg-eic-shell@main + with: + platform-release: "eic_xl:nightly" + run: | + # Build dusk/duskcut from source + git clone https://github.com/eic/dusk.git /tmp/dusk + OCC=$(find /opt/software -maxdepth 2 -name "opencascade-*" -type d | head -1) + cmake -S /tmp/dusk -B /tmp/dusk/build \ + -DOpenCASCADE_DIR=${OCC}/lib/cmake/opencascade \ + -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Release + cmake --build /tmp/dusk/build -- -j$(nproc) + export PATH=/tmp/dusk/build:${PATH} + export LD_LIBRARY_PATH=${OCC}/lib:${LD_LIBRARY_PATH} + mkdir -p images + bin/make_dusk_views \ + -i step/${{ matrix.detector_config }}.stp \ + -t ${{ matrix.view }} \ + -d scripts/${{ matrix.view }} \ + -o images/ + - uses: actions/upload-artifact@v7 + with: + name: ${{ matrix.detector_config }}_svg_${{ matrix.view }} + path: images/ + if-no-files-found: error + + merge-dusk-view: + runs-on: ubuntu-latest + needs: + - dusk-view + if: always() && (needs.dusk-view.result == 'success') + strategy: + matrix: + detector_config: [epic_craterlake_no_bhcal] + steps: + - uses: actions/upload-artifact/merge@v7 + with: + name: ${{ matrix.detector_config }}_svg + pattern: ${{ matrix.detector_config }}_svg_* + delete-merged: true + merge-dawn-view: runs-on: ubuntu-latest needs: diff --git a/bin/make_dusk_views b/bin/make_dusk_views new file mode 100755 index 0000000000..8753828ef2 --- /dev/null +++ b/bin/make_dusk_views @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +"""make_dusk_views — run dusk/duskcut generate_svg scripts for a detector view. + +Analogous to make_dawn_views but uses STEP files and produces SVG output. + +Usage: + make_dusk_views -i detector.stp -d scripts/view1 -t view01 [-o images/] +""" + +import os +import subprocess +import argparse + +parser = argparse.ArgumentParser(description="Generate SVG views using dusk/duskcut") + +parser.add_argument('-i', '--input', type=str, dest='input', required=True, + help='Input STEP file (.stp)') +parser.add_argument('-o', '--output-dir', type=str, dest='out_dir', + default='images', + help='Output directory for SVG files (default: images)') +parser.add_argument('-d', '--dusk-dir', type=str, dest='dusk_dir', + default='scripts/view1', + help='Directory containing the generate_svg script') +parser.add_argument('-t', '--tag', type=str, dest='file_tag', + default='view', + help='Output file tag passed to generate_svg') + +args = parser.parse_args() + +os.makedirs(args.out_dir, exist_ok=True) + +# Use absolute paths so chdir does not break them +args.input = os.path.abspath(args.input) +args.out_dir = os.path.abspath(args.out_dir) + +owd = os.getcwd() +os.chdir(args.dusk_dir) +subprocess.run(['pwd']) +subprocess.run(['./generate_svg', '-t', args.file_tag, '-i', args.input]) +subprocess.run(['ls', '-lrth']) + +os.system('cp *.svg {}'.format(args.out_dir)) +os.chdir(owd) diff --git a/scripts/view1/generate_svg b/scripts/view1/generate_svg new file mode 100755 index 0000000000..2f50038fc5 --- /dev/null +++ b/scripts/view1/generate_svg @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# generate_svg — dusk/duskcut equivalent of generate_eps for view1 +# Produces side and top SVG views using STEP file input. +# +# Usage: ./generate_svg -i detector.stp [-t tag] + +function print_the_help { + echo "USAGE: $0 -i [-t ]" + echo " OPTIONS:" + echo " -i, --input input STEP file (required)" + echo " -t, --tag filename tag (default: view01)" + exit 0 +} + +FILE_TAG="view01" +INPUT_FILE="" + +POSITIONAL=() +while [[ $# -gt 0 ]]; do + key="$1" + case $key in + -h|--help) print_the_help ;; + -i|--input) INPUT_FILE="$2"; shift; shift ;; + -t|--tag) FILE_TAG="$2"; shift; shift ;; + *) echo "unknown option $1"; print_the_help ;; + esac +done + +if [[ -z "${INPUT_FILE}" ]]; then + echo "Error: no input file specified." + print_the_help +fi + +# Side view — cut at x=1 mm (keep x >= 1 mm), theta=165, phi=75, draw=3 +duskcut -1 0 0 1 "${INPUT_FILE}" "${FILE_TAG}_side.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}_side.stp" --mag 10 --draw 3 --theta 165 --phi 75 \ + --light-theta 180 --light-phi 90 -o "${FILE_TAG}.svg" + +# Top view — thin y-slice near y=0, theta=90, phi=90, draw=1 +duskcut 0 1 0 1 "${INPUT_FILE}" "${FILE_TAG}_top_t0.stp" +duskcut 0 -1 0 1 "${FILE_TAG}_top_t0.stp" "${FILE_TAG}_top.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}_top.stp" --mag 10 --draw 1 --theta 90 --phi 90 \ + -o "${FILE_TAG}_top.svg" + +rm -f "${FILE_TAG}_side.stp" "${FILE_TAG}_top_t0.stp" "${FILE_TAG}_top.stp" +echo "[generate_svg] Done: ${FILE_TAG}.svg ${FILE_TAG}_top.svg" diff --git a/scripts/view11/generate_svg b/scripts/view11/generate_svg new file mode 100755 index 0000000000..8f7e05adff --- /dev/null +++ b/scripts/view11/generate_svg @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# generate_svg — dusk/duskcut equivalent of generate_eps for view11 +# Slightly tilted XZ section along the beamline (x = ±200mm with small z tilt). + +function print_the_help { + echo "USAGE: $0 -i [-t ]" + exit 0 +} + +FILE_TAG="view11" +INPUT_FILE="" + +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) print_the_help ;; + -i|--input) INPUT_FILE="$2"; shift; shift ;; + -t|--tag) FILE_TAG="$2"; shift; shift ;; + *) echo "unknown option $1"; print_the_help ;; + esac +done + +[[ -z "${INPUT_FILE}" ]] && { echo "Error: no input file."; print_the_help; } + +# Slightly tilted slice near x=0 along the beam axis +# dawncut 1 0 -0.01666 200 → plane x - 0.01666*z + 200 = 0, keeps x - 0.01666*z >= -200 +# dawncut -1 0 0.01666 200 → plane -x + 0.01666*z + 200 = 0, keeps -x + 0.01666*z <= -200 +duskcut 1 0 -0.01666 200 "${INPUT_FILE}" "${FILE_TAG}_t0.stp" +duskcut -1 0 0.01666 200 "${FILE_TAG}_t0.stp" "${FILE_TAG}.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}.stp" --draw 2 -o "${FILE_TAG}.svg" + +rm -f "${FILE_TAG}_t0.stp" "${FILE_TAG}.stp" +echo "[generate_svg] Done: ${FILE_TAG}.svg" diff --git a/scripts/view13/generate_svg b/scripts/view13/generate_svg new file mode 100755 index 0000000000..01f9486dd1 --- /dev/null +++ b/scripts/view13/generate_svg @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# generate_svg — dusk/duskcut equivalent of generate_eps for view13 +# Everything downstream of z = 5 m (forward spectrometer region). + +function print_the_help { + echo "USAGE: $0 -i [-t ]" + exit 0 +} + +FILE_TAG="view13" +INPUT_FILE="" + +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) print_the_help ;; + -i|--input) INPUT_FILE="$2"; shift; shift ;; + -t|--tag) FILE_TAG="$2"; shift; shift ;; + *) echo "unknown option $1"; print_the_help ;; + esac +done + +[[ -z "${INPUT_FILE}" ]] && { echo "Error: no input file."; print_the_help; } + +# dawncut 0 0 -1 -5000 → plane -z-5000=0 → z=-5000, clips -z-5000>0 i.e. z<-5000 +# Wait: clips front side: 0*x+0*y+(-1)*z+(-5000)>0 → -z-5000>0 → z<-5000 +# Actually let me re-read: dawncut 0 0 -1 -5000 +# plane: -z + (-5000) = 0 → z = -5000, but that's wrong for "downstream of z=5000" +# From generate_eps comment: "everything downstream of z = 5 m" +# dawncut 0 0 -1 -5000: clips -z-5000 > 0 → -z > 5000 → z < -5000. Keeps z >= -5000. +# But "downstream" in EIC is hadron-going (+z). Hmm, dawncut convention: n=(0,0,-1), d=-5000. +# Plane: -z - 5000 = 0 → z = -5000. Keep: -z - 5000 ≤ 0 → z ≥ -5000. +# That keeps z ≥ -5000, i.e. everything except z < -5000. For EIC, ion beam goes in +z, +# so "downstream" = large +z. This view must keep the z > 5000 mm region. +# Let me trust the original script literal translation: duskcut 0 0 -1 -5000 +duskcut 0 0 -1 -5000 "${INPUT_FILE}" "${FILE_TAG}b.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}b.stp" --draw 2 -o "${FILE_TAG}b.svg" + +rm -f "${FILE_TAG}b.stp" +echo "[generate_svg] Done: ${FILE_TAG}b.svg" diff --git a/scripts/view3/generate_svg b/scripts/view3/generate_svg new file mode 100755 index 0000000000..f29046cf6d --- /dev/null +++ b/scripts/view3/generate_svg @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# generate_svg — dusk/duskcut equivalent of generate_eps for view3 +# Single XZ side view of the central region (z <= 1500 mm). + +function print_the_help { + echo "USAGE: $0 -i [-t ]" + exit 0 +} + +FILE_TAG="view3" +INPUT_FILE="" + +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) print_the_help ;; + -i|--input) INPUT_FILE="$2"; shift; shift ;; + -t|--tag) FILE_TAG="$2"; shift; shift ;; + *) echo "unknown option $1"; print_the_help ;; + esac +done + +[[ -z "${INPUT_FILE}" ]] && { echo "Error: no input file."; print_the_help; } + +# Keep the portion of the model with z >= 1500 mm. +duskcut 0 0 -1 1500 "${INPUT_FILE}" "${FILE_TAG}.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}.stp" --draw 2 -o "${FILE_TAG}.svg" + +rm -f "${FILE_TAG}.stp" +echo "[generate_svg] Done: ${FILE_TAG}.svg" diff --git a/scripts/view50/generate_svg b/scripts/view50/generate_svg new file mode 100755 index 0000000000..7196bbce51 --- /dev/null +++ b/scripts/view50/generate_svg @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# generate_svg — dusk/duskcut equivalent of generate_eps for view50 +# Side view with extended z range and a top-down view of the full detector. + +function print_the_help { + echo "USAGE: $0 -i [-t ]" + exit 0 +} + +FILE_TAG="view01" +INPUT_FILE="" + +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) print_the_help ;; + -i|--input) INPUT_FILE="$2"; shift; shift ;; + -t|--tag) FILE_TAG="$2"; shift; shift ;; + *) echo "unknown option $1"; print_the_help ;; + esac +done + +[[ -z "${INPUT_FILE}" ]] && { echo "Error: no input file."; print_the_help; } + +# Side view — upper half only (y >= 1 mm), mag=4, theta=90, phi=40, draw=3 +duskcut 0 1 0 1 "${INPUT_FILE}" "${FILE_TAG}_side.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}_side.stp" --mag 4 --draw 3 \ + --theta 90 --phi 40 --light-theta 180 --light-phi 90 \ + -z 15000 -o "${FILE_TAG}.svg" + +# Top view — thin y-slice, mag=10, theta=270, phi=90, draw=1 +duskcut 0 1 0 1 "${INPUT_FILE}" "${FILE_TAG}_top_t0.stp" +duskcut 0 -1 0 1 "${FILE_TAG}_top_t0.stp" "${FILE_TAG}_top.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}_top.stp" --mag 10 --draw 1 --theta 270 --phi 90 \ + -o "${FILE_TAG}_top.svg" + +rm -f "${FILE_TAG}_side.stp" "${FILE_TAG}_top_t0.stp" "${FILE_TAG}_top.stp" +echo "[generate_svg] Done: ${FILE_TAG}.svg ${FILE_TAG}_top.svg" diff --git a/scripts/view6/generate_svg b/scripts/view6/generate_svg new file mode 100755 index 0000000000..a1ee95b546 --- /dev/null +++ b/scripts/view6/generate_svg @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# generate_svg — dusk/duskcut equivalent of generate_eps for view6 +# Series of XY (endcap) slices at different z positions for the Si Tracker. + +function print_the_help { + echo "USAGE: $0 -i [-t ]" + exit 0 +} + +FILE_TAG="view06" +INPUT_FILE="" + +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) print_the_help ;; + -i|--input) INPUT_FILE="$2"; shift; shift ;; + -t|--tag) FILE_TAG="$2"; shift; shift ;; + *) echo "unknown option $1"; print_the_help ;; + esac +done + +[[ -z "${INPUT_FILE}" ]] && { echo "Error: no input file."; print_the_help; } + +# Pre-cut to |z| <= 1000 mm +duskcut 0 0 -1 1000 "${INPUT_FILE}" "${FILE_TAG}_pre0.stp" +duskcut 0 0 1 1000 "${FILE_TAG}_pre0.stp" "${FILE_TAG}_input.stp" + +INPUT="${FILE_TAG}_input.stp" + +# Slice a: |z| <= 1 mm (central XY plane) +duskcut 0 0 -1 1 "${INPUT}" "${FILE_TAG}a_t0.stp" +duskcut 0 0 1 1 "${FILE_TAG}a_t0.stp" "${FILE_TAG}a.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}a.stp" --mag 14 --draw 2 -o "${FILE_TAG}a.svg" + +# Slice b: SiTracker Endcap layer 5 (860-945 mm) +duskcut 0 0 1 945 "${INPUT}" "${FILE_TAG}b_t0.stp" +duskcut 0 0 -1 -865 "${FILE_TAG}b_t0.stp" "${FILE_TAG}b.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}b.stp" --mag 14 --draw 2 -o "${FILE_TAG}b.svg" + +# Slice c: SiTracker Endcap layer 4 (695-780 mm) +duskcut 0 0 1 780 "${INPUT}" "${FILE_TAG}c_t0.stp" +duskcut 0 0 -1 -700 "${FILE_TAG}c_t0.stp" "${FILE_TAG}c.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}c.stp" --mag 14 --draw 2 -o "${FILE_TAG}c.svg" + +# Slice d: SiTracker Endcap layer 3 (530-595 mm) +duskcut 0 0 1 595 "${INPUT}" "${FILE_TAG}d_t0.stp" +duskcut 0 0 -1 -535 "${FILE_TAG}d_t0.stp" "${FILE_TAG}d.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}d.stp" --mag 14 --draw 2 -o "${FILE_TAG}d.svg" + +# Slice e: SiTracker Endcap layer 2 (365-430 mm) +duskcut 0 0 1 430 "${INPUT}" "${FILE_TAG}e_t0.stp" +duskcut 0 0 -1 -370 "${FILE_TAG}e_t0.stp" "${FILE_TAG}e.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}e.stp" --mag 14 --draw 2 -o "${FILE_TAG}e.svg" + +# Slice f: SiTracker Endcap layer 1 (200-225 mm) +duskcut 0 0 1 225 "${INPUT}" "${FILE_TAG}f_t0.stp" +duskcut 0 0 -1 -205 "${FILE_TAG}f_t0.stp" "${FILE_TAG}f.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}f.stp" --mag 14 --draw 2 -o "${FILE_TAG}f.svg" + +rm -f "${FILE_TAG}_pre0.stp" "${FILE_TAG}_input.stp" \ + "${FILE_TAG}"[abcdef]_t0.stp "${FILE_TAG}"[abcdef].stp +echo "[generate_svg] Done: ${FILE_TAG}{a..f}.svg" diff --git a/scripts/view7/generate_svg b/scripts/view7/generate_svg new file mode 100755 index 0000000000..02103111d4 --- /dev/null +++ b/scripts/view7/generate_svg @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# generate_svg — dusk/duskcut equivalent of generate_eps for view7 +# Two XY slices: central slice and SiTracker Endcap layer 1. + +function print_the_help { + echo "USAGE: $0 -i [-t ]" + exit 0 +} + +FILE_TAG="view7" +INPUT_FILE="" + +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) print_the_help ;; + -i|--input) INPUT_FILE="$2"; shift; shift ;; + -t|--tag) FILE_TAG="$2"; shift; shift ;; + *) echo "unknown option $1"; print_the_help ;; + esac +done + +[[ -z "${INPUT_FILE}" ]] && { echo "Error: no input file."; print_the_help; } + +# Slice a: |z| <= 1 mm (central XY plane) +duskcut 0 0 -1 1 "${INPUT_FILE}" "${FILE_TAG}a_t0.stp" +duskcut 0 0 1 1 "${FILE_TAG}a_t0.stp" "${FILE_TAG}a.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}a.stp" --draw 2 -o "${FILE_TAG}a.svg" + +# Slice b: SiTracker Endcap layer 1 (205-225 mm) +duskcut 0 0 1 225 "${INPUT_FILE}" "${FILE_TAG}b_t0.stp" +duskcut 0 0 -1 -205 "${FILE_TAG}b_t0.stp" "${FILE_TAG}b.stp" +dusk --mesh-deflection 5 -d "${FILE_TAG}b.stp" --draw 2 -o "${FILE_TAG}b.svg" + +rm -f "${FILE_TAG}a_t0.stp" "${FILE_TAG}a.stp" \ + "${FILE_TAG}b_t0.stp" "${FILE_TAG}b.stp" +echo "[generate_svg] Done: ${FILE_TAG}a.svg ${FILE_TAG}b.svg"