//******************************************************** // DFDCPseudo_factory.cc - factory producing first-order // reconstructed points for the FDC // Author: Craig Bookwalter (craigb at jlab.org) // Date: March 2006 // UVX cathode-wire matching revised by Simon Taylor, Aug 2006 //******************************************************** #include "DFDCPseudo_factory.h" #define HALF_CELL 0.5 #define MAX_DEFLECTION 0.15 #define X0 0 #define QA 1 #define K2 2 #define ITER_MAX 100 #define TOLX 1e-4 #define TOLF 1e-4 #define A_OVER_H 0.475 #define ALPHA 1e-4 // rate parameter for Newton step backtracking algorithm /// /// DFDCCathodeCluster_gLayer_cmp(): /// non-member function passed to std::sort() to sort DFDCCathodeCluster pointers /// by their gLayer attributes. /// bool DFDCCathodeCluster_gLayer_cmp(const DFDCCathodeCluster* a, const DFDCCathodeCluster* b) { return a->gLayer < b->gLayer; } /// /// DFDCAnode_gLayer_cmp(): /// non-member function passed to std::sort() to sort DFDCHit pointers /// for the anode wires by their gLayer attributes. /// bool DFDCAnode_gLayer_cmp(const DFDCHit* a, const DFDCHit* b) { return a->gLayer < b->gLayer; } /// /// DFDCPseudo_factory::DFDCPseudo_factory(): /// default constructor -- initializes log file /// DFDCPseudo_factory::DFDCPseudo_factory() { logFile = new ofstream("DFDCPseudo_factory.log"); _log = new JStreamLog(*logFile, "PSEUDO"); *_log << "File initialized." << endMsg; } /// /// DFDCPseudo_factory::~DFDCPseudo_factory(): /// default destructor -- closes log file /// DFDCPseudo_factory::~DFDCPseudo_factory() { logFile->close(); delete logFile; delete _log; } /// /// DFDCPseudo_factory::evnt(): /// this is the place that anode hits and DFDCCathodeClusters are organized into pseudopoints. /// jerror_t DFDCPseudo_factory::evnt(JEventLoop* eventLoop, int eventNo) { vector fdcHits; vector xHits; vector cathClus; vector uClus; vector oneLayerU; vector vClus; vector oneLayerV; vector oneLayerX; eventLoop->Get(fdcHits); eventLoop->Get(cathClus); // Ensure clusters are in order of ascending Z position. std::sort(cathClus.begin(), cathClus.end(), DFDCCathodeCluster_gLayer_cmp); // Sift through hits and select out anode hits. for (unsigned int i=0; i < fdcHits.size(); i++) if (fdcHits[i]->type == 0) xHits.push_back(fdcHits[i]); // Make sure the wires are also in order of ascending z position std::sort(xHits.begin(), xHits.end(), DFDCAnode_gLayer_cmp); // Sift through clusters and put U and V clusters into respective vectors. for (unsigned int i=0; i < cathClus.size(); i++) { if (cathClus[i]->plane == 1) vClus.push_back(cathClus[i]); else uClus.push_back(cathClus[i]); } vector::iterator uIt = uClus.begin(); vector::iterator vIt = vClus.begin(); vector::iterator xIt = xHits.begin(); // For each layer, get its sets of V, X, and U hits, and then pass them to the geometrical // organization routine, DFDCPseudo_factory::makePseudo() for (int iLayer=1; iLayer <= 24; iLayer++) { for (; ((uIt != uClus.end() && (*uIt)->gLayer == iLayer)); uIt++) oneLayerU.push_back(*uIt); for (; ((vIt != vClus.end() && (*vIt)->gLayer == iLayer)); vIt++) oneLayerV.push_back(*vIt); for (; ((xIt != xHits.end() && (*xIt)->gLayer == iLayer)); xIt++) oneLayerX.push_back(*xIt); makePseudo(oneLayerX, oneLayerU, oneLayerV,iLayer); oneLayerU.clear(); oneLayerV.clear(); oneLayerX.clear(); } return NOERROR; } /// /// DFDCPseudo_factory::makePseudo(): /// performs UV+X matching to create pseudopoints /// void DFDCPseudo_factory::makePseudo(vector& x, vector& u, vector& v, int layer) { if ((u.size() == 0) || (v.size() == 0) || (x.size() == 0)) return; vector::iterator xIt; vector::iterator uIt; vector::iterator vIt; centroid_t temp; float E1,E2,pos1,pos2; // Loop over all U and V clusters looking for peaks upeaks.clear(); for (uIt = u.begin(); uIt != u.end(); uIt++){ vector::const_iterator strip=(*uIt)->members.begin(); switch((*uIt)->members.size()){ case 0: // Make sure we have data!! break; case 1: // One isolated hit in the cluster: use element number itself temp.pos=(*strip)->element; temp.q=2.*((*strip)->q); // Each cathode view should see half the // anode charge upeaks.push_back(temp); break; case 2: //Two adjacent hits: use average for the centroid pos1=(*strip)->element; pos2=(*(strip+1))->element; E1=(*strip)->q; E2=(*(strip+1))->q; temp.pos=(pos1*E1+pos2*E2)/(E1+E2); temp.q=2.*(E1+E2); upeaks.push_back(temp); break; default: for (strip=(*uIt)->members.begin(); strip!=(*uIt)->members.end();strip++){ FindCentroid((*uIt)->members,strip,upeaks); } break; } } vpeaks.clear(); for (vIt = v.begin(); vIt != v.end(); vIt++){ vector::const_iterator strip=(*vIt)->members.begin(); switch((*vIt)->members.size()){ case 0: // Make sure we have data!! break; case 1: // One isolated hit in the cluster: use element number itself temp.pos=(*strip)->element; temp.q=2.*((*strip)->q); temp.numstrips=1; vpeaks.push_back(temp); break; case 2: //Two adjacent hits: use average for the centroid pos1=(*strip)->element; pos2=(*(strip+1))->element; E1=(*strip)->q; E2=(*(strip+1))->q; temp.pos=(pos1*E1+pos2*E2)/(E1+E2); temp.q=2.*(E1+E2); temp.numstrips=2; vpeaks.push_back(temp); break; default: for (strip=(*vIt)->members.begin(); strip!=(*vIt)->members.end();strip++){ FindCentroid((*vIt)->members,strip,vpeaks); } break; } } if (upeaks.size()*vpeaks.size()>0){ //Loop over all u and v centroids looking for matches with wires for (unsigned int i=0;iw = x_from_wire; newPseu->dw = xres; newPseu->s = y_from_strips; newPseu->ds = yres; newPseu->wire = DFDCGeometry::GetDFDCWire(layer, (*xIt)->element); newPseu->time = (*xIt)->t; newPseu->dist = newPseu->time*DRIFT_SPEED; newPseu->status = status; sinangle=newPseu->wire->udir(0); cosangle=newPseu->wire->udir(1); newPseu->x=(newPseu->w)*cosangle+(newPseu->s)*sinangle; newPseu->y=-(newPseu->w)*sinangle+(newPseu->s)*cosangle; DMatrix V(2,2); double sigx2=HALF_CELL*HALF_CELL/3.; double sigy2=MAX_DEFLECTION*MAX_DEFLECTION/3.; V(0,0)=sigx2*cosangle*cosangle+sigy2*sinangle*sinangle; V(1,1)=sigx2*sinangle*sinangle+sigy2*cosangle*cosangle; V(0,1)=V(1,0)=(sigy2-sigx2)*sinangle*cosangle; newPseu->cov.ResizeTo(V); newPseu->cov=V; _data.push_back(newPseu); } // match in x } // xIt loop } // vpeaks loop } // upeaks loop } // if we have peaks in both u and v views } // /// DFDCPseudo_factory::FindCentroid() /// Uses the Newton-Raphson method for solving the set of non-linear /// equations describing the charge distribution over 3 strips for the peak /// position x0, the anode charge qa, and the "width" parameter k2. /// See Numerical Recipes in C p.379-383. /// Updates list of centroids. /// jerror_t DFDCPseudo_factory::FindCentroid(const vector& H, vector::const_iterator peak, vector¢roids){ centroid_t temp; // Make sure we do not exceed the range of the vector if (peak>H.begin() && peak+1!=H.end()){ float err_diff1=0.,err_diff2=0.; // Some code for checking for significance of fluctuations. // Currently disabled. //float dq1=(*(peak-1))->dq; //float dq2=(*peak)->dq; //float dq3=(*(peak+1))->dq; //err_diff1=sqrt(dq1*dq1+dq2*dq2); //err_diff2=sqrt(dq2*dq2+dq3*dq3); // Check for a peak in three adjacent strips if ((*peak)->q-(*(peak-1))->q > err_diff1 && (*peak)->q-(*(peak+1))->q > err_diff2){ // Define some matrices for use in the Newton-Raphson iteration DMatrix J(3,3); //Jacobean matrix DMatrix F(3,1),N(3,1),X(3,1),par(3,1); DMatrix newpar(3,1); int i=0; double sum=0.; // Initialize the matrices to some suitable starting values par(X0,0)=double((*peak)->element); par(K2,0)=1.; for (vector::const_iterator j=peak-1;j<=peak+1;j++){ X(i,0)=double((*j)->element); N(i++,0)=double((*j)->q); sum+=double((*j)->q); } par(QA,0)=2.*sum; newpar=par; // Newton-Raphson procedure double errf=0.,errx=0; for (int iter=1;iter<=ITER_MAX;iter++){ errf=0.; errx=0.; // Compute Jacobian matrix: J_ij = dF_i/dx_j. for (i=0;i<3;i++){ double argp=par(K2,0)*(par(X0,0)-X(i,0)+A_OVER_H); double argm=par(K2,0)*(par(X0,0)-X(i,0)-A_OVER_H); J(i,QA)=-(tanh(argp)-tanh(argm))/4.; J(i,K2)=-par(QA,0)/4.*(argp/par(K2,0)*(1.-tanh(argp)*tanh(argp)) -argm/par(K2,0)*(1.-tanh(argm)*tanh(argm))); J(i,X0)=-par(QA,0)*par(K2,0)/4. *(tanh(argm)*tanh(argm)-tanh(argp)*tanh(argp)); F(i,0)=N(i,0)-par(QA,0)/4.*(tanh(argp)-tanh(argm)); if (fabs(F(i,0))>errf) errf=fabs(F(i,0)); } // Check for convergence if (errfwire; DVector3 pos = hit->wire->origin + hit->wire->udir*hit->s; double phi = pos.Phi(); if(phi<0.0)phi+=2.0*M_PI; printnewrow(); printcol("%d", hit->wire->layer); printcol("%d", hit->wire->wire); printcol("%3.1f", pos.Perp()); printcol("%1.3f", phi); printcol("%3.1f", pos.Z()); printcol("%3.1f", hit->time); printcol("%3.1f", hit->w); printcol("%1.4f", hit->s); printcol("%d", hit->status); printrow(); } return _table; }