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; }
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); }