112 Acts::LayerVector &layersOutput)
const {
113 using enum Acts::AxisDirection;
115 ACTS_VERBOSE(
"Build layers: BARREL");
116 std::vector<std::shared_ptr<const ActsDetectorElement>> elements =
119 std::map<int, std::vector<std::shared_ptr<const Acts::Surface>>> layers{};
121 for (
const auto &element : elements) {
128 if(
id.layer_disk() >= 2)
continue;
131 if(
id.layer_disk() <= 1)
continue;
134 m_cfg.elementStore->push_back(element);
137 elementLayer =
id.layer_disk();
139 layers[elementLayer].push_back(element->surface().getSharedPtr());
143 if (
m_cfg.objDebugOutput) {
145 for (
auto &[key, layerSurfaces] : layers) {
147 std::stringstream name;
151 name <<
"obj/" <<
m_cfg.mode <<
"_brl_" << std::setfill(
'0') << std::setw(2)
152 << std::to_string(key) +
"_bec"
155 std::ofstream ofs{name.str()};
156 Acts::ObjVisualization3D vis{};
157 Acts::ViewConfig vc = Acts::s_viewSensitive;
158 vc.quarterSegments = 200;
159 for (
const auto &surface : layerSurfaces) {
160 Acts::GeometryView3D::drawSurface(vis, *surface, gctx,
161 Acts::Transform3::Identity(), vc);
168 ACTS_VERBOSE(
"Found " << layers.size() <<
" barrel layers");
170 if (
logger().doPrint(Acts::Logging::VERBOSE)) {
172 for (
const auto &[key, surfaces] : layers) {
173 Acts::ProtoLayer pl(gctx, surfaces);
174 ACTS_VERBOSE(
"Layer #" << n <<
" with layerKey: (" << key <<
")");
175 ACTS_VERBOSE(
" -> at rMin / rMax: " << pl.min(AxisR) <<
" / "
177 ACTS_VERBOSE(
" -> at zMin / zMax: " << pl.min(AxisZ) <<
" / "
184 for (
const auto &[key, surfaces] : layers) {
186 std::unique_ptr<Acts::ApproachDescriptor> approachDescriptor =
nullptr;
187 std::shared_ptr<const Acts::ProtoSurfaceMaterial> materialProxy =
nullptr;
190 Acts::ProtoLayer pl(gctx, surfaces);
191 pl.envelope[AxisR] =
m_cfg.barrelEnvelopeR;
192 pl.envelope[AxisZ] =
m_cfg.barrelEnvelopeZ;
194 double layerZ = pl.medium(AxisZ,
true);
195 double layerHalfZ = 0.5 * pl.range(AxisZ);
197 Acts::Transform3 transform(Translation3(0., 0., -layerZ));
200 std::shared_ptr<Acts::CylinderSurface> innerBoundary =
201 Acts::Surface::makeShared<Acts::CylinderSurface>(
202 transform, pl.min(AxisR), layerHalfZ);
204 std::shared_ptr<Acts::CylinderSurface> outerBoundary =
205 Acts::Surface::makeShared<Acts::CylinderSurface>(
206 transform, pl.max(AxisR), layerHalfZ);
208 std::shared_ptr<Acts::CylinderSurface> centralSurface =
209 Acts::Surface::makeShared<Acts::CylinderSurface>(
210 transform, (pl.min(AxisR) + pl.max(AxisR)) / 2.,
213 size_t binsPhi =
m_cfg.barrelMaterialBins.first;
214 size_t binsZ =
m_cfg.barrelMaterialBins.second;
216 Acts::BinUtility materialBinUtil(binsPhi, -
M_PI,
M_PI, Acts::closed,
218 materialBinUtil += Acts::BinUtility(binsZ, -layerHalfZ, layerHalfZ,
219 Acts::open, AxisZ, transform);
222 std::make_shared<const Acts::ProtoSurfaceMaterial>(materialBinUtil);
224 ACTS_VERBOSE(
"[L] Layer is marked to carry support material on Surface ( "
225 "inner=0 / center=1 / outer=2 ) : "
227 ACTS_VERBOSE(
"with binning: [" << binsPhi <<
", " << binsZ <<
"]");
229 ACTS_VERBOSE(
"Created ApproachSurfaces for cylinder layer at:");
230 ACTS_VERBOSE(
" - inner: R=" << pl.min(AxisR));
231 ACTS_VERBOSE(
" - central: R=" << (pl.min(AxisR) + pl.max(AxisR)) /
233 ACTS_VERBOSE(
" - outer: R=" << pl.max(AxisR));
236 innerBoundary->assignSurfaceMaterial(materialProxy);
238 std::vector<std::shared_ptr<const Acts::Surface>> aSurfaces;
239 aSurfaces.push_back(std::move(innerBoundary));
240 aSurfaces.push_back(std::move(centralSurface));
241 aSurfaces.push_back(std::move(outerBoundary));
244 std::make_unique<Acts::GenericApproachDescriptor>(std::move(aSurfaces));
247 auto phiEqual = [
this](
const Acts::Surface &
a,
248 const Acts::Surface &b) {
249 Acts::GeometryContext context = Acts::GeometryContext::dangerouslyDefaultConstruct();
250 return m_cfg.surfaceMatcher(context, AxisPhi, &
a, &b);
253 auto zEqual = [
this](
const Acts::Surface &
a,
254 const Acts::Surface &b) {
255 Acts::GeometryContext thisContext = Acts::GeometryContext::dangerouslyDefaultConstruct();
256 return m_cfg.surfaceMatcher(thisContext, AxisZ, &
a, &b);
261 auto& xsurfaces = surfaces;
262 auto countKey = [&xsurfaces](
auto equal) ->
size_t {
263 std::vector<const Acts::Surface *> keySurfaces;
264 for (
const auto &surface : xsurfaces) {
266 for (
const auto* existing : keySurfaces) {
267 if (equal(*surface, *existing)) {
273 keySurfaces.push_back(surface.get());
276 return keySurfaces.size();
279 size_t nModPhi = countKey(phiEqual);
280 size_t nModZ = countKey(zEqual);
282 ACTS_VERBOSE(
"Found " << nModPhi <<
" modules in phi " << nModZ
285 std::shared_ptr<Acts::Layer> layer;
287 size_t nBinsPhi = nModPhi *
m_cfg.numberOfBinsFactor;
288 size_t nBinsZ = nModZ *
m_cfg.numberOfBinsFactor;
289 layer =
m_cfg.layerCreator->cylinderLayer(gctx, surfaces, nBinsPhi,
290 nBinsZ, pl, transform,
291 std::move(approachDescriptor));
294 size_t nBinsPhi = nModPhi *
m_cfg.numberOfBinsFactor;
295 size_t nBinsZ = nModZ *
m_cfg.numberOfBinsFactor;
301 nBinsZ = nModZ *
m_cfg.numberOfInnermostLayerBinsFactor;
304 layer =
m_cfg.layerCreator->cylinderLayer(gctx, surfaces, nBinsPhi,
305 nBinsZ, pl, transform,
306 std::move(approachDescriptor));
308 layer =
m_cfg.layerCreator->cylinderLayer(
309 gctx, surfaces, Acts::equidistant, Acts::equidistant, pl, transform,
310 std::move(approachDescriptor));
313 layersOutput.push_back(layer);
317 std::size_t numPassiveLayers =
m_cfg.passiveBarrelLayerRadii.size();
318 ACTS_DEBUG(
"Configured to build " << numPassiveLayers <<
" passive central layers.");
319 if (numPassiveLayers != 0u) {
320 for (std::size_t icl = 0; icl < numPassiveLayers; ++icl) {
321 ACTS_VERBOSE(
"- build layer " << icl
322 <<
" with radius = " <<
m_cfg.passiveBarrelLayerRadii.at(icl)
323 <<
" and halfZ = " <<
m_cfg.passiveBarrelLayerHalflengthZ.at(icl)
324 <<
" and thickness = " <<
m_cfg.passiveBarrelLayerThickness.at(icl));
327 auto cBounds = std::make_shared<const Acts::CylinderBounds>(
328 m_cfg.passiveBarrelLayerRadii.at(icl),
m_cfg.passiveBarrelLayerHalflengthZ.at(icl));
331 std::shared_ptr<Acts::Layer> layer =
332 Acts::CylinderLayer::create(Transform3::Identity(), cBounds,
nullptr,
m_cfg.passiveBarrelLayerThickness.at(icl));
334 layersOutput.push_back(layer);
340 Acts::LayerVector &layersOutput,
int type)
const
342 using enum Acts::AxisDirection;
344 ACTS_VERBOSE(
"Build layers: " << (
type < 0 ?
"NEGATIVE" :
"POSITIVE")
346 std::vector<std::shared_ptr<const ActsDetectorElement>> elements =
348 std::map<std::tuple<int, int, int>, std::vector<const Acts::Surface *>>
351 for (
const auto &element : elements) {
354 if (
id.bec() *
type <= 0) {
359 if(
id.layer_disk() >= 3)
continue;
362 if(
id.layer_disk() <= 2)
continue;
365 m_cfg.elementStore->push_back(element);
367 std::tuple<int, int, int> key{
id.bec(),
id.layer_disk(),
id.eta_module()};
369 initialLayers[key].push_back(&element->surface());
372 ACTS_VERBOSE(
"Found " << initialLayers.size() <<
" "
373 << (
type < 0 ?
"NEGATIVE" :
"POSITIVE")
374 <<
" ENDCAP inital layers");
376 std::vector<Acts::ProtoLayer> protoLayers;
377 protoLayers.reserve(initialLayers.size());
379 for (
const auto &[key, surfaces] : initialLayers) {
380 auto &pl = protoLayers.emplace_back(gctx, surfaces);
381 pl.envelope[AxisR] =
m_cfg.endcapEnvelopeR;
382 pl.envelope[AxisZ] =
m_cfg.endcapEnvelopeZ;
386 std::sort(protoLayers.begin(), protoLayers.end(),
387 [
type](
const Acts::ProtoLayer &
a,
const Acts::ProtoLayer &b) {
388 double midA = (a.min(AxisZ) + a.max(AxisZ)) / 2.0;
389 double midB = (b.min(AxisZ) + b.max(AxisZ)) / 2.0;
397 auto plPrintZ = [](
const auto &pl) -> std::string {
398 std::stringstream
ss;
399 double zMid = (pl.min(AxisZ) + pl.max(AxisZ)) / 2.0;
400 ss <<
" < " << pl.min(AxisZ) <<
" | " << zMid <<
" | "
401 << pl.max(AxisZ) <<
" > ";
404 if (
logger().doPrint(Acts::Logging::VERBOSE)) {
405 for (
const auto &pl : protoLayers) {
407 ACTS_VERBOSE(
" -> at < zMin | zMid | zMax >: " << plPrintZ(pl));
409 ACTS_VERBOSE(
" -> at rMin / rMax: " << pl.min(AxisR) <<
" / "
414 std::vector<Acts::ProtoLayer> mergedProtoLayers;
416 if (m_cfg.doEndcapLayerMerging) {
417 mergedProtoLayers.push_back(protoLayers.front());
418 std::vector<const Acts::Surface *> surfaces;
419 for (
size_t i = 1;
i < protoLayers.size();
i++) {
420 auto &pl = protoLayers[
i];
421 auto &pl_prev = mergedProtoLayers.back();
423 ACTS_VERBOSE(
"Compare: " << plPrintZ(pl_prev) <<
" and " << plPrintZ(pl));
424 bool overlap = (pl.min(AxisZ) <= pl_prev.max(AxisZ) &&
425 pl.max(AxisZ) >= pl_prev.min(AxisZ));
426 ACTS_VERBOSE(
" -> overlap? " << (overlap ?
"yes" :
"no"));
428 ACTS_VERBOSE(
" ===> merging");
430 surfaces.reserve(pl.surfaces().size() + pl_prev.surfaces().size());
431 surfaces.insert(surfaces.end(), pl.surfaces().begin(),
432 pl.surfaces().end());
433 surfaces.insert(surfaces.end(), pl_prev.surfaces().begin(),
434 pl_prev.surfaces().end());
435 mergedProtoLayers.pop_back();
437 mergedProtoLayers.emplace_back(gctx, std::move(surfaces));
438 new_pl.envelope[AxisR] = pl.envelope[AxisR];
439 new_pl.envelope[AxisZ] = pl.envelope[AxisZ];
441 mergedProtoLayers.push_back(std::move(pl));
445 ACTS_VERBOSE(
"" << mergedProtoLayers.size() <<
" "
446 << (
type < 0 ?
"NEGATIVE" :
"POSITIVE")
447 <<
" ENDCAP layers remain after merging");
449 mergedProtoLayers = std::move(protoLayers);
452 if (m_cfg.objDebugOutput) {
453 for (
size_t i = 0;
i < mergedProtoLayers.size();
i++) {
455 std::stringstream
ss;
456 ss <<
"obj/" << m_cfg.mode <<
"_" << (
type < 0 ?
"neg" :
"pos")
457 <<
"_disk_" << std::setfill(
'0') << std::setw(2) <<
i <<
".obj";
459 std::ofstream ofs{
ss.str()};
460 Acts::ObjVisualization3D vis{};
461 Acts::ViewConfig vc = Acts::s_viewSensitive;
462 vc.quarterSegments = 200;
463 for (
const auto &surface : mergedProtoLayers[i].surfaces()) {
464 Acts::GeometryView3D::drawSurface(vis, *surface, gctx,
465 Acts::Transform3::Identity(), vc);
472 std::vector<std::shared_ptr<const Surface>> ownedSurfaces;
473 for (
const auto &pl : mergedProtoLayers) {
475 std::unique_ptr<Acts::ApproachDescriptor> approachDescriptor =
nullptr;
476 std::shared_ptr<const Acts::ProtoSurfaceMaterial> materialProxy =
nullptr;
478 double layerZ = pl.medium(AxisZ);
479 double layerHalfZ = 0.5 * pl.range(AxisZ);
480 double layerThickness = pl.range(AxisZ);
482 double layerZInner = layerZ - layerHalfZ;
483 double layerZOuter = layerZ + layerHalfZ;
485 if (std::abs(layerZInner) > std::abs(layerZOuter))
488 std::vector<std::shared_ptr<const Acts::Surface>> aSurfaces;
490 Acts::Transform3 transformNominal(Translation3(0., 0., layerZ));
491 Acts::Transform3 transformInner(Translation3(0., 0., layerZInner));
492 Acts::Transform3 transformOuter(Translation3(0., 0., layerZOuter));
494 std::shared_ptr<Acts::DiscSurface> innerBoundary =
495 Acts::Surface::makeShared<Acts::DiscSurface>(
496 transformInner, pl.min(AxisR), pl.max(AxisR));
497 aSurfaces.push_back(innerBoundary);
499 std::shared_ptr<Acts::DiscSurface> nominalSurface =
500 Acts::Surface::makeShared<Acts::DiscSurface>(
501 transformNominal, pl.min(AxisR), pl.max(AxisR));
502 aSurfaces.push_back(nominalSurface);
504 std::shared_ptr<Acts::DiscSurface> outerBoundary =
505 Acts::Surface::makeShared<Acts::DiscSurface>(
506 transformOuter, pl.min(AxisR), pl.max(AxisR));
507 aSurfaces.push_back(outerBoundary);
509 if(layerThickness > 2_mm) {
510 ACTS_VERBOSE(
"Wide disc layer ("<< layerThickness <<
") => adding cylinder like approach surfaces");
511 Acts::Transform3 trf{Translation3{0, 0, layerZ}};
513 Acts::Surface::makeShared<Acts::CylinderSurface>(
514 trf, pl.min(AxisR), layerHalfZ);
515 aSurfaces.push_back(cylinderInner);
518 Acts::Surface::makeShared<Acts::CylinderSurface>(
519 trf, pl.max(AxisR), layerHalfZ);
520 aSurfaces.push_back(cylinderOuter);
524 size_t matBinsPhi = m_cfg.endcapMaterialBins.first;
525 size_t matBinsR = m_cfg.endcapMaterialBins.second;
527 Acts::BinUtility materialBinUtil(matBinsPhi, -
M_PI,
M_PI, Acts::closed,
530 Acts::BinUtility(matBinsR, pl.min(AxisR), pl.max(AxisR),
531 Acts::open, AxisR, transformNominal);
534 std::make_shared<const Acts::ProtoSurfaceMaterial>(materialBinUtil);
536 ACTS_VERBOSE(
"[L] Layer is marked to carry support material on Surface ( "
537 "inner=0 / center=1 / outer=2 ) : "
539 ACTS_VERBOSE(
"with binning: [" << matBinsPhi <<
", " << matBinsR <<
"]");
541 ACTS_VERBOSE(
"Created ApproachSurfaces for disc layer at:");
542 ACTS_VERBOSE(
" - inner: Z=" << layerZInner);
543 ACTS_VERBOSE(
" - central: Z=" << layerZ);
544 ACTS_VERBOSE(
" - outer: Z=" << layerZOuter);
547 innerBoundary->assignSurfaceMaterial(materialProxy);
551 bool isITk = m_cfg.mode == Mode::ITkPixelInner ||
552 m_cfg.mode == Mode::ITkPixelOuter ||
553 m_cfg.mode == Mode::ITkStrip;
555 std::map<int, std::set<int>> phiModuleByRing;
558 for (
const auto &srf : pl.surfaces()) {
561 auto id = elm->identityHelper();
563 if(m_cfg.mode == Mode::ITkStrip || !isITk) {
564 ring_number =
id.eta_module();
567 ring_number =
id.layer_disk();
569 phiModuleByRing[ring_number].insert(
id.phi_module());
572 size_t nModPhi = std::numeric_limits<size_t>::max();
573 for(
const auto& [ring, phiModules] : phiModuleByRing) {
574 nModPhi = std::min(nModPhi, phiModules.size());
577 size_t nModR = phiModuleByRing.size();
579 ACTS_VERBOSE(
"Identifier reports: " << nModPhi <<
" is lowest for " << nModR
582 size_t nBinsPhi = nModPhi * m_cfg.numberOfBinsFactor;
583 size_t nBinsR = nModR * m_cfg.numberOfBinsFactor;
585 ACTS_VERBOSE(
"Creating r x phi binned layer with " << nBinsR <<
" x "
586 << nBinsPhi <<
" bins");
590 std::make_unique<Acts::GenericApproachDescriptor>(aSurfaces);
593 ownedSurfaces.clear();
594 ownedSurfaces.reserve(pl.surfaces().size());
595 std::transform(pl.surfaces().begin(), pl.surfaces().end(),
596 std::back_inserter(ownedSurfaces),
597 [](
const auto &s) { return s->getSharedPtr(); });
599 auto layer = m_cfg.layerCreator->discLayer(gctx, ownedSurfaces, nBinsR,
600 nBinsPhi, pl, Transform3::Identity(),
601 std::move(approachDescriptor));
603 layersOutput.push_back(layer);