Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 36 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,51 @@
[![CI status](https://github.com/eic/epic/actions/workflows/linux-eic-shell.yml/badge.svg)](https://github.com/eic/epic/actions/workflows/linux-eic-shell.yml)

Overview
--------

<a href="https://eic.github.io/epic/artifacts/epic_craterlake_views/view1_top.pdf"><img align="right" alt="craterlake" src="https://eic.github.io/epic/artifacts/epic_craterlake_views/view1_top.png" width="70%"/></a>

**Detector geometry:**
- [Empty viewer](https://eic.github.io/epic/geoviewer)
- Craterlake: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_craterlake.root&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_craterlake.root) [step](https://eic.github.io/epic//artifacts/epic_craterlake_no_bhcal.stp/epic_craterlake_no_bhcal.stp)
- Subsystems:
- Inner detector: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_inner_detector.root&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_inner_detector.root)
- Calorimetry: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_calorimeters.root&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_calorimeters.root)
- Imaging: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_imaging_only.root&item=default;1&opt=clipx;clipy;transp30;zoom55;ROTY49;ROTZ350;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_imaging.root) [step](https://eic.github.io/epic//artifacts/epic_imaging_only.stp/epic_imaging_only.stp)
- PID: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_pid_only.root&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY320;ROTZ340;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_pid_only.root)
- dRICH: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_drich_only.root&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY290;ROTZ350;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_drich_only.root) [step](https://eic.github.io/epic//artifacts/epic_drich_only.stp/epic_drich_only.stp)
- pfRICH: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_pfrich_only.root&item=default;1&opt=clipx;clipy;transp30;zoom55;ROTY49;ROTZ350;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_pfrich_only.root)
- DIRC: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_dirc_only.root&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_dirc_only.root) [step](https://eic.github.io/epic//artifacts/epic_dirc_only.stp/epic_dirc_only.stp)
- Tracking: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_craterlake_tracking_only.root&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY320;ROTZ340;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_craterlake_tracking_only.root) [step](https://eic.github.io/epic//artifacts/epic_craterlake_tracking_only.stp/epic_craterlake_tracking_only.stp)
- Vertex: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_vertex_only.root&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_vertex_only.root)
- TOF: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_tof_only.root&item=default;1&opt=clipx;clipy;transp30;zoom55;ROTY49;ROTZ350;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_tof_only.root)
- Beamline: [viewer](https://eic.github.io/epic/geoviewer?nobrowser&file=artifacts/tgeo/epic_ip6.root&item=default;1&opt=clipx;clipy;transp30;zoom40;ROTY290;ROTZ350;trz0;trr0;ctrl;all) [tgeo](https://eic.github.io/epic//artifacts/tgeo/epic_ip6.root) [step](https://eic.github.io/epic//artifacts/epic_ip6.stp/epic_ip6.stp)

**Detector parameters:**
- Craterlake: [text](https://eic.github.io/epic/artifacts/constants/epic_craterlake_constants.out) [toml](https://eic.github.io/epic/artifacts/constants/epic_craterlake_constants.toml) [csv](https://eic.github.io/epic/artifacts/DetectorParameterTable/epic_craterlake.csv) [html](https://eic.github.io/epic/artifacts/DetectorParameterTable/epic_craterlake.html)

Getting Started
---------------

Get a copy of the latest version from this repository:
```bash
git clone https://github.com/eic/epic.git
```
Curved OB geometry test
-----------------------

### Compilation
This branch has been created by Sam Henry to test a new outer barrel geometry with curved silicon surface.

To configure, build, and install the geometry (to the `install` directory), use the following commands:
```bash
cmake -B build -S . -DCMAKE_INSTALL_PREFIX=install
cmake --build build
cmake --install build
```
To load the geometry, you can use the scripts in the `install` directory:
```bash
source install/bin/thisepic.sh
```
The OB stave structure has replaced the flat silicon surface with a curved surface. The carbon fibre frame has been replaced with a flat layer. The staves are no longer tilted and are positioned alternately at radii separated by 6mm.

In this test, the curved silicon surface for each stave is modelled as a single module - a segment of a cylinder with a radius of 80mm. In the final version we will include the top and bottom layers of the stave with 4 modules for L3 and 8 for L4.

This is not yet working - eicrecon does not see the outer barrel hits.

**Modified files:**

### Adding/changing detector geometry
```src/BarrelTrackerWithFrame_geo.cpp```

Hint: **Use the CI/CD pipelines**.
```compact/tracking/silicon_barrel.xml```

To avoid dealing with setting up all the dependencies, we recommend using the continuous integration/continuous deployment (CI/CD) pipelines to make changes and assess their effects. Any feedback to help this process is appreciated.
**Additional files:**

Here is how to begin:
```SimpleCurved_silicon_barrel.xml``` - alternative version of silicon_barrel.xml with a simpler curved model where all staves are segments of a single big cylinder.

1. Look at existing detector constructions and reuse if possible. Note that "compact detector descriptions" -> xml files, and "detector construction" -> cpp file.
2. Modify xml file or detector construction.
3. Create a WIP (or draft) merge request or pull request and look at the CI output for debugging. Then go to back to 2 if changes are needed.
4. Remove the WIP/Draft part of the merge request if you would like to see your changes merged into the main.
```TestOB.sh``` - script to test the geometry, using ```TestOB.C``` and ```epic_craterlake_tracking_only_cut.xml```

See:

- [Talk at computing round table](https://indico.jlab.org/event/420/#17-automated-workflow-for-end)
The test script runs a simulation shooting 1000 muons through the vertex and silicon barrels. It then runs eicrecon and prints the mean of CentralCKFTrajectories.nMeasurements - i.e. the number the barrels the tracks go through. If everything is well, this should be close to 5. If eicrecon is not seeing the outer barrels, it will be 3

### Compiling (avoid it)

First, see if the use case above is best for you. It most likely is and can save a lot of time for newcomers.
To run the simulation locally, we suggest using the singularity image.
More details can be found at the links below:
**Tests**

- https://dd4hep.web.cern.ch/dd4hep/page/beginners-guide/
- https://eic.phy.anl.gov/tutorials/eic_tutorial/
- https://eicweb.phy.anl.gov/containers/eic_container/
Run tests in eic-shell --version 25.07.0-stable . In the latest version, eicrecon generates errors and the control test fails, presumably due to issues with a new ACTs version.

Control test with epic-main geometry
```
source /opt/detector/epic-main/bin/thisepic.sh
./TestOB.sh
```
Mean nMeasurements: 5.02398

Related useful links
--------------------
Test new curved model
```
source install/bin/thisepic.sh
./TestOB.sh

- [EIC tutorial](https://eic.phy.anl.gov/tutorials/eic_tutorial)
- [DD4hep repository](https://github.com/AIDAsoft/DD4hep)
- [DD4hep user manual](https://dd4hep.web.cern.ch/dd4hep/usermanuals/DD4hepManual/DD4hepManual.pdf)
- [ACTS DD4hep plugin documentation](https://acts.readthedocs.io/en/latest/plugins/dd4hep.html)
Mean nMeasurements: 3
```
Test simple curved model
```
cp SimpleCurved_silicon_barrel.xml install/share/epic/compact/tracking/silicon_barrel.xml
./TestOB.sh
```
Mean nMeasurements: 4.947
201 changes: 201 additions & 0 deletions SimpleCurved_silicon_barrel.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
<!-- SPDX-License-Identifier: LGPL-3.0-or-later -->
<!-- Copyright (C) 2022 Sylvester Joosten, Wouter Deconinck, Shujie Li -->

<lccdd>
<define>
<comment>
Main parameters - this is for the more realistic June 2022 design
</comment>

<constant name="SiBarrelMod1_rmin" value="SiBarrel1_rmin+1*mm"/>
<constant name="SiBarrelMod2_rmin" value="SiBarrel2_rmin+1*cm"/>
<constant name="SiBarrelMod_angle" value="SiBarrel_angle"/>
<constant name="SiBarrelMod_dz" value="SiBarrel_dz"/>

<constant name="SiBarrelSensor_thickness" value="40*um"/>

<constant name="SiBarrelMod1Service_thickness" value="0.15*mm"/>
<constant name="SiBarrelMod2Service_thickness" value="0.37*mm"/>
<constant name="SiBarrelMod1Frame_thickness" value="0.06*mm"/>
<constant name="SiBarrelMod2Frame_thickness" value="0.12*mm"/>
<constant name="SiBarrelMod1Frame_height" value="0.8*cm"/>
<constant name="SiBarrelMod2Frame_height" value="0.8*cm"/>
<constant name="SiBarrelStave1_width" value="4*cm"/>
<constant name="SiBarrelStave2_width" value="4*cm"/>

<comment>
Actual parametrization
</comment>

<constant name="SiBarrelMod1_length" value="2 * SiBarrelMod1_rmin / tan(SiBarrelMod_angle) - SiBarrel_dz"/>
<comment> 84cm=2*42cm is the engineer max </comment>
<constant name="SiBarrelMod2_length" value="84*cm"/>

<constant name="SiBarrelLayer1_length" value="SiBarrelMod1_length + 1*um"/>
<constant name="SiBarrelLayer2_length" value="SiBarrelMod2_length + 1*um"/>
<constant name="SiBarrelEnvelope_length" value="SiBarrelLayer2_length + 1*um" />

<constant name="SiBarrelLayer_thickness" value="3.0*cm"/>
<constant name="SiBarrelLayer1_rmin" value="SiBarrelMod1_rmin "/>
<constant name="SiBarrelLayer1_rmax" value="SiBarrelLayer1_rmin + SiBarrelLayer_thickness"/>
<constant name="SiBarrelLayer2_rmin" value="SiBarrelMod2_rmin "/>
<constant name="SiBarrelLayer2_rmax" value="SiBarrelLayer2_rmin + SiBarrelLayer_thickness"/>

<constant name="SiBarrelStaveTilt_angle" value="3.0*degree"/>
<constant name="SiBarrelStave1_count" value="floor(180.*degree/asin(SiBarrelStave1_width*cos(SiBarrelStaveTilt_angle)/2/SiBarrelMod1_rmin))+2"/>
<constant name="SiBarrelStave2_count" value="floor(180.*degree/asin(SiBarrelStave2_width*cos(SiBarrelStaveTilt_angle)/2/SiBarrelMod2_rmin))+2"/>
</define>

<detectors>
<documentation level="5">
### Actual detectors
</documentation>
<detector
id="TrackerBarrel_0_ID"
name="SagittaSiBarrel"
type="epic_TrackerBarrel"
readout="SiBarrelHits"
insideTrackingVolume="true">
<type_flags type="DetType_TRACKER + DetType_BARREL"/>
<dimensions
rmin="SiBarrelLayer1_rmin"
rmax="SiBarrelLayer1_rmax"
length="SiBarrelLayer1_length" />
<comment>Silicon Barrel Modules</comment>
<module name="Module1" vis="TrackerLayerVis">
<module_component name="Support"
material="CarbonFiber"
vis="TrackerSupportVis"
width="SiBarrelStave1_width*0.8"
height="SiBarrelMod1Frame_height"
length="SiBarrelMod1_length"
thickness="SiBarrelMod1Frame_thickness" />

<module_component name="Service"
material="Aluminum"
sensitive="false"
width="SiBarrelStave1_width*0.8"
length="SiBarrelMod1_length"
thickness="SiBarrelMod1Service_thickness"
vis="TrackerLayerVis"/>
<module_component name="CurvedSilicon"
material="Silicon"
sensitive="true"
radius="SiBarrelMod1_rmin+6*mm"
offset="-SiBarrelMod1_rmin"
phi0="-0.068" phi1="0.068"
width="SiBarrelStave1_width"
length="SiBarrelMod1_length"
thickness="SiBarrelSensor_thickness"
vis="TrackerLayerVis" />
</module>
<comment> Layers composed of many arrayed modules </comment>
<layer module="Module1" id="3" vis="TrackerLayerVis">
<barrel_envelope
inner_r="SiBarrelLayer1_rmin-0.5*mm"
outer_r="SiBarrelLayer1_rmax"
z_length="SiBarrelLayer1_length" />
<layer_material surface="inner" binning="binPhi,binZ" bins0="SiBarrelStave1_count" bins1="100" />
<layer_material surface="outer" binning="binPhi,binZ" bins0="SiBarrelStave1_count" bins1="100" />
<comment>
phi0 : Starting phi of first module.
phi_tilt : Phi tilt of a module.
rc : Radius of the module center.
nphi : Number of modules in phi.
rphi_dr : The delta radius of every other module.
z0 : Z position of first module in phi.
nz : Number of modules to place in z.
dr : Radial displacement parameter, of every other module.
</comment>
<rphi_layout phi_tilt="0.0" nphi="46" phi0="0.0" rc="SiBarrelMod1_rmin" dr="0.0 * mm"/>
<z_layout dr="0.0 * mm" z0="0.0 * mm" nz="1"/>
</layer>
</detector>
<documentation level="5">
### Actual detectors
</documentation>
<detector
id="TrackerBarrel_1_ID"
name="OuterSiBarrel"
type="epic_TrackerBarrel"
readout="SiBarrelHits"
insideTrackingVolume="true">
<type_flags type="DetType_TRACKER + DetType_BARREL"/>
<dimensions
rmin="SiBarrelLayer2_rmin"
rmax="SiBarrelLayer2_rmax"
length="SiBarrelLayer2_length" />
<comment>Silicon Barrel Modules</comment>
<module name="Module1" vis="TrackerLayerVis">
<module_component name="Support"
material="CarbonFiber"
sensitive="false"
width="SiBarrelStave2_width*0.8"
length="SiBarrelMod2_length"
thickness="SiBarrelMod2Frame_thickness"
vis="TrackerLayerVis"/>
<module_component name="Service"
material="Aluminum"
sensitive="false"
width="SiBarrelStave2_width*0.8"
length="SiBarrelMod2_length"
thickness="SiBarrelMod2Service_thickness"
vis="TrackerLayerVis"/>
<module_component name="CurvedSilicon"
material="Silicon"
sensitive="true"
radius="SiBarrelMod2_rmin+6*mm"
offset="-SiBarrelMod2_rmin"
phi0="-0.044" phi1="0.044"
width="SiBarrelStave2_width"
length="SiBarrelMod2_length"
thickness="SiBarrelSensor_thickness"
vis="TrackerLayerVis" />
</module>

<comment> Layers composed of many arrayed modules </comment>
<layer module="Module1" id="4" vis="TrackerLayerVis">
<barrel_envelope
inner_r="SiBarrelLayer2_rmin-1.0*mm"
outer_r="SiBarrelLayer2_rmax"
z_length="SiBarrelLayer2_length" />
<layer_material surface="inner" binning="binPhi,binZ" bins0="128" bins1="100" />
<layer_material surface="outer" binning="binPhi,binZ" bins0="128" bins1="100" />
<comment>
phi0 : Starting phi of first module.
phi_tilt : Phi tilt of a module.
rc : Radius of the module center.
nphi : Number of modules in phi.
rphi_dr : The delta radius of every other module.
z0 : Z position of first module in phi.
nz : Number of modules to place in z.
dr : Radial displacement parameter, of every other module.
</comment>
<rphi_layout phi_tilt="0.0" nphi="70" phi0="0.0" rc="SiBarrelMod2_rmin" dr="0.0 * mm"/>
<z_layout dr="0.0 * mm" z0="0.0 * mm" nz="1"/>
</layer>
</detector>
</detectors>

<plugins>
<plugin name="DD4hep_ParametersPlugin">
<argument value="SagittaSiBarrel"/>
<argument value="layer_pattern: str=SagittaSiBarrel_layer\d"/>
</plugin>
<plugin name="DD4hep_ParametersPlugin">
<argument value="OuterSiBarrel"/>
<argument value="layer_pattern: str=OuterSiBarrel_layer\d"/>
</plugin>
</plugins>

<readouts>
<readout name="SiBarrelHits">
<segmentation type="MultiSegmentation" key="layer">
<segmentation name="L3" type="CylindricalGridPhiZ" key_value="3" grid_size_phi="0.02*mm/(SiBarrelMod1_rmin+6*mm)" grid_size_z="0.02*mm" radius="SiBarrelMod1_rmin+6*mm" />
<segmentation name="L4" type="CylindricalGridPhiZ" key_value="4" grid_size_phi="0.04*mm/(SiBarrelMod2_rmin+6*mm)" grid_size_z="0.04*mm" radius="SiBarrelMod2_rmin+6*mm" />
</segmentation>
<id>system:8,layer:4,module:12,sensor:2,phi:32:-16,z:-16</id>
</readout>
Comment on lines +192 to +198
Copy link
Contributor

@wdconinc wdconinc Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you had some questions on the segmentation, essentially the maximum extent in phi and z, divided by the grid size in that dimensions, gives you a maximum number of grid points. That number of grid points should fit within the number of bits specified for that dimensions.

E.g. assuming 360 degrees for phi, and grid_size_phi = 0.02*mm/(27.1*cm+6*mm) = 7.2e-5 rad, that means 4986000 grid points, which corresponds to 22.2 i.e. 23 whole bits. So the 16 bits reserved for this dimension is not sufficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I am still puzzling this out - please bear with me.

For this example, I have:

2pi/7.2e-5 = 87022 = 2^16.4 - so we need 17 bits for phi?
522/0.02 = 26100 = 2^14.7 - so we need 15 bits for z?

What does "phi:32:-16,z:-16" actually mean? Is it 32 bits for phi and whatever-is-left for z (then, if the total is 64 would be 64-8-4-12-2-32 = 6, so clearly not enough, unless it is 64 bits just for phi and z?), or are the 32 bits split between phi and z? Is the -16 an offset to allow for negative numbers? I'm guessing it is 32-16=16 bits for phi and then 64-8-4-12-2-16 = 22 for z?

More questions: are these local or global coordinates? Each stave is only 5-8 degrees wide, so do we need to allow for a maximum of 360 degrees? In the CartesianGridXY setup, I assumed the x and y were local coordinates in the plane of each stave. If the CylindricalGridPhiZ is a global coordinate system, that would explain why my model where each stave is a separate cylinder doesn't work. Presumably I need to define the offset axis for each one?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "phi:32:-16,z:-16" actually mean?

This means that the field phi starts at bit 32, has a width of 16 bits and the value is stored as a signed integer. Then the field z follows, also with a width of 16 bit, and also as a signed integer. Signed makes sense here. For r/phi segmentation it would not make sense. But there really is no difference since the conversion from bits to position works regardless and should give the same position.

</readouts>

</lccdd>
7 changes: 7 additions & 0 deletions TestOB.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
void TestOB() {
TFile* eicFile = new TFile("reconTest.edm4eic.root");
TTree* eicTree = (TTree*)eicFile->Get("events");
eicTree->Draw("CentralCKFTrajectories.nMeasurements>>nM");
auto h0 = (TH1I*)gPad->GetPrimitive("nM");
cout << "Mean nMeasurements: " << h0->GetMean() << endl;
}
4 changes: 4 additions & 0 deletions TestOB.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash
ddsim --compactFile epic_craterlake_tracking_only_cut.xml --outputFile test.edm4hep.root --numberOfEvents 1000 --enableGun --gun.thetaMin 50*deg --gun.thetaMax 130*deg --gun.distribution eta --gun.particle pi- --gun.momentumMin 10*GeV --gun.momentumMax 10*GeV --gun.multiplicity 1
eicrecon -Pnthreads=1 -Pjana:debug_plugin_loading=1 -Ppodio:output_file=reconTest.edm4eic.root -Pdd4hep:xml_files=epic_craterlake_tracking_only_cut.xml -Ppodio:output_collections="MCParticles,CentralCKFTrajectories,CentralCKFTrackParameters,CentralCKFSeededTrackParameters,CentralCKFTruthSeededTrackParameters,CentralTrackVertices,ReconstructedChargedParticles,ReconstructedChargedParticleAssociations" test.edm4hep.root
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this is something I was just discussing with @veprbl yesterday. When using the xml_files interface, that makes sure that the specified geometry is used, but it crucially does not change the $DETECTOR_PATH variable. So, the correct top-level entry point will be used but potentially not the underlying detector-subsystem-specific files that are included by the toplevel.

(more later, MSc defense to attend now)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This is the method I have been using to run a simulation with just a few sub-detectors - in this case the silicon and vertex barrels - I take one of the xml files in epic/install/share/epic and cut out the bits I don't want. I assume this (usually) works as the links in these files all use $DETECTOR_PATH, but it feels like a very hacky way to do it and I can see it may not always work. What is the correct way to do it? (Where do these xml files come from anyway? Are they generated automatically by cmake --install?)

root -b TestOB.C reconTest.edm4eic.root
Loading
Loading