Skip to content
Merged
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
3 changes: 3 additions & 0 deletions Detectors/Upgrades/ALICE3/IOTOF/macros/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@

o2_add_test_root_macro(defineIOTOFGeo.C
LABELS alice3)

o2_add_test_root_macro(drawTOFGeometry.C
LABELS alice3)
90 changes: 90 additions & 0 deletions Detectors/Upgrades/ALICE3/IOTOF/macros/drawTOFGeometry.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#include "IOTOFBase/GeometryTGeo.h"
#include "IOTOFSimulation/Layer.h"

#include <TCanvas.h>
#include <TGeoManager.h>
#include <TGeoMaterial.h>
#include <TGeoMatrix.h>
#include <TGeoVolume.h>
#include <TStyle.h>

#include <iostream>

namespace
{
void ensureMedium(const char* name, int id, double a, double z, double density)
{
if (!gGeoManager->GetMedium(name)) {
auto* mat = new TGeoMaterial(name, a, z, density);
new TGeoMedium(name, id, mat);
}
}

void prepareMinimalMedia()
{
ensureMedium("VACUUM$", 0, 1., 1., 1.e-16);
ensureMedium("TF3_AIR$", 1, 14.61, 7.3, 1.20479e-3);
ensureMedium("TF3_SILICON$", 3, 28.086, 14., 2.33);
}
} // namespace

void drawTOFGeometry(double x2x0 = 0.02,
double sensorThickness = 0.005,
bool checkOverlaps = true,
double overlapToleranceCm = 0.01)
{
gStyle->SetOptStat(0);

if (gGeoManager) {
delete gGeoManager;
}

auto* geo = new TGeoManager("IOTOFGeomFromLayer", "Geometry built from Layer.h classes");
prepareMinimalMedia();

auto* top = geo->MakeBox("TOP", geo->GetMedium("VACUUM$"), 1200., 1200., 1200.);
geo->SetTopVolume(top);

auto* mother = new TGeoVolumeAssembly("IOTOFMacroVol");
top->AddNode(mother, 1, new TGeoTranslation(0., 0., 0.));

// Build using the same classes and createLayer() used by detector geometry code.
o2::iotof::ITOFLayer itof(o2::iotof::GeometryTGeo::getITOFLayerPattern(),
21.f, 0.f, 129.f, 0.f, x2x0,
o2::iotof::Layer::kBarrelSegmented,
24, 5.42, 3.0, 10, sensorThickness);

o2::iotof::OTOFLayer otof(o2::iotof::GeometryTGeo::getOTOFLayerPattern(),
92.f, 0.f, 680.f, 0.f, x2x0,
o2::iotof::Layer::kBarrelSegmented,
62, 9.74, 5.0, 54, sensorThickness);

itof.createLayer(mother);
otof.createLayer(mother);

geo->CloseGeometry();

std::cout << "Built geometry from Layer.h classes with x2x0=" << x2x0
<< " and sensorThickness=" << sensorThickness << " cm\n";
std::cout << "ITOF sensitive volumes: " << o2::iotof::ITOFLayer::mRegister.size() << "\n";
std::cout << "OTOF sensitive volumes: " << o2::iotof::OTOFLayer::mRegister.size() << "\n";

if (checkOverlaps) {
std::cout << "Checking overlaps with tolerance=" << overlapToleranceCm << " cm\n";
geo->CheckOverlaps(overlapToleranceCm);
geo->PrintOverlaps();
}

top->Draw("ogl");
}
29 changes: 24 additions & 5 deletions Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -200,28 +200,47 @@ void Detector::defineSensitiveVolumes()
TGeoManager* geoManager = gGeoManager;
TGeoVolume* v;

