LDMX Software
simcore::APrimeConversionToFCPs Class Reference

Discrete process for A' -> fcp+ fcp- conversion in a nuclear field. More...

#include <APrimeConversionToFCPs.h>

Public Member Functions

 APrimeConversionToFCPs (const G4String &processName="APrimeToFCPPair", G4ProcessType type=fElectromagnetic)
 Constructor.
 
 ~APrimeConversionToFCPs ()=default
 Destructor Just the default one.
 
G4bool IsApplicable (const G4ParticleDefinition &particle) override
 Check if this process applies to the given particle.
 
void BuildPhysicsTable (const G4ParticleDefinition &p) override
 Build physics table (called during initialization).
 
void printInfoDefinition ()
 Print process information.
 
void setCrossSecFactor (G4double fac)
 Set a factor to artificially scale the cross section.
 
G4double getCrossSecFactor () const
 
G4double GetMeanFreePath (const G4Track &aTrack, G4double previousStepSize, G4ForceCondition *condition) override
 Return the mean free path of the A' in the current material.
 
G4double getCrossSectionPerAtom (const G4DynamicParticle *aDynamicAPrime, const G4Element *anElement)
 Return the total cross section per atom.
 
G4VParticleChange * PostStepDoIt (const G4Track &aTrack, const G4Step &aStep) override
 Generate the final state: A' -> fcp+ fcp-.
 
G4double computeCrossSectionPerAtom (G4double APrimeEnergy, G4int Z)
 Compute the cross section per atom for the given A' energy and Z.
 
G4double computeMeanFreePath (G4double APrimeEnergy, const G4Material *aMaterial)
 Compute the mean free path for the given energy and material.
 
 APrimeConversionToFCPs (const APrimeConversionToFCPs &)=delete
 
APrimeConversionToFCPsoperator= (const APrimeConversionToFCPs &)=delete
 

Static Public Attributes

static const std::string PROCESS_NAME = "APrimeToFCPPair"
 The name of this process.
 

Private Member Functions

const G4Element * selectRandomAtom (const G4DynamicParticle *aDynamicAPrime, const G4Material *aMaterial)
 Select a random atom from the material, weighted by cross section.
 
 enableLogging ("APrimeConversionToFCPs")
 Enable logging for this class.
 

Private Attributes

G4double mfcp_
 fcp mass
 
G4double rc_
 Coupling-scaled reduced Compton wavelength: q^2 * elm_coupling / Mfcp.
 
G4double limit_energy_
 Energy limit for accurate cross section (5 * Mfcp)
 
G4double lowest_energy_limit_
 Absolute low energy limit of the model (2 * Mfcp)
 
G4double highest_energy_limit_
 High energy limit of the model.
 
G4double cross_sec_factor_ = 1.0
 Factor to artificially scale the cross section.
 
const G4ParticleDefinition * the_a_prime_
 Pointer to the A' particle definition.
 
const G4ParticleDefinition * the_fcp_minus_
 Pointer to fcp- definition.
 
const G4ParticleDefinition * the_fcp_plus_
 Pointer to fcp+ definition.
 
std::vector< G4double > temp_
 Temporary vector for element selection.
 

Detailed Description

Discrete process for A' -> fcp+ fcp- conversion in a nuclear field.

