Exemple #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);

}
Exemple #2
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);
  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;

}