feat: switch BIC, FEMC, and EcalBarrelScFi to paramVolume1D#1051
feat: switch BIC, FEMC, and EcalBarrelScFi to paramVolume1D#1051wdconinc wants to merge 6 commits into
Conversation
af6aa53 to
3bcf1e6
Compare
wdconinc
left a comment
There was a problem hiding this comment.
For BIC, i_module is now identical to i_y.
6757f31 to
5b3378d
Compare
5b3378d to
efd95d0
Compare
efd95d0 to
ad30ff6
Compare
|
I think copilot has successfully convinced me that this geometry change modifies stepping in such a way that we don't expect the same hits for tracks that go through the modified geometry since the navigator behaves differently for parametrized and non-parametrized volumes. |
There was a problem hiding this comment.
Pull request overview
This PR updates the DD4hep geometry construction for the Forward ECal (FEMC) and Barrel Imaging Calorimeter (BIC) to use paramVolume1D (Geant4 parameterised placement) instead of explicit placement loops, with the goal of reducing the number of G4PVPlacement instances and improving Geant4 navigation performance in these subdetectors.
Changes:
- Replace per-column block placement loops in FEMC with a 1D parameterised placement per row.
- Replace per-module placement loops in BIC’s
xy_layoutwith a 1D parameterised placement (requiringnx == 1) and reconstruct per-copyDetElementplacements from the parameterisation’s placement list.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/forwardEcal_geo.cpp | Switch FEMC block column placements to paramVolume1D using an Assembly template to reduce placements per row. |
| src/BarrelCalorimeterImaging_geo.cpp | Switch BIC module placements in xy_layout to paramVolume1D (1D along Y), and rebuild per-module DetElement placements from the parameterised placement list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
EcalBarrelScFi |
| slice_thickness / 2.0); | ||
| Volume frow_vol("FEMCFiberRow", frow, Wpowder); | ||
| frow_vol.setAttributes(desc, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr()); | ||
| for (int iy = 0; iy < ny; iy++) { |
There was a problem hiding this comment.
Can this loop be also using paramVolume1D?
There was a problem hiding this comment.
No, there is staggering of the layers inside it. That makes it harder to do. It may (@veprbl claims) be possible to do this with two paramVolume1D instances (one for even, one for odd), or it is may be possible to do this with a 2-fiber unit cell, but in any case it is more complicated than just a parametrized placement. And it would likely change the numbering scheme of the fibers. And it would get is proportionally less gain than this part gets us since we are now starting to bump up against other irreducible effects.
There was a problem hiding this comment.
No, there is staggering of the layers inside it.
I guess what I meant here is that you can't easily use paramVolume2D.
There was a problem hiding this comment.
with two paramVolume1D
with one paramVolume3D
There was a problem hiding this comment.
Ok, I'll need a picture for this...
| //rows of blocks | ||
| //int nRowBlock = map->maxRowBlock(); //# of rows | ||
| int nRowBlock = mMaxRowBlock; | ||
| for (int r = 0; r < nRowBlock; r++) { |
|
Sorry I did not realize this was up. Now I'm checking out and compiling. I will be testing this (maybe next week). |
Co-authored-by: Wouter Deconinck <wdconinc@gmail.com>
for more information, see https://pre-commit.ci
Replace explicit placeVolume per fiber with paramVolume1D (one call per
z-row per grid), reducing TGeoNode count from O(N_fibers) to O(N_rows).
Each z-row of fibers is wrapped in a row Assembly with physVolID("z",
row_index), which provides unique VolumeManager cell-ID codes across rows.
Within each row, paramVolume1D encodes the fiber column index via the
Geant4 copy number into the "fiber" readout field.
Readout semantics change: the "z" field now encodes the fiber row index
within the grid (previously always 0), and "fiber" encodes the column
index within that row (previously a sequential global-per-grid ID).
Also fixes an O(N_fibers × N_grids) performance issue in geometry
initialization: the TGeoPolygon for each grid is now built once, not
once per fiber checked against that grid.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…0 for segmentation
The 'z' field in EcalBarrelScFiHits readout is used by CartesianStripZ
segmentation (identifier_x="z") to encode the longitudinal position
along the fiber axis. The physVolID z must therefore remain 0 from the
geometry side.
Replace the previous approach of addPhysVolID("z", row_index) on the
row Assembly with addPhysVolID("fiber", row_index * n_x_max), where
n_x_max is the maximum row length rounded up to the next power of two.
DD4hep ORs all physVolID values along the path into the cellID code:
- init: fiber = row_index * n_x_max | 0 = row_index * n_x_max
- runtime: fiber = row_index * n_x_max | copy_no = row_index * n_x_max + copy_no
This encodes (row, column) into the existing 16-bit fiber field with no
bit overlap, preserving uniqueness within each grid and leaving the z
field entirely free for the longitudinal segmentation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace three explicit placement loops inside the fEcalWScFi ScFi block hierarchy with DD4hep paramVolume1D placements: - Tower rows (trow) in block: 4 → 1 paramVolume1D (uniform Y spacing) - Towers in tower row: 4 → 1 paramVolume1D (uniform X spacing) - Fiber columns (fcol) in fiber row: 26 → 1 paramVolume1D (uniform X spacing) The staggered fiber row (frow) loop (ny=30) is kept as explicit placements since alternating x-offset (0 / +½ pitch) prevents simple 1D parameterisation. Net effect: ~400× reduction in G4PVPlacement count per block (from ~12,480 to ~30 per block × ~1073 blocks). The block-level paramVolume1D (already present) is unchanged. physVolID encoding is preserved: copy number equals the original loop index for y (0-3), x (0-3), and fiber_x (0-25). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
bb7123c to
5c941de
Compare
|
something is wrong... https://www.star.bnl.gov/public/spin/akio/epic/map.homo.png. Nope that was my bug in plotting. Geometry looks good in dd_web_display for both Homogeneous and SiPM. Hit mapping seems to be same as before. dE for gamma looks good. |
Briefly, what does this PR introduce?
This PR converts loops of explicit placement to parametrized placement in the BIC, FEMC, and EcalBarrelScFi detectors. This reduces the TGeoNode count, speeds up geometry initialization, and reduces memory use.
For BIC and FEMC: modules/towers are placed via
paramVolume1D.For EcalBarrelScFi: scintillating fibers are placed via
paramVolume1D, one call per HCP z-row per readout grid. Each z-row is wrapped in a thin Assembly withphysVolID("z", row_index)to give unique VolumeManager cell-ID codes across rows (required because DD4hep parameterised volumes can only carryvolID=0; the Geant4 copy number encodes the column index into the "fiber" readout field at runtime).Readout change for EcalBarrelScFi: the
zfield now encodes the fiber row index within the grid (previously always 0), andfiberencodes the column index within that row (previously a sequential per-grid ID). The total set of unique cell IDs is unchanged; the encoding has changed.Also fixes an O(N_fibers × N_grids) performance issue in geometry initialization: the TGeoPolygon for each grid is now built once instead of once per fiber.
What kind of change does this PR introduce?
Please check if this PR fulfills the following:
Does this PR introduce breaking changes? What changes might users need to make to their code?
EcalBarrelScFi readout: the
zandfiberfields have new semantics (row index and column index within row, respectively). Reconstruction code that uses these fields for individual fiber identification needs updating.Does this PR change default behavior?
Yes — EcalBarrelScFi readout IDs change encoding.