This process is the dark-sector analogue of G4GammaConversionToMuons (gamma -> mu+ mu-). A practically massless dark photon (A') converts into a pair of massive fractionally charged particles (fcp+ fcp-) in the electromagnetic field of a nucleus.

Definition at line 31 of file APrimeConversionToFCPs.h.

Constructor & Destructor Documentation

◆ APrimeConversionToFCPs()

simcore::APrimeConversionToFCPs::APrimeConversionToFCPs ( const G4String & processName = "APrimeToFCPPair",
G4ProcessType type = fElectromagnetic )
explicit

Constructor.

Parameters
[in]processNamename of this process (default: "APrimeToFCPPair")
[in]typeGeant4 process type

Definition at line 24 of file APrimeConversionToFCPs.cxx.

26 : G4VDiscreteProcess(processName, type) {
27 // Get the fcp particle definitions
28 auto* fcp_minus = G4FractionallyCharged::FractionallyCharged();
29 mfcp_ = fcp_minus->GetPDGMass();
30
31 // Get fcp charge magnitude in units of e
32 G4double qfcp = std::abs(fcp_minus->GetPDGCharge() / CLHEP::eplus);
33
34 // Coupling-scaled reduced Compton wavelength
35 // rc_ = q^2 * elm_coupling / mfcp_
36 // This gives the correct q^4 scaling in sigfac = 4*alpha*Z^2*rc_^2
37 rc_ = qfcp * qfcp * CLHEP::elm_coupling / mfcp_;
38
39 limit_energy_ = 5. * mfcp_;
41 highest_energy_limit_ = 1e12 * CLHEP::GeV;
42 ldmx_log(debug) << "Energy limits: lowest="
43 << lowest_energy_limit_ / CLHEP::MeV
44 << " MeV, limit=" << limit_energy_ / CLHEP::MeV
45 << " MeV, highest=" << highest_energy_limit_ / CLHEP::GeV
46 << " GeV";
47
48 the_a_prime_ = G4APrime::APrime();
49 the_fcp_minus_ = fcp_minus;
50 // Look up the antiparticle (fcp+) from the particle table
51 the_fcp_plus_ = G4ParticleTable::GetParticleTable()->FindParticle("fcp+");
52
53 ldmx_log(debug) << "A' particle: "
54 << (the_a_prime_ ? the_a_prime_->GetParticleName() : "NULL")
55 << ", mass="
56 << (the_a_prime_ ? the_a_prime_->GetPDGMass() / CLHEP::MeV
57 : 0)
58 << " MeV";
59 ldmx_log(debug) << "FCP+ particle: "
60 << (the_fcp_plus_ ? the_fcp_plus_->GetParticleName()
61 : "NULL");
62 ldmx_log(debug) << "FCP- particle: "
63 << (the_fcp_minus_ ? the_fcp_minus_->GetParticleName()
64 : "NULL");
65}
const G4ParticleDefinition * the_fcp_minus_
Pointer to fcp- definition.
G4double rc_
Coupling-scaled reduced Compton wavelength: q^2 * elm_coupling / Mfcp.
G4double lowest_energy_limit_
Absolute low energy limit of the model (2 * Mfcp)
G4double highest_energy_limit_
High energy limit of the model.
const G4ParticleDefinition * the_fcp_plus_
Pointer to fcp+ definition.
const G4ParticleDefinition * the_a_prime_
Pointer to the A' particle definition.
G4double limit_energy_
Energy limit for accurate cross section (5 * Mfcp)

References highest_energy_limit_, limit_energy_, lowest_energy_limit_, mfcp_, rc_, the_a_prime_, the_fcp_minus_, and the_fcp_plus_.

Member Function Documentation

◆ BuildPhysicsTable()

void simcore::APrimeConversionToFCPs::BuildPhysicsTable ( const G4ParticleDefinition & p)
override

Build physics table (called during initialization).

Sets up the temp vector for element selection.

Definition at line 76 of file APrimeConversionToFCPs.cxx.

76 {
77 ldmx_log(debug) << "=== BuildPhysicsTable for particle: "
78 << p.GetParticleName() << " ===";
79 auto table = G4Material::GetMaterialTable();
80 std::size_t nelm = 0;
81 for (auto const& mat : *table) {
82 std::size_t n = mat->GetNumberOfElements();
83 nelm = std::max(nelm, n);
84 ldmx_log(debug) << " Material: " << mat->GetName() << " with " << n
85 << " elements";
86 }
87 temp_.resize(nelm, 0);
88 ldmx_log(debug) << "Max elements in any material: " << nelm;
90}
void printInfoDefinition()
Print process information.
std::vector< G4double > temp_
Temporary vector for element selection.

References printInfoDefinition(), and temp_.

◆ computeCrossSectionPerAtom()

G4double simcore::APrimeConversionToFCPs::computeCrossSectionPerAtom ( G4double APrimeEnergy,
G4int Z )

Compute the cross section per atom for the given A' energy and Z.

Definition at line 141 of file APrimeConversionToFCPs.cxx.

142 {
143 // Cross section parametrization adapted from H. Burkhardt
144 // (G4GammaConversionToMuons) with Mmuon -> mfcp_ and
145 // coupling scaled by q_fcp^4 through rc_
146 if (Egam <= lowest_energy_limit_) {
147 return 0.0;
148 }
149
150 G4NistManager* nist = G4NistManager::Instance();
151
152 G4double pow_thres, ecor, b, dn, zthird, winfty, w_med_appr, wsatur, sigfac;
153
154 if (Z == 1) { // special case of Hydrogen
155 b = 202.4;
156 dn = 1.49;
157 } else {
158 b = 183.;
159 dn = 1.54 * nist->GetA27(Z);
160 }
161 zthird = 1. / nist->GetZ13(Z); // Z^(-1/3)
162 winfty = b * zthird * mfcp_ / (dn * electron_mass_c2);
163 w_med_appr = 1. / (4. * dn * SQRTE * mfcp_);
164 wsatur = winfty / w_med_appr;
165 sigfac = 4. * fine_structure_const * Z * Z * rc_ * rc_;
166 pow_thres = 1.479 + 0.00799 * dn;
167 ecor = -18. + 4347. / (b * zthird);
168
169 G4double cor_fuc = 1. + .04 * G4Log(1. + ecor / Egam);
170 G4double eg = G4Exp(G4Log(1. - 4. * mfcp_ / Egam) * pow_thres) *
171 G4Exp(G4Log(G4Exp(G4Log(wsatur) * POW_SAT) +
172 G4Exp(G4Log(Egam) * POW_SAT)) /
173 POW_SAT);
174
175 G4double cross_section =
176 7. / 9. * sigfac * G4Log(1. + w_med_appr * cor_fuc * eg);
177 cross_section *= cross_sec_factor_;
178 return cross_section;
179}
G4double cross_sec_factor_
Factor to artificially scale the cross section.

References cross_sec_factor_, lowest_energy_limit_, mfcp_, and rc_.

Referenced by computeMeanFreePath(), getCrossSectionPerAtom(), and selectRandomAtom().

◆ computeMeanFreePath()

G4double simcore::APrimeConversionToFCPs::computeMeanFreePath ( G4double APrimeEnergy,
const G4Material * aMaterial )

Compute the mean free path for the given energy and material.

Definition at line 105 of file APrimeConversionToFCPs.cxx.

106 {
107 if (APrimeEnergy <= lowest_energy_limit_) {
108 return DBL_MAX;
109 }
110
111 const G4ElementVector* the_element_vector = aMaterial->GetElementVector();
112 const G4double* nb_of_atoms_per_volume =
113 aMaterial->GetVecNbOfAtomsPerVolume();
114
115 G4double sigma = 0.0;
116 G4double fact = 1.0;
117 G4double e = APrimeEnergy;
118
119 // Low energy approximation as in Bethe-Heitler model
120 if (e < limit_energy_) {
121 G4double y =
123 fact = y * y;
124 e = limit_energy_;
125 }
126
127 for (std::size_t i = 0; i < aMaterial->GetNumberOfElements(); ++i) {
128 sigma += nb_of_atoms_per_volume[i] * fact *
130 e, G4lrint((*the_element_vector)[i]->GetZ()));
131 }
132 return (sigma > 0.0) ? 1. / sigma : DBL_MAX;
133}
G4double computeCrossSectionPerAtom(G4double APrimeEnergy, G4int Z)
Compute the cross section per atom for the given A' energy and Z.

