criptic v1
Cosmic Ray Interstellar Propagation Tool using Itô Calculus
Loading...
Searching...
No Matches
AdvancePacket.H
Go to the documentation of this file.
1
9#ifndef _ADVANCEPACKET_H_
10#define _ADVANCEPACKET_H_
11
12#include "CRPacket.H"
13#include "FieldQty.H"
14#include "Geometry.H"
15#include "../Gas/Gas.H"
16#include "../Losses/Losses.H"
17#include "../Propagation/Propagation.H"
18#include "../Utils/RealTensor2.H"
19#include "../Utils/RKF.H"
20#include "../Utils/RngThread.H"
21#include "../Utils/Types.H"
22#include "../Utils/Vec3.H"
23#include <sstream>
24
25namespace criptic {
26
62 const criptic::Real tStop,
63 const criptic::Geometry& geom,
64 const criptic::gas::Gas& gasBG,
66 const criptic::Losses& loss,
67 const criptic::RngThread& rng,
68 const criptic::FieldQty& qty,
69 const criptic::FieldQtyGrad& qtyGrad,
70 const criptic::Real cStep,
71 const criptic::Real errTol,
72 const criptic::Real wFracMin,
73 const criptic::Real pMin,
74 const criptic::Real TMin,
75 const criptic::Real packetDtMin,
76 const criptic::Real& h,
78 criptic::CRPacket& packet,
79 criptic::Real& dt,
80 std::vector<RealVec>& secondaryPositions,
81 std::vector<CRPacket>& secondaryPackets) {
82
83 // Set time to starting time for this packet, and initialize
84 // minimum time step recorder to numerical infinity
85 Real t = std::max(packet.tInj, tStart);
86 dt = maxReal;
87
88 // Loop until update is complete
89 bool packetDone = false;
90 while (!packetDone) {
91
92 // Step 1: grab the gas state at the start of the step, and
93 // compute the TNB basis vectors from it
94 gas::GasData gd = gasBG.gasData(x, t);
95 TNBBasis b = TNBVectors(gd.B, gd.BGrad);
96
97 // Step 2: grab the propagation parameters at the starting
98 // position and time
100 prop(x, t, gd, packet, qty, qtyGrad);
101 prop.applyLimits(gd, packet, pd);
102
103 // Step 3: compute momentum loss rate, catastrophic loss rate,
104 // and properties of secondary creation channels
105 Real dpdtCts, lossRate, wSec;
106 Losses::MechMatrix<Real> pSec;
107 loss.computeLoss(gd, packet, dpdtCts, lossRate, wSec, pSec);
108
109 // Step 4: construct the drift vector in the TNB basis,
110 // co-moving with the gas. The mathematical relationships here
111 // are:
112 //
113 // For the case with streaming, not following pitch angle:
114 // drift[0] = dKpar / dxT + vStr + (p/3) dvStr/dp
115 // drift[1] = dKperp / dxN
116 // drift[2] = dKperp / dxB
117 // pDrift = dKpp / dp + (2/p) kPP - \dot{p}_cts -
118 // (p/3) * (del . v + grad(vStr) . eT + vStr del . eT),
119 //
120 // For the case following pitch angle evolution:
121 // drift[0] = dKpar / dxT + mu * v
122 // drift[1] = dKperp / dxN
123 // drift[2] = dKperp / dxB
124 // pDrift = dKpp / dp + (2/p) kPP - \dot{p}_cts -
125 // (p/3) * (del . v)
126 // muDrift = -2 * mu * kMu + (1 - mu^2) dkMu / dMu
127 //
128 // where d/dxT indicates derivative in the T direction, and
129 // similarly for d/dxN and d/dxB. We evalute these derivatives
130 // using the relationship that, for an arbitrary scalar q, we
131 // have dq/dxT = grad(q) . eT, and similarly for the N and B
132 // directions. We also evaluate the final term del . eT, the
133 // divergence of the eT vector, using the identity
134 // div(eT) = -eT_i eT_j (dB_i / dx_j) / |B|
135 RealVec xDrift;
136#ifndef TRACK_PITCH_ANGLE
137 xDrift[0] = pd.vStr + packet.p * pd.dvStr_dp / 3.0
138 + pd.kParGrad.dot(b.eT);
139#else
140 xDrift[0] = packet.mu * packet.v() * constants::c + pd.kParGrad.dot(b.eT);
141#endif
142 xDrift[1] = pd.kPerpGrad.dot(b.eN);
143 xDrift[2] = pd.kPerpGrad.dot(b.eB);
144#ifdef TRACK_PITCH_ANGLE
145 Real pDrift = pd.dkPP_dp + 2 * pd.kPP/packet.p - dpdtCts
146 - packet.p / 3 * gd.vGrad.trace();
147 Real muDrift = -2 * packet.mu * pd.kMu +
148 (1.0 - packet.mu * packet.mu) * pd.dkMudMu;
149#else
150 Real pDrift = pd.dkPP_dp + 2 * pd.kPP/packet.p - dpdtCts
151 - packet.p / 3 *
152 (gd.vGrad.trace() + pd.vStrGrad.dot(b.eT) -
153 pd.vStr * gd.BGrad.contract(b.eT, b.eT) / gd.B.mag());
154#endif
155
156 // Step 5: compute the time step
157 Real dx = gd.dx; // Gas length scale
158 if (h != 0) dx = std::min(dx, h); // Packet length scale
159 Real xDriftMag = xDrift.mag();
160 Real dtAdv = (xDriftMag != 0.0 && dx != 0) ?
161 cStep * dx / xDriftMag : maxReal;
162 Real kMag = std::max(pd.kPar, pd.kPerp);
163 Real dtDiff = (kMag != 0.0 && dx != 0.0) ?
164 cStep * dx * dx / kMag : maxReal;
165 Real dtPAdv = pDrift != 0.0 ?
166 cStep * packet.p / std::abs(pDrift) : maxReal;
167 Real dtPP =
168 pd.kPP != 0.0 ? cStep * packet.p * packet.p / pd.kPP : maxReal;
169 Real dtLoss = lossRate != 0.0 ? cStep / lossRate : maxReal;
170#ifdef TRACK_PITCH_ANGLE
171 Real dtMuAdv = fabs(muDrift) != 0.0 ?
172 0.02 / fabs(muDrift) : maxReal;
173 Real dtMuDiff = pd.kMu != 0.0 ?
174 0.02 * cStep / pd.kMu : maxReal;
175#endif
176 // Safety check: make sure we have at least one valid time
177 // scale; issue a warning if not, but do not halt, since in some
178 // problems this will occur only very early in the calculation
179 // when the number of packets is too small to compute smoothing
180 // lengths or gradients, but the problem will resolve as soon as
181 // the number of packets becomes reasonable
182 if (dtAdv == maxReal && dtDiff == maxReal &&
183 dtPAdv == maxReal && dtPP == maxReal &&
184 dtPP == maxReal && dtLoss == maxReal
185#ifdef TRACK_PITCH_ANGLE
186 && dtMuAdv == maxReal && dtMuDiff == maxReal
187#endif
188 ) {
189 std::cout << "AdvancePacket: warning: unable to compute time "
190 << "step size; note that in problems where the gas "
191 << "does not contain a characteristic length scale, "
192 << "the length scale dx must be set by hand in order "
193 << "to compute valid spatial drift or diffusion "
194 << "timescales; calculation will continue, but time "
195 << "step will not be self-consistently computed for "
196 << "this packet advance";
197 }
198
199 Real dtStep = 1.0 / (1.0/dtAdv + 1.0/dtDiff + 1.0/dtPAdv
200 + 1.0/dtPP + 1.0/dtLoss
201#ifdef TRACK_PITCH_ANGLE
202 + 1.0/dtMuAdv + 1.0/dtMuDiff
203#endif
204 );
205
206 // Check for unacceptably small packet time step
207 if (!(dtStep >= packetDtMin)) {
208 std::stringstream ss;
209 ss << "AdvancePacket: packet dt = " << dtStep
210 << " < min dt = " << packetDtMin
211 << "; individual time steps are: "
212 << "dtAdv = " << dtAdv
213 << ", dtDiff = " << dtDiff
214 << ", dtPAdv = " << dtPAdv
215 << ", dtPP = " << dtPP
216 << ", dtLoss = " << dtLoss
217#ifdef TRACK_PITCH_ANGLE
218 << ", dtMuAdv = " << dtMuAdv
219 << ", dtMuDiff = " << dtMuDiff
220#endif
221 << "; packet x = " << x
222 << ", p = " << packet.p
223 << ", type = " << packet.type
224 << "; propagation parameters "
225#ifdef TRACK_PITCH_ANGLE
226 << "kMu = " << pd.kMu
227 << ", dkMu_dMu = " << pd.dkMudMu << ", "
228#else
229 << "vStr = " << pd.vStr
230 << ", vStrGrad = " << pd.vStrGrad
231 << ", dvStr_dp = " << pd.dvStr_dp
232#endif
233 << ", kPar = " << pd.kPar
234 << ", kPerp = " << pd.kPerp
235 << ", kPP = " << pd.kPP
236 << ", kParGrad = " << pd.kParGrad
237 << ", kPerpGrad = " << pd.kPerpGrad
238 << ", dkPP_dp = " << pd.dkPP_dp;
240 }
241 if (dt > dtStep) {
242 dt = dtStep; // Record minimum internal time step
243 }
244 if (t + dtStep >= tStop) {
245 dtStep = tStop - t;
246 packetDone = true;
247 }
248
249 // Step 6: update packet grammage, momentum, and weight; for
250 // pitch angle scattering, also update the pitch angle
251 packet.gr += gd.den * packet.v() * constants::c * dtStep;
252 Real wFac = std::exp( -lossRate * dtStep);
253 packet.w *= wFac;
254 packet.p += pDrift * dtStep +
255 std::sqrt(2 * pd.kPP * dtStep) * rng.normal();
256#ifdef TRACK_PITCH_ANGLE
257 packet.mu += dtStep * muDrift +
258 std::sqrt(2 * pd.kMu * (1.0 - packet.mu * packet.mu) * dtStep)
259 * rng.normal();
260 while (packet.mu > 2) packet.mu -= 2;
261 while (packet.mu < -2) packet.mu += 2;
262 if (packet.mu > 1) packet.mu = 2 - packet.mu;
263 if (packet.mu < -1) packet.mu = -2 - packet.mu;
264#endif
265
266 // Step 7: create secondaries
267 for (int i = 0; i < lossMech::nMech; i++) {
268 for (int j = 0; j < partTypes::nPartType; j++) {
269 if (pSec[i][j] == 0.0) continue;
270 if (rng.uniform() < pSec[i][j] * (1 - wFac)) {
271 secondaryPositions.push_back(x);
272 secondaryPackets.
273 push_back(loss.drawSecondary(gd, packet, t, wSec / wFac,
274 (lossMech::mechType) i,
275 (partTypes::pType) j));
276 }
277 }
278 }
279
280 // Step 8: compute effective velocities for position update
281 Real vT = xDrift[0]
282 + std::sqrt( 2 * pd.kPar / dtStep) * rng.normal();
283 Real vN = xDrift[1] +
284 std::sqrt( 2 * pd.kPerp / dtStep ) * rng.normal();
285 Real vB = xDrift[2] +
286 + std::sqrt( 2 * pd.kPerp / dtStep ) * rng.normal();
287 Real vMag = gd.v.mag() + std::sqrt( vT*vT + vN*vN + vB*vB );
288
289 // Step 9: update packet position; this may require several
290 // sub-cycles to ensure field lines are followed within the
291 // required tolerance
292 {
293
294 // Initial number of substeps; for gas descriptors that have
295 // ghost zones, ensure that this is small enough that we
296 // cannot move outside the ghost region in a single time step
297 int nDiv = 1;
298 if (gasBG.dxGhost() > 0.0) {
299 while (dtStep * vMag > nDiv * gasBG.dxGhost()) nDiv *= 2;
300 }
301
302 // Save starting position and time
303 RealVec xSave = x;
304
305 // Try to advance through substeps
306 bool success = false;
307 while (!success) {
308
309 // Step substep size for this attempt
310 Real dtTmp = dtStep / nDiv;
311 success = true;
312
313 // Save position at beginning of substep
314 RealVec xInit = x;
315
316 // Advance through substeps; at each substep, recompute the
317 // comoving TNB frame, then move the packet, including applying
318 // periodic or reflecting boundary conditions as needed; we then
319 // check if the accumulated error is acceptably small at the
320 // end
321 Real err2 = 0.0;
322 for (int n=0; n<nDiv; n++) {
323
324 // Stage 1
325 RealVec vCom;
326 gasBG.frame(x, t + dtTmp * n, vCom, b);
327 RealVec k1 = vCom + vT*b.eT + vN*b.eN + vB*b.eB;
328 x = xInit + dtTmp * rkf::ah[0] * k1;
329 geom.applyBC(x
330#ifdef TRACK_PITCH_ANGLE
331 , packet
332#endif
333 );
334
335 // Stage 2
336 gasBG.frame(x, t + dtTmp * (n + rkf::ah[0]), vCom, b);
337 RealVec k2 = vCom + vT*b.eT + vN*b.eN + vB*b.eB;
338 x = xInit + dtTmp * (rkf::b3[0] * k1 + rkf::b3[1] * k2);
339 geom.applyBC(x
340#ifdef TRACK_PITCH_ANGLE
341 , packet
342#endif
343 );
344
345 // Stage 3
346 gasBG.frame(x, t + dtTmp * (n + rkf::ah[1]), vCom, b);
347 RealVec k3 = vCom + vT*b.eT + vN*b.eN + vB*b.eB;
348 x = xInit + dtTmp * (rkf::b4[0] * k1 + rkf::b4[1] * k2 +
349 rkf::b4[2] * k3);
350 geom.applyBC(x
351#ifdef TRACK_PITCH_ANGLE
352 , packet
353#endif
354 );
355
356 // Stage 4
357 gasBG.frame(x, t + dtTmp * (n + rkf::ah[2]), vCom, b);
358 RealVec k4 = vCom + vT*b.eT + vN*b.eN + vB*b.eB;
359 x = xInit + dtTmp * (rkf::b5[0] * k1 + rkf::b5[1] * k2 +
360 rkf::b5[2] * k3 + rkf::b5[3] * k4);
361 geom.applyBC(x
362#ifdef TRACK_PITCH_ANGLE
363 , packet
364#endif
365 );
366
367 // Stage 5
368 gasBG.frame(x, t + dtTmp * (n + rkf::ah[3]), vCom, b);
369 RealVec k5 = vCom + vT*b.eT + vN*b.eN + vB*b.eB;
370 x = xInit + dtTmp * (rkf::b6[0] * k1 + rkf::b6[1] * k2 +
371 rkf::b6[2] * k3 + rkf::b6[3] * k4 +
372 rkf::b6[4] * k5);
373 geom.applyBC(x
374#ifdef TRACK_PITCH_ANGLE
375 , packet
376#endif
377 );
378
379 // Stage 6
380 gasBG.frame(x, t + dtTmp * (n + rkf::ah[4]), vCom, b);
381 RealVec k6 = vCom + vT*b.eT + vN*b.eN + vB*b.eB;
382 x = xInit + dtTmp * (rkf::c1 * k1 +
383 rkf::c3 * k3 +
384 rkf::c4 * k4 +
385 rkf::c5 * k5 +
386 rkf::c6 * k6);
387 geom.applyBC(x
388#ifdef TRACK_PITCH_ANGLE
389 , packet
390#endif
391 );
392
393 // Compute error on this step, add to total
394 err2 += (dtTmp/dx) * (dtTmp/dx) *
395 (rkf::ec[1] * k1 +
396 rkf::ec[3] * k3 +
397 rkf::ec[4] * k4 +
398 rkf::ec[5] * k5 +
399 rkf::ec[6] * k6).mag2();
400
401 // Check if we have exceeded error budget; if so, restore
402 // starting position and time, increase number of
403 // divisions, and try again
404 if (err2 > errTol * errTol) {
405 x = xSave;
406 nDiv *= 2;
407 success = false;
408 break;
409 }
410
411 // Check to ensure that packet is still in domain; if not,
412 // cease update and flag packet for deletion by flipping its
413 // weight negative
414 if (!geom.contains(x)) {
415 packet.w = -packet.w;
416 return t;
417 }
418 }
419 }
420 }
421
422 // Advance time
423 t += dtStep;
424
425 // Step 10: check if packet has fallen below minimum weight or
426 // momentum; if so, flag for deletion by flipping weight
427 // negative, and return
428 if (packet.w / packet.wInj < wFracMin ||
429 packet.p < pMin ||
430 packet.T() < TMin) {
431 packet.w = -packet.w;
432 return t;
433 }
434 }
435
436 // Return time
437 return t;
438 }
439
440}
441
442#endif
443// _ADANCEPACKET_H_
Class to hold data on a CR packet.
Define classes for field quantities and their gradients.
A class to describe the geometry of a calculation.
A class that holds data to describe a CR packet.
Definition CRPacket.H:28
Real tInj
Definition CRPacket.H:45
Real gr
Definition CRPacket.H:49
Real v() const
Velocity of packet.
Definition CRPacket.H:118
Real wInj
Definition CRPacket.H:46
Real T() const
Kinetic energy of packet.
Definition CRPacket.H:94
Real w
Definition CRPacket.H:48
partTypes::pType type
Definition CRPacket.H:42
Real p
Definition CRPacket.H:47
Class to hold and compute gradients of field quantities.
Definition FieldQty.H:293
Class to hold and compute field quantities.
Definition FieldQty.H:53
A class that describes the geometry of a calculation.
Definition Geometry.H:32
bool contains(const RealVec &x) const
Report if a specified point is in the problem domain.
Definition Geometry.H:245
void applyBC(RealVec &x) const
Apply boundary conditions to a packet.
Definition Geometry.H:124
Real contract(const RealVec &a, const RealVec &b) const
Compute the tensor contraction a_i b_j T_ij.
Definition RealTensor2.H:395
Real trace() const
Return the trace of this tensor.
Definition RealTensor2.H:449
Thread-safe random number generator.
Definition RngThread.H:39
Real uniform(const Real a=0.0, const Real b=1.0) const
Return a random number uniformly-distributed in (a,b)
Definition RngThread.H:66
Real normal(const Real mean=0.0, const Real stddev=1.0) const
Return a normally-distributed random number.
Definition RngThread.H:90
Real mag() const
Computes the magnitude of the vector.
Definition Vec3.H:470
auto dot(const Vec3< U > &a) const
Returns the dot product of this vector with another vector.
Definition Vec3.H:575
Trivial class to hold gas data.
Definition GasData.H:29
Real den
Definition GasData.H:36
RealVec v
Definition GasData.H:38
RealTensor2 vGrad
Definition GasData.H:44
Real dx
Definition GasData.H:33
RealVec B
Definition GasData.H:39
RealTensor2 BGrad
Definition GasData.H:45
Interface class to describe background gas.
Definition Gas.H:44
virtual void frame(const RealVec &x, const Real t, RealVec &v, TNBBasis &tnb) const
Compute the comoving TNB frame for the gas.
Definition Gas.H:67
virtual GasData gasData(const RealVec &x, const Real t) const =0
Return background gas state.
virtual Real dxGhost() const
Size of the ghost region in the gas data.
Definition Gas.H:107
Interface to describe the CR propagation model.
Definition Propagation.H:79
void applyLimits(const gas::GasData &gd, const CRPacket &packet, PropagationData &pd) const
Apply the Bohm limit and manually-set limits.
Definition Propagation.H:147
void haltRun(std::string msg, errCodes errcode)
Halt a run because an error has occurred.
Definition MPIUtil.cpp:287
static constexpr Real c
Definition Constants.H:34
pType
Enum of particle types.
Definition PartTypes.H:32
@ nPartType
Definition PartTypes.H:41
static constexpr Real ah[]
Definition RKF.H:20
static constexpr Real c6
Definition RKF.H:44
static constexpr Real b5[]
Definition RKF.H:28
static constexpr Real b3[]
Definition RKF.H:23
static constexpr Real c5
Definition RKF.H:42
static constexpr Real c1
Definition RKF.H:36
static constexpr Real ec[]
Definition RKF.H:45
static constexpr Real c3
Definition RKF.H:38
static constexpr Real c4
Definition RKF.H:40
static constexpr Real b6[]
Definition RKF.H:31
static constexpr Real b4[]
Definition RKF.H:25
The primary namespace for criptic objects.
Definition AdvancePacket.H:25
criptic::Real advancePacket(const criptic::Real tStart, const criptic::Real tStop, const criptic::Geometry &geom, const criptic::gas::Gas &gasBG, const criptic::propagation::Propagation &prop, const criptic::Losses &loss, const criptic::RngThread &rng, const criptic::FieldQty &qty, const criptic::FieldQtyGrad &qtyGrad, const criptic::Real cStep, const criptic::Real errTol, const criptic::Real wFracMin, const criptic::Real pMin, const criptic::Real TMin, const criptic::Real packetDtMin, const criptic::Real &h, criptic::RealVec &x, criptic::CRPacket &packet, criptic::Real &dt, std::vector< RealVec > &secondaryPositions, std::vector< CRPacket > &secondaryPackets)
Advance a packet by the specified time.
Definition AdvancePacket.H:61
@ errTimeStepTooSmall
Definition ErrCodes.H:39
TNBBasis TNBVectors(const RealVec &v, const RealTensor2 &vGrad)
Compute tangent, normal, and binormal vectors.
Definition RealTensor2.H:913
constexpr Real maxReal
Definition Types.H:49
double Real
Definition Types.H:38
Structure to hold TNB basis data.
Definition RealTensor2.H:898
RealVec eB
Definition RealTensor2.H:901
RealVec eN
Definition RealTensor2.H:900
RealVec eT
Definition RealTensor2.H:899
Structure contain the requires propagation parameters.
Definition Propagation.H:46
Real kPP
Definition Propagation.H:49
RealVec kParGrad
Definition Propagation.H:59
Real dvStr_dp
Definition Propagation.H:57
Real kPar
Definition Propagation.H:47
Real vStr
Definition Propagation.H:53
Real dkPP_dp
Definition Propagation.H:55
RealVec vStrGrad
Definition Propagation.H:66
RealVec kPerpGrad
Definition Propagation.H:61
Real kPerp
Definition Propagation.H:48