File indexing completed on 2026-04-05 07:50:23
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include "PrimaryGeneratorAction.hh"
0030
0031 #include "G4Event.hh"
0032 #include "G4ParticleGun.hh"
0033 #include "G4PhysicalConstants.hh"
0034 #include "G4SystemOfUnits.hh"
0035 #include "Randomize.hh"
0036
0037 #include <fstream>
0038
0039 PrimaryGeneratorAction::PrimaryGeneratorAction(DetectorConstruction* detector)
0040 : G4VUserPrimaryGeneratorAction(), fDetector(detector)
0041 {
0042 fpParticleGun = std::make_unique<G4ParticleGun>();
0043 fpParticleGun->SetParticleEnergy(-1);
0044 }
0045
0046
0047
0048 void PrimaryGeneratorAction::GeneratePrimaries(G4Event* anEvent)
0049 {
0050
0051 G4double energy = fpParticleGun->GetParticleEnergy();
0052
0053
0054
0055 if (energy == -1) {
0056
0057
0058 fMonoEnergetic = false;
0059 }
0060
0061 if (!fMonoEnergetic) {
0062 energy = GenerateParticleEnergy();
0063 }
0064
0065 fpParticleGun->SetParticleEnergy(energy);
0066 fpParticleGun->SetParticlePosition(GenerateParticlePosition());
0067 fpParticleGun->SetParticleMomentumDirection(
0068 GenerateParticleDirection());
0069
0070 fpParticleGun->GeneratePrimaryVertex(anEvent);
0071 }
0072
0073
0074
0075 G4double PrimaryGeneratorAction::GenerateParticleEnergy()
0076 {
0077 if (fEnergySpectrum_length == 0) {
0078 std::ifstream fin(fEnergySpectrumFilename);
0079 G4String len, gain, offset, counts;
0080 fin >> len >> gain >> offset;
0081 fEnergySpectrum_length = std::stoi(len);
0082 fEnergySpectrum_gain = std::stod(gain);
0083 fEnergySpectrum_offset = std::stod(offset);
0084
0085 fEnergySpectrum_counts.resize(fEnergySpectrum_length);
0086 for (G4int i = 0; i < fEnergySpectrum_length; i++) {
0087 fin >> counts;
0088 fEnergySpectrum_counts[i] = std::stoi(counts);
0089 }
0090 }
0091
0092 auto max_en_counter = fEnergySpectrum_counts[fEnergySpectrum_length - 1] - 1;
0093 auto rand_count = 1 + G4int(G4UniformRand() * max_en_counter);
0094
0095
0096
0097 G4int en_id = 0;
0098 for (; rand_count > fEnergySpectrum_counts[en_id]; en_id++)
0099 ;
0100
0101 G4int left = fEnergySpectrum_counts[en_id - 1];
0102 G4int right = fEnergySpectrum_counts[en_id];
0103
0104 G4double en_left = (en_id - 1) * fEnergySpectrum_gain + fEnergySpectrum_offset;
0105 G4double en_right = en_id * fEnergySpectrum_gain + fEnergySpectrum_offset;
0106
0107
0108 G4double slope = (en_right - en_left) / (right - left);
0109 return (en_left + slope * (rand_count - left)) * MeV;
0110 }
0111
0112
0113
0114 G4ThreeVector PrimaryGeneratorAction::GenerateParticlePosition()
0115 {
0116
0117 G4double r = std::sqrt(G4UniformRand()) * fDetector->GetCollDiameter() / 2.;
0118 G4double phi = G4UniformRand() * twopi;
0119
0120 G4double x = fDetector->GetCollExitPosistion() - fDetector->GetCollLength();
0121 G4double y = r * std::cos(phi);
0122 G4double z = r * std::sin(phi);
0123
0124 return {x, y, z};
0125 }
0126
0127
0128
0129 G4ThreeVector PrimaryGeneratorAction::GenerateParticleDirection()
0130 {
0131 G4double phi, theta;
0132 G4double px, py, pz;
0133
0134 phi = G4UniformRand() * twopi;
0135
0136
0137
0138
0139
0140
0141
0142 G4double cos_max_theta =
0143 std::cos(std::atan(fDetector->GetCollDiameter() / fDetector->GetCollLength()));
0144 theta = std::acos(cos_max_theta + G4UniformRand() * (1 - cos_max_theta));
0145
0146 px = std::cos(theta);
0147 py = std::sin(theta) * std::sin(phi);
0148 pz = std::sin(theta) * std::cos(phi);
0149
0150 return {px, py, pz};
0151 }
0152