int main(int argc, char * argv[]){ TApplication app("app", &argc, argv); plottingEngine.SetDefaultStyle(); // Load the Magboltz gas file MediumMagboltz* gas = new MediumMagboltz(); gas->SetComposition("ar", 93., "co2", 7.); gas->SetTemperature(293.15); gas->SetPressure(760.); gas->Initialise(true); gas->LoadIonMobility("/opt/garfield/Data/IonMobility_Ar+_Ar.txt"); // // Structure of Micromegas cell (from top to bottom): //------------------------ // | Drift electrode (Vdrift = -2500 V) // | Drift gap (Hdriftgap = 3 mm) // | Mesh electrode (Vmesh = -500 V) // | Amplification gap (Hampgap = 100 um) // | Strips (Vstrip = 0 V) //------------------------ // ComponentElmer * elm = new ComponentElmer("elmer/mesh.header", "elmer/mesh.elements", "elmer/mesh.nodes","elmer/dielectrics.dat", "elmer/case.result","micron"); elm->SetMedium(0,gas); ////Finally we assemble a Sensor object Sensor* sensor = new Sensor(); //// Calculate the electric field using the Component object cmp sensor->AddComponent(elm); //// Request signal calculation for the electrode named with labels above, //// using the weighting field provided by the Component object cmp. //sensor->AddElectrode(elm, "Strip1"); //sensor->AddElectrode(elm, "Strip2"); //sensor->AddElectrode(elm, "Strip3"); //// Set Time window for signal integration, units in [ns] //double tMin = 0.; //const double tMax = 100.; //const double tStep = 0.05; //const int nTimeBins = int((tMax - tMin) / tStep); //sensor->SetTimeWindow(0., tStep, nTimeBins); //// This canvas will be used to display the drift lines and the field TCanvas * c = new TCanvas("c", "c", 10, 10, 1000, 700); c->Divide(2,1); //// Construct object to visualise drift lines //ViewDrift* viewdrift = new ViewDrift(); //viewdrift->SetArea(-0.2, 0.0, -0.1, 0.2, 4,0.1 ); //viewdrift->SetClusterMarkerSize(0.1); //viewdrift->SetCollisionMarkerSize(0.5); //viewdrift->SetCanvas((TCanvas*)c->cd(1)); ////For simulating the electron avalanche we use the class AvalancheMicroscopic //AvalancheMicroscopic* aval = new AvalancheMicroscopic(); //const int aval_size = 0.1; //aval->SetSensor(sensor); //// Switch on signal calculation. //aval->EnableSignalCalculation(); //aval->SetTimeWindow(tMin,tMax ); //aval->EnableAvalancheSizeLimit(aval_size); //aval->EnablePlotting(viewdrift); //aval->EnableDriftLines(); //aval->EnableMagneticField(); //// Additional optional switches ////aval->EnableExcitationMarkers(); ////aval->EnableIonisationMarkers(); ////Add ionizing particle using Heed //// Here we add a negative pion with some momentum, units in [eV/c] //const double energy = 170.e+09; // eV/c //TrackHeed* track = new TrackHeed(); //track->SetParticle("muon"); //track->SetEnergy(energy); //track->SetSensor(sensor); //track->EnableMagneticField(); //track->EnableElectricField(); //track->EnablePlotting(viewdrift); //// Cluster info //double xcls, ycls, zcls, tcls, e, extra; //xcls = ycls = zcls = tcls = e = extra = -999.; //// Electron info //double xele, yele, zele, tele, eele, dxele, dyele, dzele; //// Electron start and endpoints, momentum direction and status //double x0ele, y0ele, z0ele, t0ele, e0ele;// start point //double x1ele, y1ele, z1ele, t1ele, e1ele;// endpoint //double dx1ele, dy1ele, dz1ele; // momentum direction //int status1ele; // status //int n = 0; // number of electrons in cluster //bool cls_ret;// return OK if cluster is OK //bool cls_ret2; //bool cls_ret3; //bool cls_ret4; //// The initial impact position of the incoming ionising track //double track_x = 0.15;// [cm] //double track_y = 0.3; //double track_z = 0.0; //// Momentum direction of incoming track //double track_dx = -0.5; //double track_dy = -0.5; // Track coming downstream //double track_dz = 0.0; //track->DisableDeltaElectronTransport(); //do //{ //// Now create a single track //track->NewTrack(track_x, track_y, track_z, tMin, track_dx, track_dy, track_dz); //cls_ret = track->GetCluster(xcls, ycls, zcls, tcls, n, e, extra); //std::cout<<"ycls="<<ycls<<std::endl; //std::cout<<"ncls="<<n<<std::endl; //std::cout<<"ecls="<<e<<std::endl; //// Now loop over electrons in cluster //for(int j = 1; j <= n; j++){ //track->GetElectron(j-1, xele, yele, zele, tele, eele, dxele, dyele, dzele); //// Simulate an avalanche for the current electron //aval->AvalancheElectron(xele, yele, zele, tele, eele, dxele, dyele, dzele); //} //track_x=xcls; //track_y=ycls; //track_z=zcls; //tMin=tcls; //std::cout<<"ycls="<<ycls<<std::endl; //} while (track_y> 0 && cls_ret); // Now plot the drift lines //viewdrift->Plot(); // View the Field ViewField * viewfield = new ViewField(); viewfield->SetComponent(elm); viewfield->SetCanvas((TCanvas*)c->cd(1)); viewfield->SetPlane(-1, 0, 0, 0, 0, 0); viewfield->SetSensor(sensor); //viewfield->SetArea(-5,0,5,0.3); //viewfield->SetArea(-5,-5,5,5); //viewfield->SetWeightingFieldRange(0.0, 10000.0); //c->cd(1); viewfield->PlotSurface(); app.Run(); return 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; }
int main(int argc, char * argv[]) { string output_file = "data.txt"; srand (time(NULL)); double gas_pressure = 760.; double gas_temperature = 273.15; double particle_energy = 4.e9; // eV/c double top_voltage = -180.; double mesh_voltage = 0.; double bottom_voltage = 500; double conc_ar = 93.; double conc_co2 = 7.; int cp; while (1) { static struct option long_options[] = { /* These options set a flag. */ // {"verbose", no_argument, &verbose_flag, 1}, // {"brief", no_argument, &verbose_flag, 0}, /* These options don’t set a flag. We distinguish them by their indices. */ {"output_file", required_argument, 0, 'o'}, {"gas_pressure", required_argument, 0, 'p'}, {"gas_temperature", required_argument, 0, 't'}, {"particle_energy", required_argument, 0, 'e'}, {"top_voltage", required_argument, 0, 'x'}, {"mesh_voltage", required_argument, 0, 'y'}, {"bottom_voltage", required_argument, 0, 'z'}, {"conc_ar", required_argument, 0, 'a'}, {"conc_co2", required_argument, 0, 'c'}, {0, 0, 0, 0} }; /* getopt_long stores the option index here. */ int option_index = 0; cp = getopt_long (argc, argv, "p:t:e:o:x:y:z:a:c:", long_options, &option_index); /* Detect the end of the options. */ if (cp == -1) break; switch (cp) { case 0: /* If this option set a flag, do nothing else now. */ if (long_options[option_index].flag != 0) break; printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case 'o': printf ("Setting output file to `%s'\n", optarg); output_file = string(optarg); break; case 'p': printf ("Setting gas pressure to `%s'\n", optarg); gas_pressure = stod(optarg); break; case 't': printf ("Setting gas temperature to `%s'\n", optarg); gas_temperature = stod(optarg); break; case 'e': printf ("Setting particle energy to `%s'\n", optarg); particle_energy = stod(optarg); break; case 'x': printf ("Setting top voltage to `%s'\n", optarg); top_voltage = stod(optarg); break; case 'y': printf ("Setting mesh voltage to `%s'\n", optarg); mesh_voltage = stod(optarg); break; case 'z': printf ("Setting bottom voltage to `%s'\n", optarg); bottom_voltage = stod(optarg); break; case 'a': printf ("Setting Ar conc to `%s'\n", optarg); conc_ar = stod(optarg); break; case 'c': printf ("Setting CO2 conc to `%s'\n", optarg); conc_co2 = stod(optarg); break; case '?': /* getopt_long already printed an error message. */ break; default: abort (); break; } } ///* Print any remaining command line arguments (not options). */ //if (optind < argc) //{ //printf ("non-option ARGV-elements: "); //while (optind < argc) //printf ("%s ", argv[optind++]); //putchar ('\n'); //} //TApplication app("app", &argc, argv); //plottingEngine.SetDefaultStyle(); // // Load the Magboltz gas file MediumMagboltz* gas = new MediumMagboltz(); gas->SetComposition("ar", conc_ar, "co2", conc_co2); gas->SetTemperature(gas_temperature); gas->SetPressure(gas_pressure); gas->Initialise(true); gas->LoadIonMobility("/opt/garfield/Data/IonMobility_Ar+_Ar.txt"); // // Structure of Micromegas cell (from top to bottom): //------------------------ // | Drift electrode (Vdrift = -2500 V) // | Drift gap (Hdriftgap = 3 mm) // | Mesh electrode (Vmesh = -500 V) // | Amplification gap (Hampgap = 100 um) // | Strips (Vstrip = 0 V) //------------------------ // // // We place 3 strips in z direction in order to // be able to resolve the avalanche signal. // Strips can be parametrized by width and pitch // // Units given in [cm] const double Hdriftgap = 0.3; // Drift gap height const double Hampgap = 0.0128; // Amplification gap height const double Htot = Hdriftgap + Hampgap; // Total height const double Pitch = 0.07; // Pitch const double Interpitch = 0.01; // Distance between two strips const double Wstrip = Pitch - Interpitch; // Electrode potentials const double Vdrift = top_voltage; const double Vamp = mesh_voltage; const double Vstrip = bottom_voltage; // Magnetic field const double MagX = 0.; const double MagY = 0.; const double MagZ = 0.; // Geometry of the structure // Parallel planes, SolidBox, height [cm] // Width [cm] const double w = 3.0; // x // Length [cm] const double l = 3.0; // y GeometrySimple* geo = new GeometrySimple(); SolidBox* box = new SolidBox(0.,Htot/2.0, 0., w, Htot/2.0, l); geo->AddSolid(box, gas); // // The Component requires a description of the geometry, that is a list of volumes // and associated media. // Here we construct 2 ComponentAnalyticalFields, to treat the // arift region and the amplification separately // ComponentAnalyticField* cmpDrift = new ComponentAnalyticField(); ComponentAnalyticField* cmpAmp = new ComponentAnalyticField(); // Pass a pointer of the geometry class to the components. cmpDrift->SetGeometry(geo); cmpAmp->SetGeometry(geo); // Now we add the planes for the electrodes with labels cmpDrift->AddPlaneY(Htot, Vdrift, "DriftPlane"); cmpDrift->AddPlaneY(Hampgap, Vamp, "AmpPlane"); cmpAmp->AddPlaneY(Hampgap, Vamp, "AmpPlane"); cmpAmp->AddPlaneY(0.0, Vstrip, "StripPlane"); //Next we construct the Strips for readout of te signal, also with labels double Xoffset = -w; int n_strips_x = w*2/Pitch; double Xstrips[n_strips_x]; //Finally we assemble a Sensor object Sensor* sensor = new Sensor(); // Calculate the electric field using the Component object cmp sensor->AddComponent(cmpDrift); sensor->AddComponent(cmpAmp); for(int j=0; j<n_strips_x; j++) { const char* name = ("Strip"+to_string(j)).c_str(); Xstrips[j]=Xoffset + Wstrip/2.0; cmpAmp->AddStripOnPlaneY('z', 0.0, Xoffset, Xoffset + Wstrip, name); Xoffset += Pitch; cmpAmp->AddReadout(name); sensor->AddElectrode(cmpAmp, name); } // Ion strip cmpAmp->AddStripOnPlaneY('z', Htot, -w/2, w/2, "StripIon"); cmpAmp->AddReadout("StripIon"); sensor->AddElectrode(cmpAmp, "StripIon"); // Set constant magnetic field in [Tesla] cmpDrift->SetMagneticField(MagX, MagY, MagZ); // Set Time window for signal integration, units in [ns] double tMin = 0.; const double tMax = 100.; const double tStep = 0.05; const int nTimeBins = int((tMax - tMin) / tStep); sensor->SetTimeWindow(0., tStep, nTimeBins); double Ttime[nTimeBins]; for (int i = 0; i < nTimeBins; i++) Ttime[i]= i * tStep; //// This canvas will be used to display the drift lines and the field //TCanvas * c = new TCanvas("c", "c", 10, 10, 1000, 700); //c->Divide(2,1); //// Construct object to visualise drift lines //ViewDrift* viewdrift = new ViewDrift(); //viewdrift->SetArea(-0.2, 0.0, -0.1, 0.2, Htot,0.1 ); //viewdrift->SetClusterMarkerSize(0.1); //viewdrift->SetCollisionMarkerSize(0.5); //viewdrift->SetCanvas((TCanvas*)c->cd(1)); //For simulating the electron avalanche we use the class AvalancheMicroscopic AvalancheMicroscopic* aval = new AvalancheMicroscopic(); //const int aval_size = 0.1; aval->SetSensor(sensor); // Switch on signal calculation. aval->EnableSignalCalculation(); aval->SetTimeWindow(tMin,tMax ); //aval->EnableAvalancheSizeLimit(aval_size); //aval->EnablePlotting(viewdrift); aval->EnableDriftLines(); aval->EnableMagneticField(); // Additional optional switches //aval->EnableExcitationMarkers(); //aval->EnableIonisationMarkers(); //Add ionizing particle using Heed // Here we add a negative pion with some momentum, units in [eV/c] TrackHeed* track = new TrackHeed(); track->SetParticle("muon"); track->SetEnergy(particle_energy); track->SetSensor(sensor); track->EnableMagneticField(); track->EnableElectricField(); //track->EnablePlotting(viewdrift); // Cluster info double xcls, ycls, zcls, tcls, e, extra; xcls = ycls = zcls = tcls = e = extra = -999.; // Electron info double xele, yele, zele, tele, eele, dxele, dyele, dzele; // Electron start and endpoints, momentum direction and status double x0ele, y0ele, z0ele, t0ele, e0ele;// start point double x1ele, y1ele, z1ele, t1ele, e1ele;// endpoint double dx1ele, dy1ele, dz1ele; // momentum direction int status1ele; // status int n = 0; // number of electrons in cluster bool cls_ret;// return OK if cluster is OK bool cls_ret2; bool cls_ret3; bool cls_ret4; // The initial impact position of the incoming ionising track double track_x = 0.15;// [cm] double track_y = 0.3; double track_z = 0.0; // Momentum direction of incoming track double track_dx = -0.5; double track_dy = -0.5; // Track coming downstream double track_dz = 0.0; TypeMode mode = MODE_POS_RND_DIR_PERP; switch (mode) { default: case MODE_FIX: { track_x = 0.15; track_y = 0.3; track_z = 0.0; track_dx = -0.5; track_dy = -0.5; track_dz = 0.0; break; } case MODE_POS_RND_DIR_PERP: { double r = ((double) rand() / (RAND_MAX)); track_x = (r-0.5)*2*w; track_y = 0.3; track_z = 0.0; track_dx = 0.0; track_dy = -1.; track_dz = 0.0; std::cout<<"random position for incoming particle; x="<<track_x<<std::endl; break; } case MODE_POS_RND_DIR_RND: { double rr = ((double) rand() / (RAND_MAX)); track_x = (rr-0.5)*2*w; track_y = 0.3; track_z = 0.0; double angle = (((double) rand() / (RAND_MAX)) -0.5 ) * M_PI; track_dx = sin (angle); track_dy = -cos (angle); track_dz = 0.0; std::cout<<"random position for incoming particle; x="<<track_x<<std::endl; std::cout<<"random angle for incoming particle; angle="<<angle/M_PI*180.<<std::endl; break; } } int n_e, n_i; int tot_ncls = 0; double tot_ecls = 0; int tot_n_e_aval = 0, tot_n_i_aval = 0; int q=0; // To accumulate the electron signal for all time for each strip separately double QstripsTot[n_strips_x]; for (int j=0; j<n_strips_x; j++) { QstripsTot[j]=0; } // To accumulate the electron signal for all strip for each time separately double QtimeTot[nTimeBins]; double QtimeIonTot[nTimeBins]; for (int i = 0; i < nTimeBins; i++) { QtimeTot[i] = 0; QtimeIonTot[i] = 0; } int tot_nElastic=0, tot_nIonising=0, tot_nAttachment=0, tot_nInelastic=0, tot_nExcitation=0, tot_nSuperelastic=0; //track->DisableDeltaElectronTransport(); // If electron transport is disabled, the number of electrons // returned by GetCluster is the number of “primary” ionisation // electrons, i. e. the photo-electrons and Auger electrons. // Their kinetic energies and locations are accessible through the // function GetElectron do { // Now create a single track track->NewTrack(track_x, track_y, track_z, tMin, track_dx, track_dy, track_dz); cls_ret = track->GetCluster(xcls, ycls, zcls, tcls, n, e, extra); std::cout<<"ycls="<<ycls<<std::endl; std::cout<<"ncls="<<n<<std::endl; // primary electrons generated in current interaction std::cout<<"ecls="<<e<<std::endl; // transferred energy from particle to electrons tot_ncls += n; // no of primary electrons generated in detector tot_ecls += e; // total energy lost by particle in detector // Now loop over electrons in cluster for(int j = 1; j <= n; j++) { track->GetElectron(j-1, xele, yele, zele, tele, eele, dxele, dyele, dzele); // Simulate an avalanche for the current electron aval->AvalancheElectron(xele, yele, zele, tele, eele, dxele, dyele, dzele); aval->GetAvalancheSize(n_e, n_i); std::cout<<"n_e="<<n_e<<std::endl; // no of electrons generated in current interaction std::cout<<"n_i="<<n_i<<std::endl; // no of ions generated in current interaction tot_n_e_aval += n_e; // no of electrons generated in total tot_n_i_aval += n_i; // no of electrons generated in total } track_x=xcls; track_y=ycls; track_z=zcls; tMin=tcls; int nElastic; int nIonising; int nAttachment; int nInelastic; int nExcitation; int nSuperelastic; gas-> GetNumberOfElectronCollisions(nElastic,nIonising,nAttachment,nInelastic,nExcitation,nSuperelastic); std::cout<<"nElastic="<<nElastic<<std::endl; std::cout<<"nIonising="<<nIonising<<std::endl; std::cout<<"nAttachment="<<nAttachment<<std::endl; std::cout<<"nInelastic="<<nInelastic<<std::endl; std::cout<<"nExcitation="<<nExcitation<<std::endl; std::cout<<"nSuperelastic="<<nSuperelastic<<std::endl; tot_nElastic += nElastic; tot_nIonising += nIonising; tot_nAttachment += nAttachment; tot_nInelastic += nInelastic; tot_nExcitation += nExcitation; tot_nSuperelastic += nSuperelastic; // To get Signal from each strip we get the it from each sensor // by integrating over time for (int j=0; j<n_strips_x; j++) { const char* name = ("Strip"+to_string(j)).c_str(); for(int i = 0; i < nTimeBins; i++) { double value = sensor->GetElectronSignal(name, i); if (std::isnan(value) == false ) { QstripsTot[j] += value; QtimeTot[i] += value; } } } for(int i = 0; i < nTimeBins; i++) { QtimeIonTot[i] += sensor->GetIonSignal("StripIon", i); } //// Sanity check //double sum_q_time = 0; //double sum_q_strip = 0; //for (int j=0; j<n_strips_x; j++) //sum_q_strip += QstripsTot[j]; //for(int i = 0; i < nTimeBins; i++) //sum_q_time += QtimeTot[i]; //if (sum_q_strip != sum_q_time) //{ //cout << "WARNING: sum_q_strip != sum_q_time" << endl; //cout << "sum_q_strip: " << sum_q_strip << endl; //cout << "sum_q_time: " << sum_q_time << endl; //} // Now calculate the reconstructed pion position in the Micromegas // using the weighted average of the Strip signals double x_mean = 0.0; double x_sum_a = 0; double x_sum_b = 0; for (int j=0; j<n_strips_x; j++) { x_sum_a += QstripsTot[j] * Xstrips[j]; x_sum_b += QstripsTot[j]; } x_mean = x_sum_a/x_sum_b; std::cout << "---------------------------" << std::endl; std::cout << "XMean: " << x_mean << " cm, XTrue: " << track_x << " cm" << std::endl; std::cout << "XTrue - XMean: " << fabs(track_x - x_mean)*10000.0 << " um" << std::endl; std::cout << "---------------------------" << std::endl; // Now calculate the reconstructed pion time in the Micromegas // using the weighted average of the Strip signals double t_mean = 0.0; double t_sum_a = 0; double t_sum_b = 0; for (int i=0; i<nTimeBins; i++) { t_sum_a += QtimeTot[i] * Ttime[i]; t_sum_b += QtimeTot[i]; } t_mean = t_sum_a/t_sum_b; std::cout << "---------------------------" << std::endl; std::cout << "TMean: " << x_mean << " ns, TTrue: " << 0 << " ns" << std::endl; std::cout << "TTrue - TMean: " << fabs(0 - t_mean) << " ns" << std::endl; std::cout << "---------------------------" << std::endl; std::cout<<"ycls="<<ycls<<std::endl; if (cls_ret > 0) q++; } while (track_y> 0 && cls_ret > 0); std::cout<<"tot_nElastic="<<tot_nElastic<<std::endl; std::cout<<"tot_nIonising="<<tot_nIonising<<std::endl; std::cout<<"tot_nAttachment="<<tot_nAttachment<<std::endl; std::cout<<"tot_nInelastic="<<tot_nInelastic<<std::endl; std::cout<<"tot_nExcitation="<<tot_nExcitation<<std::endl; std::cout<<"tot_nSuperelastic="<<tot_nSuperelastic<<std::endl; typedef std::numeric_limits< double > dbl; std::ofstream myfile; myfile.open (output_file, std::ios::app ); if (myfile.tellp() <= 10) { myfile << "# pressure, temperature, conc_Ar, conc_CO2, top_voltage, mesh_voltage, bottom_voltage, particle_energy, tot_ncls, tot_ecls, tot_n_e_aval, tot_n_i_aval, tnElastic, tnIonising, tnAttachment, tnInelastic, tnExcitation, tnSuperelastic, nr_interactions,"; for (int j=0; j < n_strips_x; j++) myfile << "QStrip" << j << " (x:" << Xstrips[j] << "),"; for (int i=0; i < nTimeBins; i++) myfile << "QTime" << i << " (t:" << Ttime[i] << "),"; for (int i=0; i < nTimeBins; i++) myfile << "QIon" << i << " (t:" << Ttime[i] << "),"; myfile << endl; } myfile.precision(dbl::max_digits10); myfile // Initial GAS << gas_pressure << " , " << gas_temperature << " , " << conc_ar << " , " << conc_co2 << " , " // voltage << top_voltage << " , " << mesh_voltage << " , " << bottom_voltage << " , " // Initial Particle << particle_energy << " , " // Final state << tot_ncls << " , " << tot_ecls << " , " << tot_n_e_aval << " , " << tot_n_i_aval << " , " << tot_nElastic << " , " << tot_nIonising << " , " << tot_nAttachment << " , " << tot_nInelastic << " , " << tot_nExcitation << " , " << tot_nSuperelastic << " , " << q << " , "; for (int j=0; j<n_strips_x; j++) myfile << QstripsTot[j] << " , " ; for (int i=0; i < nTimeBins; i++) myfile << QtimeTot[i] << " , " ; for (int i=0; i < nTimeBins; i++) myfile << QtimeIonTot[i] << " , " ; myfile << std::endl; myfile.close(); // -- Plotting -- // Now plot the drift lines //viewdrift->Plot(); //// View the Field //ViewField * viewfield = new ViewField(); //viewfield->SetComponent(cmpAmp); //viewfield->SetSensor(sensor); //viewfield->SetCanvas((TCanvas*)c->cd(2)); //viewfield->SetWeightingFieldRange(0.0, 10000.0); //c->cd(2); //viewfield->PlotContour(); //// View the strip signals //TCanvas * c2 = new TCanvas("c2", "c2", 1000, 20, 700, 500); //ViewSignal* signalView = new ViewSignal(); //signalView->SetSensor(sensor); //signalView->SetCanvas(c2); //if(Qstrip1 > 0)signalView->PlotSignal("Strip1"); //if(Qstrip2 > 0)signalView->PlotSignal("Strip2"); //if(Qstrip3 > 0)signalView->PlotSignal("Strip3"); //app.Run(); return 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); }
int main(int argc, char * argv[]){ TApplication app("app", &argc, argv); plottingEngine.SetDefaultStyle(); // Load the Magboltz gas file MediumMagboltz* gas = new MediumMagboltz(); gas->LoadGasFile("ar_90_c4h10_10_B2T_90deg.gas"); // // Structure of Micromegas cell (from top to bottom): //------------------------ // | Drift electrode (Vdrift = -2500 V) // | Drift gap (Hdriftgap = 3 mm) // | Mesh electrode (Vmesh = -500 V) // | Amplification gap (Hampgap = 100 um) // | Strips (Vstrip = 0 V) //------------------------ // // // We place 3 strips in z direction in order to // be able to resolve the avalanche signal. // Strips can be parametrized by width and pitch // // Units given in [cm] const double Hdriftgap = 0.3; // Drift gap height const double Hampgap = 0.01; // Amplification gap height const double Htot = Hdriftgap + Hampgap; // Total height const double Pitch = 0.07; // Pitch const double Interpitch = 0.01; // Distance between two strips const double Wstrip = Pitch - Interpitch; // Electrode potentials const double Vdrift = -3000.; const double Vamp = -500.; const double Vstrip = 0.; // Magnetic field const double MagX = 0.; const double MagY = 0.; const double MagZ = 2.; // Geometry of the structure // Parallel planes, SolidBox, height [cm] // Width [cm] const double w = 3.0; // Length [cm] const double l = 3.0; GeometrySimple* geo = new GeometrySimple(); SolidBox* box = new SolidBox(0.,Htot/2.0, 0., w, Htot/2.0, l); geo->AddSolid(box, gas); // // The Component requires a description of the geometry, that is a list of volumes // and associated media. // Here we construct 2 ComponentAnalyticalFields, to treat the // arift region and the amplification separately // ComponentAnalyticField* cmpDrift = new ComponentAnalyticField(); ComponentAnalyticField* cmpAmp = new ComponentAnalyticField(); // Pass a pointer of the geometry class to the components. cmpDrift->SetGeometry(geo); cmpAmp->SetGeometry(geo); // Now we add the planes for the electrodes with labels cmpDrift->AddPlaneY(Htot, Vdrift, "DriftPlane"); cmpDrift->AddPlaneY(Hampgap, Vamp, "AmpPlane"); cmpAmp->AddPlaneY(Hampgap, Vamp, "AmpPlane"); cmpAmp->AddPlaneY(0.0, Vstrip, "StripPlane"); //Next we construct the Strips for readout of te signal, also with labels double Xoffset = 0.; double Xstrip1, Xstrip2, Xstrip3; // Store the center of the strips Xstrip1 = Xoffset + Wstrip/2.0; cmpAmp->AddStripOnPlaneY('z', 0.0, Xoffset, Xoffset + Wstrip, "Strip1"); Xoffset += (Wstrip + Interpitch); Xstrip2 = Xoffset + Wstrip/2.0; cmpAmp->AddStripOnPlaneY('z', 0.0, Xoffset, Xoffset + Wstrip, "Strip2"); Xoffset += (Wstrip + Interpitch); Xstrip3 = Xoffset + Wstrip/2.0; cmpAmp->AddStripOnPlaneY('z', 0.0, Xoffset, Xoffset + Wstrip, "Strip3"); //We want to calculate the signal induced on the strip. //We have to tell this to the ComponentAnalyticalField cmpAmp->AddReadout("Strip1"); cmpAmp->AddReadout("Strip2"); cmpAmp->AddReadout("Strip3"); // Set constant magnetic field in [Tesla] cmpDrift->SetMagneticField(MagX, MagY, MagZ); //Finally we assemble a Sensor object Sensor* sensor = new Sensor(); // Calculate the electric field using the Component object cmp sensor->AddComponent(cmpDrift); sensor->AddComponent(cmpAmp); // Request signal calculation for the electrode named with labels above, // using the weighting field provided by the Component object cmp. sensor->AddElectrode(cmpAmp, "Strip1"); sensor->AddElectrode(cmpAmp, "Strip2"); sensor->AddElectrode(cmpAmp, "Strip3"); // Set Time window for signal integration, units in [ns] const double tMin = 0.; const double tMax = 100.; const double tStep = 0.05; const int nTimeBins = int((tMax - tMin) / tStep); sensor->SetTimeWindow(0., tStep, nTimeBins); // This canvas will be used to display the drift lines and the field TCanvas * c = new TCanvas("c", "c", 10, 10, 1000, 700); c->Divide(2,1); // Construct object to visualise drift lines ViewDrift* viewdrift = new ViewDrift(); viewdrift->SetArea(0.0, 0.0, -0.1, 0.2, Htot,0.1 ); viewdrift->SetClusterMarkerSize(0.1); viewdrift->SetCollisionMarkerSize(0.5); viewdrift->SetCanvas((TCanvas*)c->cd(1)); //For simulating the electron avalanche we use the class AvalancheMicroscopic AvalancheMicroscopic* aval = new AvalancheMicroscopic(); const int aval_size = 10; aval->SetSensor(sensor); // Switch on signal calculation. aval->EnableSignalCalculation(); aval->SetTimeWindow(tMin,tMax ); // aval->EnableAvalancheSizeLimit(aval_size); aval->EnablePlotting(viewdrift); aval->EnableDriftLines(); aval->EnableMagneticField(); // Additional optional switches //aval->EnableExcitationMarkers(); //aval->EnableIonisationMarkers(); //Add ionizing particle using Heed // Here we add a negative pion with some momentum, units in [eV/c] const double momentum = 300.e+06; // eV/c TrackHeed* track = new TrackHeed(); track->SetParticle("pi-"); track->SetMomentum(momentum); track->SetSensor(sensor); track->EnableMagneticField(); track->EnableElectricField(); track->EnablePlotting(viewdrift); // Cluster info double xcls, ycls, zcls, tcls, e, extra; xcls = ycls = zcls = tcls = e = extra = -999.; // Electron info double xele, yele, zele, tele, eele, dxele, dyele, dzele; // Electron start and endpoints, momentum direction and status double x0ele, y0ele, z0ele, t0ele, e0ele;// start point double x1ele, y1ele, z1ele, t1ele, e1ele;// endpoint double dx1ele, dy1ele, dz1ele; // momentum direction int status1ele; // status int n = 0; // number of electrons in cluster bool cls_ret;// return OK if cluster is OK // The initial impact position of the incoming ionising track double track_x = 0.15;// [cm] double track_y = 0.3; double track_z = 0.0; // Momentum direction of incoming track double track_dx = 0.0; double track_dy = -1.0; // Track coming downstream double track_dz = 0.0; // Now create a single track track->NewTrack(track_x, track_y, track_z, tMin, track_dx, track_dy, track_dz); cls_ret = track->GetCluster(xcls, ycls, zcls, tcls, n, e, extra); // To accumulate the electron signal for each strip separately double Qstrip1 = 0.0; double Qstrip2 = 0.0; double Qstrip3 = 0.0; // Now loop over electrons in cluster for(int j = 1; j <= n; j++){ track->GetElectron(j-1, xele, yele, zele, tele, eele, dxele, dyele, dzele); // Simulate an avalanche for the current electron aval->AvalancheElectron(xele, yele, zele, tele, eele, dxele, dyele, dzele); } // To get Signal from each strip we get the it from each sensor // by integrating over time for(int i = 0; i < nTimeBins; i++){ Qstrip1 += fabs(sensor->GetElectronSignal("Strip1", i)); Qstrip2 += fabs(sensor->GetElectronSignal("Strip2", i)); Qstrip3 += fabs(sensor->GetElectronSignal("Strip3", i)); } // Now calculate the reconstructed pion position in the Micromegas // using the weighted average of the Strip signals double mean = 0.0; mean = (Qstrip1*Xstrip1 + Qstrip2*Xstrip2 + Qstrip3*Xstrip3)/(Qstrip1+Qstrip2+Qstrip3); std::cout << "---------------------------" << std::endl; std::cout << "XMean: " << mean << " cm, XTrue: " << track_x << " cm" << std::endl; std::cout << "XTrue - XMean: " << fabs(track_x - mean)*10000.0 << " um" << std::endl; std::cout << "---------------------------" << std::endl; // -- Plotting -- // Now plot the drift lines viewdrift->Plot(); // View the Field ViewField * viewfield = new ViewField(); viewfield->SetComponent(cmpAmp); viewfield->SetSensor(sensor); viewfield->SetCanvas((TCanvas*)c->cd(2)); viewfield->SetWeightingFieldRange(0.0, 10000.0); c->cd(2); viewfield->PlotContour(); // View the strip signals TCanvas * c2 = new TCanvas("c2", "c2", 1000, 20, 700, 500); ViewSignal* signalView = new ViewSignal(); signalView->SetSensor(sensor); signalView->SetCanvas(c2); if(Qstrip1 > 0)signalView->PlotSignal("Strip1"); if(Qstrip2 > 0)signalView->PlotSignal("Strip2"); if(Qstrip3 > 0)signalView->PlotSignal("Strip3"); app.Run(); 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); }