References computeCrossSectionPerAtom(), limit_energy_, and lowest_energy_limit_.

Referenced by GetMeanFreePath().

◆ getCrossSecFactor()

G4double simcore::APrimeConversionToFCPs::getCrossSecFactor ( ) const
inline
Returns
the current cross section scaling factor

Definition at line 79 of file APrimeConversionToFCPs.h.

79{ return cross_sec_factor_; }

References cross_sec_factor_.

◆ getCrossSectionPerAtom()

G4double simcore::APrimeConversionToFCPs::getCrossSectionPerAtom ( const G4DynamicParticle * aDynamicAPrime,
const G4Element * anElement )

Return the total cross section per atom.

Definition at line 135 of file APrimeConversionToFCPs.cxx.

136 {
137 return computeCrossSectionPerAtom(aDynamicAPrime->GetKineticEnergy(),
138 G4lrint(anElement->GetZ()));
139}

References computeCrossSectionPerAtom().

◆ GetMeanFreePath()

G4double simcore::APrimeConversionToFCPs::GetMeanFreePath ( const G4Track & aTrack,
G4double previousStepSize,
G4ForceCondition * condition )
override

Return the mean free path of the A' in the current material.

Definition at line 92 of file APrimeConversionToFCPs.cxx.

93 {
94 const G4DynamicParticle* a_dynamic_a_prime = aTrack.GetDynamicParticle();
95 G4double a_prime_energy = a_dynamic_a_prime->GetKineticEnergy();
96 const G4Material* a_material = aTrack.GetMaterial();
97 G4double mfp = computeMeanFreePath(a_prime_energy, a_material);
98 ldmx_log(trace) << "GetMeanFreePath: A' KE=" << a_prime_energy / CLHEP::MeV
99 << " MeV in " << a_material->GetName()
100 << " -> MFP=" << (mfp < DBL_MAX ? mfp / CLHEP::mm : -1)
101 << " mm";
102 return mfp;
103}
G4double computeMeanFreePath(G4double APrimeEnergy, const G4Material *aMaterial)
Compute the mean free path for the given energy and material.

