OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
CollimatorPhysics.cpp
Go to the documentation of this file.
1 // Class:CollimatorPhysics
2 // Defines the collimator physics models
3 // ------------------------------------------------------------------------
4 // Class category:
5 // ------------------------------------------------------------------------
6 // $Date: 2009/07/20 09:32:31 $
7 // $Author: Bi, Yang Stachel, Adelmann$
8 //-------------------------------------------------------------------------
10 #include "Physics/Physics.h"
11 #include "Physics/Material.h"
15 #include "AbsBeamline/Degrader.h"
16 #include "AbsBeamline/Drift.h"
17 #include "AbsBeamline/SBend.h"
18 #include "AbsBeamline/RBend.h"
19 #include "AbsBeamline/Multipole.h"
20 #include "Structure/LossDataSink.h"
21 #include "Utilities/Options.h"
23 #include "Utilities/Util.h"
24 #include "Utilities/Timer.h"
25 
26 #include "Ippl.h"
27 
28 #include <cmath>
29 #include <iostream>
30 #include <fstream>
31 #include <algorithm>
32 
33 #ifdef OPAL_DKS
34 const int CollimatorPhysics::numpar_m = 13;
35 #endif
36 
37 namespace {
38  struct DegraderInsideTester: public InsideTester {
39  explicit DegraderInsideTester(ElementBase * el) {
40  deg_m = static_cast<Degrader*>(el);
41  }
42  virtual
43  bool checkHit(const Vector_t &R, const Vector_t &P, double dt) override {
44  return deg_m->isInMaterial(R(2));
45  }
46 
47  private:
48  Degrader *deg_m;
49  };
50 
51  struct CollimatorInsideTester: public InsideTester {
52  explicit CollimatorInsideTester(ElementBase * el) {
53  col_m = static_cast<CCollimator*>(el);
54  }
55  virtual
56  bool checkHit(const Vector_t &R, const Vector_t &P, double dt) override {
57  return col_m->checkPoint(R(0), R(1));
58  }
59 
60  private:
61  CCollimator *col_m;
62  };
63 
64  struct FlexCollimatorInsideTester: public InsideTester {
65  explicit FlexCollimatorInsideTester(ElementBase * el) {
66  col_m = static_cast<FlexibleCollimator*>(el);
67  }
68  virtual
69  bool checkHit(const Vector_t &R, const Vector_t &P, double dt) override {
70  return col_m->isStopped(R, P, Physics::c * dt / sqrt(1.0 + dot(P, P)));
71  }
72 
73  private:
74  FlexibleCollimator *col_m;
75  };
76 }
77 
79  ElementBase *element,
80  std::string &material,
81  bool enableRutherford):
82  ParticleMatterInteractionHandler(name, element),
83  T_m(0.0),
84  dT_m(0.0),
85  material_m(material),
86  hitTester_m(nullptr),
87  Z_m(0),
88  A_m(0.0),
89  rho_m(0.0),
90  X0_m(0.0),
91  I_m(0.0),
92  A2_c(0.0),
93  A3_c(0.0),
94  A4_c(0.0),
95  A5_c(0.0),
96  bunchToMatStat_m(0),
97  stoppedPartStat_m(0),
98  rediffusedStat_m(0),
99  totalPartsInMat_m(0),
100  Eavg_m(0.0),
101  Emax_m(0.0),
102  Emin_m(0.0),
103  enableRutherford_m(enableRutherford)
104 #ifdef OPAL_DKS
105  , curandInitSet_m(0)
106  , ierr_m(0)
107  , maxparticles_m(0)
108  , numparticles_m(0)
109  , numlocalparts_m(0)
110  , par_ptr(NULL)
111  , mem_ptr(NULL)
112 #endif
113 {
114 
115  gsl_rng_env_setup();
116  rGen_m = gsl_rng_alloc(gsl_rng_default);
117 
118  size_t mySeed = Options::seed;
119 
120  if (Options::seed == -1) {
121  struct timeval tv;
122  gettimeofday(&tv,0);
123  mySeed = tv.tv_sec + tv.tv_usec;
124  }
125 
126  gsl_rng_set(rGen_m, mySeed + Ippl::myNode());
127 
129 
131  switch (collshape_m) {
133  hitTester_m.reset(new DegraderInsideTester(element_ref_m));
134  break;
136  hitTester_m.reset(new CollimatorInsideTester(element_ref_m));
137  break;
139  hitTester_m.reset(new FlexCollimatorInsideTester(element_ref_m));
140  break;
141  default:
142  throw OpalException("CollimatorPhysics::CollimatorPhysics",
143  "Unsupported element type");
144  }
145 
146  lossDs_m = std::unique_ptr<LossDataSink>(new LossDataSink(getName(), !Options::asciidump));
147 
148 #ifdef OPAL_DKS
149  if (IpplInfo::DKSEnabled) {
150  dksbase_m.setAPI("Cuda", 4);
151  dksbase_m.setDevice("-gpu", 4);
152  dksbase_m.initDevice();
153  curandInitSet_m = -1;
154  }
155 
156 #endif
157 
158  DegraderApplyTimer_m = IpplTimings::getTimer("DegraderApply");
159  DegraderLoopTimer_m = IpplTimings::getTimer("DegraderLoop");
160  DegraderDestroyTimer_m = IpplTimings::getTimer("DegraderDestroy");
161 }
162 
164  locParts_m.clear();
165  lossDs_m->save();
166  if (rGen_m)
167  gsl_rng_free(rGen_m);
168 
169 #ifdef OPAL_DKS
171  clearCollimatorDKS();
172 #endif
173 
174 }
175 
177  return element_ref_m->getName();
178 }
179 
181 // ------------------------------------------------------------------------
183 
185  Z_m = material->getAtomicNumber();
186  A_m = material->getAtomicMass();
187  rho_m = material->getMassDensity();
188  X0_m = material->getRadiationLength();
189  I_m = material->getMeanExcitationEnergy();
190  A2_c = material->getStoppingPowerFitCoefficients(Physics::Material::A2);
191  A3_c = material->getStoppingPowerFitCoefficients(Physics::Material::A3);
192  A4_c = material->getStoppingPowerFitCoefficients(Physics::Material::A4);
193  A5_c = material->getStoppingPowerFitCoefficients(Physics::Material::A5);
194 }
195 
197  const std::pair<Vector_t, double> &boundingSphere,
198  size_t numParticlesInSimulation) {
200 
201  /*
202  Particles that have entered material are flagged as Bin[i] == -1.
203 
204  Flagged particles are copied to a local structure within Collimator Physics locParts_m.
205 
206  Particles in that structure will be pushed in the material and either come
207  back to the bunch or will be fully stopped in the material.
208  */
209 
210  Eavg_m = 0.0;
211  Emax_m = 0.0;
212  Emin_m = 0.0;
213 
214  bunchToMatStat_m = 0;
215  rediffusedStat_m = 0;
216  stoppedPartStat_m = 0;
217  totalPartsInMat_m = 0;
218 
219  dT_m = bunch->getdT();
220  T_m = bunch->getT();
221 
222 #ifdef OPAL_DKS
224  applyDKS(bunch, boundingSphere, numParticlesInSimulation);
225  } else {
226  applyNonDKS(bunch, boundingSphere, numParticlesInSimulation);
227  }
228 #else
229  applyNonDKS(bunch, boundingSphere, numParticlesInSimulation);
230 #endif
231 
233 }
234 
236  const std::pair<Vector_t, double> &boundingSphere,
237  size_t numParticlesInSimulation) {
238  bool onlyOneLoopOverParticles = ! (allParticleInMat_m);
239 
240  do {
242  push();
244 
245  /*
246  if we are not looping copy newly arrived particles
247  */
248  if (onlyOneLoopOverParticles)
249  copyFromBunch(bunch, boundingSphere);
250 
251  addBackToBunch(bunch);
252 
254 
255  push();
256  resetTimeStep();
257 
259 
260  T_m += dT_m; // update local time
261 
263 
264  if (allParticleInMat_m) {
265  onlyOneLoopOverParticles = (rediffusedStat_m > 0 || totalPartsInMat_m <= 0);
266  } else {
267  onlyOneLoopOverParticles = true;
268  }
269  } while (onlyOneLoopOverParticles == false);
270 }
271 
273  /***
274  Do physics if
275  -- particle not stopped (locParts_m[i].label != -1.0)
276 
277  Absorbed particle i: locParts_m[i].label = -1.0;
278  */
279 
280  for (size_t i = 0; i < locParts_m.size(); ++i) {
281  if (locParts_m[i].label != -1) {
282  Vector_t &R = locParts_m[i].Rincol;
283  Vector_t &P = locParts_m[i].Pincol;
284  double &dt = locParts_m[i].DTincol;
285 
286  if (hitTester_m->checkHit(R, P, dt)) {
287  bool pdead = computeEnergyLoss(P, dt);
288  if (!pdead) {
289  /*
290  Now scatter and transport particle in material.
291  The checkHit call just above will detect if the
292  particle is rediffused from the material into vacuum.
293  */
294 
295  computeCoulombScattering(R, P, dt);
296  } else {
297  // The particle is stopped in the material, set label to -1
298  locParts_m[i].label = -1.0;
300  lossDs_m->addParticle(R, P, -locParts_m[i].IDincol);
301  }
302  }
303  }
304  }
305 
306  /*
307  delete absorbed particles
308  */
310 }
311 
317 // -------------------------------------------------------------------------
319  const double deltat,
320  bool includeFluctuations) const {
321 
322  constexpr double m2cm = 1e2;
323  constexpr double GeV2keV = 1e6;
324  constexpr double massElectron_keV = Physics::m_e * GeV2keV;
325  constexpr double massProton_keV = Physics::m_p * GeV2keV;
326  constexpr double massProton_amu = Physics::m_p / Physics::amu;
327  constexpr double chargeProton = Physics::z_p;
328  constexpr double K = 4.0 * Physics::pi * Physics::Avo * Physics::r_e * m2cm * Physics::r_e * m2cm * massElectron_keV;
329 
330  double gamma = Util::getGamma(P);
331  const double gammaSqr = std::pow(gamma, 2);
332  const double betaSqr = 1.0 - 1.0 / gammaSqr;
333  double beta = sqrt(betaSqr);
334  double Ekin = (gamma - 1) * massProton_keV;
335  double dEdx = 0.0;
336 
337  const double deltas = deltat * beta * Physics::c;
338  const double deltasrho = deltas * m2cm * rho_m;
339 
340  if (Ekin >= 600) {
341  constexpr double eV2keV = 1e-3;
342  constexpr double massRatio = Physics::m_e / Physics::m_p;
343  double Tmax = (2.0 * massElectron_keV * betaSqr * gammaSqr /
344  (std::pow(gamma + massRatio, 2) - (gammaSqr - 1.0)));
345 
346  dEdx = (-K * std::pow(chargeProton, 2) * Z_m / (A_m * betaSqr) *
347  (0.5 * std::log(2 * massElectron_keV * betaSqr * gammaSqr * Tmax / std::pow(I_m * eV2keV, 2)) - betaSqr));
348 
349  Ekin += deltasrho * dEdx;
350  } else if (Ekin > 10) {
351  const double Ts = Ekin / massProton_amu;
352  const double epsilon_low = A2_c * pow(Ts, 0.45);
353  const double epsilon_high = (A3_c / Ts) * log(1 + (A4_c / Ts) + (A5_c * Ts));
354  const double epsilon = (epsilon_low * epsilon_high) / (epsilon_low + epsilon_high);
355  dEdx = -epsilon / (1e18 * (A_m / Physics::Avo));
356 
357  Ekin += deltasrho * dEdx;
358  }
359 
360  if (includeFluctuations) {
361  double sigma_E = sqrt(K * massElectron_keV * rho_m * (Z_m / A_m) * deltas * m2cm);
362  Ekin += gsl_ran_gaussian(rGen_m, sigma_E);
363  }
364 
365  gamma = Ekin / massProton_keV + 1.0;
366  beta = sqrt(1.0 - 1.0 / std::pow(gamma, 2));
367  P = gamma * beta * P / euclidean_norm(P);
368 
369  bool stopped = (Ekin < 10 || dEdx > 0);
370  return stopped;
371 }
372 
373 
374 // Implement the rotation in 2 dimensions here
375 // For details see:
376 // J. Beringer et al. (Particle Data Group), "Passage of particles through matter"
377 // Phys. Rev. D 86, 010001 (2012),
379  Vector_t &R,
380  double shift,
381  double thetacou) {
382  // Calculate the angle between the transverse and longitudinal component of the momentum
383  double Psixz = std::fmod(std::atan2(P(0), P(2)) + Physics::two_pi, Physics::two_pi);
384 
385  R(0) = R(0) + shift * cos(Psixz);
386  R(2) = R(2) - shift * sin(Psixz);
387 
388  // Apply the rotation about the random angle thetacou
389  double Px = P(0);
390  P(0) = Px * cos(thetacou) + P(2) * sin(thetacou);
391  P(2) = -Px * sin(thetacou) + P(2) * cos(thetacou);
392 }
393 
395 
396  double thetaru = 2.5 / sqrt(gsl_rng_uniform(rGen_m)) * 2.0 * theta0;
397  double phiru = Physics::two_pi * gsl_rng_uniform(rGen_m);
398 
399  double normPtrans = sqrt(P(0) * P(0) + P(1) * P(1));
400  double Theta = std::atan(normPtrans / std::abs(P(2)));
401  double CosT = cos(Theta);
402  double SinT = sin(Theta);
403 
404  Vector_t X(cos(phiru)*sin(thetaru),
405  sin(phiru)*sin(thetaru),
406  cos(thetaru));
407  X *= euclidean_norm(P);
408 
409  Vector_t W(-P(1), P(0), 0.0);
410  W = W / normPtrans;
411 
412  // Rodrigues' formula for a rotation about W by angle Theta
413  P = X * CosT + cross(W, X) * SinT + W * dot(W, X) * (1.0 - CosT);
414 }
415 
418 //--------------------------------------------------------------------------
420  Vector_t &P,
421  double dt) {
422 
423  constexpr double GeV2eV = 1e9;
424  constexpr double massProton_eV = Physics::m_p * GeV2eV;
425  constexpr double chargeProton = Physics::z_p;
426  constexpr double sqrtThreeInv = 0.57735026918962576451; // sqrt(1.0 / 3.0)
427  const double normP = euclidean_norm(P);
428  const double gammaSqr = std::pow(normP, 2) + 1.0;
429  const double beta = sqrt(1.0 - 1.0 / gammaSqr);
430  const double deltas = dt * beta * Physics::c;
431  const double theta0 = (13.6e6 / (beta * normP * massProton_eV) *
432  chargeProton * sqrt(deltas / X0_m) *
433  (1.0 + 0.038 * log(deltas / X0_m)));
434 
435  double phi = Physics::two_pi * gsl_rng_uniform(rGen_m);
436  for (unsigned int i = 0; i < 2; ++ i) {
437  CoordinateSystemTrafo randomTrafo(R, Quaternion(cos(phi), 0, 0, sin(phi)));
438  P = randomTrafo.rotateTo(P);
439  R = Vector_t(0.0); // corresponds to randomTrafo.transformTo(R);
440 
441  double z1 = gsl_ran_gaussian(rGen_m, 1.0);
442  double z2 = gsl_ran_gaussian(rGen_m, 1.0);
443 
444  while(std::abs(z2) > 3.5) {
445  z1 = gsl_ran_gaussian(rGen_m, 1.0);
446  z2 = gsl_ran_gaussian(rGen_m, 1.0);
447  }
448 
449  double thetacou = z2 * theta0;
450  double shift = (z1 * sqrtThreeInv + z2) * deltas * theta0 * 0.5;
451  applyRotation(P, R, shift, thetacou);
452 
453  P = randomTrafo.rotateFrom(P);
454  R = randomTrafo.transformFrom(R);
455 
456  phi += 0.5 * Physics::pi;
457  }
458 
459  if (enableRutherford_m &&
460  gsl_rng_uniform(rGen_m) < 0.0047) {
461 
462  applyRandomRotation(P, theta0);
463  }
464 }
465 
467 
468  const size_t nL = locParts_m.size();
469  if (nL == 0) return;
470 
471  unsigned int numLocalParticles = bunch->getLocalNum();
472  const double elementLength = element_ref_m->getElementLength();
473 
474  for (size_t i = 0; i < nL; ++ i) {
475  Vector_t &R = locParts_m[i].Rincol;
476 
477  if (R[2] >= elementLength) {
478 
479  bunch->createWithID(locParts_m[i].IDincol);
480 
481  /*
482  Binincol is still <0, but now the particle is rediffused
483  from the material and hence this is not a "lost" particle anymore
484  */
485 
486  bunch->Bin[numLocalParticles] = 1;
487  bunch->R[numLocalParticles] = R;
488  bunch->P[numLocalParticles] = locParts_m[i].Pincol;
489  bunch->Q[numLocalParticles] = locParts_m[i].Qincol;
490  bunch->Bf[numLocalParticles] = 0.0;
491  bunch->Ef[numLocalParticles] = 0.0;
492  bunch->dt[numLocalParticles] = dT_m;
493 
494  /*
495  This particle is back to the bunch, by set
496  ting the label to -1.0
497  the particle will be deleted.
498  */
499  locParts_m[i].label = -1.0;
500 
501  ++ rediffusedStat_m;
502  ++ numLocalParticles;
503  }
504  }
505 
506  /*
507  delete particles that went to the bunch
508  */
510 }
511 
513  const std::pair<Vector_t, double> &boundingSphere)
514 {
515  const size_t nL = bunch->getLocalNum();
516  if (nL == 0) return;
517 
519  double zmax = boundingSphere.first(2) + boundingSphere.second;
520  double zmin = boundingSphere.first(2) - boundingSphere.second;
521  if (zmax < 0.0 || zmin > element_ref_m->getElementLength()) {
523  return;
524  }
525 
526  size_t ne = 0;
527  std::set<size_t> partsToDel;
528  const unsigned int minNumOfParticlesPerCore = bunch->getMinimumNumberOfParticlesPerCore();
529  for (size_t i = 0; i < nL; ++ i) {
530  if ((bunch->Bin[i] == -1 || bunch->Bin[i] == 1) &&
531  ((nL - ne) > minNumOfParticlesPerCore) &&
532  hitTester_m->checkHit(bunch->R[i], bunch->P[i], dT_m))
533  {
534  // adjust the time step for those particles that enter the material
535  // such that it corresponds to the time needed to reach the curren
536  // location form the edge of the material. Only use this time step
537  // for the computation of the interaction with the material, not for
538  // the integration of the particles. This will ensure that the momenta
539  // of all particles are reduced by approcimately the same amount in
540  // computeEnergyLoss.
541  double betaz = bunch->P[i](2) / Util::getGamma(bunch->P[i]);
542  double stepWidth = betaz * Physics::c * bunch->dt[i];
543  double tau = bunch->R[i](2) / stepWidth;
544 
545  PAssert_LE(tau, 1.0);
546  PAssert_GE(tau, 0.0);
547 
548  PART x;
549  x.localID = i;
550  x.DTincol = bunch->dt[i] * tau;
551  x.IDincol = bunch->ID[i];
552  x.Binincol = bunch->Bin[i];
553  x.Rincol = bunch->R[i];
554  x.Pincol = bunch->P[i];
555  x.Qincol = bunch->Q[i];
556  x.Bfincol = bunch->Bf[i];
557  x.Efincol = bunch->Ef[i];
558  x.label = 0; // alive in matter
559 
560  locParts_m.push_back(x);
561  ne++;
563 
564  partsToDel.insert(i);
565  }
566  }
567 
568  for (auto it = partsToDel.begin(); it != partsToDel.end(); ++ it) {
569  bunch->destroy(1, *it);
570  }
571 
572  if (ne > 0) {
573  bunch->performDestroy(true);
574  }
575 
577 }
578 
580  Inform::FmtFlags_t ff = msg.flags();
581 
582  if (totalPartsInMat_m > 0 ||
583  bunchToMatStat_m > 0 ||
584  rediffusedStat_m > 0 ||
585  stoppedPartStat_m > 0) {
586 
587  OPALTimer::Timer time;
588  msg << level2
589  << "--- CollimatorPhysics - Name " << element_ref_m->getName()
590  << " Material " << material_m << "\n"
591  << "Particle Statistics @ " << time.time() << "\n"
592  << std::setw(21) << "entered: " << Util::toStringWithThousandSep(bunchToMatStat_m) << "\n"
593  << std::setw(21) << "rediffused: " << Util::toStringWithThousandSep(rediffusedStat_m) << "\n"
594  << std::setw(21) << "stopped: " << Util::toStringWithThousandSep(stoppedPartStat_m) << "\n"
595  << std::setw(21) << "total in material: " << Util::toStringWithThousandSep(totalPartsInMat_m)
596  << endl;
597  }
598 
599  msg.flags(ff);
600 }
601 
603  return totalPartsInMat_m != 0;
604 }
605 
607 
608  bool degraderAlive = true;
609 
610  //free GPU memory in case element is degrader, it is empty and bunch has moved past it
612  Degrader *deg = static_cast<Degrader *>(element_ref_m);
613 
614  //get the size of the degrader
615  double zBegin, zEnd;
616  deg->getDimensions(zBegin, zEnd);
617 
618  //get the average Z position of the bunch
619  Vector_t bunchOrigin = bunch->get_origin();
620 
621  //if bunch has moved past degrader free GPU memory
622  if (bunchOrigin[2] > zBegin) {
623  degraderAlive = false;
624 #ifdef OPAL_DKS
626  clearCollimatorDKS();
627 #endif
628  }
629  }
630 
631  return degraderAlive;
632 
633 }
634 
635 namespace {
636  bool myCompF(PART x, PART y) {
637  return x.label > y.label;
638  }
639 }
640 
642  /*
643  the particle to be deleted (label < 0) are all at the end of
644  the vector.
645  */
646  sort(locParts_m.begin(), locParts_m.end(), myCompF);
647 
648  // find start of particles to delete
650 
651  for (; inv != locParts_m.end(); ++inv) {
652  if ((*inv).label == -1)
653  break;
654  }
655  locParts_m.erase(inv, locParts_m.end());
656  locParts_m.resize(inv - locParts_m.begin());
657 
658  // update statistics
659  if (locParts_m.size() > 0) {
660  Eavg_m /= locParts_m.size();
661  Emin_m /= locParts_m.size();
662  Emax_m /= locParts_m.size();
663  }
664 }
665 
667  for (size_t i = 0; i < locParts_m.size(); ++i) {
668  Vector_t &R = locParts_m[i].Rincol;
669  Vector_t &P = locParts_m[i].Pincol;
670  double gamma = Util::getGamma(P);
671 
672  R += 0.5 * dT_m * Physics::c * P / gamma;
673  }
674 }
675 
676 // adjust the time step for those particles that will rediffuse to
677 // vacuum such that it corresponds to the time needed to reach the
678 // end of the material. Only use this time step for the computation
679 // of the interaction with the material, not for the integration of
680 // the particles. This will ensure that the momenta of all particles
681 // are reduced by approcimately the same amount in computeEnergyLoss.
683  const double elementLength = element_ref_m->getElementLength();
684 
685  for (size_t i = 0; i < locParts_m.size(); ++i) {
686  Vector_t &R = locParts_m[i].Rincol;
687  Vector_t &P = locParts_m[i].Pincol;
688  double &dt = locParts_m[i].DTincol;
689  double gamma = Util::getGamma(P);
690  Vector_t stepLength = dT_m * Physics::c * P / gamma;
691 
692  if (R(2) < elementLength &&
693  R(2) + stepLength(2) > elementLength) {
694  // particle is likely to leave material
695  double distance = elementLength - R(2);
696  double tau = distance / stepLength(2);
697 
698  PAssert_LE(tau, 1.0);
699  PAssert_GE(tau, 0.0);
700 
701  dt *= tau;
702  }
703  }
704 }
705 
707  for (size_t i = 0; i < locParts_m.size(); ++i) {
708  double &dt = locParts_m[i].DTincol;
709  dt = dT_m;
710  }
711 
712 }
713 
714 
716 
717  unsigned int locPartsInMat;
718 #ifdef OPAL_DKS
720  locPartsInMat = numparticles_m + dksParts_m.size();
721  else
722  locPartsInMat = locParts_m.size();
723 #else
724  locPartsInMat = locParts_m.size();
725 #endif
726 
727  constexpr unsigned short numItems = 4;
728  unsigned int partStatistics[numItems] = {locPartsInMat,
732 
733  allreduce(&(partStatistics[0]), numItems, std::plus<unsigned int>());
734 
735  totalPartsInMat_m = partStatistics[0];
736  bunchToMatStat_m = partStatistics[1];
737  rediffusedStat_m = partStatistics[2];
738  stoppedPartStat_m = partStatistics[3];
739 }
740 
741 
742 #ifdef OPAL_DKS
743 
744 namespace {
745  bool myCompFDKS(PART_DKS x, PART_DKS y) {
746  return x.label > y.label;
747  }
748 }
749 
750 void CollimatorPhysics::applyDKS(PartBunchBase<double, 3> *bunch,
751  const std::pair<Vector_t, double> &boundingSphere,
752  size_t numParticlesInSimulation) {
753  bool onlyOneLoopOverParticles = ! (allParticleInMat_m);
754 
755  //if firs call to apply setup needed accelerator resources
756  setupCollimatorDKS(bunch, numParticlesInSimulation);
757 
758  do {
760 
761  //write particles to GPU if there are any to write
762  if (dksParts_m.size() > 0) {
763  //wrtie data from dksParts_m to the end of mem_ptr (offset = numparticles_m)
764  dksbase_m.writeDataAsync<PART_DKS>(mem_ptr, &dksParts_m[0],
765  dksParts_m.size(), -1, numparticles_m);
766 
767  //update number of particles on Device
768  numparticles_m += dksParts_m.size();
769 
770  //free locParts_m vector
771  dksParts_m.erase(dksParts_m.begin(), dksParts_m.end());
772  }
773 
774  //execute CollimatorPhysics kernels on GPU if any particles are there
775  if (numparticles_m > 0) {
776  dksbase_m.callCollimatorPhysics2(mem_ptr, par_ptr, numparticles_m);
777  }
778 
779  //sort device particles and get number of particles comming back to bunch
780  int numaddback = 0;
781  if (numparticles_m > 0) {
782  dksbase_m.callCollimatorPhysicsSort(mem_ptr, numparticles_m, numaddback);
783  }
784 
785  //read particles from GPU if any are comming out of material
786  if (numaddback > 0) {
787 
788  //resize dksParts_m to hold particles that need to go back to bunch
789  dksParts_m.resize(numaddback);
790 
791  //read particles that need to be added back to bunch
792  //particles that need to be added back are at the end of Device array
793  dksbase_m.readData<PART_DKS>(mem_ptr, &dksParts_m[0], numaddback,
794  numparticles_m - numaddback);
795 
796  //add particles back to the bunch
797  for (unsigned int i = 0; i < dksParts_m.size(); ++i) {
798  if (dksParts_m[i].label == -2) {
799  addBackToBunchDKS(bunch, i);
801  } else {
803  lossDs_m->addParticle(dksParts_m[i].Rincol, dksParts_m[i].Pincol,
804  -locParts_m[dksParts_m[i].localID].IDincol);
805  }
806  }
807 
808  //erase particles that came from device from host array
809  dksParts_m.erase(dksParts_m.begin(), dksParts_m.end());
810 
811  //update number of particles on Device
812  numparticles_m -= numaddback;
813  }
814 
816 
817  if (onlyOneLoopOverParticles)
818  copyFromBunchDKS(bunch, boundingSphere);
819 
820  T_m += dT_m;
821 
823 
824  //more than one loop only if all the particles are in this degrader
825  if (allParticleInMat_m) {
826  onlyOneLoopOverParticles = (totalPartsInMat_m <= 0);
827  } else {
828  onlyOneLoopOverParticles = true;
829  }
830 
831  } while (onlyOneLoopOverParticles == false);
832 }
833 
834 void CollimatorPhysics::addBackToBunchDKS(PartBunchBase<double, 3> *bunch, unsigned i) {
835 
836  int id = dksParts_m[i].localID;
837 
838  bunch->createWithID(locParts_m[id].IDincol);
839 
840  /*
841  Binincol is still <0, but now the particle is rediffused
842  from the material and hence this is not a "lost" particle anymore
843  */
844  unsigned int last = bunch->getLocalNum() - 1;
845  bunch->Bin[last] = 1;
846 
847  bunch->R[last] = dksParts_m[i].Rincol;
848  bunch->P[last] = dksParts_m[i].Pincol;
849 
850  bunch->Q[last] = locParts_m[id].Qincol;
851  bunch->Bf[last] = locParts_m[id].Bfincol;
852  bunch->Ef[last] = locParts_m[id].Efincol;
853  bunch->dt[last] = locParts_m[id].DTincol;
854 
855  dksParts_m[i].label = -1.0;
856 
857  ++ rediffusedStat_m;
858 
859 }
860 
861 void CollimatorPhysics::copyFromBunchDKS(PartBunchBase<double, 3> *bunch,
862  const std::pair<Vector_t, double> &boundingSphere)
863 {
864  const size_t nL = bunch->getLocalNum();
865  if (nL == 0) return;
866 
868  double zmax = boundingSphere.first(2) + boundingSphere.second;
869  double zmin = boundingSphere.first(2) - boundingSphere.second;
870  if (zmax < 0.0 || zmin > element_ref_m->getElementLength()) {
872  return;
873  }
874 
875  size_t ne = 0;
876  const unsigned int minNumOfParticlesPerCore = bunch->getMinimumNumberOfParticlesPerCore();
877 
878  for (unsigned int i = 0; i < nL; ++i) {
879  if ((bunch->Bin[i] == -1 || bunch->Bin[i] == 1) &&
880  ((nL - ne) > minNumOfParticlesPerCore) &&
881  hitTester_m->checkHit(bunch->R[i], bunch->P[i], dT_m))
882  {
883 
884  PART x;
885  x.localID = numlocalparts_m; //unique id for each particle
886  x.DTincol = bunch->dt[i];
887  x.IDincol = bunch->ID[i];
888  x.Binincol = bunch->Bin[i];
889  x.Rincol = bunch->R[i];
890  x.Pincol = bunch->P[i];
891  x.Qincol = bunch->Q[i];
892  x.Bfincol = bunch->Bf[i];
893  x.Efincol = bunch->Ef[i];
894  x.label = 0; // alive in matter
895 
896  PART_DKS x_gpu;
897  x_gpu.label = x.label;
898  x_gpu.localID = x.localID;
899  x_gpu.Rincol = x.Rincol;
900  x_gpu.Pincol = x.Pincol;
901 
902  locParts_m.push_back(x);
903  dksParts_m.push_back(x_gpu);
904 
905  ne++;
907  numlocalparts_m++;
908 
909  //mark particle to be deleted from bunch as soon as it enters the material
910  bunch->destroy(1, i);
911  }
912  }
913  if (ne > 0) {
914  bunch->performDestroy(true);
915  }
917 
918 }
919 
920 void CollimatorPhysics::setupCollimatorDKS(PartBunchBase<double, 3> *bunch,
921  size_t numParticlesInSimulation)
922 {
923 
924  if (curandInitSet_m == -1) {
925 
926  //int size = bunch->getLocalNum() + 0.5 * bunch->getLocalNum();
927  //int size = bunch->getTotalNum() + 0.5 * bunch->getTotalNum();
928  int size = numParticlesInSimulation;
929 
930  //allocate memory for parameters
931  par_ptr = dksbase_m.allocateMemory<double>(numpar_m, ierr_m);
932 
933  //allocate memory for particles
934  mem_ptr = dksbase_m.allocateMemory<PART_DKS>((int)size, ierr_m);
935 
936  maxparticles_m = (int)size;
937  numparticles_m = 0;
938  numlocalparts_m = 0;
939 
940  //reserve space for locParts_m vector
941  locParts_m.reserve(size);
942 
943  //init curand
944  dksbase_m.callInitRandoms(size, Options::seed);
945  curandInitSet_m = 1;
946 
947  //create and transfer parameter array
948  Degrader *deg = static_cast<Degrader *>(element_ref_m);
949  double zBegin, zEnd;
950  deg->getDimensions(zBegin, zEnd);
951 
952  double params[numpar_m] = {zBegin, zEnd, rho_m, Z_m,
953  A_m, A2_c, A3_c, A4_c, A5_c, X0_m, I_m, dT_m, 1e-4
954  };
955  dksbase_m.writeDataAsync<double>(par_ptr, params, numpar_m);
956 
957  }
958 
959 }
960 
961 void CollimatorPhysics::clearCollimatorDKS() {
962  if (curandInitSet_m == 1) {
963  dksbase_m.freeMemory<double>(par_ptr, numpar_m);
964  dksbase_m.freeMemory<PART_DKS>(mem_ptr, maxparticles_m);
965  curandInitSet_m = -1;
966  }
967 
968 }
969 
970 void CollimatorPhysics::deleteParticleFromLocalVectorDKS() {
971 
972  /*
973  the particle to be deleted (label < 0) are all at the end of
974  the vector.
975  */
976  sort(dksParts_m.begin(), dksParts_m.end(), myCompFDKS);
977 
978  // find start of particles to delete
980 
981  /*
982  for (; inv != dksParts_m.end(); inv++) {
983  if ((*inv).label == -1)
984  break;
985  }
986  */
987 
988  dksParts_m.erase(inv, dksParts_m.end());
989 
990 }
991 
992 #endif
int seed
The current random seed.
Definition: Options.cpp:41
std::unique_ptr< InsideTester > hitTester_m
ParticleAttrib< Vector_t > P
virtual bool isInMaterial(double z)
Definition: Degrader.cpp:82
double getT() const
CollimatorPhysics(const std::string &name, ElementBase *element, std::string &mat, bool enableRutherford)
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
std::string toStringWithThousandSep(T value, char sep= '\'')
Definition: Util.h:185
constexpr double e
The value of .
Definition: Physics.h:40
void destroy(size_t M, size_t I, bool doNow=false)
ParticleAttrib< Vector_t > Ef
IpplTimings::TimerRef DegraderDestroyTimer_m
Interface for basic beam line object.
Definition: ElementBase.h:128
void applyRotation(Vector_t &P, Vector_t &R, double xplane, double thetacou)
Definition: TSVMeta.h:24
Vector_t rotateTo(const Vector_t &r) const
unsigned int getMinimumNumberOfParticlesPerCore() const
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Definition: rbendmap.h:8
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
ParticleAttrib< double > Q
constexpr double two_pi
The value of .
Definition: Physics.h:34
void computeCoulombScattering(Vector_t &R, Vector_t &P, double dt)
std::vector< PART > locParts_m
double getdT() const
IpplTimings::TimerRef DegraderApplyTimer_m
constexpr double m_p
The proton rest mass in GeV.
Definition: Physics.h:97
void apply(PartBunchBase< double, 3 > *bunch, const std::pair< Vector_t, double > &boundingSphere, size_t numParticlesInSimulation=0)
static bool DKSEnabled
Definition: IpplInfo.h:285
virtual void getDimensions(double &zBegin, double &zEnd) const
Definition: Degrader.cpp:193
Abstract collimator.
bool allParticleInMat_m
if all particles are in matter stay inside the particle matter interaction
static int myNode()
Definition: IpplInfo.cpp:794
Vector_t Bfincol
virtual const std::string & getName() const
Get element name.
Definition: ElementBase.cpp:95
std::unique_ptr< LossDataSink > lossDs_m
PETE_TBTree< OpNE, Index::PETE_Expr_t, PETE_Scalar< double > > ne(const Index &idx, double x)
Definition: IndexInlines.h:357
Tps< T > log(const Tps< T > &x)
Natural logarithm.
Definition: TpsMath.h:182
bool isStopped(const Vector_t &R, const Vector_t &P, double recpgamma)
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
virtual ElementType getType() const =0
Get element type std::string.
T deg(T x)
Convert radians to degrees.
Definition: matheval.hpp:82
#define PAssert_LE(a, b)
Definition: PAssert.h:122
constexpr double r_e
The classical electron radius in m.
Definition: Physics.h:88
unsigned localID
bool stillAlive(PartBunchBase< double, 3 > *bunch)
constexpr double m_e
The electron rest mass in GeV.
Definition: Physics.h:85
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
double Qincol
Vector_t Pincol
unsigned int stoppedPartStat_m
#define PAssert_GE(a, b)
Definition: PAssert.h:124
double getGamma(Vector_t p)
Definition: Util.h:24
IpplTimings::TimerRef DegraderLoopTimer_m
ParticleIndex_t & ID
FmtFlags_t flags() const
Definition: Inform.h:109
constexpr double pi
The value of .
Definition: Physics.h:31
virtual double getElementLength() const
Get design length.
Definition: ElementBase.h:511
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
PETE_TUTree< FnArcTan, typename T::PETE_Expr_t > atan(const PETE_Expr< T > &l)
Definition: PETE.h:810
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:52
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
Definition: Vector3D.cpp:111
Interface for cyclotron collimator.
Definition: CCollimator.h:13
unsigned int rediffusedStat_m
static void startTimer(TimerRef t)
Definition: IpplTimings.h:187
void print(Inform &os)
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
unsigned int bunchToMatStat_m
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
Vector_t get_origin() const
PETE_TBTree< FnFmod, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > fmod(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
size_t getLocalNum() const
Vector_t Rincol
long IDincol
void applyRandomRotation(Vector_t &P, double theta0)
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
ParticleAttrib< double > dt
void configureMaterialParameters()
The material of the collimator.
void performDestroy(bool updateLocalNum=false)
bool asciidump
Definition: Options.cpp:18
std::string time() const
Return time.
Definition: Timer.cpp:42
void createWithID(unsigned id)
double DTincol
unsigned int totalPartsInMat_m
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
Abstract collimator.
Definition: Degrader.h:37
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition: Vector.h:243
ElementBase::ElementType collshape_m
static std::shared_ptr< Material > getMaterial(const std::string &name)
Definition: Material.cpp:36
Vector_t rotateFrom(const Vector_t &r) const
const std::string name
constexpr double amu
The atomic mass unit energy equivalent in GeV.
Definition: Physics.h:82
ParticleAttrib< int > Bin
std::ios_base::fmtflags FmtFlags_t
Definition: Inform.h:101
ParticleAttrib< Vector_t > Bf
ParticlePos_t & R
std::string::iterator iterator
Definition: MSLang.h:16
constexpr double z_p
The charge of proton.
Definition: Physics.h:109
static TimerRef getTimer(const char *nm)
Definition: IpplTimings.h:182
void applyNonDKS(PartBunchBase< double, 3 > *bunch, const std::pair< Vector_t, double > &boundingSphere, size_t numParticlesInSimulation)
Vector_t Efincol
static void stopTimer(TimerRef t)
Definition: IpplTimings.h:192
#define K
Definition: integrate.cpp:118
constexpr double Avo
The Avogadro&#39;s number.
Definition: Physics.h:64
Definition: Inform.h:41
int checkPoint(const double &x, const double &y) const
Checks if coordinate is within element.
void addBackToBunch(PartBunchBase< double, 3 > *bunch)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
void copyFromBunch(PartBunchBase< double, 3 > *bunch, const std::pair< Vector_t, double > &boundingSphere)
virtual bool computeEnergyLoss(Vector_t &P, const double deltat, bool includeFluctuations=true) const
Vector_t transformFrom(const Vector_t &r) const