Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

CalRecon.cxx

Go to the documentation of this file.
00001 // $Header: /nfs/slac/g/glast/ground/cvs/reconstruction/src/CalRecon.cxx,v 1.11 2001/01/22 15:53:55 burnett Exp $
00002 
00003 
00004 #include "reconstruction/CalRecon.h"
00005 /*
00006 #include "instrument/Calorimeter.h"
00007 #include "instrument/Glast.h"
00008 #include "instrument/Tower.h"
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> // for sort
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     // Initialize the list; using position from Left/Right recombination
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     // Initialize Labelled Data Array...
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     // module with the max # of xtals with > 100 MeV apiece
00070     i_CsI_MaxMod = data.addElement("CsI_MaxModGT100MeV");
00071     // number of xtals, with > 100 MeV apiece, in any module 
00072     i_CsI_ModXtals = data.addElement("CsI_ModXtalsGT100MeV");
00073         
00074         i_Diode_Energy =  data.addElement("Diode_Energy");
00075     // Total energy in all the diodes
00076     
00077         // Make a Modules Object to analyze cal data, tower by tower
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     // First do module analysis...
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     // Determine Total energy deposited in Calorimeter
00140     unsigned int ilayer; // to be compatible with old/new ANSI for loop scoping
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;           // Total energy in CAL
00147             E_layer[ilayer] += energy;  // Total energy per layer
00148         }
00149         E_moment += E_layer[ilayer] * (ilayer - num_layers/2.);
00150     }
00151     
00152     double diode_total=0.;
00153     // computes total energy in all the diodes
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];           // Total energy in diodes
00159           }
00160     }
00161 
00162 
00163 
00164     if(eTotal <= 0 ) { // nothing in Cal: abort reconstruction
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.; //z-coord of bottom of CAL
00179     double e_bottom = 0., e_sides = 0.;
00180     float E_100MeV = 0.100f;  // 100 MeV
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; //z-coord of bottom of CAL
00188     double e_bottom = 0., e_sides = 0.;
00189     float E_100MeV = 0.100f;  // 100 MeV
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++) {    // bottom to top
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 //            double f = -3.0*LRdiff/LRsum;  // range: 0.->1. => -16.25+gap -> +16.25-gap cm
00211             double f = - ((2-light_att)/light_att)*LRdiff/LRsum; 
00212                         // light attenuation is defined now in xml file
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             // filling the new list of positions
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             // Count number of Xtals with > 1% of total energy, and with > E_nXtal
00235             if(energy > onePercent) numXtalTrunc++;
00236             if(energy > E_nXtal) numXtalkeep++;
00237             // count number of xtals with energy > E_100MeV
00238             // keeping track for individual towers
00239             if(energy > E_100MeV) ++nXtalsGT100[csiData->moduleId(ilayer, ixtl)];
00240             
00241             // Sum energy in Xtals w/in outer layers, within outzone of sides or bottom.
00242             if(ilayer == 0) e_bottom += energy;  // sum energy deposited in bottom layer
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     // which module has the most xtals with energy > 100 MeV
00265     int maxMod = 0, nXtals = 0;
00266     for(int modId = 0; modId < maxModId; ++modId) { // loop through all modules
00267         if(nXtalsGT100[modId] > nXtals){
00268             nXtals = nXtalsGT100[modId];
00269             maxMod = modId;
00270         }
00271     }
00272 
00273     // Create Use_R list and initialize to 1
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) {  // require at least 3 xtals to perform moments analysis
00284                         moments_anal(counter);
00285                 } else {
00286                         chisq = -1;
00287                         m_dir = Vector(0., 0., 0.);
00288                 }
00289         if (chisq == -1) break;
00290 
00291         // determine if reconstructed trajectory hits side or bottom. 1 = side, 0 = bottom
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         // compute perpendicular distances between longest axis and Xtal hits
00300         // creating a list of the distances.  sort, tagging distances above
00301         // {fracHits percentile} for nonuse in next iteration of moment_anal.
00302         // compute vertical energy moment and dispersion
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; // total energy deposited in CAL
00350     for(unsigned int jlayer = 0; jlayer < num_layers; jlayer++) { // From top to bottom
00351       ilayer = num_layers-1 - jlayer;
00352         data[i_CsI_eLayer[jlayer]] = E_layer[ilayer];  // Energy per layer
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     // Destroy the lists
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 ) {// no solution, no display
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     // Construct elements of (symmetric) "Inertia" Tensor:
00447     // See Goldstein, 1965, Chapter 5 (especially, eqs. 5-6,7,22,26).
00448     // Analysis easy when translated to energy centroid.
00449 
00450     m_cen = Point(bCenter.x(), bCenter.y(), bCenter.z());
00451 
00452     int ihit = -1;
00453     unsigned int ilayer; // for compatible old/new ANSI for-loop scoping
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     // Fit Calorimeter Track via principal moments approach.
00480 
00481     double intcp, slope, resid = 0.;
00482     double p, q, r, a, b, rad_test, m, psi;
00483 
00484     // Render determinant of Inertia Tensor into cubic form.
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     // See CRC's Standard Mathematical Tables (19th edition), pp 103-105.
00492     // The substitution, y = x - p/3 converts  y^3 + p*y^2 + q*y + r = 0
00493     // to the form  x^3 + a*x + b = 0 .  Then, if b^2/4 + a^3/27 < 0 ,
00494     // there will be three real roots -- guaranteed since the Inertia Tensor
00495     // is symmetric.  A second substitution, x = m*cos(psi) , yields the roots.
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         // Construct the roots, which are the principal moments.
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         // Construct direction cosines; dircos for middle root is parallel to
00521         // longest principal axis.
00522 
00523         double A, B, C, D;  // needs to be double, else FPE under OSF
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             // Create vector corresponding to roots
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         // Chisquared = sum of residuals about principal axis, through centroid
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                 //Point xPos = csiData->xtalPos(ilayer, ixtl);
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     // ill-conditioned cubic solution:
00561 
00562     else {
00563         chisq = -1.;
00564         m_dir = Vector(0., 0., 0.);
00565     }
00566 }
00567 
00568 double CalRecon::RLinePnt (Point xPos)
00569 {    
00570     // compute distance between a line and a point
00571     Vector r(xPos - m_cen);
00572     Vector LinePt = r.cross(m_dir);
00573     return( (LinePt.mag() / m_dir.mag()) );
00574 }
00575 
00576 

Generated at Wed Nov 21 12:20:43 2001 by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000