References computeMeanFreePath().

◆ IsApplicable()

G4bool simcore::APrimeConversionToFCPs::IsApplicable ( const G4ParticleDefinition & particle)
override

Check if this process applies to the given particle.

Returns
true only for the A' (dark photon)

Definition at line 67 of file APrimeConversionToFCPs.cxx.

68 {
69 bool applicable = (&particle == the_a_prime_);
70 ldmx_log(debug) << "IsApplicable called for particle: "
71 << particle.GetParticleName() << " -> "
72 << (applicable ? "YES (this is A')" : "NO");
73 return applicable;
74}

References the_a_prime_.

◆ PostStepDoIt()

G4VParticleChange * simcore::APrimeConversionToFCPs::PostStepDoIt ( const G4Track & aTrack,
const G4Step & aStep )
override

Generate the final state: A' -> fcp+ fcp-.

Definition at line 188 of file APrimeConversionToFCPs.cxx.

189 {
190 ldmx_log(debug) << "A' -> fcp+ fcp- conversion starting!";
191 aParticleChange.Initialize(aTrack);
192 const G4Material* a_material = aTrack.GetMaterial();
193
194 ldmx_log(debug) << "Conversion in material: " << a_material->GetName();
195 ldmx_log(debug) << "A' Track ID: " << aTrack.GetTrackID()
196 << ", Parent ID: " << aTrack.GetParentID();
197
198 // Current A' energy and direction
199 const G4DynamicParticle* a_dynamic_a_prime = aTrack.GetDynamicParticle();
200 G4double egam = a_dynamic_a_prime->GetKineticEnergy();
201
202 G4ThreeVector pos = aTrack.GetPosition();
203 ldmx_log(debug) << "A' kinetic energy: " << egam / CLHEP::MeV << " MeV";
204 ldmx_log(debug) << "A' position: (" << pos.x() / CLHEP::mm << ", "
205 << pos.y() / CLHEP::mm << ", " << pos.z() / CLHEP::mm
206 << ") mm";
207 ldmx_log(debug) << "A' momentum direction: "
208 << a_dynamic_a_prime->GetMomentumDirection();
209
210 if (egam <= lowest_energy_limit_) {
211 ldmx_log(warn) << "A' energy (" << egam / CLHEP::MeV
212 << " MeV) below threshold ("
213 << lowest_energy_limit_ / CLHEP::MeV
214 << " MeV), skipping conversion!";
215 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
216 }
217
218 // Kill the incident A'
219 ldmx_log(debug) << "Killing incident A' and creating fcp+/fcp- pair...";
220 aParticleChange.ProposeMomentumDirection(0., 0., 0.);
221 aParticleChange.ProposeEnergy(0.);
222 aParticleChange.ProposeTrackStatus(fStopAndKill);
223
224 G4ParticleMomentum a_prime_direction =
225 a_dynamic_a_prime->GetMomentumDirection();
226
227 // Select randomly one element constituting the material
228 const G4Element* an_element = selectRandomAtom(a_dynamic_a_prime, a_material);
229 G4int z = G4lrint(an_element->GetZ());
230
231 // Store the element Z where the A' conversion occurred for downstream DQM.
232 auto* event_info = static_cast<UserEventInformation*>(
233 G4EventManager::GetEventManager()->GetUserInformation());
234 if (event_info != nullptr) {
235 event_info->setAPrimeConversionMaterialZ(z);
236 }
237
238 G4NistManager* nist = G4NistManager::Instance();
239
240 G4double b, dn;
241 G4double a027 = nist->GetA27(z);
242
243 if (z == 1) {
244 b = 202.4;
245 dn = 1.49;
246 } else {
247 b = 183.;
248 dn = 1.54 * a027;
249 }
250 G4double zthird = 1. / nist->GetZ13(z);
251 G4double winfty = b * zthird * mfcp_ / (dn * electron_mass_c2);
252
253 G4double c1_num = 0.138 * a027;
254 G4double c1_num2 = c1_num * c1_num;
255 G4double c2_term2 = electron_mass_c2 / (183. * zthird * mfcp_);
256
257 G4double gamma_fcp_inv = mfcp_ / egam;
258
259 // Generate xPlus according to the differential cross section by rejection
260 G4double xmin =
261 (egam <= limit_energy_) ? 0.5 : 0.5 - std::sqrt(0.25 - gamma_fcp_inv);
262 G4double xmax = 1. - xmin;
263
264 G4double ds2 = (dn * SQRTE - 2.);
265 G4double s_bz = SQRTE * b * zthird / electron_mass_c2;
266 G4double log_wmax_inv = 1. / G4Log(winfty * (1. + 2. * ds2 * gamma_fcp_inv) /
267 (1. + 2. * s_bz * mfcp_ * gamma_fcp_inv));
268 G4double x_plus = 0.5;
269 G4double x_minus = 0.5;
270 G4double x_pm = 0.25;
271
272 G4int nn = 0;
273 const G4int nmax = 1000;
274
275 // Sampling for Egam > limit_energy_
276 if (xmin < 0.5) {
277 G4double result, w;
278 do {
279 x_plus = xmin + G4UniformRand() * (xmax - xmin);
280 x_minus = 1. - x_plus;
281 x_pm = x_plus * x_minus;
282 G4double del = mfcp_ * mfcp_ / (2. * egam * x_pm);
283 w = winfty * (1. + ds2 * del / mfcp_) / (1. + s_bz * del);
284 G4double xxp = 1. - 4. / 3. * x_pm;
285 result = (xxp > 0.) ? xxp * G4Log(w) * log_wmax_inv : 0.0;
286 if (result > 1.0) {
287 ldmx_log(warn) << "APrimeConversionToFCPs::PostStepDoIt WARNING:"
288 << " in dSigxPlusGen, result=" << result << " > 1";
289 }
290 ++nn;
291 if (nn >= nmax) {
292 break;
293 }
294 } while (G4UniformRand() > result);
295 }
296
297 // Generate angular variables via auxiliary variables t, psi, rho
298 G4double t;
299 G4double psi;
300 G4double rho;
301
302 G4double a3 = (gamma_fcp_inv / (2. * x_pm));
303 G4double a33 = a3 * a3;
304 G4double f1;
305 G4double b1 = 1. / (4. * c1_num2);
306 G4double b3 = b1 * b1 * b1;
307 G4double a21 = a33 + b1;
308
309 G4double f1_max =
310 -(1. - x_pm) * (2. * b1 + (a21 + a33) * G4Log(a33 / a21)) / (2 * b3);
311
312 G4double theta_plus, theta_minus, phi_half;
313 nn = 0;
314
315 // t, psi, rho generation (while angle < pi)
316 do {
317 // Generate t by rejection method
318 do {
319 ++nn;
320 t = G4UniformRand();
321 G4double a34 = a33 / (t * t);
322 G4double a22 = a34 + b1;
323 if (std::abs(b1) < 0.0001 * a34) {
324 f1 = (1. - 2. * x_pm + 4. * x_pm * t * (1. - t)) /
325 (12. * a34 * a34 * a34 * a34);
326 } else {
327 f1 = -(1. - 2. * x_pm + 4. * x_pm * t * (1. - t)) *
328 (2. * b1 + (a22 + a34) * G4Log(a34 / a22)) / (2 * b3);
329 }
330 if (f1 < 0.0 || f1 > f1_max) {
331 f1 = 0.0;
332 }
333 if (nn > nmax) {
334 break;
335 }
336 } while (G4UniformRand() * f1_max > f1);
337
338 // Generate psi by rejection method
339 G4double f2_max = 1. - 2. * x_pm * (1. - 4. * t * (1. - t));
340 G4double f2;
341 do {
342 ++nn;
343 psi = CLHEP::twopi * G4UniformRand();
344 f2 =
345 1. - 2. * x_pm + 4. * x_pm * t * (1. - t) * (1. + std::cos(2. * psi));
346 if (f2 < 0 || f2 > f2_max) {
347 f2 = 0.0;
348 }
349 if (nn >= nmax) {
350 break;
351 }
352 } while (G4UniformRand() * f2_max > f2);
353
354 // Generate rho by direct transformation
355 G4double c2_term1 = gamma_fcp_inv / (2. * x_pm * t);
356 G4double c22 = c2_term1 * c2_term1 + c2_term2 * c2_term2;
357 G4double c2 = 4. * c22 * c22 / std::sqrt(x_pm);
358 G4double rhomax = (1. / t - 1.) * 1.9 / a027;
359 G4double beta = G4Log((c2 + rhomax * rhomax * rhomax * rhomax) / c2);
360 rho = G4Exp(G4Log(c2 * (G4Exp(beta * G4UniformRand()) - 1.)) * 0.25);
361
362 // Get kinematical variables from t and psi
363 G4double u = std::sqrt(1. / t - 1.);
364 G4double xi_half = 0.5 * rho * std::cos(psi);
365 phi_half = 0.5 * rho / u * std::sin(psi);
366
367 theta_plus = gamma_fcp_inv * (u + xi_half) / x_plus;
368 theta_minus = gamma_fcp_inv * (u - xi_half) / x_minus;
369
370 // Protection against infinite loop
371 if (nn > nmax) {
372 if (std::abs(theta_plus) > CLHEP::pi) {
373 theta_plus = 0.0;
374 }
375 if (std::abs(theta_minus) > CLHEP::pi) {
376 theta_minus = 0.0;
377 }
378 }
379 } while (std::abs(theta_plus) > CLHEP::pi ||
380 std::abs(theta_minus) > CLHEP::pi);
381
382 // Construct the momentum vectors
383 // Azimuthal symmetry: take phi0 random between 0 and 2pi
384 G4double phi0 = CLHEP::twopi * G4UniformRand();
385 G4double e_plus = x_plus * egam;
386 G4double e_minus = x_minus * egam;
387
388 // fcp+ fcp- directions for A' in z-direction
389 G4ThreeVector fcp_plus_direction(
390 std::sin(theta_plus) * std::cos(phi0 + phi_half),
391 std::sin(theta_plus) * std::sin(phi0 + phi_half), std::cos(theta_plus));
392 G4ThreeVector fcp_minus_direction(
393 -std::sin(theta_minus) * std::cos(phi0 - phi_half),
394 -std::sin(theta_minus) * std::sin(phi0 - phi_half),
395 std::cos(theta_minus));
396
397 // Rotate to actual A' direction
398 fcp_plus_direction.rotateUz(a_prime_direction);
399 fcp_minus_direction.rotateUz(a_prime_direction);
400
401 // Create fcp+ secondary
402 auto a_particle1 =
403 new G4DynamicParticle(the_fcp_plus_, fcp_plus_direction, e_plus - mfcp_);
404 aParticleChange.AddSecondary(a_particle1);
405
406 ldmx_log(debug) << "Created FCP+ with:";
407 ldmx_log(debug) << " - Kinetic energy: " << (e_plus - mfcp_) / CLHEP::MeV
408 << " MeV";
409 ldmx_log(debug) << " - Total energy: " << e_plus / CLHEP::MeV << " MeV";
410 ldmx_log(debug) << " - Direction: " << fcp_plus_direction;
411
412 // Create fcp- secondary
413 auto a_particle2 = new G4DynamicParticle(the_fcp_minus_, fcp_minus_direction,
414 e_minus - mfcp_);
415 aParticleChange.AddSecondary(a_particle2);
416
417 ldmx_log(debug) << "Created FCP- with:";
418 ldmx_log(debug) << " - Kinetic energy: " << (e_minus - mfcp_) / CLHEP::MeV
419 << " MeV";
420 ldmx_log(debug) << " - Total energy: " << e_minus / CLHEP::MeV << " MeV";
421 ldmx_log(debug) << " - Direction: " << fcp_minus_direction;
422
423 ldmx_log(debug) << "=== A' -> fcp+ fcp- CONVERSION COMPLETE ===";
424
425 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
426} // end of PostStepDoIt
const G4Element * selectRandomAtom(const G4DynamicParticle *aDynamicAPrime, const G4Material *aMaterial)
Select a random atom from the material, weighted by cross section.

