00001
00002
00003
00004 #include "reconstruction/CalRecon.h"
00005
00006
00007
00008
00009
00010
00011 #include "reconstruction/ReconVisitor.h"
00012 #include "reconstruction/CalModules.h"
00013
00014 #include "data/GlastData.h"
00015 #include "data/CsIData.h"
00016 #include "gui/DisplayRep.h"
00017
00018 #include <algorithm>
00019 #include <cmath>
00020
00021 using std::vector;
00022
00023
00024 CalRecon::CalRecon ()
00025 : Recon()
00026 {
00027 getParameters();
00028 setTitle("Glast CalRecon: ver 2.0");
00029
00030 layerLabel.reserve(num_layers);
00031
00032
00033 for(unsigned int i = 0; i < num_layers; i++) {
00034 LRpos.push_back(new vector<Point>);
00035 layerLabel[i] = new char[13];
00036 sprintf(layerLabel[i], "%s%d%c", "CsI_eLayer", (i+1), '\0');
00037 }
00038
00039 i_CsI_eLayer.reserve(num_layers);
00040
00041
00042 i_CsI_Energy = data.addElement("CsI_Energy_Sum");
00043 for(unsigned int j = 0; j < num_layers; j++){
00044 i_CsI_eLayer[j] = data.addElement(layerLabel[j]);
00045 }
00046
00047 i_CsI_Etop = data.addElement("CsI_Etop_Sum");
00048 i_CsI_Ebottom = data.addElement("CsI_Ebot_Sum");
00049 i_CsI_Esides = data.addElement("CsI_Esid_Sum");
00050 i_CsI_S_or_B = data.addElement("CsI_S_or_B");
00051 i_CsI_Xtals = data.addElement("CsI_No_Xtals");
00052 i_CsI_Xtals_trunc = data.addElement("CsI_No_Xtals_Trunc");
00053 i_CsI_Xtals_keep = data.addElement("CsI_No_Xtals_keep");
00054 i_CsI_Rsq_mean = data.addElement("CsI_Rsq_mean");
00055 i_CsI_D3Mean = data.addElement("CsI_D3Mean");
00056 i_CsI_E_moment = data.addElement("CsI_E_moment");
00057 i_CsI_E_disp = data.addElement("CsI_E_disp");
00058 i_CsI_mean_X = data.addElement("CsI_X");
00059 i_CsI_mean_Y = data.addElement("CsI_Y");
00060 i_CsI_mean_Z = data.addElement("CsI_Z");
00061 i_CsI_moment1 = data.addElement("CsI_moment1");
00062 i_CsI_moment2 = data.addElement("CsI_moment2");
00063 i_CsI_moment3 = data.addElement("CsI_moment3");
00064 i_CsI_dir_X = data.addElement("CsI_Xdir");
00065 i_CsI_dir_Y = data.addElement("CsI_Ydir");
00066 i_CsI_dir_Z = data.addElement("CsI_Zdir");
00067 i_CsI_chisq = data.addElement("CsI_Chisq");
00068 i_CsI_mips = data.addElement("CsI_No_MIPs");
00069
00070 i_CsI_MaxMod = data.addElement("CsI_MaxModGT100MeV");
00071
00072 i_CsI_ModXtals = data.addElement("CsI_ModXtalsGT100MeV");
00073
00074 i_Diode_Energy = data.addElement("Diode_Energy");
00075
00076
00077
00078 calModules = new CalModules();
00079
00080 clear();
00081 }
00082
00083
00084 CalRecon::~CalRecon ()
00085 {
00086 unsigned int i;
00087 for(i = 0; i < LRpos.size(); i++) delete LRpos[i];
00088 for(i = 0; i < num_layers; i++) delete layerLabel[i];
00089
00090 delete calModules;
00091 }
00092
00093
00094 void CalRecon::getParameters ()
00095 {
00096 #if 0 // remove external dependence
00097 num_layers = Calorimeter::numberOfLayers();
00098 calmat = CsIXtal::getMaterial();
00099 s_xtal_gap = Diode::getmaxHeight();
00100 s_rad_len = Calorimeter::radLen();
00101 mod_width = Tower::mod_width;
00102 s_wall_thickness = Tower::wall_thickness;
00103 s_wall_gap = Tower::wall_gap;
00104 s_xNum = Glast::xNum;
00105 light_att = Calorimeter::light_att();
00106 #else
00107 num_layers = 8;
00108 calmat = "CsI";
00109 s_xtal_gap = 0.018;
00110 s_rad_len = 9.0300732267775;
00111 mod_width = 38.97;
00112 s_wall_thickness = 0.15;
00113 s_wall_gap = 0.1;
00114 s_xNum = 4;
00115 light_att = 0.5;
00116
00117 #endif
00118 }
00119
00120 void CalRecon::accept (ReconVisitor& rv)
00121 {
00122 rv.visit(this);
00123 }
00124
00125 void CalRecon::reconstruct (const CsIData* csiData)
00126 {
00127 using namespace idents;
00128
00129 if(state() == DONE) return;
00130
00131
00132 calModules->load( *csiData);
00133
00134
00135 const double zero = 0.;
00136 double E_moment = 0., E_disp = 0.;
00137 E_layer.resize(num_layers, 0.);
00138
00139
00140 unsigned int ilayer;
00141 for(ilayer = 0; ilayer < num_layers; ilayer++) {
00142 numlayhits.push_back(csiData->nHits(ilayer));
00143 ntothits += numlayhits[ilayer];
00144 for(int ixtl = 0; ixtl < numlayhits[ilayer]; ixtl++) {
00145 double energy = 0.5*(csiData->Lresp(ilayer, ixtl) + csiData->Rresp(ilayer, ixtl));
00146 eTotal += energy;
00147 E_layer[ilayer] += energy;
00148 }
00149 E_moment += E_layer[ilayer] * (ilayer - num_layers/2.);
00150 }
00151
00152 double diode_total=0.;
00153
00154 for(ilayer = 0; ilayer < num_layers; ilayer++) {
00155 for(int ixtl = 0; ixtl < numlayhits[ilayer]; ixtl++) {
00156 std::vector<double> energy = csiData->Diodes_Energy(ilayer,ixtl);
00157 if( energy.size()<4 ) continue;
00158 diode_total += energy[0]+energy[1]+energy[2]+energy[3];
00159 }
00160 }
00161
00162
00163
00164 if(eTotal <= 0 ) {
00165 setState(DONE);
00166 return;
00167 }
00168
00169 double onePercent = .01*eTotal;
00170
00171 #if 0 //THB: wire in constants taken from simulation
00172 Material *Mat = Material::hatch(calmat);
00173 const float outzone = Mat->radiationLength() * s_rad_len / num_layers;
00174 const float G_hafwid = Glast::Width * 0.5 - ACDTopMed::veto_thickness
00175 - (ACDSideMed::two_layer_side) * ACDTopMed::veto_thickness - ACDTopMed::veto_standoff;
00176 const float XYend_breadth = G_hafwid, XYend_longitd = G_hafwid - s_xtal_gap;
00177 const double E_nXtal = 0.006, E_D3mean = 0.010;
00178 const double zCalBot = Glast::zModCntr - Glast::zModDepth / 2.;
00179 double e_bottom = 0., e_sides = 0.;
00180 float E_100MeV = 0.100f;
00181 const int maxModId = (Glast::xNum*Glast::yNum);
00182 #else
00183 const float outzone = 2.10000f;
00184 const float G_hafwid = 73.9400f;
00185 const float XYend_breadth = G_hafwid, XYend_longitd = G_hafwid - s_xtal_gap;
00186 const double E_nXtal = 0.006, E_D3mean = 0.010;
00187 const double zCalBot = -37.186000000000;
00188 double e_bottom = 0., e_sides = 0.;
00189 float E_100MeV = 0.100f;
00190 const int maxModId = 16;
00191
00192 #endif
00193 int *nXtalsGT100;
00194 nXtalsGT100 = new int[maxModId];
00195 int i;
00196 for ( i = 0; i < maxModId; i++) nXtalsGT100[i] = 0;
00197 int numXtalTrunc = 0, numXtalkeep = 0;
00198
00199 E_hits.resize(ntothits, zero);
00200
00201 int ihit = -1;
00202 for(ilayer = 0; ilayer < num_layers; ilayer++) {
00203 for(int ixtl = 0; ixtl < numlayhits[ilayer]; ixtl++) {
00204 Vector myP = csiData->xtalPos(ilayer, ixtl);
00205
00206 double LRx, LRy, LRz;
00207 double LRsum = csiData->Lresp(ilayer, ixtl) + csiData->Rresp(ilayer, ixtl);
00208 double LRdiff = csiData->Lresp(ilayer, ixtl) - csiData->Rresp(ilayer, ixtl);
00209
00210
00211 double f = - ((2-light_att)/light_att)*LRdiff/LRsum;
00212
00213
00214 double longitudinal_pos = f * (0.5*(mod_width-2*s_xtal_gap));
00215
00216 if( ilayer%2 ) {
00217 LRx = myP.x() + longitudinal_pos;
00218 LRy = myP.y();
00219 } else {
00220 LRx = myP.x();
00221 LRy = myP.y() + longitudinal_pos;
00222 }
00223 LRz = myP.z();
00224
00225
00226 LRpos[ilayer]->push_back(Point(LRx, LRy, LRz));
00227
00228 Vector xPos(LRx, LRy, LRz);
00229
00230 double energy = LRsum*0.5;
00231 E_hits[++ihit] = energy;
00232 bCenter += xPos * energy;
00233
00234
00235 if(energy > onePercent) numXtalTrunc++;
00236 if(energy > E_nXtal) numXtalkeep++;
00237
00238
00239 if(energy > E_100MeV) ++nXtalsGT100[csiData->moduleId(ilayer, ixtl)];
00240
00241
00242 if(ilayer == 0) e_bottom += energy;
00243 if ( (ilayer != num_layers-1) && (ilayer != 0) ) {
00244 if( ilayer%2 ) {
00245 if ( ((XYend_longitd - fabs(xPos.x())) < outzone) ||
00246 ((XYend_breadth - fabs(xPos.y())) < outzone) ) {
00247 e_sides += energy;
00248 }
00249 } else {
00250 if ( ((XYend_breadth - fabs(xPos.x())) < outzone) ||
00251 ((XYend_longitd - fabs(xPos.y())) < outzone) ) {
00252 e_sides += energy;
00253 }
00254 }
00255 }
00256 }
00257 float Eterm = (E_moment - E_layer[ilayer] * (ilayer - num_layers/2.));
00258 E_disp += Eterm * Eterm;
00259 }
00260
00261 E_disp = sqrt(E_disp);
00262 bCenter *= 1./eTotal;
00263
00264
00265 int maxMod = 0, nXtals = 0;
00266 for(int modId = 0; modId < maxModId; ++modId) {
00267 if(nXtalsGT100[modId] > nXtals){
00268 nXtals = nXtalsGT100[modId];
00269 maxMod = modId;
00270 }
00271 }
00272
00273
00274 const int one = 1;
00275 Use_R.clear();
00276 Use_R.resize(ntothits, one);
00277
00278 int counter = 0, maxiter = 2, sid_OR_bot = 0;
00279 double fracHits = 0.35, D3Mean = 0.;
00280
00281 if(eTotal < 0.25) fracHits = 0.50;
00282 while (counter < maxiter) {
00283 if (ntothits > 3) {
00284 moments_anal(counter);
00285 } else {
00286 chisq = -1;
00287 m_dir = Vector(0., 0., 0.);
00288 }
00289 if (chisq == -1) break;
00290
00291
00292 if (counter == (maxiter-1)) {
00293 float zRat = (zCalBot - m_cen.z())/m_dir.z();
00294 float xEdge = zRat*m_dir.x() + m_cen.x();
00295 float yEdge = zRat*m_dir.y() + m_cen.y();
00296 if ((abs(xEdge) > G_hafwid) || (abs(yEdge) > G_hafwid)) sid_OR_bot = 1;
00297 }
00298
00299
00300
00301
00302
00303 vector<double>axial_R_D3;
00304 vector<double>axial_copy;
00305 vector<double>axial_R;
00306
00307 int ihit = -1;
00308 for(ilayer = 0; ilayer < num_layers; ilayer++) {
00309 if (numlayhits[ilayer] != 0) {
00310 for(int ixtl = 0; ixtl < numlayhits[ilayer]; ixtl++) {
00311 Point xPos = (*LRpos[ilayer])[ixtl];
00312 double temp = RLinePnt(xPos);
00313 axial_R.push_back(temp);
00314 axial_copy.push_back(temp);
00315 if(E_hits[++ihit] > E_D3mean) axial_R_D3.push_back(temp);
00316 }
00317 }
00318 }
00319
00320 if(ntothits != 0) {
00321 std::sort(axial_R.begin(), axial_R.end());
00322 double disc_R = axial_R[(int)(ntothits * fracHits)];
00323 for(unsigned int ihit = 0; ihit < axial_R.size(); ihit++) {
00324 if( axial_copy[ihit] > disc_R) Use_R[ihit]=0;
00325 }
00326
00327 if((axial_R_D3.size() > 2) && (counter == 0)) {
00328 std::sort(axial_R_D3.begin(), axial_R_D3.end());
00329 int lastindx = axial_R_D3.size() - 1;
00330 D3Mean = ( axial_R_D3[lastindx] + axial_R_D3[lastindx-1]
00331 + axial_R_D3[lastindx-2] ) / 3.;
00332 }
00333 }
00334 ++counter;
00335 }
00336
00337 float Emax = 0.;
00338 int numTowers = calModules->nMods(), noMIPS = 0;
00339 ModuleId maxTower(0,99999);
00340 for(int iTower = 0; iTower < numTowers; iTower++) {
00341 float eTower = calModules->energy(iTower);
00342 if(eTower > Emax ) {
00343 Emax = eTower;
00344 maxTower = calModules->moduleId(iTower);
00345 }
00346 if(calModules->responseType(iTower) == CalModules::MIP) noMIPS++;
00347 }
00348
00349 data[i_CsI_Energy] = eTotal;
00350 for(unsigned int jlayer = 0; jlayer < num_layers; jlayer++) {
00351 ilayer = num_layers-1 - jlayer;
00352 data[i_CsI_eLayer[jlayer]] = E_layer[ilayer];
00353 }
00354
00355 data[i_Diode_Energy] = diode_total;
00356
00357
00358 data[i_CsI_Etop] = E_layer[(num_layers-1)];
00359 data[i_CsI_Ebottom] = e_bottom;
00360 data[i_CsI_Esides] = e_sides;
00361 data[i_CsI_S_or_B] = sid_OR_bot;
00362
00363 data[i_CsI_Xtals] = ntothits;
00364 data[i_CsI_Xtals_trunc] = numXtalTrunc;
00365 data[i_CsI_Xtals_keep] = numXtalkeep;
00366 data[i_CsI_Rsq_mean] = m_Rsq_mean;
00367 data[i_CsI_D3Mean] = D3Mean;
00368 data[i_CsI_E_moment] = E_moment;
00369 data[i_CsI_E_disp] = E_disp;
00370
00371 data[i_CsI_mean_X] = m_cen.x();
00372 data[i_CsI_mean_Y] = m_cen.y();
00373 data[i_CsI_mean_Z] = m_cen.z();
00374 data[i_CsI_moment1] = moment1;
00375 data[i_CsI_moment2] = moment2;
00376 data[i_CsI_moment3] = moment3;
00377
00378 data[i_CsI_dir_X] = m_dir.x();
00379 data[i_CsI_dir_Y] = m_dir.y();
00380 data[i_CsI_dir_Z] = m_dir.z();
00381
00382 data[i_CsI_chisq] = chisq;
00383 data[i_CsI_mips] = noMIPS;
00384
00385 data[i_CsI_MaxMod] = maxMod;
00386 data[i_CsI_ModXtals] = nXtalsGT100[maxMod];
00387
00388 setState(DONE);
00389
00390 delete [] nXtalsGT100;
00391
00392 unsigned int j;
00393 for(j=0; j < LRpos.size(); j++) {
00394 LRpos[j]->clear();
00395 }
00396 return;
00397
00398 }
00399
00400 void CalRecon::clear ()
00401 {
00402 Recon::clear();
00403 data.clear();
00404 numlayhits.clear();
00405 E_hits.clear();
00406 E_layer.clear();
00407 calModules->clear();
00408 bCenter = Point(0,0,0);
00409 chisq = 0;
00410 eTotal = 0.0;
00411 ntothits = 0;
00412 m_dir = Vector(0., 0., 0.);
00413 }
00414
00415 void CalRecon::draw (gui::DisplayRep& v)
00416 {
00417 static double scale=10;
00418 static const char* number[]={"0","1","2"};
00419
00420 v.setColor("blue");
00421 v.markerAt(bCenter);
00422
00423 if( chisq > 0 ) {
00424
00425 for( int i = 0; i<3; i++) {
00426 double d = scale*moment[1]/moment[i];
00427 v.moveTo(bCenter + principal_axis[i]*d);
00428 v.lineTo(bCenter - principal_axis[i]*d);
00429 v.drawText(number[i]);
00430 }
00431 }
00432
00433 v.setColor("black");
00434 }
00435
00436 void CalRecon::moments_anal (int counter)
00437 {
00438 float Ethres = .001f;
00439 double xprm = 0., yprm = 0., zprm = 0., Rsq = 0.,
00440 Ixx = 0., Iyy = 0., Izz = 0.,
00441 Ixy = 0., Ixz = 0., Iyz = 0.;
00442
00443 numXtals = 0;
00444 if (counter == 0) m_Rsq_mean = 0.;
00445
00446
00447
00448
00449
00450 m_cen = Point(bCenter.x(), bCenter.y(), bCenter.z());
00451
00452 int ihit = -1;
00453 unsigned int ilayer;
00454 for(ilayer = 0; ilayer < num_layers; ilayer++) {
00455 for(int ixtl = 0; ixtl < numlayhits[ilayer]; ixtl++) {
00456 ++ihit;
00457 if((E_hits[ihit] > Ethres) && (Use_R[ihit] > 0)) {
00458 numXtals++;
00459
00460 Point myPos = (*LRpos[ilayer])[ixtl];
00461 xprm = myPos.x() - m_cen.x();
00462 yprm = myPos.y() - m_cen.y();
00463 zprm = myPos.z() - m_cen.z();
00464
00465 Rsq = xprm*xprm + yprm*yprm + zprm*zprm;
00466 if (counter == 0) m_Rsq_mean += Rsq;
00467 Ixx += (Rsq - xprm*xprm) * E_hits[ihit];
00468 Iyy += (Rsq - yprm*yprm) * E_hits[ihit];
00469 Izz += (Rsq - zprm*zprm) * E_hits[ihit];
00470 Ixy -= xprm*yprm * E_hits[ihit];
00471 Ixz -= xprm*zprm * E_hits[ihit];
00472 Iyz -= yprm*zprm * E_hits[ihit];
00473 }
00474 }
00475 }
00476
00477 if ((counter == 0) && (numXtals > 0)) m_Rsq_mean = m_Rsq_mean / numXtals;
00478
00479
00480
00481 double intcp, slope, resid = 0.;
00482 double p, q, r, a, b, rad_test, m, psi;
00483
00484
00485
00486 p = - (Ixx + Iyy + Izz);
00487 q = Iyy*Izz + Iyy*Ixx + Izz*Ixx - (Ixy*Ixy + Iyz*Iyz + Ixz*Ixz);
00488 r = - Ixx*Iyy*Izz + Ixx*Iyz*Iyz + Iyy*Ixz*Ixz +
00489 Izz*Ixy*Ixy - 2.*Ixy*Iyz*Ixz;
00490
00491
00492
00493
00494
00495
00496
00497 a = (3.*q - p*p)/3.;
00498 b = (2.*p*p*p - 9.*p*q + 27.*r)/27.;
00499
00500 rad_test = b*b/4. + a*a*a/27.;
00501
00502 float dircos[3][3];
00503
00504 if ((rad_test < 0.) && (Ixy != 0.) && (Ixz != 0.) && (Iyz != 0.) ){
00505
00506
00507
00508 m = 2. * sqrt(-a/3.);
00509 psi = acos( 3.*b/(a*m) ) / 3.;
00510 moment[0] = m * cos(psi) - p/3.;
00511 moment[1] = m * cos(psi + 2.*M_PI/3.) - p/3.;
00512 moment[2] = m * cos(psi + 4.*M_PI/3.) - p/3.;
00513
00514 if (counter == 0) {
00515 moment1 = moment[0];
00516 moment2 = moment[1];
00517 moment3 = moment[2];
00518 }
00519
00520
00521
00522
00523 double A, B, C, D;
00524
00525 for(int iroot=0; iroot<3; iroot++) {
00526 A = Iyz * (Ixx - moment[iroot]) - Ixy*Ixz;
00527 B = Ixz * (Iyy - moment[iroot]) - Ixy*Iyz;
00528 C = Ixy * (Izz - moment[iroot]) - Ixz*Iyz;
00529
00530 D = sqrt( 1. / ( 1./(A*A) + 1./(B*B) + 1./(C*C) ) ) / C;
00531 dircos[0][iroot] = D * C / A;
00532 dircos[1][iroot] = D * C / B;
00533 dircos[2][iroot] = D;
00534
00535
00536
00537 principal_axis[iroot] = Vector(D*C/A, D*C/B, D);
00538 }
00539
00540 m_dir = Vector(dircos[0][1], dircos[1][1], dircos[2][1]);
00541
00542
00543
00544 slope = m_dir.y() / m_dir.x();
00545 intcp = m_cen.y() - slope * m_cen.x();
00546 chisq = 0.;
00547
00548 int ihit = -1;
00549 for(ilayer = 0; ilayer < num_layers; ilayer++) {
00550 for(int ixtl = 0; ixtl < numlayhits[ilayer]; ixtl++) {
00551
00552 Point xPos = (*LRpos[ilayer])[ixtl];
00553 resid = (xPos.y() - (intcp + slope*xPos.x()));
00554 chisq += resid*resid*E_hits[++ihit];
00555 }
00556 }
00557 chisq = ntothits>2 ? chisq/(ntothits - 2): 0;
00558 }
00559
00560
00561
00562 else {
00563 chisq = -1.;
00564 m_dir = Vector(0., 0., 0.);
00565 }
00566 }
00567
00568 double CalRecon::RLinePnt (Point xPos)
00569 {
00570
00571 Vector r(xPos - m_cen);
00572 Vector LinePt = r.cross(m_dir);
00573 return( (LinePt.mag() / m_dir.mag()) );
00574 }
00575
00576