MiniballSort
Loading...
Searching...
No Matches
Reaction.cc
Go to the documentation of this file.
1#include "Reaction.hh"
2
5
6
7// Reaction things
8MiniballReaction::MiniballReaction( std::string filename, std::shared_ptr<MiniballSettings> myset ){
9
10 // Read in mass tables
12
13 // Get the info from the user input
14 set = myset;
15 SetFile( filename );
17
18}
19
20void MiniballReaction::AddBindingEnergy( short Ai, short Zi, TString ame_be_str ) {
21
22 // A key for the isotope
23 std::string isotope_key;
24 isotope_key = std::to_string( Ai ) + gElName.at( Zi );
25
26 // Remove # from AME data and replace with decimal point
27 if ( ame_be_str.Contains("#") )
28 ame_be_str.ReplaceAll("#",".");
29
30 // An * means there is no data, fill with a 0
31 if ( ame_be_str.Contains("*") )
32 ame_be.insert( std::make_pair( isotope_key, 0 ) );
33
34 // Otherwise add the real data
35 else
36 ame_be.insert( std::make_pair( isotope_key, ame_be_str.Atof() ) );
37
38 return;
39
40}
41
43
44 // Input data file is in the source code
45 // AME_FILE is passed as a definition at compilation time in Makefile
46 std::ifstream input_file;
47 input_file.open( AME_FILE );
48
49 std::string line, BE_str, N_str, Z_str;
50 std::string startline = "1N-Z";
51
52 short Ai, Zi, Ni;
53
54 // Loop over the file
55 if( input_file.is_open() ){
56
57 // Read first line
58 std::getline( input_file, line );
59
60 // Look for start of data
61 while( line.substr( 0, startline.size() ) != startline ){
62
63 // Read next line, but break if it's the end of the file
64 if( !std::getline( input_file, line ) ){
65
66 std::cout << "Can't read mass tables from ";
67 std::cout << AME_FILE << std::endl;
68 exit(1);
69
70 }
71
72 }
73
74 // Read one more nonsense line with the units on
75 std::getline( input_file, line );
76
77 // Now process the data
78 while( std::getline( input_file, line ) ){
79
80 // Get mass excess from the line
81 N_str = line.substr( 5, 5 );
82 Z_str = line.substr( 9, 5 );
83 BE_str = line.substr( 54, 13 );
84
85 // Get N and Z
86 Ni = std::stoi( N_str );
87 Zi = std::stoi( Z_str );
88 Ai = Ni + Zi;
89
90 // Add mass value
91 AddBindingEnergy( Ai, Zi, BE_str );
92
93 }
94
95 }
96
97 else {
98
99 std::cout << "Mass tables file doesn't exist: " << AME_FILE << std::endl;
100 exit(1);
101
102 }
103
104 return;
105
106}
107
109
110 TEnv *config = new TEnv( fInputFile.data() );
111
112 std::string isotope_key;
113
114 // Get particle properties
115 Beam.SetA( config->GetValue( "BeamA", 185 ) );
116 Beam.SetZ( config->GetValue( "BeamZ", 80 ) );
117 if( Beam.GetZ() < 0 || Beam.GetZ() >= (int)gElName.size() ){
118
119 std::cout << "Not a recognised element with Z = ";
120 std::cout << Beam.GetZ() << " (beam)" << std::endl;
121 exit(1);
122
123 }
125 Beam.SetEx( config->GetValue( "BeamEx", 0. ) );
126
127 Eb = config->GetValue( "BeamE", 4500.0 ); // in keV per nucleon
128 Eb *= Beam.GetMass_u(); // keV
129 Beam.SetEnergy( Eb ); // keV
130
131 Target.SetA( config->GetValue( "TargetA", 120 ) );
132 Target.SetZ( config->GetValue( "TargetZ", 50 ) );
133 Target.SetEnergy( 0.0 );
134 if( Target.GetZ() < 0 || Target.GetZ() >= (int)gElName.size() ){
135
136 std::cout << "Not a recognised element with Z = ";
137 std::cout << Target.GetZ() << " (target)" << std::endl;
138 exit(1);
139
140 }
142 Target.SetEx( config->GetValue( "TargetEx", 0. ) );
143
144 Ejectile.SetA( config->GetValue( "EjectileA", 185 ) );
145 Ejectile.SetZ( config->GetValue( "EjectileZ", 80 ) );
146 if( Ejectile.GetZ() < 0 || Ejectile.GetZ() >= (int)gElName.size() ){
147
148 std::cout << "Not a recognised element with Z = ";
149 std::cout << Ejectile.GetZ() << " (ejectile)" << std::endl;
150 exit(1);
151
152 }
154 Ejectile.SetEx( config->GetValue( "EjectileEx", 500. ) );
155
156 Recoil.SetA( config->GetValue( "RecoilA", 120 ) );
157 Recoil.SetZ( config->GetValue( "RecoilZ", 50 ) );
158 if( Recoil.GetZ() < 0 || Recoil.GetZ() >= (int)gElName.size() ){
159
160 std::cout << "Not a recognised element with Z = ";
161 std::cout << Recoil.GetZ() << " (recoil)" << std::endl;
162 exit(1);
163
164 }
166 Recoil.SetEx( config->GetValue( "RecoilEx", 0. ) );
167
168 // Get particle energy cut
169 ejectilecutfile = config->GetValue( "EjectileCut.File", "NULL" );
170 ejectilecutname = config->GetValue( "EjectileCut.Name", "CUTG" );
171 recoilcutfile = config->GetValue( "RecoilCut.File", "NULL" );
172 recoilcutname = config->GetValue( "RecoilCut.Name", "CUTG" );
173 transfercutfile = config->GetValue( "TransferCut.File", "NULL" );
174 transfercutname = config->GetValue( "TransferCut.Name", "CUTG" );
175 transfercut_x = config->GetValue( "TransferCut.X", "E" );
176 transfercut_y = config->GetValue( "TransferCut.Y", "dE" );
177
178 // Check if ejectile/recoil/transfer cuts are given by the user
182
183 // Velocity calculation for Doppler correction
184 doppler_mode = config->GetValue( "DopplerMode", 1 );
185
186 // Laser mode
187 laser_mode = config->GetValue( "LaserMode", 2 );
188
189 // EBIS time window
190 EBIS_On = config->GetValue( "EBIS.On", 1.2e6 ); // normally 1.2 ms in slow extraction
191 EBIS_Off = config->GetValue( "EBIS.Off", 2.52e7 ); // this allows a off window 20 times bigger than on
192 EBIS_ratio = config->GetValue( "EBIS.FillRatio", GetEBISTimeRatio() ); // this is the measured ratio of EBIS On/off. Default is just the time window ratio
193
194 // T1 cuts
195 t1_cut = config->GetValue( "T1.Cut", false ); // enable or disable the T1 cuts
196 t1_time[0] = config->GetValue( "T1.Min", 0.0 ); // minimum T1 time for cut (ns), default 0
197 t1_time[1] = config->GetValue( "T1.Max", 1.2e9 ); // maximum T1 time for cut (ns), default 1.2 seconds
198
199 // Events tree options
200 events_particle_gamma = config->GetValue( "Events.ParticleGammaOnly", false ); // only do histogramming for particle-gamma coincidences to speed things up
201 events_particle_cdpad_coinc = config->GetValue( "Events.CdPadCoincidence", false ); // only do histogramming for particles with CD-Pad coincidences
202 events_particle_cdpad_veto = config->GetValue( "Events.CdPadVeto", false ); // only do histogramming for particles without CD-Pad coincidences (Pad as veto)
203 events_gamma_seg_energy = config->GetValue( "Events.GammaUseSegmentEnergy", false ); // use the segment energy instead of the core energy for gamma-rays
204 events_gamma_demand_seg = config->GetValue( "Events.GammaWithSegment", false ); // only do histogramming for gamma-rays that have a segment, i.e. reject core-only gammas
205 events_gamma_max_seg_mult = config->GetValue( "Events.GammaMaxSegmentMultiplicity", 99 ); // only do histogramming for gamma-rays with a maximum segment multiplicity (all segments of a cluster = 18)
206 events_gamma_seg_ediff = config->GetValue( "Events.GammaCoreSegmentEnergyDifference", 9.9e9 ); // only do histogramming for gamma-rays where the core and sgement energies are less than this
207
208 // Histogram options
209 hist_wo_addback = config->GetValue( "Histograms.WithoutAddback", true ); // turn on histograms for gamma-rays without addback
210 hist_w_addback = config->GetValue( "Histograms.WithAddback", false ); // turn on histograms for gamma-rays with addback
211 hist_segment_phi = config->GetValue( "Histograms.SegmentPhi", false ); // turn on histograms for segment phi
212 hist_by_crystal = config->GetValue( "Histograms.ByCrystal", false ); // turn on histograms for gamma-gamma
213 hist_by_pmult = config->GetValue( "Histograms.ByMultiplicity", false ); // turn on particle-gamma(-electron) spectra by multiplicity, i.e. 1p and 2p spectra
214 hist_by_sector = config->GetValue( "Histograms.BySector", false ); // turn on sector-by-sector histograms for particles
215 hist_by_t1 = config->GetValue( "Histograms.ByT1", false ); // turn on histograms as a function of T1
216 hist_gamma_gamma = config->GetValue( "Histograms.GammaGamma", true ); // turn on histograms for gamma-gamma
217 hist_electron = config->GetValue( "Histograms.Electron", false ); // turn on histograms for electrons
218 hist_electron_gamma = config->GetValue( "Histograms.ElectronGamma", false ); // turn on histograms for electron-gamma
219 hist_beam_dump = config->GetValue( "Histograms.BeamDump", true ); // turn on histograms for beam dump
220 hist_ion_chamb = config->GetValue( "Histograms.IonChamber", false ); // turn on histograms for ionisation chamber
221
222 // Histogram ranges - gammas and electrons
223 gamma_bins = config->GetValue( "Histograms.Gamma.Bins", 6000 ); // number of bins in gamma-ray spectra
224 gamma_range[0] = config->GetValue( "Histograms.Gamma.Min", -0.5 ); // lower energy limit of gamma-ray spectra (keV)
225 gamma_range[1] = config->GetValue( "Histograms.Gamma.Max", 5999.5 ); // upper energy limit of gamma-ray spectra (keV)
226 electron_bins = config->GetValue( "Histograms.Electron.Bins", 2000 ); // number of bins in electron spectra
227 electron_range[0] = config->GetValue( "Histograms.Electron.Min", -0.5 ); // lower energy limit of electron spectra (keV)
228 electron_range[1] = config->GetValue( "Histograms.Electron.Max", 1999.5 ); // upper energy limit of electron spectra (keV)
229
230 // Histogram ranges - particles
231 double pmax_default = 2.0e6;
232 if( Beam.GetIsotope() != Ejectile.GetIsotope() ) {
233 if( Recoil.GetA() <= 12 ) pmax_default = 200e3;
234 else if( Beam.GetEnergy() < 100e3 ) pmax_default = 200e3;
235 else if( Beam.GetEnergy() < 200e3 ) pmax_default = 400e3;
236 else if( Beam.GetEnergy() < 400e3 ) pmax_default = 800e3;
237 else if( Beam.GetEnergy() < 800e3 ) pmax_default = 1600e3;
238 }
239 else {
240 if( Beam.GetEnergy() < 100e3 ) pmax_default = 200e3;
241 else if( Beam.GetEnergy() < 200e3 ) pmax_default = 400e3;
242 else if( Beam.GetEnergy() < 400e3 ) pmax_default = 800e3;
243 else if( Beam.GetEnergy() < 800e3 ) pmax_default = 1600e3;
244 else if( Beam.GetEnergy() > 2000e3 ) pmax_default = 4000e3;
245 }
246 particle_bins = config->GetValue( "Histograms.Particle.Bins", 2000 ); // number of bins in particle spectra
247 particle_range[0] = config->GetValue( "Histograms.Particle.Min", 0.0 ); // lower energy limit of particle spectra (keV)
248 particle_range[1] = config->GetValue( "Histograms.Particle.Max", pmax_default ); // upper energy limit of particle spectra (keV)
249
250 // Particle-Gamma time windows
251 pg_prompt[0] = config->GetValue( "ParticleGamma_PromptTime.Min", -300 ); // lower limit for particle-gamma prompt time difference
252 pg_prompt[1] = config->GetValue( "ParticleGamma_PromptTime.Max", 300 ); // upper limit for particle-gamma prompt time difference
253 pg_random[0] = config->GetValue( "ParticleGamma_RandomTime.Min", 600 ); // lower limit for particle-gamma random time difference
254 pg_random[1] = config->GetValue( "ParticleGamma_RandomTime.Max", 1200 ); // upper limit for particle-gamma random time difference
255 gg_prompt[0] = config->GetValue( "GammaGamma_PromptTime.Min", -250 ); // lower limit for gamma-gamma prompt time difference
256 gg_prompt[1] = config->GetValue( "GammaGamma_PromptTime.Max", 250 ); // upper limit for gamma-gamma prompt time difference
257 gg_random[0] = config->GetValue( "GammaGamma_RandomTime.Min", 500 ); // lower limit for gamma-gamma random time difference
258 gg_random[1] = config->GetValue( "GammaGamma_RandomTime.Max", 1000 ); // upper limit for gamma-gamma random time difference
259 pp_prompt[0] = config->GetValue( "ParticleParticle_PromptTime.Min", -200 ); // lower limit for particle-particle prompt time difference
260 pp_prompt[1] = config->GetValue( "ParticleParticle_PromptTime.Max", 200 ); // upper limit for particle-particle prompt time difference
261 pp_random[0] = config->GetValue( "ParticleParticle_RandomTime.Min", 400 ); // lower limit for particle-particle random time difference
262 pp_random[1] = config->GetValue( "ParticleParticle_RandomTime.Max", 800 ); // upper limit for particle-particle random time difference
263 ee_prompt[0] = config->GetValue( "ElectronElectron_PromptTime.Min", -200 ); // lower limit for electron-electron prompt time difference
264 ee_prompt[1] = config->GetValue( "ElectronElectron_PromptTime.Max", 200 ); // upper limit for electron-electron prompt time difference
265 ee_random[0] = config->GetValue( "ElectronElectron_RandomTime.Min", 400 ); // lower limit for electron-electron random time difference
266 ee_random[1] = config->GetValue( "ElectronElectron_RandomTime.Max", 800 ); // upper limit for electron-electron random time difference
267 ge_prompt[0] = config->GetValue( "GammaElectron_PromptTime.Min", -200 ); // lower limit for gamma-electron prompt time difference
268 ge_prompt[1] = config->GetValue( "GammaElectron_PromptTime.Max", 200 ); // upper limit for gamma-electron prompt time difference
269 ge_random[0] = config->GetValue( "GammaElectron_RandomTime.Min", 400 ); // lower limit for gamma-electron random time difference
270 ge_random[1] = config->GetValue( "GammaElectron_RandomTime.Max", 800 ); // upper limit for gamma-electron random time difference
271 pe_prompt[0] = config->GetValue( "ParticleElectron_PromptTime.Min", -200 ); // lower limit for particle-electron prompt time difference
272 pe_prompt[1] = config->GetValue( "ParticleElectron_PromptTime.Max", 200 ); // upper limit for particle-electron prompt time difference
273 pe_random[0] = config->GetValue( "ParticleElectron_RandomTime.Min", 400 ); // lower limit for particle-electron random time difference
274 pe_random[1] = config->GetValue( "ParticleElectron_RandomTime.Max", 800 ); // upper limit for particle-electron random time difference
275
276 // Particle-Gamma fill ratios
277 pg_ratio = config->GetValue( "ParticleGamma_FillRatio", GetParticleGammaTimeRatio() );
278 gg_ratio = config->GetValue( "GammaGamma_FillRatio", GetGammaGammaTimeRatio() );
279 pp_ratio = config->GetValue( "ParticleParticle_FillRatio", GetParticleParticleTimeRatio() );
280 ee_ratio = config->GetValue( "ElectronElectron_FillRatio", GetElectronElectronTimeRatio() );
281 ge_ratio = config->GetValue( "GammaElectron_FillRatio", GetGammaElectronTimeRatio() );
282 pe_ratio = config->GetValue( "ParticleElectron_FillRatio", GetParticleElectronTimeRatio() );
283
284 // Detector to target distances
285 cd_dist.resize( set->GetNumberOfCDDetectors() );
286 cd_offset.resize( set->GetNumberOfCDDetectors() );
287 dead_layer.resize( set->GetNumberOfCDDetectors() );
288 double d_tmp = 0;
289 for( unsigned int i = 0; i < set->GetNumberOfCDDetectors(); ++i ) {
290
291 if( i == 0 ) d_tmp = 32.0; // standard CD
292 else if( i == 1 ) d_tmp = -64.0; // TREX backwards CD
293 cd_dist[i] = config->GetValue( Form( "CD_%d.Distance", i ), d_tmp ); // distance to target in mm
294 cd_offset[i] = config->GetValue( Form( "CD_%d.PhiOffset", i ), 0.0 ); // phi rotation in degrees
295 dead_layer[i] = config->GetValue( Form( "CD_%d.DeadLayer", i ), 0.0007 ); // dead layer thickness in mm of Si
296
297 }
298
299 // Target thickness and offsets
300 target_thickness = config->GetValue( "TargetThickness", 2.0 ); // units of mg/cm^2
301 x_offset = config->GetValue( "TargetOffset.X", 0.0 ); // of course this should be 0.0 if you centre the beam! Units of mm, vertical
302 y_offset = config->GetValue( "TargetOffset.Y", 0.0 ); // of course this should be 0.0 if you centre the beam! Units of mm, horizontal
303 z_offset = config->GetValue( "TargetOffset.Z", 0.0 ); // of course this should be 0.0 if you centre the beam! Units of mm, lateral
304
305 // Degrader thickness and material
306 degrader_thickness = config->GetValue( "DegraderThickness", -1.0 ); // units of mg/cm^2 - negative means it doesn't exist (only plunger runs)
307 std::string degrader_material_tmp = config->GetValue( "DegraderMaterial", "197Au" ); // can be isotope name or other material name that matches SRIM file
308 for( unsigned int i = 0; i < degrader_material_tmp.length(); i++ ){
309 if( std::isspace( degrader_material_tmp[i] ) || degrader_material_tmp[i] == '#' )
310 break;
311 else degrader_material += degrader_material_tmp[i];
312 }
313
314 // Read in Miniball geometry
315 mb_type = config->GetValue( "MiniballGeometry.Type", 1 ); // default = 1
316 mb_geo.resize( set->GetNumberOfMiniballClusters() );
317 mb_theta.resize( set->GetNumberOfMiniballClusters() );
318 mb_phi.resize( set->GetNumberOfMiniballClusters() );
319 mb_alpha.resize( set->GetNumberOfMiniballClusters() );
320 mb_r.resize( set->GetNumberOfMiniballClusters() );
321 for( unsigned int i = 0; i < set->GetNumberOfMiniballClusters(); ++i ) {
322
323 mb_theta[i] = config->GetValue( Form( "MiniballCluster_%d.Theta", i ), 0. );
324 mb_phi[i] = config->GetValue( Form( "MiniballCluster_%d.Phi", i ), 0. );
325 mb_alpha[i] = config->GetValue( Form( "MiniballCluster_%d.Alpha", i ), 0. );
326 mb_r[i] = config->GetValue( Form( "MiniballCluster_%d.R", i ), 0. );
327
328 mb_geo[i].SetGeometryType( mb_type );
329 mb_geo[i].SetupCluster( mb_theta[i], mb_phi[i], mb_alpha[i], mb_r[i], z_offset );
330
331 }
332
333 // Read in SPEDE geometry
334 spede_dist = config->GetValue( "Spede.Distance", -30.0 ); // distance to target in mm, it's negative because it's in the backwards direction
335 spede_offset = config->GetValue( "Spede.PhiOffset", 0.0 ); // phi rotation in degrees
336 if( spede_dist > 0 ) std::cout << " !! WARNING !! Spede.Distance should be negative" << std::endl;
337
338 // Get the stopping powers
339 stopping = true;
340 for( unsigned int i = 0; i < 7; ++i )
341 gStopping.push_back( std::make_unique<TGraph>() );
347 if( degrader_thickness > 0 ) {
350 }
351
352
353 // Some diagnostics and info
354 std::cout << std::endl << " +++ ";
355 std::cout << Target.GetIsotope() << "(" << Beam.GetIsotope() << ",";
356 std::cout << Ejectile.GetIsotope() << ")" << Recoil.GetIsotope();
357 std::cout << " +++" << std::endl;
358 std::cout << "Q-value = " << GetQvalue()*0.001 << " MeV" << std::endl;
359 std::cout << "Incoming beam energy = ";
360 std::cout << Beam.GetEnergy()*0.001 << " MeV" << std::endl;
361 std::cout << "Target thickness = ";
362 std::cout << target_thickness << " mg/cm^2" << std::endl;
363
364 // Calculate the energy loss
365 if( stopping ){
366
367 double eloss = GetEnergyLoss( Beam.GetEnergy(), 0.5 * target_thickness, gStopping[0] );
368 Beam.SetEnergy( Beam.GetEnergy() - eloss );
369 std::cout << "Beam energy at centre of target = ";
370 std::cout << Beam.GetEnergy()*0.001 << " MeV" << std::endl;
371
372 }
373 else std::cout << "Stopping powers not calculated" << std::endl;
374
375 std::cout << "Beam velocity at reaction position = ";
376 std::cout << Beam.GetBeta() << "c" << std::endl;
377
378 if( degrader_thickness > 0 ) {
379
380 std::cout << "A " << degrader_material << " degrader of " << degrader_thickness;
381 std::cout << " mg/cm2 has been included. Doppler correction will be performed";
382 if( doppler_mode == 0 || doppler_mode == 1 || doppler_mode == 5 )
383 std::cout << " BEFORE the degrader";
384 else if( doppler_mode == 2 || doppler_mode == 3 || doppler_mode == 4 )
385 std::cout << " AFTER the degrader";
386 else
387 std::cout << " with unknown DopplerMode = " << doppler_mode;
388 std::cout << std::endl;
389
390 }
391
392 // Finished
393 delete config;
394
395}
396
397void MiniballReaction::PrintReaction( std::ostream &stream, std::string opt = "" ) {
398
399 // Check options (not yet implemented)
400 if( opt.length() > 0 )
401 stream << "# The following print options were used: " << opt << std::endl;
402
403 // Loop over clusters
404 for( unsigned int i = 0; i < set->GetNumberOfMiniballClusters(); ++i ) {
405
406 stream << Form( "MiniballCluster_%d.Theta: %f", i, GetMiniballTheta(i) * TMath::RadToDeg() ) << std::endl;
407 stream << Form( "MiniballCluster_%d.Phi: %f", i, GetMiniballPhi(i) * TMath::RadToDeg() ) << std::endl;
408 stream << Form( "MiniballCluster_%d.Alpha: %f", i, GetMiniballAlpha(i) * TMath::RadToDeg() ) << std::endl;
409 stream << Form( "MiniballCluster_%d.R: %f", i, GetMiniballR(i) ) << std::endl;
410
411 }
412
413}
414
418std::shared_ptr<TCutG> MiniballReaction::ReadCutFile( std::string cut_filename, std::string cut_name ) {
419
420 std::shared_ptr<TCutG> cut;
421
422 // Check if filename is given in the settings file.
423 if( cut_filename != "NULL" ) {
424
425 TFile *cut_file = new TFile( cut_filename.data(), "READ" );
426 if( cut_file->IsZombie() )
427 std::cout << "Couldn't open " << cut_filename << " correctly" << std::endl;
428
429 else {
430
431 if( !cut_file->GetListOfKeys()->Contains( cut_name.data() ) )
432 std::cout << "Couldn't find " << cut_name << " in "
433 << cut_filename << std::endl;
434 else
435 cut = std::make_shared<TCutG>( *static_cast<TCutG*>( cut_file->Get( cut_name.data() )->Clone() ) );
436
437 }
438
439 cut_file->Close();
440
441 }
442
443 // Assign an empty cut file if none is given, so the code doesn't crash
444 if( !cut ) cut = std::make_shared<TCutG>();
445
446 return cut;
447
448}
449
450
451TVector3 MiniballReaction::GetCDVector( unsigned char det, unsigned char sec, float pid, float nid ){
452
453 // Check that we have a real CD detector
454 if( det >= set->GetNumberOfCDDetectors() ) {
455
456 std::cerr << "Bad CD Detector requested = " << det << std::endl;
457 det = 0;
458
459 }
460
461 // Create a TVector3 to handle the angles
462 TVector3 vec( 0, 0, cd_dist[det] ); // set z now
463
464 // Get the phi rotation of the quadrant
465 float phi = 90.0 * sec;
466 phi += cd_offset[det]; // left edge of first strip
467
468 // Recalculate this points for the standard CD (not yet done for CREX/TREX)
469 if( set->GetNumberOfCDNStrips() == 12 || set->GetNumberOfCDNStrips() == 24 ) { // standard CD
470
471 // CD phi calculation using method from Tim Gray
472 double alpha = 82.0;
473 double offset_x = 1.6728;
474 double offset_y = 1.5751;
475 double grouping = 24.0 / (double)set->GetNumberOfCDNStrips();
476
477 double phi_body = grouping * ( nid + 0.5 ) * alpha / 24.;
478
479 double r_lab = 9.0;
480 r_lab += ( 15.5 - pid ) * 2.0; // pid = 0 is outer ring and pid = 15 is inner ring
481
482 double beta = 180.0 - TMath::ATan(offset_y/offset_x) * TMath::RadToDeg();
483 double bphi = beta + phi_body;
484 if( bphi > 180.0) bphi = 360.0 - bphi;
485
486 double r_d = TMath::Sqrt( offset_x * offset_x + offset_y * offset_y ); // from center of rings to center of sectors
487 double delta = TMath::ASin( r_d * TMath::Sin( bphi * TMath::DegToRad() ) / r_lab );
488 delta *= TMath::RadToDeg(); // angle between r_body and r_lab
489
490 double gamma = 180.0 - bphi - delta; // angle between r_d and r_lab
491
492 double r_body;
493 if (TMath::Abs(TMath::Sin( bphi * TMath::DegToRad() ) < 1e-5)) r_body = r_lab - r_d;
494 else r_body = TMath::Sin( gamma * TMath::DegToRad() ) / ( TMath::Sin( bphi * TMath::DegToRad() ) / r_lab ); // between sector center and point of interest
495
496 double x_body = r_body * TMath::Cos( phi_body * TMath::DegToRad() ); //in sector "body" coordinates
497 double y_body = r_body * TMath::Sin( phi_body * TMath::DegToRad() );
498
499 //transform back to ring "lab" coordinates
500 double y = y_body + offset_y;
501 double x = x_body + offset_x;
502
503 //should have sqrt(x*x + y*y) = r_lab at this point
504 vec.SetX(x);
505 vec.SetY(y);
506
507 /*
508 // New definition of CD segments - Konstantin Stoychev
510 //float initial_offset = 0.000286 * TMath::Power(pid,4);
511 //initial_offset += -0.00541 * TMath::Power(pid,3);
512 //initial_offset += 0.04437 * TMath::Power(pid,2);
513 //initial_offset += 0.01679 * pid;
514 //initial_offset += 2.4137;
515
517 //double phi_coverage = -0.00625 * TMath::Power(pid,3);
518 //phi_coverage += 0.07056 * TMath::Power(pid,2);
519 //phi_coverage += -0.54542 * pid;
520 //phi_coverage += 77.66278; // parametrization from Konstantin Stoychev
521
522 //float pixel_width = phi_coverage / 12.;
523
524 //phi += initial_offset;
525 //phi += pixel_width / 2.;
526 //phi += nid * pixel_width;
527 */
528
529 /*
530 // Old definition of CD segments
531 //phi += 3.5; // move the centre of first strip to zero degrees
532 //phi += nid * 7.0;
533 */
534
535 }
536
537 else if( set->GetNumberOfCDNStrips() == 16 ) { // CREX and TREX
538
539 // Inner ring starts at 9.0 mm
540 float x = 9.0;
541
542 // Each strip centre is 2.0 mm apart
543 x += ( pid + 0.5 ) * 2.0;
544 vec.SetX(x);
545
546 // Then find phi angle for each n-side strip
547 phi += 1.75; // centre of first strip
548 if( nid < 4 ) phi += nid * 3.5; // first 4 strips singles (=4 nid)
549 else if( nid < 12 ) phi += 14. + ( nid - 4 ) * 7.0; // middle 16 strips doubles (=8 nids)
550 else phi += 70. + ( nid - 12 ) * 3.5; // last 4 strips singles (=4 nid)
551
552 }
553
554 // Rotate to the correct phi angle
555 vec.RotateZ( phi * TMath::DegToRad() );
556
557 return vec;
558
559}
560
561TVector3 MiniballReaction::GetParticleVector( unsigned char det, unsigned char sec, unsigned char pid, unsigned char nid ){
562
563 // Create a TVector3 to handle the angles
564 TVector3 vec = GetCDVector( det, sec, pid, nid );
565
566 // Apply the X and Y offsets directly to the TVector3 input
567 // We move the CD opposite to the target, which replicates the same
568 // geometrical shift that is observed with respect to the beam
569 vec.SetX( vec.X() - x_offset );
570 vec.SetY( vec.Y() - y_offset );
571
572 //std::cout << "sec:pid:nid = " << (int)sec << ":" << (int)pid << ":" << (int)nid << std::endl;
573 //std::cout << "\ttheta,phi = " << vec.Theta() * TMath::RadToDeg();
574 //std::cout << ", " << vec.Phi() * TMath::RadToDeg() << std::endl;
575
576 return vec;
577
578}
579
580TVector3 MiniballReaction::GetSpedeVector( unsigned char seg, bool random ){
581
582 // Calculate the vertical distance from axis
583 float x = 10.0; // inner radius = 10.0 mm
584 float mult = 0.5; // go to the centre of each ring
585 if( random ) mult = rand.Rndm(); // go to a random point along each ring
586 if( seg < 8 ) x += 5.15 * mult; // width of first ring = 5.2 mm including 0.05 mm inter-strip region
587 else if( seg < 16 ) x += 5.2 + 3.85 * mult; // width of second ring = 3.9 mm including 0.05 mm inter-strip region
588 else if( seg < 24 ) x += 9.1 + 3.15 * mult; // width of third ring = 3.2 mm
589
590 // Create a TVector3 to handle the angles
591 TVector3 vec( x, 0, spede_dist );
592
593 // Rotate appropriately
594 if( random ) mult = rand.Rndm(); // get a new random point for the phi angle
595 float phi = (float)(seg%8) * TMath::Pi() / 4.0; // rotate every 8 slices
596 phi += 0.98 * mult * TMath::Pi() / 4.0; // rotate by half of one slice or random part thereof
597 phi += 0.01 * TMath::Pi() / 4.0; // add a small slice for the interstrip region
598
599 // Account for zero-degree offset
600 phi += spede_offset * TMath::DegToRad();
601
602 vec.RotateZ( phi );
603
604 return vec;
605
606}
607
608TVector3 MiniballReaction::GetElectronVector( unsigned char seg ){
609
610 // Create a TVector3 to handle the angles
611 TVector3 vec = GetSpedeVector( seg );
612
613 // Apply the X and Y offsets directly to the TVector3 input
614 // We move the CD opposite to the target, which replicates the same
615 // geometrical shift that is observed with respect to the beam
616 vec.SetX( vec.X() - x_offset );
617 vec.SetY( vec.Y() - y_offset );
618
619 return vec;
620
621}
622
623double MiniballReaction::CosTheta( std::shared_ptr<GammaRayEvt> g, bool ejectile ) {
624
628 if( ejectile ) p = Ejectile;
629 else p = Recoil;
630
631 TVector3 gvec = mb_geo[g->GetCluster()].GetSegVector( g->GetCrystal(), g->GetSegment() );
632
633 // Apply the X and Y offsets directly to the TVector3 input
634 // We move Miniball opposite to the target, which replicates the same
635 // geometrical shift that is observed with respect to the beam
636 // z-offset is already applied to the vector when the geometry is setup
637 gvec.SetX( gvec.X() - x_offset );
638 gvec.SetY( gvec.Y() - y_offset );
639
640 return TMath::Cos( gvec.Angle( p.GetVector() ) );
641
642}
643
644double MiniballReaction::CosTheta( std::shared_ptr<SpedeEvt> s, bool ejectile ) {
645
649 if( ejectile ) p = Ejectile;
650 else p = Recoil;
651
652 TVector3 evec = GetElectronVector( s->GetSegment() );
653
654 return TMath::Cos( evec.Angle( p.GetVector() ) );
655
656}
657
658double MiniballReaction::DopplerShift( double gen, double pbeta, double costheta ) {
659
661 double gamma = 1.0 / TMath::Sqrt( 1.0 - TMath::Power( pbeta, 2.0 ) );
662 double corr = 1.0 - pbeta * costheta;
663 corr *= gamma;
664
665 return gen / corr;
666
667}
668
669double MiniballReaction::DopplerCorrection( double gen, double gtheta, double gphi, double pbeta, double ptheta, double pphi ) {
670
672 TVector3 gvec = TVector3( 0., 0., 1.0 );
673 gvec.SetTheta( gtheta );
674 gvec.SetPhi( gphi);
675
676 // Apply the X and Y offsets directly to the TVector3 input
677 // We move Miniball opposite to the target, which replicates the same
678 // geometrical shift that is observed with respect to the beam
679 // z-offset is already applied to the vector when the geometry is setup
680 gvec.SetX( gvec.X() - x_offset );
681 gvec.SetY( gvec.Y() - y_offset );
682
683 // Setup the particle vector, no shifts becuase theta,phi explicitly given
684 TVector3 pvec( 0., 0., 1.0 );
685 pvec.SetTheta( ptheta );
686 pvec.SetPhi( pphi );
687
688 double gamma = 1.0 / TMath::Sqrt( 1.0 - TMath::Power( pbeta, 2.0 ) );
689 double corr = 1.0 - pbeta * TMath::Cos( gvec.Angle( pvec ) );
690 corr *= gamma;
691
692 return corr * gen;
693
694}
695
696double MiniballReaction::DopplerCorrection( double gen, double gtheta, double gphi, bool ejectile ) {
697
699 TVector3 gvec = TVector3( 0., 0., 1.0 );
700 gvec.SetTheta( gtheta );
701 gvec.SetPhi( gphi);
702
703 // Apply the X and Y offsets directly to the TVector3 input
704 // We move Miniball opposite to the target, which replicates the same
705 // geometrical shift that is observed with respect to the beam
706 // z-offset is already applied to the vector when the geometry is setup
707 gvec.SetX( gvec.X() - x_offset );
708 gvec.SetY( gvec.Y() - y_offset );
709
713 if( ejectile ) p = Ejectile;
714 else p = Recoil;
715
716 double costheta = TMath::Cos( gvec.Angle( p.GetVector() ) );
717 double corr = 1.0 - p.GetBeta() * costheta;
718 corr *= p.GetGamma();
719
720 return corr * gen;
721
722}
723
724double MiniballReaction::DopplerCorrection( std::shared_ptr<GammaRayEvt> g, double pbeta, double ptheta, double pphi ) {
725
727 TVector3 gvec = mb_geo[g->GetCluster()].GetSegVector( g->GetCrystal(), g->GetSegment() );
728
729 // Apply the X and Y offsets directly to the TVector3 input
730 // We move Miniball opposite to the target, which replicates the same
731 // geometrical shift that is observed with respect to the beam
732 // z-offset is already applied to the vector when the geometry is setup
733 gvec.SetX( gvec.X() - x_offset );
734 gvec.SetY( gvec.Y() - y_offset );
735
736 // Setup the particle vector, no shifts becuase theta,phi explicitly given
737 TVector3 pvec( 0., 0., 1.0 );
738 pvec.SetTheta( ptheta );
739 pvec.SetPhi( pphi );
740
741 double gamma = 1.0 / TMath::Sqrt( 1.0 - TMath::Power( pbeta, 2.0 ) );
742 double corr = 1.0 - pbeta * TMath::Cos( gvec.Angle( pvec ) );
743 corr *= gamma;
744
746 return corr * g->GetSegmentSumEnergy();
747 else
748 return corr * g->GetEnergy();
749
750}
751
752double MiniballReaction::DopplerCorrection( std::shared_ptr<GammaRayEvt> g, bool ejectile ) {
753
757 if( ejectile ) p = Ejectile;
758 else p = Recoil;
759
760 double corr = 1.0 - p.GetBeta() * CosTheta( g, ejectile );
761 corr *= p.GetGamma();
762
764 return corr * g->GetSegmentSumEnergy();
765 else
766 return corr * g->GetEnergy();
767
768}
769
770double MiniballReaction::DopplerCorrection( std::shared_ptr<SpedeEvt> s, bool ejectile ) {
771
775 if( ejectile ) p = Ejectile;
776 else p = Recoil;
777
778 // Joonas version
779 double corr=((s->GetEnergy() + e_mass - p.GetBeta() * CosTheta( s, ejectile ) *
780 TMath::Sqrt(s->GetEnergy() * s->GetEnergy() + 2.0 * e_mass * s->GetEnergy())) /
781 TMath::Sqrt(1.0 - p.GetBeta() * p.GetBeta())) - e_mass;
782 return corr;
783
784 // Liam version
785 //double corr = TMath::Power( s->GetEnergy(), 2.0 );
786 //corr += 2.0 * e_mass * s->GetEnergy();
787 //corr = TMath::Sqrt( corr );
788 //corr *= s->GetEnergy() + e_mass - p.GetBeta() * CosTheta( s, ejectile );
789 //corr *= p.GetGamma();
790 //corr -= e_mass;
791
792 //return corr;
793
794}
795
796void MiniballReaction::IdentifyEjectile( std::shared_ptr<ParticleEvt> p, bool kinflag ){
797
800 double En = p->GetEnergy(), Eemit = En;
801 double eloss = 0.0;
802 if( stopping && ( doppler_mode == 3 || doppler_mode == 5 ) ) {
803
804 double eff_thick = dead_layer[p->GetDetector()] / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) );
805 eloss = GetEnergyLoss( En, -1.0 * eff_thick, gStopping[3] ); // ejectile in dead layer
806 En -= eloss;
807 Eemit = En;
808
809 // Correction for degrader, so we get energy after target
810 if( ( doppler_mode == 3 || doppler_mode == 5 ) && degrader_thickness > 0 ) {
811
812 eff_thick = degrader_thickness / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) );
813 eloss = GetEnergyLoss( En, -1.0 * eff_thick, gStopping[5] ); // ejectile in degrader
814 En -= eloss;
815 if( doppler_mode == 5 ) Eemit = En;
816 }
817
818 }
819
820 // Correction for energy loss in second half of target, so we get energy in the centre of the target
821 if( stopping && ( doppler_mode == 2 || doppler_mode == 3 || doppler_mode == 5 ) ) {
822 double eff_thick = target_thickness / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) );
823 eloss = GetEnergyLoss( En, -0.5 * eff_thick, gStopping[1] ); // ejectile in target
824 En -= eloss;
825 }
826
827 // Here, En is the energy at the centre of the target needed for the kinematic
828 // calculation, while Eemit is the energy at the point where the gamma ray was
829 // emitted (in the CD for mode 2, between degrader and CD for mode 5 and between
830 // target and degrader for mode 3.
831
832 // Set observables
833 Ejectile.SetEnergy( En ); // eloss is negative
836
837 // Calculate the centre of mass angle
838 // TODO: Replace with the full relativisic kinematics
839 double maxang = TMath::ASin( 1. / ( GetTau() * GetEpsilon() ) );
840 double y = GetEpsilon() * GetTau();
841 if( GetTau() * GetEpsilon() > 1 && GetParticleTheta(p) > maxang )
842 y *= TMath::Sin( maxang );
843 else
844 y *= TMath::Sin( GetParticleTheta(p) );
845
846 // Only one solution for the beam in normal kinematics, kinflag = false
847 if( kinflag && GetTau() * GetEpsilon() < 1 ) kinflag = false;
848
849 if( kinflag ) y = TMath::ASin( -y );
850 else y = TMath::ASin( y );
851
853
854 ejectile_detected = true;
855
856 // Now restore the energy to the value at the point of gamma-ray emission
857 Ejectile.SetEnergy(Eemit);
858
859 // Overwrite energy with kinematics if requested
860 if( doppler_mode == 0 || doppler_mode == 1 || doppler_mode == 4 ) {
861
862 // Energy of the ejectile from the centre of mass angle
863 // TODO: Replace with the full relativisic kinematics
864 double En = TMath::Power( GetTau() * GetEpsilon(), 2.0 ) + 1.0;
865 En += 2.0 * GetTau() * GetEpsilon() * TMath::Cos( Ejectile.GetThetaCoM() );
866 En *= TMath::Power( Recoil.GetMass() / ( Recoil.GetMass() + Ejectile.GetMass() ), 2.0 );
867 En *= GetEnergyPrime();
868
869 // Do energy loss out the back of target if requested
870 if( stopping && ( doppler_mode == 1 || doppler_mode == 4 ) ) {
871
872 eloss = GetEnergyLoss( En, 0.5 * target_thickness / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) ), gStopping[0] );
873 En -= eloss;
874
875 }
876
877 // Do energy loss through the full degrader if requested
878 if( stopping && doppler_mode == 4 && degrader_thickness > 0 ) {
879
880 eloss = GetEnergyLoss( En, degrader_thickness / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) ), gStopping[5] );
881 En -= eloss;
882
883 }
884
885 // Finally set the energy
886 Ejectile.SetEnergy( En );
887
888 }
889
890 //std::cout << "Theta = " << GetParticleTheta(p)*TMath::RadToDeg() << ": Energy = " << p->GetEnergy();
891 //std::cout << ", Eloss = " << eloss << ", beta = " << Ejectile.GetBeta() << std::endl;
892
893}
894
895void MiniballReaction::IdentifyRecoil( std::shared_ptr<ParticleEvt> p, bool kinflag ){
896
899 double En = p->GetEnergy(), Eemit = En;
900 double eloss = 0.0;
901 if( stopping && ( doppler_mode == 3 || doppler_mode == 5 ) ) {
902
903 double eff_thick = dead_layer[p->GetDetector()] / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) );
904 eloss = GetEnergyLoss( En, -1.0 * eff_thick, gStopping[4] ); // recoil in dead layer
905 En -= eloss;
906 Eemit = En;
907
908 // Correction for degrader, so we get energy after target
909 if( doppler_mode == 5 && degrader_thickness > 0 ) {
910
911 eff_thick = degrader_thickness / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) );
912 eloss = GetEnergyLoss( En, -1.0 * eff_thick, gStopping[6] ); // recoil in degrader
913 En -= eloss;
914 if( doppler_mode == 5 ) Eemit = En;
915 }
916
917 }
918
919 // Correction for energy loss in second half of target, so we get energy in the centre of the target
920 if( stopping && ( doppler_mode == 2 || doppler_mode == 3 || doppler_mode == 5 ) ) {
921 double eff_thick = target_thickness / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) );
922 eloss = GetEnergyLoss( En, -0.5 * eff_thick, gStopping[2] ); // recoil in target
923 En -= eloss;
924 }
925
926 // Set observables
927 Recoil.SetEnergy( En ); // eloss is negative to add back the dead layer energy
930
931 // Calculate the centre of mass angle
932 double maxang = TMath::ASin( 1. / GetEpsilon() );
933 double y = GetEpsilon();
934 if( GetParticleTheta(p) > maxang )
935 y *= TMath::Sin( maxang );
936 else
937 y *= TMath::Sin( GetParticleTheta(p) );
938
939 if( kinflag ) y = TMath::ASin( -y );
940 else y = TMath::ASin( y );
941
943 recoil_detected = true;
944
945 // Now restore the energy to the value at the point of gamma-ray emission
946 Recoil.SetEnergy(Eemit);
947
948 // Overwrite energy with kinematics if requested
949 if( doppler_mode == 0 || doppler_mode == 1 || doppler_mode == 4 ) {
950
951 // Energy of the recoil from the centre of mass angle
952 En = TMath::Power( GetEpsilon(), 2.0 ) + 1.0;
953 En += 2.0 * GetEpsilon() * TMath::Cos( Recoil.GetThetaCoM() );
954 En *= Recoil.GetMass() * Ejectile.GetMass() / TMath::Power( Recoil.GetMass() + Ejectile.GetMass(), 2.0 );
955 En *= GetEnergyPrime();
956
957 // Do energy loss out the back of target if requested
958 if( stopping && ( doppler_mode == 1 || doppler_mode == 4 ) ) {
959
960 eloss = GetEnergyLoss( En, 0.5 * target_thickness / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) ), gStopping[2] );
961 En -= eloss;
962
963 }
964
965 // Do energy loss through the full degrader if requested
966 if( stopping && doppler_mode == 4 && degrader_thickness > 0 ) {
967
968 eloss = GetEnergyLoss( En, degrader_thickness / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) ), gStopping[6] );
969 En -= eloss;
970
971 }
972
973 // Finally set the energy
974 Recoil.SetEnergy( En );
975
976 }
977
978}
979
981
983 // Assume that the centre of mass angle is defined by the recoil
984 Ejectile.SetThetaCoM( TMath::Pi() - Recoil.GetThetaCoM() );
985
986 // Energy of the ejectile from the centre of mass angle
987 double En = TMath::Power( GetTau() * GetEpsilon(), 2.0 ) + 1.0;
988 En += 2.0 * GetTau() * GetEpsilon() * TMath::Cos( Ejectile.GetThetaCoM() );
989 En *= TMath::Power( Recoil.GetMass() / ( Recoil.GetMass() + Ejectile.GetMass() ), 2.0 );
990 En *= GetEnergyPrime();
991
992 // Angle from the centre of mass angle
993 // y = tan(theta_lab)
994 double y = TMath::Sin( Ejectile.GetThetaCoM() );
995 y /= TMath::Cos( Ejectile.GetThetaCoM() ) + GetTau() * GetEpsilon();
996
997 double Th = TMath::ATan(y);
998 if( Th < 0. ) Th += TMath::Pi();
999
1000 // Do energy loss out the back of target if requested
1001 double eloss = 0.0;
1002 if( stopping && doppler_mode > 0 ) {
1003
1004 eloss = GetEnergyLoss( En, 0.5 * target_thickness / TMath::Abs( TMath::Cos(Th) ), gStopping[1] );
1005 En -= eloss;
1006
1007 // Do energy loss through the full degrader if requested
1008 if( ( doppler_mode == 3 || doppler_mode == 4 ) && degrader_thickness > 0 ) {
1009
1010 eloss = GetEnergyLoss( En, degrader_thickness / TMath::Abs( TMath::Cos(Th) ), gStopping[5] );
1011 En -= eloss;
1012
1013 }
1014
1015 }
1016
1017 // Set observables
1018 Ejectile.SetEnergy( En );
1019 Ejectile.SetTheta( Th );
1020 Ejectile.SetPhi( TMath::Pi() + Recoil.GetPhi() );
1021 ejectile_detected = false;
1022
1023}
1024
1026
1028 // Assume that the centre of mass angle is defined by the ejectile
1029 Recoil.SetThetaCoM( TMath::Pi() - Ejectile.GetThetaCoM() );
1030
1031 // Energy of the recoil from the centre of mass angle
1032 double En = TMath::Power( GetEpsilon(), 2.0 ) + 1.0;
1033 En += 2.0 * GetEpsilon() * TMath::Cos( Recoil.GetThetaCoM() );
1034 En *= Recoil.GetMass() * Ejectile.GetMass() / TMath::Power( Recoil.GetMass() + Ejectile.GetMass(), 2.0 );
1035 En *= GetEnergyPrime();
1036
1037 // Angle from the centre of mass angle
1038 // y = tan(theta_lab)
1039 double y = TMath::Sin( Recoil.GetThetaCoM() );
1040 y /= TMath::Cos( Recoil.GetThetaCoM() ) + GetEpsilon();
1041
1042 double Th = TMath::ATan(y);
1043 if( Th < 0. ) Th += TMath::Pi();
1044
1045 // Do energy loss out the back of target if requested
1046 double eloss = 0.0;
1047 if( stopping && doppler_mode > 0 ) {
1048
1049 eloss = GetEnergyLoss( En, 0.5 * target_thickness / TMath::Abs( TMath::Cos(Th) ), gStopping[2] );
1050 En -= eloss;
1051
1052 // Do energy loss through the full degrader if requested
1053 if( ( doppler_mode == 3 || doppler_mode == 4 ) && degrader_thickness > 0 ) {
1054
1055 eloss = GetEnergyLoss( En, degrader_thickness / TMath::Abs( TMath::Cos(Th) ), gStopping[6] );
1056 En -= eloss;
1057
1058 }
1059
1060 }
1061
1062 // Set observables
1063 Recoil.SetEnergy( En );
1064 Recoil.SetTheta( Th );
1065 Recoil.SetPhi( TMath::Pi() + Ejectile.GetPhi() );
1066 recoil_detected = false;
1067
1068}
1069
1070void MiniballReaction::TransferProduct( std::shared_ptr<ParticleEvt> p, bool /* kinflag */ ){
1071
1074
1075 //this assumes the reaction product is emitted at the centre of the target
1076 double En = p->GetEnergy(); //get energy of the reaction product
1077 double eloss = 0.0;
1078 double after_target_recoil_energy = p->GetEnergy();
1079 double after_degrader_recoil_energy = p->GetEnergy();
1080
1081 // Correcting energy loss in CD dead layer
1082 if( stopping && ( doppler_mode == 3 || doppler_mode == 5 ) ) {
1083 double eff_thick = dead_layer[p->GetDetector()] / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) );
1084 eloss = GetEnergyLoss( En, -1.0 * eff_thick, gStopping[4] ); // recoil in dead layer
1085 En -= eloss;
1086 after_target_recoil_energy = En;
1087 after_degrader_recoil_energy = En;
1088 }
1089
1090 // Correction for energy loss in the degrader
1091 if( stopping && degrader_thickness > 0 ) {
1092 double eff_thick = degrader_thickness / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) );
1093 eloss = GetEnergyLoss( En, -1.0 * eff_thick, gStopping[6] ); // recoil in degrader
1094 En -= eloss;
1095 after_target_recoil_energy = En;
1096 }
1097
1098 // Correction for energy loss through half of the target material
1099 if( stopping ) {
1100 double eff_thick = 0.5 * target_thickness / TMath::Abs( TMath::Cos( GetParticleTheta(p) ) );
1101 eloss = GetEnergyLoss( En, -1.0 * eff_thick, gStopping[2] ); // recoil in target
1102 En -= eloss;
1103 }
1104
1105 // Set observables
1106 Recoil.SetEnergy( En );
1109
1110 // Kinematics calculations assuming this energy
1111 double p4x = Recoil.GetMomentum() * TMath::Cos(Recoil.GetTheta());
1112 double p4y = Recoil.GetMomentum() * TMath::Sin(Recoil.GetTheta());
1113 double p3x = Beam.GetMomentum() - p4x;
1114 double p3y = p4y;
1115 double theta3 = TMath::ATan2(p3y, p3x);
1116 //double E3 = GetEnergyTotLab() - Recoil.GetEnergyTot();
1117 double E3 = Beam.GetEnergyTot() + Target.GetEnergyTot() - Recoil.GetEnergyTot(); // Total energy of ejectile
1118
1119 // Kinetic energy at the reaction position in the centre of the target
1120 double beam_kinetic_energy = E3 - Ejectile.GetMass();
1121
1122 // Calculate the centre-of-mass energy and angle
1123 // Vili's version
1124 double E3_CoM = GetGammaCoM()*(E3 - GetBetaCoM() * p3x);
1125 double p3x_CoM = GetGammaCoM()*(p3x - GetBetaCoM() * E3);
1126 double p3y_CoM = p3y;
1127 // double p_CoM = TMath::Sqrt(TMath::Power(p3x_CoM, 2.0) + TMath::Power(p3y_CoM, 2.0));
1128 double theta3_CoM = TMath::ATan2(p3y_CoM, p3x_CoM);
1129
1130 // Lets check E4_CoM also with lorentz transfrom
1131 //double E4_CoM = Recoil.GetEnergyTotCM(); This is only calculated from projectile = target -> bad
1132 double E4_CoM = GetGammaCoM()*(Recoil.GetEnergyTot() - GetBetaCoM() * p4x);
1133// double p4x_CoM = GetGammaCoM()*(p4x - GetBetaCoM() * Recoil.GetEnergyTot());
1134// double p4y_CoM = p4y;
1135// double theta4_CoM = TMath::ATan2(p4y_CoM, p4x_CoM);
1136
1137 Ejectile.SetEnergyCoM(E3_CoM - Ejectile.GetMass() ); // Energy of the ejectile in CoM frame
1138 Ejectile.SetThetaCoM(theta3_CoM); // theta of ejectile in CoM frame in radians
1139 Recoil.SetEnergyCoM(E4_CoM - Recoil.GetMass()); // Set Recoil energy in CoM
1140 Recoil.SetThetaCoM( TMath::Pi() - theta3_CoM ); // theta of recoil in CoM frame in radians
1141
1142 // Calculate the ejectile stopping
1143 if( stopping && doppler_mode > 0 ) {
1144
1145 double eff_thick = 0.5 * target_thickness / TMath::Abs( TMath::Cos(theta3) );
1146 eloss = GetEnergyLoss( beam_kinetic_energy, eff_thick, gStopping[1] );
1147 beam_kinetic_energy -= eloss;
1148
1149 // Do energy loss through the full degrader if requested
1151
1152 eff_thick = degrader_thickness / TMath::Abs( TMath::Cos(theta3) );
1153 eloss = GetEnergyLoss( beam_kinetic_energy, eff_thick, gStopping[5] );
1154 beam_kinetic_energy -= eloss;
1155
1156 }
1157
1158 }
1159
1160 // Set the ejectile energy
1161 Ejectile.SetEnergy( beam_kinetic_energy ); // Kinetic energy of ejectile
1162 Ejectile.SetTheta( theta3 ); // Calculates ejectile theta angle from recoil information
1163 Ejectile.SetPhi( TMath::Pi() + Recoil.GetPhi() );
1164
1165 // Calculate also the energy loss of the recoil as requested
1166 if( doppler_mode == 2 )
1167 Recoil.SetEnergy( p->GetEnergy() );
1168 else if( doppler_mode == 1 || doppler_mode == 3 )
1169 Recoil.SetEnergy( after_target_recoil_energy );
1170 else if( doppler_mode == 4 )
1171 Recoil.SetEnergy( after_degrader_recoil_energy );
1172
1173 // Flag that we have a transfer product
1174 transfer_detected = true;
1175
1176 return;
1177
1178}
1179
1180
1181
1182double MiniballReaction::GetEnergyLoss( double Ei, double dist, std::unique_ptr<TGraph> &g ) {
1183
1187 unsigned int Nmeshpoints = 50; // number of steps to take in integration
1188 double dx = dist/(double)Nmeshpoints;
1189 double E = Ei;
1190
1191 for( unsigned int i = 0; i < Nmeshpoints; i++ ){
1192
1193 double Eloss = g->Eval(E) * dx;
1194 if( Eloss > E ) {
1195 E = 0.01;
1196 break;
1197 }
1198 else
1199 E -= Eloss;
1200
1201 }
1202
1203 return Ei - E;
1204
1205}
1206
1207bool MiniballReaction::ReadStoppingPowers( std::string isotope1, std::string isotope2, std::unique_ptr<TGraph> &g ) {
1208
1209 // Convert deuterium to CD2, and others
1210 if( isotope2 == "1H" ) isotope2 = "CH2";
1211 if( isotope2 == "2H" ) isotope2 = "CD2";
1212 if( isotope2 == "3H" ) isotope2 = "Ti";
1213
1215 std::string title = "Stopping powers for ";
1216 title += isotope1 + " in " + isotope2;
1217 title += ";" + isotope1 + " energy [keV];";
1218 title += "Energy loss in " + isotope2;
1219 if( isotope2 == "Si" ) title += " [keV/mm]";
1220 else title += " [keV/(mg/cm^{2})]";
1221
1222 // Initialise an empty TGraph
1223 g->SetTitle( title.c_str() );
1224
1225 // Keep things quiet from ROOT
1226 gErrorIgnoreLevel = kWarning;
1227
1228 // Open the data file
1229 // SRIM_DIR is defined at compilation and is in source code
1230 std::string srimfilename = std::string( SRIM_DIR ) + "/";
1231 srimfilename += isotope1 + "_" + isotope2 + ".txt";
1232
1233 std::ifstream input_file;
1234 input_file.open( srimfilename, std::ios::in );
1235
1236 // If it fails to open print an error
1237 if( !input_file.is_open() ) {
1238
1239 std::cerr << "Cannot open " << srimfilename << std::endl;
1240 return false;
1241
1242 }
1243
1244
1245 std::string line, units, tmp_str;
1246 std::stringstream line_ss;
1247 double En, nucl, elec, total, tmp_dbl;
1248
1249 // Test file format
1250 std::getline( input_file, line );
1251 if( line.substr( 3, 5 ) == "=====" ) {
1252
1253 // Advance
1254 while( std::getline( input_file, line ) && !input_file.eof() ) {
1255
1256 // Skip over the really short lines
1257 if( line.length() < 10 ) continue;
1258
1259 // Check for the start of the data
1260 if( line.substr( 3, 5 ) == "-----" ) break;
1261
1262 }
1263
1264 }
1265 else {
1266
1267 std::cerr << "Not a srim file: " << srimfilename << std::endl;
1268 return false;
1269
1270 }
1271
1272 // Read in the data
1273 while( std::getline( input_file, line ) && !input_file.eof() ) {
1274
1275 // Skip over the really short lines
1276 if( line.length() < 10 ) continue;
1277
1278 // Read in data
1279 line_ss.str("");
1280 line_ss << line;
1281 line_ss >> En >> units >> nucl >> elec >> tmp_dbl >> tmp_str >> tmp_dbl >> tmp_str;
1282
1283 if( units == "eV" ) En *= 1E-3;
1284 else if( units == "keV" ) En *= 1E0;
1285 else if( units == "MeV" ) En *= 1E3;
1286 else if( units == "GeV" ) En *= 1E6;
1287
1288 total = nucl + elec ; // in some units, conversion done later
1289
1290 // If we've reached the end, stop
1291 if( line.substr( 3, 9 ) == "---------" ) break;
1292
1293 g->SetPoint( g->GetN(), En, total );
1294
1295 }
1296
1297 // Get next line and check there are conversion factors
1298 std::getline( input_file, line );
1299 if( line.substr( 0, 9 ) != " Multiply" ){
1300
1301 std::cerr << "Couldn't get conversion factors from ";
1302 std::cerr << srimfilename << std::endl;
1303 return false;
1304
1305 }
1306 std::getline( input_file, line ); // next line is just ------
1307
1308 // Get conversion factors
1309 double conv, conv_keVum, conv_MeVmgcm2;
1310 std::getline( input_file, line ); // first conversion is eV / Angstrom
1311 std::getline( input_file, line ); // keV / micron
1312 conv_keVum = std::stod( line.substr( 0, 15 ) );
1313 std::getline( input_file, line ); // MeV / mm
1314 std::getline( input_file, line ); // keV / (ug/cm2)
1315 std::getline( input_file, line ); // MeV / (mg/cm2)
1316 conv_MeVmgcm2 = std::stod( line.substr( 0, 15 ) );
1317
1318 // Now convert all the points in the plot
1319 if( isotope2 == "Si" ) conv = conv_keVum * 1E3; // silicon thickness in mm, energy in keV
1320 else conv = conv_MeVmgcm2 * 1E3; // target thickness in mg/cm2, energy in keV
1321 for( Int_t i = 0; i < g->GetN(); ++i ){
1322
1323 g->GetPoint( i, En, total );
1324 g->SetPoint( i, En, total*conv );
1325
1326 }
1327 g->Sort();
1328
1329 // Draw the plot and save it somewhere
1330 TCanvas *c = new TCanvas();
1331 c->SetLogx();
1332 //c->SetLogy();
1333 g->Draw("A*");
1334 std::string pdfname = srimfilename.substr( 0, srimfilename.find_last_of(".") ) + ".pdf";
1335 c->SaveAs( pdfname.c_str() );
1336
1337 delete c;
1338 input_file.close();
1339
1340 // ROOT can be noisey again
1341 gErrorIgnoreLevel = kInfo;
1342
1343 return true;
1344
1345}
ClassImp(MiniballParticle) ClassImp(MiniballReaction) MiniballReaction
Definition Reaction.cc:3
#define SRIM_DIR
Definition Reaction.hh:46
const std::vector< std::string > gElName
Definition Reaction.hh:55
const double e_mass
mass of the electron in keV/c^2
Definition Reaction.hh:52
#define AME_FILE
Definition Reaction.hh:43
TVector3 GetVector()
Definition Reaction.hh:117
void SetBindingEnergy(double myBE)
Definition Reaction.hh:133
double GetEnergy()
Definition Reaction.hh:111
void SetTheta(double mytheta)
Definition Reaction.hh:137
double GetMomentum()
Definition Reaction.hh:123
void SetPhi(double myphi)
Definition Reaction.hh:139
double GetTheta()
Definition Reaction.hh:114
double GetEnergyTot()
Definition Reaction.hh:98
void SetThetaCoM(double mytheta)
Definition Reaction.hh:138
double GetMass()
Definition Reaction.hh:84
void SetEx(double myEx)
Definition Reaction.hh:136
double GetThetaCoM()
Definition Reaction.hh:115
void SetZ(int myZ)
Definition Reaction.hh:132
double GetMass_u()
Definition Reaction.hh:81
double GetGamma()
Definition Reaction.hh:105
double GetPhi()
Definition Reaction.hh:116
void SetEnergy(double myElab)
Definition Reaction.hh:134
void SetA(int myA)
Definition Reaction.hh:131
double GetBeta()
Definition Reaction.hh:99
std::string GetIsotope()
Definition Reaction.hh:94
void SetEnergyCoM(double myECoM)
Definition Reaction.hh:135
std::vector< double > cd_dist
distance from target to CD detector in mm
Definition Reaction.hh:618
TVector3 GetCDVector(unsigned char det, unsigned char sec, float pid, float nid)
Definition Reaction.cc:451
std::vector< double > mb_r
Definition Reaction.hh:624
double GetEBISTimeRatio()
Definition Reaction.hh:384
TVector3 GetElectronVector(unsigned char seg)
Definition Reaction.cc:608
double GetParticleElectronTimeRatio()
Definition Reaction.hh:484
double GetEnergyPrime()
Definition Reaction.hh:362
double EBIS_On
beam on max time in ns
Definition Reaction.hh:583
std::string transfercutname
Definition Reaction.hh:676
double spede_offset
phi rotation of the SPEDE detector
Definition Reaction.hh:629
double GetMiniballAlpha(unsigned char clu)
Definition Reaction.hh:265
double y_offset
vertical offset of the target/beam position, with respect to the CD and Miniball in mm
Definition Reaction.hh:610
double GetTau()
Definition Reaction.hh:359
MiniballParticle Ejectile
Definition Reaction.hh:573
std::vector< double > mb_alpha
Definition Reaction.hh:624
void IdentifyRecoil(std::shared_ptr< ParticleEvt > p, bool kinflag=false)
Definition Reaction.cc:895
std::vector< std::unique_ptr< TGraph > > gStopping
Definition Reaction.hh:684
double x_offset
horizontal offset of the target/beam position, with respect to the CD and Miniball in mm
Definition Reaction.hh:609
int pe_prompt[2]
particle-electron prompt
Definition Reaction.hh:602
std::shared_ptr< TCutG > recoil_cut
Definition Reaction.hh:680
std::vector< double > mb_theta
Definition Reaction.hh:624
std::string ejectilecutfile
Definition Reaction.hh:674
TVector3 GetSpedeVector(unsigned char seg, bool random=false)
Definition Reaction.cc:580
int pp_prompt[2]
particle-particle prompt
Definition Reaction.hh:596
double events_gamma_seg_ediff
Definition Reaction.hh:650
std::string degrader_material
can be an isotope name, or some string that matches the material used and corresponding SRIM file
Definition Reaction.hh:615
ClassDef(MiniballReaction, 3) private std::shared_ptr< MiniballSettings > set
Definition Reaction.hh:560
int gg_random[2]
gamma-gamma random
Definition Reaction.hh:595
double GetBetaCoM()
Definition Reaction.hh:350
double EBIS_Off
beam off max time in ns
Definition Reaction.hh:584
std::string transfercutfile
Definition Reaction.hh:676
void ReadReaction()
Definition Reaction.cc:108
void SetFile(std::string filename)
Definition Reaction.hh:176
double GetParticleGammaTimeRatio()
Definition Reaction.hh:404
std::shared_ptr< TCutG > ejectile_cut
Definition Reaction.hh:679
double DopplerCorrection(double gen, double gth, double gph, double pbeta, double ptheta, double pphi)
Definition Reaction.cc:669
unsigned int events_gamma_max_seg_mult
Definition Reaction.hh:649
double z_offset
lateral offset of the target/beam position, with respect to the only Miniball in mm (cd_dist is indep...
Definition Reaction.hh:611
void PrintReaction(std::ostream &stream, std::string opt)
Definition Reaction.cc:397
int gg_prompt[2]
gamma-gamma prompt
Definition Reaction.hh:594
double Eb
laboratory beam energy in keV/u
Definition Reaction.hh:580
bool events_gamma_seg_energy
Definition Reaction.hh:647
std::string ejectilecutname
Definition Reaction.hh:674
double GetMiniballTheta(unsigned char clu)
Definition Reaction.hh:259
double GetGammaCoM()
Definition Reaction.hh:356
void AddBindingEnergy(short Ai, short Zi, TString ame_be_str)
Definition Reaction.cc:20
unsigned int particle_bins
Definition Reaction.hh:667
int ge_prompt[2]
gamma-electron prompt
Definition Reaction.hh:598
MiniballReaction(std::string filename, std::shared_ptr< MiniballSettings > myset)
std::vector< double > mb_phi
Definition Reaction.hh:624
std::string transfercut_x
Definition Reaction.hh:677
std::string recoilcutname
Definition Reaction.hh:675
std::vector< MiniballGeometry > mb_geo
Definition Reaction.hh:623
double GetParticleTheta(unsigned char det, unsigned char sec, unsigned char pid, unsigned char nid)
Definition Reaction.hh:218
MiniballParticle Beam
Definition Reaction.hh:573
double EBIS_ratio
ratio of ebis on/off as measured
Definition Reaction.hh:585
double ee_ratio
fill ratios
Definition Reaction.hh:605
double t1_time[2]
event time - T1 cut window
Definition Reaction.hh:589
double gamma_range[2]
Definition Reaction.hh:668
double target_thickness
target thickness in units of mg/cm^2
Definition Reaction.hh:608
std::shared_ptr< TCutG > transfer_cut
Definition Reaction.hh:681
std::string transfercut_y
Definition Reaction.hh:677
bool events_particle_gamma
Definition Reaction.hh:644
int pe_random[2]
particle-electron random
Definition Reaction.hh:603
MiniballParticle Target
Definition Reaction.hh:573
TVector3 GetParticleVector(unsigned char det, unsigned char sec, unsigned char pid, unsigned char nid)
Definition Reaction.cc:561
MiniballParticle Recoil
Definition Reaction.hh:573
double GetGammaElectronTimeRatio()
Definition Reaction.hh:452
double degrader_thickness
target thickness in units of mg/cm^2. Negative if degrader not present. SHM, RAB 12 June 2025
Definition Reaction.hh:614
std::vector< double > cd_offset
phi rotation of the CD in degrees
Definition Reaction.hh:619
void ReadMassTables()
Definition Reaction.cc:42
double CosTheta(std::shared_ptr< GammaRayEvt > g, bool ejectile)
Definition Reaction.cc:623
unsigned int electron_bins
Definition Reaction.hh:667
bool hist_electron_gamma
Definition Reaction.hh:662
bool ReadStoppingPowers(std::string isotope1, std::string isotope2, std::unique_ptr< TGraph > &g)
Definition Reaction.cc:1207
double GetMiniballR(unsigned char clu)
Definition Reaction.hh:268
double GetMiniballPhi(unsigned char clu)
Definition Reaction.hh:262
int pg_prompt[2]
particle-gamma prompt
Definition Reaction.hh:592
void TransferProduct(std::shared_ptr< ParticleEvt > p, bool kinflag=false)
Definition Reaction.cc:1070
double GetGammaGammaTimeRatio()
Definition Reaction.hh:420
double GetEpsilon()
Definition Reaction.hh:365
int ee_random[2]
electron-electron random
Definition Reaction.hh:601
double electron_range[2]
Definition Reaction.hh:668
double pp_ratio
fill ratios
Definition Reaction.hh:604
int ge_random[2]
gamma-electron random
Definition Reaction.hh:599
double spede_dist
distance from target to SPEDE detector
Definition Reaction.hh:628
bool events_particle_cdpad_coinc
Definition Reaction.hh:645
void CalculateRecoil()
Definition Reaction.cc:1025
void IdentifyEjectile(std::shared_ptr< ParticleEvt > p, bool kinflag=false)
Definition Reaction.cc:796
unsigned int gamma_bins
Definition Reaction.hh:667
double GetQvalue()
Definition Reaction.hh:333
double GetElectronElectronTimeRatio()
Definition Reaction.hh:468
double GetParticlePhi(unsigned char det, unsigned char sec, unsigned char pid, unsigned char nid)
Definition Reaction.hh:221
unsigned char doppler_mode
Definition Reaction.hh:631
void CalculateEjectile()
Definition Reaction.cc:980
std::shared_ptr< TCutG > ReadCutFile(std::string cut_filename, std::string cut_name)
Definition Reaction.cc:418
bool events_gamma_demand_seg
Definition Reaction.hh:648
double GetEnergyLoss(double Ei, double dist, std::unique_ptr< TGraph > &g)
Definition Reaction.cc:1182
unsigned char mb_type
Definition Reaction.hh:625
double GetParticleParticleTimeRatio()
Definition Reaction.hh:436
std::vector< double > dead_layer
dead layer thickness in mm
Definition Reaction.hh:620
double particle_range[2]
Definition Reaction.hh:668
std::map< std::string, double > ame_be
List of biniding energies from AME2021.
Definition Reaction.hh:570
std::string recoilcutfile
Definition Reaction.hh:675
int pp_random[2]
particle-particle random
Definition Reaction.hh:597
bool t1_cut
enable/disable T1 cuts on data
Definition Reaction.hh:588
unsigned char laser_mode
Definition Reaction.hh:640
int ee_prompt[2]
electron-electron prompt
Definition Reaction.hh:600
int pg_random[2]
particle-gamma random
Definition Reaction.hh:593
double DopplerShift(double gen, double pbeta, double costheta)
Definition Reaction.cc:658
bool events_particle_cdpad_veto
Definition Reaction.hh:646
std::shared_ptr< MiniballSettings > myset
Definition mb_sort.cc:123