References limit_energy_, lowest_energy_limit_, mfcp_, selectRandomAtom(), the_fcp_minus_, and the_fcp_plus_.

◆ printInfoDefinition()

void simcore::APrimeConversionToFCPs::printInfoDefinition ( )

Print process information.

Definition at line 455 of file APrimeConversionToFCPs.cxx.

455 {
456 G4cout << G4endl << GetProcessName() << ": "
457 << "A' -> fcp+ fcp- Bethe-Heitler-like process" << G4endl;
458 G4cout << " good cross section parametrization from "
459 << G4BestUnit(lowest_energy_limit_, "Energy") << " to "
460 << highest_energy_limit_ / GeV << " GeV for all Z." << G4endl;
461 G4cout << " cross section factor: " << cross_sec_factor_ << G4endl;
462}

References cross_sec_factor_, highest_energy_limit_, and lowest_energy_limit_.

Referenced by BuildPhysicsTable().

◆ selectRandomAtom()

const G4Element * simcore::APrimeConversionToFCPs::selectRandomAtom ( const G4DynamicParticle * aDynamicAPrime,
const G4Material * aMaterial )
private

Select a random atom from the material, weighted by cross section.

Definition at line 428 of file APrimeConversionToFCPs.cxx.

429 {
430 const std::size_t number_of_elements = aMaterial->GetNumberOfElements();
431 const G4ElementVector* the_element_vector = aMaterial->GetElementVector();
432 const G4Element* elm = (*the_element_vector)[0];
433
434 if (number_of_elements > 1) {
435 G4double e = std::max(aDynamicAPrime->GetKineticEnergy(), limit_energy_);
436 const G4double* natom = aMaterial->GetVecNbOfAtomsPerVolume();
437
438 G4double sum = 0.;
439 for (std::size_t i = 0; i < number_of_elements; ++i) {
440 elm = (*the_element_vector)[i];
441 sum += natom[i] * computeCrossSectionPerAtom(e, G4lrint(elm->GetZ()));
442 temp_[i] = sum;
443 }
444 sum *= G4UniformRand();
445 for (std::size_t i = 0; i < number_of_elements; ++i) {
446 if (sum <= temp_[i]) {
447 elm = (*the_element_vector)[i];
448 break;
449 }
450 }
451 }
452 return elm;
453}