// The names of the IOTOF sensitive volumes have the format: IOTOFLayer(0...mLayers.size()-1)
auto& iotofPars = IOTOFBaseParam::Instance();
if (iotofPars.enableInnerTOF) {
const bool itof = iotofPars.enableInnerTOF;
const bool otof = iotofPars.enableOuterTOF;
bool ftof = iotofPars.enableForwardTOF;
bool btof = iotofPars.enableBackwardTOF;
const std::string pattern = iotofPars.detectorPattern;
if (pattern == "") {
LOG(info) << "Default pattern";
} else if (pattern == "v3b") {
ftof = false;
btof = false;
} else if (pattern == "v3b1a") {
} else if (pattern == "v3b1b") {
} else if (pattern == "v3b2a") {
} else if (pattern == "v3b2b") {
} else if (pattern == "v3b3") {
} else {
LOG(fatal) << "IOTOF layer pattern " << pattern << " not recognized, exiting";
}

// The names of the IOTOF sensitive volumes have the format: IOTOFLayer(0...mLayers.size()-1)
if (itof) {
for (const std::string& itofSensor : ITOFLayer::mRegister) {
v = geoManager->GetVolume(itofSensor.c_str());
LOGP(info, "Adding IOTOF Sensitive Volume {}", v->GetName());
AddSensitiveVolume(v);
}
}
if (iotofPars.enableOuterTOF) {
if (otof) {
for (const std::string& otofSensor : OTOFLayer::mRegister) {
v = geoManager->GetVolume(otofSensor.c_str());
LOGP(info, "Adding IOTOF Sensitive Volume {}", v->GetName());
AddSensitiveVolume(v);
}
}
if (iotofPars.enableForwardTOF) {
if (ftof) {
v = geoManager->GetVolume(GeometryTGeo::getFTOFSensorPattern());
LOGP(info, "Adding IOTOF Sensitive Volume {}", v->GetName());
AddSensitiveVolume(v);
}
if (iotofPars.enableBackwardTOF) {
if (btof) {
v = geoManager->GetVolume(GeometryTGeo::getBTOFSensorPattern());
LOGP(info, "Adding IOTOF Sensitive Volume {}", v->GetName());
AddSensitiveVolume(v);
Expand Down
53 changes: 39 additions & 14 deletions Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,24 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume)
case kBarrelSegmented: {
// First we create the volume for the whole layer, which will be used as mother volume for the segments
const double avgRadius = 0.5 * (mInnerRadius + mOuterRadius);
const double staveSizeX = mStaves.second; // cm
const double staveSizeY = mOuterRadius - mInnerRadius; // cm
const double staveSizeZ = mZLength; // cm
const double deltaForTilt = 0.5 * (std::sin(TMath::DegToRad() * mTiltAngle) * staveSizeX + std::cos(TMath::DegToRad() * mTiltAngle) * staveSizeY); // we increase the size of the layer to account for the tilt of the staves
const double radiusMax = std::sqrt(avgRadius * avgRadius + 0.25 * staveSizeX * staveSizeX + 0.25 * staveSizeY * staveSizeY + avgRadius * 2. * deltaForTilt); // we increase the outer radius to account for the tilt of the staves
const double radiusMin = std::sqrt(avgRadius * avgRadius + 0.25 * staveSizeX * staveSizeX + 0.25 * staveSizeY * staveSizeY - avgRadius * 2. * deltaForTilt); // we decrease the inner radius to account for the tilt of the staves
const double staveSizeX = mStaves.second; // cm, tangential stave size
const double staveSizeY = mOuterRadius - mInnerRadius; // cm, radial stave size
const double staveSizeZ = mZLength; // cm

// Build the mother layer tube from the exact inscribed/outscribed radii of a tilted stave rectangle.
const double alpha = mTiltAngle * TMath::DegToRad();
const double u0 = -avgRadius * std::cos(alpha);
const double v0 = avgRadius * std::sin(alpha);
const double uClamped = std::max(-0.5 * staveSizeY, std::min(0.5 * staveSizeY, u0));
const double vClamped = std::max(-0.5 * staveSizeX, std::min(0.5 * staveSizeX, v0));
const double radiusMin = std::hypot(uClamped - u0, vClamped - v0);

const double uCorners[4] = {-0.5 * staveSizeY, 0.5 * staveSizeY, 0.5 * staveSizeY, -0.5 * staveSizeY};
const double vCorners[4] = {-0.5 * staveSizeX, -0.5 * staveSizeX, 0.5 * staveSizeX, 0.5 * staveSizeX};
double radiusMax = 0.0;
for (int i = 0; i < 4; ++i) {
radiusMax = std::max(radiusMax, std::hypot(uCorners[i] - u0, vCorners[i] - v0));
}
TGeoTube* layer = new TGeoTube(radiusMin, radiusMax, mZLength / 2);
TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir);
setLayerStyle(layerVol);
Expand All @@ -312,10 +324,21 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume)
setStaveStyle(staveVol);

// Now we create the volume for a single module (sensor + chip)
const int modulesPerStaveX = 1; // we assume that each stave is divided in 2 modules along the x direction
const double moduleSizeX = staveSizeX / modulesPerStaveX; // cm
const double moduleSizeY = staveSizeY; // cm
const double moduleSizeZ = staveSizeZ / mModulesPerStave; // cm
// oTOF V2 is a 2xN matrix of modules per stave with overlap along z.
const int modulesPerStaveX = 2;
if (mModulesPerStave % modulesPerStaveX != 0) {
LOG(fatal) << "Invalid oTOF module layout: total modules per stave " << mModulesPerStave
<< " is not divisible by modulesPerStaveX=" << modulesPerStaveX;
}
const int modulesPerStaveZ = mModulesPerStave / modulesPerStaveX;
const double moduleOverlapZ = 0.7; // cm, 7 mm longitudinal overlap from oTOF V2 specs
const double moduleSizeX = staveSizeX / modulesPerStaveX;
const double moduleSizeY = staveSizeY;
const double moduleSizeZ = (staveSizeZ + (modulesPerStaveZ - 1) * moduleOverlapZ) / modulesPerStaveZ;
const double modulePitchZ = moduleSizeZ - moduleOverlapZ;
if (modulePitchZ <= 0.0) {
LOG(fatal) << "Invalid oTOF module overlap " << moduleOverlapZ << " cm for module size " << moduleSizeZ << " cm";
}
TGeoBBox* module = new TGeoBBox(moduleSizeX * 0.5, moduleSizeY * 0.5, moduleSizeZ * 0.5);
TGeoVolume* moduleVol = new TGeoVolume(moduleName, module, medAir);
setModuleStyle(moduleVol);
Expand Down Expand Up @@ -363,10 +386,12 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume)

// Now we build a stave from modules
for (int i = 0; i < modulesPerStaveX; ++i) {
for (int j = 0; j < mModulesPerStave; ++j) {
LOGP(info, "oTOF: Creating module {}/{} for stave {}/{}", i + 1, modulesPerStaveX, j + 1, mModulesPerStave);
auto* translation = new TGeoTranslation((i + 0.5) * moduleSizeX - 0.5 * staveSizeX, 0, (j + 0.5) * moduleSizeZ - 0.5 * staveSizeZ);
staveVol->AddNode(moduleVol, 1 + i * mModulesPerStave + j, translation);
for (int j = 0; j < modulesPerStaveZ; ++j) {
LOGP(info, "oTOF: Creating module {}/{} for stave {}/{}", i + 1, modulesPerStaveX, j + 1, modulesPerStaveZ);
const double tx = (i + 0.5) * moduleSizeX - 0.5 * staveSizeX;
const double tz = -0.5 * staveSizeZ + 0.5 * moduleSizeZ + j * modulePitchZ;
auto* translation = new TGeoTranslation(tx, 0, tz);
staveVol->AddNode(moduleVol, 1 + i * modulesPerStaveZ + j, translation);
}
}

Expand Down
Loading