OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
ParallelTTracker.cpp
Go to the documentation of this file.
1 //
2 // Class ParallelTTracker
3 // OPAL-T tracker.
4 // The visitor class for tracking particles with time as independent
5 // variable.
6 //
7 // Copyright (c) 200x - 2014, Christof Kraus, Paul Scherrer Institut, Villigen PSI, Switzerland
8 // 2015 - 2016, Christof Metzger-Kraus, Helmholtz-Zentrum Berlin, Germany
9 // 2017 - 2020, Christof Metzger-Kraus
10 // All rights reserved
11 //
12 // This file is part of OPAL.
13 //
14 // OPAL is free software: you can redistribute it and/or modify
15 // it under the terms of the GNU General Public License as published by
16 // the Free Software Foundation, either version 3 of the License, or
17 // (at your option) any later version.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
21 //
23 
24 #include <cfloat>
25 #include <cmath>
26 #include <fstream>
27 #include <limits>
28 #include <iomanip>
29 #include <iostream>
30 #include <sstream>
31 #include <string>
32 
33 #include "AbsBeamline/Monitor.h"
37 #include "BasicActions/Option.h"
38 #ifdef ENABLE_OPAL_FEL
40 #endif
41 #include "Beamlines/Beamline.h"
44 #include "Elements/OpalBeamline.h"
45 #include "Physics/Units.h"
49 #include "Structure/BoundingBox.h"
51 #include "Utilities/Options.h"
52 #include "Utilities/Timer.h"
53 #include "Utilities/Util.h"
55 
56 extern Inform* gmsg;
57 
58 class PartData;
59 
61  const PartData &reference,
62  bool revBeam,
63  bool revTrack):
64  Tracker(beamline, reference, revBeam, revTrack),
65  itsDataSink_m(nullptr),
66  itsOpalBeamline_m(beamline.getOrigin3D(), beamline.getInitialDirection()),
67  globalEOL_m(false),
68  wakeStatus_m(false),
69  wakeFunction_m(nullptr),
70  pathLength_m(0.0),
71  zstart_m(0.0),
72  dtCurrentTrack_m(0.0),
73  minStepforReBin_m(-1),
74  minBinEmitted_m(std::numeric_limits<size_t>::max()),
75  repartFreq_m(-1),
76  emissionSteps_m(std::numeric_limits<unsigned int>::max()),
77  numParticlesInSimulation_m(0),
78  timeIntegrationTimer1_m(IpplTimings::getTimer("TIntegration1")),
79  timeIntegrationTimer2_m(IpplTimings::getTimer("TIntegration2")),
80  fieldEvaluationTimer_m(IpplTimings::getTimer("External field eval")),
81  BinRepartTimer_m(IpplTimings::getTimer("Binaryrepart")),
82  WakeFieldTimer_m(IpplTimings::getTimer("WakeField")),
83  particleMatterStatus_m(false)
84 {}
85 
88  DataSink &ds,
89  const PartData &reference,
90  bool revBeam,
91  bool revTrack,
92  const std::vector<unsigned long long> &maxSteps,
93  double zstart,
94  const std::vector<double> &zstop,
95  const std::vector<double> &dt):
96  Tracker(beamline, bunch, reference, revBeam, revTrack),
97  itsDataSink_m(&ds),
98  itsOpalBeamline_m(beamline.getOrigin3D(), beamline.getInitialDirection()),
99  globalEOL_m(false),
100  wakeStatus_m(false),
101  wakeFunction_m(nullptr),
102  pathLength_m(0.0),
103  zstart_m(zstart),
104  dtCurrentTrack_m(0.0),
105  minStepforReBin_m(-1),
106  minBinEmitted_m(std::numeric_limits<size_t>::max()),
107  repartFreq_m(-1),
108  emissionSteps_m(std::numeric_limits<unsigned int>::max()),
109  numParticlesInSimulation_m(0),
110  timeIntegrationTimer1_m(IpplTimings::getTimer("TIntegration1")),
111  timeIntegrationTimer2_m(IpplTimings::getTimer("TIntegration2")),
112  fieldEvaluationTimer_m(IpplTimings::getTimer("External field eval")),
113  BinRepartTimer_m(IpplTimings::getTimer("Binaryrepart")),
114  WakeFieldTimer_m(IpplTimings::getTimer("WakeField")),
115  particleMatterStatus_m(false)
116 {
117  for (unsigned int i = 0; i < zstop.size(); ++ i) {
118  stepSizes_m.push_back(dt[i], zstop[i], maxSteps[i]);
119  }
120 
123 }
124 
126 
128  const FlaggedBeamline* fbl = static_cast<const FlaggedBeamline*>(&bl);
129  if (fbl->getRelativeFlag()) {
130  OpalBeamline stash(fbl->getOrigin3D(), fbl->getInitialDirection());
131  stash.swap(itsOpalBeamline_m);
132  fbl->iterate(*this, false);
135  stash.merge(itsOpalBeamline_m);
136  stash.swap(itsOpalBeamline_m);
137  } else {
138  fbl->iterate(*this, false);
139  }
140 }
141 
142 void ParallelTTracker::updateRFElement(std::string elName, double maxPhase) {
145  cavities.insert(cavities.end(), travelingwaves.begin(), travelingwaves.end());
146 
147  for (FieldList::iterator fit = cavities.begin(); fit != cavities.end(); ++ fit) {
148  if ((*fit).getElement()->getName() == elName) {
149 
150  RFCavity *element = static_cast<RFCavity *>((*fit).getElement().get());
151 
152  element->setPhasem(maxPhase);
153  element->setAutophaseVeto();
154 
155  INFOMSG("Restored cavity phase from the h5 file. Name: " << element->getName() << ", phase: " << maxPhase << " rad" << endl);
156  return;
157  }
158  }
159 }
160 
163 }
164 
167 
168  if (OpalData::getInstance()->hasPriorTrack() ||
169  OpalData::getInstance()->inRestartRun()) {
170  iterator_t it = OpalData::getInstance()->getFirstMaxPhases();
171  iterator_t end = OpalData::getInstance()->getLastMaxPhases();
172  for (; it < end; ++ it) {
173  updateRFElement((*it).first, (*it).second);
174  }
175  }
176 }
177 
179  Inform msg("ParallelTTracker ", *gmsg);
181 
182  BorisPusher pusher(itsReference);
183  const double globalTimeShift = itsBunch_m->weHaveEnergyBins()? OpalData::getInstance()->getGlobalPhaseShift(): 0.0;
185 
186  // the time step needs to be positive in the setup
189 
191 
192  if (OpalData::getInstance()->hasPriorTrack() || OpalData::getInstance()->inRestartRun()) {
194  }
195 
196  prepareSections();
197 
198  double minTimeStep = stepSizes_m.getMinTimeStep();
199 
201 
202  if ( OpalData::getInstance()->hasPriorTrack() ||
203  OpalData::getInstance()->inRestartRun()) {
204 
207 
209  } else {
210 
211  double momentum = euclidean_norm(itsBunch_m->get_pmean_Distribution());
213  itsBunch_m->toLabTrafo_m = beamlineToLab;
214 
215  itsBunch_m->RefPartR_m = beamlineToLab.transformTo(Vector_t(0.0));
216  itsBunch_m->RefPartP_m = beamlineToLab.rotateTo(momentum * Vector_t(0, 0, 1));
217 
218  if (itsBunch_m->getTotalNum() > 0) {
220  momentum = itsReference.getP() / itsBunch_m->getM();
221  itsBunch_m->RefPartP_m = beamlineToLab.rotateTo(momentum * Vector_t(0, 0, 1));
222  }
223 
224  if (zstart_m > pathLength_m) {
225  findStartPosition(pusher);
226  }
227 
229  }
230  }
231 
233  if (back_track) {
237  ++ stepSizes_m;
238  }
239  }
240 
241  Vector_t rmin(0.0), rmax(0.0);
242  if (itsBunch_m->getTotalNum() > 0) {
243  itsBunch_m->get_bounds(rmin, rmax);
244  }
245 
249  pathLength_m,
250  -rmin(2),
251  itsBunch_m->getT(),
252  (back_track? -minTimeStep: minTimeStep),
253  stepSizes_m,
255 
256  oth.execute();
257  BoundingBox globalBoundingBox = oth.getBoundingBox();
258 
260 
262 
263  setTime();
264 
265  double time = itsBunch_m->getT() - globalTimeShift;
266  itsBunch_m->setT(time);
267 
268  *gmsg << level1 << *itsBunch_m << endl;
269 
270  unsigned long long step = itsBunch_m->getGlobalTrackStep();
271  OPALTimer::Timer myt1;
272  *gmsg << "* Track start at: " << myt1.time() << ", t= " << Util::getTimeString(time) << "; "
273  << "zstart at: " << Util::getLengthString(pathLength_m)
274  << endl;
275 
276  prepareEmission();
277 
278  *gmsg << "* Executing ParallelTTracker\n"
279  << "* Initial dt = " << Util::getTimeString(itsBunch_m->getdT()) << "\n"
280  << "* Max integration steps = " << stepSizes_m.getMaxSteps()
281  << ", next step = " << step << endl << endl;
282 
284 
285  globalEOL_m = false;
286  wakeStatus_m = false;
287  deletedParticles_m = false;
289  while (!stepSizes_m.reachedEnd()) {
290  unsigned long long trackSteps = stepSizes_m.getNumSteps() + step;
293 
294  for (; step < trackSteps; ++ step) {
295  Vector_t rmin(0.0), rmax(0.0);
296  if (itsBunch_m->getTotalNum() > 0) {
297  itsBunch_m->get_bounds(rmin, rmax);
298  }
299 
300  timeIntegration1(pusher);
301 
302  itsBunch_m->Ef = Vector_t(0.0);
303  itsBunch_m->Bf = Vector_t(0.0);
304 
306 
308  emitParticles(step);
310 
312 
313  timeIntegration2(pusher);
314 
316 
317  if (itsBunch_m->getT() > 0.0 ||
318  itsBunch_m->getdT() < 0.0) {
319  updateReference(pusher);
320  }
321 
322  if (deletedParticles_m) {
324  deletedParticles_m = false;
325  }
327 
328  if (hasEndOfLineReached(globalBoundingBox)) break;
329 
330  bool const psDump = ((itsBunch_m->getGlobalTrackStep() % Options::psDumpFreq) + 1 == Options::psDumpFreq);
331  bool const statDump = ((itsBunch_m->getGlobalTrackStep() % Options::statDumpFreq) + 1 == Options::statDumpFreq);
332  dumpStats(step, psDump, statDump);
333 
335 
337  double driftPerTimeStep = std::abs(itsBunch_m->getdT()) * Physics::c * beta;
338  if (std::abs(stepSizes_m.getZStop() - pathLength_m) < 0.5 * driftPerTimeStep) {
339  break;
340  }
341  }
342 
343  if (globalEOL_m)
344  break;
345 
346  ++ stepSizes_m;
347  }
348 
350 
353  }
354 
355  bool const psDump = (((itsBunch_m->getGlobalTrackStep() - 1) % Options::psDumpFreq) + 1 != Options::psDumpFreq);
356  bool const statDump = (((itsBunch_m->getGlobalTrackStep() - 1) % Options::statDumpFreq) + 1 != Options::statDumpFreq);
357  writePhaseSpace((step + 1), psDump, statDump);
358 
359  msg << level2 << "Dump phase space of last step" << endl;
360 
362 
363  OPALTimer::Timer myt3;
364  *gmsg << endl << "* Done executing ParallelTTracker at "
365  << myt3.time() << endl << endl;
366 
368 
370 }
371 
373 
374  itsBeamline_m.accept(*this);
375 
377 
381 }
382 
384 
386  pushParticles(pusher);
388 }
389 
390 
392  /*
393  transport and emit particles
394  that passed the cathode in the first
395  half-step or that would pass it in the
396  second half-step.
397 
398  to make IPPL and the field solver happy
399  make sure that at least 10 particles are emitted
400 
401  also remember that node 0 has
402  all the particles to be emitted
403 
404  this has to be done *after* the calculation of the
405  space charges! thereby we neglect space charge effects
406  in the very first step of a new-born particle.
407 
408  */
409 
411  kickParticles(pusher);
412  //switchElements();
413  pushParticles(pusher);
414 
415  const unsigned int localNum = itsBunch_m->getLocalNum();
416  for (unsigned int i = 0; i < localNum; ++ i) {
417  itsBunch_m->dt[i] = itsBunch_m->getdT();
418  }
419 
421 }
422 
423 void ParallelTTracker::selectDT(bool backTrack) {
424 
425  if (itsBunch_m->getIfBeamEmitting()) {
426  double dt = itsBunch_m->getEmissionDeltaT();
427  itsBunch_m->setdT(dt);
428  } else {
429  double dt = dtCurrentTrack_m;
430  itsBunch_m->setdT(dt);
431  }
432  if (backTrack) {
434  }
435 }
436 
437 void ParallelTTracker::changeDT(bool backTrack) {
438  selectDT(backTrack);
439  const unsigned int localNum = itsBunch_m->getLocalNum();
440  for (unsigned int i = 0; i < localNum; ++ i) {
441  itsBunch_m->dt[i] = itsBunch_m->getdT();
442  }
443 }
444 
445 void ParallelTTracker::emitParticles(long long step) {
446  if (!itsBunch_m->weHaveEnergyBins()) return;
447 
448  if (itsBunch_m->getIfBeamEmitting()) {
451 
452  transformBunch(refToGun);
453 
455 
456  Vector_t externalE = Vector_t(0.0);
457  Vector_t externalB = Vector_t(0.0);
459  gunToLab.rotateTo(Vector_t(0.0)),
460  itsBunch_m->getT() + 0.5 * itsBunch_m->getdT(),
461  externalE,
462  externalB);
463  itsBunch_m->emitParticles(externalE(2));
464 
468 
469  transformBunch(refToGun.inverted());
470  }
471 
472  if (step > minStepforReBin_m) {
473  itsBunch_m->Rebin();
475  }
476 }
477 
478 
479 void ParallelTTracker::computeSpaceChargeFields(unsigned long long step) {
480  if (numParticlesInSimulation_m <= minBinEmitted_m || !itsBunch_m->hasFieldSolver()) {
481  return;
482  }
483 
485  Quaternion alignment = getQuaternion(itsBunch_m->get_pmean(), Vector_t(0, 0, 1));
486  CoordinateSystemTrafo beamToReferenceCSTrafo(Vector_t(0, 0, pathLength_m), alignment.conjugate());
487  CoordinateSystemTrafo referenceToBeamCSTrafo = beamToReferenceCSTrafo.inverted();
488  const unsigned int localNum1 = itsBunch_m->getLocalNum();
489  for (unsigned int i = 0; i < localNum1; ++ i) {
490  itsBunch_m->R[i] = referenceToBeamCSTrafo.transformTo(itsBunch_m->R[i]);
491  }
492 
493  itsBunch_m->boundp();
494 
495  if (step % repartFreq_m + 1 == repartFreq_m) {
497  }
498 
499  if (itsBunch_m->weHaveEnergyBins()) {
503  for (int binNumber = 0; binNumber < itsBunch_m->getLastEmittedEnergyBin() &&
504  binNumber < itsBunch_m->getNumberOfEnergyBins(); ++binNumber) {
505 
506  itsBunch_m->setBinCharge(binNumber);
508  itsBunch_m->computeSelfFields(binNumber);
509  itsBunch_m->Q = Q_back;
510 
511  }
512 
513  } else {
516  }
517 
518  const unsigned int localNum2 = itsBunch_m->getLocalNum();
519  for (unsigned int i = 0; i < localNum2; ++ i) {
520  itsBunch_m->R[i] = beamToReferenceCSTrafo.transformTo(itsBunch_m->R[i]);
521  itsBunch_m->Ef[i] = beamToReferenceCSTrafo.rotateTo(itsBunch_m->Ef[i]);
522  itsBunch_m->Bf[i] = beamToReferenceCSTrafo.rotateTo(itsBunch_m->Bf[i]);
523  }
524 }
525 
526 
529  Inform msg("ParallelTTracker ", *gmsg);
530  const unsigned int localNum = itsBunch_m->getLocalNum();
531  bool locPartOutOfBounds = false, globPartOutOfBounds = false;
532  Vector_t rmin(0.0), rmax(0.0);
533  if (itsBunch_m->getTotalNum() > 0)
534  itsBunch_m->get_bounds(rmin, rmax);
536 
537  try {
538  elements = oth.query(pathLength_m + 0.5 * (rmax(2) + rmin(2)), rmax(2) - rmin(2));
539  } catch(IndexMap::OutOfBounds &e) {
540  globalEOL_m = true;
541  return;
542  }
543 
544  IndexMap::value_t::const_iterator it = elements.begin();
545  const IndexMap::value_t::const_iterator end = elements.end();
546 
547  for (; it != end; ++ it) {
548  CoordinateSystemTrafo refToLocalCSTrafo = (itsOpalBeamline_m.getMisalignment((*it)) *
550  CoordinateSystemTrafo localToRefCSTrafo = refToLocalCSTrafo.inverted();
551 
552  (*it)->setCurrentSCoordinate(pathLength_m + rmin(2));
553 
554  for (unsigned int i = 0; i < localNum; ++ i) {
555  if (itsBunch_m->Bin[i] < 0) continue;
556 
557  itsBunch_m->R[i] = refToLocalCSTrafo.transformTo(itsBunch_m->R[i]);
558  itsBunch_m->P[i] = refToLocalCSTrafo.rotateTo(itsBunch_m->P[i]);
559  double &dt = itsBunch_m->dt[i];
560 
561  Vector_t localE(0.0), localB(0.0);
562 
563  if ((*it)->apply(i, itsBunch_m->getT() + 0.5 * dt, localE, localB)) {
564  itsBunch_m->R[i] = localToRefCSTrafo.transformTo(itsBunch_m->R[i]);
565  itsBunch_m->P[i] = localToRefCSTrafo.rotateTo(itsBunch_m->P[i]);
566  itsBunch_m->Bin[i] = -1;
567  locPartOutOfBounds = true;
568 
569  continue;
570  }
571 
572  itsBunch_m->R[i] = localToRefCSTrafo.transformTo(itsBunch_m->R[i]);
573  itsBunch_m->P[i] = localToRefCSTrafo.rotateTo(itsBunch_m->P[i]);
574  itsBunch_m->Ef[i] += localToRefCSTrafo.rotateTo(localE);
575  itsBunch_m->Bf[i] += localToRefCSTrafo.rotateTo(localB);
576  }
577  }
578 
580 
581  computeWakefield(elements);
582 #ifdef ENABLE_OPAL_FEL
583  computeUndulator(elements);
584 #endif
585  computeParticleMatterInteraction(elements, oth);
586 
587  reduce(locPartOutOfBounds, globPartOutOfBounds, OpOrAssign());
588 
589  size_t ne = 0;
590  if (globPartOutOfBounds) {
591  if (itsBunch_m->hasFieldSolver()) {
592  ne = itsBunch_m->boundp_destroyT();
593  } else {
594  ne = itsBunch_m->destroyT();
595  }
597  deletedParticles_m = true;
598  }
599 
600  size_t totalNum = itsBunch_m->getTotalNum();
602  numParticlesInSimulation_m = totalNum;
603  }
604 
605  if (ne > 0) {
606  msg << level1 << "* Deleted " << ne << " particles, "
607  << "remaining " << numParticlesInSimulation_m << " particles" << endl;
608  }
609 }
610 
611 #ifdef ENABLE_OPAL_FEL
612 void ParallelTTracker::computeUndulator(IndexMap::value_t &elements) {
613  // Check if bunch has entered undulator field.
614  UndulatorRep* und;
615  IndexMap::value_t::const_iterator it = elements.begin();
616  for (; it != elements.end(); ++ it)
617  if ((*it)->getType() == ElementType::UNDULATOR) {
618  und = dynamic_cast<UndulatorRep*>(it->get());
619  if (!und->getHasBeenSimulated())
620  break;
621  }
622  if (it == elements.end())
623  return;
624 
625  // Apply MITHRA full wave solver for undulator.
626  CoordinateSystemTrafo refToLocalCSTrafo = (itsOpalBeamline_m.getMisalignment((*it)) *
628 
629  und->apply(itsBunch_m, refToLocalCSTrafo);
630 
632 }
633 #endif
634 
636  bool hasWake = false;
637  WakeFunction *wfInstance;
638 
639  Inform msg("ParallelTTracker ", *gmsg);
640 
641  const unsigned int localNum = itsBunch_m->getLocalNum();
642 
643  IndexMap::value_t::const_iterator it = elements.begin();
644  const IndexMap::value_t::const_iterator end = elements.end();
645 
646  for (; it != end; ++ it) {
647  if ((*it)->hasWake() && !hasWake) {
649 
650  hasWake = true;
651 
652  if ((*it)->getWake()->getType() == WakeType::CSRWakeFunction ||
653  (*it)->getWake()->getType() == WakeType::CSRIGFWakeFunction) {
654  if ((*it)->getType() == ElementType::RBEND ||
655  (*it)->getType() == ElementType::SBEND) {
656  wfInstance = (*it)->getWake();
657  wakeFunction_m = wfInstance;
658  } else {
659  wfInstance = wakeFunction_m;
660  }
661  } else {
662  wfInstance = (*it)->getWake();
663  }
664 
665  if (!wfInstance) {
666  throw OpalException("ParallelTTracker::computeWakefield",
667  "empty wake function");
668  }
669 
670  if (!wakeStatus_m) {
671  msg << level2 << "============== START WAKE CALCULATION =============" << endl;
672  wfInstance->initialize((*it).get());
673  wakeStatus_m = true;
674  }
675 
677 
678  Quaternion alignment = getQuaternion(itsBunch_m->get_pmean(), Vector_t(0, 0, 1));
679  CoordinateSystemTrafo referenceToBeamCSTrafo(Vector_t(0.0), alignment);
680  CoordinateSystemTrafo beamToReferenceCSTrafo = referenceToBeamCSTrafo.inverted();
681 
682  for (unsigned int i = 0; i < localNum; ++ i) {
683  itsBunch_m->R[i] = referenceToBeamCSTrafo.transformTo(itsBunch_m->R[i]);
684  itsBunch_m->P[i] = referenceToBeamCSTrafo.rotateTo(itsBunch_m->P[i]);
685  itsBunch_m->Ef[i] = referenceToBeamCSTrafo.rotateTo(itsBunch_m->Ef[i]);
686  }
687 
688  wfInstance->apply(itsBunch_m);
689 
690  for (unsigned int i = 0; i < localNum; ++ i) {
691  itsBunch_m->R[i] = beamToReferenceCSTrafo.transformTo(itsBunch_m->R[i]);
692  itsBunch_m->P[i] = beamToReferenceCSTrafo.rotateTo(itsBunch_m->P[i]);
693  itsBunch_m->Ef[i] = beamToReferenceCSTrafo.rotateTo(itsBunch_m->Ef[i]);
694  }
695 
697  }
698  }
699 
700  if (wakeStatus_m && !hasWake) {
701  msg << level2 << "=============== END WAKE CALCULATION ==============" << endl;
702  wakeStatus_m = false;
703  }
704 }
705 
707  Inform msg("ParallelTTracker ", *gmsg);
708  std::set<IndexMap::value_t::value_type> elementsWithParticleMatterInteraction;
709  std::set<ParticleMatterInteractionHandler*> particleMatterinteractionHandlers;
710  IndexMap::key_t currentRange{0.0, 0.0};
711 
712  while (elements.size() > 0) {
713  auto it = elements.begin();
714  if ((*it)->hasParticleMatterInteraction()) {
715  elementsWithParticleMatterInteraction.insert(*it);
716  particleMatterinteractionHandlers.insert((*it)->getParticleMatterInteraction());
717 
718  IndexMap::key_t range = oth.getRange(*it, pathLength_m);
719  currentRange.begin = std::min(currentRange.begin, range.begin);
720  currentRange.end = std::max(currentRange.end, range.end);
721 
722  IndexMap::value_t touching = oth.getTouchingElements(range);
723  elements.insert(touching.begin(), touching.end());
724  }
725 
726  elements.erase(it);
727  }
728 
729  if (!elementsWithParticleMatterInteraction.empty()) {
730  std::set<ParticleMatterInteractionHandler*> oldSPHandlers;
731  std::vector<ParticleMatterInteractionHandler*> leftBehindSPHandlers, newSPHandlers;
733  oldSPHandlers.insert(it);
734  }
735 
736  leftBehindSPHandlers.resize(std::max(oldSPHandlers.size(),
737  particleMatterinteractionHandlers.size()));
738  auto last = std::set_difference(oldSPHandlers.begin(), oldSPHandlers.end(),
739  particleMatterinteractionHandlers.begin(), particleMatterinteractionHandlers.end(),
740  leftBehindSPHandlers.begin());
741  leftBehindSPHandlers.resize(last - leftBehindSPHandlers.begin());
742 
743  for (auto it: leftBehindSPHandlers) {
744  if (!it->stillActive()) {
745  activeParticleMatterInteractionHandlers_m.erase(it);
746  }
747  }
748 
749  newSPHandlers.resize(std::max(oldSPHandlers.size(),
750  elementsWithParticleMatterInteraction.size()));
751  last = std::set_difference(particleMatterinteractionHandlers.begin(), particleMatterinteractionHandlers.end(),
752  oldSPHandlers.begin(), oldSPHandlers.end(),
753  newSPHandlers.begin());
754  newSPHandlers.resize(last - newSPHandlers.begin());
755 
756  for (auto it: newSPHandlers) {
757  activeParticleMatterInteractionHandlers_m.insert(it);
758  }
759 
761  msg << level2 << "============== START PARTICLE MATTER INTERACTION CALCULATION =============" << endl;
762  particleMatterStatus_m = true;
763  }
764  } else {
765  for (auto it = activeParticleMatterInteractionHandlers_m.begin();
767  if (!(*it)->stillActive()) {
768  auto next = std::next(it);
770  it = next;
771  } else {
772  it = std::next(it);
773  }
774  }
775  }
776 
778  do {
780  //check if more than one degrader has particles
781  ParticleMatterInteractionHandler* onlyDegraderWithParticles = nullptr;
782  int degradersWithParticlesCount = 0;
784  it->setFlagAllParticlesIn(false);
785  if (it->getParticlesInMat() > 0) {
786  onlyDegraderWithParticles = it;
787  ++ degradersWithParticlesCount;
788  }
789  }
790 
791  //if max particles per node is 2, and only one degrader has particles set
792  //AllParticlesIn for this degrader to true
793  unsigned int localNum = itsBunch_m->getLocalNum();
794  unsigned int totalNum = 0;
795  reduce(localNum, totalNum, OpAddAssign());
796  bool allParticlesInMat = (totalNum == 0 &&
797  degradersWithParticlesCount == 1);
798 
799  if (allParticlesInMat) {
800  onlyDegraderWithParticles->setFlagAllParticlesIn(true);
801  msg << "All particles in degrader" << endl;
802  }
803 
804  auto boundingSphere = itsBunch_m->getLocalBoundingSphere();
805  unsigned int rediffusedParticles = 0;
806  unsigned int numEnteredParticles = 0;
807  for (auto it: activeParticleMatterInteractionHandlers_m) {
808  ElementBase* element = it->getElement();
809  CoordinateSystemTrafo refToLocalCSTrafo = (element->getMisalignment() *
811  CoordinateSystemTrafo localToRefCSTrafo = refToLocalCSTrafo.inverted();
812 
813  const unsigned int localNum = itsBunch_m->getLocalNum();
814  for (unsigned int i = 0; i < localNum; ++i) {
815  itsBunch_m->R[i] = refToLocalCSTrafo.transformTo(itsBunch_m->R[i]);
816  itsBunch_m->P[i] = refToLocalCSTrafo.rotateTo(itsBunch_m->P[i]);
817  }
818  boundingSphere.first = refToLocalCSTrafo.transformTo(boundingSphere.first);
819 
820  it->apply(itsBunch_m, boundingSphere);
821  it->print(msg);
822 
823  boundingSphere.first = localToRefCSTrafo.transformTo(boundingSphere.first);
824 
825  const unsigned int newLocalNum = itsBunch_m->getLocalNum();
826  for (unsigned int i = 0; i < newLocalNum; ++i) {
827  itsBunch_m->R[i] = localToRefCSTrafo.transformTo(itsBunch_m->R[i]);
828  itsBunch_m->P[i] = localToRefCSTrafo.rotateTo(itsBunch_m->P[i]);
829  }
830 
831  rediffusedParticles += it->getRediffused();
832  numEnteredParticles += it->getNumEntered();
833 
834  //if all particles were in material update time to time in degrader
835  if (it->getFlagAllParticlesIn()) {
836  double timeDifference = it->getTime() - itsBunch_m->getdT() - itsBunch_m->getT();
837  if (timeDifference > 0.0) {
838  const unsigned int numSteps = std::ceil(timeDifference / itsBunch_m->getdT());
839  const double origdT = itsBunch_m->getdT();
840  itsBunch_m->setdT(timeDifference / numSteps);
841  BorisPusher pusher(itsReference);
842  for (unsigned int i = 0; i < numSteps; ++ i) {
843  updateReference(pusher);
844  }
845  itsBunch_m->setdT(origdT);
846  }
847  itsBunch_m->setT(it->getTime() - itsBunch_m->getdT());
848  }
849  }
850 
851  //perform boundp only if there are particles in the bunch, or there are particles
852  //comming out of the degrader
853  if (numEnteredParticles > 0 || rediffusedParticles > 0) {
854  totalNum -= (numEnteredParticles + rediffusedParticles);
855  if (totalNum > minBinEmitted_m && itsBunch_m->hasFieldSolver()) {
856  itsBunch_m->boundp();
857  } else {
859  }
860  }
861 
862  //if bunch has no particles update time to time in degrader
863  if (itsBunch_m->getTotalNum() == 0)
865 
866  } while (itsBunch_m->getTotalNum() == 0);
867 
868 
870  msg << level2 << "============== END PARTICLE MATTER INTERACTION CALCULATION =============" << endl;
871  particleMatterStatus_m = false;
872  }
873  }
874 }
875 
877  size_t particles_or_bins = std::max(minBinEmitted_m, size_t(1000));
878  if (itsBunch_m->hasFieldSolver() && numParticlesInSimulation_m > particles_or_bins) {
879 
880  INFOMSG("*****************************************************************" << endl);
881  INFOMSG("do repartition because of repartFreq_m" << endl);
882  INFOMSG("*****************************************************************" << endl);
885  Ippl::Comm->barrier();
887  INFOMSG("*****************************************************************" << endl);
888  INFOMSG("do repartition done" << endl);
889  INFOMSG("*****************************************************************" << endl);
890  }
891 }
892 
893 void ParallelTTracker::dumpStats(long long step, bool psDump, bool statDump) {
894  OPALTimer::Timer myt2;
895  Inform msg("ParallelTTracker ", *gmsg);
896 
897  if (itsBunch_m->getGlobalTrackStep() % 1000 + 1 == 1000) {
898  msg << level1;
899  } else if (itsBunch_m->getGlobalTrackStep() % 100 + 1 == 100) {
900  msg << level2;
901  } else {
902  msg << level3;
903  }
904 
905  if (numParticlesInSimulation_m == 0) {
906  msg << myt2.time() << " "
907  << "Step " << std::setw(6) << itsBunch_m->getGlobalTrackStep() << "; "
908  << " -- no emission yet -- "
909  << "t= " << Util::getTimeString(itsBunch_m->getT())
910  << endl;
911  return;
912  }
913 
915  size_t totalParticles_f = numParticlesInSimulation_m;
916  if (totalParticles_f <= minBinEmitted_m) {
917  msg << myt2.time() << " "
918  << "Step " << std::setw(6) << itsBunch_m->getGlobalTrackStep() << "; "
919  << "only " << std::setw(4) << totalParticles_f << " particles emitted; "
920  << "t= " << Util::getTimeString(itsBunch_m->getT()) << ", "
922  << endl;
924  throw OpalException("ParallelTTracker::dumpStats()",
925  "there seems to be something wrong with the position of the bunch!");
926  } else {
927 
928  msg << myt2.time() << " "
929  << "Step " << std::setw(6) << itsBunch_m->getGlobalTrackStep() << " "
930  << "at " << Util::getLengthString(pathLength_m) << ", "
931  << "t= " << Util::getTimeString(itsBunch_m->getT()) << ", "
933  << endl;
934 
935  writePhaseSpace(step, psDump, statDump);
936  }
937 }
938 
939 
941  Inform msg("ParallelTTracker ", *gmsg);
942 
944  RealVariable *ar = dynamic_cast<RealVariable *>(OpalData::getInstance()->find("MINBINEMITTED"));
945  if (ar)
946  minBinEmitted_m = static_cast<size_t>(ar->getReal());
947  msg << level2 << "MINBINEMITTED " << minBinEmitted_m << endl;
948 
950  RealVariable *br = dynamic_cast<RealVariable *>(OpalData::getInstance()->find("MINSTEPFORREBIN"));
951  if (br)
952  minStepforReBin_m = static_cast<int>(br->getReal());
953  msg << level2 << "MINSTEPFORREBIN " << minStepforReBin_m << endl;
954 
955  // there is no point to do repartitioning with one node
956  if (Ippl::getNodes() == 1) {
958  } else {
960  RealVariable *rep = dynamic_cast<RealVariable *>(OpalData::getInstance()->find("REPARTFREQ"));
961  if (rep)
962  repartFreq_m = static_cast<int>(rep->getReal());
963  msg << level2 << "REPARTFREQ " << repartFreq_m << endl;
964  }
965 }
966 
967 
968 bool ParallelTTracker::hasEndOfLineReached(const BoundingBox& globalBoundingBox) {
970  globalEOL_m = globalEOL_m || globalBoundingBox.isOutside(itsBunch_m->RefPartR_m);
971  return globalEOL_m;
972 }
973 
975  const unsigned int localNum = itsBunch_m->getLocalNum();
976  for (unsigned int i = 0; i < localNum; ++i) {
977  itsBunch_m->dt[i] = itsBunch_m->getdT();
978  }
979 }
980 
982  Inform msg("ParallelTTracker ", *gmsg);
983 
984  if (!itsBunch_m->doEmission()) return;
985 
987  msg << level2 << "Do emission for " << itsBunch_m->getTEmission() << " [s] using "
988  << itsBunch_m->getNumberOfEnergyBins() << " energy bins " << endl
989  << "Change dT from " << itsBunch_m->getdT() << " [s] to "
990  << itsBunch_m->getEmissionDeltaT() << " [s] during emission " << endl;;
991 
992 }
993 
994 void ParallelTTracker::writePhaseSpace(const long long /*step*/, bool psDump, bool statDump) {
995  extern Inform *gmsg;
996  Inform msg("OPAL ", *gmsg);
997  Vector_t externalE, externalB;
998  Vector_t FDext[2]; // FDext = {BHead, EHead, BRef, ERef, BTail, ETail}.
999 
1000  // Sample fields at (xmin, ymin, zmin), (xmax, ymax, zmax) and the centroid location. We
1001  // are sampling the electric and magnetic fields at the back, front and
1002  // center of the beam.
1003  Vector_t rmin, rmax;
1004  itsBunch_m->get_bounds(rmin, rmax);
1005 
1006  if (psDump || statDump) {
1007  externalB = Vector_t(0.0);
1008  externalE = Vector_t(0.0);
1011  itsBunch_m->getT() - 0.5 * itsBunch_m->getdT(),
1012  externalE,
1013  externalB);
1014  FDext[0] = itsBunch_m->toLabTrafo_m.rotateFrom(externalB);
1015  FDext[1] = itsBunch_m->toLabTrafo_m.rotateFrom(externalE * Units::Vpm2MVpm);
1016  }
1017 
1018  if (statDump) {
1019  std::vector<std::pair<std::string, unsigned int> > collimatorLosses;
1021  if (!collimators.empty()) {
1022  for (FieldList::iterator it = collimators.begin(); it != collimators.end(); ++ it) {
1023  FlexibleCollimator* coll = static_cast<FlexibleCollimator*>(it->getElement().get());
1024  std::string name = coll->getName();
1025  unsigned int losses = coll->getLosses();
1026  collimatorLosses.push_back(std::make_pair(name, losses));
1027  }
1028  std::sort(collimatorLosses.begin(), collimatorLosses.end(),
1029  [](const std::pair<std::string, unsigned int>& a, const std::pair<std::string, unsigned int>& b) ->bool {
1030  return a.first < b.first;
1031  });
1032  std::vector<unsigned int> bareLosses(collimatorLosses.size(),0);
1033  for (size_t i = 0; i < collimatorLosses.size(); ++ i){
1034  bareLosses[i] = collimatorLosses[i].second;
1035  }
1036 
1037  reduce(&bareLosses[0], &bareLosses[0] + bareLosses.size(), &bareLosses[0], OpAddAssign());
1038 
1039  for (size_t i = 0; i < collimatorLosses.size(); ++ i){
1040  collimatorLosses[i].second = bareLosses[i];
1041  }
1042  }
1043  // Write statistical data.
1044  itsDataSink_m->dumpSDDS(itsBunch_m, FDext, collimatorLosses);
1045 
1046  msg << level3 << "* Wrote beam statistics." << endl;
1047  }
1048 
1049  if (psDump && (itsBunch_m->getTotalNum() > 0)) {
1050  // Write fields to .h5 file.
1051  const size_t localNum = itsBunch_m->getLocalNum();
1052  double distToLastStop = stepSizes_m.getFinalZStop() - pathLength_m;
1054  Vector_t driftPerTimeStep = itsBunch_m->getdT() * Physics::c * itsBunch_m->toLabTrafo_m.rotateFrom(beta);
1055  bool driftToCorrectPosition = std::abs(distToLastStop) < 0.5 * euclidean_norm(driftPerTimeStep);
1056  Ppos_t stashedR;
1057  Vector_t stashedRefPartR;
1058 
1059  if (driftToCorrectPosition) {
1060  const double tau = distToLastStop / euclidean_norm(driftPerTimeStep) * itsBunch_m->getdT();
1061  if (localNum > 0) {
1062  stashedR.create(localNum);
1063  stashedR = itsBunch_m->R;
1064  stashedRefPartR = itsBunch_m->RefPartR_m;
1065 
1066  for (size_t i = 0; i < localNum; ++ i) {
1067  itsBunch_m->R[i] += tau * (Physics::c * itsBunch_m->P[i] / Util::getGamma(itsBunch_m->P[i]) -
1068  driftPerTimeStep / itsBunch_m->getdT());
1069  }
1070  }
1071 
1072  driftPerTimeStep = itsBunch_m->toLabTrafo_m.rotateTo(driftPerTimeStep);
1073  itsBunch_m->RefPartR_m = itsBunch_m->RefPartR_m + tau * driftPerTimeStep / itsBunch_m->getdT();
1074  CoordinateSystemTrafo update(tau * driftPerTimeStep / itsBunch_m->getdT(),
1075  Quaternion(1.0, 0.0, 0.0, 0.0));
1077 
1079 
1081  }
1082  if (!statDump && !driftToCorrectPosition) itsBunch_m->calcBeamParameters();
1083 
1084  msg << *itsBunch_m << endl;
1085  itsDataSink_m->dumpH5(itsBunch_m, FDext);
1086 
1087  if (driftToCorrectPosition) {
1088  if (localNum > 0) {
1089  itsBunch_m->R = stashedR;
1090  stashedR.destroy(localNum, 0);
1091  }
1092 
1093  itsBunch_m->RefPartR_m = stashedRefPartR;
1095 
1097  }
1098 
1099  msg << level2 << "* Wrote beam phase space." << endl;
1100  }
1101 }
1102 
1104  updateReferenceParticle(pusher);
1106 }
1107 
1109  const double direction = back_track? -1: 1;
1110  const double dt = direction * std::min(itsBunch_m->getT(),
1111  direction * itsBunch_m->getdT());
1112  const double scaleFactor = Physics::c * dt;
1113  Vector_t Ef(0.0), Bf(0.0);
1114 
1115  itsBunch_m->RefPartR_m /= scaleFactor;
1117  itsBunch_m->RefPartR_m *= scaleFactor;
1118 
1120  IndexMap::value_t::const_iterator it = elements.begin();
1121  const IndexMap::value_t::const_iterator end = elements.end();
1122 
1123  for (; it != end; ++ it) {
1124  const CoordinateSystemTrafo &refToLocalCSTrafo = itsOpalBeamline_m.getCSTrafoLab2Local((*it));
1125 
1126  Vector_t localR = refToLocalCSTrafo.transformTo(itsBunch_m->RefPartR_m);
1127  Vector_t localP = refToLocalCSTrafo.rotateTo(itsBunch_m->RefPartP_m);
1128  Vector_t localE(0.0), localB(0.0);
1129 
1130  if ((*it)->applyToReferenceParticle(localR,
1131  localP,
1132  itsBunch_m->getT() - 0.5 * dt,
1133  localE,
1134  localB)) {
1135  *gmsg << level1 << "The reference particle hit an element" << endl;
1136  globalEOL_m = true;
1137  }
1138 
1139  Ef += refToLocalCSTrafo.rotateFrom(localE);
1140  Bf += refToLocalCSTrafo.rotateFrom(localB);
1141  }
1142 
1143  pusher.kick(itsBunch_m->RefPartR_m, itsBunch_m->RefPartP_m, Ef, Bf, dt);
1144 
1145  itsBunch_m->RefPartR_m /= scaleFactor;
1147  itsBunch_m->RefPartR_m *= scaleFactor;
1148 }
1149 
1151  const unsigned int localNum = itsBunch_m->getLocalNum();
1152  for (unsigned int i = 0; i < localNum; ++i) {
1153  itsBunch_m->R[i] = trafo.transformTo(itsBunch_m->R[i]);
1154  itsBunch_m->P[i] = trafo.rotateTo(itsBunch_m->P[i]);
1155  itsBunch_m->Ef[i] = trafo.rotateTo(itsBunch_m->Ef[i]);
1156  itsBunch_m->Bf[i] = trafo.rotateTo(itsBunch_m->Bf[i]);
1157  }
1158 }
1159 
1163 
1165 
1167 
1168  transformBunch(update);
1169 
1171 }
1172 
1173 void ParallelTTracker::applyFractionalStep(const BorisPusher &pusher, double tau) {
1174  double t = itsBunch_m->getT();
1175  t += tau;
1176  itsBunch_m->setT(t);
1177 
1178  // the push method below pushes for half a time step. Hence the ref particle
1179  // should be pushed for 2 * tau
1180  itsBunch_m->RefPartR_m /= (Physics::c * 2 * tau);
1182  itsBunch_m->RefPartR_m *= (Physics::c * 2 * tau);
1183 
1185 
1190 }
1191 
1193 
1194  StepSizeConfig stepSizesCopy(stepSizes_m);
1195  if (back_track) {
1196  stepSizesCopy.shiftZStopLeft(zstart_m);
1197  }
1198 
1199  double t = 0.0;
1200  itsBunch_m->setT(t);
1201 
1202  dtCurrentTrack_m = stepSizesCopy.getdT();
1203  selectDT();
1204 
1207  double gamma = 0.1 / itsBunch_m->getM() + 1.0;
1208  double beta = sqrt(1.0 - 1.0 / std::pow(gamma, 2));
1209  itsBunch_m->RefPartP_m = itsBunch_m->toLabTrafo_m.rotateTo(beta * gamma * Vector_t(0, 0, 1));
1210  }
1211 
1212  while (true) {
1213  autophaseCavities(pusher);
1214 
1215  t += itsBunch_m->getdT();
1216  itsBunch_m->setT(t);
1217 
1218  Vector_t oldR = itsBunch_m->RefPartR_m;
1219  updateReferenceParticle(pusher);
1221 
1223 
1224  if (pathLength_m > stepSizesCopy.getZStop()) {
1225  ++ stepSizesCopy;
1226 
1227  if (stepSizesCopy.reachedEnd()) {
1228  -- stepSizesCopy;
1229  double tau = (stepSizesCopy.getZStop() - pathLength_m) / speed;
1230  applyFractionalStep(pusher, tau);
1231 
1232  break;
1233  }
1234 
1235  dtCurrentTrack_m = stepSizesCopy.getdT();
1236  selectDT();
1237  }
1238 
1239  if (std::abs(pathLength_m - zstart_m) <= 0.5 * itsBunch_m->getdT() * speed) {
1240  double tau = (zstart_m - pathLength_m) / speed;
1241  applyFractionalStep(pusher, tau);
1242 
1243  break;
1244  }
1245  }
1246 
1247  changeDT();
1248 }
1249 
1251 
1252  double t = itsBunch_m->getT();
1254  pusher.push(nextR, itsBunch_m->RefPartP_m, itsBunch_m->getdT());
1255  nextR *= Physics::c * itsBunch_m->getdT();
1256 
1257  auto elementSet = itsOpalBeamline_m.getElements(nextR);
1258  for (auto element: elementSet) {
1259  if (element->getType() == ElementType::TRAVELINGWAVE) {
1260  const TravelingWave *TWelement = static_cast<const TravelingWave *>(element.get());
1261  if (!TWelement->getAutophaseVeto()) {
1262  CavityAutophaser ap(itsReference, element);
1265  t, itsBunch_m->getdT());
1266  }
1267 
1268  } else if (element->getType() == ElementType::RFCAVITY) {
1269  const RFCavity *RFelement = static_cast<const RFCavity *>(element.get());
1270  if (!RFelement->getAutophaseVeto()) {
1271  CavityAutophaser ap(itsReference, element);
1274  t, itsBunch_m->getdT());
1275  }
1276  }
1277  }
1278 }
1279 
1281  unsigned int who;
1282  unsigned int whom;
1283  unsigned int howMany;
1284 };
1285 
1287  const int numNodes = Ippl::getNodes();
1288  if (itsBunch_m->hasFieldSolver() || numNodes == 1) return;
1289 
1290  long onAverage = itsBunch_m->getTotalNum() / Ippl::getNodes();
1291  if (itsBunch_m->getTotalNum() % Ippl::getNodes() > 0.5 * Ippl::getNodes())
1292  ++ onAverage;
1293 
1294  std::vector<long> localParticles(numNodes, 0);
1295  localParticles[Ippl::myNode()] = itsBunch_m->getLocalNum() - onAverage;
1296  allreduce(&(localParticles[0]),
1297  numNodes,
1298  std::plus<long>());
1299 
1300  std::vector<DistributionInfo> send;
1301  std::vector<DistributionInfo> receive;
1302 
1303  for (int i = 0; i < Ippl::getNodes(); ++ i) {
1304  if (localParticles[i] <= 0) continue;
1305 
1306  for (int j = 0; j < Ippl::getNodes(); ++ j) {
1307  if (j == i || localParticles[j] >= 0) continue;
1308 
1309  long numParts = std::min(localParticles[i], -localParticles[j]);
1310  localParticles[i] -= numParts;
1311  localParticles[j] += numParts;
1312 
1313  if (i == Ippl::myNode() || j == Ippl::myNode()) {
1314  DistributionInfo request;
1315  request.who = i;
1316  request.whom = j;
1317  request.howMany = numParts;
1318 
1319  if (i == Ippl::myNode()) {
1320  send.push_back(request);
1321  } else {
1322  receive.push_back(request);
1323  }
1324  }
1325 
1326  if (localParticles[i] == 0) break;
1327  }
1328  }
1329 
1330  std::vector<MPI_Request> requests;
1331  const long sizeSingleParticle = 9 * sizeof(double) + sizeof(short) + sizeof(int) + sizeof(PID_t::Return_t);
1332  long idx = itsBunch_m->getLocalNum() - 1;
1334 
1335  std::vector<char> send_msgbuf;
1336 
1337  if (!send.empty()) {
1338  const char *buffer;
1339 
1340  unsigned int totalSend = 0, startIndex = 0;
1341  for (DistributionInfo &request: send) {
1342  totalSend += request.howMany;
1343  }
1344  send_msgbuf.reserve(totalSend * sizeSingleParticle);
1345 
1346  for (DistributionInfo &request: send) {
1347  size_t sizePrior = send_msgbuf.size();
1348  for (long i = 0; i < request.howMany; ++ i, -- idx) {
1349  buffer = reinterpret_cast<const char*>(&(itsBunch_m->R[idx](0)));
1350  send_msgbuf.insert(send_msgbuf.end(), buffer, buffer + 3 * sizeof(double));
1351  buffer = reinterpret_cast<const char*>(&(itsBunch_m->P[idx](0)));
1352  send_msgbuf.insert(send_msgbuf.end(), buffer, buffer + 3 * sizeof(double));
1353  buffer = reinterpret_cast<const char*>(&(itsBunch_m->Q[idx]));
1354  send_msgbuf.insert(send_msgbuf.end(), buffer, buffer + sizeof(double));
1355  buffer = reinterpret_cast<const char*>(&(itsBunch_m->M[idx]));
1356  send_msgbuf.insert(send_msgbuf.end(), buffer, buffer + sizeof(double));
1357  buffer = reinterpret_cast<const char*>(&(itsBunch_m->dt[idx]));
1358  send_msgbuf.insert(send_msgbuf.end(), buffer, buffer + sizeof(double));
1359  buffer = reinterpret_cast<const char*>(&(itsBunch_m->POrigin[idx]));
1360  send_msgbuf.insert(send_msgbuf.end(), buffer, buffer + sizeof(ParticleOrigin));
1361  buffer = reinterpret_cast<const char*>(&(itsBunch_m->TriID[idx]));
1362  send_msgbuf.insert(send_msgbuf.end(), buffer, buffer + sizeof(int));
1363  buffer = reinterpret_cast<const char*>(&(itsBunch_m->ID[idx]));
1364  send_msgbuf.insert(send_msgbuf.end(), buffer, buffer + sizeof(PID_t::Return_t));
1365  }
1366 
1367  size_t sendSizeThis = send_msgbuf.size() - sizePrior;
1368  MPI_Request req = Ippl::Comm->raw_isend(&(send_msgbuf[startIndex]),
1369  sendSizeThis,
1370  request.whom,
1371  tag);
1372 
1373  requests.push_back(req);
1374 
1375  startIndex += sendSizeThis;
1376  }
1377 
1378  itsBunch_m->destroy(totalSend, idx + 1, true);
1379  }
1380 
1381  for (unsigned int i = 0; i < receive.size(); ++ i) {
1382  int node = Communicate::COMM_ANY_NODE;
1383  char *recvbuf;
1384  const int bufsize = Ippl::Comm->raw_probe_receive(recvbuf, node, tag);
1385 
1386  int j = 0;
1387 
1388  while (j < bufsize) {
1389  ++ idx;
1390  itsBunch_m->create(1);
1391  {
1392  const double *buffer = reinterpret_cast<const double*>(recvbuf + j);
1393  itsBunch_m->R[idx] = Vector_t(buffer[0], buffer[1], buffer[2]);
1394  itsBunch_m->P[idx] = Vector_t(buffer[3], buffer[4], buffer[5]);
1395  itsBunch_m->Q[idx] = buffer[6];
1396  itsBunch_m->M[idx] = buffer[7];
1397  itsBunch_m->dt[idx] = buffer[8];
1398  }
1399  j += 9 * sizeof(double);
1400 
1401  {
1402  const ParticleOrigin *buffer = reinterpret_cast<const ParticleOrigin*>(recvbuf + j);
1403  itsBunch_m->POrigin[idx] = buffer[0];
1404  }
1405  j += sizeof(ParticleOrigin);
1406 
1407  {
1408  const int *buffer = reinterpret_cast<const int*>(recvbuf + j);
1409  itsBunch_m->TriID[idx] = buffer[0];
1410  }
1411  j += sizeof(int);
1412 
1413  {
1414  const PID_t::Return_t *buffer = reinterpret_cast<const PID_t::Return_t*>(recvbuf + j);
1415  itsBunch_m->ID[idx] = buffer[0];
1416  }
1417  j += sizeof(PID_t::Return_t);
1418  }
1419 
1420  delete[] recvbuf;
1421  }
1422 
1423  if (!requests.empty()) {
1424  MPI_Waitall(requests.size(), &(requests[0]), MPI_STATUSES_IGNORE);
1425  }
1426 }
void setOpenMode(OpenMode openMode)
Definition: OpalData.cpp:349
virtual bool getAutophaseVeto() const
Definition: RFCavity.h:434
std::set< ParticleMatterInteractionHandler * > activeParticleMatterInteractionHandlers_m
IndexMap::value_t getTouchingElements(const IndexMap::key_t &range) const
static OpalData * getInstance()
Definition: OpalData.cpp:196
void timeIntegration2(BorisPusher &pusher)
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
virtual void computeSelfFields()=0
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:45
unsigned int repartFreq_m
ParticleOrigin
static void writeStatistics()
Definition: Monitor.cpp:213
double getZStop() const
Quaternion conjugate() const
Definition: Quaternion.h:103
void writePhaseSpace(const long long step, bool psDump, bool statDump)
void findStartPosition(const BorisPusher &pusher)
bool getHasBeenSimulated() const
Definition: Undulator.cpp:347
ParticleAttrib< ParticleOrigin > POrigin
void setInPrepState(bool state)
Definition: OpalData.cpp:300
double getGlobalPhaseShift()
units: (sec)
Definition: OpalData.cpp:452
DataSink * itsDataSink_m
virtual void do_binaryRepart()
IpplTimings::TimerRef WakeFieldTimer_m
ParticleAttrib< int > TriID
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two distribute and or modify the software for each author s protection and we want to make certain that everyone understands that there is no warranty for this free software If the software is modified by someone else and passed we want its recipients to know that what they have is not the so that any problems introduced by others will not reflect on the original authors reputations any free program is threatened constantly by software patents We wish to avoid the danger that redistributors of a free program will individually obtain patent in effect making the program proprietary To prevent we have made it clear that any patent must be licensed for everyone s free use or not licensed at all The precise terms and conditions for distribution and modification follow GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR DISTRIBUTION AND MODIFICATION This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License The refers to any such program or and a work based on the Program means either the Program or any derivative work under copyright a work containing the Program or a portion of it
Definition: LICENSE:43
Vector_t transformToLocalCS(const std::shared_ptr< Component > &comp, const Vector_t &r) const
Definition: OpalBeamline.h:166
void setGlobalPhaseShift(double shift)
units: (sec)
Definition: OpalData.cpp:447
PETE_TBTree< FnCopysign, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > copysign(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
void barrier(void)
void computeWakefield(IndexMap::value_t &elements)
double getFinalZStop() const
std::pair< Vector_t, double > getLocalBoundingSphere()
CoordinateSystemTrafo getCSTrafoGlobal2Local() const
Definition: ElementBase.h:498
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
IpplTimings::TimerRef BinRepartTimer_m
bool getRelativeFlag() const
Definition: TBeamline.h:453
virtual void destroy(size_t M, size_t I, bool optDestroy=true)
void getMisalignment(double &x, double &y, double &s) const
void setdT(double dt)
WakeFunction * wakeFunction_m
int repartFreq
The frequency to do particles repartition for better load balance between nodes.
Definition: Options.cpp:49
CoordinateSystemTrafo inverted() const
ParticleAttrib< Vector_t > P
void switchOffUnitlessPositions(bool use_dt_per_particle=false)
void sortAscendingZStop()
static int myNode()
Definition: IpplInfo.cpp:691
void setT(double t)
void selectDT(bool backTrack=false)
void computeExternalFields(OrbitThreader &oth)
IpplTimings::TimerRef timeIntegrationTimer2_m
std::set< std::shared_ptr< Component > > value_t
Definition: IndexMap.h:47
bool reachedEnd() const
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
Vector_t rotateToLocalCS(const std::shared_ptr< Component > &comp, const Vector_t &r) const
Definition: OpalBeamline.h:178
std::set< std::shared_ptr< Component > > getElements(const Vector_t &x)
void destroy(size_t M, size_t I, bool doNow=false)
ParticleAttrib< Vector_t > Ef
virtual void accept(BeamlineVisitor &visitor) const =0
Apply visitor.
Vector_t get_centroid() const
void calcGammas()
Compute the gammas of all bins.
void activateElements()
void get_bounds(Vector_t &rmin, Vector_t &rmax) const
double zstart_m
where to start
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
void compute3DLattice()
Vector_t get_pmean_Distribution() const
ParticleAttrib< double > M
void save3DInput()
virtual MPI_Request raw_isend(void *, int, int, int)
Definition: Communicate.h:196
Vector_t get_pmean() const
bool containsSource()
Definition: OpalBeamline.h:205
void calcBeamParameters()
void dumpStats(long long step, bool psDump, bool statDump)
CoordinateSystemTrafo getCSTrafoLab2Local(const std::shared_ptr< Component > &comp) const
Definition: OpalBeamline.h:190
void push(Vector_t &R, const Vector_t &P, const double &dt) const
Definition: BorisPusher.h:131
An abstract sequence of beam line components.
Definition: Beamline.h:34
double get_sPos() const
BoundingBox getBoundingBox() const
StepSizeConfig & advanceToPos(double spos)
void swap(OpalBeamline &rhs)
void kickParticles(const BorisPusher &pusher)
virtual const std::string & getName() const
Get element name.
constexpr double Vpm2MVpm
Definition: Units.h:125
#define INFOMSG(msg)
Definition: IpplInfo.h:348
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
Vector_t transformFrom(const Vector_t &r) const
double getdT() const
double getM() const
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:76
void storeCavityInformation()
Write cavity information from H5 file.
Definition: DataSink.cpp:136
size_t getNumberOfEmissionSteps()
void changeDT(bool backTrack=false)
CoordinateSystemTrafo toLabTrafo_m
virtual void boundp()
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
Vector_t rotateFrom(const Vector_t &r) const
ParticleAttrib< Vector_t > Bf
size_t emitParticles(double eZ)
Emit particles in the given bin i.e. copy the particles from the bin structure into the particle cont...
std::vector< MaxPhasesT >::iterator getLastMaxPhases()
Definition: OpalData.cpp:402
void set_sPos(double s)
std::string::const_iterator iterator_t
Definition: array.cpp:19
static void startTimer(TimerRef t)
Definition: IpplTimings.h:187
std::string::iterator iterator
Definition: MSLang.h:15
void switchElementsOff()
void update(PyOpalObjectNS::PyOpalObject< C > pyelement)
Definition: PyOpalObject.h:340
virtual void iterate(BeamlineVisitor &, bool r2l) const
Apply visitor to all elements of the line.
Definition: TBeamline.h:205
void push_back(double dt, double zstop, unsigned long numSteps)
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition: Vector.h:243
std::string getTimeString(double time, unsigned int precision=3)
Definition: Util.h:74
Vector_t getOrigin3D() const
Definition: TBeamline.h:433
void switchToUnitlessPositions(bool use_dt_per_particle=false)
CoordinateSystemTrafo getMisalignment(const std::shared_ptr< Component > &comp) const
Definition: OpalBeamline.h:200
void apply(PartBunchBase< double, 3 > *itsBunch, CoordinateSystemTrafo const &refToLocalCSTrafo)
Definition: Undulator.cpp:87
const Beamline & itsBeamline_m
Definition: Tracker.h:122
static int getNodes()
Definition: IpplInfo.cpp:670
double getT() const
virtual double getReal() const
Return value.
size_t getTotalNum() const
static Communicate * Comm
Definition: IpplInfo.h:84
The base class for all OPAL exceptions.
Definition: OpalException.h:28
virtual void resetInterpolationCache(bool clearCache=false)
Vector_t rotateTo(const Vector_t &r) const
void updateReferenceParticle(const BorisPusher &pusher)
size_t getLocalNum() const
#define P_SPATIAL_TRANSFER_TAG
Definition: Tags.h:82
int psDumpFreq
The frequency to dump the phase space, i.e.dump data when steppsDumpFreq==0.
Definition: Options.cpp:39
int getNumberOfEnergyBins()
unsigned long getFieldAt(const unsigned int &, const Vector_t &, const long &, const double &, Vector_t &, Vector_t &)
elements
Definition: IndexMap.cpp:163
Definition: Inform.h:42
void dumpH5(PartBunchBase< double, 3 > *beam, Vector_t FDext[]) const
Definition: DataSink.cpp:87
const PartData itsReference
The reference information.
unsigned long long getMaxSteps() const
double getEmissionDeltaT()
int minBinEmitted
The number of bins that have to be emitted before the bin are squashed into a single bin...
Definition: Options.cpp:51
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
long long getGlobalTrackStep() const
double getKineticEnergy(Vector_t p, double mass)
Definition: Util.h:56
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
ParticleAttrib< double > Q
second_type end
Definition: IndexMap.h:44
std::string getEnergyString(double energyInMeV, unsigned int precision=3)
Definition: Util.h:147
virtual int raw_probe_receive(char *&, int &, int &)
Definition: Communicate.h:208
void emitParticles(long long step)
void pushParticles(const BorisPusher &pusher)
Vector_t transformTo(const Vector_t &r) const
double getdT() const
int minStepForRebin
The number of steps into the simulation before the bins are squashed into a single bin...
Definition: Options.cpp:53
virtual void setAutophaseVeto(bool veto=true)
Definition: RFCavity.h:429
ParticleAttrib< double > dt
void prepareSections()
double getMinTimeStep() const
void computeParticleMatterInteraction(IndexMap::value_t elements, OrbitThreader &oth)
unsigned int getLosses() const
int getLastEmittedEnergyBin()
size_t boundp_destroyT()
double getGamma(Vector_t p)
Definition: Util.h:46
void dumpSDDS(PartBunchBase< double, 3 > *beam, Vector_t FDext[], const double &azimuth=-1) const
Definition: DataSink.cpp:106
void applyFractionalStep(const BorisPusher &pusher, double tau)
virtual void setBinCharge(int bin, double q)
Set the charge of one bin to the value of q and all other to zero.
bool hasEndOfLineReached(const BoundingBox &globalBoundingBox)
IpplTimings::TimerRef timeIntegrationTimer1_m
const std::string name
void shiftZStopLeft(double back)
unsigned long getNumSteps() const
ParticlePos_t & R
void autophaseCavities(const BorisPusher &pusher)
void updateRFElement(std::string elName, double maxPhi)
FieldList getElementByType(ElementType)
void timeIntegration1(BorisPusher &pusher)
std::vector< MaxPhasesT >::iterator getFirstMaxPhases()
Definition: OpalData.cpp:398
std::string time() const
Return time.
Definition: Timer.cpp:42
void setGlobalMeanR(Vector_t globalMeanR)
ParticleIndex_t & ID
virtual void execute()
Apply the algorithm to the top-level beamline.
void save3DLattice()
Quaternion getQuaternion(Vector_t u, Vector_t ref)
Definition: Quaternion.cpp:34
PartBunchBase< double, 3 > * itsBunch_m
The bunch of particles to be tracked.
Definition: Tracker.h:151
OpalBeamline itsOpalBeamline_m
first_type begin
Definition: IndexMap.h:43
double getPhaseAtMaxEnergy(const Vector_t &R, const Vector_t &P, double t, double dt)
std::list< ClassicField > FieldList
Definition: ClassicField.h:43
void transformBunch(const CoordinateSystemTrafo &trafo)
Vector_t RefPartR_m
StepSizeConfig stepSizes_m
Inform & level3(Inform &inf)
Definition: Inform.cpp:47
IndexMap::value_t query(IndexMap::key_t::first_type step, IndexMap::key_t::second_type length)
Quaternion getInitialDirection() const
Definition: TBeamline.h:443
T isnan(T x)
isnan function with adjusted return type
Definition: matheval.hpp:67
Object * find(const std::string &name)
Find entry.
Definition: OpalData.cpp:571
constexpr double e
The value of .
Definition: Physics.h:39
PETE_TBTree< OpNE, Index::PETE_Expr_t, PETE_Scalar< double > > ne(const Index &idx, double x)
Definition: IndexInlines.h:357
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
void create(size_t M)
PETE_TUTree< FnCeil, typename T::PETE_Expr_t > ceil(const PETE_Expr< T > &l)
Definition: PETE.h:728
double get_meanKineticEnergy() const
virtual void apply(PartBunchBase< double, 3 > *bunch)=0
double getP() const
The constant reference momentum per particle.
Definition: PartData.h:126
ParticleAttrib< int > Bin
virtual void create(size_t)
unsigned int emissionSteps_m
std::string getLengthString(double spos, unsigned int precision=3)
Definition: Util.h:97
virtual void initialize(const ElementBase *)
Definition: WakeFunction.h:43
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
Vector_t RefPartP_m
static void stopTimer(TimerRef t)
Definition: IpplTimings.h:192
void updateReference(const BorisPusher &pusher)
void kick(const Vector_t &R, Vector_t &P, const Vector_t &Ef, const Vector_t &Bf, const double &dt) const
Definition: BorisPusher.h:65
bool weHaveEnergyBins()
IndexMap::key_t getRange(const IndexMap::value_t::value_type &element, double position) const
virtual void visitBeamline(const Beamline &)
Apply the algorithm to a beam line.
bool getIfBeamEmitting()
Inform & level1(Inform &inf)
Definition: Inform.cpp:45
size_t numParticlesInSimulation_m
Inform * gmsg
Definition: Main.cpp:70
int statDumpFreq
The frequency to dump statistical values, e.e. dump data when stepstatDumpFreq==0.
Definition: Options.cpp:41
end
Definition: multipole_t.tex:9
T isinf(T x)
isinf function with adjusted return type
Definition: matheval.hpp:71
bool isOutside(const Vector_t &position) const
Definition: BoundingBox.h:62
IpplTimings::TimerRef fieldEvaluationTimer_m
void setPriorTrack(const bool &value=true)
true if in follow-up track
Definition: OpalData.cpp:308
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
Definition: GlobalComm.hpp:55
double getTEmission()
void computeSpaceChargeFields(unsigned long long step)
virtual void setPhasem(double phase)
Definition: RFCavity.h:389