References computeCrossSectionPerAtom(), limit_energy_, and temp_.

Referenced by PostStepDoIt().

◆ setCrossSecFactor()

void simcore::APrimeConversionToFCPs::setCrossSecFactor ( G4double fac)

Set a factor to artificially scale the cross section.

Parameters
[in]facmultiplicative factor (default 1.0)

Definition at line 181 of file APrimeConversionToFCPs.cxx.

181 {
182 if (fac < 0.0) return;
183 cross_sec_factor_ = fac;
184 ldmx_log(info) << "APrimeConversionToFCPs cross section factor set to "
186}

References cross_sec_factor_.

Referenced by simcore::APrimePhysics::ConstructProcess().

Member Data Documentation

◆ cross_sec_factor_

G4double simcore::APrimeConversionToFCPs::cross_sec_factor_ = 1.0
private

Factor to artificially scale the cross section.

Definition at line 132 of file APrimeConversionToFCPs.h.

Referenced by computeCrossSectionPerAtom(), getCrossSecFactor(), printInfoDefinition(), and setCrossSecFactor().

◆ highest_energy_limit_

G4double simcore::APrimeConversionToFCPs::highest_energy_limit_
private

High energy limit of the model.

Definition at line 130 of file APrimeConversionToFCPs.h.

Referenced by APrimeConversionToFCPs(), and printInfoDefinition().

