Example #1
0
int main(int argc, char * argv[]) {

  TApplication app("app", &argc, argv);
 
  const double pressure = 1 * AtmosphericPressure;
  const double temperature = 273.15;
 
  // Setup the gas.
  MediumMagboltz* gas = new MediumMagboltz();
  gas->SetTemperature(temperature);
  gas->SetPressure(pressure);
  gas->SetComposition("Ar", 66.4, "iC4H10", 33.6);

  //**ONLY NEED THIS SECTION IF YOU NEED TO SETUP A NEW GASTABLE**//


  //Set the field range to be covered by the gas table. 
  const int nFields = 20;
  const double emin =    100.;
  const double emax = 10000.;
  //Flag to request logarithmic spacing.
  const bool useLog = true;
  gas->SetFieldGrid(emin, emax, nFields, useLog); 

  const int ncoll = 10;
  // Switch on debugging to print the Magboltz output.
  gas->DisableDebugging();
  // Run Magboltz to generate the gas table.
  gas->GenerateGasTable(ncoll);
  //gas->DisableDebugging();
  //Save the table. 
  gas->WriteGasFile("ar_66_ic4h10_34.gas");


  //If using a different gas, will need to load the correct gasfile//
  gas->LoadGasFile("ar_66_ic4h10_34.gas");


  ComponentAnalyticField* cmp = new ComponentAnalyticField();

  //Define radius of sense wire, diameter of field wire, dimensions of tube//
  const double rWire= 0.00125, dfWire=0.015;
  const double rTube= 1; 
  const double lTube= 53.5; 

  //Setup geometry//
  GeometrySimple* geo = new GeometrySimple();
  SolidBox* tube = new SolidBox(0.,0.,0.,rTube,rTube,lTube);
  //Add tube and gas to geometry//
  geo->AddSolid(tube, gas);
  //Add geometry to analytic field//
  cmp->SetGeometry(geo);

  //Setup and add wires and tube to the field, may not need a tube//
  const double vWire= 2700.;
  //const double vTube = 0.;
  cmp->AddWire(0.,0., 2*rWire, vWire, "s");
  cmp->AddWire(rTube/2,0, dfWire, -1900, "g1");
  cmp->AddWire(-rTube/2,0, dfWire,-1900, "g1");
  cmp->AddWire(0,rTube/2, dfWire, -2400, "g4");
  cmp->AddWire(0,-rTube/2, dfWire, -2400, "g4");
  cmp->AddWire(.5,.5, dfWire, 0., "g5");
  cmp->AddWire(0.5,-.5, dfWire, 0., "g5");
  cmp->AddWire(-0.5,.5, dfWire, 0., "g5");
  cmp->AddWire(-0.5,-.5, dfWire, 0., "g5");
  //Repeat components every 1 unit (cm)//
  cmp->SetPeriodicityY(1);
 
  
  cmp->AddReadout("s");

  //Create sensor and add component field to it, not always necessary unless calculating signals//
  Sensor* sensor=new Sensor();
  sensor->AddComponent(cmp);
  sensor->AddElectrode(cmp, "s");

  //Visualize the field//
  ViewField* field= new ViewField();
  field->SetSensor(sensor);
  //May need to change the range//
  field->SetElectricFieldRange(0, 10000.);
  field->PlotContour("e");
  //Prepare to make a plot of drift velocity versus electric field//
  double efield[50], dvel[50];
  double vx,vy,vz;
  TGraph *drifefie= new TGraph();
  
  for (int i=0; i<50; i++){
    //loop over positions you are interested in//
    double pos[2]= {0.01*i,0.01*i};

    //  Not sure how what[] comes into play, but it is needed to tell 
    //  EvaluatePotential whether to get electric field components, e-field 
    //  mag. or get the potential. EvalutatePotential only reads what[0]. 
    //
    //     if (what[0] > 30.) {
    //        return Z-component of electric field;
    //      } else if (what[0] > 20.) {
    //        return Y-component of electric field;
    //      } else if (what[0] > 10.) {
    //        return X-component of electric field;
    //      } else if (what[0] > 0.) {
    //        return Magnitude of electric field;
    //      }
    //     return potential;

    double what[3]={11,1,2};
    double ex=(field->EvaluatePotential(pos, what));
    what[0]=what[0]*2;
    double ey= (field->EvaluatePotential(pos, what));
    what[0]=what[0]*3;
    double ez=(field->EvaluatePotential(pos, what));

//  ElectronVelocity only returns a bool. However, it does store the components 
//  of drift velocity at that point in vx,vy,vz
    gas->ElectronVelocity(ex, ey, ez, 0., 0., 0., vx,vy,vz);

    //Store the e-field and drift velocity magnitudes//
    efield[i]=sqrt(ex*ex+ey*ey+ez*ez);
    dvel[i]=sqrt(vx*vx+vy*vy+vz*vz);
  
    //Plot the points//
    if (efield[i]<10000.){
      drifefie->SetPoint(i, efield[i], dvel[i]);
    }
  }

  //NEXT COMMENTS NECESSARY ONLY IF YOU WANT TO COMPARE TO THE GASTABLE RESULTS
  //ALSO THESE MUST BE CHANGED IF USING A GAS OTHER THAN Ar-C2H6 50/50.

  // Double_t xgpoints[20]={ 1.31578947e-01, 1.67667761e-01, 2.13654834e-01, 2.72255011e-01, 3.46927750e-01, 4.42081353e-01, 5.63333210e-01, 7.17841419e-01, 9.14727363e-01, 1.16561420e+00, 1.48531302e+00, 1.89269722e+00, 2.41181672e+00, 3.07331772e+00, 3.91625190e+00, 4.99038183e+00, 6.35911873e+00, 8.10326594e+00, 1.03257891e+01, 1.31578947e+01};

  //  Double_t ygpoints[20]={ 2.46561830e+00, 2.98075892e+00, 3.48895177e+00, 3.95223049e+00, 4.34517668e+00, 4.66439922e+00, 4.91746082e+00, 5.11043863e+00, 5.24838191e+00, 5.32293867e+00, 5.32005531e+00, 5.23377813e+00, 5.07646060e+00, 4.89688261e+00, 4.74778419e+00, 4.66468487e+00, 4.63585997e+00, 4.65042164e+00, 4.69895847e+00, 4.80436817e+00}; 

  //  TGraph* garf=new TGraph();
  //  for (Int_t i=0; i<18; i++){
  //    garf->SetPoint(i, xgpoints[i]*1000, ygpoints[i]/1000);
  //  }



  TMultiGraph* mg= new TMultiGraph();
  mg->Add(drifefie);
  //mg->Add(garf);
  drifefie->SetMarkerStyle(20);
  drifefie->SetMarkerSize(1);
  //garf->SetMarkerStyle(21); garf->SetMarkerColor(2);
  //mg->Draw("AP");
 
  // ViewDrift is if you want to view the drift lines of the electron\s //
  
  ViewDrift* drift= new ViewDrift();

  // Setup time //
  const double tmin=0., tmax=1., tstep=.000001;
  const int ntimebins=int((tmax-tmin)/tstep);
  sensor->SetTimeWindow(0., tstep, ntimebins);
  
  // Use to simulate either an avalanche of electrons or just one single drifting
  // electron. For drift->Plot(bool, bool):
  //        Plot(true, true)= 2-D plot
  //        Plot(false, true)=3-D plot

  // AvalancheMicroscopic* aval= new AvalancheMicroscopic();
  // aval->EnablePlotting(drift);
  // aval->SetSensor(sensor);
  // aval->EnableSignalCalculation();
  // aval->SetTimeWindow(0.,1000.);
  // const double x0=0.4  , y0=0., z0=0., t0=0.;
  // aval->EnableAvalancheSizeLimit(150);
  // aval->AvalancheElectron(x0, y0, z0, t0,0.);
  // drift->Plot(true,true);
  

// Yet to be correctly implemented due to C2H6 not being in their table of cross
// sections. TrackElectron simulates a high-energy electron traversing the cell

  TRandom *rand=new TRandom(0);
  TrackElectron* elec=new TrackElectron();
  elec->SetSensor(sensor);
  elec->EnablePlotting(drift);
  elec->SetEnergy(4e9);
  TH1F *dist= new TH1F("distance", "distance", 20,0,0.5);
  AvalancheMicroscopic* aval= new AvalancheMicroscopic();
  aval->EnablePlotting(drift);
  aval->EnableDistanceHistogramming(1);
  aval->SetDistanceHistogram(dist, 'r');
  aval->SetSensor(sensor);
  aval->EnableSignalCalculation();
  aval->SetTimeWindow(0.,1000.);
  double xcls, ycls, zcls, tcls, ecls, extra;
  int ncls, count=0, place=0;
  double xi,yi,zi,ti,ei,xf,yf,zf,tf,ef;
  int state,spot=0;
  int min=0;
  TArrayD *time= new TArrayD(), *xpos= new TArrayD(), *smalt= new TArrayD(), *minx=new TArrayD();
  for (Int_t i=0; i<10000; i++){
    elec->NewTrack(-1, (rand->Uniform(-.49,.49)), 0., 0., 1,0,0);
    place++;
    std::cout<<place<<"->loop iteration \n";
    while (elec->GetCluster(xcls, ycls, zcls, tcls, ncls, ecls, extra)){
      double location=sqrt(xcls*xcls+ycls*ycls+zcls*zcls);
      //std::cout<<count<<std::endl;
      if (location<=rTube/2){
	aval->EnableAvalancheSizeLimit(20);
	aval->DriftElectron(xcls, ycls, zcls, tcls, ecls);
	aval->GetElectronEndpoint(0,xi,yi,zi,ti,ei,xf,yf,zf,tf,ef,state);
	if (sqrt(xf*xf+yf*yf)<=rWire){
	  time->Set(count+1);
	  time->AddAt((tf-ti),count);
	  xpos->Set(count+1);
	  xpos->AddAt(xi,count);
	  count++;
	}
	
      }
    }
    int a=spot;
    //std::cout<<(time->GetSize())-spot<<std::endl;
    for (Int_t p=0; p<((time->GetSize())-spot);p++){
      if ((time->GetAt(a))>(time->GetAt(spot+p))){
    	a=(spot+p);
      }
    }
    min=a;
    smalt->Set(i+1); minx->Set(i+1);
    smalt->AddAt(time->GetAt(min), i); minx->AddAt(xpos->GetAt(min), i);
  
    spot=count;
    //a=spot+1;
    //std::cout<<xpos->GetAt(min)<<std::endl;
    // std::cout<<smalt->GetAt(i)<<std::endl;
  }
  
  //drift->Plot(true,true);
  TCanvas *can=new TCanvas("DriftTime", "Drift Time", 600, 600);
  TCanvas *can2=new TCanvas("DriftPos", "Drift Position", 600, 600);
  dist->SetBinContent(1,0.);
  //dist->Draw();
  // TH1D *times=new TH1D("DriftsTime", "Drift Times", 75,0,150);
  // for (int k; k<time->GetSize(); k++){
  //   times->Fill(time->GetAt(k));
  // }
  // times->Draw();

  TH1D *mintimes=new TH1D("MinTime", "Minimum Drift Times", 75,0,150), *minxpos=new TH1D("minxpos", "X-pos of min. Drift Time",50 ,-.1, .1);
  for (int k; k<smalt->GetSize(); k++){
    mintimes->Fill(smalt->GetAt(k));
    minxpos->Fill(minx->GetAt(k));
  }
  can->cd();
  mintimes->Draw();
  can2->cd();
  minxpos->Draw();
  

  //** Makes plot of drift time vs x-position**// 

  // TGraph *tvsy=new TGraph();
  // for (Int_t j=0; j<time->GetSize(); j++){
  //   tvsy->SetPoint(j, xpos->GetAt(j), time->GetAt(j));
  // }
  // tvsy->SetMarkerSize(1);
  // tvsy->SetMarkerStyle(20);
  // tvsy->Draw("AP");

  //can->SaveSource("minimum_drift_times");

  //DON'T GET RID OF THIS OR YOUR STUFF WON'T WORK//
  app.Run(kTRUE);

}
Example #2
0
int main(int argc, char * argv[]) {
    
    TStopwatch watch;
    gRandom = new TRandom3(0); // set random seed
    gROOT->ProcessLine(".L loader.c+"); // Initialize struct objects (see dictionaries)
    
    // Gas setup
    TString gasmixt[6] = { "C5H12", "CF4", "", "60", "40", "" };
    TString output = gasmixt[0] + "-" + gasmixt[1] + "-" + gasmixt[2] + "-" + gasmixt[3] + "-" + gasmixt[4] + "-" + gasmixt[5];
    
    std::string workingdir = "includes/";
    workingdir.append("GEM5"); // Name of the working directory which contains the GEM files
    workingdir.append("/");

    std::string particleType = "mu";
    Double_t particleEnergy = 100.e9;
    bool debug = true;
    Int_t it = 100;

    // Load GEM dimensions
    GEMconfig g;
    loadGEMconfig(workingdir, g);
    
    // Load the field map
    ComponentAnsys123* fm = new ComponentAnsys123();
    std::string efile = workingdir + "ELIST.lis";
    std::string nfile = workingdir + "NLIST.lis";
    std::string mfile = workingdir + "MPLIST.lis";
    std::string sfile = workingdir + "PRNSOL.lis";
    std::string wfile = workingdir + "WSOL.lis";
    std::string dfile = workingdir + "WSOLD.lis";
    if(!fm->Initialise(efile, nfile, mfile, sfile, "mm")) {
        std::cout << "Error while loading the ANSYS field map files." << std::endl;
    }
    fm->EnableMirrorPeriodicityX();
    fm->EnableMirrorPeriodicityY();
    if(debug) {
        fm->PrintRange();
    }
    fm->SetWeightingField(wfile, "readout");
    fm->SetWeightingField(dfile, "ions");
	
    // Gas setup
    MediumMagboltz* gas = new MediumMagboltz();
    gas->SetComposition((std::string)gasmixt[0], atof(gasmixt[3]), (std::string)gasmixt[1], atof(gasmixt[4]), (std::string)gasmixt[2], atof(gasmixt[5]));
    gas->SetTemperature(293.15);
    gas->SetPressure(760.0);	
    //gas->SetMaxElectronEnergy(200.);
    gas->EnableDebugging();
    gas->Initialise();
    gas->DisableDebugging();
    //const double rPenning = 0.57;
    //const double lambdaPenning = 0.;
    //gas->EnablePenningTransfer(rPenning, lambdaPenning, "ar");
    gas->LoadIonMobility(GARFIELD + "Data/IonMobility_Ar+_Ar.txt");
    //gas->LoadIonMobility(GARFIELD + "Data/IonMobility_CO2+_CO2");
     
    //Associate the gas with the corresponding field map material.
    const int nMaterials = fm->GetNumberOfMaterials();
    for(int i=0; i<nMaterials; ++i) {
 	
        const double eps = fm->GetPermittivity(i);
        if(fabs(eps - 1.) < 1.e-3) fm->SetMedium(i, gas);
    }
    if(debug) {
        fm->PrintMaterials();
    }
    
    // Sensor setup
    Sensor* sensor = new Sensor();
    sensor->AddComponent(fm);
    sensor->SetArea(-5.*(g.pitch), -5.*(g.pitch), 0.0, 5.*(g.pitch), 5.*(g.pitch), g.totalT);
    
    // Setup HEED
    TrackHeed* heed = new TrackHeed();
    heed->SetSensor(sensor);
    //heed->DisableDeltaElectronTransport();
    heed->SetParticle(particleType);
    heed->SetMomentum(particleEnergy);
    if(debug) {
        heed->EnableDebugging();
    }
	
    // Setup electron transport
    AvalancheMicroscopic* aval = new AvalancheMicroscopic();
    aval->SetSensor(sensor);
    //aval->EnableAvalancheSizeLimit(1000);
    
    sensor->AddElectrode(fm, "readout");
    sensor->AddElectrode(fm, "ions");
    const double tMin = 0.;
    const double tMax = 75.;
    const double tStep = 0.2;
    const int nTimeBins = int((tMax - tMin)/tStep);
    sensor->SetTimeWindow(0., tStep, nTimeBins);
    aval->EnableSignalCalculation();
    
    ViewSignal* signalView = new ViewSignal();
    signalView->SetSensor(sensor);
    TH1D* h; // tmp storage of timing histogram

    // Setup ion transport
    AvalancheMC* iondrift = new AvalancheMC();
    iondrift->SetSensor(sensor);
    iondrift->EnableSignalCalculation();
    iondrift->SetDistanceSteps(2e-4);

    // Calculate avalanche
    int ne, ni, np, status, nc;
    double ec, extra;
    double x0, y0, z0, t0, e0, x1, y1, z1, t1, e1, x2, y2, z2, t2, e2, x3, y3, z3, t3, e3;
    double vx0, vy0, vz0, vx1, vy1, vz1;
	
    TRandom3 r;
    r.SetSeed(0);

    TString savefile = workingdir + "output/" + output + ".root";
    TFile f(savefile, "recreate");
    TDirectory *dir = f.mkdir("signals");
    dir->cd();
    
    // Prepare tree for charged particle and clusters
    particle p;
    TTree *pTree = new TTree("pTree", "Charged particle");
    pTree->Branch("x0", &p.x0);
    pTree->Branch("y0", &p.y0);
    pTree->Branch("z0", &p.z0);
    pTree->Branch("vx0", &p.vx0);
    pTree->Branch("vy0", &p.vy0);
    pTree->Branch("vz0", &p.vz0);
    pTree->Branch("t0", &p.t0);
    pTree->Branch("e0", &p.e0);
    pTree->Branch("type", "TString", &p.type);
    pTree->Branch("noClusters", &p.noClusters);
    pTree->Branch("stoppingpower", &p.stoppingPower);
    pTree->Branch("lambda", &p.lambda);
    pTree->Branch("clusters", "std::vector<cluster>", &p.clusters);
  
    // Prepare tree for electrons
    avalancheE aE;
    TTree *ETree = new TTree("eTree", "Avalanche electrons");
    ETree->Branch("x0", &aE.x0);
    ETree->Branch("y0", &aE.y0);
    ETree->Branch("z0", &aE.z0);
    ETree->Branch("vx0", &aE.vx0);
    ETree->Branch("vy0", &aE.vy0);
    ETree->Branch("vz0", &aE.vz0);
    ETree->Branch("t0", &aE.t0);
    ETree->Branch("e0", &aE.e0);
    ETree->Branch("ne", &aE.ne);
    ETree->Branch("x1", &aE.x1);
    ETree->Branch("y1", &aE.y1);
    ETree->Branch("z1", &aE.z1);
    ETree->Branch("t1", &aE.t1);
    ETree->Branch("e1", &aE.e1);
    ETree->Branch("x2", &aE.x2);
    ETree->Branch("y2", &aE.y2);
    ETree->Branch("z2", &aE.z2);
    ETree->Branch("t2", &aE.t2);
    ETree->Branch("e2", &aE.e2);
    ETree->Branch("status", &aE.status);
    
    // Prepare tree for ions
    avalancheI aI;
    TTree *ITree = new TTree("iTree", "Avalanche ions");
    ITree->Branch("x0", &aI.x0);
    ITree->Branch("y0", &aI.y0);
    ITree->Branch("z0", &aI.z0);
    ITree->Branch("t0", &aI.t0);
    ITree->Branch("ni", &aI.ni);
    ITree->Branch("x1", &aI.x1);
    ITree->Branch("y1", &aI.y1);
    ITree->Branch("z1", &aI.z1);
    ITree->Branch("t1", &aI.t1);
    ITree->Branch("x2", &aI.x2);
    ITree->Branch("y2", &aI.y2);
    ITree->Branch("z2", &aI.z2);
    ITree->Branch("t2", &aI.t2);
    ITree->Branch("status", &aI.status);
    
    // Start iteration
    std::cout << "---------------------------------------------------------------" << std::endl;
    for(int i=0; i<it; i++) {
        
        if(debug) {
            std::cout << "Progress: " << 100.*(i+1)/it << "%" << std::endl;
        }

	system("mail -s 'timeResolution10' [email protected] <<< 'Progress: " + int2str(i) + "' ");
        
        // Set random velocity direction, in positive hemisphere
        const double ctheta = 1. - r.Uniform();
        const double stheta = sqrt(1. - ctheta*ctheta);
        const double phi = TwoPi*r.Uniform();
        vx0 = cos(phi)*stheta;
        vy0 = sin(phi)*stheta;
        vz0 = ctheta;
  
        // Set initial time
        t0 = 0.0;

        // Generate random (x,y) position in unit cell
        x0 = r.Uniform()*g.pitch/2; 
        y0 = r.Uniform()*g.pitch*TMath::Sqrt(3)/2;
        z0 = 0.;
        
        // Set muon perpendicular in midpoint of GEM
        x0 = 0.;
        y0 = 0.;
        vx0 = 0.;
        vy0 = 0.;
        vz0 = 1.;
        
        heed->NewTrack(x0, y0, z0, t0, vx0, vy0, vz0); // generate particle track
        
        // Storage of TRACK coordinates and primary ionization properties
        p.x0 = x0;
        p.y0 = y0;
        p.z0 = z0;
        p.vx0 = vx0;
        p.vy0 = vy0;
        p.vz0 = vz0;
        p.t0 = t0;
        p.e0 = particleEnergy;
        p.type = particleType;
        p.noClusters = 0;
        p.lambda = 1/heed->GetClusterDensity();
        p.stoppingPower = heed->GetStoppingPower();

        // Loop over clusters
        int l=0;
        while(heed->GetCluster(x0, y0, z0, t0, nc, ec, extra)) {
            
            // Skip the clusters which are not in the drift region
            if(z0 > g.driftT) {
                continue;
            }
            
            if(debug) {
                std::cout << "  cluster " << l << " (# electrons = " << nc << ", ec = " << ec <<" )" << std::endl;
            } 

            cluster c;
            // Storage of cluster information
            p.noClusters++;
            c.x0 = x0;
            c.y0 = y0;
            c.z0 = z0;
            c.t0 = t0;
            c.nc = nc; // amount of primary electrons
            c.ec = ec; // energy transferred to gas
            
            // Loop over electrons in cluster
            for(int j=0; j<nc; j++) {

                heed->GetElectron(j, x1, y1, z1, t1, e1, vx1, vy1, vz1);
                
                c.x1.push_back(x1);
                c.y1.push_back(y1);
                c.z1.push_back(z1);
                c.t1.push_back(t1);
                c.e1.push_back(e1);
                c.vx1.push_back(vx1);
                c.vy1.push_back(vy1);
                c.vz1.push_back(vz1);

                // Calculate the drift of electrons and ions
                aval->AvalancheElectron(x1, y1, z1, t1, e1, vx1, vy1, vz1);
                aval->GetAvalancheSize(ne, ni);
                np = aval->GetNumberOfElectronEndpoints();
        
                if(debug) {
                    std::cout << "    avalanche electrons = " << np << std::endl;
                }
                
                aE.ne = ne;
                aE.x0 = x1;
                aE.y0 = y1;
                aE.z0 = z1;
                aE.vx0 = vx1;
                aE.vy0 = vy1;
                aE.vz0 = vz1;
                aE.t0 = t1;
                aE.e0 = e1;
                aI.ni = ni;
                aI.x0 = x1;
                aI.y0 = y1;
                aI.z0 = z1;
                aI.t0 = t1;
                       
                // Loop over all electrons in avalanche
                for(int k=0; k<np; k++) {

                    aval->GetElectronEndpoint(k, x2, y2, z2, t2, e2, x3, y3, z3, t3, e3, status);
                    aE.x1.push_back(x2);
                    aE.y1.push_back(y2);
                    aE.z1.push_back(z2);
                    aE.t1.push_back(t2);
                    aE.e1.push_back(e2);
                    aE.x2.push_back(x3);
                    aE.y2.push_back(y3);
                    aE.z2.push_back(z3);
                    aE.t2.push_back(t3);
                    aE.e2.push_back(e3);
                    aE.status.push_back(status);  

                    iondrift->DriftIon(x2, y2, z2, t2);
                    iondrift->GetIonEndpoint(0, x2, y2, z2, t2, x3, y3, z3, t3, status);
                    aI.x1.push_back(x2);
                    aI.y1.push_back(y2);
                    aI.z1.push_back(z2);
                    aI.t1.push_back(t2);
                    aI.x2.push_back(x3);
                    aI.y2.push_back(y3);
                    aI.z2.push_back(z3);
                    aI.t2.push_back(t3);
                    aI.status.push_back(status);
                    
                    
                }
        
                ETree->Fill();
                ITree->Fill();
        
                // Reset vectors
                aE.x1.clear();
                aE.y1.clear();
                aE.z1.clear();
                aE.t1.clear();
                aE.e1.clear();
                aE.x2.clear();
                aE.y2.clear();
                aE.z2.clear();
                aE.t2.clear();
                aE.e2.clear();
                aE.status.clear();

                aI.x1.clear();
                aI.y1.clear();
                aI.z1.clear();
                aI.t1.clear();
                aI.e1.clear();
                aI.x2.clear();
                aI.y2.clear();
                aI.z2.clear();
                aI.t2.clear();
                aI.e2.clear();
                aI.status.clear();    
            }     
            
            p.clusters.push_back(c);
            l++;
        }

        pTree->Fill();
        p.clusters.clear();
        
        signalView->PlotSignal("readout");
        h = signalView->GetHistogram();
        h->Write("signal");

        sensor->SetTransferFunction(transferf);
        sensor->ConvoluteSignal();
        signalView->PlotSignal("readout");
        h = signalView->GetHistogram();
        h->Write("signalT");    
        sensor->ClearSignal();
    }
    
    f.cd(); // go to top directory
    ETree->Write();
    ITree->Write();
    pTree->Write();
    f.Close();
    
    std::cout << "--------------- TIMING ---------------" << std::endl;
    std::cout << watch.CpuTime() << std::endl;

    return 0;
}
Example #3
0
int main(int argc, char * argv[]) {

  TApplication app("app", &argc, argv);
  plottingEngine.SetDefaultStyle();

  const bool debug = true;

  // Load the field map.
  ComponentAnsys123* fm = new ComponentAnsys123();
  const std::string efile = "ELIST.lis";
  const std::string nfile = "NLIST.lis";
  const std::string mfile = "MPLIST.lis";
  const std::string sfile = "PRNSOL.lis";
  fm->Initialise(efile, nfile, mfile, sfile, "mm");
  fm->EnableMirrorPeriodicityX();
  fm->EnableMirrorPeriodicityY();
  fm->PrintRange();

  // Dimensions of the GEM
  const double pitch = 0.014;
  const double kapton = 50.e-4;
  const double metal = 5.e-4;
  const double outdia = 70.e-4;
  const double middia = 50.e-4;

  const bool plotField = false;
  if (plotField) {
    ViewField* fieldView = new ViewField();
    fieldView->SetComponent(fm);
    fieldView->SetPlane(0., -1., 0., 0., 0., 0.);
    fieldView->SetArea(-pitch / 2., -0.02, pitch / 2., 0.02);
    fieldView->SetVoltageRange(-160., 160.);
    TCanvas* cF = new TCanvas();
    fieldView->SetCanvas(cF);
    fieldView->PlotContour();
  }

  // Setup the gas.
  MediumMagboltz* gas = new MediumMagboltz();
  gas->SetComposition("ar", 70., "co2", 30.);
  gas->SetTemperature(293.15);
  gas->SetPressure(760.);
  gas->EnableDebugging();
  gas->Initialise();  
  gas->DisableDebugging();
  // Set the Penning transfer efficiency.
  const double rPenning = 0.57;
  const double lambdaPenning = 0.;
  gas->EnablePenningTransfer(rPenning, lambdaPenning, "ar");
  // Load the ion mobilities.
  gas->LoadIonMobility("IonMobility_Ar+_Ar.txt");
  
  // Associate the gas with the corresponding field map material. 
  const int nMaterials = fm->GetNumberOfMaterials();
  for (int i = 0; i < nMaterials; ++i) {
    const double eps = fm->GetPermittivity(i);
    if (fabs(eps - 1.) < 1.e-3) fm->SetMedium(i, gas);
  }
  fm->PrintMaterials();

  // Create the sensor.
  Sensor* sensor = new Sensor();
  sensor->AddComponent(fm);
  sensor->SetArea(-5 * pitch, -5 * pitch, -0.03,
                   5 * pitch,  5 * pitch,  0.03);

  AvalancheMicroscopic* aval = new AvalancheMicroscopic();
  aval->SetSensor(sensor);

  AvalancheMC* drift = new AvalancheMC();
  drift->SetSensor(sensor);
  drift->SetDistanceSteps(2.e-4);

  const bool plotDrift = true;
  ViewDrift* driftView = new ViewDrift();
  if (plotDrift) {
    driftView->SetArea(-2 * pitch, -2 * pitch, -0.02,
                        2 * pitch,  2 * pitch,  0.02);
    // Plot every 10 collisions (in microscopic tracking).
    aval->SetCollisionSteps(10); 
    aval->EnablePlotting(driftView);
    drift->EnablePlotting(driftView);
  }

  // Histograms
  int nBinsGain = 100;
  double gmin =   0.;
  double gmax = 100.;
  TH1F* hElectrons = new TH1F("hElectrons", "Number of electrons",
                              nBinsGain, gmin, gmax);
  TH1F* hIons = new TH1F("hIons", "Number of ions",
                         nBinsGain, gmin, gmax);

  int nBinsChrg = 100;
  TH1F* hChrgE = new TH1F("hChrgE", "Electrons on plastic",
                          nBinsChrg, -0.5e4 * kapton, 0.5e4 * kapton);
  TH1F* hChrgI = new TH1F("hChrgI", "Ions on plastic", 
                          nBinsChrg, -0.5e4 * kapton, 0.5e4 * kapton);

  double sumIonsTotal = 0.;
  double sumIonsDrift = 0.;
  double sumIonsPlastic = 0.;

  double sumElectronsTotal = 0.;
  double sumElectronsPlastic = 0.;
  double sumElectronsUpperMetal = 0.;
  double sumElectronsLowerMetal = 0.;
  double sumElectronsTransfer = 0.;
  double sumElectronsOther = 0.;

  const int nEvents = 10;
  for (int i = nEvents; i--;) { 
    if (debug || i % 10 == 0) std::cout << i << "/" << nEvents << "\n";
    // Randomize the initial position.
    const double smear = pitch / 2.; 
    double x0 = -smear + RndmUniform() * smear;
    double y0 = -smear + RndmUniform() * smear;
    double z0 = 0.025; 
    double t0 = 0.;
    double e0 = 0.1;
    aval->AvalancheElectron(x0, y0, z0, t0, e0, 0., 0., 0.);
    int ne = 0, ni = 0;
    aval->GetAvalancheSize(ne, ni);
    hElectrons->Fill(ne);
    hIons->Fill(ni); 
    const int np = aval->GetNumberOfElectronEndpoints();
    double xe1, ye1, ze1, te1, e1;
    double xe2, ye2, ze2, te2, e2;
    double xi1, yi1, zi1, ti1;
    double xi2, yi2, zi2, ti2;
    int status;
    for (int j = np; j--;) {
      aval->GetElectronEndpoint(j, xe1, ye1, ze1, te1, e1, 
                                   xe2, ye2, ze2, te2, e2, status);
      sumElectronsTotal += 1.;
      if (ze2 > -kapton / 2. && ze2 < kapton / 2.) {
        hChrgE->Fill(ze2 * 1.e4);
        sumElectronsPlastic += 1.;
      } else if (ze2 >= kapton / 2. && ze2 <= kapton  / 2. + metal) {
        sumElectronsUpperMetal += 1.;
      } else if (ze2 <= -kapton / 2. && ze2 >= -kapton / 2. - metal) {
        sumElectronsLowerMetal += 1.;
      } else if (ze2 < -kapton / 2. - metal) {
        sumElectronsTransfer += 1.;
      } else {
        sumElectronsOther += 1.;
      }
      drift->DriftIon(xe1, ye1, ze1, te1);
      drift->GetIonEndpoint(0, xi1, yi1, zi1, ti1, 
                               xi2, yi2, zi2, ti2, status);
      if (zi1 < 0.01) {
        sumIonsTotal += 1.;
        if (zi2 > 0.01) sumIonsDrift += 1.;
      }
      if (zi2 > -kapton / 2. && zi2 < kapton / 2.) {
        hChrgI->Fill(zi2 * 1.e4);
        sumIonsPlastic += 1.;
      }
    }
  }

  double fFeedback = 0.;
  if (sumIonsTotal > 0.) fFeedback = sumIonsDrift / sumIonsTotal;
  std::cout << "Fraction of ions drifting back: " << fFeedback << "\n"; 

  const double neMean = hElectrons->GetMean();
  std::cout << "Mean number of electrons: " << neMean << "\n";
  const double niMean = hIons->GetMean();
  std::cout << "Mean number of ions: " << niMean << "\n";

  std::cout << "Mean number of electrons on plastic: "
            << sumElectronsPlastic / nEvents << "\n";
  std::cout << "Mean number of ions on plastic: "
            << sumIonsPlastic / nEvents << "\n";
 
  std::cout << "Electron endpoints:\n";
  const double fUpperMetal = sumElectronsUpperMetal / sumElectronsTotal;
  const double fPlastic = sumElectronsPlastic / sumElectronsTotal;
  const double fLowerMetal = sumElectronsLowerMetal / sumElectronsTotal;
  const double fTransfer = sumElectronsTransfer / sumElectronsTotal;
  const double fOther = sumElectronsOther / sumElectronsTotal;
  std::cout << "    upper metal: " << fUpperMetal * 100. << "%\n";
  std::cout << "    plastic:     " << fPlastic * 100. << "%\n";
  std::cout << "    lower metal: " << fLowerMetal * 100. << "%\n";
  std::cout << "    transfer:    " << fTransfer * 100. << "%\n";
  std::cout << "    other:       " << fOther * 100. << "%\n";

  TCanvas* cD = new TCanvas();
  const bool plotGeo = true;
  if (plotGeo && plotDrift) {
    // Build the geometry in Root.
    TGeoManager* geoman = new TGeoManager("world", "geometry");
    TGeoMaterial* matVacuum = new TGeoMaterial("Vacuum", 0, 0, 0);
    TGeoMedium* medVacuum = new TGeoMedium("Vacuum", 1, matVacuum);
    TGeoMaterial* matKapton = new TGeoMaterial("Kapton", 12, 6, 1.42);
    TGeoMedium* medKapton = new TGeoMedium("Kapton", 2, matKapton);
    TGeoMaterial* matCopper = new TGeoMaterial("Copper", 63, 29, 8.94);
    TGeoMedium* medCopper = new TGeoMedium("Copper", 3, matCopper);
    TGeoVolume* volTop = geoman->MakeBox("TOP", 
                                         medVacuum, pitch, pitch, 0.02);
    volTop->SetVisibility(0);
    TGeoBBox* shpKapton = new TGeoBBox("K", pitch / 2., 
                                            pitch / 2., 
                                            kapton / 2.);
    TGeoPcon* shpHole = new TGeoPcon("H", 0., 360., 3);
    shpHole->DefineSection(0, -kapton / 2., 0., outdia / 2.);
    shpHole->DefineSection(1,           0., 0., middia / 2.);
    shpHole->DefineSection(2,  kapton / 2., 0., outdia / 2.);

    TGeoCompositeShape* shpGem = new TGeoCompositeShape("G", "K - H");
    TGeoVolume* volKapton = new TGeoVolume("Kapton", shpGem, medKapton);
    volKapton->SetLineColor(kGreen);
    volKapton->SetTransparency(50);

    TGeoBBox* shpMetal = new TGeoBBox("M", pitch / 2., 
                                           pitch / 2., 
                                           metal / 2.);
    TGeoTube* shpTube = new TGeoTube("T", 0., outdia / 2., metal / 2.);
    TGeoCompositeShape* shpElectrode = new TGeoCompositeShape("E", "M - T");
    TGeoVolume* volElectrode = new TGeoVolume("Electrode", 
                                              shpElectrode, medCopper);
    volElectrode->SetLineColor(kBlue);
    volElectrode->SetTransparency(50);

    TGeoVolumeAssembly* volGem = new TGeoVolumeAssembly("Gem");
    const double shift =  0.5 * (metal + kapton);
    volGem->AddNode(volKapton, 1);
    volGem->AddNode(volElectrode, 2, new TGeoTranslation(0., 0.,  shift));
    volGem->AddNode(volElectrode, 3, new TGeoTranslation(0., 0., -shift));

    volTop->AddNode(volGem, 1);
    volTop->AddNode(volGem, 2, new TGeoTranslation(-pitch, 0., 0.));
    volTop->AddNode(volGem, 3, new TGeoTranslation(+pitch, 0., 0.));
    volTop->AddNode(volGem, 4, 
               new TGeoTranslation(-pitch / 2., sqrt(3) * pitch / 2., 0.));
    volTop->AddNode(volGem, 5, 
               new TGeoTranslation(+pitch / 2., sqrt(3) * pitch / 2., 0.));
    volTop->AddNode(volGem, 6,
               new TGeoTranslation(-pitch / 2., -sqrt(3) * pitch / 2., 0.));
    volTop->AddNode(volGem, 7,
               new TGeoTranslation(+pitch / 2., -sqrt(3) * pitch / 2., 0.));
    geoman->SetVerboseLevel(0);
    geoman->SetTopVolume(volTop);
    geoman->CloseGeometry();
    geoman->CheckOverlaps(0.1e-4);
    geoman->SetNmeshPoints(100000);
    cD->cd();
    geoman->GetTopVolume()->Draw("ogl");
  }

  if (plotDrift) {
    driftView->SetCanvas(cD);
    driftView->Plot();
  }

  const bool plotHistogram = true;
  if (plotHistogram) {
    TCanvas* cH = new TCanvas("cH", "Histograms", 800, 700);
    cH->Divide(2, 2);
    cH->cd(1);
    hElectrons->Draw();
    cH->cd(2);
    hIons->Draw();
    cH->cd(3);
    hChrgE->Draw();
    cH->cd(4);
    hChrgI->Draw();
  }

  app.Run(kTRUE);

}