9 #include <arich/geometry/ARICHGeometryPar.h>
11 #include <framework/logging/Logger.h>
12 #include <framework/gearbox/GearDir.h>
13 #include <framework/gearbox/Unit.h>
15 #include <Math/VectorUtil.h>
18 #include <boost/format.hpp>
19 #include <boost/foreach.hpp>
22 using namespace boost;
30 ARICHGeometryPar* ARICHGeometryPar::p_B4ARICHGeometryParDB = 0;
34 if (!p_B4ARICHGeometryParDB) {
37 return p_B4ARICHGeometryParDB;
40 ARICHGeometryPar::ARICHGeometryPar()
45 ARICHGeometryPar::~ARICHGeometryPar()
49 void ARICHGeometryPar::Initialize(
const GearDir& content,
const GearDir& mirrorcontent)
53 string Type = content.getString(
"@type",
"");
54 if (Type ==
"beamtest") {
56 modulesPositionSimple(content);
57 mirrorPositionSimple(mirrorcontent);
59 modulesPosition(content);
60 mirrorPositions(content);
61 frontEndMapping(content);
65 initDetectorMask(m_fR.size());
66 readModuleInfo(content);
70 void ARICHGeometryPar::Initialize(
const GearDir& content)
72 Initialize(content, content);
75 void ARICHGeometryPar::clear(
void)
83 m_mirrorOuterRad = 0.0;
84 m_mirrorThickness = 0.0;
85 m_mirrorStartAng = 0.0;
90 m_detInnerRadius = 0.0;
91 m_detOuterRadius = 0.0;
96 m_ncol.clear(); m_fDFi.clear(); m_fDR.clear(); m_fR.clear();
97 m_fFi.clear(); m_fFiMod.clear(); m_chipLocPos.clear(); m_padWorldPositions.clear(); m_mirrornorm.clear(); m_mirrorpoint.clear();
99 for (
int i = 0; i < MAX_N_ALAYERS; i++) {
100 m_aeroTrLength[i] = 0; m_aeroRefIndex[i] = 0;
101 m_aeroZPosition[i] = 0; m_aeroThickness[i] = 0;
109 m_windowAbsorbtion = 0.;
110 m_chipNegativeCrosstalk = 0;
111 for (
int i = 0; i < MAXPTS_QE; i++) {m_QE[i] = 0.;}
117 for (
int i = 0; i < 5; i++) m_tileNphi[i] = 0;
121 void ARICHGeometryPar::read(
const GearDir& content)
127 GearDir detParams(content,
"Detector");
128 m_modXSize = detParams.
getLength(
"Module/moduleXSize");
129 m_modZSize = detParams.
getLength(
"Module/moduleZSize");
130 m_winThick = detParams.
getLength(
"Module/windowThickness");
131 m_nPadX = detParams.
getInt(
"Module/padXNum");
132 m_nPads = m_nPadX * m_nPadX;
133 m_padSize = detParams.
getLength(
"Module/padSize");
134 m_chipGap = detParams.
getLength(
"Module/chipGap");
135 m_detZpos = detParams.
getLength(
"Plane/zPosition");
136 m_qeScale = detParams.
getDouble(
"Module/qeScale");
137 m_windowAbsorbtion = detParams.
getDouble(
"Module/windowAbsorbtion");
138 m_chipNegativeCrosstalk = detParams.
getDouble(
"Module/chipNegativeCrosstalk");
139 string Type = content.getString(
"@type",
"");
140 if (Type ==
"beamtest")
return;
141 m_detInnerRadius = detParams.
getLength(
"Plane/tubeInnerRadius");
142 m_detOuterRadius = detParams.
getLength(
"Plane/tubeOuterRadius");
144 GearDir mirrParams(content,
"Mirrors");
146 m_nMirrors = mirrParams.
getInt(
"nMirrors");
147 m_mirrorThickness = mirrParams.
getLength(
"mirrorThickness");
148 m_mirrorOuterRad = mirrParams.
getLength(
"outerRadius");
149 m_mirrorStartAng = mirrParams.
getAngle(
"startAngle");
150 m_mirrorZPos = mirrParams.
getLength(
"Zposition");
153 GearDir qeParams(content,
"QE");
154 m_ColEffi = qeParams.
getDouble(
"ColEffi");
155 m_LambdaFirst = qeParams.
getLength(
"LambdaFirst") / Unit::nm;
156 m_LambdaStep = qeParams.
getLength(
"LambdaStep") / Unit::nm;
158 for (
int i = 0; i < MAXPTS_QE; i++) {
160 stringstream ss;
string cc;
162 string path =
"Qeffi[@component='point-" + cc +
"']/";
169 GearDir aerogel(content,
"Aerogel");
170 m_tileNr = aerogel.
getInt(
"tileNr");
171 m_tileGap = aerogel.
getLength(
"tileGap") / Unit::cm;
172 m_aeroRin = aerogel.
getLength(
"tubeInnerRadius") / Unit::cm;
173 m_aeroRout = aerogel.
getLength(
"tubeOuterRadius") / Unit::cm;
177 m_tileNphi[i] = ring.getInt();
183 void ARICHGeometryPar::frontEndMapping(
const GearDir& content)
186 GearDir mapping(content,
"FrontEndMapping");
189 unsigned mergerID = (unsigned) merger.getInt(
"@id");
191 auto testMer = m_mergerIDs.find(mergerID);
192 if (testMer != m_mergerIDs.end()) {
193 B2ERROR(mapping.
getPath() <<
"/MergerID " << mergerID <<
194 " ***input already used");
197 m_mergerIDs.insert(mergerID);
199 std::vector<unsigned> boardIDs;
200 for (
const GearDir& board : merger.getNodes(
"FEboards/FEboard")) {
201 unsigned boardID = board.getInt();
202 auto testBor = m_boardIDs.find(boardID);
203 if (testBor != m_boardIDs.end()) {
204 B2ERROR(mapping.
getPath() <<
"/FEboardID " << boardID <<
205 " ***input already used");
207 boardIDs.push_back(boardID);
208 m_boardIDs.insert(boardID);
210 m_merger2feb.insert(std::pair<
int, std::vector<unsigned>>(mergerID, boardIDs));
211 unsigned copperID = (unsigned) merger.getInt(
"COPPERid");
212 string finesseSlot = merger.getString(
"FinesseSlot");
214 if (finesseSlot ==
"A") {finesse = 0;}
215 else if (finesseSlot ==
"B") {finesse = 1;}
216 else if (finesseSlot ==
"C") {finesse = 2;}
217 else if (finesseSlot ==
"D") {finesse = 3;}
219 B2ERROR(merger.getPath() <<
"/FinesseSlot " << finesseSlot <<
220 " ***invalid slot (valid are A, B, C, D)");
224 m_copperIDs.insert(copperID);
226 std::pair<unsigned, int> copfin(copperID, finesse);
227 m_copper2merger.insert(std::pair<std::pair<unsigned, int>,
unsigned>(copfin, mergerID));
233 int ARICHGeometryPar::getMergerFromCooper(
int copperID,
int finesse)
235 auto merger = m_copper2merger.find(std::pair<unsigned, int>(copperID, finesse));
236 if (merger == m_copper2merger.end()) {
242 return merger->second;
245 int ARICHGeometryPar::getBoardFromMerger(
int mergerID,
int slot)
247 auto boards = m_merger2feb.find(mergerID);
248 if (boards == m_merger2feb.end()) {
249 B2ERROR(
"getBoardFromMerger: " <<
" merger " << mergerID <<
" is not mapped");
252 if ((boards->second).size() <=
unsigned(slot)) {
253 B2ERROR(
"getBoardFromMerger: " <<
" merger " << mergerID <<
" slot " << slot <<
" is not assigned to FE board.");
256 return (boards->second).at(slot);
259 int ARICHGeometryPar::getNBoardsOnMerger(
int mergerID)
261 auto boards = m_merger2feb.find(mergerID);
262 if (boards == m_merger2feb.end()) {
263 B2ERROR(
"getNBoardsOnMerger: " <<
" merger " << mergerID <<
" is not mapped");
265 return (boards->second).size();
268 void ARICHGeometryPar::readModuleInfo(
const GearDir& content)
270 istringstream chstream;
272 GearDir modParams(content,
"ModuleInfo");
273 uint8_t defqe = uint8_t(modParams.
getDouble(
"DefaultQE") * 100);
274 m_ChannelQE.assign(m_nPads * m_fR.size(), defqe);
276 int modid = atoi(module.getString(
"@id",
"").c_str());
277 chstream.str(module.getString(
"ChannelsQE"));
278 while (chstream >> ch >> qq) {
279 int chid = (modid - 1) * m_nPads + ch;
280 m_ChannelQE[chid] = uint8_t(qq * 100);
283 chstream.str(module.getString(
"DeadChannels"));
284 while (chstream >> ch) {
285 setActive(modid, ch,
false);
291 double ARICHGeometryPar::QE(
double e)
const
293 if (e < 0.001)
return 0;
294 double dlam = 1240 / e - m_LambdaFirst;
295 if (dlam < 0)
return 0;
296 int i = int(dlam / m_LambdaStep);
297 if (i > m_NpointsQE - 2)
return 0;
298 return m_QE[i] + (m_QE[i + 1] - m_QE[i]) / m_LambdaStep * (dlam - i * m_LambdaStep);
302 void ARICHGeometryPar::Print(
void)
const
306 double ARICHGeometryPar::getChannelQE(
int moduleID,
int channelID)
308 int id = (moduleID - 1) * m_nPads + channelID;
309 return m_ChannelQE.at(
id) / 100.0;
312 int ARICHGeometryPar::getChannelID(TVector2 position)
314 int ChipID = getChipID(position);
315 int Npad = int(m_nPadX / 2);
316 TVector2 chipPos = getChipLocPos(ChipID);
317 TVector2 locloc = position - chipPos;
318 int ix = int(locloc.X() / m_padSize);
319 int iy = int(locloc.Y() / m_padSize);
320 if (locloc.X() < 0 || locloc.Y() < 0)
return -1;
321 if (ix > Npad - 1 || iy > Npad - 1)
return -1;
322 int chID = ChipID * Npad * Npad + iy + ix * Npad;
326 void ARICHGeometryPar::modulesPosition(
const GearDir& content)
329 GearDir detParams(content,
"Detector/Plane/Rings");
331 double r = m_detInnerRadius;
336 double rcenter = r + m_modXSize / 2.;
337 if (rcenter + m_modXSize *
sqrt(2) / 2. > m_detOuterRadius) {
338 B2WARNING(m_ncol.size() + 1 <<
"th ring of ARICH photon detectors will not be placed (out of detector tube).");
342 int nSeg = ring.
getInt(
"nSegments") ;
345 double f = 2.*atan2((m_modXSize + dFi) / 2., r);
346 int blaa = int(2.*M_PI / f / nSeg) * nSeg;
347 m_ncol.push_back(blaa);
348 f = 2.*M_PI / double(blaa);
350 B2INFO(blaa <<
" modules of " << m_ncol.size() <<
"th ring of ARICH photon detectors will be placed at r = " << rcenter <<
"cm. ");
351 for (
int nv = 0; nv < blaa; ++nv) {
352 m_fR.push_back(rcenter);
353 double fi = f * (nv + 0.5);
355 m_fFiMod.push_back(fi);
357 r += (m_modXSize + r * (1 - cos(f / 2.)));
359 B2INFO(
"Altogether " << m_fR.size() <<
" ARICH photon detector modules will be placed.");
362 void ARICHGeometryPar::modulesPositionSimple(
const GearDir& content)
364 BOOST_FOREACH(
const GearDir & module, content.getNodes(
"Detector/Plane/Modules/Module")) {
365 TVector2 position(module.getLength(
"xPos"), module.getLength(
"yPos"));
366 double angle = module.getAngle(
"angle") / Unit::rad;
367 m_fFi.push_back(position.Phi());
368 m_fR.push_back(position.Mod());
369 m_fFiMod.push_back(angle);
371 B2INFO(
"Altogether " << m_fR.size() <<
" ARICH photon detector modules will be placed.");
374 int ARICHGeometryPar::getCopyNo(TVector3 hit)
378 double r =
sqrt(x * x + y * y);
379 double fi = atan2(y, x);
380 if (fi < 0) fi += 2 * M_PI;
382 for (
int i = 0; i < m_nrow; i++) {
383 int nfi = int(fi / m_fDFi[i]);
384 int copyno = ntot + nfi;
385 if (fabs(r - m_fR[copyno]) < m_modXSize / 2.)
return copyno + 1;
391 int ARICHGeometryPar::getCopyNo(
const ROOT::Math::XYZVector& hit)
393 TVector3 hitVector(hit.X(), hit.Y(), hit.Z());
394 return getCopyNo(hitVector);
397 TVector3 ARICHGeometryPar::getOrigin(
int copyNo)
400 origin.SetMagPhi(m_fR[copyNo - 1], m_fFi[copyNo - 1]);
401 return TVector3(origin.X(), origin.Y(), m_detZpos + m_modZSize / 2.);
404 G4ThreeVector ARICHGeometryPar::getOriginG4(
int copyNo)
406 TVector3 origin = getOrigin(copyNo);
407 return G4ThreeVector(origin.X() / Unit::mm, origin.Y() / Unit::mm, origin.Z() / Unit::mm);
410 double ARICHGeometryPar::getModAngle(
int copyno)
412 return m_fFiMod[copyno - 1];
415 void ARICHGeometryPar::chipLocPosition()
417 double xycenter = m_padSize * m_nPadX / 4. + m_chipGap / 2.;
418 m_chipLocPos.push_back(TVector2(xycenter - m_padSize * m_nPadX / 4., xycenter - m_padSize * m_nPadX / 4.));
419 m_chipLocPos.push_back(TVector2(xycenter - m_padSize * m_nPadX / 4., -xycenter - m_padSize * m_nPadX / 4.));
420 m_chipLocPos.push_back(TVector2(-xycenter - m_padSize * m_nPadX / 4., xycenter - m_padSize * m_nPadX / 4.));
421 m_chipLocPos.push_back(TVector2(-xycenter - m_padSize * m_nPadX / 4., -xycenter - m_padSize * m_nPadX / 4.));
425 int ARICHGeometryPar::getChipID(TVector2 locpos)
427 if (locpos.X() > 0) {
428 if (locpos.Y() > 0)
return 0;
431 if (locpos.Y() > 0)
return 2;
436 TVector3 ARICHGeometryPar::getChannelCenterGlob(
int modID,
int chanID)
438 int id = (modID - 1) * m_nPads + chanID;
439 return TVector3(m_padWorldPositions.at(
id).X(), m_padWorldPositions.at(
id).Y(), m_detZpos + m_winThick);
442 TVector2 ARICHGeometryPar::getChannelCenterLoc(
int chID)
444 return m_padLocPositions[chID];
448 void ARICHGeometryPar::padPositions()
450 int Npad = int(m_nPadX / 2.);
451 TVector2 xstart(m_padSize / 2., m_padSize / 2.);
452 for (
int chipID = 0; chipID < 4; chipID++) {
453 TVector2 chipPos = getChipLocPos(chipID);
454 for (
int ix = 0; ix < Npad; ix++) {
455 for (
int iy = 0; iy < Npad; iy++) {
456 int chanID = chipID * Npad * Npad + ix * Npad + iy;
457 TVector2 center(m_padSize / 2. + ix * m_padSize, m_padSize / 2. + iy * m_padSize);
458 center = center + chipPos;
459 m_padLocPositions[chanID] = center;
463 for (
int iMod = 0; iMod < getNMCopies(); iMod++) {
464 for (
unsigned int iChan = 0; iChan < m_padLocPositions.size(); iChan++) {
466 iModCenter.SetMagPhi(m_fR[iMod], m_fFi[iMod]);
467 TVector2 iChanCenter = m_padLocPositions[iChan];
468 iChanCenter = iChanCenter.Rotate(m_fFiMod[iMod]);
469 TVector2 iWorld((iModCenter + iChanCenter).X(), (iModCenter + iChanCenter).Y());
470 m_padWorldPositions.push_back(iWorld);
475 void ARICHGeometryPar::mirrorPositions(
const GearDir& content)
477 double rmir = m_mirrorOuterRad * cos(M_PI / m_nMirrors) - m_mirrorThickness;
478 for (
int i = 0; i < m_nMirrors; i++) {
479 TVector3 norm(cos(2.*M_PI /
double(m_nMirrors) * (i + 0.5) + m_mirrorStartAng),
480 sin(2.*M_PI /
double(m_nMirrors) * (i + 0.5) + m_mirrorStartAng), 0);
481 m_mirrornorm.push_back(norm);
482 m_mirrorpoint.push_back(rmir * norm);
484 readMirrorAlignment(content);
487 void ARICHGeometryPar::mirrorPositionSimple(
const GearDir& content)
489 double thick = content.getLength(
"Mirrors/thickness");
490 BOOST_FOREACH(
const GearDir & mirror, content.getNodes(
"Mirrors/Mirror")) {
491 double angle = mirror.
getAngle(
"angle");
492 TVector3 point(mirror.
getLength(
"xPos") - cos(angle)*thick / 2., mirror.
getLength(
"yPos") - sin(angle)*thick / 2., 0);
493 TVector3 norm(cos(angle), sin(angle), 0);
494 m_mirrorpoint.push_back(point);
495 m_mirrornorm.push_back(norm);
501 TVector3 ARICHGeometryPar::getMirrorNormal(
int mirID)
503 return m_mirrornorm[mirID];
506 TVector3 ARICHGeometryPar::getMirrorPoint(
int mirID)
508 return m_mirrorpoint[mirID];
511 void ARICHGeometryPar::setAeroTransLength(
int layer,
double trlength)
513 m_aeroTrLength[layer] = trlength;
516 void ARICHGeometryPar::setAeroRefIndex(
int layer,
double n)
518 if (n) m_aeroRefIndex[layer] = n;
521 void ARICHGeometryPar::setAerogelThickness(
int layer,
double thick)
524 m_aeroThickness[layer] = thick;
527 void ARICHGeometryPar::setAerogelZPosition(
int layer,
double zPos)
529 m_aeroZPosition[layer] = zPos;
532 void ARICHGeometryPar::setWindowRefIndex(
double refInd)
534 m_winRefInd = refInd;
537 void ARICHGeometryPar::initDetectorMask(
int nmodules)
539 int m_DetectorMaskSize = m_nPads * nmodules / 32 + 1;
540 for (
int i = 0; i < m_DetectorMaskSize; i++) {
541 m_DetectorMask.push_back(0xFFFFFFFF);
543 B2INFO(
"DetectorMask initialized size=" << m_nPads <<
" * " << nmodules <<
" +1 =" << m_DetectorMaskSize);
547 void ARICHGeometryPar::setActive(
int module,
int channel,
bool active)
549 int ch = (module - 1) * m_nPads + channel;
551 unsigned int idx = ch / 32;
552 if (idx >= m_DetectorMask.size()) {
553 B2WARNING(idx <<
" Wrong detector mask size >= " << m_DetectorMask.size());
555 if (active) m_DetectorMask[idx] |= (1 << bit);
556 else m_DetectorMask[idx] &= ~(1 << bit);
559 bool ARICHGeometryPar::isActive(
int module,
int channel)
561 int ch = (module - 1) * m_nPads + channel;
564 return m_DetectorMask[idx] & (1 << bit);
567 void ARICHGeometryPar::readMirrorAlignment(
const GearDir& content)
569 GearDir modParams(content,
"Mirrors/Alignment");
572 int id = atoi(plate.
getString(
"@id").c_str());
574 double dphi = plate.
getAngle(
"dphi");
575 double dtheta = plate.
getAngle(
"dtheta");
576 m_mirrorpoint[
id - 1].SetMag(m_mirrorpoint[
id - 1].Mag() + dr);
577 m_mirrornorm[
id - 1].SetTheta(m_mirrornorm[
id - 1].Theta() + dtheta);
578 m_mirrornorm[
id - 1].SetPhi(m_mirrornorm[
id - 1].Phi() + dphi);
583 int ARICHGeometryPar::getAerogelTileID(TVector2 locpos)
586 double size = (m_aeroRout - m_aeroRin) /
double(m_tileNr);
587 double r = locpos.Mod();
588 double phi = ROOT::Math::VectorUtil::Phi_0_2pi(locpos.Phi());
589 int nr = int((r - m_aeroRin) / size);
591 if (r < m_aeroRin + nr * size + m_tileGap / 2. || r > m_aeroRin + (nr + 1)*size - m_tileGap / 2.)
return 0;
593 double dphi = 2.*M_PI / double(m_tileNphi[nr]);
594 double gapPhi = m_tileGap / (m_aeroRin + (nr + 1) * size - m_tileGap / 2.);
596 int nphi = int(phi / dphi);
597 if (phi < nphi * dphi + gapPhi / 2. || phi > (nphi + 1)*dphi - gapPhi / 2.)
return 0;
600 for (
int i = 0; i < nr; i++) tileID += m_tileNphi[i];
The Class for ARICH Geometry Parameters.
GearDir is the basic class used for accessing the parameter store.
virtual std::string getString(const std::string &path="") const noexcept(false) override
Get the parameter path as a string.
double getAngle(const std::string &path="") const noexcept(false)
Get the parameter path as a double converted to the standard angle unit.
double getDouble(const std::string &path="") const noexcept(false)
Get the parameter path as a double.
std::string getPath() const
Return path of the current interface.
double getLength(const std::string &path="") const noexcept(false)
Get the parameter path as a double converted to the standard length unit.
std::vector< GearDir > getNodes(const std::string &path="") const
Get vector of GearDirs which point to all the nodes the given path evaluates to.
int getInt(const std::string &path="") const noexcept(false)
Get the parameter path as a int.
double sqrt(double a)
sqrt for double
Abstract base class for different kinds of events.