Line data Source code
1 : #include "crpropa/module/Acceleration.h"
2 : #include <crpropa/Common.h>
3 : #include <crpropa/Random.h>
4 : #include <cmath>
5 :
6 : namespace crpropa {
7 :
8 0 : AbstractAccelerationModule::AbstractAccelerationModule(double _stepLength)
9 0 : : crpropa::Module(), stepLength(_stepLength) {}
10 :
11 :
12 0 : void AbstractAccelerationModule::add(StepLengthModifier *modifier) {
13 0 : modifiers.push_back(modifier);
14 0 : }
15 :
16 :
17 0 : void AbstractAccelerationModule::scatter(
18 : crpropa::Candidate *candidate,
19 : const crpropa::Vector3d &scatter_center_velocity) const {
20 : // particle momentum in lab frame
21 0 : const double E = candidate->current.getEnergy();
22 0 : const crpropa::Vector3d p = candidate->current.getMomentum();
23 :
24 : // transform to rest frame of scatter center (p: prime)
25 0 : const double beta = scatter_center_velocity.getR() / crpropa::c_light;
26 0 : const double gamma = 1. / sqrt(1 - beta * beta);
27 0 : const double Ep = gamma * (E - scatter_center_velocity.dot(p));
28 : const crpropa::Vector3d pp = (p - scatter_center_velocity* E /
29 : (crpropa::c_light * crpropa::c_light)) * gamma;
30 :
31 : // scatter into random direction
32 0 : const crpropa::Vector3d pp_new = crpropa::Random::instance().randVector() * pp.getR();
33 :
34 : // transform back
35 0 : const double E_new = gamma * (Ep + scatter_center_velocity.dot(pp_new));
36 : const crpropa::Vector3d p_new = (pp_new + scatter_center_velocity * Ep /
37 : (crpropa::c_light * crpropa::c_light)) * gamma;
38 :
39 : // update candidate properties
40 0 : candidate->current.setEnergy(E_new);
41 0 : candidate->current.setDirection(p_new / p_new.getR());
42 0 : }
43 :
44 :
45 0 : void AbstractAccelerationModule::process(crpropa::Candidate *candidate) const {
46 0 : double currentStepLength = stepLength;
47 0 : for (auto m : modifiers) {
48 0 : currentStepLength = m->modify(currentStepLength, candidate);
49 : }
50 :
51 0 : double step = candidate->getCurrentStep();
52 0 : while (step > 0) {
53 0 : double randDistance = -1. * log(crpropa::Random::instance().rand()) * currentStepLength;
54 :
55 0 : if (step < randDistance) {
56 0 : candidate->limitNextStep(0.1 * currentStepLength);
57 0 : return;
58 : }
59 0 : scatter(candidate, scatterCenterVelocity(candidate));
60 0 : step -= randDistance;
61 : }
62 : }
63 :
64 :
65 0 : SecondOrderFermi::SecondOrderFermi(double scatterVelocity, double stepLength,
66 0 : unsigned int sizeOfPitchangleTable)
67 : : AbstractAccelerationModule(stepLength),
68 0 : scatterVelocity(scatterVelocity) {
69 0 : setDescription("SecondOrderFermi Acceleration");
70 0 : angle.resize(sizeOfPitchangleTable);
71 0 : angleCDF.resize(sizeOfPitchangleTable);
72 :
73 : // have a discretized table of beamed pitch angles
74 0 : for (unsigned int i =0; i < sizeOfPitchangleTable; i++) {
75 0 : angle[i] = i * M_PI / (sizeOfPitchangleTable-1);
76 0 : angleCDF[i] = (angle[i] +scatterVelocity / crpropa::c_light * sin(angle[i])) / M_PI;
77 : }
78 0 : }
79 :
80 :
81 0 : crpropa::Vector3d SecondOrderFermi::scatterCenterVelocity(crpropa::Candidate *candidate) const
82 : {
83 0 : size_t idx = crpropa::closestIndex(crpropa::Random::instance().rand(), angleCDF);
84 0 : crpropa::Vector3d rv = crpropa::Random::instance().randVector();
85 0 : crpropa::Vector3d rotationAxis = candidate->current.getDirection().cross(rv);
86 :
87 0 : rv = candidate->current.getDirection().getRotated(rotationAxis, M_PI - angle[idx]);
88 0 : return rv * scatterVelocity;
89 : }
90 :
91 :
92 0 : DirectedFlowOfScatterCenters::DirectedFlowOfScatterCenters(
93 0 : const Vector3d &scatterCenterVelocity)
94 0 : : __scatterVelocity(scatterCenterVelocity) {}
95 :
96 :
97 0 : double DirectedFlowOfScatterCenters::modify(double steplength, Candidate* candidate)
98 : {
99 0 : double directionModifier = (-1. * __scatterVelocity.dot(candidate->current.getDirection()) + c_light) / c_light;
100 0 : return steplength / directionModifier;
101 : }
102 :
103 :
104 0 : DirectedFlowScattering::DirectedFlowScattering(
105 0 : crpropa::Vector3d scatterCenterVelocity, double stepLength)
106 : : __scatterVelocity(scatterCenterVelocity),
107 0 : AbstractAccelerationModule(stepLength) {
108 :
109 : // In a directed field of scatter centers, the probability to encounter a
110 : // scatter center depends on the direction of the candidate.
111 0 : StepLengthModifier *mod = new DirectedFlowOfScatterCenters(__scatterVelocity);
112 0 : this->add(mod);
113 0 : }
114 :
115 :
116 0 : crpropa::Vector3d DirectedFlowScattering::scatterCenterVelocity(
117 : crpropa::Candidate *candidate) const { // does not depend on candidate here.
118 0 : return __scatterVelocity;
119 : }
120 :
121 :
122 0 : QuasiLinearTheory::QuasiLinearTheory(double referenecEnergy,
123 : double turbulenceIndex,
124 0 : double minimumRigidity)
125 0 : : __referenceEnergy(referenecEnergy), __turbulenceIndex(turbulenceIndex),
126 0 : __minimumRigidity(minimumRigidity) {}
127 :
128 :
129 0 : double QuasiLinearTheory::modify(double steplength, Candidate* candidate)
130 : {
131 0 : if (candidate->current.getRigidity() < __minimumRigidity)
132 : {
133 0 : return steplength * std::pow(__minimumRigidity /
134 0 : (__referenceEnergy / eV), 2. - __turbulenceIndex);
135 : }
136 : else
137 : {
138 0 : return steplength * std::pow(candidate->current.getRigidity() /
139 0 : (__referenceEnergy / eV), 2. - __turbulenceIndex);
140 : }
141 : }
142 :
143 :
144 0 : ParticleSplitting::ParticleSplitting(Surface *surface, int crossingThreshold,
145 0 : int numberSplits, double minWeight, std::string counterid)
146 0 : : surface(surface), crossingThreshold(crossingThreshold),
147 0 : numberSplits(numberSplits), minWeight(minWeight), counterid(counterid){};
148 :
149 0 : void ParticleSplitting::process(Candidate *candidate) const {
150 : const double currentDistance =
151 0 : surface->distance(candidate->current.getPosition());
152 : const double previousDistance =
153 0 : surface->distance(candidate->previous.getPosition());
154 :
155 0 : if (currentDistance * previousDistance > 0)
156 : // candidate remains on the same side
157 : return;
158 :
159 0 : if (candidate->getWeight() < minWeight)
160 : return;
161 :
162 : int num_crossings = 1;
163 0 : if (candidate->hasProperty(counterid))
164 0 : num_crossings = candidate->getProperty(counterid).toInt32() + 1;
165 0 : candidate->setProperty(counterid, num_crossings);
166 :
167 0 : if (num_crossings % crossingThreshold != 0)
168 : return;
169 :
170 0 : candidate->updateWeight(1. / numberSplits);
171 :
172 0 : for (size_t i = 1; i < numberSplits; i++) {
173 : // No recursive split as the weights of the secondaries created
174 : // before the split are not affected
175 0 : ref_ptr<Candidate> new_candidate = candidate->clone(false);
176 0 : new_candidate->parent = candidate;
177 0 : uint64_t snr = Candidate::getNextSerialNumber();
178 0 : Candidate::setNextSerialNumber(snr + 1);
179 0 : new_candidate->setSerialNumber(snr);
180 : candidate->addSecondary(new_candidate);
181 : }
182 : };
183 :
184 : } // namespace crpropa
|