◆ limit_energy_

G4double simcore::APrimeConversionToFCPs::limit_energy_
private

Energy limit for accurate cross section (5 * Mfcp)

Definition at line 126 of file APrimeConversionToFCPs.h.

Referenced by APrimeConversionToFCPs(), computeMeanFreePath(), PostStepDoIt(), and selectRandomAtom().

◆ lowest_energy_limit_

G4double simcore::APrimeConversionToFCPs::lowest_energy_limit_
private

Absolute low energy limit of the model (2 * Mfcp)

Definition at line 128 of file APrimeConversionToFCPs.h.

Referenced by APrimeConversionToFCPs(), computeCrossSectionPerAtom(), computeMeanFreePath(), PostStepDoIt(), and printInfoDefinition().

◆ mfcp_

G4double simcore::APrimeConversionToFCPs::mfcp_
private

fcp mass

Definition at line 122 of file APrimeConversionToFCPs.h.

Referenced by APrimeConversionToFCPs(), computeCrossSectionPerAtom(), and PostStepDoIt().

◆ PROCESS_NAME

const std::string simcore::APrimeConversionToFCPs::PROCESS_NAME = "APrimeToFCPPair"
static

The name of this process.

Used to attach biasing operators to this process.

Definition at line 37 of file APrimeConversionToFCPs.h.

