9 #include <framework/gearbox/GearDir.h>
10 #include <framework/logging/Logger.h>
11 #include <framework/gearbox/Unit.h>
13 #include <arich/geometry/ARICHGeometryPar.h>
16 #include <boost/format.hpp>
17 #include <boost/foreach.hpp>
20 using namespace boost;
28 ARICHGeometryPar* ARICHGeometryPar::p_B4ARICHGeometryParDB = 0;
32 if (!p_B4ARICHGeometryParDB) {
35 return p_B4ARICHGeometryParDB;
38 ARICHGeometryPar::ARICHGeometryPar()
43 ARICHGeometryPar::~ARICHGeometryPar()
47 void ARICHGeometryPar::Initialize(
const GearDir& content,
const GearDir& mirrorcontent)
51 string Type = content.getString(
"@type",
"");
52 if (Type ==
"beamtest") {
54 modulesPositionSimple(content);
55 mirrorPositionSimple(mirrorcontent);
57 modulesPosition(content);
58 mirrorPositions(content);
59 frontEndMapping(content);
63 initDetectorMask(m_fR.size());
64 readModuleInfo(content);
68 void ARICHGeometryPar::Initialize(
const GearDir& content)
73 void ARICHGeometryPar::clear(
void)
81 m_mirrorOuterRad = 0.0;
82 m_mirrorThickness = 0.0;
83 m_mirrorStartAng = 0.0;
88 m_detInnerRadius = 0.0;
89 m_detOuterRadius = 0.0;
94 m_ncol.clear(); m_fDFi.clear(); m_fDR.clear(); m_fR.clear();
95 m_fFi.clear(); m_fFiMod.clear(); m_chipLocPos.clear(); m_padWorldPositions.clear(); m_mirrornorm.clear(); m_mirrorpoint.clear();
97 for (
int i = 0; i < MAX_N_ALAYERS; i++) {
98 m_aeroTrLength[i] = 0; m_aeroRefIndex[i] = 0;
99 m_aeroZPosition[i] = 0; m_aeroThickness[i] = 0;
107 m_windowAbsorbtion = 0.;
108 m_chipNegativeCrosstalk = 0;
109 for (
int i = 0; i < MAXPTS_QE; i++) {m_QE[i] = 0.;}
115 for (
int i = 0; i < 5; i++) m_tileNphi[i] = 0;
119 void ARICHGeometryPar::read(
const GearDir& content)
125 GearDir detParams(content,
"Detector");
126 m_modXSize = detParams.
getLength(
"Module/moduleXSize");
127 m_modZSize = detParams.
getLength(
"Module/moduleZSize");
128 m_winThick = detParams.
getLength(
"Module/windowThickness");
129 m_nPadX = detParams.
getInt(
"Module/padXNum");
130 m_nPads = m_nPadX * m_nPadX;
131 m_padSize = detParams.
getLength(
"Module/padSize");
132 m_chipGap = detParams.
getLength(
"Module/chipGap");
133 m_detZpos = detParams.
getLength(
"Plane/zPosition");
134 m_qeScale = detParams.
getDouble(
"Module/qeScale");
135 m_windowAbsorbtion = detParams.
getDouble(
"Module/windowAbsorbtion");
136 m_chipNegativeCrosstalk = detParams.
getDouble(
"Module/chipNegativeCrosstalk");
137 string Type = content.getString(
"@type",
"");
138 if (Type ==
"beamtest")
return;
139 m_detInnerRadius = detParams.
getLength(
"Plane/tubeInnerRadius");
140 m_detOuterRadius = detParams.
getLength(
"Plane/tubeOuterRadius");
142 GearDir mirrParams(content,
"Mirrors");
144 m_nMirrors = mirrParams.
getInt(
"nMirrors");
145 m_mirrorThickness = mirrParams.
getLength(
"mirrorThickness");
146 m_mirrorOuterRad = mirrParams.
getLength(
"outerRadius");
147 m_mirrorStartAng = mirrParams.
getAngle(
"startAngle");
148 m_mirrorZPos = mirrParams.
getLength(
"Zposition");
151 GearDir qeParams(content,
"QE");
152 m_ColEffi = qeParams.
getDouble(
"ColEffi");
153 m_LambdaFirst = qeParams.
getLength(
"LambdaFirst") / Unit::nm;
154 m_LambdaStep = qeParams.
getLength(
"LambdaStep") / Unit::nm;
156 for (
int i = 0; i < MAXPTS_QE; i++) {
158 stringstream ss;
string cc;
160 string path =
"Qeffi[@component='point-" + cc +
"']/";
167 GearDir aerogel(content,
"Aerogel");
168 m_tileNr = aerogel.
getInt(
"tileNr");
169 m_tileGap = aerogel.
getLength(
"tileGap") / Unit::cm;
170 m_aeroRin = aerogel.
getLength(
"tubeInnerRadius") / Unit::cm;
171 m_aeroRout = aerogel.
getLength(
"tubeOuterRadius") / Unit::cm;
175 m_tileNphi[i] = ring.getInt();
181 void ARICHGeometryPar::frontEndMapping(
const GearDir& content)
184 GearDir mapping(content,
"FrontEndMapping");
187 unsigned mergerID = (unsigned) merger.getInt(
"@id");
189 auto testMer = m_mergerIDs.find(mergerID);
190 if (testMer != m_mergerIDs.end()) {
191 B2ERROR(mapping.
getPath() <<
"/MergerID " << mergerID <<
192 " ***input already used");
195 m_mergerIDs.insert(mergerID);
197 std::vector<unsigned> boardIDs;
198 for (
const GearDir& board : merger.getNodes(
"FEboards/FEboard")) {
199 unsigned boardID = board.getInt();
200 auto testBor = m_boardIDs.find(boardID);
201 if (testBor != m_boardIDs.end()) {
202 B2ERROR(mapping.
getPath() <<
"/FEboardID " << boardID <<
203 " ***input already used");
205 boardIDs.push_back(boardID);
206 m_boardIDs.insert(boardID);
208 m_merger2feb.insert(std::pair<
int, std::vector<unsigned>>(mergerID, boardIDs));
209 unsigned copperID = (unsigned) merger.getInt(
"COPPERid");
210 string finesseSlot = merger.getString(
"FinesseSlot");
212 if (finesseSlot ==
"A") {finesse = 0;}
213 else if (finesseSlot ==
"B") {finesse = 1;}
214 else if (finesseSlot ==
"C") {finesse = 2;}
215 else if (finesseSlot ==
"D") {finesse = 3;}
217 B2ERROR(merger.getPath() <<
"/FinesseSlot " << finesseSlot <<
218 " ***invalid slot (valid are A, B, C, D)");
222 m_copperIDs.insert(copperID);
224 std::pair<unsigned, int> copfin(copperID, finesse);
225 m_copper2merger.insert(std::pair<std::pair<unsigned, int>,
unsigned>(copfin, mergerID));
231 int ARICHGeometryPar::getMergerFromCooper(
int copperID,
int finesse)
233 auto merger = m_copper2merger.find(std::pair<unsigned, int>(copperID, finesse));
234 if (merger == m_copper2merger.end()) {
240 return merger->second;
243 int ARICHGeometryPar::getBoardFromMerger(
int mergerID,
int slot)
245 auto boards = m_merger2feb.find(mergerID);
246 if (boards == m_merger2feb.end()) {
247 B2ERROR(
"getBoardFromMerger: " <<
" merger " << mergerID <<
" is not mapped");
250 if ((boards->second).size() <=
unsigned(slot)) {
251 B2ERROR(
"getBoardFromMerger: " <<
" merger " << mergerID <<
" slot " << slot <<
" is not assigned to FE board.");
254 return (boards->second).at(slot);
257 int ARICHGeometryPar::getNBoardsOnMerger(
int mergerID)
259 auto boards = m_merger2feb.find(mergerID);
260 if (boards == m_merger2feb.end()) {
261 B2ERROR(
"getNBoardsOnMerger: " <<
" merger " << mergerID <<
" is not mapped");
263 return (boards->second).size();
266 void ARICHGeometryPar::readModuleInfo(
const GearDir& content)
268 istringstream chstream;
270 GearDir modParams(content,
"ModuleInfo");
271 uint8_t defqe = uint8_t(modParams.
getDouble(
"DefaultQE") * 100);
272 m_ChannelQE.assign(m_nPads * m_fR.size(), defqe);
274 int modid = atoi(module.getString(
"@id",
"").c_str());
275 chstream.str(module.getString(
"ChannelsQE"));
276 while (chstream >> ch >> qq) {
277 int chid = (modid - 1) * m_nPads + ch;
278 m_ChannelQE[chid] = uint8_t(qq * 100);
281 chstream.str(module.getString(
"DeadChannels"));
282 while (chstream >> ch) {
283 setActive(modid, ch,
false);
289 double ARICHGeometryPar::QE(
double e)
const
291 if (e < 0.001)
return 0;
292 double dlam = 1240 / e - m_LambdaFirst;
293 if (dlam < 0)
return 0;
294 int i = int(dlam / m_LambdaStep);
295 if (i > m_NpointsQE - 2)
return 0;
296 return m_QE[i] + (m_QE[i + 1] - m_QE[i]) / m_LambdaStep * (dlam - i * m_LambdaStep);
300 void ARICHGeometryPar::Print(
void)
const
304 double ARICHGeometryPar::getChannelQE(
int moduleID,
int channelID)
306 int id = (moduleID - 1) * m_nPads + channelID;
307 return m_ChannelQE.at(
id) / 100.0;
310 int ARICHGeometryPar::getChannelID(TVector2 position)
312 int ChipID = getChipID(position);
313 int Npad = int(m_nPadX / 2);
314 TVector2 chipPos = getChipLocPos(ChipID);
315 TVector2 locloc = position - chipPos;
316 int ix = int(locloc.X() / m_padSize);
317 int iy = int(locloc.Y() / m_padSize);
318 if (locloc.X() < 0 || locloc.Y() < 0)
return -1;
319 if (ix > Npad - 1 || iy > Npad - 1)
return -1;
320 int chID = ChipID * Npad * Npad + iy + ix * Npad;
324 void ARICHGeometryPar::modulesPosition(
const GearDir& content)
327 GearDir detParams(content,
"Detector/Plane/Rings");
329 double r = m_detInnerRadius;
334 double rcenter = r + m_modXSize / 2.;
335 if (rcenter + m_modXSize * sqrt(2) / 2. > m_detOuterRadius) {
336 B2WARNING(m_ncol.size() + 1 <<
"th ring of ARICH photon detectors will not be placed (out of detector tube).");
340 int nSeg = ring.
getInt(
"nSegments") ;
343 double f = 2.*atan2((m_modXSize + dFi) / 2., r);
344 int blaa = int(2.*M_PI / f / nSeg) * nSeg;
345 m_ncol.push_back(blaa);
346 f = 2.*M_PI / double(blaa);
348 B2INFO(blaa <<
" modules of " << m_ncol.size() <<
"th ring of ARICH photon detectors will be placed at r = " << rcenter <<
"cm. ");
349 for (
int nv = 0; nv < blaa; ++nv) {
350 m_fR.push_back(rcenter);
351 double fi = f * (nv + 0.5);
353 m_fFiMod.push_back(fi);
355 r += (m_modXSize + r * (1 - cos(f / 2.)));
357 B2INFO(
"Altogether " << m_fR.size() <<
" ARICH photon detector modules will be placed.");
360 void ARICHGeometryPar::modulesPositionSimple(
const GearDir& content)
362 BOOST_FOREACH(
const GearDir & module, content.getNodes(
"Detector/Plane/Modules/Module")) {
363 TVector2 position(module.getLength(
"xPos"), module.getLength(
"yPos"));
364 double angle = module.getAngle(
"angle") / Unit::rad;
365 m_fFi.push_back(position.Phi());
366 m_fR.push_back(position.Mod());
367 m_fFiMod.push_back(angle);
369 B2INFO(
"Altogether " << m_fR.size() <<
" ARICH photon detector modules will be placed.");
372 int ARICHGeometryPar::getCopyNo(TVector3 hit)
376 double r = sqrt(x * x + y * y);
377 double fi = atan2(y, x);
378 if (fi < 0) fi += 2 * M_PI;
380 for (
int i = 0; i < m_nrow; i++) {
381 int nfi = int(fi / m_fDFi[i]);
382 int copyno = ntot + nfi;
383 if (fabs(r - m_fR[copyno]) < m_modXSize / 2.)
return copyno + 1;
389 TVector3 ARICHGeometryPar::getOrigin(
int copyNo)
392 origin.SetMagPhi(m_fR[copyNo - 1], m_fFi[copyNo - 1]);
393 return TVector3(origin.X(), origin.Y(), m_detZpos + m_modZSize / 2.);
396 G4ThreeVector ARICHGeometryPar::getOriginG4(
int copyNo)
398 TVector3 origin = getOrigin(copyNo);
399 return G4ThreeVector(origin.X() / Unit::mm, origin.Y() / Unit::mm, origin.Z() / Unit::mm);
402 double ARICHGeometryPar::getModAngle(
int copyno)
404 return m_fFiMod[copyno - 1];
407 void ARICHGeometryPar::chipLocPosition()
409 double xycenter = m_padSize * m_nPadX / 4. + m_chipGap / 2.;
410 m_chipLocPos.push_back(TVector2(xycenter - m_padSize * m_nPadX / 4., xycenter - m_padSize * m_nPadX / 4.));
411 m_chipLocPos.push_back(TVector2(xycenter - m_padSize * m_nPadX / 4., -xycenter - m_padSize * m_nPadX / 4.));
412 m_chipLocPos.push_back(TVector2(-xycenter - m_padSize * m_nPadX / 4., xycenter - m_padSize * m_nPadX / 4.));
413 m_chipLocPos.push_back(TVector2(-xycenter - m_padSize * m_nPadX / 4., -xycenter - m_padSize * m_nPadX / 4.));
417 int ARICHGeometryPar::getChipID(TVector2 locpos)
419 if (locpos.X() > 0) {
420 if (locpos.Y() > 0)
return 0;
423 if (locpos.Y() > 0)
return 2;
428 TVector3 ARICHGeometryPar::getChannelCenterGlob(
int modID,
int chanID)
430 int id = (modID - 1) * m_nPads + chanID;
431 return TVector3(m_padWorldPositions.at(
id).X(), m_padWorldPositions.at(
id).Y(), m_detZpos + m_winThick);
434 TVector2 ARICHGeometryPar::getChannelCenterLoc(
int chID)
436 return m_padLocPositions[chID];
440 void ARICHGeometryPar::padPositions()
442 int Npad = int(m_nPadX / 2.);
443 TVector2 xstart(m_padSize / 2., m_padSize / 2.);
444 for (
int chipID = 0; chipID < 4; chipID++) {
445 TVector2 chipPos = getChipLocPos(chipID);
446 for (
int ix = 0; ix < Npad; ix++) {
447 for (
int iy = 0; iy < Npad; iy++) {
448 int chanID = chipID * Npad * Npad + ix * Npad + iy;
449 TVector2 center(m_padSize / 2. + ix * m_padSize, m_padSize / 2. + iy * m_padSize);
450 center = center + chipPos;
451 m_padLocPositions[chanID] = center;
455 for (
int iMod = 0; iMod < getNMCopies(); iMod++) {
456 for (
unsigned int iChan = 0; iChan < m_padLocPositions.size(); iChan++) {
458 iModCenter.SetMagPhi(m_fR[iMod], m_fFi[iMod]);
459 TVector2 iChanCenter = m_padLocPositions[iChan];
460 iChanCenter = iChanCenter.Rotate(m_fFiMod[iMod]);
461 TVector2 iWorld((iModCenter + iChanCenter).X(), (iModCenter + iChanCenter).Y());
462 m_padWorldPositions.push_back(iWorld);
467 void ARICHGeometryPar::mirrorPositions(
const GearDir& content)
469 double rmir = m_mirrorOuterRad * cos(M_PI / m_nMirrors) - m_mirrorThickness;
470 for (
int i = 0; i < m_nMirrors; i++) {
471 TVector3 norm(cos(2.*M_PI /
double(m_nMirrors) * (i + 0.5) + m_mirrorStartAng),
472 sin(2.*M_PI /
double(m_nMirrors) * (i + 0.5) + m_mirrorStartAng), 0);
473 m_mirrornorm.push_back(norm);
474 m_mirrorpoint.push_back(rmir * norm);
476 readMirrorAlignment(content);
479 void ARICHGeometryPar::mirrorPositionSimple(
const GearDir& content)
481 double thick = content.getLength(
"Mirrors/thickness");
482 BOOST_FOREACH(
const GearDir & mirror, content.getNodes(
"Mirrors/Mirror")) {
483 double angle = mirror.
getAngle(
"angle");
484 TVector3 point(mirror.
getLength(
"xPos") - cos(angle)*thick / 2., mirror.
getLength(
"yPos") - sin(angle)*thick / 2., 0);
485 TVector3 norm(cos(angle), sin(angle), 0);
486 m_mirrorpoint.push_back(point);
487 m_mirrornorm.push_back(norm);
493 TVector3 ARICHGeometryPar::getMirrorNormal(
int mirID)
495 return m_mirrornorm[mirID];
498 TVector3 ARICHGeometryPar::getMirrorPoint(
int mirID)
500 return m_mirrorpoint[mirID];
503 void ARICHGeometryPar::setAeroTransLength(
int layer,
double trlength)
505 m_aeroTrLength[layer] = trlength;
508 void ARICHGeometryPar::setAeroRefIndex(
int layer,
double n)
510 if (n) m_aeroRefIndex[layer] = n;
513 void ARICHGeometryPar::setAerogelThickness(
int layer,
double thick)
516 m_aeroThickness[layer] = thick;
519 void ARICHGeometryPar::setAerogelZPosition(
int layer,
double zPos)
521 m_aeroZPosition[layer] = zPos;
524 void ARICHGeometryPar::setWindowRefIndex(
double refInd)
526 m_winRefInd = refInd;
529 void ARICHGeometryPar::initDetectorMask(
int nmodules)
531 int m_DetectorMaskSize = m_nPads * nmodules / 32 + 1;
532 for (
int i = 0; i < m_DetectorMaskSize; i++) {
533 m_DetectorMask.push_back(0xFFFFFFFF);
535 B2INFO(
"DetectorMask initialized size=" << m_nPads <<
" * " << nmodules <<
" +1 =" << m_DetectorMaskSize);
539 void ARICHGeometryPar::setActive(
int module,
int channel,
bool active)
541 int ch = (module - 1) * m_nPads + channel;
543 unsigned int idx = ch / 32;
544 if (idx >= m_DetectorMask.size()) {
545 B2WARNING(idx <<
" Wrong detector mask size >= " << m_DetectorMask.size());
547 if (active) m_DetectorMask[idx] |= (1 << bit);
548 else m_DetectorMask[idx] &= ~(1 << bit);
551 bool ARICHGeometryPar::isActive(
int module,
int channel)
553 int ch = (module - 1) * m_nPads + channel;
556 return m_DetectorMask[idx] & (1 << bit);
559 void ARICHGeometryPar::readMirrorAlignment(
const GearDir& content)
561 GearDir modParams(content,
"Mirrors/Alignment");
564 int id = atoi(plate.
getString(
"@id").c_str());
566 double dphi = plate.
getAngle(
"dphi");
567 double dtheta = plate.
getAngle(
"dtheta");
568 m_mirrorpoint[
id - 1].SetMag(m_mirrorpoint[
id - 1].Mag() + dr);
569 m_mirrornorm[
id - 1].SetTheta(m_mirrornorm[
id - 1].Theta() + dtheta);
570 m_mirrornorm[
id - 1].SetPhi(m_mirrornorm[
id - 1].Phi() + dphi);
575 int ARICHGeometryPar::getAerogelTileID(TVector2 locpos)
578 double size = (m_aeroRout - m_aeroRin) /
double(m_tileNr);
579 double r = locpos.Mod();
580 double phi = TVector2::Phi_0_2pi(locpos.Phi());
581 int nr = int((r - m_aeroRin) / size);
583 if (r < m_aeroRin + nr * size + m_tileGap / 2. || r > m_aeroRin + (nr + 1)*size - m_tileGap / 2.)
return 0;
585 double dphi = 2.*M_PI / double(m_tileNphi[nr]);
586 double gapPhi = m_tileGap / (m_aeroRin + (nr + 1) * size - m_tileGap / 2.);
588 int nphi = int(phi / dphi);
589 if (phi < nphi * dphi + gapPhi / 2. || phi > (nphi + 1)*dphi - gapPhi / 2.)
return 0;
592 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.
Abstract base class for different kinds of events.