From 9cad5e2117982541d2cebcb360c4577320c47ca2 Mon Sep 17 00:00:00 2001 From: Giovanni Marchiori <39376142+giovannimarchiori@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:46:34 +0200 Subject: [PATCH] Make topoclustering work with new theta-module merged readout (#63) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Âcomment unneeded code * add xml files for calibration of latest FCCee ALLEGRO detector version with 1545 modules and module-theta readout * move some printout before the assert to easier debugging * modify LAr gap thickness to have 1536 modules * remove extra spaces * remove debug code. Add case of diagonal neighbours * fix calculation of diagonal cells, simplify and document code * cleanup * add comment --- .../DetCommon/include/DetCommon/DetUtils.h | 26 +- Detector/DetCommon/src/DetUtils.cpp | 252 +++++++++++++++++- .../FCCee_ECalBarrel_thetamodulemerged.xml | 13 +- ...alBarrel_thetamodulemerged_calibration.xml | 136 ++++++++++ ..._ECalBarrel_thetamodulemerged_upstream.xml | 136 ++++++++++ .../src/ECalBarrelInclined_geo.cpp | 9 +- .../FCCSWGridModuleThetaMerged.h | 8 +- 7 files changed, 551 insertions(+), 29 deletions(-) create mode 100644 Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged_calibration.xml create mode 100644 Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged_upstream.xml diff --git a/Detector/DetCommon/include/DetCommon/DetUtils.h b/Detector/DetCommon/include/DetCommon/DetUtils.h index 148bc895..2ece5321 100644 --- a/Detector/DetCommon/include/DetCommon/DetUtils.h +++ b/Detector/DetCommon/include/DetCommon/DetUtils.h @@ -4,7 +4,7 @@ // FCCSW #include "DetSegmentation/FCCSWGridPhiEta.h" #include "DetSegmentation/FCCSWGridPhiTheta.h" - +#include "DetSegmentation/FCCSWGridModuleThetaMerged.h" // DD4hep #include "DD4hep/DetFactoryHelper.h" @@ -84,6 +84,24 @@ std::vector neighbours(const dd4hep::DDSegmentation::BitFieldCoder& aD const std::vector& aFieldCyclic = {false, false, false, false}, bool aDiagonal = true); +/** Special version of the neighbours function for the readout with module and theta merged cells + * Compared to the standard version, it needs a reference to the segmentation class to + * access the number of merged cells per layer. The other parameters and return value are the same + * @param[in] aSeg Reference to the segmentation object. + * @param[in] aDecoder Handle to the bitfield decoder. + * @param[in] aFieldNames Names of the fields for which neighbours are found. + * @param[in] aFieldExtremes Minimal and maximal values for the fields. + * @param[in] aCellId ID of cell. + * @param[in] aDiagonal If diagonal neighbours should be included (all combinations of fields). + * return Vector of neighbours. + */ +std::vector neighbours_ModuleThetaMerged(const dd4hep::DDSegmentation::FCCSWGridModuleThetaMerged& aSeg, + const dd4hep::DDSegmentation::BitFieldCoder& aDecoder, + const std::vector& aFieldNames, + const std::vector>& aFieldExtremes, + uint64_t aCellId, + bool aDiagonal = false); + /** Get minimal and maximal values that can be decoded in the fields of the bitfield. * @param[in] aDecoder Handle to the bitfield decoder. * @param[in] aFieldNames Names of the fields for which extremes are found. @@ -146,16 +164,18 @@ std::array numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentati */ std::array numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::CartesianGridXYZ& aSeg); -/** Get the number of cells for the volume and a given Phi-Eta segmentation. +/** Get the number of cells for the volume and a given Phi-Eta / Phi-Theta / Module-Theta segmentation. * It is assumed that the volume has a cylindrical shape (and full azimuthal coverage) * and that it is centred at (0,0,0). * For an example see: Test/TestReconstruction/tests/options/testcellcountingPhiEta.py. * @warning No offset in segmentation is currently taken into account. * @param[in] aVolumeId The volume for which the cells are counted. * @param[in] aSeg Handle to the segmentation of the volume. - * return Array of the number of cells in (phi, eta) and the minimum eta ID. + * return Array of the number of cells in (phi, eta) / (phi, theta) / (module, theta) and the minimum eta / theta ID. */ std::array numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::FCCSWGridPhiEta& aSeg); +std::array numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::FCCSWGridPhiTheta& aSeg); +std::array numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::FCCSWGridModuleThetaMerged& aSeg); /** Get the number of cells for the volume and a given R-phi segmentation. * It is assumed that the volume has a cylindrical shape - TGeoTube (and full azimuthal coverage) diff --git a/Detector/DetCommon/src/DetUtils.cpp b/Detector/DetCommon/src/DetUtils.cpp index 3bb69167..1aedbee6 100644 --- a/Detector/DetCommon/src/DetUtils.cpp +++ b/Detector/DetCommon/src/DetUtils.cpp @@ -16,6 +16,9 @@ #define MM_2_CM 0.1 #endif +#include + +#include namespace det { namespace utils { @@ -78,7 +81,7 @@ std::vector> combinations(int N, int K) { std::vector> permutations(int K) { std::vector> indexes; - int N = pow(2, K); // number of permutations with repetition of 2 numbers (0,1) + int N = pow(2, K); // number of permutations with repetition of 2 numbers (-1,1) for (int i = 0; i < N; i++) { // permutation = binary representation of i std::vector tmp; @@ -94,11 +97,13 @@ std::vector> permutations(int K) { return indexes; } +// use it for field module/phi int cyclicNeighbour(int aCyclicId, std::pair aFieldExtremes) { + int nBins = aFieldExtremes.second - aFieldExtremes.first + 1; if (aCyclicId < aFieldExtremes.first) { - return aFieldExtremes.second + aCyclicId; + return (aFieldExtremes.second + 1 - ((aFieldExtremes.first - aCyclicId) % nBins) ); } else if (aCyclicId > aFieldExtremes.second) { - return aCyclicId % (aFieldExtremes.second + 1); + return ( ((aCyclicId - aFieldExtremes.first) % nBins) + aFieldExtremes.first) ; } return aCyclicId; } @@ -111,7 +116,11 @@ std::vector neighbours(const dd4hep::DDSegmentation::BitFieldCoder& aD dd4hep::DDSegmentation::CellID cID = aCellId; for (uint itField = 0; itField < aFieldNames.size(); itField++) { const auto& field = aFieldNames[itField]; - dd4hep::DDSegmentation::CellID id = aDecoder.get(cID,field); + // note: get(..) returns a FieldID i.e. a int64_t + // while CellID (used previously) is a uint64_t + // similarly, the second argument of set(..) + // is signed (FieldID) rather than unsigned (CellID) + int id = aDecoder.get(cID,field); if (aFieldCyclic[itField]) { aDecoder[field].set(cID, cyclicNeighbour(id - 1, aFieldExtremes[itField])); neighbours.emplace_back(cID); @@ -119,15 +128,15 @@ std::vector neighbours(const dd4hep::DDSegmentation::BitFieldCoder& aD neighbours.emplace_back(cID); } else { if (id > aFieldExtremes[itField].first) { - aDecoder.set(cID, field, id - 1); + aDecoder[field].set(cID, id - 1); neighbours.emplace_back(cID); } if (id < aFieldExtremes[itField].second) { - aDecoder.set(cID, field, id + 1); + aDecoder[field].set(cID, id + 1); neighbours.emplace_back(cID); } } - aDecoder.set(cID, field, id); + aDecoder[field].set(cID, id); } if (aDiagonal) { std::vector fieldIds; // initial IDs @@ -150,7 +159,7 @@ std::vector neighbours(const dd4hep::DDSegmentation::BitFieldCoder& aD for (uint iField = 0; iField < indexes[iComb].size(); iField++) { if (aFieldCyclic[indexes[iComb][iField]]) { aDecoder[aFieldNames[indexes[iComb][iField]]].set(cID, cyclicNeighbour(fieldIds[indexes[iComb][iField]] + calculation[iCalc][iField], - aFieldExtremes[indexes[iComb][iField]]) ); + aFieldExtremes[indexes[iComb][iField]]) ); } else if ((calculation[iCalc][iField] > 0 && fieldIds[indexes[iComb][iField]] < aFieldExtremes[indexes[iComb][iField]].second) || (calculation[iCalc][iField] < 0 && @@ -175,6 +184,176 @@ std::vector neighbours(const dd4hep::DDSegmentation::BitFieldCoder& aD return neighbours; } +// use it for module-theta merged readout (FCCSWGridModuleThetaMerged) +std::vector neighbours_ModuleThetaMerged(const dd4hep::DDSegmentation::FCCSWGridModuleThetaMerged& aSeg, + const dd4hep::DDSegmentation::BitFieldCoder& aDecoder, + const std::vector& aFieldNames, + const std::vector>& aFieldExtremes, + uint64_t aCellId, + bool aDiagonal) { + + std::vector neighbours; + + // check that field names and extremes have the proper length + if (aFieldNames.size() != 3 || aFieldExtremes.size()!=3) { + std::cout << "ERROR: the vectors aFieldNames and aFieldSizes should be of length = 3, corresponding to the theta/module/layer fields" << std::endl; + std::cout << "ERROR: will return empty neighbour map" << std::endl; + return neighbours; + } + + // find index of layer, module and theta in field extremes vector + int idModuleField(-1); + int idThetaField(-1); + int idLayerField(-1); + for (uint itField = 0; itField < aFieldNames.size(); itField++) { + if (aFieldNames[itField] == aSeg.fieldNameModule()) + idModuleField = (int) itField; + else if (aFieldNames[itField] == aSeg.fieldNameTheta()) + idThetaField = (int) itField; + else if (aFieldNames[itField] == aSeg.fieldNameLayer()) + idLayerField = (int) itField; + + } + if (idModuleField < 0) { + std::cout << "WARNING: module field " << aSeg.fieldNameModule() << " not found in aFieldNames vector" << std::endl; + std::cout << "WARNING: will return empty neighbour map" << std::endl; + return neighbours; + } + if (idThetaField < 0) { + std::cout << "WARNING: theta field " << aSeg.fieldNameTheta() << " not found in aFieldNames vector" << std::endl; + std::cout << "WARNING: will return empty neighbour map" << std::endl; + return neighbours; + } + if (idLayerField < 0) { + std::cout << "WARNING: layer field " << aSeg.fieldNameLayer() << " not found in aFieldNames vector" << std::endl; + std::cout << "WARNING: will return empty neighbour map" << std::endl; + return neighbours; + } + + // retrieve layer/module/theta of cell under study + int layer_id = aDecoder.get(aCellId, aFieldNames[idLayerField]); + int module_id = aDecoder.get(aCellId, aFieldNames[idModuleField]); + int theta_id = aDecoder.get(aCellId, aFieldNames[idThetaField]); + + // now find the neighbours + dd4hep::DDSegmentation::CellID cID = aCellId; + + // for neighbours across different layers, we have to take into + // account that merging along module and/or theta could be different + // so one cell in layer N could be neighbour to several in layer N+-1 + // The cells are classified in a different way whether they are + // direct neighbours (common surface), diagonal neighbours (common edge or vertex) + // or neither. + // To decide this, we need to check how the cells are related in both directions: + // neighbours (edge at least partially in common), diagonal neigbours (common vertex), + // none + int neighbourTypeModuleDir; // 0: not neighbour; 1: diagonal neighbour; 2: neighbour in module direction + int neighbourTypeThetaDir; // 0: not neighbour; 1: diagonal neighbour; 2: neighbour in module direction + + for (int deltaLayer = -1; deltaLayer<2; deltaLayer+=2) { + + // no neighbours in layer N-1 for innermost layer + if (layer_id == aFieldExtremes[idLayerField].first && deltaLayer<0) continue; + // and in layer N+1 for outermost layer + if (layer_id == aFieldExtremes[idLayerField].second && deltaLayer>0) continue; + + // set layer field of neighbour cell + aDecoder.set(cID, aSeg.fieldNameLayer(), layer_id + deltaLayer); + + // find the neighbour(s) in module and theta + // if the numbers of module (theta) merged cells across 2 layers are the + // same then we just take the same module (theta) ID + // otherwise, we need to do some math to account for the different mergings + // note: even if number of merged cells in layer-1 is larger, a cell + // in layer could neighbour more than one cell in layer-1 if the merged + // cells are not aligned, for example if cells are grouped by 3 in a layer + // and by 4 in the next one, cell 435 in the former (which groups together + // 435-436-437) will be neighbour to cells 432 and 436 of the latter + // this might introduce duplicates, we will remove them later + // another issue is that it could add spurious cells beyond the maximum module number + // to prevent this we would need to know the max module number in layer -1 + // which would require modifying this function passing the extrema for all layers + // instead of the extrema only for a certain layer + // this border effect is also present in the original method.. + for (int i=-1; i <= aSeg.mergedThetaCells(layer_id); i++) { + int theta_id_neighbour = (theta_id + i) - ((theta_id + i) % aSeg.mergedThetaCells(layer_id+deltaLayer)); + if (theta_id_neighbour >= theta_id && theta_id_neighbour < (theta_id + aSeg.mergedThetaCells(layer_id))) neighbourTypeThetaDir = 2; + else if (theta_id_neighbour < theta_id && theta_id_neighbour > (theta_id - aSeg.mergedThetaCells(layer_id+deltaLayer))) neighbourTypeThetaDir = 2; + else if (theta_id_neighbour == (theta_id + aSeg.mergedThetaCells(layer_id))) neighbourTypeThetaDir = 1; + else if (theta_id_neighbour == (theta_id - aSeg.mergedThetaCells(layer_id+deltaLayer))) neighbourTypeThetaDir = 1; + else neighbourTypeThetaDir = 0; + + // if there is no point of contact along theta, no need to check also for module direction + if (neighbourTypeThetaDir == 0) continue; + // if we are not considering diagonal neighbours, and cells in theta have only an edge in common, then skip + if (!aDiagonal && neighbourTypeThetaDir == 1) continue; + // otherwise, check status along module direction + for (int j=-1; j <= aSeg.mergedModules(layer_id); j++) { + int module_id_neighbour = (module_id + j) - ((module_id + j) % aSeg.mergedModules(layer_id+deltaLayer)); + int module_id_neighbour_cyclic = cyclicNeighbour(module_id_neighbour, + aFieldExtremes[idModuleField] + ); + + if (module_id_neighbour >= module_id && module_id_neighbour < (module_id + aSeg.mergedModules(layer_id))) neighbourTypeModuleDir = 2; + else if (module_id_neighbour < module_id && module_id_neighbour > (module_id - aSeg.mergedModules(layer_id+deltaLayer))) neighbourTypeModuleDir = 2; + else if (module_id_neighbour == (module_id + aSeg.mergedModules(layer_id))) neighbourTypeModuleDir = 1; + else if (module_id_neighbour == (module_id - aSeg.mergedModules(layer_id+deltaLayer))) neighbourTypeModuleDir = 1; + else neighbourTypeModuleDir = 0; + + // if there is no point of contact along module, then skip + if (neighbourTypeModuleDir == 0) continue; + // otherwise: if neighbours along both module and theta, or along one of the two + // and we also consider diagonal neighbours, then add cells to list of neighbours + if ( (neighbourTypeModuleDir == 2 && neighbourTypeThetaDir==2) || + (aDiagonal && neighbourTypeThetaDir > 0 && neighbourTypeModuleDir>0) ) { + aDecoder.set(cID, aSeg.fieldNameModule(), module_id_neighbour_cyclic); + aDecoder.set(cID, aSeg.fieldNameTheta(), theta_id_neighbour); + neighbours.emplace_back(cID); + } + } + } + } + // reset cellID + // aDecoder.set(cID, aSeg.fieldNameModule(), module_id); + // aDecoder.set(cID, aSeg.fieldNameTheta(), theta_id); + + // for neighbours in module/theta direction at same layer_id, do +-nMergedCells instead of +-1 + aDecoder.set(cID, aSeg.fieldNameLayer(), layer_id); + // loop over theta cells + for (int i=-1; i<=1; i++) { + // calculate theta_id of neighbour + int theta_id_neighbour = theta_id + i*aSeg.mergedThetaCells(layer_id); + // check that it is within the ranges + if ( + (theta_id_neighbour < aFieldExtremes[idThetaField].first) || + (theta_id_neighbour > aFieldExtremes[idThetaField].second) + ) continue; + // set theta_id of cell ID + aDecoder[aSeg.fieldNameTheta()].set(cID, theta_id + i*aSeg.mergedThetaCells(layer_id)); + // loop over modules + for (int j=-1; j<=1; j++) { + // skip the cell under study (i==j==0) + if (i==0 && j==0) continue; + // calculate module_id of neighbour + int newid = cyclicNeighbour(module_id + j*aSeg.mergedModules(layer_id), aFieldExtremes[idModuleField]); + newid -= (newid % aSeg.mergedModules(layer_id)); + // set module_if of cell ID + aDecoder[aSeg.fieldNameModule()].set(cID, newid); + // add cell to neighbour list + if ( i==0 || j==0 || aDiagonal ) { // first two conditions correspond to non diagonal neighbours + neighbours.emplace_back(cID); + } + } + } + + // remove duplicates + std::unordered_set s; + for (uint64_t i : neighbours) + s.insert(i); + neighbours.assign( s.begin(), s.end() ); + return neighbours; +} + std::vector> bitfieldExtremes(const dd4hep::DDSegmentation::BitFieldCoder& aDecoder, const std::vector& aFieldNames) { std::vector> extremes; @@ -265,6 +444,11 @@ std::array tubeEtaExtremes(uint64_t aVolumeId) { // eta segmentation calculate maximum eta from the inner radius (no offset is taken into account) double maxEta = 0; double minEta = 0; + + double rIn = sizes.x(); + double rOut = sizes.y(); + double dZ = sizes.z(); + // check if it is a cylinder centred at z=0 dd4hep::VolumeManager volMgr = dd4hep::Detector::getInstance().volumeManager(); auto detelement = volMgr.lookupDetElement(aVolumeId); @@ -272,13 +456,20 @@ std::array tubeEtaExtremes(uint64_t aVolumeId) { double outGlobal[3]; double inLocal[] = {0, 0, 0}; // to get middle of the volume transformMatrix.LocalToMaster(inLocal, outGlobal); - if (outGlobal[2] < 1e-10) { + double zCenter = outGlobal[2]; + if (fabs(zCenter) < 1e-10) { // this assumes cylinder centred at z=0 - maxEta = CLHEP::Hep3Vector(sizes.x(), 0, sizes.z()).eta(); + maxEta = CLHEP::Hep3Vector(rIn, 0, dZ).eta(); minEta = -maxEta; } else { - maxEta = CLHEP::Hep3Vector(sizes.x(), 0, std::max(sizes.z() + outGlobal[2], -sizes.z() + outGlobal[2])).eta(); - minEta = CLHEP::Hep3Vector(sizes.y(), 0, std::min(sizes.z() + outGlobal[2], -sizes.z() + outGlobal[2])).eta(); + maxEta = std::max( + CLHEP::Hep3Vector(rIn, 0, zCenter+dZ).eta(), + CLHEP::Hep3Vector(rOut, 0, zCenter+dZ).eta() + ); + minEta = std::min( + CLHEP::Hep3Vector(rIn, 0, zCenter-dZ).eta(), + CLHEP::Hep3Vector(rOut, 0, zCenter-dZ).eta() + ); } return {minEta, maxEta}; } @@ -338,6 +529,43 @@ std::array numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentati return {phiCellNumber, cellsEta, minEtaID}; } +std::array numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::FCCSWGridPhiTheta& aSeg) { + uint phiCellNumber = aSeg.phiBins(); + double thetaCellSize = aSeg.gridSizeTheta(); + auto etaExtremes = volumeEtaExtremes(aVolumeId); + double thetaMin = 2.*atan(exp(-etaExtremes[1])); + double thetaMax = 2.*atan(exp(-etaExtremes[0])); + + uint cellsTheta = ceil(( thetaMax - thetaMin - thetaCellSize ) / 2 / thetaCellSize) * 2 + 1; + uint minThetaID = int(floor((thetaMin + 0.5 * thetaCellSize - aSeg.offsetTheta()) / thetaCellSize)); + return {phiCellNumber, cellsTheta, minThetaID}; +} + +std::array numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::FCCSWGridModuleThetaMerged& aSeg) { + + const dd4hep::DDSegmentation::BitFieldCoder* aDecoder = aSeg.decoder(); + int nLayer = aDecoder->get(aVolumeId, aSeg.fieldNameLayer()); + // + 0.5 to avoid integer division + uint nModules = aSeg.nModules() / aSeg.mergedModules(nLayer); + if (aSeg.nModules() % aSeg.mergedModules(nLayer) != 0) nModules++; + // get minimum and maximum theta of volume + auto etaExtremes = volumeEtaExtremes(aVolumeId); + double thetaMin = 2.*atan(exp(-etaExtremes[1])); + double thetaMax = 2.*atan(exp(-etaExtremes[0])); + + // convert to minimum and maximum theta bins + double thetaCellSize = aSeg.gridSizeTheta(); + double thetaOffset = aSeg.offsetTheta(); + uint minThetaID = int(floor((thetaMin + 0.5 * thetaCellSize - thetaOffset) / thetaCellSize)); + uint maxThetaID = int(floor((thetaMax + 0.5 * thetaCellSize - thetaOffset) / thetaCellSize)); + // correct minThetaID and maxThetaID for merging + uint mergedThetaCells = aSeg.mergedThetaCells(nLayer); + minThetaID -= (minThetaID % mergedThetaCells); + maxThetaID -= (maxThetaID % mergedThetaCells); + uint nThetaCells = 1 + (maxThetaID - minThetaID)/ mergedThetaCells; + return {nModules, nThetaCells, minThetaID}; +} + std::array numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::PolarGridRPhi& aSeg) { // get half-widths, auto tubeSizes = tubeDimensions(aVolumeId); diff --git a/Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged.xml b/Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged.xml index c9a8f312..9411b7dc 100644 --- a/Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged.xml +++ b/Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged.xml @@ -23,7 +23,8 @@ - + + @@ -58,7 +59,7 @@ - + @@ -66,7 +67,7 @@ taking into account the angular projection effect --> - + @@ -76,20 +77,20 @@ - + - + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 - + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 diff --git a/Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged_calibration.xml b/Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged_calibration.xml new file mode 100644 index 00000000..a4f8e444 --- /dev/null +++ b/Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged_calibration.xml @@ -0,0 +1,136 @@ + + + + + Settings for the inclined EM calorimeter. + The barrel is filled with liquid argon. Passive material includes lead in the middle and steal on the outside, glued together. + Passive plates are inclined by a certain angle from the radial direction. + In between of two passive plates there is a readout. + Space between the plate and readout is of trapezoidal shape and filled with liquid argon. + Definition of sizes, visualization settings, readout and longitudinal segmentation are specified. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 + + + + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged_upstream.xml b/Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged_upstream.xml new file mode 100644 index 00000000..8a37644b --- /dev/null +++ b/Detector/DetFCCeeECalInclined/compact/FCCee_ECalBarrel_thetamodulemerged_upstream.xml @@ -0,0 +1,136 @@ + + + + + Settings for the inclined EM calorimeter. + The barrel is filled with liquid argon. Passive material includes lead in the middle and steal on the outside, glued together. + Passive plates are inclined by a certain angle from the radial direction. + In between of two passive plates there is a readout. + Space between the plate and readout is of trapezoidal shape and filled with liquid argon. + Definition of sizes, visualization settings, readout and longitudinal segmentation are specified. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 + + + + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Detector/DetFCChhECalInclined/src/ECalBarrelInclined_geo.cpp b/Detector/DetFCChhECalInclined/src/ECalBarrelInclined_geo.cpp index 31abfcfa..51178159 100644 --- a/Detector/DetFCChhECalInclined/src/ECalBarrelInclined_geo.cpp +++ b/Detector/DetFCChhECalInclined/src/ECalBarrelInclined_geo.cpp @@ -205,6 +205,11 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, uint numPlanes = round(M_PI / asin((passiveThickness + activeThickness + readoutThickness) / (2. * caloDim.rmin() * cos(angle)))); + double dPhi = 2. * M_PI / numPlanes; + lLog << MSG::INFO << "number of passive plates = " << numPlanes << " azim. angle difference = " << dPhi << endmsg; + lLog << MSG::INFO << " distance at inner radius (cm) = " << 2. * M_PI * caloDim.rmin() / numPlanes << "\n" + << " distance at outer radius (cm) = " << 2. * M_PI * caloDim.rmax() / numPlanes << endmsg; + // The following code checks if the xml geometry file contains a constant defining // the number of planes in the barrel. In that case, it makes the program abort // if the number of planes in the xml is different from the one calculated from @@ -227,10 +232,6 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, // make the code crash (incidentSvc does not work) assert(nModules == numPlanes); } - double dPhi = 2. * M_PI / numPlanes; - lLog << MSG::INFO << "number of passive plates = " << numPlanes << " azim. angle difference = " << dPhi << endmsg; - lLog << MSG::INFO << " distance at inner radius (cm) = " << 2. * M_PI * caloDim.rmin() / numPlanes << "\n" - << " distance at outer radius (cm) = " << 2. * M_PI * caloDim.rmax() / numPlanes << endmsg; // Readout is in the middle between two passive planes double offsetPassivePhi = caloDim.offset() + dPhi / 2.; double offsetReadoutPhi = caloDim.offset() + 0; diff --git a/Detector/DetSegmentation/include/DetSegmentation/FCCSWGridModuleThetaMerged.h b/Detector/DetSegmentation/include/DetSegmentation/FCCSWGridModuleThetaMerged.h index c549eabe..12cbafe9 100644 --- a/Detector/DetSegmentation/include/DetSegmentation/FCCSWGridModuleThetaMerged.h +++ b/Detector/DetSegmentation/include/DetSegmentation/FCCSWGridModuleThetaMerged.h @@ -63,7 +63,7 @@ class FCCSWGridModuleThetaMerged : public GridTheta { * return The number of merged cells in theta */ inline int mergedThetaCells(const int layer) const { - if (layer m_mergedCellsTheta; - /// vector of number of modules to be merged for each layer + /// vector of number of modules to be merged for each layer (typically 1 or 2) std::vector m_mergedModules; /// number of modules (or, equivalently, the deltaPhi between adjacent modules)