hitFDC.c

Go to the documentation of this file.
00001 /*
00002  * hitFDC - registers hits for forward drift chambers
00003  *
00004  *        This is a part of the hits package for the
00005  *        HDGeant simulation program for Hall D.
00006  *
00007  *        version 1.0         -Richard Jones July 16, 2001
00008  *
00009  * changes: Wed Jun 20 13:19:56 EDT 2007 B. Zihlmann 
00010  *          add ipart to the function hitForwardDC
00011  */
00012 
00013 #include <stdlib.h>
00014 #include <stdio.h>
00015 #include <math.h>
00016 
00017 #include <hddm_s.h>
00018 #include <geant3.h>
00019 #include <bintree.h>
00020 
00021 #include "calibDB.h"
00022 extern s_HDDM_t* thisInputEvent;
00023 extern double asic_response(double t);
00024 extern double Ei(double x);
00025 
00026 typedef struct{
00027   int writeenohits;
00028   int showersincol;
00029   int driftclusters;
00030 }controlparams_t;
00031 
00032 extern controlparams_t controlparams_;
00033 
00034 
00035 const float wire_dead_zone_radius[4]={3.0,3.0,3.9,3.9};
00036 const float strip_dead_zone_radius[4]={1.3,1.3,1.3,1.3};
00037 
00038 #define CATHODE_ROT_ANGLE 1.309 // 75 degrees
00039 
00040 // Drift speed 2.2cm/us is appropriate for a 90/10 Argon/Methane mixture
00041 static float DRIFT_SPEED           =.0055;
00042 static float ACTIVE_AREA_OUTER_RADIUS =48.5;
00043 static float ANODE_CATHODE_SPACING =0.5;
00044 static float TWO_HIT_RESOL         =25.;
00045 static int   WIRES_PER_PLANE       =96;
00046 static float WIRE_SPACING          =1.0;
00047 static float U_OF_WIRE_ZERO        =0;//(-((WIRES_PER_PLANE-1.)*WIRE_SPACING)/2)
00048 static float STRIPS_PER_PLANE      =192;
00049 static float STRIP_SPACING         =0.5;
00050 static float U_OF_STRIP_ZERO     =0;//  (-((STRIPS_PER_PLANE-1.)*STRIP_SPACING)/2)
00051 static float STRIP_GAP             =0.1;
00052 static int   MAX_HITS             =100;
00053 static float K2                  =1.15;
00054 static float STRIP_NODES          = 3;
00055 static float THRESH_KEV           =1. ;
00056 static float THRESH_ANODE         = 1.;
00057 static float THRESH_STRIPS        =5. ;  /* pC */
00058 static float ELECTRON_CHARGE =1.6022e-4; /* fC */
00059 static float DIFFUSION_COEFF  =   1.1e-6; // cm^2/s --> 200 microns at 1 cm
00060 static float FDC_TIME_WINDOW = 1000.0; //time window for accepting FDC hits, ns
00061 static float GAS_GAIN = 8e4;
00062 
00063 
00064 #if 0
00065 static float wire_dx_offset[2304];
00066 static float wire_dz_offset[2304];
00067 #endif
00068 
00069 binTree_t* forwardDCTree = 0;
00070 static int stripCount = 0;
00071 static int wireCount = 0;
00072 static int pointCount = 0;
00073 static int initializedx=0;
00074 
00075 void gpoiss_(float*,int*,const int*); // avoid solaris compiler warnings
00076 void rnorml_(float*,int*);
00077 
00078 typedef int (*compfn)(const void*, const void*);
00079 
00080 // Sort functions for sorting clusters
00081 int fdc_anode_cluster_sort(const void *a,const void *b){
00082   const s_FdcAnodeTruthHit_t *ca=a;
00083   const s_FdcAnodeTruthHit_t *cb=b;
00084   if (ca->t<cb->t) return -1;
00085   else if (ca->t>cb->t) return 1;
00086   else return 0;
00087 }
00088 int fdc_cathode_cluster_sort(const void *a,const void *b){
00089   const s_FdcCathodeTruthHit_t *ca=a;
00090   const s_FdcCathodeTruthHit_t *cb=b;
00091   if (ca->t<cb->t) return -1;
00092   else if (ca->t>cb->t) return 1;
00093   else return 0;
00094 }
00095 
00096 
00097 
00098 // Locate a position in array xx given x
00099 void locate(float *xx,int n,float x,int *j){
00100   int ju,jm,jl;
00101   int ascnd;
00102   
00103   jl=-1;
00104   ju=n;
00105   ascnd=(xx[n-1]>=xx[0]);
00106   while(ju-jl>1){
00107     jm=(ju+jl)>>1;
00108     if (x>=xx[jm]==ascnd)
00109       jl=jm;
00110     else
00111       ju=jm;
00112   }
00113   if (x==xx[0]) *j=0;
00114   else if (x==xx[n-1]) *j=n-2;
00115   else *j=jl; 
00116 }
00117 
00118 // Polynomial interpolation on a grid.
00119 // Adapted from Numerical Recipes in C (2nd Edition), pp. 121-122.
00120 void polint(float *xa, float *ya,int n,float x, float *y,float *dy){
00121   int i,m,ns=0;
00122   float den,dif,dift,ho,hp,w;
00123 
00124   float *c=(float *)calloc(n,sizeof(float));
00125   float *d=(float *)calloc(n,sizeof(float));
00126 
00127   dif=fabs(x-xa[0]);
00128   for (i=0;i<n;i++){
00129     if ((dift=fabs(x-xa[i]))<dif){
00130       ns=i;
00131       dif=dift;
00132     }
00133     c[i]=ya[i];
00134     d[i]=ya[i];
00135   }
00136   *y=ya[ns--];
00137 
00138   for (m=1;m<n;m++){
00139     for (i=1;i<=n-m;i++){
00140       ho=xa[i-1]-x;
00141       hp=xa[i+m-1]-x;
00142       w=c[i+1-1]-d[i-1];
00143       if ((den=ho-hp)==0.0) {
00144         free(c);
00145         free(d);
00146         return;
00147       }
00148       
00149       den=w/den;
00150       d[i-1]=hp*den;
00151       c[i-1]=ho*den;
00152       
00153     }
00154     
00155     *y+=(*dy=(2*ns<(n-m) ?c[ns+1]:d[ns--]));
00156   }
00157   free(c);
00158   free(d);
00159 }
00160 
00161 // Simulation of signal on a wire
00162 double wire_signal(double t,s_FdcAnodeTruthHits_t* ahits){
00163   double t0=1.0; // ns; rough order of magnitude
00164   int m;
00165   double asic_gain=0.76; // mV/fC
00166   double func=0;
00167   for (m=0;m<ahits->mult;m++){
00168     if (t>ahits->in[m].t){
00169       double my_time=t-ahits->in[m].t;
00170       func+=asic_gain*ahits->in[m].dE*asic_response(my_time);
00171     }
00172   }
00173   return func;
00174 }
00175 
00176 // Simulation of signal on a cathode strip (ASIC output)
00177 double cathode_signal(double t,s_FdcCathodeTruthHits_t* chits){
00178   double t0=1.0; // ns; rough order of magnitude
00179   int m;
00180   double asic_gain=2.3;
00181   double func=0;
00182   for (m=0;m<chits->mult;m++){
00183     if (t>chits->in[m].t){
00184       double my_time=t-chits->in[m].t;
00185       func+=asic_gain*chits->in[m].q*asic_response(my_time);
00186     }
00187   }
00188   return func;
00189 }
00190 
00191 // Generate hits in two cathode planes flanking the wire plane  
00192 void AddFDCCathodeHits(int PackNo,float xwire,float avalanche_y,float tdrift,
00193              int n_p,int track,int ipart,int chamber,int module,
00194              int layer, int global_wire_number){
00195 
00196   s_FdcCathodeTruthHits_t* chits;        
00197 
00198   // Anode charge
00199   float q_anode;
00200   int n_t;
00201   // Average number of secondary ion pairs for 40/60 Ar/CO2 mixture
00202   float n_s_per_p=1.89; 
00203   if (controlparams_.driftclusters==0){    
00204     /* Total number of ion pairs.  On average for each primary ion 
00205        pair produced there are n_s secondary ion pairs produced.  The
00206        probability distribution is a compound poisson distribution
00207        that requires generating two Poisson variables.
00208     */
00209     int n_s,one=1;  
00210     float n_s_mean = ((float)n_p)*n_s_per_p;
00211     gpoiss_(&n_s_mean,&n_s,&one);
00212     n_t = n_s+n_p;
00213     q_anode=((float)n_t)*GAS_GAIN*ELECTRON_CHARGE;
00214   }
00215   else{
00216     // Distribute the number of secondary ionizations for this primary
00217     // ionization according to a Poisson distribution with mean n_s_over_p.
00218     // For simplicity we assume these secondary electrons and the primary
00219     // electron stay together as a cluster.
00220     int n_s;
00221     int one=1;
00222     gpoiss_(&n_s_per_p,&n_s,&one);
00223     // Anode charge in units of fC
00224     n_t=1+n_s;
00225     q_anode=GAS_GAIN*ELECTRON_CHARGE*((float)n_t);
00226   }
00227 
00228   /* Mock-up of cathode strip charge distribution */ 
00229   int plane, node;
00230   for (plane=1; plane<4; plane+=2){
00231     float theta = (plane == 1)? -CATHODE_ROT_ANGLE : +CATHODE_ROT_ANGLE;
00232     float cathode_u = xwire*cos(theta)+avalanche_y*sin(theta);
00233     int strip1 = ceil((cathode_u-U_OF_STRIP_ZERO)/STRIP_SPACING +0.5);
00234     float cathode_u1 = (strip1-1)*STRIP_SPACING + U_OF_STRIP_ZERO;
00235     float delta = cathode_u-cathode_u1;
00236     float half_gap=ANODE_CATHODE_SPACING;
00237 
00238 #if 0
00239     half_gap+=(plane==1)?+wire_dz_offset[global_wire_number]:
00240           -wire_dz_offset[global_wire_number];
00241 #endif
00242 
00243     for (node=-STRIP_NODES; node<=STRIP_NODES; node++){
00244       /* Induce charge on the strips according to the Mathieson 
00245     function tuned to results from FDC prototype
00246       */
00247       float lambda1=(((float)node-0.5)*STRIP_SPACING+STRIP_GAP/2.
00248            -delta)/half_gap;
00249       float lambda2=(((float)node+0.5)*STRIP_SPACING-STRIP_GAP/2.
00250            -delta)/half_gap;
00251       float factor=0.25*M_PI*K2;
00252       float q = 0.25*q_anode*(tanh(factor*lambda2)-tanh(factor*lambda1));
00253       
00254       int strip = strip1+node;
00255       /* Throw away hits on strips falling within a certain dead-zone
00256     radius */
00257       float strip_outer_u=cathode_u1
00258    +(STRIP_SPACING+STRIP_GAP/2.)*(int)node;
00259       float cathode_v=-xwire*sin(theta)+avalanche_y*cos(theta);
00260       float check_radius=sqrt(strip_outer_u*strip_outer_u
00261                +cathode_v*cathode_v);
00262       
00263       if ((strip > 0) 
00264      && (check_radius>strip_dead_zone_radius[PackNo]) 
00265      && (strip <= STRIPS_PER_PLANE)){
00266    int mark = (chamber<<20) + (plane<<10) + strip;
00267    void** cathodeTwig = getTwig(&forwardDCTree, mark);
00268    if (*cathodeTwig == 0){
00269      s_ForwardDC_t* fdc = *cathodeTwig = make_s_ForwardDC();
00270      s_FdcChambers_t* chambers = make_s_FdcChambers(1);
00271      s_FdcCathodeStrips_t* strips = make_s_FdcCathodeStrips(1);
00272      strips->mult = 1;
00273      strips->in[0].plane = plane;
00274      strips->in[0].strip = strip;
00275      strips->in[0].fdcCathodeTruthHits = chits
00276        = make_s_FdcCathodeTruthHits(MAX_HITS);
00277      chambers->mult = 1;
00278      chambers->in[0].module = module;
00279      chambers->in[0].layer = layer;
00280      chambers->in[0].fdcCathodeStrips = strips;
00281      fdc->fdcChambers = chambers;
00282      stripCount++;
00283    }
00284    else{
00285      s_ForwardDC_t* fdc = *cathodeTwig;
00286      chits = fdc->fdcChambers->in[0].fdcCathodeStrips
00287        ->in[0].fdcCathodeTruthHits;
00288    }
00289    
00290    int nhit;
00291    for (nhit = 0; nhit < chits->mult; nhit++){
00292      // To cut down on the number of output clusters, combine 
00293      // those that would be indistiguishable in time given the 
00294      // expected timing resolution
00295      if (fabs(chits->in[nhit].t - tdrift) <TWO_HIT_RESOL)
00296        {
00297          break;
00298        }
00299    }
00300    if (nhit < chits->mult)    /* merge with former hit */
00301      {
00302        /* Use the time from the earlier hit but add the charge */
00303        chits->in[nhit].q += q;
00304        if(chits->in[nhit].t>tdrift){
00305          chits->in[nhit].t = tdrift;
00306          chits->in[nhit].itrack = track;
00307          chits->in[nhit].ptype = ipart;
00308        }
00309      }
00310    else if (nhit < MAX_HITS){        /* create new hit */
00311      chits->in[nhit].t = tdrift;
00312      chits->in[nhit].q = q;
00313      chits->in[nhit].itrack = track;
00314      chits->in[nhit].ptype = ipart;
00315      chits->mult++;
00316    }
00317    else{
00318      // supress warning
00319      /*
00320        fprintf(stderr,"HDGeant error in hitForwardDC: ");
00321        fprintf(stderr,"max hit count %d exceeded, truncating!\n",
00322        MAX_HITS);
00323      */
00324    }
00325    
00326       }
00327     } // loop over cathode strips
00328   } // loop over cathode views
00329 }
00330 
00331 
00332 
00333 
00334 
00335 
00336 
00337 
00338 
00339 // Add wire information
00340 int AddFDCAnodeHit(s_FdcAnodeTruthHits_t* ahits,int layer,int ipart,int track,
00341          float xwire,float xyz[3],float dE,float t,float *tdrift){
00342  
00343   // Generate 2 random numbers from a Gaussian distribution
00344   // 
00345   float rndno[2];
00346   int two=2;
00347 
00348   // Only and always use the built-in Geant random generator,
00349   // otherwise debugging is a problem because sequences are not
00350      // reproducible from a given pair of random seeds. [rtj]
00351   
00352   /* rnorml_(rndno,&two); */ {
00353     float rho,phi1;
00354     grndm_(rndno,&two);
00355     rho = sqrt(-2*log(rndno[0]));
00356     phi1 = rndno[1]*2*M_PI;
00357     rndno[0] = rho*cos(phi1);
00358     rndno[1] = rho*sin(phi1);
00359   }
00360 
00361    // Get the magnetic field at this cluster position     
00362   float x[3],B[3];
00363   transformCoord(xyz,"local",x,"global");
00364   gufld_db_(x,B);
00365   
00366   // Find the angle between the wire direction and the direction of the
00367   // magnetic field in the x-y plane
00368   float wire_dir[2];
00369   float wire_theta=1.0472*(float)((layer%3)-1);
00370   float phi=0.;;
00371   float Br=sqrt(B[0]*B[0]+B[1]*B[1]);
00372   
00373   wire_dir[0]=sin(wire_theta);
00374   wire_dir[1]=cos(wire_theta);
00375   if (Br>0.) phi= acos((B[0]*wire_dir[0]+B[1]*wire_dir[1])/Br);
00376   
00377   // useful combinations of dx and dz
00378   float dx=xyz[0]-xwire;
00379   float dx2=dx*dx;
00380   float dx4=dx2*dx2;
00381   float dz2=xyz[2]*xyz[2];
00382   float dz4=dz2*dz2;
00383   
00384   // Next compute the avalanche position along wire.  
00385   // Correct avalanche position with deflection along wire due to 
00386   // Lorentz force.
00387   xyz[1]+=( 0.1458*B[2]*(1.-0.048*Br) )*dx
00388     +( 0.1717+0.01227*B[2] )*(Br*cos(phi))*xyz[2]
00389     +( -0.000176 )*dx*dx2/(dz2+0.001);
00390   // Add transverse diffusion
00391   xyz[1]+=(( 0.01 )*pow(dx2+dz2,0.125)+( 0.0061 )*dx2)*rndno[1];
00392 
00393   // Do not use this cluster if the Lorentz force would deflect 
00394   // the electrons outside the active region of the detector
00395   if (sqrt(xyz[1]*xyz[1]+xwire*xwire)>ACTIVE_AREA_OUTER_RADIUS) 
00396     return 0;
00397 
00398   // Model the drift time and longitudinal diffusion as a function of 
00399   // position of the cluster within the cell         
00400   float tdrift_unsmeared=( 1086.0-106.7*B[2] )*dx2+( 1068.0 )*dz2
00401     +dx4*(( -2.675 )/(dz2+0.001)+( 2.4e4 )*dz2);   
00402   float dt=(( 39.44   )*dx4/(0.5-dz2)+( 56.0  )*dz4/(0.5-dx2)
00403       +( 0.01566 )*dx4/(dz4+0.002)/(0.251-dx2))*rndno[1];
00404   // Only allow deviations to longer times if near the cell border
00405   double dradius=sqrt(dx2+dz2);
00406   if (dradius-0.5>=0. && dt<0){ 
00407     dt=0.;
00408   }
00409 
00410   // Minimum drift time for docas near wire (very crude approximation)
00411   double v_max=0.08; // guess for now based on Garfield, near wire 
00412   double tmin=dradius/v_max;
00413   double tdrift_smeared=tdrift_unsmeared+dt;
00414   if (tdrift_smeared<tmin){
00415     tdrift_smeared=tmin;
00416   }
00417 
00418   // Avalanche time
00419   *tdrift=t+tdrift_smeared;
00420      
00421   // Skip cluster if the time would go beyond readout window
00422   if (t>FDC_TIME_WINDOW) return 0;
00423 
00424   int nhit;
00425 
00426   // Record the anode hit
00427   for (nhit = 0; nhit < ahits->mult; nhit++)
00428     {
00429       if (fabs(ahits->in[nhit].t - *tdrift) < TWO_HIT_RESOL)
00430    {
00431      break;
00432    }
00433     }
00434   if (nhit < ahits->mult)                 /* merge with former hit */
00435     {
00436       /* use the time from the earlier hit but add the energy */
00437       ahits->in[nhit].dE += dE;
00438       if(ahits->in[nhit].t>*tdrift){
00439    ahits->in[nhit].t = *tdrift;
00440    ahits->in[nhit].t_unsmeared=tdrift_unsmeared;
00441    ahits->in[nhit].d = sqrt(dx2+dz2);
00442    
00443    ahits->in[nhit].itrack = track;
00444    ahits->in[nhit].ptype = ipart;
00445       }
00446     
00447       /*ahits->in[nhit].t = 
00448    (ahits->in[nhit].t * ahits->in[nhit].dE + tdrift * dE)
00449    / (ahits->in[nhit].dE += dE);
00450       */
00451     }
00452   else if (nhit < MAX_HITS)              /* create new hit */
00453     {
00454       ahits->in[nhit].t = *tdrift;
00455       ahits->in[nhit].t_unsmeared=tdrift_unsmeared;
00456       ahits->in[nhit].dE = dE;
00457       ahits->in[nhit].d = sqrt(dx2+dz2);
00458       ahits->in[nhit].itrack = track;
00459       ahits->in[nhit].ptype = ipart;
00460       ahits->mult++;
00461     }
00462   else
00463     {
00464       fprintf(stderr,"HDGeant error in hitForwardDC: ");
00465       fprintf(stderr,"max hit count %d exceeded, truncating!\n",MAX_HITS);
00466     }
00467 
00468   return 1;
00469 }
00470 
00471 /* register hits during tracking (from gustep) */
00472 
00473 void hitForwardDC (float xin[4], float xout[4],
00474                    float pin[5], float pout[5], float dEsum,
00475                    int track, int stack, int history, int ipart)
00476 {
00477   float x[3], t;
00478   float dx[3], dr;
00479   float dEdx;
00480   float xlocal[3];
00481   float xinlocal[3];
00482   float xoutlocal[3];
00483   float dradius;
00484   float alpha,sinalpha,cosalpha;
00485   int i,j;
00486 
00487   if (!initializedx){
00488       mystr_t strings[250];
00489       float values[250];
00490       int nvalues = 250;
00491 
00492       // Get parameters related to the geometry and the signals 
00493       int status = GetConstants("FDC/fdc_parms", &nvalues,values,strings);
00494       if (!status) {
00495         int ncounter = 0;
00496         int i;
00497         for ( i=0;i<(int)nvalues;i++){
00498           //printf("%d %s %f\n",i,strings[i].str,values[i]);
00499           if (!strcmp(strings[i].str,"FDC_DRIFT_SPEED")) {
00500             DRIFT_SPEED  = values[i];
00501             ncounter++;
00502           }
00503           if (!strcmp(strings[i].str,"FDC_ACTIVE_AREA_OUTER_RADIUS")) {
00504             ACTIVE_AREA_OUTER_RADIUS  = values[i];
00505             ncounter++;
00506           }
00507           if (!strcmp(strings[i].str,"FDC_ANODE_CATHODE_SPACING")) {
00508             ANODE_CATHODE_SPACING  = values[i];
00509             ncounter++;
00510           }
00511           if (!strcmp(strings[i].str,"FDC_TWO_HIT_RESOL")) {
00512             TWO_HIT_RESOL  = values[i];
00513             ncounter++;
00514           }
00515           if (!strcmp(strings[i].str,"FDC_WIRES_PER_PLANE")) {
00516             WIRES_PER_PLANE  = values[i];
00517             ncounter++;
00518           }
00519           if (!strcmp(strings[i].str,"FDC_WIRE_SPACING")) {
00520             WIRE_SPACING  = values[i];
00521             ncounter++;
00522           }
00523           if (!strcmp(strings[i].str,"FDC_STRIPS_PER_PLANE")) {
00524             STRIPS_PER_PLANE  = values[i];
00525             ncounter++;
00526           }
00527           if (!strcmp(strings[i].str,"FDC_STRIP_SPACING")) {
00528             STRIP_SPACING  = values[i];
00529             ncounter++;
00530           }
00531           if (!strcmp(strings[i].str,"FDC_STRIP_GAP")) {
00532             STRIP_GAP  = values[i];
00533             ncounter++;
00534           }
00535           if (!strcmp(strings[i].str,"FDC_MAX_HITS")) {
00536             MAX_HITS  = values[i];
00537             ncounter++;
00538           }
00539           if (!strcmp(strings[i].str,"FDC_K2")) {
00540             K2  = values[i];
00541             ncounter++;
00542           }
00543           if (!strcmp(strings[i].str,"FDC_STRIP_NODES")) {
00544             STRIP_NODES  = values[i];
00545             ncounter++;
00546           }
00547           if (!strcmp(strings[i].str,"FDC_THRESH_KEV")) {
00548             THRESH_KEV  = values[i];
00549             ncounter++;
00550           }
00551           if (!strcmp(strings[i].str,"FDC_THRESH_STRIPS")) {
00552             THRESH_STRIPS  = values[i];
00553             ncounter++;
00554           }
00555           if (!strcmp(strings[i].str,"FDC_ELECTRON_CHARGE")) {
00556             ELECTRON_CHARGE  = values[i];
00557             ncounter++;
00558           }
00559           if (!strcmp(strings[i].str,"FDC_DIFFUSION_COEFF")) {
00560             DIFFUSION_COEFF  = values[i];
00561             ncounter++;
00562           }
00563    }
00564    U_OF_WIRE_ZERO     = (-((WIRES_PER_PLANE-1.)*WIRE_SPACING)/2);
00565    U_OF_STRIP_ZERO      = (-((STRIPS_PER_PLANE-1.)*STRIP_SPACING)/2);
00566   
00567    if (ncounter==16){
00568           printf("FDC: ALL parameters loaded from Data Base\n");
00569         } else if (ncounter<16){
00570           printf("FDC: NOT ALL necessary parameters found in Data Base %d out of 16\n",ncounter);
00571         } else {
00572           printf("FDC: SOME parameters found more than once in Data Base\n");
00573         }       
00574 #if 0
00575    {
00576      int num_values=2304*2;
00577      float my_values[2304*2]; 
00578      mystr_t my_strings[2304*2];
00579      status=GetArrayConstants("FDC/fdc_wire_offsets",&num_values,
00580                my_values,my_strings);
00581      if (!status){
00582        int i;
00583        for (i=0;i<num_values;i+=2){
00584          int j=i/2;
00585          wire_dx_offset[j]=my_values[i];
00586          wire_dz_offset[j]=my_values[i+1];
00587        }
00588      }
00589    }
00590 #endif
00591       }
00592       initializedx = 1 ;
00593   }
00594 
00595   /* Get chamber information */ 
00596   int layer = getlayer_wrapper_(); 
00597   if (layer==0){
00598     printf("hitFDC: FDC layer number evaluates to zero! THIS SHOULD NEVER HAPPEN! drop this particle.\n");
00599     return;
00600   }
00601   //int module = getmodule_wrapper_();
00602   //int chamber = (module*10)+layer;
00603   //int PackNo = (chamber-11)/20;
00604   int PackNo = getpackage_wrapper_()-1;
00605   if (PackNo==-1){
00606      printf("hitFDC: FDC package number evaluates to zero! THIS SHOULD NEVER HAPPEN! drop this particle.\n");
00607     return;
00608   }
00609   int glayer=6*PackNo+layer-1;
00610   int module = 2*(PackNo)+(layer-1)/3+1;
00611   int chamber = (module*10)+(layer-1)%3+1;
00612   int wire1,wire2;
00613   int wire,dwire;
00614 
00615   // transform layer number into Richard's scheme
00616   layer=(layer-1)%3+1;
00617 
00618   transformCoord(xin,"global",xinlocal,"local");
00619 
00620   wire1 = ceil((xinlocal[0] - U_OF_WIRE_ZERO)/WIRE_SPACING +0.5);
00621   transformCoord(xout,"global",xoutlocal,"local");
00622   wire2 = ceil((xoutlocal[0] - U_OF_WIRE_ZERO)/WIRE_SPACING +0.5);
00623   // Check that wire numbers are not out of range
00624   if ((wire1>WIRES_PER_PLANE && wire2==WIRES_PER_PLANE) ||
00625       (wire2>WIRES_PER_PLANE && wire1==WIRES_PER_PLANE)) 
00626     wire1=wire2=WIRES_PER_PLANE;  
00627   if ((wire1==0 && wire2 == 1) || (wire1==1 && wire2== 0)){
00628     wire1=wire2=1;
00629   }
00630   // Make sure at least one wire number is valid
00631   if (wire1>WIRES_PER_PLANE&&wire2>WIRES_PER_PLANE) return;
00632   if (wire1==0 && wire2==0) return;
00633 
00634   if (wire1>WIRES_PER_PLANE) wire1=wire2;
00635   else if (wire2>WIRES_PER_PLANE) wire2=wire1;
00636   if (wire1==0) wire1=wire2;
00637   else if (wire2==0) wire2=wire1;
00638 
00639   dwire = (wire1 < wire2)? 1 : -1;
00640   alpha = atan2(xoutlocal[0]-xinlocal[0],xoutlocal[2]-xinlocal[2]);
00641   sinalpha=sin(alpha);
00642   cosalpha=cos(alpha);
00643   xlocal[0] = (xinlocal[0] + xoutlocal[0])/2;
00644   xlocal[1] = (xinlocal[1] + xoutlocal[1])/2;
00645   xlocal[2] = (xinlocal[2] + xoutlocal[2])/2;
00646 
00647   wire = ceil((xlocal[0] - U_OF_WIRE_ZERO)/WIRE_SPACING +0.5);
00648   x[0] = (xin[0] + xout[0])/2;
00649   x[1] = (xin[1] + xout[1])/2;
00650   x[2] = (xin[2] + xout[2])/2;
00651   t = (xin[3] + xout[3])/2 * 1e9;
00652   dx[0] = xin[0] - xout[0];
00653   dx[1] = xin[1] - xout[1];
00654   dx[2] = xin[2] - xout[2];
00655   dr = sqrt(dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]);
00656   if (dr > 1e-3)
00657   {
00658     dEdx = dEsum/dr;
00659   }
00660   else
00661   {
00662     dEdx = 0;
00663   }
00664 
00665   /* Make a fuzzy boundary around the forward dead region 
00666    * by killing any track segment whose midpoint is within the boundary */
00667 
00668   if (sqrt(xlocal[0]*xlocal[0]+xlocal[1]*xlocal[1])
00669       < wire_dead_zone_radius[PackNo])
00670   {
00671     return;
00672   }
00673 
00674   /* post the hit to the truth tree */
00675  
00676   if (history == 0)
00677   {
00678     int mark = (1<<16) + (chamber<<20) + pointCount;
00679     void** twig = getTwig(&forwardDCTree, mark);
00680     if (*twig == 0)
00681     {
00682       s_ForwardDC_t* fdc = *twig = make_s_ForwardDC();
00683       s_FdcChambers_t* chambers = make_s_FdcChambers(1);
00684       s_FdcTruthPoints_t* points = make_s_FdcTruthPoints(1);
00685       float xwire = U_OF_WIRE_ZERO + (wire-1)*WIRE_SPACING;
00686       float u[2];
00687       u[0] = xinlocal[2];
00688       u[1] = xinlocal[0]-xwire;
00689       dradius = fabs(u[1]*cosalpha-u[0]*sinalpha);
00690       points->mult = 1;
00691         int a = thisInputEvent->physicsEvents->in[0].reactions->in[0].vertices->in[0].products->mult;
00692       points->in[0].primary = (stack <= a);
00693       points->in[0].track = track;
00694       points->in[0].x = x[0];
00695       points->in[0].y = x[1];
00696       points->in[0].z = x[2];
00697       points->in[0].t = t;
00698       points->in[0].px = pin[0]*pin[4];
00699       points->in[0].py = pin[1]*pin[4];
00700       points->in[0].pz = pin[2]*pin[4];
00701       points->in[0].E = pin[3];
00702       points->in[0].dradius = dradius;
00703       points->in[0].dEdx = dEdx;
00704       points->in[0].ptype = ipart;
00705       chambers->mult = 1;
00706       chambers->in[0].module = module;
00707       chambers->in[0].layer = layer;
00708       chambers->in[0].fdcTruthPoints = points;
00709       fdc->fdcChambers = chambers;
00710       pointCount++;
00711     }
00712   }
00713 
00714   /* post the hit to the hits tree, mark cell as hit */
00715 
00716   if (dEsum > 0)
00717   {
00718     float sign=1.; // for dealing with the y-position for tracks crossing two cells
00719 
00720     for (wire=wire1; wire-dwire != wire2; wire+=dwire)
00721     {
00722       int valid_hit=1;
00723       float dE,dt;
00724       float u[2];
00725       float x0[3],x1[3];
00726       float avalanche_y;
00727       float xwire = U_OF_WIRE_ZERO + (wire-1)*WIRE_SPACING;
00728       int global_wire_number=96*glayer+wire-1;
00729 
00730 #if 0
00731       xwire+=wire_dx_offset[global_wire_number];
00732 #endif     
00733 
00734       if (wire1==wire2){
00735    dE=dEsum; 
00736    x0[0] = xinlocal[0];
00737    x0[1] = xinlocal[1];
00738    x0[2] = xinlocal[2]; 
00739    x1[0] = xoutlocal[0];
00740    x1[1] = xoutlocal[1];
00741    x1[2] = xoutlocal[2];
00742       }
00743       else{
00744    x0[0] = xwire-0.5*dwire*WIRE_SPACING;
00745    x0[1] = xinlocal[1] + (x0[0]-xinlocal[0]+1e-20)*
00746      (xoutlocal[1]-xinlocal[1])/(xoutlocal[0]-xinlocal[0]+1e-20);
00747    x0[2] = xinlocal[2] + (x0[0]-xinlocal[0]+1e-20)*
00748      (xoutlocal[2]-xinlocal[2])/(xoutlocal[0]-xinlocal[0]+1e-20);
00749    if (fabs(x0[2]-xoutlocal[2]) > fabs(xinlocal[2]-xoutlocal[2]))
00750      {
00751        x0[0] = xinlocal[0];
00752        x0[1] = xinlocal[1];
00753        x0[2] = xinlocal[2];
00754      }
00755    x1[0] = xwire+0.5*dwire*WIRE_SPACING;
00756    x1[1] = xinlocal[1] + (x1[0]-xinlocal[0]+1e-20)*
00757      (xoutlocal[1]-xinlocal[1])/(xoutlocal[0]-xinlocal[0]+1e-20);
00758    x1[2] = xinlocal[2] + (x1[0]-xinlocal[0]+1e-20)*
00759      (xoutlocal[2]-xinlocal[2])/(xoutlocal[0]-xinlocal[0]+1e-20);
00760    if (fabs(x1[2]-xinlocal[2]) > fabs(xoutlocal[2]-xinlocal[2]))
00761      {
00762        x1[0] = xoutlocal[0];
00763        x1[1] = xoutlocal[1];
00764        x1[2] = xoutlocal[2];
00765      }
00766    dE = dEsum*(x1[2]-x0[2])/(xoutlocal[2]-xinlocal[2]);
00767       }
00768 
00769       if (dE > 0){
00770    s_FdcAnodeTruthHits_t* ahits;    
00771 
00772    // Create (or grab) an entry in the tree for the anode wire
00773    int mark = (chamber<<20) + (2<<10) + wire;
00774    void** twig = getTwig(&forwardDCTree, mark);
00775          
00776    if (*twig == 0)
00777      {
00778        s_ForwardDC_t* fdc = *twig = make_s_ForwardDC();
00779        s_FdcChambers_t* chambers = make_s_FdcChambers(1);
00780        s_FdcAnodeWires_t* wires = make_s_FdcAnodeWires(1);
00781        wires->mult = 1;
00782        wires->in[0].wire = wire;
00783        wires->in[0].fdcAnodeTruthHits = ahits = make_s_FdcAnodeTruthHits(MAX_HITS);
00784        chambers->mult = 1;
00785        chambers->in[0].module = module;
00786        chambers->in[0].layer = layer;
00787        chambers->in[0].fdcAnodeWires = wires;
00788        fdc->fdcChambers = chambers;
00789        wireCount++;          
00790      }
00791    else
00792      {
00793        s_ForwardDC_t* fdc = *twig;
00794        ahits = fdc->fdcChambers->in[0].fdcAnodeWires->in[0].fdcAnodeTruthHits;
00795      }
00796    
00797 
00798    float rndno[2];
00799    int two=2;
00800       
00801    // Find the number of primary ion pairs:
00802    /* The total number of ion pairs depends on the energy deposition 
00803       and the effective average energy to produce a pair, w_eff.
00804       On average for each primary ion pair produced there are n_s_per_p 
00805       secondary ion pairs produced. 
00806    */
00807    int one=1;
00808    // Average number of secondary ion pairs for 40/60 Ar/CO2 mixture
00809    float n_s_per_p=1.89; 
00810    //Average energy needed to produce an ion pair for 50/50 mixture
00811    float w_eff=30.2e-9; // GeV
00812    // Average number of primary ion pairs
00813    float n_p_mean = dE/w_eff/(1.+n_s_per_p);
00814    int n_p; // number of primary ion pairs
00815    gpoiss_(&n_p_mean,&n_p,&one);
00816    
00817    // Drift time
00818    float tdrift=0;
00819 
00820    if (controlparams_.driftclusters==0){
00821      float zrange=x1[2]-x0[2];
00822      float tany=(x1[1]-x0[1])/zrange;
00823      float tanx=(x1[0]-x0[0])/zrange;
00824      float dz=ANODE_CATHODE_SPACING-dradius*sign*sinalpha;
00825 #if 0   
00826      dz+=wire_dz_offset[global_wire_number];
00827 #endif
00828      xlocal[0]=x0[0]+tanx*dz;
00829      if (fabs(xlocal[0]-xwire)>0.5){
00830        xlocal[0]=x1[0];
00831        xlocal[1]=x1[1];
00832        xlocal[2]=x1[2];
00833      }
00834      else{
00835        xlocal[1]=x0[1]+tany*dz;
00836        xlocal[2]=x0[2]+dz;
00837      }
00838      
00839      /* If the cluster position is within the wire-deadened region of the 
00840         detector, skip this cluster 
00841      */
00842      if (sqrt(xlocal[0]*xlocal[0]+xlocal[1]*xlocal[1])
00843          >=wire_dead_zone_radius[PackNo]){    
00844        if (AddFDCAnodeHit(ahits,layer,ipart,track,xwire,xlocal,dE,t,
00845                 &tdrift)){
00846          AddFDCCathodeHits(PackNo,xwire,xlocal[1],tdrift,n_p,track,ipart,
00847             chamber,module,layer,global_wire_number);
00848        }
00849      
00850      }
00851    }
00852    else{
00853      // Loop over the number of primary ion pairs
00854      int n;
00855      for (n=0;n<n_p;n++){
00856        // Generate a cluster at a random position along the path with cell
00857        float rndno[2];
00858        grndm_(rndno,&two);
00859        float dzrand=(x1[2]-x0[2])*rndno[0];
00860        // Position of the cluster
00861        xlocal[0]=x0[0]+(x1[0]-x0[0])*rndno[0];
00862        xlocal[1]=x0[1]+(x1[1]-x0[1])*rndno[0];
00863        xlocal[2]=x0[2]+dzrand;
00864        /* If the cluster position is within the wire-deadened region of the 
00865           detector, skip this cluster 
00866        */
00867        if (sqrt(xlocal[0]*xlocal[0]+xlocal[1]*xlocal[1])
00868       >=wire_dead_zone_radius[PackNo]){      
00869          if (AddFDCAnodeHit(ahits,layer,ipart,track,xwire,xlocal,dE,t,
00870              &tdrift)){
00871       AddFDCCathodeHits(PackNo,xwire,xlocal[1],tdrift,n_p,track,ipart,
00872               chamber,module,layer,global_wire_number);
00873          }
00874        }
00875 
00876      } // loop over primary ion pairs 
00877    }
00878       } // Check for non-zero energy
00879 
00880       sign*=-1; // for dealing with the y-position for tracks crossing two cells
00881     } // loop over wires
00882   } // Check that total energy deposition is not zero
00883 }
00884 
00885 /* entry points from fortran */
00886 
00887 void hitforwarddc_(float* xin, float* xout,
00888                    float* pin, float* pout, float* dEsum,
00889                    int* track, int* stack, int* history, int* ipart)
00890 {
00891    hitForwardDC(xin,xout,pin,pout,*dEsum,*track,*stack,*history,*ipart);
00892 }
00893 
00894 
00895 /* pick and package the hits for shipping */
00896 
00897 s_ForwardDC_t* pickForwardDC ()
00898 {
00899    s_ForwardDC_t* box;
00900    s_ForwardDC_t* item;
00901 
00902    if ((stripCount == 0) && (wireCount == 0) && (pointCount == 0))
00903    {
00904       return HDDM_NULL;
00905    }
00906 
00907    box = make_s_ForwardDC();
00908    box->fdcChambers = make_s_FdcChambers(32);
00909    box->fdcChambers->mult = 0;
00910    while (item = (s_ForwardDC_t*) pickTwig(&forwardDCTree))
00911    {
00912       s_FdcChambers_t* chambers = item->fdcChambers;
00913       int module = chambers->in[0].module;
00914       int layer = chambers->in[0].layer;
00915       int m = box->fdcChambers->mult;
00916 
00917       /* compress out the hits below threshold */
00918       s_FdcAnodeWires_t* wires = chambers->in[0].fdcAnodeWires;
00919       int wire;
00920       s_FdcCathodeStrips_t* strips = chambers->in[0].fdcCathodeStrips;
00921       int strip;
00922       s_FdcTruthPoints_t* points = chambers->in[0].fdcTruthPoints;
00923       int point;
00924       int mok=0;
00925       for (wire=0; wire < wires->mult; wire++)
00926       {
00927          s_FdcAnodeTruthHits_t* ahits = wires->in[wire].fdcAnodeTruthHits;
00928       
00929     // Sort the clusters by time
00930     qsort(ahits->in,ahits->mult,sizeof(s_FdcAnodeTruthHit_t),
00931           (compfn)fdc_anode_cluster_sort);
00932     
00933     int i,iok=0;
00934 
00935     if (controlparams_.driftclusters==0){
00936       for (iok=i=0; i < ahits->mult; i++)
00937         {
00938           if (ahits->in[i].dE >= THRESH_KEV/1e6)
00939        {
00940                if (iok < i)
00941        {
00942          ahits->in[iok] = ahits->in[i];
00943        }
00944                ++iok;
00945                ++mok;
00946        }
00947         }
00948     }
00949     else{  // Simulate clusters within the cell
00950    
00951       // printf("-------------\n");
00952      
00953       
00954       // Temporary histogram in 1 ns bins to store waveform data
00955       int num_samples=(int)FDC_TIME_WINDOW;
00956       float *samples=(float *)malloc(num_samples*sizeof(float));
00957       for (i=0;i<num_samples;i++){
00958         samples[i]=wire_signal((float)i,ahits);
00959         //printf("%f %f\n",(float)i,samples[i]);
00960       }
00961       
00962       int returned_to_baseline=0;
00963       float q=0;
00964       for (i=0;i<num_samples;i++){
00965         if (samples[i]>=THRESH_ANODE){
00966           if (returned_to_baseline==0){
00967        ahits->in[iok].itrack = ahits->in[0].itrack;
00968        ahits->in[iok].ptype = ahits->in[0].ptype;
00969        
00970        // Do an interpolation to find the time at which the threshold
00971        // was crossed.
00972        float t_array[4];
00973        int k;
00974        float my_t,my_terr;
00975        for (k=0;k<4;k++) t_array[k]=i-1+k;
00976        polint(&samples[i-1],t_array,4,THRESH_ANODE,&my_t,&my_terr);
00977        ahits->in[iok].t=my_t;
00978        
00979        returned_to_baseline=1;
00980        iok++;
00981        mok++;
00982           }
00983           q+=samples[i];
00984         }
00985         if (returned_to_baseline 
00986        && (samples[i]<THRESH_ANODE)){
00987           returned_to_baseline=0;   
00988         }
00989       }
00990       free(samples);
00991     } // Simulation of clusters within cell
00992 
00993     if (iok)
00994       {
00995         ahits->mult = iok;
00996       }
00997     else if (ahits != HDDM_NULL)
00998       {
00999         FREE(ahits);
01000       }
01001       } 
01002       if ((wires != HDDM_NULL) && (mok == 0))
01003    {
01004      FREE(wires);
01005      wires = HDDM_NULL;
01006    }
01007       
01008       
01009       mok = 0;
01010       for (strip=0; strip < strips->mult; strip++)
01011    {
01012      s_FdcCathodeTruthHits_t* chits = strips->in[strip].fdcCathodeTruthHits;
01013      
01014      // Sort the clusters by time
01015      qsort(chits->in,chits->mult,sizeof(s_FdcCathodeTruthHit_t),
01016         (compfn)fdc_cathode_cluster_sort);
01017      
01018      int i,iok=0;
01019      
01020      if (controlparams_.driftclusters==0){
01021        for (iok=i=0; i < chits->mult; i++)
01022          {
01023       if (chits->in[i].q > 0.)
01024         {
01025           if (iok < i)
01026             {
01027          chits->in[iok] = chits->in[i];
01028             }
01029           ++iok;
01030           ++mok;
01031         }
01032          }      
01033        
01034      }
01035      else{
01036       
01037        // Temporary histogram in 1 ns bins to store waveform data
01038        int num_samples=(int)(FDC_TIME_WINDOW);
01039        float *samples=(float *)malloc(num_samples*sizeof(float));
01040        for (i=0;i<num_samples;i++){
01041          samples[i]=cathode_signal((float)i,chits);
01042        //printf("t %f V %f\n",(float)i,samples[i]);
01043        }  
01044        
01045        int threshold_toggle=0;
01046        int istart=0;
01047        float q=0;
01048        int FADC_BIN_SIZE=1;
01049        for (i=0;i<num_samples;i+=FADC_BIN_SIZE){
01050          if (samples[i]>=THRESH_STRIPS){
01051       if (threshold_toggle==0){
01052         chits->in[iok].itrack = chits->in[0].itrack;
01053         chits->in[iok].ptype = chits->in[0].ptype;
01054         chits->in[iok].t=(float) i;
01055         //chits->in[iok].q=samples[i];
01056         istart=i-1;
01057         threshold_toggle=1;
01058         //iok++;
01059         //mok++;
01060       }
01061          }
01062          if (threshold_toggle && 
01063         (samples[i]<THRESH_STRIPS)){
01064       int j;
01065       // Find the first peak
01066       for (j=istart+1;j<i-1;j++){
01067         if (samples[j]>samples[j-1] && samples[j]>samples[j+1]){
01068           chits->in[iok].q=samples[j];
01069           break;
01070         }
01071       } 
01072       threshold_toggle=0; 
01073       iok++;
01074       mok++;
01075       //break;
01076          }
01077        }
01078        i=num_samples-1;
01079        if (samples[i]>=THRESH_STRIPS&&threshold_toggle){
01080          int j;
01081          for (j=istart+1;j<i-1;j++){
01082       if (samples[j]>samples[j-1] && samples[j]>samples[j+1]){
01083         chits->in[iok].q=samples[j];
01084         break;
01085       }
01086          }
01087        }
01088        
01089        free(samples);
01090      }// Simulate clusters within cell
01091    
01092      if (iok)
01093        {
01094          chits->mult = iok;
01095          //chits->mult=1;
01096        }
01097      else if (chits != HDDM_NULL)
01098        {
01099          FREE(chits);
01100        }
01101      
01102    }
01103       if ((strips != HDDM_NULL) && (mok == 0))
01104    {
01105      FREE(strips);
01106      strips = HDDM_NULL;
01107    }
01108       
01109       if ((wires != HDDM_NULL) || 
01110           (strips != HDDM_NULL) ||
01111           (points != HDDM_NULL))
01112    {
01113      if ((m == 0) || (module > box->fdcChambers->in[m-1].module)
01114                      || (layer  > box->fdcChambers->in[m-1].layer))
01115        {
01116           box->fdcChambers->in[m] = chambers->in[0];
01117 
01118           box->fdcChambers->in[m].fdcCathodeStrips = 
01119                               make_s_FdcCathodeStrips(stripCount);
01120           box->fdcChambers->in[m].fdcAnodeWires =
01121                               make_s_FdcAnodeWires(wireCount);
01122           box->fdcChambers->in[m].fdcTruthPoints =
01123                               make_s_FdcTruthPoints(pointCount);
01124           box->fdcChambers->mult++;
01125         }
01126         else
01127         {
01128           m--;
01129         }
01130         for (strip=0; strip < strips->mult; ++strip)
01131         {
01132            int mm = box->fdcChambers->in[m].fdcCathodeStrips->mult++;
01133            box->fdcChambers->in[m].fdcCathodeStrips->in[mm] = strips->in[strip];
01134         }
01135         if (strips != HDDM_NULL)
01136         {
01137            FREE(strips);
01138         }
01139         for (wire=0; wire < wires->mult; ++wire)
01140         {
01141            int mm = box->fdcChambers->in[m].fdcAnodeWires->mult++;
01142            box->fdcChambers->in[m].fdcAnodeWires->in[mm] = wires->in[wire];
01143         }
01144         if (wires != HDDM_NULL)
01145         {
01146            FREE(wires);
01147         }
01148         for (point=0; point < points->mult; ++point)
01149         {
01150            int mm = box->fdcChambers->in[m].fdcTruthPoints->mult++;
01151            box->fdcChambers->in[m].fdcTruthPoints->in[mm] = points->in[point];
01152         }
01153         if (points != HDDM_NULL)
01154         {
01155            FREE(points);
01156         }
01157      }
01158      FREE(chambers);
01159      FREE(item);
01160    }
01161 
01162    stripCount = wireCount = pointCount = 0;
01163 
01164    if ((box->fdcChambers != HDDM_NULL) &&
01165        (box->fdcChambers->mult == 0))
01166    {
01167       FREE(box->fdcChambers);
01168       box->fdcChambers = HDDM_NULL;
01169    }
01170    if (box->fdcChambers->mult == 0)
01171    {
01172       FREE(box);
01173       box = HDDM_NULL;
01174    }
01175    return box;
01176 }

Generated on 21 May 2013 for Hall-D Software by  doxygen 1.4.7