diff --git a/.github/workflows/check-geometry-configs.yml b/.github/workflows/check-geometry-configs.yml new file mode 100644 index 000000000..549d9579f --- /dev/null +++ b/.github/workflows/check-geometry-configs.yml @@ -0,0 +1,31 @@ +name: Check geometry configs + +on: + workflow_call: + inputs: + detector_configs: + required: true + type: string + +jobs: + check-geometry-configs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: build-gcc-fast-eic-shell + path: install/ + - uses: cvmfs-contrib/github-action-cvmfs@v4 + - uses: eic/run-cvmfs-osg-eic-shell@main + with: + platform-release: "jug_xl:nightly" + network_types: "none" + setup: install/bin/thisepic.sh + run: | + IFS=, read -a configs <<< "${{inputs.detector_configs}}" + for config in ${configs[@]} ; do + echo "::group::${config}" ; + checkGeometry -c ${DETECTOR_PATH}/${config}.xml ; + echo "::endgroup::" ; + done diff --git a/.github/workflows/check-tracking-geometry.yml b/.github/workflows/check-tracking-geometry.yml new file mode 100644 index 000000000..69e4e0f06 --- /dev/null +++ b/.github/workflows/check-tracking-geometry.yml @@ -0,0 +1,30 @@ +name: Check tracking geometry + +on: + workflow_call: + inputs: + detector_configs: + required: true + type: string + +jobs: + check-tracking-geometry: + runs-on: ubuntu-latest + strategy: + matrix: + detector_config: ${{fromJson(inputs.detector_configs)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: build-gcc-fast-eic-shell + path: install/ + - uses: cvmfs-contrib/github-action-cvmfs@v4 + - uses: eic/run-cvmfs-osg-eic-shell@main + with: + platform-release: "jug_xl:nightly" + network_types: "none" + setup: install/bin/thisepic.sh + run: | + root -b -q "scripts/test_ACTS.cxx+(\"${DETECTOR_PATH}/${{matrix.detector_config}}.xml\")" | tee check_tracking_geometry.out + bin/acts_geo_check check_tracking_geometry.out diff --git a/.github/workflows/convert-to-gdml.yml b/.github/workflows/convert-to-gdml.yml new file mode 100644 index 000000000..2620cf0fd --- /dev/null +++ b/.github/workflows/convert-to-gdml.yml @@ -0,0 +1,36 @@ +name: Convert to GDML + +on: + workflow_call: + inputs: + detector_configs: + required: true + type: string + +jobs: + convert-to-gdml: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: build-gcc-full-eic-shell + path: install/ + - uses: cvmfs-contrib/github-action-cvmfs@v4 + - uses: eic/run-cvmfs-osg-eic-shell@main + with: + platform-release: "jug_xl:nightly" + network_types: "none" + setup: install/bin/thisepic.sh + run: | + IFS=, read -a configs <<< "${{inputs.detector_configs}}" + for config in ${configs[@]} ; do + echo "::group::${config}" ; + geoConverter -compact2gdml -input ${DETECTOR_PATH}/${config}.xml -output ${config}.gdml ; + echo "::endgroup::" ; + done + - uses: actions/upload-artifact@v4 + with: + name: gdml + path: "*.gdml" + if-no-files-found: error diff --git a/.github/workflows/convert-to-step.yml b/.github/workflows/convert-to-step.yml new file mode 100644 index 000000000..d6c61bf6f --- /dev/null +++ b/.github/workflows/convert-to-step.yml @@ -0,0 +1,44 @@ +name: Convert to STEP + +on: + workflow_call: + inputs: + detector_configs: + required: true + type: string + +jobs: + convert-to-step: + runs-on: ubuntu-latest + strategy: + matrix: + detector_config: ${{fromJson(inputs.detector_configs)}} + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: build-gcc-fast-eic-shell + path: install/ + - uses: cvmfs-contrib/github-action-cvmfs@v4 + - uses: eic/run-cvmfs-osg-eic-shell@main + with: + platform-release: "jug_xl:nightly" + network_types: "none" + setup: install/bin/thisepic.sh + run: | + # For some reason npdet_to_step really wants a space in IFS + IFS=$' \n\t' + # First get all detectors (except world) + declare -A detectors + while read d ; do detectors[$d]='-l 3' ; done <<< $(npdet_to_step list $DETECTOR_PATH/${{matrix.detector_config}}.xml | sed '/world/d;s/.*(vol: \(.*\)).*/\1/g') + # Then tweak the levels (default is 1) + detectors[HcalBarrel]='-l 1' + detectors[LFHCAL]='-l 2' + detectors[OuterBarrelMPGDSubAssembly]='-l 4' + # Export to one STEP file + npdet_to_step $(for d in ${!detectors[@]} ; do echo part ${detectors[$d]} $d ; done) -o ${{matrix.detector_config}} $DETECTOR_PATH/${{matrix.detector_config}}.xml 2>&1 | sed '/TGeoMatrix::dtor/d' + - uses: actions/upload-artifact@v4 + with: + name: ${{matrix.detector_config}}.stp + path: ${{matrix.detector_config}}.stp + if-no-files-found: error diff --git a/.github/workflows/convert-to-tgeo.yml b/.github/workflows/convert-to-tgeo.yml new file mode 100644 index 000000000..20c7347f1 --- /dev/null +++ b/.github/workflows/convert-to-tgeo.yml @@ -0,0 +1,36 @@ +name: Convert to TGeo + +on: + workflow_call: + inputs: + detector_configs: + required: true + type: string + +jobs: + convert-to-tgeo: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: build-gcc-full-eic-shell + path: install/ + - uses: cvmfs-contrib/github-action-cvmfs@v4 + - uses: eic/run-cvmfs-osg-eic-shell@main + with: + platform-release: "jug_xl:nightly" + network_types: "none" + setup: install/bin/thisepic.sh + run: | + IFS=, read -a configs <<< "${{inputs.detector_configs}}" + for config in ${configs[@]} ; do + echo "::group::${config}" ; + geoConverter -compact2tgeo -input ${DETECTOR_PATH}/${config}.xml -output ${config}.root + echo "::endgroup::" ; + done + - uses: actions/upload-artifact@v4 + with: + name: tgeo + path: "*.root" + if-no-files-found: error diff --git a/.github/workflows/linux-eic-shell.yml b/.github/workflows/linux-eic-shell.yml index 0a1464361..598d8d107 100644 --- a/.github/workflows/linux-eic-shell.yml +++ b/.github/workflows/linux-eic-shell.yml @@ -37,9 +37,9 @@ jobs: ls -1 configurations | sed 's/^/epic_/g' | xargs | sed 's/\.yml//g;s/ /,/g' ) CONFIGS_JSON=$(( - echo '{ "detector_config": [' + echo '[' ls -1 configurations | sed 's/^/epic_/g' | xargs | sed 's/\.yml//g;s/ /, /g' | xargs -n 1 echo | sed -r 's/^([^,]*)(,?)$/"\1"\2/' - echo ' ]}' + echo ']' ) | jq -c .) echo "configs_csv=${CONFIGS_CSV}" | tee -a $GITHUB_OUTPUT echo "configs_json=${CONFIGS_JSON}" | tee -a $GITHUB_OUTPUT @@ -99,7 +99,7 @@ jobs: - run: | source install/bin/thisepic.sh sed -i 's%\(\1%g; s%\(/fiber>\|/lens>\)%\1%g' \ - ${DETECTOR_PATH}/compact/ecal/barrel_interlayers.xml \ + ${DETECTOR_PATH}/compact/ecal/bic_default.xml \ ${DETECTOR_PATH}/compact/ecal/forward_scfi.xml \ ${DETECTOR_PATH}/compact/far_forward/ZDC_Ecal_WSciFi.xml \ ${DETECTOR_PATH}/compact/pid/mrich.xml @@ -122,75 +122,19 @@ jobs: sudo apt-get install -y libxml2-utils find install/share -name "*.xml" -exec xmllint {} \; > /dev/null - trigger-geoviewer: - runs-on: ubuntu-latest - needs: - - xmllint-after-build - - list-detector-configs - steps: - - uses: eic/trigger-gitlab-ci@v3 - id: trigger - with: - url: https://eicweb.phy.anl.gov - project_id: 539 - token: ${{ secrets.EICWEB_GEOVIEWER_TRIGGER }} - ref_name: main - variables: | - DETECTOR=epic - DETECTOR_REPOSITORYURL=${{ github.server_url }}/${{ github.repository }} - DETECTOR_REPOSITORYREF=${{ github.ref }} - DETECTOR_CONFIG=${{ needs.list-detector-configs.outputs.configs_csv }} - DETECTOR_VERSION=${{ github.event.pull_request.head.ref || github.ref_name }} - GITHUB_REPOSITORY=${{ github.repository }} - GITHUB_SHA=${{ github.event.pull_request.head.sha || github.sha }} - GITHUB_PR=${{ github.event.pull_request.number }} - check-geometry-configs: - runs-on: ubuntu-latest needs: - build - list-detector-configs - steps: - - uses: actions/checkout@v4 - - uses: actions/download-artifact@v4 - with: - name: build-gcc-fast-eic-shell - path: install/ - - uses: cvmfs-contrib/github-action-cvmfs@v4 - - uses: eic/run-cvmfs-osg-eic-shell@main - with: - platform-release: "jug_xl:nightly" - network_types: "none" - setup: install/bin/thisepic.sh - run: | - IFS=, read -a configs <<< "${{ needs.list-detector-configs.outputs.configs_csv }}" - for config in ${configs[@]} ; do - echo "::group::${config}" ; - checkGeometry -c ${DETECTOR_PATH}/${config}.xml ; - echo "::endgroup::" ; - done + uses: ./.github/workflows/check-geometry-configs.yml + with: + detector_configs: ${{needs.list-detector-configs.outputs.configs_csv}} check-tracking-geometry: - runs-on: ubuntu-latest needs: build - strategy: - matrix: - detector_config: [epic_craterlake, epic_ip6] - steps: - - uses: actions/checkout@v4 - - uses: actions/download-artifact@v4 - with: - name: build-gcc-fast-eic-shell - path: install/ - - uses: cvmfs-contrib/github-action-cvmfs@v4 - - uses: eic/run-cvmfs-osg-eic-shell@main - with: - platform-release: "jug_xl:nightly" - network_types: "none" - setup: install/bin/thisepic.sh - run: | - root -b -q "scripts/test_ACTS.cxx+(\"${DETECTOR_PATH}/${{matrix.detector_config}}.xml\")" | tee check_tracking_geometry.out - bin/acts_geo_check check_tracking_geometry.out + uses: ./.github/workflows/check-tracking-geometry.yml + with: + detector_configs: "['epic_craterlake', 'epic_ip6']" validate-material-map: runs-on: ubuntu-latest @@ -224,101 +168,28 @@ jobs: if-no-files-found: error convert-to-gdml: - runs-on: ubuntu-latest needs: - build - list-detector-configs - steps: - - uses: actions/checkout@v4 - - uses: actions/download-artifact@v4 - with: - name: build-gcc-full-eic-shell - path: install/ - - uses: cvmfs-contrib/github-action-cvmfs@v4 - - uses: eic/run-cvmfs-osg-eic-shell@main - with: - platform-release: "jug_xl:nightly" - network_types: "none" - setup: install/bin/thisepic.sh - run: | - IFS=, read -a configs <<< "${{ needs.list-detector-configs.outputs.configs_csv }}" - for config in ${configs[@]} ; do - echo "::group::${config}" ; - geoConverter -compact2gdml -input ${DETECTOR_PATH}/${config}.xml -output ${config}.gdml ; - echo "::endgroup::" ; - done - - uses: actions/upload-artifact@v4 - with: - name: gdml - path: "*.gdml" - if-no-files-found: error + uses: ./.github/workflows/convert-to-gdml.yml + with: + detector_configs: ${{needs.list-detector-configs.outputs.configs_csv}} convert-to-tgeo: - runs-on: ubuntu-latest needs: - build - list-detector-configs - steps: - - uses: actions/checkout@v4 - - uses: actions/download-artifact@v4 - with: - name: build-gcc-full-eic-shell - path: install/ - - uses: cvmfs-contrib/github-action-cvmfs@v4 - - uses: eic/run-cvmfs-osg-eic-shell@main - with: - platform-release: "jug_xl:nightly" - network_types: "none" - setup: install/bin/thisepic.sh - run: | - IFS=, read -a configs <<< "${{ needs.list-detector-configs.outputs.configs_csv }}" - for config in ${configs[@]} ; do - echo "::group::${config}" ; - geoConverter -compact2tgeo -input ${DETECTOR_PATH}/${config}.xml -output ${config}.root - echo "::endgroup::" ; - done - - uses: actions/upload-artifact@v4 - with: - name: tgeo - path: "*.root" - if-no-files-found: error + uses: ./.github/workflows/convert-to-tgeo.yml + with: + detector_configs: ${{needs.list-detector-configs.outputs.configs_csv}} convert-to-step: - runs-on: ubuntu-latest needs: - build - list-detector-configs - strategy: - matrix: ${{fromJson(needs.list-detector-configs.outputs.configs_json)}} - steps: - - uses: actions/checkout@v4 - - uses: actions/download-artifact@v4 - with: - name: build-gcc-fast-eic-shell - path: install/ - - uses: cvmfs-contrib/github-action-cvmfs@v4 - - uses: eic/run-cvmfs-osg-eic-shell@main - with: - platform-release: "jug_xl:nightly" - network_types: "none" - setup: install/bin/thisepic.sh - run: | - # For some reason npdet_to_step really wants a space in IFS - IFS=$' \n\t' - # First get all detectors (except world) - declare -A detectors - while read d ; do detectors[$d]='-l 3' ; done <<< $(npdet_to_step list $DETECTOR_PATH/${{matrix.detector_config}}.xml | sed '/world/d;s/.*(vol: \(.*\)).*/\1/g') - # Then tweak the levels (default is 1) - detectors[HcalBarrel]='-l 1' - detectors[LFHCAL]='-l 2' - detectors[OuterBarrelMPGDSubAssembly]='-l 4' - # Export to one STEP file - npdet_to_step $(for d in ${!detectors[@]} ; do echo part ${detectors[$d]} $d ; done) -o ${{matrix.detector_config}} $DETECTOR_PATH/${{matrix.detector_config}}.xml 2>&1 | sed '/TGeoMatrix::dtor/d' - - uses: actions/upload-artifact@v4 - with: - name: ${{matrix.detector_config}}.stp - path: ${{matrix.detector_config}}.stp - if-no-files-found: error + uses: ./.github/workflows/convert-to-step.yml + with: + detector_configs: ${{needs.list-detector-configs.outputs.configs_json}} dump-constants: runs-on: ubuntu-latest @@ -517,39 +388,28 @@ jobs: noverlaps="$(grep -c GeomVol1002 doc/overlap_check_geant4.out || true)" if [[ "${noverlaps}" -gt "0" ]] ; then echo "${noverlaps} overlaps found!" && false ; fi - trigger-benchmarks: + trigger-container: runs-on: ubuntu-latest + if: ${{ github.actor != 'dependabot[bot]' }} needs: [check-overlap-tgeo, check-overlap-geant4-fast] - strategy: - matrix: - detector_config: [epic_craterlake] - benchmark_repo: [detector_benchmarks, physics_benchmarks, reconstruction_benchmarks] - include: - - benchmark_repo: detector_benchmarks - project_id: 399 - secret_var: EICWEB_DETECTOR_BENCHMARK_TRIGGER - - benchmark_repo: physics_benchmarks - project_id: 400 - secret_var: EICWEB_PHYSICS_BENCHMARK_TRIGGER - - benchmark_repo: reconstruction_benchmarks - project_id: 408 - secret_var: EICWEB_RECONSTRUCTION_BENCHMARK_TRIGGER steps: - uses: eic/trigger-gitlab-ci@v3 id: trigger with: url: https://eicweb.phy.anl.gov - project_id: ${{ matrix.project_id }} - token: ${{ secrets[matrix.secret_var] }} + project_id: 290 + token: ${{ secrets.EICWEB_CONTAINER_TRIGGER }} ref_name: master variables: | DETECTOR=epic DETECTOR_REPOSITORYURL=${{ github.server_url }}/${{ github.repository }} - DETECTOR_VERSION=${{ github.event.pull_request.head.ref || github.ref_name }} - DETECTOR_CONFIG=${{ matrix.detector_config }} + DETECTOR_VERSION=${{ github.sha }} + DETECTOR_CONFIG=epic_craterlake GITHUB_REPOSITORY=${{ github.repository }} GITHUB_SHA=${{ github.event.pull_request.head.sha || github.sha }} - PIPELINE_NAME=${{ github.event.pull_request.title || github.sha }} + GITHUB_PR=${{ github.event.pull_request.number }} + EPIC_VERSION="${{ github.event.pull_request.head.ref || github.ref_name }}" + PIPELINE_NAME=${{ github.repository }}: ${{ github.event.pull_request.title || github.ref_name }} - run: | gh api \ --method POST \ @@ -558,7 +418,7 @@ jobs: -f state="pending" \ -f target_url="${{ steps.trigger.outputs.web_url }}" \ -f description="Triggered... $(TZ=America/New_York date)" \ - -f context="eicweb/${{ matrix.benchmark_repo }} (${{ matrix.detector_config }})" + -f context="eicweb/eic_container" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -693,7 +553,7 @@ jobs: if-no-files-found: error - name: Download previous artifact id: download_previous_artifact - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: branch: ${{ github.event.pull_request.base.ref || github.ref_name }} path: ref/ @@ -753,7 +613,7 @@ jobs: if-no-files-found: error - name: Download previous artifact id: download_previous_artifact - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: branch: ${{ github.event.pull_request.base.ref || github.ref_name }} path: ref/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6ee3808cc..2c68811fd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,12 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v18.1.5 + rev: v19.1.1 hooks: - id: clang-format - repo: https://github.com/Lucas-C/pre-commit-hooks diff --git a/CMakeLists.txt b/CMakeLists.txt index fa06a7105..49e5778d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,10 @@ PROJECT(epic DESCRIPTION "DD4hep Geometry Description of the EPIC Experiment" ) +# Set version based on git +include(cmake/git_version.cmake) +set_git_version(CMAKE_PROJECT_VERSION) + # C++ standard set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17 CACHE STRING "Set the C++ standard to be used") @@ -101,14 +105,16 @@ install(DIRECTORY calibrations/ ) #----------------------------------------------------------------------------------- -# Configure and install detector setup script +# Configure and install compact/version.xml # -execute_process( - COMMAND git rev-parse --abbrev-ref HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_BRANCH - OUTPUT_STRIP_TRAILING_WHITESPACE +configure_file(templates/version.xml.in ${CMAKE_CURRENT_BINARY_DIR}/version.xml @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/version.xml + DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact ) + +#----------------------------------------------------------------------------------- +# Configure and install detector setup script +# configure_file(templates/thisepic.sh.in ${CMAKE_CURRENT_BINARY_DIR}/thisepic.sh @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/thisepic.sh DESTINATION ${CMAKE_INSTALL_BINDIR} diff --git a/bin/g4MaterialScan_raw_plot b/bin/g4MaterialScan_raw_plot new file mode 100755 index 000000000..3b2cf3075 --- /dev/null +++ b/bin/g4MaterialScan_raw_plot @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: LGPL-3.0-or-later +# Copyright (C) 2024 Chao Peng +''' + A script to plot raw data output from the script g4MaterialScan_to_csv +''' + +import os +import re +import argparse +import pandas as pd +import numpy as np +from matplotlib import pyplot as plt +from matplotlib.ticker import AutoMinorLocator + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + prog='g4MaterialScan_raw_plot', + description = 'A python script to draw material thickness from raw output of g4MaterialScan_to_csv.' + ) + parser.add_argument( + 'data_path', + help='path to the raw data from scan (a csv file).' + ) + parser.add_argument( + '--path-lengths', default="0, 180, 600", + help='path length points, separated by \",\".' + ) + parser.add_argument( + '--sep', default='\t', + help='Seperator for the CSV file.' + ) + parser.add_argument( + '--font-size', type=float, default=18., + help='Font size of the plots.' + ) + args = parser.parse_args() + + # get the path length points + pls = np.array([float(x.strip()) for x in args.path_lengths.split(',')]) + if len(pls) < 2: + print('Need at least two points in --path-lengths') + exit(-1) + + # determine the eta and phi from path + eta, phi = 0., 0. + try: + match = re.search(r'eta=([\d\-\.]*\d).*phi=([\d\-\.]*\d)', args.data_path) + eta = float(match[1]) + phi = float(match[2]) + except: + print('WARNING: Fail to determine eta, phi from data path, information may be incorrect.') + + # read and process data + df = pd.read_csv(args.data_path, sep=args.sep, index_col=0) + df.loc[:, 'X0_cum'] = df['X0'].cumsum() + df.loc[:, 'lambda_cum'] = df['lambda'].cumsum() + # print(df) + + # font size and colors + fs = args.font_size + prop_cycle = plt.rcParams['axes.prop_cycle'] + colors = prop_cycle.by_key()['color'] + + # plot X0 and lambda in the path length intervals [pl(i), pl(i+1)] + fig, axs = plt.subplots(1, len(pls) - 1, figsize=(8 * (len(pls) - 1), 6), dpi=160, + gridspec_kw=dict(left=0.1, right=0.92, top=0.95, wspace=0.4)) + for i, ax in enumerate(axs.flat): + min_pl, max_pl = pls[i], pls[i + 1] + + dfr = df[(df['path_length'] <= max_pl) & (df['path_length'] >= min_pl)] + # X0 + ax.step(df['path_length'], df['X0_cum'], color=colors[0]) + + # lambda + ax2 = ax.twinx() + ax2.step(df['path_length'], df['lambda_cum'], color=colors[1], ls='--') + + + ax.text(0.05, 0.95, r'$\eta={:.3f}, \phi={:.3f}^{{\circ}}$'.format(eta, phi), + fontsize=fs, color=colors[2], + horizontalalignment='left', verticalalignment='top', transform=ax.transAxes) + # axis format + ax.set_xlabel('Path Length [cm]', fontsize=fs) + ax.set_ylabel('$X/X_0$ (Cumulative)', fontsize=fs, color=colors[0]) + ax2.set_ylabel('$\Lambda$ (Cumulative)', fontsize=fs, color=colors[1]) + ax.xaxis.set_minor_locator(AutoMinorLocator(5)) + ax.yaxis.set_minor_locator(AutoMinorLocator(5)) + ax2.yaxis.set_minor_locator(AutoMinorLocator(5)) + ax.set_xlim(min_pl, max_pl) + ax.set_ylim(0, dfr['X0_cum'].max()*1.1) + ax2.set_ylim(0, dfr['lambda_cum'].max()*1.1) + ax.tick_params(direction='in', which='both', labelsize=fs) + ax2.tick_params(direction='in', which='both', labelsize=fs) + ax.grid(which='major', ls=':') + ax.set_axisbelow(True) + # save the plot with the same name + save_path = '.'.join(args.data_path.split('.')[:-1]) + '.png' + fig.savefig(save_path) + print('Plot saved as \"{}\"'.format(save_path)) diff --git a/bin/g4MaterialScan_raw_plot_2d b/bin/g4MaterialScan_raw_plot_2d new file mode 100755 index 000000000..02fd9e28e --- /dev/null +++ b/bin/g4MaterialScan_raw_plot_2d @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: LGPL-3.0-or-later +# Copyright (C) 2024 Chao Peng +''' + A script to plot raw data output from the script g4MaterialScan_to_csv +''' + +import os +import re +import argparse +import pandas as pd +import numpy as np + +import matplotlib as mpl +from matplotlib import pyplot as plt +from matplotlib.collections import LineCollection, PatchCollection +from matplotlib.patches import Wedge +from mpl_toolkits.axes_grid1 import make_axes_locatable + + +''' + A helper function to convert a string ([:[:]]) to an array +''' +def args_array(arg, step=1, include_end=True): + vals = [float(x.strip()) for x in arg.split(':')] + # empty or only one value + if len(vals) < 2: + return np.array(vals) + # has step input + if len(vals) > 2: + step = vals[2] + # inclusion of the endpoint (max) + if include_end: + vals[1] += step + return np.arange(vals[0], vals[1], step) + + +def eta2theta(v_eta): + return 2.*np.arctan(np.exp(-v_eta)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + prog='g4MaterialScan_raw_plot', + description = 'A python script to draw 2d plot of material thickness from raw outputs of g4MaterialScan_to_csv.' + ) + parser.add_argument( + '--path-format', default=r'scan_raw_eta={eta:.3f}_phi={phi:.3f}.csv', + help='modify the path format, default is \"scan_raw_eta={eta:.3f}_phi={phi:.3f}.csv\".' + ) + parser.add_argument( + '--eta', default='-4.0:4.0:0.1', + help='Eta range, in the format of \"[:[:]]\".' + ) + parser.add_argument( + '--eta-values', default=None, + help='a list of eta values, separated by \",\", this option overwrites --eta.' + ) + parser.add_argument( + '--phi', default='0', type=float, + help='A single phi value to lookup for the data files.' + ) + parser.add_argument( + '--path-lengths', default="0, 180, 600", + help='path length points, separated by \",\".' + ) + parser.add_argument( + '--sep', default='\t', + help='Seperator for the CSV file.' + ) + parser.add_argument( + '--z-max', type=float, default=600, + help='maximum z (x-axis) of the plot.' + ) + parser.add_argument( + '--z-min', type=float, default=-600, + help='minimum z (x-axis) of the plot.' + ) + parser.add_argument( + '--r-max', type=float, default=600, + help='maximum r (y-axis) of the plot.' + ) + parser.add_argument( + '--r-min', type=float, default=0, + help='minimum r (y-axis) of the plot.' + ) + parser.add_argument( + '--x0-max', type=float, default=None, + help='maximum x0 of the plot.' + ) + parser.add_argument( + '--x0-min', type=float, default=None, + help='minimum x0 of the plot.' + ) + parser.add_argument( + '--lambda-max', type=float, default=None, + help='maximum lambda of the plot.' + ) + parser.add_argument( + '--lambda-min', type=float, default=None, + help='minimum lambda of the plot.' + ) + parser.add_argument( + '--plot-scale', type=str, default='log', + help='only support \"log\" or \"linear\" scale.' + ) + parser.add_argument( + '--output-path', type=str, default='mat_scan_2D.{output_format}', + help='path of the output plot, it supports the string format with inputs of the arguments.' + ) + parser.add_argument( + '--output-format', type=str, default='png', + help='format of the plots, default is png, eps is also recommended (vectorized graphics).' + ) + args = parser.parse_args() + + # get the path length points + pls = np.array([float(x.strip()) for x in args.path_lengths.split(',')]) + if len(pls) < 2: + print('Need at least two points in --path-lengths') + exit(1) + + if args.eta_values is not None: + etas = np.array([float(xval.strip()) for xval in args.eta_values.split(',')]) + else: + etas = args_array(args.eta) + + norm = None + if args.plot_scale.lower() == 'linear': + norm = mpl.colors.Normalize + elif args.plot_scale.lower() == 'log': + norm = mpl.colors.LogNorm + else: + print('Error: unsupported plot scale {}, please choose it from [log, linear].'.format(args.plot_scale)) + exit(1) + + phi = args.phi + zmin, zmax = args.z_min, args.z_max + rmin, rmax = args.r_min, args.r_max + + # read raw output data, collect information + patches, x0_array, lmd_array = [], [], [] + thetas = eta2theta(etas) + th_diffs = np.hstack([0., -np.diff(thetas)/2., 0.]) + th_mins = thetas - th_diffs[:-1] + th_maxes = thetas + th_diffs[1:] + + # iterate every eta (theta) scan data + for i, (eta, theta, th_min, th_max) in enumerate(zip(etas, thetas, th_mins, th_maxes)): + # read data file + dpath = args.path_format.format(eta=eta, phi=phi) + if not os.path.exists(dpath): + print('Error: cannot find data file \"{}\", please check the path.'.format(dpath)) + exit(1) + df = pd.read_csv(args.path_format.format(eta=eta, phi=phi), sep=args.sep, index_col=0) + pls = df['path_length'].values + x0s = df['X0'].cumsum().values + lmds = df['lambda'].cumsum().values + # a virtual bin size for the scan (fill all the 2D phase space) + angle_min = th_min/np.pi*180. + angle_max = th_max/np.pi*180. + # determine if the lines are in range + # segments of each scan (assuming start from 0) + for seg_start, seg_end, x0, lmd in zip(np.hstack([0., pls[:-1]]), pls, x0s, lmds): + # start point is already out of the plot range + z0, r0 = np.cos(theta)*seg_start, np.sin(theta)*seg_start + in_range = (z0 <= zmax) & (z0 >= zmin) & (r0 <= rmax) & (r0 >= rmin) + if not in_range: + continue + x0_array.append(x0) + lmd_array.append(lmd) + width = seg_end - seg_start + patches.append(Wedge((0., 0.), seg_end, angle_min, angle_max, width=width)) + + # generate plots + cmap = mpl.colormaps['viridis'] + plot_meta = [ + ('Cumulative X0', x0_array, dict(cmap=cmap, norm=norm(vmin=args.x0_min, vmax=args.x0_max))), + ('Cumulative $\Lambda$', lmd_array, dict(cmap=cmap, norm=norm(vmin=args.lambda_min, vmax=args.lambda_max))), + ] + + fig, axs = plt.subplots(len(plot_meta), 1, figsize=(10, 4*len(plot_meta)), dpi=600) + for ax, (zlabel, data, p_kwargs) in zip(axs.flat, plot_meta): + ax.set_xlim(zmin, zmax) + ax.set_ylim(rmin, rmax) + p = PatchCollection(patches, **p_kwargs) + p.set_array(data) + ax.add_collection(p) + ax.set_xlabel('Z [cm]') + ax.set_ylabel('R [cm] ($\phi = {}^{{\circ}}$)'.format(phi)) + # color bar + divider = make_axes_locatable(ax) + cax = divider.append_axes('right', size='3%', pad=0.05) + cbar = fig.colorbar(p, cax=cax, orientation='vertical') + cbar.ax.set_ylabel(zlabel, rotation=90) + fig.savefig(args.output_path.format(**vars(args)), format=args.output_format) diff --git a/bin/g4MaterialScan_to_csv b/bin/g4MaterialScan_to_csv index 5238d4574..fa05c363b 100755 --- a/bin/g4MaterialScan_to_csv +++ b/bin/g4MaterialScan_to_csv @@ -108,6 +108,7 @@ class g4MaterialScanner: ] dft = pd.read_csv(StringIO('\n'.join(scans)), sep='\s+', header=None, index_col=0, names=cols) + print(dft) return dft.astype({key: np.float64 for key in cols[1:]}) @@ -151,13 +152,25 @@ if __name__ == '__main__': '--eta', default='-4.0:4.0:0.1', help='Eta range, in the format of \"[:[:]]\".' ) + parser.add_argument( + '--eta-values', default=None, + help='a list of eta values, separated by \",\", this option overwrites --eta.' + ) parser.add_argument( '--phi', default='0:30:1', help='Phi angle range, in the format of \"[:[:]]\" (degree).' ) + parser.add_argument( + '--phi-values', default=None, + help='a list of phi values, separated by \",\", this option overwrites --phi.' + ) parser.add_argument( '--mat-buffer-size', type=int, default=50, - help='Material buffer size.' + help='Maximum number of materials included in the aggregated output.' + ) + parser.add_argument( + '--raw-output', action='store_true', + help='Turn on to save the raw outputs from scan.' ) parser.add_argument( '--sep', default='\t', @@ -170,8 +183,15 @@ if __name__ == '__main__': exit(-1) start_point = np.array([float(v.strip()) for v in args.start_point.split(',')]) - etas = args_array(args.eta) - phis = args_array(args.phi) + if args.eta_values is not None: + etas = np.array([float(xval.strip()) for xval in args.eta_values.split(',')]) + else: + etas = args_array(args.eta) + + if args.phi_values is not None: + phis = np.array([float(xval.strip()) for xval in args.phi_values.split(',')]) + else: + phis = args_array(args.phi) # sanity check if not len(phis): print('No phi values from the input {}, aborted!'.format(args.phi)) @@ -201,6 +221,8 @@ if __name__ == '__main__': for vt in value_types: dfa.loc[:, vt] = dfa['int_{}'.format(vt)].diff(1).fillna(dfa['int_{}'.format(vt)]) + if args.raw_output: + dfa.to_csv('scan_raw_eta={:.3f}_phi={:.3f}.csv'.format(eta, phi), sep=args.sep, float_format='%g') # group by materials single_scan = dfa.groupby('material')[value_types].sum() # print(single_scan) diff --git a/cmake/git_version.cmake b/cmake/git_version.cmake new file mode 100644 index 000000000..98e013cfe --- /dev/null +++ b/cmake/git_version.cmake @@ -0,0 +1,29 @@ +# Determine version from git describe cmake-lint: disable=C0103 +macro(set_git_version VERSION) + if(NOT Git_Found) + find_package(Git) + endif() + + if(GIT_EXECUTABLE) + # Generate a git-describe version string from Git repository tags + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags --dirty --match "v*" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_DESCRIBE_VERSION + RESULT_VARIABLE GIT_DESCRIBE_ERROR_CODE + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT GIT_DESCRIBE_ERROR_CODE) + set(${VERSION} ${GIT_DESCRIBE_VERSION}) + endif() + endif() + + # Final fallback: Just use a bogus version string that is semantically older + # than anything else and spit out a warning to the developer. + if(NOT DEFINED ${VERSION}) + set(${VERSION} v0.0.0-unknown) + message( + WARNING + "Failed to determine VERSION from Git tags. Using default version \"${${VERSION}}\"." + ) + endif() +endmacro() diff --git a/compact/calibrations.xml b/compact/calibrations.xml index 724d7b239..a6abaca26 100644 --- a/compact/calibrations.xml +++ b/compact/calibrations.xml @@ -32,7 +32,7 @@ - + diff --git a/compact/definitions.xml b/compact/definitions.xml index 0d0b0831e..5b3eac10f 100644 --- a/compact/definitions.xml +++ b/compact/definitions.xml @@ -314,6 +314,7 @@ The unused IDs below are saved for future use. + @@ -589,14 +590,14 @@ Service gaps in FW direction (before endcapP ECAL) and BW direction (before endc LFHCAL is 140 cm total, but current implementation leaves the final 10 cm empty - + - - + + diff --git a/compact/display.xml b/compact/display.xml index d08ad4fb8..69e76b048 100644 --- a/compact/display.xml +++ b/compact/display.xml @@ -50,14 +50,14 @@ - - - + + + For shielded modules by default just display to module instead of 6 layers - + Luminosity Visualisation @@ -165,6 +165,8 @@ + + diff --git a/compact/ecal/backward_PbWO4.xml b/compact/ecal/backward_PbWO4.xml index 636440545..ad371a013 100644 --- a/compact/ecal/backward_PbWO4.xml +++ b/compact/ecal/backward_PbWO4.xml @@ -103,9 +103,9 @@ electron_rmax="73 * mm" proton_rmin="35 * mm" proton_rmax="43 * mm" - straight_section_tilt="62.05 * deg" z_length="EcalEndcapN_inner_support_length" x_offset="-1 * mm" + proton_x_offset="64 * mm" material="Copper" vis="AnlOrange" /> diff --git a/compact/ecal/barrel_interlayers.xml b/compact/ecal/bic/bic.xml similarity index 84% rename from compact/ecal/barrel_interlayers.xml rename to compact/ecal/bic/bic.xml index a305d9dec..71cd141f4 100644 --- a/compact/ecal/barrel_interlayers.xml +++ b/compact/ecal/bic/bic.xml @@ -15,7 +15,11 @@ To change the number of imaging layer slots from, e.g., 9 to 6, - change EcalBarrelImagingLayers_nMax variable + change EcalBarrelImagingLayers_nMax variable. Note that this does NOT change the + number of silicon frames, as each silicon frame and layer is placed manually. + + This file assumes the EcalBarrel_enable_staves_N variables have been defined to allow + changing the configuration by enabling/disabling staves @@ -160,7 +164,8 @@ thickness="EcalBarrel_Stave_thickness" angle="EcalBarrel_StaveTilt_angle" module="AstroPix_Module" - vis="EcalBarrelStaveVis"> + vis="EcalBarrelStaveVis" + enable="EcalBarrel_enable_staves_1"> + + + - + + + + + + + + vis="EcalBarrelStaveVis" + enable="EcalBarrel_enable_staves_4"> + + + + vis="EcalBarrelStaveVis" + enable="EcalBarrel_enable_staves_6"> + + + + + + + + + + + + + + + diff --git a/compact/ecal/bic_default.xml b/compact/ecal/bic_default.xml new file mode 100644 index 000000000..ed31ff3d7 --- /dev/null +++ b/compact/ecal/bic_default.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/compact/ecal/forward_insert_homogeneous.xml b/compact/ecal/forward_insert_homogeneous.xml index 301030816..3b950b623 100644 --- a/compact/ecal/forward_insert_homogeneous.xml +++ b/compact/ecal/forward_insert_homogeneous.xml @@ -85,6 +85,7 @@ final_hole_x="EcalEndcapPInsert_hole_xposition" initial_hole_y="EcalEndcapPInsert_hole_yposition" final_hole_y="EcalEndcapPInsert_hole_yposition" + left_right_gap="0.38*cm" /> @@ -99,7 +100,7 @@ grid_size_x="24.925*mm" grid_size_y="24.65*mm" /> - system:8,barrel:3,module:4,layer:8,slice:5,x:32:-16,y:-16 + system:8,barrel:3,module:4,layer:7,side:1,slice:5,x:32:-16,y:-16 diff --git a/compact/far_backward/beamline_extension_electron.xml b/compact/far_backward/beamline_extension_electron.xml index 9a47d3f38..e1346df24 100644 --- a/compact/far_backward/beamline_extension_electron.xml +++ b/compact/far_backward/beamline_extension_electron.xml @@ -25,7 +25,8 @@ + rout1="Q4eR_InnerRadius" rout2="Q4eR_InnerRadius" + limits="kill_limits"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:8,pipe:8,end:2 + + + + + diff --git a/compact/far_backward/extended.xml b/compact/far_backward/extended.xml index bcbb157de..dbd48fc5b 100644 --- a/compact/far_backward/extended.xml +++ b/compact/far_backward/extended.xml @@ -13,4 +13,6 @@ + + diff --git a/compact/far_forward/roman_pots_eRD24_design.xml b/compact/far_forward/roman_pots_eRD24_design.xml index f3a393c62..ea301ec34 100644 --- a/compact/far_forward/roman_pots_eRD24_design.xml +++ b/compact/far_forward/roman_pots_eRD24_design.xml @@ -5,9 +5,10 @@ --------------------------------- - Roman Pots Implementation from eRD24 RD Effort + Roman Pots Implementation updated strawman layout (only layer materials) Author: Alex Jentsch Date of first commit: June 15th, 2021 + Last update: Oct 8th, 2024 --------------------------------- @@ -21,45 +22,31 @@ - - - - - - + - - + - + + - - + + - - + + + + - - - - - - - - - - - - + - - + + @@ -88,49 +75,60 @@ reflect="false" vis="FFTrackerVis"> - + - - - + + - - + + - + - - - - - - - - - - - - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -163,7 +161,7 @@ vis="FFTrackerVis"> - + @@ -172,38 +170,50 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -232,7 +242,7 @@ - system:8,assembly:3,layer:4,module:4,sensor:4,x:32:-16,y:-16 + system:8,assembly:3,layer:4,module:8,sensor:8,x:32:-16,y:-16 diff --git a/compact/fields/beamline_10x100.xml b/compact/fields/beamline_10x100.xml index 8d9ce5c11..174e6cbea 100644 --- a/compact/fields/beamline_10x100.xml +++ b/compact/fields/beamline_10x100.xml @@ -54,4 +54,14 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + + + + + + diff --git a/compact/fields/beamline_10x110_H2.xml b/compact/fields/beamline_10x110_H2.xml index e1fbea347..47f6eee52 100644 --- a/compact/fields/beamline_10x110_H2.xml +++ b/compact/fields/beamline_10x110_H2.xml @@ -55,4 +55,16 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + Nuclei currently based on nearest per-nucleon proton energy (needs eventual update from machine). + + + + + + + diff --git a/compact/fields/beamline_10x275.xml b/compact/fields/beamline_10x275.xml index a2d0e47f0..e8a790ecb 100644 --- a/compact/fields/beamline_10x275.xml +++ b/compact/fields/beamline_10x275.xml @@ -54,4 +54,14 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + + + + + + diff --git a/compact/fields/beamline_18x110_Au.xml b/compact/fields/beamline_18x110_Au.xml index 44725ebc8..78800577e 100644 --- a/compact/fields/beamline_18x110_Au.xml +++ b/compact/fields/beamline_18x110_Au.xml @@ -55,4 +55,16 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + Nuclei currently based on nearest per-nucleon proton energy (needs eventual update from machine). + + + + + + + diff --git a/compact/fields/beamline_18x110_H2.xml b/compact/fields/beamline_18x110_H2.xml index 7ab918a99..23c5b4c90 100644 --- a/compact/fields/beamline_18x110_H2.xml +++ b/compact/fields/beamline_18x110_H2.xml @@ -55,4 +55,16 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + Nuclei currently based on nearest per-nucleon proton energy (needs eventual update from machine). + + + + + + + diff --git a/compact/fields/beamline_18x110_He3.xml b/compact/fields/beamline_18x110_He3.xml index d1bf496f1..899b830eb 100644 --- a/compact/fields/beamline_18x110_He3.xml +++ b/compact/fields/beamline_18x110_He3.xml @@ -55,4 +55,16 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + Nuclei currently based on nearest per-nucleon proton energy (needs eventual update from machine). + + + + + + + diff --git a/compact/fields/beamline_18x110_Pb.xml b/compact/fields/beamline_18x110_Pb.xml index 9801622be..eee1d8ea4 100644 --- a/compact/fields/beamline_18x110_Pb.xml +++ b/compact/fields/beamline_18x110_Pb.xml @@ -55,4 +55,16 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + Nuclei currently based on nearest per-nucleon proton energy (needs eventual update from machine). + + + + + + + diff --git a/compact/fields/beamline_18x275.xml b/compact/fields/beamline_18x275.xml index 713ae0b2b..3e1f2c634 100644 --- a/compact/fields/beamline_18x275.xml +++ b/compact/fields/beamline_18x275.xml @@ -55,4 +55,15 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + + + + + + + diff --git a/compact/fields/beamline_5x100.xml b/compact/fields/beamline_5x100.xml index 9d8624b6e..0a35ef845 100644 --- a/compact/fields/beamline_5x100.xml +++ b/compact/fields/beamline_5x100.xml @@ -54,4 +54,14 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + + + + + + diff --git a/compact/fields/beamline_5x110_H2.xml b/compact/fields/beamline_5x110_H2.xml index 7a65b2ee3..7669f7f11 100644 --- a/compact/fields/beamline_5x110_H2.xml +++ b/compact/fields/beamline_5x110_H2.xml @@ -55,4 +55,16 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + Nuclei currently based on nearest per-nucleon proton energy (needs eventual update from machine). + + + + + + + diff --git a/compact/fields/beamline_5x41.xml b/compact/fields/beamline_5x41.xml index ca787e71b..1b8a4f0d1 100644 --- a/compact/fields/beamline_5x41.xml +++ b/compact/fields/beamline_5x41.xml @@ -54,4 +54,14 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + + + + + + diff --git a/compact/fields/beamline_5x41_H2.xml b/compact/fields/beamline_5x41_H2.xml index f38e05f7e..101fb0ac4 100644 --- a/compact/fields/beamline_5x41_H2.xml +++ b/compact/fields/beamline_5x41_H2.xml @@ -3,7 +3,7 @@ - + @@ -55,4 +55,16 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + Nuclei currently based on nearest per-nucleon proton energy (needs eventual update from machine). + + + + + + + diff --git a/compact/fields/beamline_5x41_He3.xml b/compact/fields/beamline_5x41_He3.xml index d474b021f..b7ada8161 100644 --- a/compact/fields/beamline_5x41_He3.xml +++ b/compact/fields/beamline_5x41_He3.xml @@ -55,4 +55,16 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + Nuclei currently based on nearest per-nucleon proton energy (needs eventual update from machine). + + + + + + + diff --git a/compact/fields/beamline_5x41_He4.xml b/compact/fields/beamline_5x41_He4.xml index 1a2561621..21e8abf83 100644 --- a/compact/fields/beamline_5x41_He4.xml +++ b/compact/fields/beamline_5x41_He4.xml @@ -55,4 +55,16 @@ + + These are the ten-sigma cuts for the Roman pots, translated to the physical layout we currently have. + They are not perfectly ten-sigma for reasons of physical geometry. + + Nuclei currently based on nearest per-nucleon proton energy (needs eventual update from machine). + + + + + + + diff --git a/compact/hcal/backward.xml b/compact/hcal/backward.xml index 2df2373cd..5f23ab662 100644 --- a/compact/hcal/backward.xml +++ b/compact/hcal/backward.xml @@ -20,7 +20,7 @@ + value="HcalEndcapNSteelThickness + HcalEndcapNPolystyreneThickness + HcalEndcapNLayerGap"/> diff --git a/compact/hcal/forward_insert.xml b/compact/hcal/forward_insert.xml index 1c8037d44..05bde6e18 100644 --- a/compact/hcal/forward_insert.xml +++ b/compact/hcal/forward_insert.xml @@ -23,6 +23,24 @@ + + #### Cell Sizes + + + + + + #### Transverse offsets of cells + + + + + + + + + + - Insert N Layers and computed Thickness @@ -49,8 +67,7 @@ HcalEndcapPInsertAirThickness " /> - - + @@ -58,7 +75,7 @@ ### Forward (Positive Z) Endcap Insert for Hadronic Calorimeter Insert goes in the middle of the forward endcap HCal -- around the beampipe - Insert is 1 front layer of Steel/Sc, 10 layers of W/Sc, 54 layers of Steel/Sc + 1 backplate of steel + Insert is 60 layers of Steel/Sc + 1 backplate of steel Each of the layers (sans backplate) includes air gaps (front and back of each layer), ESR foil (front and back of scintillator), a PCB, and an aluminum scitnillator cover @@ -74,6 +91,7 @@ vis="HcalEndcapInsertVis" readout="HcalEndcapPInsertHits" calorimeterType="HAD_ENDCAP" + left_right_gap="0.38*cm" > - Front layer to match front walls of LFHCAL modules - Slices will be ordered according to the slice order listed here - - - - - - - - - - - Tungsten/Scintillator layers - - - - - - - - - - Steel/Sc layers @@ -140,21 +135,61 @@ - Readout is segmented into hexagons with sides of 1.889 cm - The hexagons positions cycle through four sets of layer configurations ("H4 staggering") + Readout is segmented into hexagons with sides of 2.16 cm, 2.84 cm, and 3.10 cm in the high-granularity upstream section (layers 1-16, for both left and right sides), + the left downstream section (layers 17-60), and the right downstream section (layers 17-60), respectively. + The hexagons positions in the first 16 layers cycle through four sets of layer configurations ("H4 staggering") i.e. hexagons in layers 1-4 (5-8, ...) are all offset transversely from each other with the centers of the cells of one layer being at the midpoints of the edges of the cells in - the other layers + the other layers. + Staggering defined in https://github.com/AIDASoft/DD4hep/blob/1962f7d1ace4484efb8886d66a6759a83c5107a3/DDCore/include/DDSegmentation/HexGrid.h#L112-L114 and https://github.com/AIDASoft/DD4hep/blob/1962f7d1ace4484efb8886d66a6759a83c5107a3/DDCore/src/segmentations/HexGrid.cpp#L102-L120 - - system:8,layer:8,slice:8,x:32:-16,y:-16 + + + + + + + + + + + + system:8,side:1,layer:8,slice:7,x:32:-16,y:-16 diff --git a/compact/hcal/lfhcal.xml b/compact/hcal/lfhcal.xml index 3a903e6c7..8e794258e 100644 --- a/compact/hcal/lfhcal.xml +++ b/compact/hcal/lfhcal.xml @@ -22,30 +22,32 @@ FIXME: Need actual values once they are decided upon + - + + - + - + - - + + - - + + @@ -108,6 +110,7 @@ heightBackInner="EightM_BackInnerHeight" widthSideWall="Mod_SideWallThickness" widthTopWall="Mod_TopWallThickness" + thicknessMountingPlate="Mod_MountingPlateThickness" thicknessFrontWall="Mod_FrontWallThickness" thicknessBackWall="Mod_BackWallThickness" arrayX="EightM_xArr" @@ -129,6 +132,7 @@ heightBackInner="FourM_BackInnerHeight" widthSideWall="Mod_SideWallThickness" widthTopWall="Mod_TopWallThickness" + thicknessMountingPlate="Mod_MountingPlateThickness" thicknessFrontWall="Mod_FrontWallThickness" thicknessBackWall="Mod_BackWallThickness" arrayX="FourM_xArr" @@ -142,1234 +146,1192 @@ /> - - - + - - - - - - - - + + + + - - + + - - + + - - + + - - + + - - - - - + + ### for testing of a single module - + + + --> + ### positions of modules for full area LFHCAL (sorted by ascending r, x, y) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compact/materials.xml b/compact/materials.xml index 95ee8d1a5..fbefb0638 100644 --- a/compact/materials.xml +++ b/compact/materials.xml @@ -338,7 +338,7 @@ - + diff --git a/compact/pid/pfrich.xml b/compact/pid/pfrich.xml index cf5d085ae..3652d0c46 100644 --- a/compact/pid/pfrich.xml +++ b/compact/pid/pfrich.xml @@ -38,6 +38,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -47,9 +98,9 @@ name="RICHEndcapN" type="epic_PFRICH" readout="RICHEndcapNHits" - gas="C4F10_PFRICH" - material="Aluminum" - vis_vessel="DRICH_vessel_vis" + gas="N2cherenkov" + material="CarbonFiber" + vis_vessel="PFRICH_vessel_vis" vis_gas="DRICH_gas_vis" > @@ -78,6 +129,10 @@ side="PFRICH_sensor_sensitive_size" thickness="PFRICH_sensor_thickness" gap="0.2*mm" + windowmat="Quartz" + pcbmat="G10" + mpdmat="SiliconDioxide" + asicmat="SiliconCarbide" /> going from back to front - + - + - + - + - + - + @@ -1161,22 +1161,22 @@ total X0 0.24% per disk layer (4 sectors per disk): going from back to front - + - + - + - + - + - + @@ -1195,22 +1195,22 @@ total X0 0.24% per disk layer (4 sectors per disk): going from back to front - + - + - + - + - + - + @@ -1309,22 +1309,22 @@ total X0 0.24% per disk layer (4 sectors per disk): going from back to front - + - + - + - + - + - + diff --git a/compact/tracking/definitions_craterlake.xml b/compact/tracking/definitions_craterlake.xml index 1ad650f24..3963c0ec5 100644 --- a/compact/tracking/definitions_craterlake.xml +++ b/compact/tracking/definitions_craterlake.xml @@ -41,15 +41,18 @@ Main parameters for Barrel TOF layers Barrel TOF region - - + + + + + Forward TOF region - - + + @@ -197,7 +200,7 @@ - + diff --git a/compact/tracking/deprecated/gem_tracker_endcap.xml b/compact/tracking/deprecated/gem_tracker_endcap.xml index 71df2d13e..f3a0b1e96 100644 --- a/compact/tracking/deprecated/gem_tracker_endcap.xml +++ b/compact/tracking/deprecated/gem_tracker_endcap.xml @@ -113,22 +113,22 @@ Going from HV side to readout side - + - + - + - + - + - + @@ -177,22 +177,22 @@ Going from HV side to readout side - + - + - + - + - + - + diff --git a/compact/tracking/mpgd_backward_endcap.xml b/compact/tracking/mpgd_backward_endcap.xml index 0d4f8c99b..37f34975e 100644 --- a/compact/tracking/mpgd_backward_endcap.xml +++ b/compact/tracking/mpgd_backward_endcap.xml @@ -62,7 +62,7 @@ - + Window and drift region - - + + HV Cathode @@ -94,8 +94,8 @@ Window and drift region - - + + HV Cathode diff --git a/compact/tracking/mpgd_barrel.xml b/compact/tracking/mpgd_barrel.xml index 8f163b37d..903fa7735 100644 --- a/compact/tracking/mpgd_barrel.xml +++ b/compact/tracking/mpgd_barrel.xml @@ -1,5 +1,5 @@ - + @@ -21,70 +21,91 @@ - - - + Intrinsic parameters... + ...Thicknesses - - + + - FIXME: No support material is here, so fudge factor used to bring material budget to ~0.5% for barrel - + + FIXME: No definite plan for connections/services to the inner sectors yet, so guess value + + ...Dimensions + + + + + + + ...Positioning + + - - - Extra parameters to approximate a cylinder as a set of skinny staves - due to ACTS limitations. - FIXME: this shouldn't be needed anymore, need to update the cylindrical plugin. - - - + In principle, stave count should not be independenty specified: it is fixed by above intrinsic parameters + + + + + + - - + insideTrackingVolume="true" + vis="TrackerVis"> + + + + + Models describe the overlapping of staves along phi, either (I) via offsets or (II) via distinct radii ("rmin1/2"). Solution (II) is only partially implemented: would require FOUR distinct "radius" in the readout segmentation. Note that in any case "rsensor" must be set equal the "radius" of the corresponding segmentation and is used internally to double-check the consistency between the stack of "module_component" and the segmentation "radius". + + + + + This includes cables => Kapton as a material is overoptimistic. Going from the inside (sensitive) side to the readout side - - - - - - - - - - - - - + + + + + + + + + + + + + - + + - - - - + + + + @@ -98,8 +119,16 @@ - - system:8,layer:4,module:12,sensor:2,x:32:-14,y:-18 + 768 strips in phi yield a segmentation of 2pi/8/768 ~= 1mrad. Which in turn, yields ~160 um in resolution. + + + In preparation for a 2-sensors-w/-strip setup. Presently sensors w/ odd key values do not exist. + + + + + + system:8,layer:4,module:12,sensor:2,phi:32:-16,z:-16 diff --git a/compact/tracking/mpgd_forward_endcap.xml b/compact/tracking/mpgd_forward_endcap.xml index afd5b0cf2..f36b0fd67 100644 --- a/compact/tracking/mpgd_forward_endcap.xml +++ b/compact/tracking/mpgd_forward_endcap.xml @@ -75,8 +75,8 @@ Window and drift region - - + + HV Cathode @@ -93,8 +93,8 @@ Window and drift region - - + + HV Cathode diff --git a/compact/tracking/mpgd_innerbarrel.xml b/compact/tracking/mpgd_innerbarrel.xml deleted file mode 100644 index 24c081e0f..000000000 --- a/compact/tracking/mpgd_innerbarrel.xml +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - - - Inner MPGD tracking layer(s) - - Note: the inner and outer layers are implemented as separate detectors, as they - belong to different ACTS tracking volumes. If this restriction goes away - in the future they could be put together in a single tag. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FIXME: No support material is here, so fudge factor used to bring material budget to ~1% for barrel - - - - - Extra parameters to approximate a cylinder as a set of skinny staves - due to ACTS limitations. - FIXME: this shouldn't be needed anymore, need to update the cylindrical plugin. - - - - - - - - - - - - Central Barrel modules - - - - - - - - - - - - - - - - - Layers composed of many arrayed modules - - - - - - - - - - - - - - - - - - - - - - - Layers composed of many arrayed modules - - - - - - - - - - - - - - - - - - - - - - - Layers composed of many arrayed modules - - - - - - - - - - - - - - - - - - - - system:8,layer:3,module:12,sensor:2,x:32:-14,y:-18 - - - - diff --git a/compact/tracking/mpgd_outerbarrel.xml b/compact/tracking/mpgd_outerbarrel.xml index c4e69c044..f838e8e8f 100644 --- a/compact/tracking/mpgd_outerbarrel.xml +++ b/compact/tracking/mpgd_outerbarrel.xml @@ -59,7 +59,7 @@ Layout for MPGD DIRC layers - + - - - - + + + + + + + + + + + + + + + @@ -82,52 +93,104 @@ insideTrackingVolume="true"> + rmin="BarrelTOF_rmin - 1*mm" + rmax="BarrelTOF_rmax + 1*mm" + length="BarrelTOF_length" + /> Tracker Barrel Modules - - + + keep_layer means the next module is located at the same thickness level + so you can place component side by side + Just make sure all components you placed side by side share the same thickness + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + - - + + + + - - + + + + - - + + + + - - + + + - - + + - - + + + - - + + + + + + + + + + - + + @@ -140,8 +203,8 @@ - - system:8,layer:4,module:12,sensor:2,x:32:-16,y:-16 + + system:8,layer:4,module:12,sensor:10,x:40:-8,y:-16 diff --git a/compact/tracking/tof_endcap.xml b/compact/tracking/tof_endcap.xml index e0c78530b..ebec385ff 100644 --- a/compact/tracking/tof_endcap.xml +++ b/compact/tracking/tof_endcap.xml @@ -107,7 +107,7 @@ 1 um padding to not have layer and module touch (ACTS requirement) - + @@ -122,8 +122,8 @@ - - + + @@ -133,19 +133,25 @@ - - - - - - - + + + + + + + + + + + - + + + @@ -155,12 +161,14 @@ - + + - + + @@ -205,7 +213,7 @@ reflect="false"> - + @@ -218,19 +226,99 @@ - - + + + + + + + + + + + - + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -244,13 +332,16 @@ - + + + zstart="ForwardTOF_zmin" + xoffset="EndcapTOF_Module_length_design/2" + /> @@ -261,13 +352,300 @@ rmin="ForwardTOFLayer_rmin" rmax="ForwardTOFLayer_rmax" length="12*mm" - zstart="ForwardTOF_zmin" /> + zstart="ForwardTOF_zmin" + xoffset="EndcapTOF_Module_length_design/2" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + spacing="EndcapTOF_Module_spacing" + board_gap="EndcapTOF_Board_spacing" /> @@ -280,8 +658,8 @@ - - system:8,layer:4,module:8,idx:7,idy:5,x:32:-16,y:-16 + + system:8,layer:4,module:2,idx:5,idy:5,ids:6,x:36:-12,y:-16 diff --git a/compact/unused/mrich_alt.xml b/compact/unused/mrich_alt.xml deleted file mode 100644 index 792c3cf78..000000000 --- a/compact/unused/mrich_alt.xml +++ /dev/null @@ -1,115 +0,0 @@ - - - - - MRICH (alternative design) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - system:8,module:14,sensor:8,x:32:-16,y:-16 - - - - - - - - diff --git a/configurations/backward_hcal_only.yml b/configurations/backward_hcal_only.yml new file mode 100644 index 000000000..af9406eab --- /dev/null +++ b/configurations/backward_hcal_only.yml @@ -0,0 +1,6 @@ +features: + fields: + marco: + hcal: + backward: + backward_endcap_flux: diff --git a/configurations/bhcal.yml b/configurations/bhcal.yml index 56f290907..991a3576f 100644 --- a/configurations/bhcal.yml +++ b/configurations/bhcal.yml @@ -1,5 +1,6 @@ features: - solenoid: beampipe: + fields: + marco: hcal: barrel_gdml: diff --git a/configurations/calorimeters.yml b/configurations/calorimeters.yml index 542f38c2c..f02337758 100644 --- a/configurations/calorimeters.yml +++ b/configurations/calorimeters.yml @@ -4,7 +4,7 @@ features: ecal: forward_homogeneous: forward_insert_homogeneous: - barrel_interlayers: + bic_default: backward_PbWO4: hcal: lfhcal_with_space_for_insert: diff --git a/configurations/craterlake.yml b/configurations/craterlake.yml index 2b9b241d1..c31cb1318 100644 --- a/configurations/craterlake.yml +++ b/configurations/craterlake.yml @@ -21,7 +21,7 @@ features: ecal: forward_homogeneous: forward_insert_homogeneous: - barrel_interlayers: + bic_default: backward_PbWO4: solenoid: hcal: diff --git a/configurations/craterlake_10x100.yml b/configurations/craterlake_10x100.yml index 39bfe43ad..3e6f1ec6e 100644 --- a/configurations/craterlake_10x100.yml +++ b/configurations/craterlake_10x100.yml @@ -21,7 +21,7 @@ features: ecal: forward_homogeneous: forward_insert_homogeneous: - barrel_interlayers: + bic_default: backward_PbWO4: solenoid: hcal: diff --git a/configurations/craterlake_10x275.yml b/configurations/craterlake_10x275.yml index c645a6926..021150e71 100644 --- a/configurations/craterlake_10x275.yml +++ b/configurations/craterlake_10x275.yml @@ -21,7 +21,7 @@ features: ecal: forward_homogeneous: forward_insert_homogeneous: - barrel_interlayers: + bic_default: backward_PbWO4: solenoid: hcal: diff --git a/configurations/craterlake_18x110_Au.yml b/configurations/craterlake_18x110_Au.yml index e9736a234..55963a6fe 100644 --- a/configurations/craterlake_18x110_Au.yml +++ b/configurations/craterlake_18x110_Au.yml @@ -21,7 +21,7 @@ features: ecal: forward_homogeneous: forward_insert_homogeneous: - barrel_interlayers: + bic_default: backward_PbWO4: solenoid: hcal: diff --git a/configurations/craterlake_18x275.yml b/configurations/craterlake_18x275.yml index 7f0972f1d..b1fe4981e 100644 --- a/configurations/craterlake_18x275.yml +++ b/configurations/craterlake_18x275.yml @@ -21,7 +21,7 @@ features: ecal: forward_homogeneous: forward_insert_homogeneous: - barrel_interlayers: + bic_default: backward_PbWO4: solenoid: hcal: diff --git a/configurations/craterlake_5x100.yml b/configurations/craterlake_5x100.yml new file mode 100644 index 000000000..25b7b6c1e --- /dev/null +++ b/configurations/craterlake_5x100.yml @@ -0,0 +1,38 @@ +ebeam: 5 +pbeam: 100 +features: + beampipe: + tracking: + definitions_craterlake: + vertex_barrel: + silicon_barrel: + mpgd_barrel: + support_service_craterlake: + mpgd_outerbarrel: + mpgd_forward_endcap: + mpgd_backward_endcap: + silicon_disks: + tof_barrel: + tof_endcap: + pid: + dirc: + pfrich: + drich: + ecal: + forward_homogeneous: + forward_insert_homogeneous: + bic_default: + backward_PbWO4: + solenoid: + hcal: + lfhcal_with_space_for_insert: + forward_insert: + barrel_gdml: + barrel_flux_return: + forward_endcap_flux: + backward: + backward_endcap_flux: + far_forward: + default: + far_backward: + default: diff --git a/configurations/craterlake_5x41.yml b/configurations/craterlake_5x41.yml index 050c73b00..ef920a70d 100644 --- a/configurations/craterlake_5x41.yml +++ b/configurations/craterlake_5x41.yml @@ -21,7 +21,7 @@ features: ecal: forward_homogeneous: forward_insert_homogeneous: - barrel_interlayers: + bic_default: backward_PbWO4: solenoid: hcal: diff --git a/configurations/craterlake_bic_6layers.yml b/configurations/craterlake_bic_6layers.yml new file mode 100644 index 000000000..45cd342d6 --- /dev/null +++ b/configurations/craterlake_bic_6layers.yml @@ -0,0 +1,38 @@ +ebeam: 10 +pbeam: 100 +features: + beampipe: + tracking: + definitions_craterlake: + vertex_barrel: + silicon_barrel: + mpgd_barrel: + support_service_craterlake: + mpgd_outerbarrel: + mpgd_forward_endcap: + mpgd_backward_endcap: + silicon_disks: + tof_barrel: + tof_endcap: + pid: + dirc: + pfrich: + drich: + ecal: + forward_homogeneous: + forward_insert_homogeneous: + bic_6layers: + backward_PbWO4: + solenoid: + hcal: + lfhcal_with_space_for_insert: + forward_insert: + barrel_gdml: + barrel_flux_return: + forward_endcap_flux: + backward: + backward_endcap_flux: + far_forward: + default: + far_backward: + default: diff --git a/configurations/craterlake_no_bhcal.yml b/configurations/craterlake_no_bhcal.yml index 94223d402..889884c89 100644 --- a/configurations/craterlake_no_bhcal.yml +++ b/configurations/craterlake_no_bhcal.yml @@ -21,7 +21,7 @@ features: ecal: forward_homogeneous: forward_insert_homogeneous: - barrel_interlayers: + bic_default: backward_PbWO4: solenoid: hcal: diff --git a/configurations/craterlake_no_zdc_lyso.yml b/configurations/craterlake_no_zdc_lyso.yml new file mode 100644 index 000000000..4f24db21c --- /dev/null +++ b/configurations/craterlake_no_zdc_lyso.yml @@ -0,0 +1,47 @@ +ebeam: 5 +pbeam: 41 +features: + beampipe: + tracking: + definitions_craterlake: + vertex_barrel: + silicon_barrel: + mpgd_barrel: + support_service_craterlake: + mpgd_outerbarrel: + mpgd_forward_endcap: + mpgd_backward_endcap: + silicon_disks: + tof_barrel: + tof_endcap: + pid: + dirc: + pfrich: + drich: + ecal: + forward_homogeneous: + forward_insert_homogeneous: + bic_default: + backward_PbWO4: + solenoid: + hcal: + lfhcal_with_space_for_insert: + forward_insert: + barrel_gdml: + barrel_flux_return: + forward_endcap_flux: + backward: + backward_endcap_flux: + far_forward: + ion_beamline: + beampipe_hadron_B0: + electron_beamline: + B0_tracker: + B0_ECal: + offM_tracker: + ZDC_SiPMonTile: + roman_pots_eRD24_design: + vacuum: + magnets: + far_backward: + default: diff --git a/configurations/craterlake_tracking_only.yml b/configurations/craterlake_tracking_only.yml index bf942cca6..f7291b991 100644 --- a/configurations/craterlake_tracking_only.yml +++ b/configurations/craterlake_tracking_only.yml @@ -1,7 +1,7 @@ features: + beampipe: fields: marco: - beampipe: tracking: definitions_craterlake: vertex_barrel: @@ -16,3 +16,5 @@ features: tof_endcap: far_forward: default: + far_backward: + default: diff --git a/configurations/eeemcal_only.yml b/configurations/eeemcal_only.yml index 1e0a3ef80..0da281326 100644 --- a/configurations/eeemcal_only.yml +++ b/configurations/eeemcal_only.yml @@ -1,7 +1,5 @@ features: - # beampipe: - tracking: - definitions_craterlake: - support_service_craterlake: + fields: + marco: ecal: backward_PbWO4: diff --git a/configurations/forward_detectors.yml b/configurations/forward_detectors.yml index 31f32e017..eedc65bf2 100644 --- a/configurations/forward_detectors.yml +++ b/configurations/forward_detectors.yml @@ -1,5 +1,7 @@ features: beampipe: + fields: + marco: tracking: definitions_craterlake: vertex_barrel: diff --git a/configurations/forward_detectors_with_inserts.yml b/configurations/forward_detectors_with_inserts.yml index fadbb50a8..61edc648d 100644 --- a/configurations/forward_detectors_with_inserts.yml +++ b/configurations/forward_detectors_with_inserts.yml @@ -1,5 +1,7 @@ features: beampipe: + fields: + marco: tracking: definitions_craterlake: vertex_barrel: diff --git a/configurations/full.yml b/configurations/full.yml index 050c73b00..ef920a70d 100644 --- a/configurations/full.yml +++ b/configurations/full.yml @@ -21,7 +21,7 @@ features: ecal: forward_homogeneous: forward_insert_homogeneous: - barrel_interlayers: + bic_default: backward_PbWO4: solenoid: hcal: diff --git a/configurations/imaging_only.yml b/configurations/imaging_only.yml index 294aaea59..e7f10e26b 100644 --- a/configurations/imaging_only.yml +++ b/configurations/imaging_only.yml @@ -2,4 +2,4 @@ features: fields: marco: ecal: - barrel_interlayers: + bic_default: diff --git a/configurations/inner_detector.yml b/configurations/inner_detector.yml index 12ce0efd0..1f8281e04 100644 --- a/configurations/inner_detector.yml +++ b/configurations/inner_detector.yml @@ -1,5 +1,7 @@ features: beampipe: + fields: + marco: tracking: definitions_craterlake: vertex_barrel: @@ -13,7 +15,8 @@ features: tof_barrel: tof_endcap: ecal: - barrel_interlayers: + forward_homogeneous: + bic_default: backward_PbWO4: pid: dirc: diff --git a/configurations/lfhcal_only.yml b/configurations/lfhcal_only.yml index b8ebe1122..f5b7de3b7 100644 --- a/configurations/lfhcal_only.yml +++ b/configurations/lfhcal_only.yml @@ -1,3 +1,5 @@ features: + fields: + marco: hcal: lfhcal_without_space_for_insert: diff --git a/configurations/lfhcal_with_insert.yml b/configurations/lfhcal_with_insert.yml index 3cff4476f..2c166dbdc 100644 --- a/configurations/lfhcal_with_insert.yml +++ b/configurations/lfhcal_with_insert.yml @@ -1,4 +1,7 @@ features: + fields: + marco: hcal: lfhcal_with_space_for_insert: forward_insert: + forward_endcap_flux: diff --git a/configurations/mrich_only.yml b/configurations/mrich_only.yml deleted file mode 100644 index 3f03d2f63..000000000 --- a/configurations/mrich_only.yml +++ /dev/null @@ -1,5 +0,0 @@ -features: - fields: - marco: - pid: - mrich: diff --git a/scripts/material_map/run_material_map_validation.sh b/scripts/material_map/run_material_map_validation.sh index 3daafd1bd..e964ed00f 100755 --- a/scripts/material_map/run_material_map_validation.sh +++ b/scripts/material_map/run_material_map_validation.sh @@ -11,7 +11,7 @@ if [[ -z ${DETECTOR_PATH} || -z ${DETECTOR_CONFIG} ]] ; then fi # Download required Acts files -ACTS_VERSION="682d2080d36712ac15975340c92f860b25169213" +ACTS_VERSION="00591a593a648430820e980b031301d25c18f1c7" # v33.1.0 ACTS_URL="https://github.com/acts-project/acts/raw/" ACTS_FILES=( "Examples/Scripts/Python/geometry.py" @@ -35,6 +35,20 @@ for file in ${ACTS_FILES[@]} ; do done export PYTHONPATH=$PWD/Examples/Scripts/Python:$PYTHONPATH +# FIXME +# Disable ACTS FpeMonitor due to unexplained FPEINV in RootMaterialTrackReader +# FPE summary for Reader: RootMaterialTrackReader +# FLTINV: (2 times) +# 0# Acts::MaterialSlab::MaterialSlab(Acts::Material const&, float) in /opt/local/python/acts/../../lib/libActsCore.so +# 1# ActsExamples::RootMaterialTrackReader::read(ActsExamples::AlgorithmContext const&) in /opt/local/python/acts/../../lib/libActsExamplesIoRoot.so +# 2# ActsExamples::Sequencer::run()::$_0::operator()() const::{lambda(tbb::blocked_range const&)#1}::operator()(tbb::blocked_range const&) const in /opt/local/python/acts/../../lib/libActsExamplesFramework.so +# 3# ActsExamples::Sequencer::run()::$_0::operator()() const in /opt/local/python/acts/../../lib/libActsExamplesFramework.so +# 4# ActsExamples::Sequencer::run() in /opt/local/python/acts/../../lib/libActsExamplesFramework.so +# 5# 0x000070B51DE55640 in /opt/local/python/acts/ActsPythonBindings.cpython-310-x86_64-linux-gnu.so +# 6# 0x000070B51DE49ACD in /opt/local/python/acts/ActsPythonBindings.cpython-310-x86_64-linux-gnu.so +# 7# cfunction_call at Objects/methodobject.c:543 +export ACTS_SEQUENCER_DISABLE_FPEMON=1 + # Default arguments nevents=1000 nparticles=1000 diff --git a/src/BarrelCalorimeterImaging_geo.cpp b/src/BarrelCalorimeterImaging_geo.cpp index 93bb7c737..66753a981 100644 --- a/src/BarrelCalorimeterImaging_geo.cpp +++ b/src/BarrelCalorimeterImaging_geo.cpp @@ -227,10 +227,18 @@ static Ref_t create_detector(Detector& desc, xml_h e, SensitiveDetector sens) { // Set region, limitset, and vis of layer. layer_volume.setAttributes(desc, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr()); - // Loop over the staves for this layer. + // Loop over the staves for this layer, if the tray is enabled int stave_num = 1; for (xml_coll_t i_stave(x_layer, _U(stave)); i_stave; ++i_stave) { xml_comp_t x_stave = i_stave; + // Check if we enabled this silicon tray (actual silicon detector in the slots) at the top level + // allowing us to easily disable layers in the XML file without needing multiple + // copies of the XML file + if (getAttrOrDefault(x_stave, _Unicode(enable), 1) == 0) { + // disabled + continue; + } + int stave_repeat = x_stave.repeat(); double stave_thick = x_stave.thickness(); double stave_dim_x = x_stave.width() / 2.0; @@ -361,7 +369,7 @@ static Ref_t create_detector(Detector& desc, xml_h e, SensitiveDetector sens) { } } - // Place frame + // Place frame if defined. if (layer_has_frame) { xml_comp_t x_frame = x_layer.child(_Unicode(frame)); double frame_height = x_frame.height(); diff --git a/src/BarrelTOFTracker_geo.cpp b/src/BarrelTOFTracker_geo.cpp new file mode 100644 index 000000000..6598bc961 --- /dev/null +++ b/src/BarrelTOFTracker_geo.cpp @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2022 - 2024, Whitney Armstrong, Chun Yuen Tsang + +/** \addtogroup Trackers Trackers + * \brief Type: **TOFBarrel**. + * \author W. Armstrong + * \modified by C.Y Tsang 3rd Aug, 2024 + * + * \ingroup trackers + * + * @{ + */ +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" +#include "DD4hep/Shapes.h" +#include "DDRec/DetectorData.h" +#include "DDRec/Surface.h" +#include "XML/Layering.h" +#include "XML/Utilities.h" +#include +#include +#include "DD4hepDetectorHelper.h" + +using namespace std; +using namespace dd4hep; +using namespace dd4hep::rec; +using namespace dd4hep::detail; + +/** Barrel Tracker with space frame. + * + * - Optional "support" tag within the detector element. + * + * The shapes are created using createShape which can be one of many basic geomtries. + * See the examples Check_shape_*.xml in + * [dd4hep's examples/ClientTests/compact](https://github.com/AIDASoft/DD4hep/tree/master/examples/ClientTests/compact) + * directory. + * + * + * - Optional "frame" tag within the module element. + * + * \ingroup trackers + * + * \code + * \endcode + * + * + * @author Whitney Armstrong + */ +static Ref_t create_TOFBarrel(Detector& description, xml_h e, SensitiveDetector sens) { + typedef vector Placements; + xml_det_t x_det = e; + Material air = description.air(); + int det_id = x_det.id(); + string det_name = x_det.nameStr(); + DetElement sdet(det_name, det_id); + + map volumes; + map sensitives; + map> volplane_surfaces; + map> module_thicknesses; + + PlacedVolume pv; + + // Set detector type flag + dd4hep::xml::setDetectorTypeFlag(x_det, sdet); + auto& params = DD4hepDetectorHelper::ensureExtension(sdet); + + // Add the volume boundary material if configured + for (xml_coll_t bmat(x_det, _Unicode(boundary_material)); bmat; ++bmat) { + xml_comp_t x_boundary_material = bmat; + DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_boundary_material, params, + "boundary_material"); + } + + // dd4hep::xml::Dimension dimensions(x_det.dimensions()); + // Tube topVolumeShape(dimensions.rmin(), dimensions.rmax(), dimensions.length() * 0.5); + // Volume assembly(det_name,topVolumeShape,air); + Assembly assembly(det_name); + + sens.setType("tracker"); + + // Loop over the suports + for (xml_coll_t su(x_det, _U(support)); su; ++su) { + xml_comp_t x_support = su; + double support_thickness = getAttrOrDefault(x_support, _U(thickness), 2.0 * mm); + double support_length = getAttrOrDefault(x_support, _U(length), 2.0 * mm); + double support_rmin = getAttrOrDefault(x_support, _U(rmin), 2.0 * mm); + double support_zstart = getAttrOrDefault(x_support, _U(zstart), 2.0 * mm); + std::string support_name = + getAttrOrDefault(x_support, _Unicode(name), "support_tube"); + std::string support_vis = getAttrOrDefault(x_support, _Unicode(vis), "AnlRed"); + xml_dim_t pos(x_support.child(_U(position), false)); + xml_dim_t rot(x_support.child(_U(rotation), false)); + Solid support_solid; + if (x_support.hasChild(_U(shape))) { + xml_comp_t shape(x_support.child(_U(shape))); + string shape_type = shape.typeStr(); + support_solid = xml::createShape(description, shape_type, shape); + } else { + support_solid = Tube(support_rmin, support_rmin + support_thickness, support_length / 2); + } + Transform3D tr = + Transform3D(Rotation3D(), Position(0, 0, (support_zstart + support_length / 2))); + if (pos.ptr() && rot.ptr()) { + Rotation3D rot3D(RotationZYX(rot.z(0), rot.y(0), rot.x(0))); + Position pos3D(pos.x(0), pos.y(0), pos.z(0)); + tr = Transform3D(rot3D, pos3D); + } else if (pos.ptr()) { + tr = Transform3D(Rotation3D(), Position(pos.x(0), pos.y(0), pos.z(0))); + } else if (rot.ptr()) { + Rotation3D rot3D(RotationZYX(rot.z(0), rot.y(0), rot.x(0))); + tr = Transform3D(rot3D, Position()); + } + Material support_mat = description.material(x_support.materialStr()); + Volume support_vol(support_name, support_solid, support_mat); + support_vol.setVisAttributes(description.visAttributes(support_vis)); + pv = assembly.placeVolume(support_vol, tr); + // pv = assembly.placeVolume(support_vol, Position(0, 0, support_zstart + support_length / 2)); + } + + // loop over the modules + for (xml_coll_t mi(x_det, _U(module)); mi; ++mi) { + xml_comp_t x_mod = mi; + string m_nam = x_mod.nameStr(); + + if (volumes.find(m_nam) != volumes.end()) { + printout(ERROR, "TOFBarrel", + string((string("Module with named ") + m_nam + string(" already exists."))).c_str()); + throw runtime_error("Logics error in building modules."); + } + + int ncomponents = 0; + int sensor_number = 1; + double total_thickness = 0; + + // Compute module total thickness from components + xml_coll_t ci(x_mod, _U(module_component)); + for (ci.reset(), total_thickness = 0.0; ci; ++ci) { + if (!getAttrOrDefault(xml_comp_t(ci), _Unicode(keep_layer), false)) + total_thickness += xml_comp_t(ci).thickness(); + } + // the module assembly volume + Assembly m_vol(m_nam); + volumes[m_nam] = m_vol; + m_vol.setVisAttributes(description.visAttributes(x_mod.visStr())); + + // Optional module frame. + if (x_mod.hasChild(_U(frame))) { + xml_comp_t m_frame = x_mod.child(_U(frame)); + // xmleles[m_nam] = x_mod; + double frame_thickness = m_frame.thickness(); + double frame_width = m_frame.width(); + double frame_height = getAttrOrDefault(m_frame, _U(height), 5.0 * mm); + double tanth = frame_height / (frame_width / 2.0); + double costh = 1. / sqrt(1 + tanth * tanth); + double frame_height2 = frame_height - frame_thickness - frame_thickness / costh; + double frame_width2 = 2.0 * frame_height2 / tanth; + + Trd1 moduleframe_part1(frame_width / 2, 0.001 * mm, m_frame.length() / 2, frame_height / 2); + Trd1 moduleframe_part2(frame_width2 / 2, 0.001 * mm, m_frame.length() / 2 + 0.01 * mm, + frame_height2 / 2); + + SubtractionSolid moduleframe(moduleframe_part1, moduleframe_part2, + Position(0.0, frame_thickness, 0.0)); + Volume v_moduleframe(m_nam + "_vol", moduleframe, + description.material(m_frame.materialStr())); + v_moduleframe.setVisAttributes(description, m_frame.visStr()); + m_vol.placeVolume(v_moduleframe, + Position(0.0, 0.0, frame_height / 2 + total_thickness / 2.0)); + } + + double thickness_so_far = 0.0; + double thickness_sum = -total_thickness / 2.0; + for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci) { + xml_comp_t x_comp = mci; + xml_comp_t x_pos = x_comp.position(false); + xml_comp_t x_rot = x_comp.rotation(false); + auto make_box = [&](double width, double length, double thickness, double pos_x = 0, + double pos_y = 0, double pos_z = 0, double rot_x = 0, double rot_y = 0, + double rot_z = 0, bool z_stacking = true) { + // Utility variable for the relative z-offset based off the previous components + const double zoff = thickness_sum + thickness / 2.0; + + const string c_nam = _toString(ncomponents, "component%d"); + ++ncomponents; + Box c_box(width / 2, length / 2, thickness / 2); + Volume c_vol; + + xml_coll_t ci_tube(x_comp, _Unicode(inner_tube)); + if (ci_tube) { + double max_r = 0; + for (; ci_tube; ++ci_tube) { + // fill the hole with tube + xml_comp_t ct = ci_tube; + max_r = std::max(max_r, ct.rmax()); + Tube c_tube(ct.rmin(), ct.rmax(), length / 2); + Volume c_tubevol(c_nam + ct.nameStr(), c_tube, description.material(ct.materialStr())); + if (ct.visStr() != "") + c_tubevol.setVisAttributes(description, ct.visStr()); + m_vol.placeVolume(c_tubevol, Transform3D(RotationZYX(0, 0, -M_PI / 2), + Position(pos_x, pos_y, pos_z + zoff))); + } + + Tube c_fbox(0, max_r, length / 2 + 1); + SubtractionSolid c_sbox(c_box, c_fbox, + Transform3D(RotationZYX(0, 0, -M_PI / 2), + Position(0, 0, 0))); //pos_x, pos_y, pos_z + zoff))); + + c_vol = Volume(c_nam, c_sbox, description.material(x_comp.materialStr())); + } else + c_vol = Volume(c_nam, c_box, description.material(x_comp.materialStr())); + + Volume test; + test = c_vol; + + // center if off by half the box length if box length is cut in half + Position c_pos(pos_x, pos_y, pos_z + zoff); + RotationZYX c_rot(rot_z, rot_y, rot_x); + pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos)); + + c_vol.setRegion(description, x_comp.regionStr()); + c_vol.setLimitSet(description, x_comp.limitsStr()); + c_vol.setVisAttributes(description, x_comp.visStr()); + if (x_comp.isSensitive()) { + pv.addPhysVolID("sensor", sensor_number++); + c_vol.setSensitiveDetector(sens); + sensitives[m_nam].push_back(pv); + module_thicknesses[m_nam] = {thickness_so_far + thickness / 2.0, + total_thickness - thickness_so_far - thickness / 2.0}; + + // -------- create a measurement plane for the tracking surface attched to the sensitive volume ----- + Vector3D u(-1., 0., 0.); + Vector3D v(0., -1., 0.); + Vector3D n(0., 0., 1.); + // Vector3D o( 0. , 0. , 0. ) ; + + // compute the inner and outer thicknesses that need to be assigned to the tracking surface + // depending on wether the support is above or below the sensor + double inner_thickness = module_thicknesses[m_nam][0]; + double outer_thickness = module_thicknesses[m_nam][1]; + + SurfaceType type(SurfaceType::Sensitive); + + // if( isStripDetector ) + // type.setProperty( SurfaceType::Measurement1D , true ) ; + + VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ; + volplane_surfaces[m_nam].push_back(surf); + + //-------------------------------------------- + } + if (z_stacking) { + thickness_sum += thickness; + thickness_so_far += thickness; + // apply relative offsets in z-position used to stack components side-by-side + thickness_sum += pos_z; + thickness_so_far += pos_z; + } + }; + + double pos_x = 0, pos_y = 0, pos_z = 0; + double rot_x = 0, rot_y = 0, rot_z = 0; + if (x_rot) { + rot_x = x_rot.x(0); + rot_y = x_rot.y(0); + rot_z = x_rot.z(0); + } + if (x_pos) { + pos_x = x_pos.x(0); + pos_y = x_pos.y(0); + pos_z = x_pos.z(0); + } + double width = x_comp.width(); + double length = x_comp.length(); + double thickness = x_comp.thickness(); + bool keep_layer = getAttrOrDefault(x_comp, _Unicode(keep_layer), false); + + if (x_comp.hasChild(_Unicode(GridSensors))) { + auto x_comp_t = x_comp.child(_Unicode(GridSensors)); + // x-distance between centers of neighboring sensors + double sensors_xdist = getAttrOrDefault(x_comp_t, _Unicode(xdist), x_comp.width()); + // y-distance between centers of neighboring sensors + double sensors_ydist = getAttrOrDefault(x_comp_t, _Unicode(ydist), x_comp.length()); + // number of rows of sensors in a stave + int nsensors_x = getAttrOrDefault(x_comp_t, _Unicode(nx), 1); + // number of column of sensors in a stave + int nsensors_y = getAttrOrDefault(x_comp_t, _Unicode(ny), 1); + // x-location of the center of the leftmost sensor + double start_x = getAttrOrDefault(x_comp_t, _Unicode(start_x), 0); + // y-location of the center of the uppermost sensor + double start_y = getAttrOrDefault(x_comp_t, _Unicode(start_y), 0); + // z-locatino of the center of all sensors (All sensors appears at the same z-layer + double start_z = getAttrOrDefault(x_comp_t, _Unicode(start_z), 0); + // central ring is located to the right of the ny_before_ring th sensor + int ny_before_ring = getAttrOrDefault(x_comp_t, _Unicode(ny_before_ring), 0); + // Extra width caused by the ring + // |<--sensors_ydist-->|<--sensors_ydist-->|<-----ring_extra_width------->|<--sensors_ydist-->| + // || || || + // ring_extra_width is the extra width between boundaries of the sensor boundaries (including dead space) + double ring_extra_width = getAttrOrDefault(x_comp_t, _Unicode(ring_extra_width), 0); + auto half_length_str = + getAttrOrDefault(x_comp_t, _Unicode(half_length), "none"); + + double current_x = start_x; + for (int nx = 0; nx < nsensors_x; ++nx) { + double current_y = start_y; + for (int ny = 0; ny < nsensors_y; ++ny) { + double sensor_length = length; + double tmp_sensors_ydist = sensors_ydist; + // when we draw half a sensor, the center has to be shifted by 0.25 times the length of a sensor + // distance between centers to the next sensor also has to be reduced by 0.25 times the length of a sensor + if ((half_length_str == "left" || half_length_str == "both") && ny == 0) { + sensor_length = 0.5 * length; + current_y += 0.25 * length; + tmp_sensors_ydist -= 0.25 * length; + } + // same idea, but when you are drawing to the right, the right sensor center has to move in -y direction + if ((half_length_str == "right" || half_length_str == "both") && ny == nsensors_y - 1) { + sensor_length = 0.5 * length; + current_y -= 0.25 * length; + } + make_box(width, sensor_length, thickness, current_x, current_y, start_z, rot_x, rot_y, + rot_z, + (((nx == nsensors_x - 1) && (ny == nsensors_y - 1))) && + !keep_layer); // all sensors are located at the same z-layer + // increment z-layers only at the end, after the last sensor is added + current_y += tmp_sensors_ydist; + if (ny + 1 == ny_before_ring) + current_y += ring_extra_width; + } + current_x += sensors_xdist; + } + } else + make_box(width, length, thickness, pos_x, pos_y, pos_z, rot_x, rot_y, rot_z, !keep_layer); + } + } + + // now build the layers + for (xml_coll_t li(x_det, _U(layer)); li; ++li) { + xml_comp_t x_layer = li; + xml_comp_t x_barrel = x_layer.child(_U(barrel_envelope)); + xml_comp_t x_layout = x_layer.child(_U(rphi_layout)); + xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the element. + int lay_id = x_layer.id(); + string m_nam = x_layer.moduleStr(); + string lay_nam = det_name + _toString(x_layer.id(), "_layer%d"); + Tube lay_tub(x_barrel.inner_r(), x_barrel.outer_r(), x_barrel.z_length() / 2.0); + Volume lay_vol(lay_nam, lay_tub, air); // Create the layer envelope volume. + Position lay_pos(0, 0, getAttrOrDefault(x_barrel, _U(z0), 0.)); + lay_vol.setVisAttributes(description.visAttributes(x_layer.visStr())); + + double phi0 = x_layout.phi0(); // Starting phi of first module. + double phi_tilt = x_layout.phi_tilt(); // Phi tilt of a module. + double rc = x_layout.rc(); // Radius of the module center. + int nphi = x_layout.nphi(); // Number of modules in phi. + double rphi_dr = x_layout.dr(); // The delta radius of every other module. + double phi_incr = (M_PI * 2) / nphi; // Phi increment for one module. + double phic = phi0; // Phi of the module center. + double z0 = z_layout.z0(); // Z position of first module in phi. + double nz = z_layout.nz(); // Number of modules to place in z. + double z_dr = z_layout.dr(); // Radial displacement parameter, of every other module. + + Volume module_env = volumes[m_nam]; + DetElement lay_elt(sdet, lay_nam, lay_id); + Placements& sensVols = sensitives[m_nam]; + + // the local coordinate systems of modules in dd4hep and acts differ + // see http://acts.web.cern.ch/ACTS/latest/doc/group__DD4hepPlugins.html + auto& layerParams = + DD4hepDetectorHelper::ensureExtension(lay_elt); + + for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) { + xml_comp_t x_layer_material = lmat; + DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_layer_material, layerParams, + "layer_material"); + } + + // Z increment for module placement along Z axis. + // Adjust for z0 at center of module rather than + // the end of cylindrical envelope. + double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0; + // Starting z for module placement along Z axis. + double module_z = -z0; + int module = 1; + + // Loop over the number of modules in phi. + for (int ii = 0; ii < nphi; ii++) { + double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of module position. + double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of module position. + double x = rc * std::cos(phic); // Basic x module position. + double y = rc * std::sin(phic); // Basic y module position. + + // Loop over the number of modules in z. + for (int j = 0; j < nz; j++) { + string module_name = _toString(module, "module%d"); + DetElement mod_elt(lay_elt, module_name, module); + + Transform3D tr(RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2), + Position(x, y, module_z)); + + pv = lay_vol.placeVolume(module_env, tr); + pv.addPhysVolID("module", module); + mod_elt.setPlacement(pv); + for (size_t ic = 0; ic < sensVols.size(); ++ic) { + PlacedVolume sens_pv = sensVols[ic]; + DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name(), module); + comp_de.setPlacement(sens_pv); + + auto& comp_de_params = + DD4hepDetectorHelper::ensureExtension(comp_de); + comp_de_params.set("axis_definitions", "XYZ"); + // comp_de.setAttributes(description, sens_pv.volume(), x_layer.regionStr(), x_layer.limitsStr(), + // xml_det_t(xmleles[m_nam]).visStr()); + // + + volSurfaceList(comp_de)->push_back(volplane_surfaces[m_nam][ic]); + } + + /// Increase counters etc. + module++; + // Adjust the x and y coordinates of the module. + x += dx; + y += dy; + // Flip sign of x and y adjustments. + dx *= -1; + dy *= -1; + // Add z increment to get next z placement pos. + module_z += z_incr; + } + phic += phi_incr; // Increment the phi placement of module. + rc += rphi_dr; // Increment the center radius according to dr parameter. + rphi_dr *= -1; // Flip sign of dr parameter. + module_z = -z0; // Reset the Z placement parameter for module. + } + // Create the PhysicalVolume for the layer. + pv = assembly.placeVolume(lay_vol, lay_pos); // Place layer in mother + pv.addPhysVolID("layer", lay_id); // Set the layer ID. + lay_elt.setAttributes(description, lay_vol, x_layer.regionStr(), x_layer.limitsStr(), + x_layer.visStr()); + lay_elt.setPlacement(pv); + } + sdet.setAttributes(description, assembly, x_det.regionStr(), x_det.limitsStr(), x_det.visStr()); + assembly.setVisAttributes(description.invisible()); + pv = description.pickMotherVolume(sdet).placeVolume(assembly); + pv.addPhysVolID("system", det_id); // Set the subdetector system ID. + sdet.setPlacement(pv); + return sdet; +} + +//@} +// clang-format off +DECLARE_DETELEMENT(epic_TOFBarrel, create_TOFBarrel) diff --git a/src/BarrelTrackerWithFrame_geo.cpp b/src/BarrelTrackerWithFrame_geo.cpp index e8fa910c0..0d0665279 100644 --- a/src/BarrelTrackerWithFrame_geo.cpp +++ b/src/BarrelTrackerWithFrame_geo.cpp @@ -349,5 +349,4 @@ static Ref_t create_BarrelTrackerWithFrame(Detector& description, xml_h e, Sensi DECLARE_DETELEMENT(epic_BarrelTrackerWithFrame, create_BarrelTrackerWithFrame) DECLARE_DETELEMENT(epic_TrackerBarrel, create_BarrelTrackerWithFrame) DECLARE_DETELEMENT(epic_VertexBarrel, create_BarrelTrackerWithFrame) -DECLARE_DETELEMENT(epic_TOFBarrel, create_BarrelTrackerWithFrame) DECLARE_DETELEMENT(epic_InnerMPGDBarrel, create_BarrelTrackerWithFrame) diff --git a/src/BeamPipeChain_geo.cpp b/src/BeamPipeChain_geo.cpp index 8da51d510..706c7e810 100644 --- a/src/BeamPipeChain_geo.cpp +++ b/src/BeamPipeChain_geo.cpp @@ -31,6 +31,7 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector / double thickness = getAttrOrDefault(x_det, _Unicode(wall_thickness), 0); vector names; + vector ids; vector xCenters; vector zCenters; vector lengths; @@ -44,6 +45,7 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector / xml_comp_t pipe(pipe_coll); names.push_back(getAttrOrDefault(pipe, _Unicode(name), "")); + ids.push_back(getAttrOrDefault(pipe, _Unicode(id), 0)); // Vectors momentarily filled with zeros for pipes in between magnets xCenters.push_back(getAttrOrDefault(pipe, _Unicode(xcenter), 0)); @@ -108,8 +110,12 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector / assembly.placeVolume(v_tube, Transform3D(RotationY(thetas[pipeN]), Position(xCenters[pipeN], 0, zCenters[pipeN]))); - assembly.placeVolume(v_vacuum, Transform3D(RotationY(thetas[pipeN]), - Position(xCenters[pipeN], 0, zCenters[pipeN]))); + auto placed_vacuum = + assembly.placeVolume(v_vacuum, Transform3D(RotationY(thetas[pipeN]), + Position(xCenters[pipeN], 0, zCenters[pipeN]))); + + DetElement vacuum_element(sdet, names[pipeN] + "_vacuum", ids[pipeN]); + vacuum_element.setPlacement(placed_vacuum); } // Final placement diff --git a/src/BeamPipeStop_geo.cpp b/src/BeamPipeStop_geo.cpp new file mode 100644 index 000000000..5b42e33d9 --- /dev/null +++ b/src/BeamPipeStop_geo.cpp @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Simon Gardner + +//========================================================================== +// +// Places a small sensitive disk of vacuum at the end of beam pipes +// +//========================================================================== + +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" +#include "TMath.h" +#include + +using namespace std; +using namespace dd4hep; + +static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector /* sens */) { + + using namespace ROOT::Math; + xml_det_t x_det = e; + string det_name = x_det.nameStr(); + int det_id = x_det.id(); + Material m_Vacuum = description.material("Vacuum"); + string vis_name = dd4hep::getAttrOrDefault(x_det, _Unicode(vis), "BeamPipeVis"); + + string grandmotherName = x_det.attr(_Unicode(grandmother)); + string motherName = x_det.attr(_Unicode(mother)); + bool detStart = getAttrOrDefault(x_det, _Unicode(end), true); + DetElement mother = description.detector(grandmotherName).child(motherName); + + DetElement sdet(det_name, det_id); + + // Get the mother volume + Volume mother_vol = mother.volume(); + + // Get mother volume shape as cone segment + ConeSegment mother_shape = mother_vol.solid(); + + // Get the parameters of the mother volume + double rOuter1 = mother_shape.rMax1(); + double rOuter2 = mother_shape.rMax2(); + double length = 2 * mother_shape.dZ(); + + double sensitive_thickness = 100 * mm; + + //Calculate R or cone after sensitive layer + double rEnd = rOuter2 - (rOuter2 - rOuter1) * sensitive_thickness / length; + double zPos = length / 2.0 - sensitive_thickness / 2.0; + if (detStart) { + rEnd = rOuter1 - (rOuter1 - rOuter2) * sensitive_thickness / length; + zPos = -length / 2.0 + sensitive_thickness / 2.0; + } + + ConeSegment s_start_disk(sensitive_thickness / 2, 0.0, rOuter2, 0.0, rEnd); + Volume v_start_disk("stop_disk_" + motherName, s_start_disk, m_Vacuum); + + v_start_disk.setLimitSet(description, "kill_limits"); + + auto disk_placement = mother_vol.placeVolume(v_start_disk, Position(0.0, 0.0, zPos)); + + sdet.setPlacement(disk_placement); + description.declareParent(det_name, mother); + + return sdet; +} + +DECLARE_DETELEMENT(BeamPipeStop, create_detector) diff --git a/src/BeamPipeTracking_geo.cpp b/src/BeamPipeTracking_geo.cpp new file mode 100644 index 000000000..d8f4d2953 --- /dev/null +++ b/src/BeamPipeTracking_geo.cpp @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Simon Gardner + +//========================================================================== +// +// Places a small sensitive disk of vacuum at the end of beam pipes +// +//========================================================================== + +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" +#include "TMath.h" +#include + +using namespace std; +using namespace dd4hep; + +static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) { + + using namespace ROOT::Math; + xml_det_t x_det = e; + string det_name = x_det.nameStr(); + int det_id = x_det.id(); + Material m_Vacuum = description.material("Vacuum"); + string vis_name = dd4hep::getAttrOrDefault(x_det, _Unicode(vis), "BeamPipeVis"); + + sens.setType("tracker"); + + DetElement sdet(det_name, det_id); + Assembly assembly(det_name + "_assembly"); + + // Grab info for beamline magnets + for (xml_coll_t slice_coll(x_det, _Unicode(slice)); slice_coll; slice_coll++) { // pipes + + string grandmotherName = slice_coll.attr(_Unicode(grandmother)); + string motherName = slice_coll.attr(_Unicode(mother)); + bool detStart = getAttrOrDefault(slice_coll, _Unicode(end), true); + int pipe_id = getAttrOrDefault(slice_coll, _Unicode(pipe_id), 0); + string slice_name = slice_coll.attr(_Unicode(name)); + DetElement mother = description.detector(grandmotherName).child(motherName); + + // Get the mother volume + Volume mother_vol = mother.volume(); + + // Get mother volume shape as cone segment + ConeSegment mother_shape = mother_vol.solid(); + + // Get the parameters of the mother volume + double rOuter1 = mother_shape.rMax1(); + double rOuter2 = mother_shape.rMax2(); + double length = 2 * mother_shape.dZ(); + + double sensitive_thickness = 0.1 * mm; + + //Calculate R or cone after sensitive layer + + double rEnd = rOuter2 - (rOuter2 - rOuter1) * sensitive_thickness / length; + double zPos = length / 2.0 - sensitive_thickness / 2.0; + if (detStart) { + rEnd = rOuter1 - (rOuter1 - rOuter2) * sensitive_thickness / length; + zPos = -length / 2.0 + sensitive_thickness / 2.0; + } + + ConeSegment s_start_disk(sensitive_thickness / 2, 0.0, rOuter2, 0.0, rEnd); + Volume v_start_disk("v_start_disk_" + motherName, s_start_disk, m_Vacuum); + v_start_disk.setSensitiveDetector(sens); + + auto disk_placement = mother_vol.placeVolume(v_start_disk, Position(0.0, 0.0, zPos)); + disk_placement.addPhysVolID("end", detStart); + disk_placement.addPhysVolID("pipe", pipe_id); + disk_placement.addPhysVolID("system", det_id); + + DetElement slice_element(sdet, slice_name, pipe_id); + + slice_element.setPlacement(disk_placement); + description.declareParent(slice_name, mother); + } + + auto pv_assembly = description.worldVolume().placeVolume(assembly, Position(0.0, 0.0, 0.0)); + pv_assembly.addPhysVolID("system", det_id); + sdet.setPlacement(pv_assembly); + + return sdet; +} + +DECLARE_DETELEMENT(BeamPipeTracking, create_detector) diff --git a/src/EndcapTOF_geo.cpp b/src/EndcapTOF_geo.cpp index c4edc64a8..5e6c0c01c 100644 --- a/src/EndcapTOF_geo.cpp +++ b/src/EndcapTOF_geo.cpp @@ -1,9 +1,8 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2022 Nicolas Schmidt +// Copyright (C) 2022 - 2024, Nicolas Schmidt, Chun Yuen Tsang /** \addtogroup Trackers Trackers * \brief Type: **Endcap Tracker with TOF**. - * \author N. Schmidt * * \ingroup trackers * @@ -19,6 +18,7 @@ #include "XML/Utilities.h" #include #include +#include using namespace std; using namespace dd4hep; @@ -83,152 +83,220 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s double module_y = x_modsz.width(); double module_overlap = getAttrOrDefault(x_modsz, _Unicode(overlap), 0.); // x_modsz.overlap(); double module_spacing = getAttrOrDefault(x_modsz, _Unicode(spacing), 0.); // x_modsz.overlap(); + double board_gap = getAttrOrDefault(x_modsz, _Unicode(board_gap), 0.); //! Add support structure xml_comp_t x_supp = x_det.child(_Unicode(support)); xml_comp_t x_supp_envelope = x_supp.child(_Unicode(envelope), false); - double total_thickness = 0; - xml_comp_t x_modFront = x_det.child(_Unicode(moduleFront)); - xml_comp_t x_modBack = x_det.child(_Unicode(moduleBack)); - - // Compute module total thickness from components - xml_coll_t ci(x_modFront, _U(module_component)); - for (ci.reset(), total_thickness = 0.0; ci; ++ci) { - total_thickness += xml_comp_t(ci).thickness(); - } - - int module = 0; - int nx = 25; - int ny = 15; - for (int ix = 0; ix < 2 * nx; ix++) { - float xcoord = (ix - nx) * (module_x + module_spacing); - for (int iy = 0; iy < 2 * ny; iy++) { - float ycoord = (iy - ny) * (module_y - module_overlap); - //! Note the module ordering is different for front and back side - xml_comp_t x_modCurr = iy % 2 == 0 ? x_modFront : x_modBack; - - double module_z = x_supp_envelope.length() / 2.0 + total_thickness / 2; - if (iy % 2 == 0) { - module_z *= -1; - } - float corner_x1 = xcoord + module_x / 2; - float corner_x2 = xcoord - module_x / 2; - float corner_y1 = ycoord + module_y / 2; - float corner_y2 = ycoord - module_y / 2; - float maxRadius = - std::max(std::max(std::hypot(corner_x1, corner_y1), std::hypot(corner_x2, corner_y2)), - std::max(std::hypot(corner_x1, corner_y2), std::hypot(corner_x2, corner_y1))); - float minRadius = - std::min(std::min(std::hypot(corner_x1, corner_y1), std::hypot(corner_x2, corner_y2)), - std::min(std::hypot(corner_x1, corner_y2), std::hypot(corner_x2, corner_y1))); - if (maxRadius > envelope.rmax() || minRadius < envelope.rmin()) { - continue; - } - - string module_name = Form("module%d_%d_%d", module, ix, iy); - DetElement mod_elt(lay_elt, module_name, module); - - // create individual sensor layers here - string m_nam = Form("EndcapTOF_Module1_%d_%d", ix, iy); - - int ncomponents = 0; - // the module assembly volume - Assembly m_vol(m_nam); - m_vol.setVisAttributes(description.visAttributes(x_modCurr.visStr())); - - double thickness_so_far = 0.0; - double thickness_sum = -total_thickness / 2.0; - double thickness_carbonsupp = 0.0; - for (xml_coll_t mci(x_modCurr, _U(module_component)); mci; ++mci, ++ncomponents) { - xml_comp_t x_comp = mci; - xml_comp_t x_pos = x_comp.position(false); - xml_comp_t x_rot = x_comp.rotation(false); - const string c_nam = Form("component_%d_%d", ix, iy); - Box c_box(x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2); - Volume c_vol(c_nam, c_box, description.material(x_comp.materialStr())); - if (x_comp.materialStr() == "CarbonFiber") { - thickness_carbonsupp = x_comp.thickness(); - } - // Utility variable for the relative z-offset based off the previous components - const double zoff = thickness_sum + x_comp.thickness() / 2.0; - if (x_pos && x_rot) { - Position c_pos(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff); - RotationZYX c_rot(x_rot.z(0), x_rot.y(0), x_rot.x(0)); - pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos)); - } else if (x_rot) { - Position c_pos(0, 0, zoff); - pv = m_vol.placeVolume( - c_vol, Transform3D(RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0)), c_pos)); - } else if (x_pos) { - pv = m_vol.placeVolume(c_vol, Position(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff)); + xml_comp_t x_modFrontLeft = x_det.child(_Unicode(moduleFrontLeft)); + xml_comp_t x_modFrontRight = x_det.child(_Unicode(moduleFrontRight)); + xml_comp_t x_modBackLeft = x_det.child(_Unicode(moduleBackLeft)); + xml_comp_t x_modBackRight = x_det.child(_Unicode(moduleBackRight)); + + xml_comp_t x_sensor_layout_front_left = x_det.child(_Unicode(sensor_layout_front_left)); + xml_comp_t x_sensor_layout_back_left = x_det.child(_Unicode(sensor_layout_back_left)); + xml_comp_t x_sensor_layout_front_right = x_det.child(_Unicode(sensor_layout_front_right)); + xml_comp_t x_sensor_layout_back_right = x_det.child(_Unicode(sensor_layout_back_right)); + + for (bool left : std::vector{true, false}) { + for (bool front : std::vector{true, false}) { + int module = (front << 1) + left; + float ycoord = envelope.rmax() - + module_y / 2.; // y-center-coord of the top sensor. Start from the top row + int iy = 0; + xml_comp_t x_sensor_layout = x_sensor_layout_front_left; + xml_comp_t x_modCurr = x_modFrontLeft; + + if (front) { + if (left) { + x_sensor_layout = x_sensor_layout_front_left; + x_modCurr = x_modFrontLeft; } else { - pv = m_vol.placeVolume(c_vol, Position(0, 0, zoff)); - } - c_vol.setRegion(description, x_comp.regionStr()); - c_vol.setLimitSet(description, x_comp.limitsStr()); - c_vol.setVisAttributes(description, x_comp.visStr()); - if (x_comp.isSensitive()) { - pv.addPhysVolID("idx", ix); - pv.addPhysVolID("idy", iy); - c_vol.setSensitiveDetector(sens); - module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0, - total_thickness - thickness_so_far - - x_comp.thickness() / 2.0}; - - // -------- create a measurement plane for the tracking surface attched to the sensitive volume ----- - Vector3D u(-1., 0., 0.); - Vector3D v(0., -1., 0.); - Vector3D n(0., 0., 1.); - - // compute the inner and outer thicknesses that need to be assigned to the tracking surface - // depending on wether the support is above or below the sensor - double inner_thickness = module_thicknesses[m_nam][0]; - double outer_thickness = module_thicknesses[m_nam][1]; - - SurfaceType type(SurfaceType::Sensitive); - - VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); - - DetElement comp_de(mod_elt, std::string("de_") + pv.volume().name(), module); - comp_de.setPlacement(pv); - - auto& comp_de_params = - DD4hepDetectorHelper::ensureExtension(comp_de); - comp_de_params.set("axis_definitions", "XYZ"); - volSurfaceList(comp_de)->push_back(surf); - - //-------------------------------------------- + x_sensor_layout = x_sensor_layout_front_right; + x_modCurr = x_modFrontRight; } - thickness_sum += x_comp.thickness(); - thickness_so_far += x_comp.thickness(); - // apply relative offsets in z-position used to stack components side-by-side - if (x_pos) { - thickness_sum += x_pos.z(0); - thickness_so_far += x_pos.z(0); + } else { + if (left) { + x_sensor_layout = x_sensor_layout_back_left; + x_modCurr = x_modBackLeft; + } else { + x_sensor_layout = x_sensor_layout_back_right; + x_modCurr = x_modBackRight; } } - const string suppb_nam = - Form("suppbar_%d_%d", ix, iy); //_toString(ncomponents, "component%d"); - Box suppb_box((module_x + module_spacing) / 2, thickness_carbonsupp / 2, - x_supp_envelope.length() / 2); - Volume suppb_vol(suppb_nam, suppb_box, carbon); - Transform3D trsupp(RotationZYX(0, 0, 0), - Position(xcoord, ycoord + module_y / 2 - module_overlap / 2, 0)); - suppb_vol.setVisAttributes(description, "AnlGray"); + double total_thickness = 0; + // Compute module total thickness from components + xml_coll_t ci(x_modCurr, _U(module_component)); - pv = lay_vol.placeVolume(suppb_vol, trsupp); - // module built! + for (ci.reset(), total_thickness = 0.0; ci; ++ci) { + xml_comp_t x_comp = ci; + bool keep_same_layer = getAttrOrDefault(x_comp, _Unicode(keep_layer), false); + if (!keep_same_layer) + total_thickness += x_comp.thickness(); + } - Transform3D tr(RotationZYX(M_PI / 2, 0, 0), Position(xcoord, ycoord, module_z)); + for (xml_coll_t lrow(x_sensor_layout, _Unicode(row)); lrow; ++lrow) { + xml_comp_t x_row = lrow; + double deadspace = getAttrOrDefault(x_row, _Unicode(deadspace), 0); + if (deadspace > 0) { + ycoord -= deadspace; + continue; + } + double x_offset = getAttrOrDefault(x_row, _Unicode(x_offset), 0); + int nsensors = getAttrOrDefault(x_row, _Unicode(nsensors), 0); + + // find the sensor id that corrsponds to the rightmost sensor in a board + // we need to know where to apply additional spaces between neighboring board + std::unordered_set sensors_id_board_edge; + int curr_ix = nsensors; // the first sensor to the right of center has ix of nsensors + for (xml_coll_t lboard(x_row, _Unicode(board)); lboard; ++lboard) { + xml_comp_t x_board = lboard; + int nboard_sensors = getAttrOrDefault(x_board, _Unicode(nsensors), 1); + curr_ix += nboard_sensors; + sensors_id_board_edge.insert(curr_ix); + sensors_id_board_edge.insert(2 * nsensors - curr_ix - + 1); // reflected to sensor id on the left + } - pv = lay_vol.placeVolume(m_vol, tr); - pv.addPhysVolID("module", module); - mod_elt.setPlacement(pv); + double accum_xoffset = x_offset; + for (int ix = (left ? nsensors - 1 : nsensors); (ix >= 0) && (ix < 2 * nsensors); + ix = ix + (left ? -1 : 1)) { + // add board spacing + if (sensors_id_board_edge.find(ix) != sensors_id_board_edge.end()) + accum_xoffset = accum_xoffset + board_gap; + + // there is a hole in the middle, with radius = x_offset + float xcoord = (ix - nsensors + 0.5) * (module_x + module_spacing) + + +(left ? -accum_xoffset : accum_xoffset); + //! Note the module ordering is different for front and back side + + double module_z = x_supp_envelope.length() / 2.0 + total_thickness / 2; + if (front) + module_z *= -1; + + string module_name = Form("module%d_%d_%d", module, ix, iy); + DetElement mod_elt(lay_elt, module_name, module); + + // create individual sensor layers here + string m_nam = Form("EndcapTOF_Module%d_%d_%d", module, ix, iy); + + int ncomponents = 0; + // the module assembly volume + Assembly m_vol(m_nam); + m_vol.setVisAttributes(description.visAttributes(x_modCurr.visStr())); + + double thickness_so_far = 0.0; + double thickness_sum = -total_thickness / 2.0; + double thickness_carbonsupp = 0.0; + int sensitive_id = 0; + for (xml_coll_t mci(x_modCurr, _U(module_component)); mci; ++mci, ++ncomponents) { + xml_comp_t x_comp = mci; + xml_comp_t x_pos = x_comp.position(false); + xml_comp_t x_rot = x_comp.rotation(false); + const string c_nam = Form("component_%d_%d_%d", module, ix, iy); + + Box c_box(x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2); + Volume c_vol(c_nam, c_box, description.material(x_comp.materialStr())); + if (x_comp.materialStr() == "CarbonFiber") { + thickness_carbonsupp = x_comp.thickness(); + } + // Utility variable for the relative z-offset based off the previous components + const double zoff = thickness_sum + x_comp.thickness() / 2.0; + if (x_pos && x_rot) { + Position c_pos(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff); + RotationZYX c_rot(x_rot.z(0), x_rot.y(0), x_rot.x(0)); + pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos)); + } else if (x_rot) { + Position c_pos(0, 0, zoff); + pv = m_vol.placeVolume( + c_vol, Transform3D(RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0)), c_pos)); + } else if (x_pos) { + pv = m_vol.placeVolume(c_vol, Position(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff)); + } else { + pv = m_vol.placeVolume(c_vol, Position(0, 0, zoff)); + } + c_vol.setRegion(description, x_comp.regionStr()); + c_vol.setLimitSet(description, x_comp.limitsStr()); + c_vol.setVisAttributes(description, x_comp.visStr()); + if (x_comp.isSensitive()) { + pv.addPhysVolID("idx", ix); + pv.addPhysVolID("idy", iy); + pv.addPhysVolID("ids", sensitive_id); + ++sensitive_id; + + c_vol.setSensitiveDetector(sens); + module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0, + total_thickness - thickness_so_far - + x_comp.thickness() / 2.0}; + + // -------- create a measurement plane for the tracking surface attched to the sensitive volume ----- + Vector3D u(-1., 0., 0.); + Vector3D v(0., -1., 0.); + Vector3D n(0., 0., 1.); + + // compute the inner and outer thicknesses that need to be assigned to the tracking surface + // depending on wether the support is above or below the sensor + double inner_thickness = module_thicknesses[m_nam][0]; + double outer_thickness = module_thicknesses[m_nam][1]; + + SurfaceType type(SurfaceType::Sensitive); + + VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); + + DetElement comp_de(mod_elt, + std::string("de_") + pv.volume().name() + "_" + + std::to_string(sensitive_id), + module); + comp_de.setPlacement(pv); + + auto& comp_de_params = + DD4hepDetectorHelper::ensureExtension(comp_de); + comp_de_params.set("axis_definitions", "XYZ"); + volSurfaceList(comp_de)->push_back(surf); + + //-------------------------------------------- + } + bool keep_same_layer = getAttrOrDefault(x_comp, _Unicode(keep_layer), false); + if (!keep_same_layer) { + thickness_sum += x_comp.thickness(); + thickness_so_far += x_comp.thickness(); + // apply relative offsets in z-position used to stack components side-by-side + if (x_pos) { + thickness_sum += x_pos.z(0); + thickness_so_far += x_pos.z(0); + } + } + } + + if (front) { + // only draw support bar on one side + // if you draw on both sides, they may overlap + const string suppb_nam = + Form("suppbar_%d_%d", ix, iy); //_toString(ncomponents, "component%d"); + Box suppb_box((module_x + module_spacing) / 2, thickness_carbonsupp / 2, + x_supp_envelope.length() / 2); + Volume suppb_vol(suppb_nam, suppb_box, carbon); + Transform3D trsupp(RotationZYX(0, 0, 0), + Position(xcoord, ycoord + module_y / 2 - module_overlap / 2, 0)); + suppb_vol.setVisAttributes(description, "AnlGray"); + + pv = lay_vol.placeVolume(suppb_vol, trsupp); + } + // module built! + + Transform3D tr(RotationZYX(M_PI / 2, 0, 0), Position(xcoord, ycoord, module_z)); + + pv = lay_vol.placeVolume(m_vol, tr); + pv.addPhysVolID("module", module); + mod_elt.setPlacement(pv); + } + ycoord -= (module_y - module_overlap); + ++iy; + } } } - // Create the PhysicalVolume for the layer. pv = assembly.placeVolume(lay_vol, lay_pos); // Place layer in mother pv.addPhysVolID("layer", lay_id); // Set the layer ID. diff --git a/src/FileLoaderHelper.h b/src/FileLoaderHelper.h index 5680febc0..669bd2bf1 100644 --- a/src/FileLoaderHelper.h +++ b/src/FileLoaderHelper.h @@ -18,7 +18,7 @@ namespace fs = std::filesystem; -using dd4hep::ERROR, dd4hep::WARNING, dd4hep::INFO; +using dd4hep::ERROR, dd4hep::WARNING, dd4hep::VERBOSE, dd4hep::INFO; using dd4hep::printout; namespace FileLoaderHelper { @@ -70,13 +70,13 @@ inline void EnsureFileFromURLExists(std::string url, std::string file, std::stri // if file exists and is symlink to correct hash fs::path hash_path(parent_path / hash); - if (fs::exists(file_path) && fs::equivalent(file_path, hash_path)) { + if (fs::exists(file_path) && fs::exists(hash_path) && fs::equivalent(file_path, hash_path)) { printout(INFO, "FileLoader", "link " + file + " -> hash " + hash + " already exists"); return; } - if (fs::exists(fs::symlink_status(hash_path)) && !fs::exists(fs::status(hash_path))) { - printout(INFO, "FileLoader", "removing broken \"" + hash_path.string() + "\" symlink"); + if (fs::exists(fs::symlink_status(hash_path))) { + printout(INFO, "FileLoader", "removing symlink \"" + hash_path.string() + "\""); remove(hash_path); } @@ -89,11 +89,11 @@ inline void EnsureFileFromURLExists(std::string url, std::string file, std::stri printout(INFO, "FileLoader", "cache " + cache_path.string()); if (fs::exists(cache_path)) { auto check_path = [&](const fs::path& cache_dir_path) { - printout(INFO, "FileLoader", "checking " + cache_dir_path.string()); + printout(VERBOSE, "FileLoader", "checking " + cache_dir_path.string()); fs::path cache_hash_path = cache_dir_path / hash; if (fs::exists(cache_hash_path)) { // symlink hash to cache/.../hash - printout(INFO, "FileLoader", + printout(VERBOSE, "FileLoader", "file " + file + " with hash " + hash + " found in " + cache_hash_path.string()); fs::path link_target; @@ -151,7 +151,8 @@ inline void EnsureFileFromURLExists(std::string url, std::string file, std::stri // file already exists if (fs::is_symlink(file_path)) { // file is symlink - if (fs::equivalent(hash_path, fs::read_symlink(file_path))) { + fs::path symlink_target = fs::read_symlink(file_path); + if (fs::exists(symlink_target) && fs::equivalent(hash_path, symlink_target)) { // link points to correct path return; } else { diff --git a/src/ForwardRomanPot_geo.cpp b/src/ForwardRomanPot_geo.cpp index f3e9e2b50..052178b3d 100644 --- a/src/ForwardRomanPot_geo.cpp +++ b/src/ForwardRomanPot_geo.cpp @@ -32,8 +32,8 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s for (xml_coll_t mi(x_det, _U(module)); mi; ++mi, ++m_id) { xml_comp_t x_mod = mi; string m_nam = x_mod.nameStr(); - double mod_width = getAttrOrDefault(x_mod, _U(width), 3.2 * cm); - double mod_height = getAttrOrDefault(x_mod, _U(height), 3.2 * cm); + double mod_width = getAttrOrDefault(x_mod, _U(width), 1.6 * cm); + double mod_height = getAttrOrDefault(x_mod, _U(height), 1.6 * cm); double mod_total_thickness = 0.; xml_coll_t ci(x_mod, _U(module_component)); @@ -42,9 +42,7 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s Box m_solid(mod_width / 2.0, mod_height / 2.0, mod_total_thickness / 2.0); Volume m_volume(m_nam, m_solid, vacuum); - //set to AnlGold temporarily for future RP troubleshooting - //m_volume.setVisAttributes(description.visAttributes(x_mod.visStr())); - m_volume.setVisAttributes(description.visAttributes("AnlGold")); + m_volume.setVisAttributes(description.visAttributes(x_mod.visStr())); double comp_z_pos = -mod_total_thickness / 2.0; int n_sensor = 1; @@ -99,8 +97,8 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s double nx = getAttrOrDefault(x_array, _Unicode(nx), 1); double ny = getAttrOrDefault(x_array, _Unicode(ny), 1); double dz = getAttrOrDefault(x_array, _Unicode(dz), 0 * mm); - double arr_width = getAttrOrDefault(x_array, _Unicode(width), 3.2 * cm); - double arr_height = getAttrOrDefault(x_array, _Unicode(height), 3.2 * cm); + double arr_width = getAttrOrDefault(x_array, _Unicode(width), 1.6 * cm); + double arr_height = getAttrOrDefault(x_array, _Unicode(height), 1.6 * cm); std::string arr_module = getAttrOrDefault(x_array, _Unicode(module), ""); // TODO: add check here auto arr_vol = modules[arr_module]; @@ -120,6 +118,7 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s if (x_pos) { arr_pos += Position(x_pos.x(0), x_pos.y(0), x_pos.z(0)); } + DetElement mod_de(ma_de, ma_name + std::string("_mod") + std::to_string(i_mod), i_mod); pv = ma_vol.placeVolume(arr_vol, arr_pos); pv.addPhysVolID("module", i_mod); @@ -128,12 +127,6 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s PlacedVolume sens_pv = sensVols[ic]; DetElement comp_de(mod_de, std::string("de_") + sens_pv.volume().name(), ic + 1); comp_de.setPlacement(sens_pv); - // Acts::ActsExtension* sensorExtension = new Acts::ActsExtension(); - //// sensorExtension->addType("sensor", "detector"); - // comp_de.addExtension(sensorExtension); - //// comp_de.setAttributes(description, sens_pv.volume(), - /// x_layer.regionStr(), / x_layer.limitsStr(), / - /// xml_det_t(xmleles[m_nam]).visStr()); } } } @@ -159,11 +152,9 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s xml_comp_t x_comp = ci; xml_comp_t c_pos = x_comp.position(false); - // string ma_name = x_comp.nameStr(); string comp_assembly = getAttrOrDefault(x_comp, _Unicode(assembly), ""); auto comp_vol = module_assemblies[comp_assembly]; - // auto de = ; auto comp_de = module_assembly_delements[comp_assembly].clone(comp_assembly + std::to_string(l_num)); if (c_pos) { @@ -175,25 +166,13 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s comp_de.setPlacement(pv); layer.add(comp_de); i_assembly++; - // DetElement det = module > 1 ? stave.clone(_toString(module,"stave%d")) - // : stave; Transform3D trafo(RotationZYX(0, rotY, rotX), - // Translation3D(-posX, -posY, 0)); PlacedVolume pv = - // envelopeVolume.placeVolume(sectVolume,trafo); - //// Not a valid volID: pv.addPhysVolID("stave", 0); - // pv.addPhysVolID("module", module); - // det.setPlacement(pv); - // parent.add(det); } pv = assembly.placeVolume(l_vol, l_pos); pv.addPhysVolID("layer", l_num); } - // pv = description.pickMotherVolume(sdet).placeVolume(assembly, - // Position(pos.x(), pos.y(), pos.z())); Transform3D posAndRot(RotationZYX(rot.z(), rot.y(), rot.x()), Position(pos.x(), pos.y(), pos.z())); - // pv = description.pickMotherVolume(sdet).placeVolume(assembly, - // Position(pos.x(), pos.y(), pos.z())); pv = description.pickMotherVolume(sdet).placeVolume(assembly, posAndRot); pv.addPhysVolID("system", x_det.id()); // Set the subdetector system ID. sdet.setPlacement(pv); diff --git a/src/HomogeneousCalorimeter_geo.cpp b/src/HomogeneousCalorimeter_geo.cpp index e24ceeae8..ea3f69f35 100644 --- a/src/HomogeneousCalorimeter_geo.cpp +++ b/src/HomogeneousCalorimeter_geo.cpp @@ -45,15 +45,15 @@ static Volume inner_support_collar(Detector& desc, xml_comp_t handle) { Material inner_ring_material = desc.material(handle.materialStr()); - double electron_rmin = handle.attr(_Unicode(electron_rmin)); - double electron_rmax = handle.attr(_Unicode(electron_rmax)); - double proton_rmin = handle.attr(_Unicode(proton_rmin)); - double proton_rmax = handle.attr(_Unicode(proton_rmax)); - double straight_section_tilt = handle.attr(_Unicode(straight_section_tilt)); - double z_length = handle.z_length(); - - double proton_x_offset = ((electron_rmax + electron_rmin) - (proton_rmax + proton_rmin)) / 2 / - cos(straight_section_tilt); + double electron_rmin = handle.attr(_Unicode(electron_rmin)); + double electron_rmax = handle.attr(_Unicode(electron_rmax)); + double proton_rmin = handle.attr(_Unicode(proton_rmin)); + double proton_rmax = handle.attr(_Unicode(proton_rmax)); + double proton_x_offset = handle.attr(_Unicode(proton_x_offset)); + double z_length = handle.z_length(); + + double straight_section_tilt = + acos(((electron_rmax + electron_rmin) - (proton_rmax + proton_rmin)) / 2 / proton_x_offset); double mean_radius = (electron_rmax + electron_rmin + proton_rmax + proton_rmin) / 4; Position straight_section_offset{ proton_x_offset / 2 + cos(straight_section_tilt) * mean_radius, diff --git a/src/InsertCalorimeter_geo.cpp b/src/InsertCalorimeter_geo.cpp index 5a7e8bfd0..611f11526 100644 --- a/src/InsertCalorimeter_geo.cpp +++ b/src/InsertCalorimeter_geo.cpp @@ -54,6 +54,8 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens pos.y(); const std::pair hole_y_parameters(hole_y_initial, hole_y_final); + const double left_right_gap = + dd4hep::getAttrOrDefault(detElem, _Unicode(left_right_gap), 0.38 * cm); // Getting thickness of backplate /* The hole radius & position is determined by liner interpolation @@ -100,93 +102,107 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens // FIXME Workaround for https://github.com/eic/epic/issues/411 assembly.setVisAttributes(desc.visAttributes("InvisibleWithDaughters")); PlacedVolume pv; - - // Keeps track of the z location as we move longiduinally through the insert - // Will use this tracking variable as input to get_hole_rxy - double z_distance_traversed = 0.; - - int layer_num = 1; - - // Looping through all the different layer sections (W/Sc, Steel/Sc, backplate) - for (xml_coll_t c(detElem, _U(layer)); c; c++) { - xml_comp_t x_layer = c; - int repeat = x_layer.repeat(); - double layer_thickness = x_layer.thickness(); - - // Looping through the number of repeated layers in each section - for (int i = 0; i < repeat; i++) { - std::string layer_name = detName + _toString(layer_num, "_layer%d"); - Box layer(width / 2., height / 2., layer_thickness / 2.); - - // Hole radius and position for each layer is determined from z position at the front of the layer - const auto hole_rxy = get_hole_rxy(z_distance_traversed); - double hole_r = std::get<0>(hole_rxy); - double hole_x = std::get<1>(hole_rxy); - double hole_y = std::get<2>(hole_rxy); - - // Removing beampipe shape from each layer - Tube layer_hole(0., hole_r, layer_thickness / 2.); - SubtractionSolid layer_with_hole(layer, layer_hole, Position(hole_x, hole_y, 0.)); - Volume layer_vol(layer_name, layer_with_hole, air); - - int slice_num = 1; - double slice_z = -layer_thickness / 2.; // Keeps track of slices' z locations in each layer - - // Looping over each layer's slices - for (xml_coll_t l(x_layer, _U(slice)); l; l++) { - xml_comp_t x_slice = l; - double slice_thickness = x_slice.thickness(); - std::string slice_name = layer_name + _toString(slice_num, "slice%d"); - Material slice_mat = desc.material(x_slice.materialStr()); - slice_z += slice_thickness / 2.; // Going to slice halfway point - - // Each slice within a layer has the same hole radius and x-y position - Box slice(width / 2., height / 2., slice_thickness / 2.); - Tube slice_hole(0., hole_r, slice_thickness / 2.); - SubtractionSolid slice_with_hole(slice, slice_hole, Position(hole_x, hole_y, 0.)); - Volume slice_vol(slice_name, slice_with_hole, slice_mat); - - // Setting appropriate slices as sensitive - if (x_slice.isSensitive()) { - sens.setType("calorimeter"); - slice_vol.setSensitiveDetector(sens); + for (int side_num = 0; side_num < 2; side_num++) { // 0 = right, 1 = left + std::string side_name = side_num == 1 ? "L" : "R"; + // Keeps track of the z location as we move longiduinally through the insert + // Will use this tracking variable as input to get_hole_rxy + double z_distance_traversed = 0.; + + int layer_num = 1; + + // Looping through all the different layer sections (W/Sc, Steel/Sc, backplate) + for (xml_coll_t c(detElem, _U(layer)); c; c++) { + xml_comp_t x_layer = c; + int repeat = x_layer.repeat(); + double layer_thickness = x_layer.thickness(); + + // Looping through the number of repeated layers in each section + for (int i = 0; i < repeat; i++) { + std::string layer_name = detName + _toString(layer_num, "_layer%d") + "_" + side_name; + Box layer(width / 2., height / 2., layer_thickness / 2.); + + // Hole radius and position for each layer is determined from z position at the front of the layer + const auto hole_rxy = get_hole_rxy(z_distance_traversed); + double hole_r = std::get<0>(hole_rxy); + double hole_x = std::get<1>(hole_rxy); + double hole_y = std::get<2>(hole_rxy); + + // Removing beampipe shape from each layer + Tube layer_hole(0., hole_r, layer_thickness / 2.); + SubtractionSolid layer_with_hole(layer, layer_hole, Position(hole_x, hole_y, 0.)); + // Only select the left or right side of the layer + Box side_cut(width / 2., height, layer_thickness); + Position side_cut_position((width / 2 - left_right_gap / 2) * (1 - 2 * side_num) - pos.x(), + 0, 0); + SubtractionSolid layer_side_with_hole(layer_with_hole, side_cut, side_cut_position); + Volume layer_vol(layer_name, layer_side_with_hole, air); + + int slice_num = 1; + double slice_z = -layer_thickness / 2.; // Keeps track of slices' z locations in each layer + + // Looping over each layer's slices + for (xml_coll_t l(x_layer, _U(slice)); l; l++) { + xml_comp_t x_slice = l; + double slice_thickness = x_slice.thickness(); + std::string slice_name = layer_name + _toString(slice_num, "slice%d"); + Material slice_mat = desc.material(x_slice.materialStr()); + slice_z += slice_thickness / 2.; // Going to slice halfway point + + // Each slice within a layer has the same hole radius and x-y position + Box slice(width / 2., height / 2., slice_thickness / 2.); + Tube slice_hole(0., hole_r, slice_thickness / 2.); + SubtractionSolid slice_with_hole(slice, slice_hole, Position(hole_x, hole_y, 0.)); + Box side_cut_slice(width / 2., height, layer_thickness); + Position side_cut_position_slice( + (width / 2 - left_right_gap / 2) * (1 - 2 * side_num) - pos.x(), 0, 0); + SubtractionSolid slice_side_with_hole(slice_with_hole, side_cut_slice, + side_cut_position_slice); + Volume slice_vol(slice_name, slice_side_with_hole, slice_mat); + + // Setting appropriate slices as sensitive + if (x_slice.isSensitive()) { + sens.setType("calorimeter"); + slice_vol.setSensitiveDetector(sens); + } + + // Setting slice attributes + slice_vol.setAttributes(desc, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr()); + + // Placing slice within layer + pv = layer_vol.placeVolume(slice_vol, + Transform3D(RotationZYX(0, 0, 0), Position(0., 0., slice_z))); + pv.addPhysVolID("slice", slice_num); + pv.addPhysVolID("side", side_num); + slice_z += slice_thickness / 2.; + z_distance_traversed += slice_thickness; + slice_num++; } - // Setting slice attributes - slice_vol.setAttributes(desc, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr()); - - // Placing slice within layer - pv = layer_vol.placeVolume(slice_vol, - Transform3D(RotationZYX(0, 0, 0), Position(0., 0., slice_z))); - pv.addPhysVolID("slice", slice_num); - slice_z += slice_thickness / 2.; - z_distance_traversed += slice_thickness; - slice_num++; + // Setting layer attributes + layer_vol.setAttributes(desc, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr()); + /* + Placing each layer inside assembly + -length/2. is front of detector in global coordinate system + + (z_distance_traversed - layer_thickness) goes to the front of each layer + + layer_thickness/2. places layer in correct spot + Example: After placement of slices in first layer, z_distance_traversed = layer_thickness + Subtracting layer_thickness goes back to the front of the first slice (Now, z = -length/2) + Adding layer_thickness / 2. goes to half the first layer thickness (proper place to put layer) + Each loop over repeat will increases z_distance_traversed by layer_thickness + */ + pv = assembly.placeVolume( + layer_vol, + Transform3D(RotationZYX(0, 0, 0), + Position(0., 0., + -length / 2. + (z_distance_traversed - layer_thickness) + + layer_thickness / 2.))); + + pv.addPhysVolID("layer", layer_num); + pv.addPhysVolID("side", side_num); + layer_num++; } - - // Setting layer attributes - layer_vol.setAttributes(desc, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr()); - /* - Placing each layer inside assembly - -length/2. is front of detector in global coordinate system - + (z_distance_traversed - layer_thickness) goes to the front of each layer - + layer_thickness/2. places layer in correct spot - Example: After placement of slices in first layer, z_distance_traversed = layer_thickness - Subtracting layer_thickness goes back to the front of the first slice (Now, z = -length/2) - Adding layer_thickness / 2. goes to half the first layer thickness (proper place to put layer) - Each loop over repeat will increases z_distance_traversed by layer_thickness - */ - pv = assembly.placeVolume( - layer_vol, Transform3D(RotationZYX(0, 0, 0), - Position(0., 0., - -length / 2. + (z_distance_traversed - layer_thickness) + - layer_thickness / 2.))); - - pv.addPhysVolID("layer", layer_num); - layer_num++; } } - DetElement det(detName, detID); Volume motherVol = desc.pickMotherVolume(det); diff --git a/src/LFHCAL_geo.cpp b/src/LFHCAL_geo.cpp index d705263da..80cc6c38f 100644 --- a/src/LFHCAL_geo.cpp +++ b/src/LFHCAL_geo.cpp @@ -23,6 +23,7 @@ struct moduleParamsStrct { , mod_BIheight(0.) , mod_SWThick(0.) , mod_TWThick(0.) + , mod_MPThick(0.) , mod_FWThick(0.) , mod_BWThick(0.) , mod_width(0.) @@ -36,14 +37,15 @@ struct moduleParamsStrct { , mod_visStr("") , mod_regStr("") , mod_limStr("") {} - moduleParamsStrct(double BIwidth, double BIheight, double SWThick, double TWThick, double FWThick, - double BWThick, double width, double height, double notchDepth, + moduleParamsStrct(double BIwidth, double BIheight, double SWThick, double TWThick, double MPThick, + double FWThick, double BWThick, double width, double height, double notchDepth, double notchHeight, double foilThick, double pcbLegth, double pcbThick, double pcbWidth, std::string visStr, std::string regStr, std::string limStr) { mod_BIwidth = BIwidth; mod_BIheight = BIheight; mod_SWThick = SWThick; mod_TWThick = TWThick; + mod_MPThick = MPThick; mod_FWThick = FWThick; mod_BWThick = BWThick; mod_width = width; @@ -62,6 +64,7 @@ struct moduleParamsStrct { double mod_BIheight = 0.; double mod_SWThick = 0.; double mod_TWThick = 0.; + double mod_MPThick = 0.; double mod_FWThick = 0.; double mod_BWThick = 0.; double mod_width = 0.; @@ -478,18 +481,22 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params, // Casing definition // ******************************************************************************** // geom definition 8M module casing + Box MountingPlate(mod_params.mod_width / 2., mod_params.mod_height / 2., + mod_params.mod_MPThick / 2.); Box modFrontPlate(mod_params.mod_width / 2., mod_params.mod_height / 2., mod_params.mod_FWThick / 2.); - Box modSidePlateL(mod_params.mod_SWThick / 2., mod_params.mod_height / 2., - (length - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); - Box modSidePlateR(mod_params.mod_SWThick / 2., mod_params.mod_height / 2., - (length - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); - Box modTopPlate((mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., - mod_params.mod_TWThick / 2., - (length - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); - Box modBottomPlate((mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., - mod_params.mod_TWThick / 2., - (length - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); + Box modSidePlateL( + mod_params.mod_SWThick / 2., mod_params.mod_height / 2., + (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); + Box modSidePlateR( + mod_params.mod_SWThick / 2., mod_params.mod_height / 2., + (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); + Box modTopPlate( + (mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., mod_params.mod_TWThick / 2., + (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); + Box modBottomPlate( + (mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., mod_params.mod_TWThick / 2., + (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); Box modBackCutOut(mod_params.mod_BIwidth / 2., mod_params.mod_BIheight / 2., mod_params.mod_BWThick / 2.); Box modBackPlateFull(mod_params.mod_width / 2., mod_params.mod_height / 2., @@ -497,6 +504,7 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params, SubtractionSolid modBackPlate(modBackPlateFull, modBackCutOut); // volume definition 8M module casing + Volume vol_mountingPlate(baseName + "_MountingPlate", MountingPlate, desc.material("Steel235")); Volume vol_modFrontPlate(baseName + "_FrontPlate", modFrontPlate, desc.material("Steel235")); Volume vol_modBackPlate(baseName + "_BackPlate", modBackPlate, desc.material("Steel235")); Volume vol_modSidePlateL(baseName + "_LeftSidePlate", modSidePlateL, desc.material("Steel235")); @@ -506,6 +514,7 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params, if (allSen) { sens.setType("calorimeter"); + vol_mountingPlate.setSensitiveDetector(sens); vol_modFrontPlate.setSensitiveDetector(sens); vol_modBackPlate.setSensitiveDetector(sens); vol_modSidePlateL.setSensitiveDetector(sens); @@ -515,19 +524,28 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params, } if (renderComp) { + vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, + // mod_params.mod_visStr); + "LFHCALLayerTungstenVis"); vol_modFrontPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, - mod_params.mod_visStr); + // mod_params.mod_visStr); + "LFHCALLayerSteelVis"); vol_modBackPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, - mod_params.mod_visStr); + // mod_params.mod_visStr); + "LFHCALLayerSteelVis"); vol_modSidePlateL.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, mod_params.mod_visStr); vol_modSidePlateR.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, mod_params.mod_visStr); vol_modTopPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, - mod_params.mod_visStr); + // mod_params.mod_visStr); + "LFHCALLayerSteelVis"); vol_modBottomPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, - mod_params.mod_visStr); + // mod_params.mod_visStr); + "LFHCALLayerSteelVis"); } else { + vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, + "InvisibleNoDaughters"); vol_modFrontPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, "InvisibleNoDaughters"); vol_modBackPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, @@ -556,7 +574,8 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params, } int layer_num = 0; - double slice_z = -length / 2 + mod_params.mod_FWThick; // Keeps track of layers' local z locations + double slice_z = -length / 2 + mod_params.mod_MPThick + + mod_params.mod_FWThick; // Keeps track of layers' local z locations // Looping through the number of repeated layers & slices in each section for (int i = 0; i < (int)sl_params.size(); i++) { slice_z += sl_params[i].slice_offset + @@ -628,8 +647,11 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params, } // placement 8M module casing - pvm = vol_mod.placeVolume(vol_modFrontPlate, - Position(0, 0, -(length - mod_params.mod_FWThick) / 2.)); + pvm = vol_mod.placeVolume(vol_mountingPlate, + Position(0, 0, -(length - mod_params.mod_MPThick) / 2.)); + pvm = vol_mod.placeVolume( + vol_modFrontPlate, + Position(0, 0, -(length - mod_params.mod_FWThick) / 2. + mod_params.mod_MPThick)); if (allSen) pvm.addPhysVolID("towerx", 2) .addPhysVolID("towery", 0) @@ -642,42 +664,48 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params, .addPhysVolID("towery", 0) .addPhysVolID("layerz", layer_num) .addPhysVolID("passive", 1); - pvm = vol_mod.placeVolume(vol_modSidePlateL, - Position(-(mod_params.mod_width - mod_params.mod_SWThick) / 2., 0, - (mod_params.mod_FWThick - mod_params.mod_BWThick) / 2)); + pvm = vol_mod.placeVolume( + vol_modSidePlateL, + Position(-(mod_params.mod_width - mod_params.mod_SWThick) / 2., 0, + (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2)); if (allSen) pvm.addPhysVolID("towerx", 3) .addPhysVolID("towery", 0) .addPhysVolID("layerz", 0) .addPhysVolID("passive", 1); - pvm = vol_mod.placeVolume(vol_modSidePlateR, - Position((mod_params.mod_width - mod_params.mod_SWThick) / 2., 0, - (mod_params.mod_FWThick - mod_params.mod_BWThick) / 2)); + pvm = vol_mod.placeVolume( + vol_modSidePlateR, + Position((mod_params.mod_width - mod_params.mod_SWThick) / 2., 0, + (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2)); if (allSen) pvm.addPhysVolID("towerx", 0) .addPhysVolID("towery", 1) .addPhysVolID("layerz", 0) .addPhysVolID("passive", 1); - pvm = vol_mod.placeVolume(vol_modTopPlate, - Position(0, (mod_params.mod_height - mod_params.mod_TWThick) / 2., - (mod_params.mod_FWThick - mod_params.mod_BWThick) / 2)); + pvm = vol_mod.placeVolume( + vol_modTopPlate, + Position(0, (mod_params.mod_height - mod_params.mod_TWThick) / 2., + (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2)); if (allSen) pvm.addPhysVolID("towerx", 1) .addPhysVolID("towery", 1) .addPhysVolID("layerz", 0) .addPhysVolID("passive", 1); - pvm = vol_mod.placeVolume(vol_modBottomPlate, - Position(0, -(mod_params.mod_height - mod_params.mod_TWThick) / 2., - (mod_params.mod_FWThick - mod_params.mod_BWThick) / 2)); + pvm = vol_mod.placeVolume( + vol_modBottomPlate, + Position(0, -(mod_params.mod_height - mod_params.mod_TWThick) / 2., + (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2)); if (allSen) pvm.addPhysVolID("towerx", 2) .addPhysVolID("towery", 1) .addPhysVolID("layerz", 0) .addPhysVolID("passive", 1); - double lengthA = length - mod_params.mod_FWThick - mod_params.mod_BWThick; - double z_offSetPCB = (mod_params.mod_FWThick - mod_params.mod_BWThick) / 2 - - (lengthA - mod_params.mod_pcbLength) / 2.; + double lengthA = + length - mod_params.mod_FWThick - mod_params.mod_MPThick + mod_params.mod_BWThick / 2; + double z_offSetPCB = + (mod_params.mod_FWThick + mod_params.mod_MPThick + mod_params.mod_BWThick) / 2 - + (lengthA - mod_params.mod_pcbLength) / 2.; pvm = vol_mod.placeVolume( vol_modPCB, @@ -710,18 +738,22 @@ Volume createFourMModule(Detector& desc, moduleParamsStrct mod_params, // Casing definition // ******************************************************************************** // geom definition 8M module casing + Box MountingPlate(mod_params.mod_width / 2., mod_params.mod_height / 2., + mod_params.mod_MPThick / 2.); Box modFrontPlate(mod_params.mod_width / 2., mod_params.mod_height / 2., mod_params.mod_FWThick / 2.); - Box modSidePlateL(mod_params.mod_SWThick / 2., mod_params.mod_height / 2., - (length - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); - Box modSidePlateR(mod_params.mod_SWThick / 2., mod_params.mod_height / 2., - (length - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); - Box modTopPlate((mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., - mod_params.mod_TWThick / 2., - (length - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); - Box modBottomPlate((mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., - mod_params.mod_TWThick / 2., - (length - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); + Box modSidePlateL( + mod_params.mod_SWThick / 2., mod_params.mod_height / 2., + (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); + Box modSidePlateR( + mod_params.mod_SWThick / 2., mod_params.mod_height / 2., + (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); + Box modTopPlate( + (mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., mod_params.mod_TWThick / 2., + (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); + Box modBottomPlate( + (mod_params.mod_width - 2 * mod_params.mod_SWThick) / 2., mod_params.mod_TWThick / 2., + (length - mod_params.mod_MPThick - mod_params.mod_FWThick - mod_params.mod_BWThick) / 2.); Box modBackCutOut(mod_params.mod_BIwidth / 2., mod_params.mod_BIheight / 2., mod_params.mod_BWThick / 2.); Box modBackPlateFull(mod_params.mod_width / 2., mod_params.mod_height / 2., @@ -729,6 +761,7 @@ Volume createFourMModule(Detector& desc, moduleParamsStrct mod_params, SubtractionSolid modBackPlate(modBackPlateFull, modBackCutOut); // volume definition 8M module casing + Volume vol_mountingPlate(baseName + "_MountingPlate", MountingPlate, desc.material("Steel235")); Volume vol_modFrontPlate(baseName + "_FrontPlate", modFrontPlate, desc.material("Steel235")); Volume vol_modBackPlate(baseName + "_BackPlate", modBackPlate, desc.material("Steel235")); Volume vol_modSidePlateL(baseName + "_LeftSidePlate", modSidePlateL, desc.material("Steel235")); @@ -738,6 +771,7 @@ Volume createFourMModule(Detector& desc, moduleParamsStrct mod_params, if (allSen) { sens.setType("calorimeter"); + vol_mountingPlate.setSensitiveDetector(sens); vol_modFrontPlate.setSensitiveDetector(sens); vol_modBackPlate.setSensitiveDetector(sens); vol_modSidePlateL.setSensitiveDetector(sens); @@ -747,19 +781,28 @@ Volume createFourMModule(Detector& desc, moduleParamsStrct mod_params, } if (renderComp) { + vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, + // mod_params.mod_visStr); + "LFHCALLayerTungstenVis"); vol_modFrontPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, - mod_params.mod_visStr); + // mod_params.mod_visStr); + "LFHCALLayerSteelVis"); vol_modBackPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, - mod_params.mod_visStr); + // mod_params.mod_visStr); + "LFHCALLayerSteelVis"); vol_modSidePlateL.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, mod_params.mod_visStr); vol_modSidePlateR.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, mod_params.mod_visStr); vol_modTopPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, - mod_params.mod_visStr); + // mod_params.mod_visStr); + "LFHCALLayerSteelVis"); vol_modBottomPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, - mod_params.mod_visStr); + // mod_params.mod_visStr); + "LFHCALLayerSteelVis"); } else { + vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, + "InvisibleNoDaughters"); vol_modFrontPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, "InvisibleNoDaughters"); vol_modBackPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr, @@ -788,7 +831,8 @@ Volume createFourMModule(Detector& desc, moduleParamsStrct mod_params, } int layer_num = 0; - double slice_z = -length / 2 + mod_params.mod_FWThick; // Keeps track of layers' local z locations + double slice_z = -length / 2 + mod_params.mod_MPThick + + mod_params.mod_FWThick; // Keeps track of layers' local z locations // Looping through the number of repeated layers & slices in each section for (int i = 0; i < (int)sl_params.size(); i++) { @@ -861,8 +905,11 @@ Volume createFourMModule(Detector& desc, moduleParamsStrct mod_params, } // placement 4M module casing - pvm = vol_mod.placeVolume(vol_modFrontPlate, - Position(0, 0, -(length - mod_params.mod_FWThick) / 2.)); + pvm = vol_mod.placeVolume(vol_mountingPlate, + Position(0, 0, -(length - mod_params.mod_MPThick) / 2.)); + pvm = vol_mod.placeVolume( + vol_modFrontPlate, + Position(0, 0, -(length - mod_params.mod_FWThick) / 2. + mod_params.mod_MPThick)); if (allSen) pvm.addPhysVolID("towerx", 2) .addPhysVolID("towery", 0) @@ -875,42 +922,48 @@ Volume createFourMModule(Detector& desc, moduleParamsStrct mod_params, .addPhysVolID("towery", 0) .addPhysVolID("layerz", layer_num) .addPhysVolID("passive", 1); - pvm = vol_mod.placeVolume(vol_modSidePlateL, - Position(-(mod_params.mod_width - mod_params.mod_SWThick) / 2., 0, - (mod_params.mod_FWThick - mod_params.mod_BWThick) / 2)); + pvm = vol_mod.placeVolume( + vol_modSidePlateL, + Position(-(mod_params.mod_width - mod_params.mod_SWThick) / 2., 0, + (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2)); if (allSen) pvm.addPhysVolID("towerx", 3) .addPhysVolID("towery", 0) .addPhysVolID("layerz", 0) .addPhysVolID("passive", 1); - pvm = vol_mod.placeVolume(vol_modSidePlateR, - Position((mod_params.mod_width - mod_params.mod_SWThick) / 2., 0, - (mod_params.mod_FWThick - mod_params.mod_BWThick) / 2)); + pvm = vol_mod.placeVolume( + vol_modSidePlateR, + Position((mod_params.mod_width - mod_params.mod_SWThick) / 2., 0, + (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2)); if (allSen) pvm.addPhysVolID("towerx", 0) .addPhysVolID("towery", 1) .addPhysVolID("layerz", 0) .addPhysVolID("passive", 1); - pvm = vol_mod.placeVolume(vol_modTopPlate, - Position(0, (mod_params.mod_height - mod_params.mod_TWThick) / 2., - (mod_params.mod_FWThick - mod_params.mod_BWThick) / 2)); + pvm = vol_mod.placeVolume( + vol_modTopPlate, + Position(0, (mod_params.mod_height - mod_params.mod_TWThick) / 2., + (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2)); if (allSen) pvm.addPhysVolID("towerx", 1) .addPhysVolID("towery", 1) .addPhysVolID("layerz", 0) .addPhysVolID("passive", 1); - pvm = vol_mod.placeVolume(vol_modBottomPlate, - Position(0, -(mod_params.mod_height - mod_params.mod_TWThick) / 2., - (mod_params.mod_FWThick - mod_params.mod_BWThick) / 2)); + pvm = vol_mod.placeVolume( + vol_modBottomPlate, + Position(0, -(mod_params.mod_height - mod_params.mod_TWThick) / 2., + (mod_params.mod_FWThick + mod_params.mod_MPThick - mod_params.mod_BWThick) / 2)); if (allSen) pvm.addPhysVolID("towerx", 2) .addPhysVolID("towery", 1) .addPhysVolID("layerz", 0) .addPhysVolID("passive", 1); - double lengthA = length - mod_params.mod_FWThick - mod_params.mod_BWThick; - double z_offSetPCB = (mod_params.mod_FWThick - mod_params.mod_BWThick) / 2 - - (lengthA - mod_params.mod_pcbLength) / 2.; + double lengthA = + length - mod_params.mod_FWThick - mod_params.mod_MPThick + mod_params.mod_BWThick / 2; + double z_offSetPCB = + (mod_params.mod_FWThick + mod_params.mod_MPThick + mod_params.mod_BWThick) / 2 - + (lengthA - mod_params.mod_pcbLength) / 2.; pvm = vol_mod.placeVolume( vol_modPCB, @@ -960,41 +1013,44 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens // 8M module specific loading xml_comp_t eightM_xml = detElem.child(_Unicode(eightmodule)); xml_dim_t eightMmod_dim = eightM_xml.dimensions(); - moduleParamsStrct eightM_params(getAttrOrDefault(eightMmod_dim, _Unicode(widthBackInner), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(heightBackInner), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(widthSideWall), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(widthTopWall), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(thicknessFrontWall), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(thicknessBackWall), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(width), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(height), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(notchDepth), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(notchHeight), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(foilThick), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(pcbLength), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(pcbThick), 0.), - getAttrOrDefault(eightMmod_dim, _Unicode(pcbWidth), 0.), - eightM_xml.visStr(), eightM_xml.regionStr(), - eightM_xml.limitsStr()); + moduleParamsStrct eightM_params( + getAttrOrDefault(eightMmod_dim, _Unicode(widthBackInner), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(heightBackInner), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(widthSideWall), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(widthTopWall), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(thicknessMountingPlate), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(thicknessFrontWall), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(thicknessBackWall), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(width), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(height), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(notchDepth), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(notchHeight), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(foilThick), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(pcbLength), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(pcbThick), 0.), + getAttrOrDefault(eightMmod_dim, _Unicode(pcbWidth), 0.), eightM_xml.visStr(), + eightM_xml.regionStr(), eightM_xml.limitsStr()); // 4M module specific loading xml_comp_t fourM_xml = detElem.child(_Unicode(fourmodule)); xml_dim_t fourMmod_dim = fourM_xml.dimensions(); - moduleParamsStrct fourM_params(getAttrOrDefault(fourMmod_dim, _Unicode(widthBackInner), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(heightBackInner), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(widthSideWall), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(widthTopWall), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(thicknessFrontWall), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(thicknessBackWall), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(width), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(height), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(notchDepth), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(notchHeight), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(foilThick), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(pcbLength), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(pcbThick), 0.), - getAttrOrDefault(fourMmod_dim, _Unicode(pcbWidth), 0.), - fourM_xml.visStr(), fourM_xml.regionStr(), fourM_xml.limitsStr()); + moduleParamsStrct fourM_params( + getAttrOrDefault(fourMmod_dim, _Unicode(widthBackInner), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(heightBackInner), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(widthSideWall), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(widthTopWall), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(thicknessMountingPlate), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(thicknessFrontWall), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(thicknessBackWall), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(width), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(height), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(notchDepth), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(notchHeight), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(foilThick), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(pcbLength), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(pcbThick), 0.), + getAttrOrDefault(fourMmod_dim, _Unicode(pcbWidth), 0.), fourM_xml.visStr(), + fourM_xml.regionStr(), fourM_xml.limitsStr()); std::vector slice_Params; int layer_num = 0; @@ -1009,7 +1065,7 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens } // Looping through the number of repeated layers in each section for (int i = 0; i < repeat; i++) { - int slice_num = 1; + int slice_num = 0; // Looping over each layer's slices for (xml_coll_t l(x_layer, _U(slice)); l; ++l) { @@ -1069,9 +1125,8 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens moduleIDy = ((pos8M[e].y + 265) / 10); // Placing modules in world volume - auto tr8M = - Transform3D(Position(-pos8M[e].x - 0.5 * eightM_params.mod_width, -pos8M[e].y, pos8M[e].z)); - phv = assembly.placeVolume(eightMassembly, tr8M); + auto tr8M = Transform3D(Position(-pos8M[e].x, -pos8M[e].y, pos8M[e].z)); + phv = assembly.placeVolume(eightMassembly, tr8M); phv.addPhysVolID("moduleIDx", moduleIDx) .addPhysVolID("moduleIDy", moduleIDy) .addPhysVolID("moduletype", 0); @@ -1108,9 +1163,8 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens _toString((int)pos4M.size()) + "\t" + _toString(moduleIDx) + "\t" + _toString(moduleIDy)); } - auto tr4M = - Transform3D(Position(-pos4M[f].x - 0.5 * fourM_params.mod_width, -pos4M[f].y, pos4M[f].z)); - phv = assembly.placeVolume(fourMassembly, tr4M); + auto tr4M = Transform3D(Position(-pos4M[f].x, -pos4M[f].y, pos4M[f].z)); + phv = assembly.placeVolume(fourMassembly, tr4M); phv.addPhysVolID("moduleIDx", moduleIDx) .addPhysVolID("moduleIDy", moduleIDy) .addPhysVolID("moduletype", 1); diff --git a/src/MPGDCylinderBarrelTracker_geo.cpp b/src/MPGDCylinderBarrelTracker_geo.cpp new file mode 100644 index 000000000..8120d9ef8 --- /dev/null +++ b/src/MPGDCylinderBarrelTracker_geo.cpp @@ -0,0 +1,564 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2022-2024 Whitney Armstrong, Nivedith Ramasubramanian, Yann Bedfer + +/** \addtogroup Trackers Trackers + * \brief Type: **Barrel Cylinder MPGD with frames**. + * \author Nivedith Ramasubramanian + * Modified by M. Posik, Y. Bedfer + * + * \ingroup trackers + * + * @{ + */ +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" +#include "DD4hep/Shapes.h" +#include "DDRec/DetectorData.h" +#include "DDRec/Surface.h" +#include "XML/Layering.h" +#include "XML/Utilities.h" +#include +#include "DD4hepDetectorHelper.h" + +using namespace std; +using namespace dd4hep; +using namespace dd4hep::rec; +using namespace dd4hep::detail; + +#include "Math/Vector2D.h" +using ROOT::Math::XYVector; + +/** Micromegas Barrel Tracker with space frame + * + * - Designed to process "mpgd_barrel.xml" ("mpgd_barrel_ver1" as of 2024/02). + * + * - Derived from "BarrelTrackerWithFrame_geo.cpp". + * + * - "support" tag not addressed. + * + * - "frame" tag within the module element. + * + * - Several models of modules, with each a distinct radius of curvature + * but a single XML and a single . + * + * \code + * \endcode + * + * + * @author Yann Bedfer + */ +static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, + SensitiveDetector sens) { + xml_det_t x_det = e; + Material air = description.air(); + int det_id = x_det.id(); + string det_name = x_det.nameStr(); + DetElement sdet(det_name, det_id); + + vector volumes; + vector sensitives; + vector volplane_surfaces; + + PlacedVolume pv; + + //#define DEBUG_MPGDCylinderBarrelTracker +#ifdef DEBUG_MPGDCylinderBarrelTracker + // TEMPORARILY INCREASE VERBOSITY level for debugging purposes + PrintLevel priorPrintLevel = printLevel(); + setPrintLevel(DEBUG); +#endif + + // Set detector type flag + dd4hep::xml::setDetectorTypeFlag(x_det, sdet); + auto& params = DD4hepDetectorHelper::ensureExtension(sdet); + + // Add the volume boundary material if configured + for (xml_coll_t bmat(x_det, _Unicode(boundary_material)); bmat; ++bmat) { + xml_comp_t x_boundary_material = bmat; + DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_boundary_material, params, + "boundary_material"); + } + + dd4hep::xml::Dimension dimensions(x_det.dimensions()); + Assembly assembly(det_name); + + sens.setType("tracker"); + + // ********** MODULE + // ***** ONE AND ONLY ONE MODULE + xml_coll_t modules(x_det, _U(module)); + if (modules.size() != 1) { + // Present detector constructor can only handle ONE tag + printout(ERROR, "MPGDCylinderBarrelTracker", "Number of modules = %u. Must be = 1", + modules.size()); + throw runtime_error("Logics error in building modules."); + } + xml_comp_t x_mod = modules; + string m_nam = x_mod.nameStr(); + double stave_width = dimensions.width(), det_length = dimensions.length(); + printout(DEBUG, "MPGDCylinderBarrelTracker", "Module \"%s\" width = %.2f cm length = %.2f cm", + m_nam.c_str(), stave_width / cm, det_length / cm); + + // ********** LAYER + // ***** ONE AND ONLY ONE LAYER + xml_coll_t li(x_det, _U(layer)); + if (li.size() != 1) { + printout(ERROR, "MPGDCylinderBarrelTracker", "Number of layers = %d. Must be = 1", + (int)li.size()); + throw runtime_error("Logics error in building modules."); + } + // ***** RETRIEVE PARAMETERS + xml_comp_t x_layer = li; + int lay_id = x_layer.id(); + if (x_layer.moduleStr() != m_nam) { + printout(ERROR, "MPGDCylinderBarrelTracker", "Layer \"%s\" does not match module \"%s\"", + x_layer.moduleStr().c_str(), m_nam.c_str()); + throw runtime_error("Logics error in building layer."); + } + xml_comp_t x_barrel = x_layer.child(_U(barrel_envelope)); + double barrel_length = x_barrel.z_length(); + double barrel_z0 = getAttrOrDefault(x_barrel, _U(z0), 0.); + // ***** LAYOUTS + xml_comp_t x_layout = x_layer.child(_U(rphi_layout)); + double phi0 = x_layout.phi0(); // Starting phi of first module. + xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the element. + double z_gap = z_layout.gap(); + // ***** UNVALID LAYOUT PROPERTIES + // # of staves (along phi) and sectors (along z) are now derived from stave + // width and sector length. Used to be specified directly. In order to remind + // the user this is no longer the case, let's forbid the use of the + // corresponding (and a few more) tags. + const int nUnvalids = 4; + const xml::Tag_t unvalidTags[nUnvalids] = {_U(phi_tilt), _U(nphi), _U(rc), _U(dr)}; + for (int uv = 0; uv < nUnvalids; uv++) { + if (x_barrel.hasChild(unvalidTags[uv])) { + const string tag = _U(nphi); + printout(ERROR, "MPGDCylinderBarrelTracker", + "Layer \"%s\": Unvalid property \"%s\" in \"rphi_layout\"", m_nam.c_str(), + tag.c_str()); + throw runtime_error("Logics error in building modules."); + } + } + + // ***** MODELS + // Model = set of two radii of curvature used alternatingly for staves + // + an offset to be applied radially. + // - The offset may be null if the two radii are different enough that + // staves adjacent along phi do not overlap. + // - There needs to be 2, as of 2024/03: Inner and outer. + // StaveModel = radius of curvature (=> "nphi", given "rmin") + // + offset + // sector2Models[2][2]: Which model for [inner,outer][r1,r2] + typedef struct { + string name; + double rmin; + // "rsensor" is supposed to have been set equal to the radius specified in + // the segmentation and is used here to double-check the consistency + // between the stack of module components and that segmentation radius. + double rsensor; + int nphi; + double offset; + int io; + } StaveModel; + StaveModel staveModels[4]; + int sector2Models[2][2]; + xml_coll_t mi(x_mod, _U(model)); + if (mi.size() != 2) { + printout(ERROR, "MPGDCylinderBarrelTracker", "Number of models = %d. Must be = 2", + (int)mi.size()); + throw runtime_error("Logics error in building modules."); + } + int nStaveModels; + for (nStaveModels = 0; mi; ++mi) { + xml_comp_t x_model = mi; + double rmin1 = x_model.rmin1(), rmin2 = x_model.rmin2(); + double rsensor = x_model.attr(_Unicode(rsensor)); + // Determine "nphi" from stave width and radius + int nphi = int(2 * M_PI * rmin1 / stave_width + .5), + nphi2 = int(2 * M_PI * rmin2 / stave_width + .5); + if (nphi2 != nphi) { + printout(ERROR, "MPGDCylinderBarrelTracker", + "Model \"%s\": rmin1,2 = %.2f,%.2f cm are incompatible", x_model.nameStr().c_str(), + rmin1, rmin2); + throw runtime_error("Logics error in building modules."); + } + double offset = x_model.offset(); + StaveModel& staveModel = staveModels[nStaveModels++]; + staveModel.rmin = rmin1; + staveModel.rsensor = rsensor; + staveModel.nphi = nphi; + staveModel.offset = offset; + int io; + if (nStaveModels == 1) // 1st encountered "x_model" => ... + io = 0; // ...it's the inner one => io = 0. + else + io = 1; + staveModel.io = io; + sector2Models[io][0] = nStaveModels - 1; + if (fabs(rmin2 - rmin1) > 1.e6) { + StaveModel& staveMode2 = staveModels[nStaveModels++]; + staveMode2.rmin = rmin2; + staveModel.rsensor = rsensor + rmin2 - rmin1; + staveModel.nphi = nphi; + staveMode2.offset = offset; + staveMode2.io = io; + staveModel.name = x_model.nameStr() + string("_1"); + staveMode2.name = x_model.nameStr() + string("_2"); + } else + staveModel.name = x_model.nameStr(); + sector2Models[io][1] = nStaveModels - 1; + } + printout(DEBUG, "MPGDCylinderBarrelTracker", "%d Stave Models:", nStaveModels); + for (int iSM = 0; iSM < nStaveModels; iSM++) { + StaveModel& sM = staveModels[iSM]; + printout(DEBUG, "MPGDCylinderBarrelTracker", + "Stave Model #%d \"%s\": rmin = %.2f cm offset = ±%.2f cm %s", iSM, sM.name.c_str(), + sM.rmin, sM.offset / 2, sM.io ? "Outer" : "Inner"); + } + + // ***** FRAMES + // There must be two: + // - Outward frame (wider, because supporting connectors) + // - Otherwise frame. + // Widest is taken as outward frame. + typedef struct { + string name; + double width; + string material; + string vis; + } Frame; + Frame frames[2]; + xml_coll_t fi(x_mod, _U(frame)); + if (fi.size() != 2) { + printout(ERROR, "MPGDCylinderBarrelTracker", "Number of frames = %d. Must be = 2", + (int)fi.size()); + throw runtime_error("Logics error in building modules."); + } + printout(DEBUG, "MPGDCylinderBarrelTracker", "2 Frames:"); + int iFr; + for (iFr = 0; fi; ++fi, iFr++) { + xml_comp_t x_frame = fi; + string name = x_frame.nameStr(); + double width = x_frame.width(); + string material = x_frame.materialStr(), vis = x_frame.visStr(); + Frame& frame = frames[iFr]; + frame.name = name; + frame.width = width; + frame.material = material; + frame.vis = vis; + } + if (frames[0].width < frames[1].width) // Outward = widest must be first + swap(frames[0], frames[1]); + for (iFr = 0; iFr < 2; iFr++) { + Frame& frame = frames[iFr]; + printout(DEBUG, "MPGDCylinderBarrelTracker", + "Frame #%d \"%s\": width = %.2f cm material = \"%s\" vis = \"%s\"", iFr, + frame.name.c_str(), frame.width, frame.material.c_str(), frame.vis.c_str()); + } + + // ***** SERVICE + xml_coll_t si(x_mod, _Unicode(service)); + if (si.size() != 1) { + printout(ERROR, "MPGDCylinderBarrelTracker", "Number of services = %d. Must be = 1", + (int)si.size()); + throw runtime_error("Logics error in building modules."); + } + xml_comp_t x_service = si; + double service_thickness = x_service.thickness(); + printout(DEBUG, "MPGDCylinderBarrelTracker", + "1 Service \"%s\": thickness = %.4f cm, material = \"%s\"", x_service.nameStr().c_str(), + service_thickness, x_service.materialStr().c_str()); + + // ***** TOTAL THICKNESS from components (used to build frames) + double total_thickness = 0; + xml_coll_t ci(x_mod, _U(module_component)); + for (ci.reset(), total_thickness = 0.0; ci; ++ci) { + const xml_comp_t x_comp = ci; + printout(DEBUG, "MPGDCylinderBarrelTracker", "\"%s\": \t total_thickness %.4f cm", + x_comp.nameStr().c_str(), total_thickness / cm); + total_thickness += x_comp.thickness(); + } + printout(DEBUG, "MPGDCylinderBarrelTracker", " => total_thickness %.4f cm", total_thickness / cm); + + // Now that we know total thickness, let's "printout" the characteristics + // of the models (extrema, phi superposition). + printout(DEBUG, "MPGDCylinderBarrelTracker", "2 Sector Models:"); + double outerPhiSuperpos = 0; // Later used to define phi range of service to inner + for (int io = 0; io < 2; io++) { + StaveModel& sM0 = staveModels[sector2Models[io][0]]; + StaveModel& sM1 = staveModels[sector2Models[io][1]]; + XYVector vOffset(sM0.offset / 2, 0); + double phiEdge0 = stave_width / 2 / sM0.rmin; + XYVector vEdge0(sM0.rmin * cos(phiEdge0), sM0.rmin * sin(phiEdge0)); + vEdge0 -= vOffset; + // Module0: Stave model has smaller curvature than circle centred on + // beam axis. => Minimum is in the middle. + double RMn = sM0.rmin - sM0.offset / 2, Mag0 = sqrt(vEdge0.Mag2()); + double phiEdge1 = stave_width / 2 / sM1.rmin; + XYVector vEdge1(sM1.rmin * cos(phiEdge1), sM1.rmin * sin(phiEdge1)); + vEdge1 += vOffset; + // Module1: Stave model has larger curvature than circle centred on + // beam axis. => Maximum is in the middle. + double RMx = sM1.rmin + sM1.offset / 2, Mag1 = sqrt(vEdge1.Mag2()); + double dPhi = acos(vEdge0.Dot(vEdge1) / Mag0 / Mag1); + RMx += total_thickness; + if (io == 1) { + RMn -= service_thickness; // Outer sector: acount for services to inner sector + outerPhiSuperpos = dPhi; + } + printout( + DEBUG, "MPGDCylinderBarrelTracker", + "Sector Model #%d,\"%s\" = \"%s\"+\"%s\": phi overlap = %.1f deg, Extrema R = %.2f,%.2f", + io, io ? "Outer" : "Inner", sM0.name.c_str(), sM1.name.c_str(), dPhi / M_PI * 180, RMn, + RMx); + } + + // ********** LOOP OVER STAVE MODELS + double total_length = 0; // Total length including frames + for (int iSM = 0; iSM < nStaveModels; iSM++) { + // "sensor_number" = Bit field in cellID identifying the sensitive surface. + // We intend to use it to set up two discrimination schemes: + // i) Stave model w/ its distinctive radius. + // ii) Readout coordinate: phi or Z. + int sensor_number = 2 * iSM; + StaveModel& staveModel = staveModels[iSM]; + // phi range, when excluding frames + double stave_rmin = staveModel.rmin; + double dphi = stave_width / stave_rmin / 2; + double phi_start = -dphi, phi_end = dphi; + + // ***** ASSEMBLY VOLUME: ONE PER STAVE MODEL + Assembly m_vol(staveModel.name); + volumes.push_back(m_vol); + m_vol.setVisAttributes(description.visAttributes(x_mod.visStr())); + + // Stave frames + double zthickness, stave_rmax = stave_rmin + total_thickness; + Frame &out_frame = frames[0], &frame = frames[1]; + total_length = det_length + out_frame.width + frame.width; + // Outward frame + zthickness = out_frame.width; + Tube frame_tube_O(stave_rmin, stave_rmax, zthickness / 2, phi_start, phi_end); + Volume frame_vol_O(out_frame.name, frame_tube_O, description.material(out_frame.material)); + m_vol.placeVolume(frame_vol_O, Position(0, 0, -(total_length - zthickness) / 2)); + // Inward frame + zthickness = frame.width; // Update "zthickness" + Tube frame_tube_I(stave_rmin, stave_rmax, zthickness / 2, phi_start, phi_end); + Volume frame_vol_I(frame.name, frame_tube_I, description.material(frame.material)); + m_vol.placeVolume(frame_vol_I, Position(0, 0, (total_length - zthickness) / 2)); + + // Start/stop frames + double frame_dphi = + zthickness / stave_rmin; //converting the thickness of the frame to angular radians. + Tube frame_tube_3(stave_rmin, stave_rmax, total_length / 2, phi_start - frame_dphi, phi_start); + const string start_frame_nam("StartFrame"); + Volume frame_vol_3(start_frame_nam, frame_tube_3, description.material(frame.material)); + m_vol.placeVolume(frame_vol_3); + + Tube frame_tube_4(stave_rmin, stave_rmax, total_length / 2, phi_end, phi_end + frame_dphi); + const string stop_frame_nam("StopFrame"); + Volume frame_vol_4(stop_frame_nam, frame_tube_4, description.material(frame.material)); + m_vol.placeVolume(frame_vol_4); + + frame_vol_O.setVisAttributes(description, out_frame.vis); + frame_vol_I.setVisAttributes(description, frame.vis); + frame_vol_3.setVisAttributes(description, frame.vis); + frame_vol_4.setVisAttributes(description, frame.vis); + + // ***** OUTER SECTORS: SERVICES TO INNER + // Don't know what the purpose of the "(inner|outer)_thickness" arg.s + // to the surface volume (see infra) and whether "inner_thickness" has to + // include the extra thickness corresponding to the services. + // Note: The phi range of the service volume is set so that it's smaller + // than that of the rest of components. This, in order to avoid the + // addition of a thickness of service to the already thick superposition + // of 2 module thicknesses (or module+frame) on the edge. + if (staveModel.io == 1) { + // Superposition along Z + double outerPos = barrel_length / 2 - total_length / 2; + double innerPos = (total_length + z_gap) / 2; + double zSuperpos = total_length - outerPos + innerPos; + // Parameters + double serv_thickness = service_thickness; + double serv_rmin = stave_rmin - service_thickness; + double serv_length = total_length - zSuperpos; + // phi range: stay away from phi overlap and frame, add 1mm margin + double dPhi = outerPhiSuperpos / 2 + (frame.width + .1) / stave_rmin; + double serv_start = phi_start + dPhi, serv_stop = phi_end - dPhi; + Tube c_tube(serv_rmin, serv_rmin + serv_thickness, serv_length / 2, serv_start, serv_stop); + Volume c_vol(x_service.nameStr(), c_tube, description.material(x_service.materialStr())); + pv = m_vol.placeVolume(c_vol, Position(0, 0, -zSuperpos / 2)); + c_vol.setRegion(description, x_service.regionStr()); + c_vol.setLimitSet(description, x_service.limitsStr()); + c_vol.setVisAttributes(description, x_service.visStr()); + } + + // ********** LOOP OVER COMPONENTS + double comp_rmin = stave_rmin; + double thickness_so_far = 0; + xml_comp_t* sensitiveComp = 0; + for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci) { + xml_comp_t x_comp = mci; + const string c_nam = x_comp.nameStr(); + double comp_thickness = x_comp.thickness(); + Tube c_tube(comp_rmin, comp_rmin + comp_thickness, det_length / 2, phi_start, phi_end); + Volume c_vol(c_nam, c_tube, description.material(x_comp.materialStr())); + pv = m_vol.placeVolume(c_vol, Position(0, 0, (out_frame.width - frame.width) / 2)); + c_vol.setRegion(description, x_comp.regionStr()); + c_vol.setLimitSet(description, x_comp.limitsStr()); + c_vol.setVisAttributes(description, x_comp.visStr()); + if (x_comp.isSensitive()) { + // ***** SENSITIVE VOLUME + if (sensitiveComp) { + printout(ERROR, "MPGDCylinderBarrelTracker", + "Component \"%s\": 2nd sensitive component in module \"%s\" (1st is \"%s\"). " + "One only allowed.", + c_nam.c_str(), m_nam.c_str(), sensitiveComp->nameStr().c_str()); + throw runtime_error("Logics error in building modules."); + } + sensitiveComp = &x_comp; // TODO: Add second sensitive + pv.addPhysVolID("sensor", sensor_number++); + c_vol.setSensitiveDetector(sens); + sensitives.push_back(pv); + + // -------- create a measurement plane for the tracking surface attached to the sensitive volume ----- + Vector3D u(-1., 0., 0.); + Vector3D v(0., -1., 0.); + Vector3D n(0., 0., 1.); + + // Compute the inner (i.e. thickness until mid-sensitive-volume) and + // outer (from mid-sensitive-volume to top) + // thicknesses that need to be assigned to the tracking surface + // depending on wether the support is above or below the sensor (!?) + double inner_thickness = thickness_so_far + comp_thickness / 2; + double outer_thickness = total_thickness - inner_thickness; + // Consistency(+/-1um) check: segmentation = stack of module components + double rXCheck = comp_rmin + comp_thickness / 2; + if (fabs(staveModel.rsensor - rXCheck) > .0001 / cm) { + printout(ERROR, "MPGDCylinderBarrelTracker", + "Sensitive Component \"%s\" of StaveModel #%d,\"%s\": rsensor(%.4f cm) != " + "radius @ sensitive surface(%.4f cm)", + iSM, c_nam.c_str(), staveModel.name.c_str(), staveModel.rsensor / cm, + rXCheck / cm); + throw runtime_error("Logics error in building modules."); + } + printout(DEBUG, "MPGDCylinderBarrelTracker", + "Stave Model #%d,\"%s\": Sensitive surface @ R = %.4f (%.4f,%.4f) cm", iSM, + staveModel.name.c_str(), staveModel.rsensor / cm, inner_thickness / cm, + outer_thickness / cm); + + SurfaceType type(SurfaceType::Sensitive); + VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ; + volplane_surfaces.push_back(surf); + } + comp_rmin += comp_thickness; + thickness_so_far += comp_thickness; + } //end of module component loop + } //end of stave model loop + + // ********** LAYER + // ***** ENVELOPE + string lay_nam = det_name + _toString(x_layer.id(), "_layer%d"); + Tube lay_tub(x_barrel.inner_r(), x_barrel.outer_r(), barrel_length / 2); + Volume lay_vol(lay_nam, lay_tub, air); // Create the layer envelope volume. + Position lay_pos(0, 0, barrel_z0); + lay_vol.setVisAttributes(description.visAttributes(x_layer.visStr())); + printout(DEBUG, "MPGDCylinderBarrelTracker", + "Layer \"%s\": rmin,max = %.2f,%.2f cm 1/2length = %.2f cm", lay_nam.c_str(), + x_barrel.inner_r(), x_barrel.outer_r(), barrel_length / 2); + + DetElement lay_elt(sdet, lay_nam, lay_id); + + // the local coordinate systems of modules in dd4hep and acts differ + // see http://acts.web.cern.ch/ACTS/latest/doc/group__DD4hepPlugins.html + auto& layerParams = + DD4hepDetectorHelper::ensureExtension(lay_elt); + + // ********** LOOP OVER THE SECTORS IN z + // ***** SECTOR POSITIONS ALONG Z + // These are the 4 central values in Z where the four sets of modules, called + // sectors, will be placed. + double modz_pos[4] = {-barrel_length / 2 + (total_length) / 2, -(total_length + z_gap) / 2, + +(total_length + z_gap) / 2, +barrel_length / 2 - (total_length) / 2}; + int nModules = 0; + for (int iz = 0; iz < 4; iz++) { + int io = (iz == 1 || iz == 2) ? 0 : 1; + int iSMs[2] = {sector2Models[io][0], sector2Models[io][1]}; + int iSM0 = iSMs[0]; + const StaveModel& sm0 = staveModels[iSM0]; + int nphi = sm0.nphi; + double offset = sm0.offset; + double phi_incr = 2 * M_PI / nphi; // Phi increment for one module. + // ***** LOOP OVER THE STAVES IN phi. + int iphi; + double phic; + for (iphi = 0, phic = phi0; iphi < nphi; iphi++, phic += phi_incr, nModules++) { + // Every other module... + int jphi = iphi % 2, iV = iSMs[jphi]; // ...swap stave volume/sensitive + double rc = (2 * jphi - 1) * offset / 2; // ...flip sign of offset + if (iz >= 2) + rc *= -1; // Swap >0 and <0 offsets. + double x1, y1; // Coordinates of the centre of curvature of + x1 = rc * std::cos(phic); + y1 = rc * std::sin(phic); + string module_name = _toString(10 * iz + iphi, "module%02d"); + DetElement mod_elt(lay_elt, module_name, nModules); + printout(DEBUG, "MPGDCylinderBarrelTracker", + "System %d Layer \"%s\",id=%d Module \"%s\",id=%d: x,y,r: %7.4f,%7.4f,%7.4f cm", + det_id, lay_nam.c_str(), lay_id, module_name.c_str(), nModules, x1 / cm, y1 / cm, + sqrt(x1 * x1 + y1 * y1) / cm); + RotationZYX rot; + rot = RotationZYX(phic, 0, 0); + if (iz >= 2) // Rotate so that outward-frame faces outwards. + // Note: The product of rotations seems to have to be done in this + // order (i.e. rotation by "phi" about Z times rotation by pi about Y. + // This, for reason I don't fully understand. Anyway, a consequence of + // that is that, in order to have iz=2,3 not out of phase w/ iz=0,1, + // one has to swap >0 and <0 offsets (see instruction supra). + rot *= RotationZYX(0, M_PI, 0); + Transform3D tr(rot, Position(x1, y1, modz_pos[iz])); + Volume& module_vol = volumes[iV]; + pv = lay_vol.placeVolume(module_vol, tr); + pv.addPhysVolID("module", nModules); + mod_elt.setPlacement(pv); + // ***** SENSITIVE COMPONENT + PlacedVolume& sens_pv = sensitives[iV]; + DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name(), nModules); + comp_de.setPlacement(sens_pv); + auto& comp_de_params = + DD4hepDetectorHelper::ensureExtension(comp_de); + comp_de_params.set("axis_definitions", "XYZ"); + volSurfaceList(comp_de)->push_back(volplane_surfaces[iV]); + } + } + + for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) { + xml_comp_t x_layer_material = lmat; + DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_layer_material, layerParams, + "layer_material"); + } + + // ***** CREATE THE PhysicalVolume FOR THE LAYER. + pv = assembly.placeVolume(lay_vol, lay_pos); // Place layer in mother + pv.addPhysVolID("layer", lay_id); // Set the layer ID. + lay_elt.setAttributes(description, lay_vol, x_layer.regionStr(), x_layer.limitsStr(), + x_layer.visStr()); + lay_elt.setPlacement(pv); + + sdet.setAttributes(description, assembly, x_det.regionStr(), x_det.limitsStr(), x_det.visStr()); + assembly.setVisAttributes(description.invisible()); + pv = description.pickMotherVolume(sdet).placeVolume(assembly); + pv.addPhysVolID("system", det_id); // Set the subdetector system ID. + sdet.setPlacement(pv); + +#ifdef DEBUG_MPGDCylinderBarrelTracker + // Reset initial print level before exiting + setPrintLevel(priorPrintLevel); +#endif + + return sdet; +} + +//@} +// clang-format off +DECLARE_DETELEMENT(epic_CylinderMPGDBarrel, create_MPGDCylinderBarrelTracker) diff --git a/src/PFRICH_geo.cpp b/src/PFRICH_geo.cpp index 1d2ee5613..07fec6bd1 100644 --- a/src/PFRICH_geo.cpp +++ b/src/PFRICH_geo.cpp @@ -63,8 +63,6 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se xml_dim_t x_pos(x_det.child(_U(position), false)); xml_dim_t x_rot(x_det.child(_U(rotation), false)); - auto vesselMat = description.material("VacuumOptical"); - Tube pfRICH_air_volume(0.0, 65.0, 25.0); // dimension of the pfRICH world in cm Rotation3D rot(RotationZYX(0, M_PI, 0)); @@ -84,6 +82,11 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se double sensorThickness = sensorElem.attr(_Unicode(thickness)); auto readoutName = detElem.attr(_Unicode(readout)); + auto HRPPD_WindowMat = description.material(sensorElem.attr(_Unicode(windowmat))); + auto HRPPD_PCBMat = description.material(sensorElem.attr(_Unicode(pcbmat))); + auto HRPPD_MPDMat = description.material(sensorElem.attr(_Unicode(mpdmat))); + auto HRPPD_ASICMat = description.material(sensorElem.attr(_Unicode(asicmat))); + double vesselRmin0 = dims.attr(_Unicode(rmin0)); double vesselRmin1 = dims.attr(_Unicode(rmin1)); double vesselRmax0 = dims.attr(_Unicode(rmax0)); @@ -91,9 +94,9 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se int imod = 0; // module number - auto gasvolMat = description.material("C4F10_PFRICH"); + auto gasvolMat = description.material(detElem.attr(_Unicode(gas))); auto gasvolVis = description.visAttributes("DRICH_gas_vis"); - auto vesselVis = description.visAttributes("DRICH_gas_vis"); + auto vesselVis = description.visAttributes(detElem.attr(_Unicode(vis_vessel))); double windowThickness = dims.attr(_Unicode(window_thickness)); double wallThickness = dims.attr(_Unicode(wall_thickness)); @@ -113,11 +116,13 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se double radiatorRmin = radiatorElem.attr(_Unicode(rmin)); double radiatorRmax = radiatorElem.attr(_Unicode(rmax)); + auto filterElem = radiatorElem.child(_Unicode(filter)); + double airgapThickness = 0.1; double filterThickness = 1; - auto aerogelMat = description.material("C4F10_PFRICH"); - auto filterMat = description.material("C4F10_PFRICH"); + auto aerogelMat = description.material(aerogelElem.attr(_Unicode(material))); + auto filterMat = description.material(filterElem.attr(_Unicode(material))); double vesselLength = dims.attr(_Unicode(length)); auto originFront = Position(0., 0., vesselLength / 2.0); @@ -152,12 +157,71 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se Cone mirror_cone(vesselLength / 2.0, vesselRmax1 - 7, vesselRmax1 - 7 + 0.3, vesselRmax1 - 13, vesselRmax1 - 13 + 0.3); - // flange + /*--------------------------------------------------*/ + // Vessel + auto vesselMat = description.material(detElem.attr(_Unicode(material))); + auto vesselGas = description.material(detElem.attr(_Unicode(gas))); + + /*--------------------------------------------------*/ + // Flange + float _FLANGE_EPIPE_DIAMETER_ = description.constant("FLANGE_EPIPE_DIAMETER"); + float _FLANGE_HPIPE_DIAMETER_ = description.constant("FLANGE_HPIPE_DIAMETER"); + float _FLANGE_HPIPE_OFFSET_ = description.constant("FLANGE_HPIPE_OFFSET"); + double clearance = description.constant("CLEARANCE"); + + // Mirrors + float _CONICAL_MIRROR_INNER_RADIUS_ = description.constant("CONICAL_MIRROR_INNER_RADIUS"); + float _CONICAL_MIRROR_OUTER_RADIUS_ = description.constant("CONICAL_MIRROR_OUTER_RADIUS"); + float _INNER_MIRROR_THICKNESS_ = description.constant("INNER_MIRROR_THICKNESS"); + float _OUTER_MIRROR_THICKNESS_ = description.constant("OUTER_MIRROR_THICKNESS"); - float _FLANGE_EPIPE_DIAMETER_ = 10.53; // in cm - float _FLANGE_HPIPE_DIAMETER_ = 4.47; // in cm - float _FLANGE_HPIPE_OFFSET_ = 6.76; // in cm - float clearance = 0.5; // in cm + // HRPPD + float _FIDUCIAL_VOLUME_LENGTH_ = description.constant("FIDUCIAL_VOLUME_LENGTH"); + float _SENSOR_AREA_LENGTH_ = description.constant("SENSOR_AREA_LENGTH"); + float _HRPPD_CENTRAL_ROW_OFFSET_ = description.constant("HRPPD_CENTRAL_ROW_OFFSET"); + float _HRPPD_WINDOW_THICKNESS_ = description.constant("HRPPD_WINDOW_THICKNESS"); + float _HRPPD_CONTAINER_VOLUME_HEIGHT_ = + description.constant("HRPPD_CONTAINER_VOLUME_HEIGHT"); + float _HRPPD_INSTALLATION_GAP_ = description.constant("HRPPD_INSTALLATION_GAP"); + + float _HRPPD_SUPPORT_GRID_BAR_HEIGHT_ = + description.constant("HRPPD_SUPPORT_GRID_BAR_HEIGHT"); + + float _HRPPD_TILE_SIZE_ = description.constant("HRPPD_TILE_SIZE"); + float _HRPPD_OPEN_AREA_SIZE_ = description.constant("HRPPD_OPEN_AREA_SIZE"); + float _HRPPD_ACTIVE_AREA_SIZE_ = description.constant("HRPPD_ACTIVE_AREA_SIZE"); + float _HRPPD_CERAMIC_BODY_THICKNESS_ = + description.constant("HRPPD_CERAMIC_BODY_THICKNESS"); + float _HRPPD_BASEPLATE_THICKNESS_ = description.constant("HRPPD_BASEPLATE_THICKNESS"); + float _HRPPD_PLATING_LAYER_THICKNESS_ = + description.constant("HRPPD_PLATING_LAYER_THICKNESS"); + float _EFFECTIVE_MCP_THICKNESS_ = description.constant("EFFECTIVE_MCP_THICKNESS"); + + float _READOUT_PCB_THICKNESS_ = description.constant("READOUT_PCB_THICKNESS"); + float _READOUT_PCB_SIZE_ = description.constant("READOUT_PCB_SIZE"); + + float _ASIC_SIZE_XY_ = description.constant("ASIC_SIZE_XY"); + float _ASIC_THICKNESS_ = description.constant("ASIC_THICKNESS"); + + // Aerogel + float _AEROGEL_INNER_WALL_THICKNESS_ = + description.constant("AEROGEL_INNER_WALL_THICKNESS"); + float _VESSEL_INNER_WALL_THICKNESS_ = description.constant("VESSEL_INNER_WALL_THICKNESS"); + float _VESSEL_OUTER_WALL_THICKNESS_ = description.constant("VESSEL_OUTER_WALL_THICKNESS"); + float _VESSEL_OUTER_RADIUS_ = description.constant("VESSEL_OUTER_RADIUS"); + double _VESSEL_FRONT_SIDE_THICKNESS_ = + description.constant("VESSEL_FRONT_SIDE_THICKNESS"); + float _FLANGE_CLEARANCE_ = description.constant("FLANGE_CLEARANCE"); + float _BUILDING_BLOCK_CLEARANCE_ = description.constant("BUILDING_BLOCK_CLEARANCE"); + //float _AEROGEL_BAND_COUNT_ = aerogel_band_count; + float _AEROGEL_SEPARATOR_WALL_THICKNESS_ = + description.constant("AEROGEL_SEPARATOR_WALL_THICKNESS"); + float _AEROGEL_OUTER_WALL_THICKNESS_ = + description.constant("AEROGEL_OUTER_WALL_THICKNESS"); + + double m_gas_volume_length = + _FIDUCIAL_VOLUME_LENGTH_ - _VESSEL_FRONT_SIDE_THICKNESS_ - _SENSOR_AREA_LENGTH_; + double m_gas_volume_radius = _VESSEL_OUTER_RADIUS_ - _VESSEL_OUTER_WALL_THICKNESS_; /// Inner mirror cone // A wedge bridging two cylinders; @@ -190,7 +254,7 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se SubtractionSolid pfRICH_volume_shape(pfRICH_air_volume, flange_final_shape); Volume pfRICH_volume(detName + "_Vol", pfRICH_volume_shape, - vesselMat); // dimension of the pfRICH world in cm + vesselGas); // dimension of the pfRICH world in cm pv = mother.placeVolume(pfRICH_volume, transform); @@ -207,6 +271,9 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se vesselRmax1 - wallThickness, vesselRmin0 + wallThickness, vesselRmax0 - wallThickness); + Cone vesselWall(vesselLength / 2.0, vesselRmax1 - 0.1, vesselRmax1, vesselRmax0 - 0.1, + vesselRmax0); + Box gasvolBox(1000, 1000, 1000); Solid gasvolSolid; @@ -218,18 +285,15 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se Solid mirrorSolid; mirrorSolid = mirror_cone; - Volume vesselVol(detName, vesselSolid, vesselMat); - Volume gasvolVol(detName + "_gas", gasvolSolid, gasvolMat); - vesselVol.setVisAttributes(vesselVis); - gasvolVol.setVisAttributes(gasvolVis); + Solid wallSolid; + wallSolid = vesselWall; - Volume mirrorVol(detName, mirrorSolid, mirrorMat); - mirrorVol.setVisAttributes(mirrorVis); + Volume vesselVol(detName + "_vesel_vol", wallSolid, vesselMat); + vesselVol.setVisAttributes(vesselVis); - // place gas volume - PlacedVolume gasvolPV = vesselVol.placeVolume(gasvolVol, Position(0, 0, 0)); - DetElement gasvolDE(sdet, "gasvol_de", 0); - gasvolDE.setPlacement(gasvolPV); + PlacedVolume vesselPV = pfRICH_volume.placeVolume(vesselVol, Position(0, 0, 0)); + DetElement vesselDE(sdet, "vessel_de", 0); + vesselDE.setPlacement(vesselPV); // BUILD RADIATOR ////////////////////////////////////// @@ -261,36 +325,9 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se // -- Mirrors --------------------------------------------------------------------------------- // Some "standard" value applied to all mirrors; // At the downstream (sensor plane) location; upstream radii are calculated automatically; - double _CONICAL_MIRROR_INNER_RADIUS_ = 12.0; - double _CONICAL_MIRROR_OUTER_RADIUS_ = 57.0; - - double _INNER_MIRROR_THICKNESS_ = 0.1; //0.29*_INCH - double _OUTER_MIRROR_THICKNESS_ = 0.2; //0.54*_INCH - - /// Detailed sensor description - - double _FIDUCIAL_VOLUME_LENGTH_ = 49.1; // cm - double _SENSOR_AREA_LENGTH_ = 5; // cm - double _HRPPD_CENTRAL_ROW_OFFSET_ = 4.0; // cm - double _HRPPD_WINDOW_THICKNESS_ = 0.38; // cm - double _HRPPD_CONTAINER_VOLUME_HEIGHT_ = 3.2; // cm - double _HRPPD_INSTALLATION_GAP_ = 0.25; // cm - - double _HRPPD_SUPPORT_GRID_BAR_HEIGHT_ = 0.2; - double _HRPPD_TILE_SIZE_ = 12.0; // cm - double _HRPPD_OPEN_AREA_SIZE_ = 11.4; // cm - double _HRPPD_ACTIVE_AREA_SIZE_ = 10.8; // cm - double _HRPPD_CERAMIC_BODY_THICKNESS_ = 0.9; // cm - double _HRPPD_BASEPLATE_THICKNESS_ = 0.3; // cm - double _HRPPD_PLATING_LAYER_THICKNESS_ = 0.006; // cm - double _EFFECTIVE_MCP_THICKNESS_ = 2 * 0.06 * 0.3; // cm - - double _READOUT_PCB_THICKNESS_ = 0.2; - double _READOUT_PCB_SIZE_ = _HRPPD_OPEN_AREA_SIZE_ - 0.2; - - double _ASIC_SIZE_XY_ = 1.6; - double _ASIC_THICKNESS_ = 0.1; + Volume mirrorVol(detName, mirrorSolid, mirrorMat); + mirrorVol.setVisAttributes(mirrorVis); double xysize = _HRPPD_TILE_SIZE_, wndthick = _HRPPD_WINDOW_THICKNESS_; @@ -299,11 +336,12 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se double _ACRYLIC_THICKNESS_ = 0.3; - // HRPPD + /*--------------------------------------------------*/ + // HRPPD material definition: + Box hrppd_Solid(xysize / 2, xysize / 2, hrppd_container_volume_thickness / 2); Volume hrppdVol_air(detName + "_air_hrppd", hrppd_Solid, air); - Volume hrppdVol(detName + "_hrppd", hrppd_Solid, sensorMat); hrppdVol_air.setSensitiveDetector(sens); hrppdVol_air.setVisAttributes(gasvolVis); @@ -312,7 +350,7 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se // Quartz Window Box wnd_Solid(xysize / 2, xysize / 2, wndthick / 2); - Volume wndVol(detName + "_wnd", wnd_Solid, gasvolMat); + Volume wndVol(detName + "_wnd", wnd_Solid, HRPPD_WindowMat); wndVol.setVisAttributes(gasvolVis); double accu = -hrppd_container_volume_thickness / 2; @@ -335,7 +373,7 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se SubtractionSolid ceramic(cerbox, cut_box, Position(0, 0, -_HRPPD_BASEPLATE_THICKNESS_)); - Volume ceramicVol(detName + "_ceramic", ceramic, air); + Volume ceramicVol(detName + "_ceramic", ceramic, HRPPD_MPDMat); ceramicVol.setVisAttributes(gasvolVis); PlacedVolume ceramicPV = @@ -346,7 +384,7 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se // Plating body Box plating_solid(xyopen / 2, xyopen / 2, _HRPPD_PLATING_LAYER_THICKNESS_ / 2); - Volume platingVol(detName + "_plating", plating_solid, air); + Volume platingVol(detName + "_plating", plating_solid, HRPPD_MPDMat); platingVol.setVisAttributes(gasvolVis); PlacedVolume platingPV = @@ -357,7 +395,7 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se // MCP body Box mcp_solid(xyopen / 2, xyopen / 2, _EFFECTIVE_MCP_THICKNESS_ / 2); - Volume mcpVol(detName + "_mcp", mcp_solid, air); + Volume mcpVol(detName + "_mcp", mcp_solid, HRPPD_MPDMat); mcpVol.setVisAttributes(gasvolVis); PlacedVolume mcpPV = hrppdVol_air.placeVolume( @@ -370,7 +408,7 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se double pdthick = 0.001; Box pdbox_solid(xyactive / 2, xyactive / 2, pdthick / 2); - Volume pdboxVol(detName + "_pd", pdbox_solid, air); + Volume pdboxVol(detName + "_pd", pdbox_solid, HRPPD_MPDMat); pdboxVol.setVisAttributes(gasvolVis); PlacedVolume pdboxPV = @@ -380,7 +418,7 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se pdboxDE.setPlacement(pdboxPV); Box qdbox_solid(xyactive / 2, xyactive / 2, pdthick / 2); - Volume qdboxVol(detName + "_qd", qdbox_solid, air); + Volume qdboxVol(detName + "_qd", qdbox_solid, HRPPD_MPDMat); qdboxVol.setVisAttributes(gasvolVis); PlacedVolume qdboxPV = hrppdVol_air.placeVolume(qdboxVol, Position(0.0, 0.0, accu + pdthick / 2)); @@ -393,7 +431,7 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se /// PCB Board Box pcb_solid(_READOUT_PCB_SIZE_ / 2, _READOUT_PCB_SIZE_ / 2, _READOUT_PCB_THICKNESS_ / 2); - Volume pcbVol(detName + "_pcb", pcb_solid, air); + Volume pcbVol(detName + "_pcb", pcb_solid, HRPPD_PCBMat); pcbVol.setVisAttributes(gasvolVis); PlacedVolume pcbPV = @@ -407,7 +445,7 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se // ASIC Board Box asic_solid(_ASIC_SIZE_XY_ / 2, _ASIC_SIZE_XY_ / 2, _ASIC_THICKNESS_ / 2); - Volume asicVol(detName + "_asic", asic_solid, mirrorMat); + Volume asicVol(detName + "_asic", asic_solid, HRPPD_ASICMat); asicVol.setVisAttributes(mirrorVis); double asic_pitch = _READOUT_PCB_SIZE_ / 2; @@ -494,30 +532,7 @@ static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector se /// Aerogel - float _AEROGEL_INNER_WALL_THICKNESS_ = 0.01; - - float _VESSEL_INNER_WALL_THICKNESS_ = 0.29 * 2.54; - - float _VESSEL_OUTER_WALL_THICKNESS_ = 0.54 * 2.54; - ; - - float _VESSEL_OUTER_RADIUS_ = 63.8; - - double _VESSEL_FRONT_SIDE_THICKNESS_ = 0.29 * 2.54; - - double m_gas_volume_length = - _FIDUCIAL_VOLUME_LENGTH_ - _VESSEL_FRONT_SIDE_THICKNESS_ - _SENSOR_AREA_LENGTH_; - double m_gas_volume_radius = _VESSEL_OUTER_RADIUS_ - _VESSEL_OUTER_WALL_THICKNESS_; - - float _FLANGE_CLEARANCE_ = 0.5; - float _BUILDING_BLOCK_CLEARANCE_ = 0.1; - const int _AEROGEL_BAND_COUNT_ = 3; - - float _AEROGEL_SEPARATOR_WALL_THICKNESS_ = 0.05; - - float _AEROGEL_OUTER_WALL_THICKNESS_ = 0.1; - float m_r0min = _FLANGE_EPIPE_DIAMETER_ / 2 + _FLANGE_CLEARANCE_ + _VESSEL_INNER_WALL_THICKNESS_ + _BUILDING_BLOCK_CLEARANCE_; float m_r0max = m_gas_volume_radius - _BUILDING_BLOCK_CLEARANCE_; diff --git a/src/PolyhedraEndcapCalorimeter2_geo.cpp b/src/PolyhedraEndcapCalorimeter2_geo.cpp index 546b84278..c8cbc56c4 100644 --- a/src/PolyhedraEndcapCalorimeter2_geo.cpp +++ b/src/PolyhedraEndcapCalorimeter2_geo.cpp @@ -70,11 +70,12 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s string s_name = _toString(s_num, "slice%d"); double s_thick = x_slice.thickness(); Material s_mat = description.material(x_slice.materialStr()); - Volume s_vol(s_name, PolyhedraRegular(numsides, rmin, rmax, s_thick), s_mat); + Volume s_vol(s_name, PolyhedraRegular(numsides, M_PI / numsides, rmin, rmax, s_thick), s_mat); s_vol.setVisAttributes(description.visAttributes(x_slice.visStr())); sliceZ += s_thick / 2; - PlacedVolume s_phv = l_vol.placeVolume(s_vol, Position(0, 0, sliceZ)); + PlacedVolume s_phv = l_vol.placeVolume( + s_vol, Transform3D(RotationZYX(-M_PI / numsides, 0, 0), Position(0, 0, sliceZ))); s_phv.addPhysVolID("slice", s_num); if (x_slice.isSensitive()) { sens.setType("calorimeter"); diff --git a/templates/epic.xml.jinja2 b/templates/epic.xml.jinja2 index ad376206d..c3729f8f5 100644 --- a/templates/epic.xml.jinja2 +++ b/templates/epic.xml.jinja2 @@ -48,6 +48,7 @@ + @@ -70,6 +71,9 @@ + + + diff --git a/templates/thisepic.sh.in b/templates/thisepic.sh.in index 9a6013f05..f3ef9fde5 100644 --- a/templates/thisepic.sh.in +++ b/templates/thisepic.sh.in @@ -3,6 +3,7 @@ export DETECTOR=@PROJECT_NAME@ export DETECTOR_PATH=@CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@ export DETECTOR_CONFIG=${1:-@PROJECT_NAME@} +export DETECTOR_VERSION=@CMAKE_PROJECT_VERSION@ ## Warn is not the right name (this script is sourced, hence $1) if [[ "$(basename ${BASH_SOURCE[0]})" != "thisepic.sh" ]]; then diff --git a/templates/version.xml.in b/templates/version.xml.in new file mode 100644 index 000000000..6398540f7 --- /dev/null +++ b/templates/version.xml.in @@ -0,0 +1,4 @@ + + + +