Referenced by simcore::biasoperators::APrimeToFCPPair::getProcessToBias().

◆ rc_

G4double simcore::APrimeConversionToFCPs::rc_
private

Coupling-scaled reduced Compton wavelength: q^2 * elm_coupling / Mfcp.

Definition at line 124 of file APrimeConversionToFCPs.h.

Referenced by APrimeConversionToFCPs(), and computeCrossSectionPerAtom().

◆ temp_

std::vector<G4double> simcore::APrimeConversionToFCPs::temp_
private

Temporary vector for element selection.

Definition at line 142 of file APrimeConversionToFCPs.h.

Referenced by BuildPhysicsTable(), and selectRandomAtom().

◆ the_a_prime_

const G4ParticleDefinition* simcore::APrimeConversionToFCPs::the_a_prime_
private

Pointer to the A' particle definition.

Definition at line 135 of file APrimeConversionToFCPs.h.

Referenced by APrimeConversionToFCPs(), and IsApplicable().

◆ the_fcp_minus_

const G4ParticleDefinition* simcore::APrimeConversionToFCPs::the_fcp_minus_
private

Pointer to fcp- definition.

Definition at line 137 of file APrimeConversionToFCPs.h.

Referenced by APrimeConversionToFCPs(), and PostStepDoIt().

◆ the_fcp_plus_

const G4ParticleDefinition* simcore::APrimeConversionToFCPs::the_fcp_plus_
private

Pointer to fcp+ definition.

Definition at line 139 of file APrimeConversionToFCPs.h.

Referenced by APrimeConversionToFCPs(), and PostStepDoIt().


The documentation for this class was generated from the following files: