Skip to content
Snippets Groups Projects
Commit a3bb7076 authored by Sylvester Joosten's avatar Sylvester Joosten
Browse files

Tweaked nECAL fill algorithm for better fill, and added asymetric extra fill around beampipe

parent 18003ba5
No related branches found
No related tags found
1 merge request!303Tweaked nECAL fill algorithm for better fill, and added asymetric extra fill around beampipe
...@@ -311,6 +311,13 @@ Examples: ...@@ -311,6 +311,13 @@ Examples:
<constant name="Eta3_9_tan" value="tan(2*atan(exp(-3.9)))" /> <constant name="Eta3_9_tan" value="tan(2*atan(exp(-3.9)))" />
<constant name="Eta4_0_tan" value="tan(2*atan(exp(-4.0)))" /> <constant name="Eta4_0_tan" value="tan(2*atan(exp(-4.0)))" />
<constant name="Eta4_1_tan" value="tan(2*atan(exp(-4.1)))" /> <constant name="Eta4_1_tan" value="tan(2*atan(exp(-4.1)))" />
<constant name="Eta4_2_tan" value="tan(2*atan(exp(-4.2)))" />
<constant name="Eta4_3_tan" value="tan(2*atan(exp(-4.3)))" />
<constant name="Eta4_4_tan" value="tan(2*atan(exp(-4.4)))" />
<constant name="Eta4_5_tan" value="tan(2*atan(exp(-4.5)))" />
<constant name="Eta4_6_tan" value="tan(2*atan(exp(-4.6)))" />
<constant name="Eta4_7_tan" value="tan(2*atan(exp(-4.7)))" />
<constant name="Eta4_8_tan" value="tan(2*atan(exp(-4.8)))" />
<comment>Solenoid option</comment> <comment>Solenoid option</comment>
...@@ -429,7 +436,12 @@ Service gaps in FW direction (before endcapP ECAL) and BW direction (before endc ...@@ -429,7 +436,12 @@ Service gaps in FW direction (before endcapP ECAL) and BW direction (before endc
<constant name="EcalEndcapN_zmin" value="BackwardPIDRegion_zmin + BackwardInnerEndcapRegion_length"/> <constant name="EcalEndcapN_zmin" value="BackwardPIDRegion_zmin + BackwardInnerEndcapRegion_length"/>
<constant name="EcalEndcapN_length" value="60*cm" /> <constant name="EcalEndcapN_length" value="60*cm" />
<constant name="EcalEndcapN_rmin" value="max((EcalEndcapN_zmin + EcalEndcapN_length) * tan(abs(CrossingAngle)) + 15.5 * mm, 5*cm)" /> <comment>
rmin1: rmin round electron pipe (ignoring the hadron pipe)
rmin2: rmin around both beam pipes
</comment>
<constant name="EcalEndcapN_rmin1" value="Eta4_6_tan * EcalEndcapN_zmin" />
<constant name="EcalEndcapN_rmin2" value="Eta4_1_tan * EcalEndcapN_zmin" />
<constant name="EcalEndcapN_rmax" value="CentralTrackingRegion_rmax" /> <constant name="EcalEndcapN_rmax" value="CentralTrackingRegion_rmax" />
<constant name="EcalBarrelRegion_thickness" value="45.0*cm"/> <constant name="EcalBarrelRegion_thickness" value="45.0*cm"/>
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
<constant name="GlassModule_wrap" value="2*CrystalModule_wrap"/> <constant name="GlassModule_wrap" value="2*CrystalModule_wrap"/>
<constant name="GlassModule_z0" value="0.0*cm"/> <constant name="GlassModule_z0" value="0.0*cm"/>
<constant name="EcalEndcapNIonCutout_dphi" value="30*degree"/>
<constant name="EcalEndcapN_thickness" value="GlassModule_length"/> <constant name="EcalEndcapN_thickness" value="GlassModule_length"/>
<constant name="EcalEndcapN_z0" value="-EcalEndcapN_zmin - EcalEndcapN_thickness/2"/> <constant name="EcalEndcapN_z0" value="-EcalEndcapN_zmin - EcalEndcapN_thickness/2"/>
<constant name="EcalEndcapNCrystal_rmax" value="40*cm"/> <constant name="EcalEndcapNCrystal_rmax" value="40*cm"/>
......
...@@ -40,7 +40,9 @@ static Ref_t create_detector(Detector& desc, xml::Handle_t handle, SensitiveDete ...@@ -40,7 +40,9 @@ static Ref_t create_detector(Detector& desc, xml::Handle_t handle, SensitiveDete
auto air_material = desc.material("Air"); auto air_material = desc.material("Air");
double ROut = desc.constantAsDouble("EcalEndcapN_rmax"); double ROut = desc.constantAsDouble("EcalEndcapN_rmax");
double RIn = desc.constantAsDouble("EcalEndcapN_rmin"); double RIn_el = desc.constantAsDouble("EcalEndcapN_rmin1");
double ionCutout_dphi = desc.constantAsDouble("EcalEndcapNIonCutout_dphi");
double RIn = desc.constantAsDouble("EcalEndcapN_rmin2");
double SizeZ = desc.constantAsDouble("EcalEndcapN_thickness"); double SizeZ = desc.constantAsDouble("EcalEndcapN_thickness");
double thickness = desc.constantAsDouble("EcalEndcapN_thickness"); double thickness = desc.constantAsDouble("EcalEndcapN_thickness");
double trans_radius = desc.constantAsDouble("EcalEndcapNCrystal_rmax"); double trans_radius = desc.constantAsDouble("EcalEndcapNCrystal_rmax");
...@@ -57,23 +59,35 @@ static Ref_t create_detector(Detector& desc, xml::Handle_t handle, SensitiveDete ...@@ -57,23 +59,35 @@ static Ref_t create_detector(Detector& desc, xml::Handle_t handle, SensitiveDete
double Crystal_z0 = desc.constantAsDouble("CrystalModule_z0"); double Crystal_z0 = desc.constantAsDouble("CrystalModule_z0");
// RIn and ROut will define outer tube embedding the calorimeter // RIn and ROut will define outer tube embedding the calorimeter
// centers_rin/out define the maximum radius of module centers // centers_rmin/out define the maximum radius of module centers
// so that modules are not overlapping with mother tube volume // so that modules are not overlapping with mother tube volume
double hypotenuse = sqrt(0.5 * glass_distance * glass_distance); const double glassHypotenuse = std::hypot(glass_distance, glass_distance)/2;
double centers_rin = RIn + hypotenuse + 1*mm; const double crystalHypotenuse = glassHypotenuse/2;
double centers_rout = ROut - hypotenuse - 1*mm; // Offset these values a bit so we don't miss edge-blocks
const double glassCenters_rmax = ROut - glassHypotenuse + 1 * mm;
const double Crystal_offset = -0.5*(Crystal_thickness - thickness); const double crystalCenters_rmin = RIn + crystalHypotenuse - 1 * mm;
// Also limits of the inner crystal blocks fill
const double cutout_tan = tan(ionCutout_dphi/2);
const double cutout_rmin = RIn_el + crystalHypotenuse - 1 * mm;
// Offset to align the modules at the zmin of the endcap,
const double Crystal_offset = -0.5 * (Crystal_thickness - thickness);
const double Glass_offset = -0.5*(Glass_thickness - thickness); const double Glass_offset = -0.5*(Glass_thickness - thickness);
// envelope // envelope
// consists of an glass tube of the full thickness, and a crystal inner tube
// Assembly assembly(detName); // for the crystal that allows us to get closet to the beampipe without
// overlaps, and a partial electron tube that allows us to get closer to the
Tube outer_tube(RIn, ROut, SizeZ / 2.0, 0., 360.0 * deg); // electron beampipe in the region where there is no ion beampipe
Volume ecal_vol("negative_ecal", outer_tube, air_material); Tube glass_tube(min(RIn + glassHypotenuse*2, trans_radius), ROut, SizeZ / 2.0, 0., 360.0 * deg);
Tube crystal_tube(RIn, min(RIn + glassHypotenuse*2, trans_radius), Crystal_thickness/ 2.0, 0., 360.0 * deg);
Tube electron_tube(RIn_el, RIn, Crystal_thickness / 2., ionCutout_dphi / 2., 360.0 * deg - ionCutout_dphi / 2);
UnionSolid outer_envelope(glass_tube, crystal_tube, Position(0,0,Crystal_offset));
UnionSolid envelope(outer_envelope, electron_tube, Position(0,0,Crystal_offset));
Volume ecal_vol("negative_ecal", envelope, air_material);
ecal_vol.setVisAttributes(desc.visAttributes("HybridEcalOuterVis")); ecal_vol.setVisAttributes(desc.visAttributes("HybridEcalOuterVis"));
// TODO why 1cm and not something else?
double Glass_OuterR = ROut - 1 * cm ; double Glass_OuterR = ROut - 1 * cm ;
double Glass_InnerR = trans_radius; double Glass_InnerR = trans_radius;
...@@ -91,9 +105,11 @@ static Ref_t create_detector(Detector& desc, xml::Handle_t handle, SensitiveDete ...@@ -91,9 +105,11 @@ static Ref_t create_detector(Detector& desc, xml::Handle_t handle, SensitiveDete
// GLASS // GLASS
double diameter = 2 * Glass_OuterR; double diameter = 2 * Glass_OuterR;
// How many towers do we have per row/columnt? // Can we fit an even or odd amount of glass blocks within our rmax?
// Add a gap + diameter as if we have N towers, we have N-1 gaps; // This determines the transition points between crystal and glass as we need the
int towersInRow = std::ceil((diameter + Glass_Gap) / (Glass_Width + Glass_Gap)); // outer crystal arangement to be in multiples of 2 (aligned with glass)
const int towersInRow = std::ceil((diameter + Glass_Gap) / (Glass_Width + Glass_Gap));
const bool align_even = (towersInRow % 2);
// Is it odd or even number of towersInRow // Is it odd or even number of towersInRow
double leftTowerPos, topTowerPos; double leftTowerPos, topTowerPos;
...@@ -114,109 +130,39 @@ static Ref_t create_detector(Detector& desc, xml::Handle_t handle, SensitiveDete ...@@ -114,109 +130,39 @@ static Ref_t create_detector(Detector& desc, xml::Handle_t handle, SensitiveDete
int moduleIndex = 0; int moduleIndex = 0;
// fmt::print("\nCE EMCAL GLASS SQUARE START\n");
// fmt::print("Glass_thickness = {} cm;\n", Glass_thickness / cm);
// fmt::print("Glass_Width = {} cm;\n", Glass_Width / cm);
// fmt::print("Glass_Gap = {} cm;\n", Glass_Gap / cm);
// fmt::print("Glass_InnerR = {} cm;\n", Glass_InnerR / cm);
// fmt::print("Glass_OuterR = {} cm;\n", Glass_OuterR / cm);
// fmt::print("Glass_PosZ = {} cm;\n", glass_shift_z / cm);
// fmt::print("Towers in Row/Col = {} cm;\n", glass_shift_z / cm);
// fmt::print("Top left tower pos = {:<10} {:<10} cm;\n", -leftTowerPos / cm, topTowerPos / cm);
// fmt::print("#Towers info:\n");
// fmt::print("#{:<5} {:<6} {:<3} {:<3} {:>10} {:>10} {}\n", "idx", "code", "col", "row", "x", "y", "name");
// We first do a "dry run", not really placing modules,
// but figuring out the ID scheme, number of modules, etc.
int glassModuleCount = 0;
int crystalModuleCount = 0;
int firstCrystRow = 1000000; // The first row, where crystals are started
int firstCrystCol = 1000000; // The fist column, where crystals are started
for(int rowIndex=0; rowIndex < towersInRow; rowIndex++) {
for(int colIndex=0; colIndex < towersInRow; colIndex++) {
double glass_x = leftTowerPos + colIndex * glass_distance;
double glass_y = topTowerPos + rowIndex * glass_distance;
double r = sqrt(glass_x * glass_x + glass_y * glass_y);
if (r < centers_rout && r > centers_rin) {
// we are placing something
if(r<trans_radius) {
// 4 crystal modules will be placed
crystalModuleCount+=4;
// Finding the first col and row where crystals start
// is the same algorithm as finding a minimum in array
if(colIndex<firstCrystCol) {
firstCrystCol = colIndex;
}
if(rowIndex<firstCrystRow) {
firstCrystRow = rowIndex;
}
}
else
{
// glass module will be places
glassModuleCount++;
}
}
}
}
// fmt::print("#Towers info:\n");
// fmt::print("#{:<5} {:<6} {:<3} {:<3} {:>10} {:>10} {}\n", "idx", "code", "col", "row", "x", "y", "name");
int glass_module_index = 0; int glass_module_index = 0;
int cryst_module_index = 0; int cryst_module_index = 0;
for(int rowIndex=0; rowIndex < towersInRow; rowIndex++) { for(int rowIndex=0; rowIndex < towersInRow; rowIndex++) {
for(int colIndex=0; colIndex < towersInRow; colIndex++) { for(int colIndex=0; colIndex < towersInRow; colIndex++) {
double glass_x = leftTowerPos + colIndex * (Glass_Width + Glass_Gap); const double glass_x = leftTowerPos + colIndex * (Glass_Width + Glass_Gap);
double glass_y = topTowerPos + rowIndex * (Glass_Width + Glass_Gap); const double glass_y = topTowerPos + rowIndex * (Glass_Width + Glass_Gap);
double r = sqrt(glass_x * glass_x + glass_y * glass_y); const double r = std::hypot(glass_x, glass_y);
// crystal if within the transition radius (as defined by the equivalent glass
if (r < centers_rout && r > centers_rin) { // block)
int code = 1000 * rowIndex + colIndex; if (r < trans_radius) {
std::string name = fmt::format("ce_EMCAL_glass_phys_{}", code); for (const auto dx : {-1, 1}) {
for (const auto& dy : {-1, 1}) {
if(r<trans_radius) { const double crystal_x = glass_x + dx * crystal_distance / 2;
const double crystal_y = glass_y + dy * crystal_distance / 2;
// first crystal module const double crystal_r = std::hypot(crystal_x, crystal_y);
double crystal_x = glass_x - crystal_distance / 2; // check if crystal in the main crystal ring?
double crystal_y = glass_y - crystal_distance / 2; const bool mainRing = (crystal_r > crystalCenters_rmin);
auto placement = ecal_vol.placeVolume(crystal_module, Position(crystal_x, crystal_y, Crystal_z0 + Crystal_offset)); const bool innerRing = !mainRing && crystal_r > cutout_rmin;
placement.addPhysVolID("sector", 1); const bool ionCutout = crystal_x > 0 && fabs(crystal_y / crystal_x) < cutout_tan;
placement.addPhysVolID("module", cryst_module_index++); if (mainRing || (innerRing && !ionCutout)) {
auto placement =
// second crystal module ecal_vol.placeVolume(crystal_module, Position(crystal_x, crystal_y, Crystal_z0 + Crystal_offset));
crystal_x = glass_x + crystal_distance / 2; placement.addPhysVolID("sector", 1);
crystal_y = glass_y - crystal_distance / 2; placement.addPhysVolID("module", cryst_module_index++);
placement = ecal_vol.placeVolume(crystal_module, Position(crystal_x, crystal_y, Crystal_z0 + Crystal_offset)); }
placement.addPhysVolID("sector", 1); }
placement.addPhysVolID("module", cryst_module_index++);
// third crystal module
crystal_x = glass_x - crystal_distance / 2;
crystal_y = glass_y + crystal_distance / 2;
placement = ecal_vol.placeVolume(crystal_module, Position(crystal_x, crystal_y, Crystal_z0 + Crystal_offset));
placement.addPhysVolID("sector", 1);
placement.addPhysVolID("module", cryst_module_index++);
// forth crystal module
crystal_x = glass_x + crystal_distance / 2;
crystal_y = glass_y + crystal_distance / 2;
placement = ecal_vol.placeVolume(crystal_module, Position(crystal_x, crystal_y, Crystal_z0 + Crystal_offset));
placement.addPhysVolID("sector", 1);
placement.addPhysVolID("module", cryst_module_index++);
}
else
{
// glass module
auto placement = ecal_vol.placeVolume(glass_module, Position(glass_x, glass_y, Glass_z0 + Glass_offset));
placement.addPhysVolID("sector", 2);
placement.addPhysVolID("module", glass_module_index++);
} }
// Glass block if within the rmax
} else if (r < glassCenters_rmax) {
// fmt::print(" {:<5} {:<6} {:<3} {:<3} {:>10.4f} {:>10.4f} {}\n", towerIndex, code, colIndex, rowIndex, x / cm, y / cm, name); // glass module
//glass_module_index++; auto placement = ecal_vol.placeVolume(glass_module, Position(glass_x, glass_y, Glass_z0 + Glass_offset));
placement.addPhysVolID("sector", 2);
placement.addPhysVolID("module", glass_module_index++);
} }
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment