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