OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
EnvelopeBunch.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <cfloat>
3 #include <fstream>
4 #include <cmath>
5 #include <string>
6 #include <limits>
7 #include <algorithm>
8 #include <typeinfo>
9 
10 //FIXME: replace with IPPL Vector_t
11 #include <vector>
12 //FIXME: remove
13 #include <mpi.h>
14 
15 #include "Algorithms/bet/math/root.h" // root finding routines
16 #include "Algorithms/bet/math/linfit.h" // linear fitting routines
17 #include "Algorithms/bet/math/savgol.h" // savgol smoothing routine
18 #include "Algorithms/bet/math/rk.h" // Runge-Kutta Integration
19 
21 #include "Utilities/Util.h"
22 #include "Utility/IpplTimings.h"
23 
24 #define USE_HOMDYN_SC_MODEL
25 
26 extern Inform *gmsg;
27 
42 #define BETA_MIN1 0.30 // minimum beta-value for space-charge calculations: start
43 
44 #ifndef USE_HOMDYN_SC_MODEL
45 #define BETA_MIN2 0.45 // minimum beta-value for space-charge calculations: full impact
46 #endif
47 
48 // Hack allows odeint in rk.C to be called with a class member function
49 static EnvelopeBunch *thisBunch = NULL; // pointer to access calling bunch
50 static void Gderivs(double t, double Y[], double dYdt[]) { thisBunch->derivs(t, Y, dYdt); }
51 //static double Gcur(double z) { return thisBunch->currentProfile_m->get(z, itype_lin); }
52 static double rootValue = 0.0;
53 
54 // used in setLShape for Gaussian
55 static void erfRoot(double x, double *fn, double *df) {
56  double v = erfc(fabs(x));
57  double eps = 1.0e-05;
58 
59  *fn = v - rootValue;
60  *df = (erfc(fabs(x) + eps) - v) / eps;
61 }
62 
63 
65  PartBunch(ref),
66  numSlices_m(0),
67  numMySlices_m(0) {
68 
71  isValid_m = true;
72 
73 }
74 
75 
76 EnvelopeBunch::EnvelopeBunch(const std::vector<OpalParticle> &rhs,
77  const PartData *ref):
78  PartBunch(ref),
79  numSlices_m(0),
80  numMySlices_m(0)
81 {}
82 
83 
85 }
86 
88  Inform msg("calcBeamParameters");
90  double ex, ey, nex, ney, b0, bRms, bMax, bMin, g0, dgdt, gInc;
91  double RxRms = 0.0, RyRms = 0.0, Px = 0.0, PxRms = 0.0, PxMax = 0.0, PxMin = 0.0, Py = 0.0, PyRms = 0.0, PyMax = 0.0, PyMin = 0.0;
92  double Pz, PzMax, PzMin, PzRms;
93  double x0Rms, y0Rms, zRms, zMax, zMin, I0, IRms, IMax, IMin;
94 
95  runStats(sp_beta, &b0, &bMax, &bMin, &bRms, &nValid_m);
96  runStats(sp_I, &I0, &IMax, &IMin, &IRms, &nValid_m);
97  runStats(sp_z, &z0_m, &zMax, &zMin, &zRms, &nValid_m);
98  runStats(sp_Pz, &Pz, &PzMax, &PzMin, &PzRms, &nValid_m);
99 
100  if(solver_m & sv_radial) {
101  runStats(sp_Rx, &Rx_m, &RxMax_m, &RxMin_m, &RxRms, &nValid_m);
102  runStats(sp_Ry, &Ry_m, &RyMax_m, &RyMin_m, &RyRms, &nValid_m);
103  runStats(sp_Px, &Px, &PxMax, &PxMin, &PxRms, &nValid_m);
104  runStats(sp_Py, &Py, &PyMax, &PyMin, &PyRms, &nValid_m);
105  calcEmittance(&nex, &ney, &ex, &ey, &nValid_m);
106  }
107 
108  if(solver_m & sv_offaxis) {
109  runStats(sp_x0, &x0_m, &x0Max_m, &x0Min_m, &x0Rms, &nValid_m);
110  runStats(sp_y0, &y0_m, &y0Max_m, &y0Min_m, &y0Rms, &nValid_m);
111  }
112 
113  calcEnergyChirp(&g0, &dgdt, &gInc, &nValid_m);
114  double Bfz = AvBField();
115  double Efz = AvEField();
116  double mc2e = 1.0e-6 * Physics::EMASS * Physics::c * Physics::c / Physics::q_e;
117 
118  E_m = mc2e * (g0 - 1.0);
119  dEdt_m = 1.0e-12 * mc2e * dgdt;
120  Einc_m = mc2e * gInc;
121  tau_m = zRms / Physics::c;
122  I_m = IMax;
124  Px_m = Px / Physics::c;
125  Py_m = Py / Physics::c;
126  // dx02_m = dx0_m;
127  // dy02_m = dy0_m;
128  // dfi_x_m = 180.0 * dfi_x / Physics::pi;
129  // dfi_y_m = 180.0 * dfi_y / Physics::pi;
130  Ez_m = 1.0e-6 * Efz;
131  Bz_m = Bfz;
132 
133  //in [mrad]
134  emtn_m = Vector_t(ex, ey, 0.0);
135  norm_emtn_m = Vector_t(nex, ney, 0.0);
136 
137  maxX_m = Vector_t(RxMax_m, RyMax_m, zMax);
138  maxP_m = Vector_t(PxMax * E_m * sqrt((g0 + 1.0) / (g0 - 1.0)) / Physics::c * Physics::pi, PyMax * E_m * sqrt((g0 + 1.0) / (g0 - 1.0)) / Physics::c * Physics::pi, PzMax);
139 
140  //minX in the T-T sense is -RxMax_m
141  minX_m = Vector_t(-RxMax_m, -RyMax_m, zMin);
142  minP_m = Vector_t(-PxMax * E_m * sqrt((g0 + 1.0) / (g0 - 1.0)) / Physics::c * Physics::pi, -PyMax * E_m * sqrt((g0 + 1.0) / (g0 - 1.0)) / Physics::c * Physics::pi, PzMin);
143  //minP_m = Vector_t(-maxP_m[0], -maxP_m[1], PzMin);
144 
145  /* PxRms is the rms of the divergence in x direction in [rad]: x'
146  * x' = Px/P0 -> Px = x' * P0 = x' * \beta/c*E (E is the particle total
147  * energy)
148  * Pz* in [\beta\gamma]
149  * \pi from [rad]
150  */
151  sigmax_m = Vector_t(RxRms / 2.0, RyRms / 2.0, zRms);
152  sigmap_m = Vector_t(PxRms * E_m * sqrt((g0 + 1.0) / (g0 - 1.0)) / Physics::c * Physics::pi / 2.0, PyRms * E_m * sqrt((g0 + 1.0) / (g0 - 1.0)) / Physics::c * Physics::pi / 2.0, PzRms);
153 
154  dEdt_m = PzRms * mc2e * b0;
155 
157 }
158 
159 void EnvelopeBunch::runStats(EnvelopeBunchParameter sp, double *xAvg, double *xMax, double *xMin, double *rms, int *nValid) {
160  int i, nV = 0;
161  std::vector<double> v(numMySlices_m, 0.0);
162 
163  //FIXME: why from 1 to n-1??
164  switch(sp) {
165  case sp_beta: // normalized velocity (total) [-]
166  for(i = 1; i < numMySlices_m - 1; i++) {
167  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = slices_m[i]->p[SLI_beta];
168  }
169  break;
170  case sp_gamma: // Lorenz factor
171  for(i = 1; i < numMySlices_m - 1; i++) {
172  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = slices_m[i]->computeGamma();
173  }
174  break;
175  case sp_z: // slice position [m]
176  for(i = 0; i < numMySlices_m - 0; i++) {
177  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = slices_m[i]->p[SLI_z];
178  }
179  break;
180  case sp_I: // slice position [m]
181  for(i = 1; i < numMySlices_m - 1; i++) {
182  if((slices_m[i]->p[SLI_beta] > BETA_MIN1) && ((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()))
183  v[nV++] = 0.0; //FIXME: currentProfile_m->get(slices_m[i]->p[SLI_z], itype_lin);
184  }
185  break;
186  case sp_Rx: // beam size x [m]
187  for(i = 0; i < numMySlices_m - 0; i++) {
188  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = 2.* slices_m[i]->p[SLI_x];
189  }
190  break;
191  case sp_Ry: // beam size y [m]
192  for(i = 0; i < numMySlices_m - 0; i++) {
193  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = 2. * slices_m[i]->p[SLI_y];
194  }
195  break;
196  case sp_Px: // beam divergence x
197  for(i = 0; i < numMySlices_m - 0; i++) {
198  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = slices_m[i]->p[SLI_px];
199  }
200  break;
201  case sp_Py: // beam divergence y
202  for(i = 0; i < numMySlices_m - 0; i++) {
203  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = slices_m[i]->p[SLI_py];
204  }
205  break;
206  case sp_Pz:
207  for(i = 1; i < numMySlices_m - 1; i++) {
208  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = slices_m[i]->p[SLI_beta] * slices_m[i]->computeGamma();
209  }
210  break;
211  case sp_x0: // position centroid x [m]
212  for(i = 1; i < numMySlices_m - 1; i++) {
213  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = slices_m[i]->p[SLI_x0];
214  }
215  break;
216  case sp_y0: // position centroid y [m]
217  for(i = 1; i < numMySlices_m - 1; i++) {
218  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = slices_m[i]->p[SLI_y0];
219  }
220  break;
221  case sp_px0: // angular deflection centroid x
222  for(i = 1; i < numMySlices_m - 1; i++) {
223  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = slices_m[i]->p[SLI_px0];
224  }
225  break;
226  case sp_py0: // angular deflection centroid y
227  for(i = 1; i < numMySlices_m - 1; i++) {
228  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) v[nV++] = slices_m[i]->p[SLI_py0];
229  }
230  break;
231  default :
232  throw OpalException("EnvelopeBunch", "EnvelopeBunch::runStats() Undefined label (programming error)");
233  break;
234  }
235 
236  int nVTot = nV;
237  MPI_Allreduce(MPI_IN_PLACE, &nVTot, 1, MPI_INT, MPI_SUM, Ippl::getComm());
238  if(nVTot <= 0) {
239  *xAvg = 0.0;
240  *xMax = 0.0;
241  *xMin = 0.0;
242  *rms = 0.0;
243  *nValid = 0;
244  } else {
245  double M1 = 0.0;
246  double M2 = 0.0;
247  double maxv = std::numeric_limits<double>::min();
248  double minv = std::numeric_limits<double>::max();
249  if(nV > 0) {
250  M1 = v[0];
251  M2 = v[0] * v[0];
252  maxv = v[0];
253  minv = v[0];
254  for(i = 1; i < nV; i++) {
255  M1 += v[i];
256  M2 += v[i] * v[i];
257  maxv = std::max(maxv, v[i]);
258  minv = std::min(minv, v[i]);
259  }
260  }
261 
262  MPI_Allreduce(MPI_IN_PLACE, &M1, 1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
263  MPI_Allreduce(MPI_IN_PLACE, &M2, 1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
264  MPI_Allreduce(MPI_IN_PLACE, &maxv, 1, MPI_DOUBLE, MPI_MAX, Ippl::getComm());
265  MPI_Allreduce(MPI_IN_PLACE, &minv, 1, MPI_DOUBLE, MPI_MIN, Ippl::getComm());
266 
267  *xAvg = M1 / nVTot;
268  *xMax = maxv;
269  *xMin = minv;
270 
271  //XXX: ok so this causes problems. E.g in the case of all transversal
272  //components we cannot compare a rms_rx with rms_x (particles)
273  //produced by the T-Tracker
274 
275  //in case of transversal stats we want to calculate the rms
276  //*rms = sqrt(M2/nVTot);
277 
278  //else a sigma
279  //*sigma = sqrt(M2/nVTot - M1*M1/(nVTot*nVTot));
280  //this is sigma:
281  //*rms = sqrt(M2/nVTot - M1*M1/(nVTot*nVTot));
282  *nValid = nVTot;
283 
284  if(sp == sp_Rx ||
285  sp == sp_Ry ||
286  sp == sp_Px ||
287  sp == sp_Py)
288  *rms = sqrt(M2 / nVTot); //2.0: half of the particles
289  else
290  *rms = sqrt(M2 / nVTot - M1 * M1 / (nVTot * nVTot));
291  }
292 }
293 
294 void EnvelopeBunch::calcEmittance(double *emtnx, double *emtny, double *emtx, double *emty, int *nValid) {
295  double sx = 0.0;
296  double sxp = 0.0;
297  double sxxp = 0.0;
298  double sy = 0.0;
299  double syp = 0.0;
300  double syyp = 0.0;
301  double betagamma = 0.0;
302 
303  // find the amount of active slices
304  int nV = 0;
305  for(int i = 0; i < numMySlices_m; i++) {
306  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid())
307  nV++;
308  }
309 
310  if(nV > 0) {
311  int i1 = nV;
312  nV = 0;
313  double bg = 0.0;
314  for(int i = 0; i < i1; i++) {
315  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) {
316  nV++;
317 
318  if(solver_m & sv_radial) {
319  assert(i < numMySlices_m);
320  auto sp = slices_m[i];
321  bg = sp->p[SLI_beta] * sp->computeGamma();
322 
323  double pbc = bg * sp->p[SLI_px] / (sp->p[SLI_beta] * Physics::c);
324  sx += sp->p[SLI_x] * sp->p[SLI_x];
325  sxp += pbc * pbc;
326  sxxp += sp->p[SLI_x] * pbc;
327 
328  pbc = bg * sp->p[SLI_py] / (sp->p[SLI_beta] * Physics::c);
329  sy += sp->p[SLI_y] * sp->p[SLI_y];
330  syp += pbc * pbc;
331  syyp += sp->p[SLI_y] * pbc;
332 
333  betagamma += sqrt(1 + sp->p[SLI_px] * sp->p[SLI_px] + sp->p[SLI_py] * sp->p[SLI_py]);
334  }
335  }
336  }
337  }
338 
339  int nVToT = nV;
340  reduce(nVToT, nVToT, OpAddAssign());
341  if(nVToT == 0) {
342  *emtnx = 0.0;
343  *emtny = 0.0;
344  *emtx = 0.0;
345  *emty = 0.0;
346  *nValid = 0;
347  } else {
348  reduce(sx, sx, OpAddAssign());
349  reduce(sy, sy, OpAddAssign());
350  reduce(sxp, sxp, OpAddAssign());
351  reduce(syp, syp, OpAddAssign());
352  reduce(sxxp, sxxp, OpAddAssign());
353  reduce(syyp, syyp, OpAddAssign());
354  reduce(betagamma, betagamma, OpAddAssign());
355  sx /= nVToT;
356  sy /= nVToT;
357  sxp /= nVToT;
358  syp /= nVToT;
359  sxxp /= nVToT;
360  syyp /= nVToT;
361 
362  *emtnx = sqrt(sx * sxp - sxxp * sxxp + emtnx0_m * emtnx0_m + emtbx0_m * emtbx0_m);
363  *emtny = sqrt(sy * syp - syyp * syyp + emtny0_m * emtny0_m + emtby0_m * emtby0_m);
364 
365  betagamma /= nVToT;
366  betagamma *= sqrt(1.0 - (1 / betagamma) * (1 / betagamma));
367  *emtx = *emtnx / betagamma;
368  *emty = *emtny / betagamma;
369  *nValid = nVToT;
370  }
371 }
372 
373 void EnvelopeBunch::calcEnergyChirp(double *g0, double *dgdt, double *gInc, int *nValid) {
374  std::vector<double> dtl(numMySlices_m, 0.0);
375  std::vector<double> b(numMySlices_m, 0.0);
376  std::vector<double> g(numMySlices_m, 0.0);
377 
378  // defaults
379  *g0 = 1.0;
380  *dgdt = 0.0;
381  *gInc = 0.0;
382 
383  double zAvg = 0.0;
384  double gAvg = 0.0;
385  int j = 0;
386  for(int i = 0; i < numMySlices_m; i++) {
387  std::shared_ptr<EnvelopeSlice> cs = slices_m[i];
388  if((cs->is_valid()) && (cs->p[SLI_z] > zCat_m)) {
389  zAvg += cs->p[SLI_z];
390  dtl[i-j] = cs->p[SLI_z];
391  b[i-j] = cs->p[SLI_beta];
392  g[i-j] = cs->computeGamma();
393  gAvg += g[i-j];
394  } else
395  ++j;
396  }
397  int nV = numMySlices_m - j;
398 
399  int nVTot = nV;
400  reduce(nVTot, nVTot, OpAddAssign());
401  if(nVTot > 0) {
402  reduce(gAvg, gAvg, OpAddAssign());
403  reduce(zAvg, zAvg, OpAddAssign());
404  gAvg = gAvg / nVTot;
405  zAvg = zAvg / nVTot;
406  *g0 = gAvg;
407  }
408 
409  // FIXME: working with global arrays
410  // make dtl, b and g global
411  if(nVTot > 2) {
412  std::vector<double> dtG(nVTot, 0.0);
413  std::vector<double> bG(nVTot, 0.0);
414  std::vector<double> gG(nVTot, 0.0);
415 
416  int numproc = Ippl::Comm->getNodes();
417  std::vector<int> numsend(numproc, nV);
418  std::vector<int> offsets(numproc);
419  std::vector<int> offsetsG(numproc);
420  std::vector<int> zeros(numproc, 0);
421 
422  MPI_Allgather(&nV, 1, MPI_INT, &offsets.front(), 1, MPI_INT, Ippl::getComm());
423  offsetsG[0] = 0;
424  for(int i = 1; i < numproc; i++) {
425  if(offsets[i-1] == 0)
426  offsetsG[i] = 0;
427  else
428  offsetsG[i] = offsetsG[i-1] + offsets[i-1];
429  }
430 
431  MPI_Alltoallv(&dtl.front(), &numsend.front(), &zeros.front(), MPI_DOUBLE,
432  &dtG.front(), &offsets.front(), &offsetsG.front(), MPI_DOUBLE,
433  Ippl::getComm());
434 
435  MPI_Alltoallv(&b.front(), &numsend.front(), &zeros.front(), MPI_DOUBLE,
436  &bG.front(), &offsets.front(), &offsetsG.front(), MPI_DOUBLE,
437  Ippl::getComm());
438 
439  MPI_Alltoallv(&g.front(), &numsend.front(), &zeros.front(), MPI_DOUBLE,
440  &gG.front(), &offsets.front(), &offsetsG.front(), MPI_DOUBLE,
441  Ippl::getComm());
442 
443  double dum2, dum3, dum4, rms, gZero, gt;
444 
445  // convert z to t
446  for(int i = 0; i < nVTot; i++) {
447  dtG[i] = (dtG[i] - zAvg) / (bG[i] * Physics::c);
448  }
449 
450  // chrip and uncorrelated energy sread
451  linfit(&dtG[0], &gG[0], nVTot, &gZero, &gt, &dum2, &dum3, &dum4);
452  *dgdt = gt;
453 
454  rms = 0.0;
455  for(int i = 0; i < nVTot; i++) {
456  rms += pow(gG[i] - gZero - gt * dtG[i], 2);
457  }
458 
459  *gInc = sqrt(rms / nVTot);
460  }
461 }
462 
463 
465  numSlices_m = nSlice;
466  int rank = Ippl::Comm->myNode();
467  int numproc = Ippl::Comm->getNodes();
468  numMySlices_m = nSlice / numproc;
469  if(numMySlices_m < 13) {
470  if(rank == 0) {
471  numMySlices_m = 14;
472  } else {
473  numMySlices_m = (nSlice - 14) / (numproc - 1);
474  if(rank - 1 < (nSlice - 14) % (numproc - 1))
475  numMySlices_m++;
476  }
477  } else {
478  if(rank < nSlice % numproc)
479  numMySlices_m++;
480  }
481 
482  mySliceStartOffset_m = rank * ((int)numSlices_m / numproc);
483  if(rank < numSlices_m % numproc)
484  mySliceStartOffset_m += rank;
485  else
486  mySliceStartOffset_m += numSlices_m % numproc;
488 }
489 
490 
492 
493  // Memory issue when going to larger number of processors (this is
494  // also the reason for the 30 slices hard limit per core!)
495  // using heuristic (until problem is located)
496  //size_t nSlices = (3 / 100.0 + 1.0) * numMySlices_m;
497 
498  size_t nSlices = getLocalNum();
499 
500  KR = std::unique_ptr<Vector_t[]>(new Vector_t[nSlices]);
501  KT = std::unique_ptr<Vector_t[]>(new Vector_t[nSlices]);
502  EF = std::unique_ptr<Vector_t[]>(new Vector_t[nSlices]);
503  BF = std::unique_ptr<Vector_t[]>(new Vector_t[nSlices]);
504 
505  z_m.resize(numSlices_m, 0.0);
506  b_m.resize(numSlices_m, 0.0);
507 
508  for(unsigned int i = 0; i < nSlices; i++) {
509  KR[i] = Vector_t(0);
510  KT[i] = Vector_t(0);
511  BF[i] = Vector_t(0);
512  EF[i] = Vector_t(0);
513  }
514 
515  // set default DE solver method
517 
518  //FIXME: WHY?
519  if(numSlices_m < 14)
520  throw OpalException("EnvelopeBunch::createSlices", "use more than 13 slices");
521 
522  // defaults:
523  Q_m = 0.0; // no charge
524  t_m = 0.0; // t = 0 s
525  t_offset_m = 0.0; // offset time by tReset function
526  emtnx0_m = 0.0;
527  emtny0_m = 0.0; // no intrinsic emittance
528  emtbx0_m = 0.0;
529  emtby0_m = 0.0; // no intrinsic emittance Bush effect
530  Bz0_m = 0.0; // no magnetic field on creation (cathode)
531  dx0_m = 0.0;
532  dy0_m = 0.0; // no offset of coordinate system
533  dfi_x_m = 0.0;
534  dfi_y_m = 0.0; // no rotation of coordinate system
535 
536  slices_m.resize(nSlices);
537  for( auto & slice : slices_m ) {
538  slice = std::shared_ptr<EnvelopeSlice>(new EnvelopeSlice());
539  }
540  //XXX: not supported by clang at the moment
541  //std::generate(s.begin(), s.end(),
542  //[]()
543  //{
544  //return std::shared_ptr<EnvelopeSlice>(new EnvelopeSlice());
545  //});
546 
547  Esct_m.resize(nSlices, 0.0);
548  G_m.resize(nSlices, 0.0);
549  Exw_m.resize(nSlices, 0.0);
550  Eyw_m.resize(nSlices, 0.0);
551  Ezw_m.resize(nSlices, 0.0);
552 
553  for(unsigned int i = 0; i < nSlices; i++) {
554  Esct_m[i] = 0.0;
555  G_m[i] = 0.0;
556  Ezw_m[i] = 0.0;
557  Exw_m[i] = 0.0;
558  Eyw_m[i] = 0.0;
559  }
560 
561  currentProfile_m = NULL;
562  I0avg_m = 0.0;
564 }
565 
566 //XXX: convention: s[n] is the slice closest to the cathode and all positions
567 //are negative (slices left of cathode)
568 //XXX: every processor fills its slices in bins (every proc holds all bins,
569 //some empty)
570 void EnvelopeBunch::setBinnedLShape(EnvelopeBunchShape shape, double z0, double emission_time_s, double frac) {
571  unsigned int n2 = numSlices_m / 2;
572  double sqr2 = sqrt(2.0), v;
573  double bunch_width = 0.0;
574 
575  switch(shape) {
576  case bsRect:
577 
578  bunch_width = Physics::c * emission_time_s * slices_m[0]->p[SLI_beta];
579 // std::cout << "bunch_width = " << bunch_width << " SLI_beta= " << slices_m[0]->p[SLI_beta] << std::endl;
580  for(int i = 0; i < numMySlices_m; i++) {
581  slices_m[i]->p[SLI_z] = -(((numSlices_m - 1) - (mySliceStartOffset_m + i)) * bunch_width) / numSlices_m;
582  }
583  I0avg_m = Q_m * Physics::c / fabs(2.0 * emission_time_s);
584  break;
585 
586  case bsGauss:
587  if(n2 >= mySliceStartOffset_m && n2 <= mySliceEndOffset_m)
588  slices_m[n2-mySliceStartOffset_m]->p[SLI_z] = z0;
589 
590  for(int i = 1; i <= numSlices_m / 2; i++) {
591  rootValue = 1.0 - 2.0 * i * frac / (numSlices_m + 1);
592  v = fabs(emission_time_s) * sqr2 * findRoot(erfRoot, 0.0, 5.0, 1.0e-5) * (emission_time_s < 0.0 ? Physics::c : 1.0);
593 
594  if((n2 + i) >= mySliceStartOffset_m && (n2 + i) <= mySliceEndOffset_m)
596 
597  if((n2 - i) >= mySliceStartOffset_m && (n2 - i) <= mySliceEndOffset_m)
599  }
600 
601  I0avg_m = 0.0;
602  break;
603  }
604 
605  double gz0 = 0.0, gzN = 0.0;
606  if(Ippl::Comm->myNode() == 0)
607  gz0 = slices_m[0]->p[SLI_z];
608  if(Ippl::Comm->myNode() == Ippl::Comm->getNodes() - 1)
609  gzN = slices_m[numMySlices_m-1]->p[SLI_z];
610  reduce(gz0, gz0, OpAddAssign());
611  reduce(gzN, gzN, OpAddAssign());
612 
613  hbin_m = (gzN - gz0) / nebin_m;
614 
615  // initialize all bins with an empty vector
616  for(int i = 0; i < nebin_m; i++) {
617  std::vector<int> tmp;
618  this->bins_m.push_back(tmp);
619  }
620 
621  // add all slices to appropriated bins
622  int bin_i = 0, slice_i = 0;
623  while(slice_i < numMySlices_m) {
624  if((bin_i + 1) * hbin_m < slices_m[slice_i]->p[SLI_z] - gz0) {
625  bin_i++;
626  } else {
627  this->bins_m[bin_i].push_back(slice_i);
628  slice_i++;
629  }
630  }
631 
633  /*
634  for(unsigned int i = 0; i < bins_m.size(); i++) {
635  if(bins_m[i].size() > 0) {
636  std::cout << Ippl::Comm->myNode() << ": Bin " << i << ": ";
637  for(unsigned int j = 0; j < bins_m[i].size(); j++)
638  std::cout << " " << mySliceStartOffset_m + bins_m[i][j] << "(" << slices_m[j]->p[SLI_z] << ")";
639  std::cout << std::endl;
640  }
641  }
642  */
643  //find first bin containing slices
646  if(bins_m[firstBinWithValue_m].size() != 0) break;
647 
648  backup();
649 }
650 
651 void EnvelopeBunch::setTShape(double enx, double eny, double rx, double ry, double b0) {
652  /*
653  Inform msg("setTshape");
654  msg << "set SLI_x to " << rx / 2.0 << endl;
655  msg << "set SLI_y to " << ry / 2.0 << endl;
656  */
657  // set emittances
658  emtnx0_m = enx;
659  emtny0_m = eny;
660  //FIXME: is rx here correct?
661  emtbx0_m = Physics::q_e * rx * rx * Bz0_m / (8.0 * Physics::EMASS * Physics::c);
662  emtby0_m = Physics::q_e * ry * ry * Bz0_m / (8.0 * Physics::EMASS * Physics::c);
663  //msg << "set emtbx0 to " << emtbx0 << endl;
664  //msg << "set emtby0 to " << emtby0 << endl;
665 
666  //XXX: rx = 2*rms_x
667  for(int i = 0; i < numMySlices_m; i++) {
668  slices_m[i]->p[SLI_x] = rx / 2.0; //rms_x
669  slices_m[i]->p[SLI_y] = ry / 2.0; //rms_y
670  slices_m[i]->p[SLI_px] = 0.0;
671  slices_m[i]->p[SLI_py] = 0.0;
672  }
673 
674  backup();
675 }
676 
677 void EnvelopeBunch::setTOffset(double x0, double px0, double y0, double py0) {
678  for(int i = 0; i < numMySlices_m; i++) {
679  slices_m[i]->p[SLI_x0] = x0;
680  slices_m[i]->p[SLI_px0] = px0;
681  slices_m[i]->p[SLI_y0] = y0;
682  slices_m[i]->p[SLI_py0] = py0;
683  }
684 }
685 
686 void EnvelopeBunch::setEnergy(double E0, double dE) {
687  double g0 = 1.0 + (Physics::q_e * E0 / (Physics::EMASS * Physics::c * Physics::c));
688  double dg = fabs(dE) * Physics::q_e / (Physics::EMASS * Physics::c * Physics::c);
689  double z0 = zAvg();
690 
691  for(int i = 0; i < numMySlices_m; i++) {
692  double g = g0 + (slices_m[i]->p[SLI_z] - z0) * dg;
693  slices_m[i]->p[SLI_beta] = sqrt(1.0 - (1.0 / (g * g)));
694  }
695 
696  backup();
697 }
698 
700 
701  for(int i = 0; i < numSlices_m; i++) {
702  z_m[i] = 0.0;
703  b_m[i] = 0.0;
704  }
705  for(int i = 0; i < numMySlices_m; i++) {
708  }
709 
710  MPI_Allreduce(MPI_IN_PLACE, &(z_m[0]), numSlices_m, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
711  MPI_Allreduce(MPI_IN_PLACE, &(b_m[0]), numSlices_m, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
712 }
713 
715  Inform msg("calcI ");
716 
717  static int already_called = 0;
718  if((dStat_m & ds_currentCalculated) || (already_called && (Q_m <= 0.0)))
719  return;
720  already_called = 1;
721 
722  std::vector<double> z1(numSlices_m, 0.0);
723  std::vector<double> b (numSlices_m, 0.0);
724  double bSum = 0.0;
725  double dz2Sum = 0.0;
726  int n1 = 0;
727  int my_start = 0, my_end = 0;
728 
729  for(int i = 0; i < numSlices_m; i++) {
730  if(b_m[i] > 0.0) {
731  if((unsigned int) i == mySliceStartOffset_m)
732  my_start = n1;
733  if((unsigned int) i == mySliceEndOffset_m)
734  my_end = n1;
735 
736  b[n1] = b_m[i];
737  z1[n1] = z_m[i];
738  if(n1 > 0)
739  dz2Sum += ((z1[n1] - z1[n1-1]) * (z1[n1] - z1[n1-1]));
740  bSum += b_m[i];
741  n1++;
742  }
743  }
744  if(Ippl::Comm->myNode() == 0)
745  my_start++;
746 
747  if(n1 < 2) {
748  msg << "n1 (= " << n1 << ") < 2" << endl;
749  //throw OpalException("EnvelopeBunch", "Insufficient points to calculate the current (n1)");
750  currentProfile_m = std::unique_ptr<Profile>(new Profile(0.0));
751  return;
752  }
753 
754  double sigma_dz = sqrt(dz2Sum / (n1 - 1));
755  double beta = bSum / n1;
756 
757  //sort beta's according to z1 with temporary vector of pairs
758  std::vector<std::pair<double,double>> z1_b(numSlices_m);
759  for (int i=0; i<numSlices_m; i++) {
760  z1_b[i] = std::make_pair(z1[i],b[i]);
761  }
762 
763  std::sort(z1_b.begin(), z1_b.end(),
764  [](const std::pair<double,double> &left, const std::pair<double,double> &right)
765  {return left.first < right.first;});
766 
767  for (int i=0; i<numSlices_m; i++) {
768  z1[i] = z1_b[i].first;
769  b [i] = z1_b[i].second;
770  }
771 
772  double q = Q_m > 0.0 ? Q_m / numSlices_m : Physics::q_e;
773  double dz = 0.0;
774 
775  // 1. Determine current from the slice distance
776  std::vector<double> I1(n1, 0.0);
777 
778  //limit the max current to 5x the sigma value to reduce noise problems
779  double dzMin = 0.2 * sigma_dz;
780 
781  //FIXME: Instead of using such a complicated mechanism (store same value
782  //again) to enforce only to use a subsample of all points, use a vector to
783  //which all values get pushed, no need for elimination later.
784 
785  int vend = my_end;
786  if(Ippl::Comm->myNode() == Ippl::Comm->getNodes() - 1)
787  vend--;
788 
789  //XXX: THIS LOOP IS THE EXPENSIVE PART!!!
790  int i, j;
791 #ifdef _OPENMP
792 #pragma omp parallel for private(i,j,dz)
793 #endif //_OPENMP
794  for(i = my_start; i <= vend; i++) {
795  j = 1;
796  do {
797  dz = fabs(z1[i+j] - z1[i-j]);
798  j++;
799  } while((dz < dzMin * (j - 1)) && ((i + j) < n1) && ((i - j) >= 0));
800 
801  if((dz >= dzMin * (j - 1)) && ((i + j) < n1) && ((i - j) >= 0)) {
802  I1[i] = 0.25 * q * Physics::c * (b[i+j] + b[i-j]) / (dz * (j - 1)); // WHY 0.25?
803  } else {
804  I1[i] = 0.0;
805  }
806  }
807 
808  MPI_Allreduce(MPI_IN_PLACE, &(I1[0]), n1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
809  for(int i = 1; i < n1 - 1; i++) {
810  if(I1[i] == 0.0)
811  I1[i] = I1[i-1];
812  }
813  I1[0] = I1[1];
814  I1[n1-1] = I1[n1-2];
815 
816 
817  //2. Remove points with identical z-value and then smooth the current profile
818  double zMin = zTail();
819  double zMax = zHead();
820  dz = (zMax - zMin) / numSlices_m; // create a window of the average slice distance
821  std::vector<double> z2(n1, 0.0);
822  std::vector<double> I2(n1, 0.0);
823  double Mz1 = 0.0;
824  double MI1 = 0.0;
825  int np = 0;
826  j = 0;
827 
828  // XXX: COMPUTE ON ALL NODES
829  // first value
830  while((j < n1) && ((z1[j] - z1[0]) <= dz)) {
831  Mz1 += z1[j];
832  MI1 += I1[j];
833  ++j;
834  ++np;
835  }
836  z2[0] = Mz1 / np;
837  I2[0] = MI1 / np;
838 
839  // following values
840  int k = 0;
841  for(int i = 1; i < n1; i++) {
842  //for(int i = my_start; i <= my_end; i++) {
843  // add new points
844  int j = 0;
845  while(((i + j) < n1) && ((z1[i+j] - z1[i]) <= dz)) {
846  if((z1[i+j] - z1[i-1]) > dz) {
847  Mz1 += z1[i+j];
848  MI1 += I1[i+j];
849  ++np;
850  }
851  ++j;
852  }
853 
854  // remove obsolete points
855  j = 1;
856  while(((i - j) >= 0) && ((z1[i-1] - z1[i-j]) < dz)) {
857  if((z1[i] - z1[i-j]) > dz) {
858  Mz1 -= z1[i-j];
859  MI1 -= I1[i-j];
860  --np;
861  }
862  ++j;
863  }
864  //z2_temp[i] = Mz1 / np;
865  //I2_temp[i] = MI1 / np;
866  z2[i-k] = Mz1 / np;
867  I2[i-k] = MI1 / np;
868 
869  // make sure there are no duplicate z coordinates
870  if(z2[i-k] <= z2[i-k-1]) {
871  I2[i-k-1] = 0.5 * (I2[i-k] + I2[i-k-1]);
872  k++;
873  }
874  }
875 
876  //MPI_Allreduce(MPI_IN_PLACE, &(z2_temp[0]), n1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
877  //MPI_Allreduce(MPI_IN_PLACE, &(I2_temp[0]), n1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
878 
880  //int k = 0;
881  //for(int i = 1; i < n1; i++) {
882  //z2[i-k] = z2_temp[i];
883  //I2[i-k] = I2_temp[i];
885  //if(z2[i-k] <= z2[i-k-1]) {
886  //I2[i-k-1] = 0.5 * (I2[i-k] + I2[i-k-1]);
887  //k++;
888  //}
889  //}
890 
891  //free(z2_temp);
892  //free(I2_temp);
893 
894  int n2 = n1 - k;
895  if(n2 < 1) {
896  msg << "Insufficient points to calculate the current (m = " << n2 << ")" << endl;
897  currentProfile_m = std::unique_ptr<Profile>(new Profile(0.0));
898  } else {
899  // 3. smooth further
900  if(n2 > 40) {
901  sgSmooth(&I2.front(), n2, n2 / 20, n2 / 20, 0, 1);
902  }
903 
904  // 4. create current profile
905  currentProfile_m = std::unique_ptr<Profile>(new Profile(&z2.front(),
906  &I2.front(), n2));
907 
911  thisBunch = this;
912 
913  double Qcalc = 0.0;
914  double z = zMin;
915  dz = (zMax - zMin) / 99;
916  for(int i = 1; i < 100; i++) {
917  Qcalc += currentProfile_m->get(z, itype_lin);
918  z += dz;
919  }
920  Qcalc *= (dz / (beta * Physics::c));
921  currentProfile_m->scale((Q_m > 0.0 ? Q_m : Physics::q_e) / Qcalc);
922  }
923 
925 }
926 
928  Inform msg("cSpaceCharge");
929 
930 #ifdef USE_HOMDYN_SC_MODEL
931  int icON = 1;
932  double zhead = zHead();
933  double ztail = zTail();
934  double L = zhead - ztail;
935 
936  for(int i = 0; i < numMySlices_m; i++) {
937 
938  if(slices_m[i]->p[SLI_z] > 0.0) {
939  double zeta = slices_m[i]->p[SLI_z] - ztail;
940  double xi = slices_m[i]->p[SLI_z] + zhead;
941  double sigma_av = (slices_m[i]->p[SLI_x] + slices_m[i]->p[SLI_y]) / 2;
942  double R = 2 * sigma_av;
943  double A = R / L / getGamma(i);
944 
945  double H1 = sqrt((1 - zeta / L) * (1 - zeta / L) + A * A) - sqrt((zeta / L) * (zeta / L) + A * A) - fabs(1 - zeta / L) + fabs(zeta / L);
946  double H2 = sqrt((1 - xi / L) * (1 - xi / L) + A * A) - sqrt((xi / L) * (xi / L) + A * A) - fabs(1 - xi / L) + fabs(xi / L);
947 
948  //FIXME: Q_act or Q?
949  //double Q = activeSlices_m * Q_m / numSlices_m;
950  Esct_m[i] = (Q_m / 2 / Physics::pi / Physics::epsilon_0 / R / R) * (H1 - icON * H2);
951  double G1 = (1 - zeta / L) / sqrt((1 - zeta / L) * (1 - zeta / L) + A * A) + (zeta / L) / sqrt((zeta / L) * (zeta / L) + A * A);
952  double G2 = (1 - xi / L) / sqrt((1 - xi / L) * (1 - xi / L) + A * A) + (xi / L) / sqrt((xi / L) * (xi / L) + A * A);
953 
954  G_m[i] = (1 - getBeta(i) * getBeta(i)) * G1 - icON * (1 + getBeta(i) * getBeta(i)) * G2;
955  }
956  }
957 #else
958  if(numSlices_m < 2) {
959  msg << "called with insufficient slices (" << numSlices_m << ")" << endl;
960  return;
961  }
962 
963  if((Q_m <= 0.0) || (currentProfile_m->max() <= 0.0)) {
964  msg << "Q or I_max <= 0.0, aborting calculation" << endl;
965  return;
966  }
967 
968  for(int i = 0; i < numMySlices_m; ++i) {
969  Esct[i] = 0.0;
970  G[i] = 0.0;
971  }
972 
973  double Imax = currentProfile_m->max();
974  int nV = 0;
975  double sm = 0.0;
976  double A0 = 0.0;
977  std::vector<double> xi(numSlices_m, 0.0);
978 
979  for(int i = 0; i < numMySlices_m; i++) {
980  if(slices_m[i]->p[SLI_z] > 0.0) {
981  nV++;
982  A0 = 4.0 * slices_m[i]->p[SLI_x] * slices_m[i]->p[SLI_y];
983  sm += A0;
984  xi[i+mySliceStartOffset_m] = A0 * (1.0 - slices_m[i]->p[SLI_beta] * slices_m[i]->p[SLI_beta]); // g2
985  }
986  }
987 
988  int nVTot = nV;
989  MPI_Allreduce(MPI_IN_PLACE, &nVTot, 1, MPI_INT, MPI_SUM, Ippl::getComm());
990  if(nVTot < 2) {
991  msg << "Exiting, to few nV slices" << endl;
992  return;
993  }
994 
995  MPI_Allreduce(MPI_IN_PLACE, &xi[0], numSlices_m, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
996  MPI_Allreduce(MPI_IN_PLACE, &sm, 1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
997  A0 = sm / nVTot;
998  double dzMin = 5.0 * Physics::c * Q_m / (Imax * numSlices_m);
999 
1000  for(int localIdx = 0; localIdx < numMySlices_m; localIdx++) {
1001  double z0 = z_m[localIdx + mySliceStartOffset_m];
1002  if(z0 > 0.0 && slices_m[localIdx]->p[SLI_beta] > BETA_MIN1) {
1003 
1004  sm = 0.0;
1005 
1006  for(int j = 0; j < numSlices_m; j++) {
1007  double zj = z_m[j];
1008  double dz = fabs(zj - z0);
1009  if((dz > dzMin) && (zj > zCat)) {
1010  double Aj = xi[j] / (dz * dz);
1011  double v = 1.0 - (1.0 / sqrt(1.0 + Aj));
1012  if(zj > z0) {
1013  sm -= v;
1014  } else {
1015  sm += v;
1016  }
1017  }
1018  }
1019 
1020  // longitudinal effect
1021  double bt = slices_m[localIdx]->p[SLI_beta];
1022  double btsq = (bt - BETA_MIN1) / (BETA_MIN2 - BETA_MIN1) * (bt - BETA_MIN1) / (BETA_MIN2 - BETA_MIN1);
1023  Esct[localIdx] = (bt < BETA_MIN1 ? 0.0 : bt < BETA_MIN2 ? btsq : 1.0);
1024  Esct[localIdx] *= Q_m * sm / (Physics::two_pi * Physics::epsilon_0 * A0 * (nVTot - 1));
1025  G[localIdx] = currentProfile_m->get(z0, itype_lin) / Imax;
1026 
1027  // tweak to compensate for non-relativity
1028  if(bt < BETA_MIN2) {
1029  if(slices_m[localIdx]->p[SLI_beta] < BETA_MIN1)
1030  G[localIdx] = 0.0;
1031  else
1032  G[localIdx] *= btsq;
1033  }
1034  }
1035  }
1036 
1037  return;
1038 #endif
1039 }
1040 
1041 double EnvelopeBunch::moveZ0(double zC) {
1042  zCat_m = zC;
1043  double dz = zC - zHead();
1044  if(dz > 0.0) {
1045  for(int i = 0; i < numMySlices_m; i++) {
1046  slices_m[i]->p[SLI_z] += dz;
1047  }
1048  backup(); // save the new state
1049  *gmsg << "EnvelopeBunch::moveZ0(): bunch moved with " << dz << " m to " << zCat_m << " m" << endl;
1050  }
1051 
1052  return dz;
1053 }
1054 
1055 double EnvelopeBunch::tReset(double dt) {
1056  double new_dt = dt;
1057 
1058  if(dt == 0.0) {
1059  new_dt = t_m;
1060  *gmsg << "EnvelopeBunch time reset at z = " << zAvg() << " m with: " << t_m << " s, new offset: " << t_m + t_offset_m << " s";
1061  }
1062 
1063  t_offset_m += new_dt;
1064  t_m -= new_dt;
1065 
1066  return new_dt;
1067 }
1068 
1092 void EnvelopeBunch::derivs(double tc, double Y[], double dYdt[]) {
1093  double g2 = 1.0 / (1.0 - Y[SLI_beta] * Y[SLI_beta]);
1094  double g = sqrt(g2);
1095  double g3 = g2 * g;
1096 
1097  double alpha = sqrt(Y[SLI_px0] * Y[SLI_px0] + Y[SLI_py0] * Y[SLI_py0]) / Y[SLI_beta] / Physics::c;
1099  dYdt[SLI_z] = Y[SLI_beta] * Physics::c * cos(alpha);
1100 
1101  //NOTE: (reason for - when using Esl(2)) In OPAL we use e_0 with a sign.
1102  // The same issue with K factors (accounted in K factor calculation)
1103  //
1106 
1108  double bg2dbdt = Y[SLI_beta] * g2 * dYdt[SLI_beta];
1109 
1110  if(solver_m & sv_radial) {
1113  double enxc2 = pow((emtnx0_m + emtbx0_m) * Physics::c / (Y[SLI_beta] * g), 2);
1114  double enyc2 = pow((emtny0_m + emtby0_m) * Physics::c / (Y[SLI_beta] * g), 2);
1115 
1116 
1117 #ifdef USE_HOMDYN_SC_MODEL
1118  //FIXME: Q_act or Q?
1119  //double Q = activeSlices_m * Q_m / numSlices_m;
1121 
1123  dYdt[SLI_x] = Y[SLI_px];
1124  dYdt[SLI_y] = Y[SLI_py];
1125 
1126  double sigma_av = (Y[SLI_x] + Y[SLI_y]) / 2;
1127 
1129  dYdt[SLI_px] = -bg2dbdt * Y[SLI_px] - KRsl_m(0) * Y[SLI_x] + (kpc / sigma_av / Y[SLI_beta] / g / 2) * G_m[currentSlice_m] + enxc2 / g3;
1130  dYdt[SLI_py] = -bg2dbdt * Y[SLI_py] - KRsl_m(1) * Y[SLI_y] + (kpc / sigma_av / Y[SLI_beta] / g / 2) * G_m[currentSlice_m] + enyc2 / g3;
1131 #else
1132  // transverse space charge
1133  // somewhat strange: I expected: c*c*I/(2*Ia) (R. Bakker)
1134  //XXX: Renes version, I[cs] already in G
1135  double kpc = 0.5 * Physics::c * Physics::c * currentProfile_m->max() / Physics::Ia;
1136 
1138  dYdt[SLI_x] = Y[SLI_px];
1139  dYdt[SLI_y] = Y[SLI_py];
1140  dYdt[SLI_px] = (kpc * G_m[currentSlice_m] / (Y[SLI_x] * Y[SLI_beta] * g3)) + enxc2 / g3 - (KRsl_m(0) * Y[SLI_x]) - (bg2dbdt * Y[SLI_px]);
1141  dYdt[SLI_py] = (kpc * G_m[currentSlice_m] / (Y[SLI_y] * Y[SLI_beta] * g3)) + enyc2 / g3 - (KRsl_m(1) * Y[SLI_y]) - (bg2dbdt * Y[SLI_py]);
1142 #endif
1143  } else {
1145  dYdt[SLI_x] = Y[SLI_px];
1146  dYdt[SLI_y] = Y[SLI_py];
1147  dYdt[SLI_px] = 0.0;
1148  dYdt[SLI_py] = 0.0;
1149  }
1150 
1151  if(solver_m & sv_offaxis) {
1152  dYdt[SLI_x0] = Y[SLI_px0];
1153  dYdt[SLI_y0] = Y[SLI_py0];
1154  dYdt[SLI_px0] = -KTsl_m(0) - (bg2dbdt * Y[SLI_px0]) + Physics::e0m * (g * Exw_m[currentSlice_m]);
1155  dYdt[SLI_py0] = -KTsl_m(1) - (bg2dbdt * Y[SLI_py0]) + Physics::e0m * (g * Eyw_m[currentSlice_m]);
1156  } else {
1157  dYdt[SLI_x0] = Y[SLI_px0];
1158  dYdt[SLI_y0] = Y[SLI_py0];
1159  dYdt[SLI_px0] = 0.0;
1160  dYdt[SLI_py0] = 0.0;
1161  }
1162 }
1163 
1164 
1167 
1168  // Calculate the current profile
1169  if(Q_m > 0.0) {
1170 
1172 #ifndef USE_HOMDYN_SC_MODEL
1173  //XXX: only used in BET-SC-MODEL
1174  // make sure all processors have all global betas and positions
1176  calcI();
1177 #endif
1179 
1180  // the following assumes space-charges do not change significantly over nSc steps
1182  cSpaceCharge();
1184 
1185  //if(numSlices_m > 40) {
1186  // smooth Esct to get rid of numerical noise
1187  //double Esc = 0;
1188  //sgSmooth(Esct,n,n/20,n/20,0,4);
1189  //}
1190  } else {
1191  currentProfile_m = std::unique_ptr<Profile>(new Profile(0.0));
1192  }
1193 
1195 }
1196 
1197 
1198 void EnvelopeBunch::timeStep(double tStep, double _zCat) {
1199  Inform msg("tStep");
1200  static int msgParsed = 0;
1201 
1202  // default accuracy of integration
1203  double eps = 1.0e-4;
1204  double time_step_s = tStep;
1205 
1206  thisBunch = this;
1207  zCat_m = _zCat;
1208 
1209  // backup last stage before new execution
1210  backup();
1211 
1212  //FIXME: HAVE A PROBLEM WITH EMISSION (EMISSION OFF GIVES GOOD RESULTS)
1214 
1215  //if(lastEmittedBin_m < nebin_m) {
1216 
1217  //time_step_s = emission_time_step_;
1218  //size_t nextBin = nebin_m - 1 - lastEmittedBin_m;
1219  //if(Ippl::Comm->myNode() == 0) cout << "Emitting bin " << nextBin << endl;
1220 
1221  //double gz0 = 0.0;
1222  //if(Ippl::Comm->myNode() == 0)
1223  //gz0 = slices_m[0]->p[SLI_z];
1224  //MPI_Allreduce(MPI_IN_PLACE, &gz0, 1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
1225 
1227  //for(int j = 0; j < bins_m[nextBin].size(); j++) {
1228  //slices_m[bins_m[nextBin][j]]->p[SLI_z] -= gz0;
1229  //slices_m[bins_m[nextBin][j]]->p[SLI_z] -= hbin_m * nextBin;
1230  //slices_m[bins_m[nextBin][j]]->emitted = true;
1231  //cout << "\tEmitting slice " << mySliceStartOffset_m + bins_m[nextBin][j] << " at " << slices_m[bins_m[nextBin][j]]->p[SLI_z] << endl;
1232  //}
1233 
1234  //lastEmittedBin_m++;
1235  //activeSlices_m += bins_m[nextBin].size();
1236  //}
1237 
1238  //activeSlices_m = min(activeSlices_m+1, numSlices_m);
1239  //if(activeSlices_m != numSlices_m)
1240  //time_step_s = emission_time_step_;
1241  //else
1242  //time_step_s = tStep;
1243 
1244  curZHead_m = zHead();
1245  curZTail_m = zTail();
1246 
1247  for(int i = 0; i < numMySlices_m; i++) {
1248  // make the current slice index global in this class
1249  currentSlice_m = i;
1250  std::shared_ptr<EnvelopeSlice> sp = slices_m[i];
1251 
1252  //if(i + mySliceStartOffset_m == numSlices_m - activeSlices_m) {
1253  //sp->emitted = true;
1254  //sp->p[SLI_z] = 0.0;
1255  //std::cout << "emitting " << i + mySliceStartOffset_m << std::endl;
1256  //}
1257 
1258  // Assign values of K for certain slices
1259  KRsl_m = KR[i];
1260  KTsl_m = KT[i];
1261  Esl_m = EF[i];
1262  Bsl_m = BF[i];
1263 
1264  // only for slices already emitted
1265  if(true /*sp->emitted*/) {
1266  // set default allowed error for integration
1267  double epsLocal = eps;
1268  // mark that the integration was not successful yet
1269  int ode_result = 1;
1270 
1271  while(ode_result == 1) {
1272 
1273  if(solver_m & sv_fixedStep) {
1274  rk4(&(sp->p[SLI_z]), SLNPAR, t_m, time_step_s, Gderivs);
1275  ode_result = 0;
1276  } else {
1277  int nok, nbad;
1278  activeSlice_m = i;
1279  ode_result = odeint(&(sp->p[SLI_z]), SLNPAR, t_m, t_m + time_step_s, epsLocal, 0.1 * time_step_s, 0.0, &nok, &nbad, Gderivs);
1280  }
1281 
1282  if(ode_result != 0) {
1283  // restore the backup
1284  sp->restore();
1285  epsLocal *= 10.0;
1286  }
1287  }
1288 
1289  if(ode_result == 1) {
1290  // use fixed step integration if dynamic fails
1291  rk4(&(sp->p[SLI_z]), SLNPAR, t_m, time_step_s, Gderivs);
1292 
1293  if(msgParsed < 2) {
1294  msg << "EnvelopeBunch::run() Switched to fixed step RK rountine for solving of DE at slice " << i << endl;
1295  msgParsed = 2;
1296  }
1297  } else if((epsLocal != eps) && (msgParsed == 0)) {
1298  msg << "EnvelopeBunch::run() integration accuracy relaxed to " << epsLocal << " for slice " << i << " (ONLY FIRST OCCURENCE MARKED!)" << endl;
1299  msgParsed = 1;
1300  }
1301  }
1302 
1303  if(slices_m[i]->check()) {
1304  msg << "Slice " << i << " no longer valid at z = " << slices_m[i]->p_old[SLI_z] << " beta = " << slices_m[i]->p_old[SLI_beta] << endl;
1305  msg << "Slice " << i << " no longer valid at z = " << slices_m[i]->p[SLI_z] << " beta = " << slices_m[i]->p[SLI_beta] << endl;
1306  isValid_m = false;
1307  return;
1308  }
1309  }
1310  // mark that slices might not be synchronized (and space charge accordingly)
1312 
1314  t_m += time_step_s;
1315 
1317  if(solver_m & sv_s_path) {
1318  int nV = 0;
1319  double ga = 0.0, x0a = 0.0, px0a = 0.0, y0a = 0.0, py0a = 0.0;
1320  double beta, fi_x, fi_y;
1321 
1322  //FIXME: BET calculates only 80 %, OPAL doesn't ?
1323 
1324  for(int i = 0; i < numMySlices_m; i++) {
1325  std::shared_ptr<EnvelopeSlice> sp = slices_m[i];
1326  if((sp->p[SLI_z] >= zCat_m) && sp->is_valid()) {
1327  ++nV;
1328  ga += sp->computeGamma();
1329  x0a += sp->p[SLI_x0];
1330  y0a += sp->p[SLI_y0];
1331  px0a += sp->p[SLI_px0];
1332  py0a += sp->p[SLI_py0];
1333  }
1334  }
1335 
1336  int nVTot = nV;
1337  reduce(nVTot, nVTot, OpAddAssign());
1338  if(nVTot > 0) {
1339  if(nV > 0) {
1340  reduce(ga, ga, OpAddAssign());
1341  reduce(x0a, x0a, OpAddAssign());
1342  reduce(px0a, px0a, OpAddAssign());
1343  reduce(y0a, y0a, OpAddAssign());
1344  reduce(py0a, py0a, OpAddAssign());
1345  }
1346  ga = ga / nVTot;
1347  x0a = x0a / nVTot;
1348  px0a = px0a / nVTot;
1349  y0a = y0a / nVTot;
1350  py0a = py0a / nVTot;
1351  } else {
1352  msg << "EnvelopeBunch::run() No valid slices to subtract average" << endl;
1353  }
1354  beta = sqrt(1.0 - (1.0 / pow(ga, 2)));
1355  fi_x = px0a / Physics::c / beta;
1356  fi_y = py0a / Physics::c / beta;
1357 
1358  dx0_m -= x0a;
1359  dy0_m -= y0a;
1360  dfi_x_m -= fi_x;
1361  dfi_y_m -= fi_y;
1362  for(int i = 0; i < numMySlices_m; i++) {
1363  std::shared_ptr<EnvelopeSlice> sp = slices_m[i];
1364 
1365  sp->p[SLI_x0] -= x0a;
1366  sp->p[SLI_y0] -= y0a;
1367  sp->p[SLI_px0] -= px0a;
1368  sp->p[SLI_py0] -= py0a;
1369  sp->p[SLI_z] += (sp->p[SLI_x0] * sin(fi_x) + sp->p[SLI_y0] * sin(fi_y));
1370  }
1371  }
1372 }
1373 
1374 void EnvelopeBunch::initialize(int num_slices, double Q, double energy, double width, double emission_time, double frac, double current, double bunch_center, double bX, double bY, double mX, double mY, double Bz0, int nbin) {
1375 
1376 #ifdef USE_HOMDYN_SC_MODEL
1377  *gmsg << "* Using HOMDYN space-charge model" << endl;
1378 #else
1379  *gmsg << "* Using BET space-charge model" << endl;
1380 #endif
1381  distributeSlices(num_slices);
1382  createBunch();
1383 
1384  this->setCharge(Q);
1385  this->setEnergy(energy);
1386 
1387  //FIXME: how do I have to set this (only used in Gauss)
1388  bunch_center = -1 * emission_time / 2.0;
1389 
1390  //FIXME: pass values
1391  nebin_m = nbin;
1392 
1393  lastEmittedBin_m = 0;
1394  activeSlices_m = 0;
1395  emission_time_step_m = emission_time / nebin_m;
1396 
1397  this->setBinnedLShape(bsRect, bunch_center, emission_time, frac);
1398  this->setTShape(mX, mY, bX, bY, Bz0);
1399 
1400  //FIXME:
1401  // 12: on-axis, radial, default track all
1402  this->setSolverParameter(12);
1403 }
1404 
1406  double bf = 0.0;
1407  for(int slice = 0; slice < numMySlices_m; slice++) {
1408  for(int i = 0; i < 3; i++) {
1409  bf += BF[slice](i);
1410  }
1411  }
1412 
1413  MPI_Allreduce(MPI_IN_PLACE, &bf, 1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
1414  return bf / numSlices_m;
1415 }
1416 
1418  double ef = 0.0;
1419  for(int slice = 0; slice < numMySlices_m; slice++) {
1420  for(int i = 0; i < 3; i++) {
1421  ef += EF[slice](i);
1422  }
1423  }
1424 
1425  MPI_Allreduce(MPI_IN_PLACE, &ef, 1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
1426  return ef / numSlices_m;
1427 }
1428 
1430  int nValid = 0;
1431  double sum = 0.0;
1432  for(int i = 0; i < numMySlices_m; i++) {
1433  if((slices_m[i]->p[SLI_z] > zCat_m) && slices_m[i]->is_valid()) {
1434  sum += slices_m[i]->computeGamma();
1435  nValid++;
1436  }
1437  }
1438  MPI_Allreduce(MPI_IN_PLACE, &nValid, 1, MPI_INT, MPI_SUM, Ippl::getComm());
1439  MPI_Allreduce(MPI_IN_PLACE, &sum, 1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
1440  sum /= nValid;
1441  return (nValid > 0 ? ((Physics::EMASS * Physics::c * Physics::c / Physics::q_e) * (sum - 1.0)) : 0.0);
1442 }
1443 
1445  //FIXME: find reference position = centroid?
1446  double refpos = 0.0;
1447  size_t count = 0;
1448  for(int i = 0; i < numMySlices_m; i++) {
1449  if(slices_m[i]->p[SLI_z] > 0.0) {
1450  refpos += slices_m[i]->p[SLI_z];
1451  count++;
1452  }
1453  }
1454 
1455  MPI_Allreduce(MPI_IN_PLACE, &count, 1, MPI_LONG, MPI_SUM, Ippl::getComm());
1456  MPI_Allreduce(MPI_IN_PLACE, &refpos, 1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
1457  return refpos / count;
1458 }
1459 
1461  int nV = 0;
1462  double sum = 0.0;
1463  for(int i = 0; i < numMySlices_m; i++) {
1464  if(slices_m[i]->is_valid()) {
1465  sum += slices_m[i]->p[SLI_z];
1466  nV++;
1467  }
1468  }
1469 
1470  MPI_Allreduce(MPI_IN_PLACE, &nV, 1, MPI_INT, MPI_SUM, Ippl::getComm());
1471  if(nV < 1) {
1472  isValid_m = false;
1473  return -1;
1474  //throw OpalException("EnvelopeBunch", "EnvelopeBunch::zAvg() no valid slices left");
1475  }
1476 
1477  MPI_Allreduce(MPI_IN_PLACE, &sum, 1, MPI_DOUBLE, MPI_SUM, Ippl::getComm());
1478  return (sum / nV);
1479 }
1480 
1482  double min;
1483 
1484  int i = 0;
1485  while((i < numMySlices_m) && (!slices_m[i]->is_valid()))
1486  i++;
1487  //throw OpalException("EnvelopeBunch", "EnvelopeBunch::zTail() no valid slices left");
1488  if(i == numMySlices_m)
1489  isValid_m = false;
1490  else
1491  min = slices_m[i]->p[SLI_z];
1492 
1493  for(i = i + 1; i < numMySlices_m; i++)
1494  if((slices_m[i]->p[SLI_z] < min) && (slices_m[i]->is_valid()))
1495  min = slices_m[i]->p[SLI_z];
1496 
1497  //reduce(min, min, OpMinAssign());
1498  MPI_Allreduce(MPI_IN_PLACE, &min, 1, MPI_DOUBLE, MPI_MIN, Ippl::getComm());
1499  return min;
1500 }
1501 
1503  double max;
1504 
1505  int i = 0;
1506  while((i < numMySlices_m) && (slices_m[i]->is_valid() == 0))
1507  i++;
1508  //throw OpalException("EnvelopeBunch", "EnvelopeBunch::zHead() no valid slices left");
1509  if(i == numMySlices_m)
1510  isValid_m = false;
1511  else
1512  max = slices_m[i]->p[SLI_z];
1513 
1514  for(i = 1; i < numMySlices_m; i++)
1515  if(slices_m[i]->p[SLI_z] > max) max = slices_m[i]->p[SLI_z];
1516 
1517  //reduce(max, max, OpMaxAssign());
1518  MPI_Allreduce(MPI_IN_PLACE, &max, 1, MPI_DOUBLE, MPI_MAX, Ippl::getComm());
1519  return max;
1520 }
1521 
1522 
1524  if(this->getTotalNum() != 0) { // to suppress Nan's
1525  os << "* ************** S L B U N C H ***************************************************** " << endl;
1526  os << "* NSlices= " << this->getTotalNum() << " Qtot= " << Q_m << endl; //" [nC] Qi= " << std::abs(qi_m) << " [C]" << endl;
1527  os << "* Emean= " << get_meanKineticEnergy() * 1e-6 << " [MeV]" << endl;
1528  os << "* dT= " << this->getdT() << " [s]" << endl;
1529  os << "* spos= " << this->zAvg() << " [m]" << endl;
1530 
1531  //os << "* rmax= " << rmax_m << " [m]" << endl;
1532  //os << "* rmin= " << rmin_m << " [m]" << endl;
1533  //os << "* rms beam size= " << rrms_m << " [m]" << endl;
1534  //os << "* rms momenta= " << prms_m << " [beta gamma]" << endl;
1535  //os << "* mean position= " << rmean_m << " [m]" << endl;
1536  //os << "* mean momenta= " << pmean_m << " [beta gamma]" << endl;
1537  //os << "* rms emmitance= " << eps_m << " (not normalized)" << endl;
1538  //os << "* rms correlation= " << rprms_m << endl;
1539  //os << "* tEmission= " << getTEmission() << " [s]" << endl;
1540  os << "* ********************************************************************************** " << endl;
1541 
1542  //Inform::FmtFlags_t ff = os.flags();
1543  //os << scientific;
1544  //os << "* ************** B U N C H ********************************************************* " << endl;
1545  //os << "* NSlices= " << this->getTotalNum() << " Qtot= " << abs(sum(Q) * 1.0E9) << " [nC]" << endl;
1546  //os << "* Ekin = " << setw(12) << setprecision(5) << eKin_m << " [MeV] dEkin= " << dE_m << " [MeV]" << endl;
1547  //os << "* rmax = " << setw(12) << setprecision(5) << rmax_m << " [m]" << endl;
1548  //os << "* rmin = " << setw(12) << setprecision(5) << rmin_m << " [m]" << endl;
1549  //os << "* rms beam size = " << setw(12) << setprecision(5) << rrms_m << " [m]" << endl;
1550  //os << "* rms momenta = " << setw(12) << setprecision(5) << prms_m << " [beta gamma]" << endl;
1551  //os << "* mean position = " << setw(12) << setprecision(5) << rmean_m << " [m]" << endl;
1552  //os << "* mean momenta = " << setw(12) << setprecision(5) << pmean_m << " [beta gamma]" << endl;
1553  //os << "* rms emittance = " << setw(12) << setprecision(5) << eps_m << " (not normalized)" << endl;
1554  //os << "* rms correlation = " << setw(12) << setprecision(5) << rprms_m << endl;
1555  //os << "* hr = " << setw(12) << setprecision(5) << hr_m << " [m]" << endl;
1556  //os << "* dh = " << setw(12) << setprecision(5) << dh_m << " [m]" << endl;
1557  //os << "* t = " << setw(12) << setprecision(5) << getT() << " [s] dT= " << getdT() << " [s]" << endl;
1558  //os << "* spos = " << setw(12) << setprecision(5) << get_sPos() << " [m]" << endl;
1559  //os << "* ********************************************************************************** " << endl;
1560  //os.flags(ff);
1561  }
1562  return os;
1563 }
std::unique_ptr< Vector_t[]> EF
external E fields
size_t mySliceEndOffset_m
last global slice on this processor
double zCat_m
cathode position
pX0 angular deflection centriod x
Definition: EnvelopeSlice.h:22
void sgSmooth(double *c, int n, int nl, int nr, int ld, int m)
Definition: savgol.cpp:457
Definition: rbendmap.h:8
IpplTimings::TimerRef selfFieldTimer_m
timer for selfField calculation
std::vector< double > Exw_m
transverse wake field x
double get_meanKineticEnergy()
returns the mean energy
void calcEmittance(double *emtnx, double *emtny, double *emtx, double *emty, int *nValid)
calculate bunch emittance
double emtnx0_m
intrinsic normalized emittance of slice [m rad]
double findRoot(void(*funcd)(double, double *, double *), double x1, double x2, double xacc)
Definition: root.cpp:35
constexpr double e
The value of .
Definition: Physics.h:40
void backup()
backup slice values
PETE_TBTree< OpGT, Index::PETE_Expr_t, PETE_Scalar< double > > gt(const Index &idx, double x)
Definition: IndexInlines.h:354
double t_m
local time in bunch [s]
std::vector< double > b_m
synchronized betas for parallel tracker
y beam size y (rms) [m]
Definition: EnvelopeSlice.h:16
core of the envelope tracker based on Rene Bakkers BET implementation
Definition: EnvelopeBunch.h:60
double dfi_x_m
rotation of coordinate system when tracking along the s-axis [rad]
int myNode() const
Definition: Communicate.h:155
std::unique_ptr< Vector_t[]> KR
define value of radial kick for each slice
unsigned int activeSlice_m
PETE_TUTree< FnFabs, typename T::PETE_Expr_t > fabs(const PETE_Expr< T > &l)
Definition: PETE.h:815
void setCharge(double _Q)
set the charge of the bunch
IpplTimings::TimerRef calcITimer_m
Definition: EnvelopeBunch.h:86
void synchronizeSlices()
synchronize z position and betas of all slices (needed in calcI and space charge calculation) ...
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:123
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
Vector_t KTsl_m
transverse kick of beam
Vector_t maxP_m
EnvelopeBunchParameter
Definition: EnvelopeBunch.h:15
constexpr double two_pi
The value of .
Definition: Physics.h:34
z slice position [m]
Definition: EnvelopeSlice.h:8
int numMySlices_m
number of my slices in bunch
virtual ~EnvelopeBunch()
void initialize(int sli, double charge, double energy, double width, double te, double frac, double current, double center, double bX, double bY, double mX, double mY, double Bz, int nbin)
Particle reference data.
Definition: PartData.h:38
Inform * gmsg
Definition: Main.cpp:21
FTps< T, N > erfc(const FTps< T, N > &x, int trunc=(FTps< T, N >::EXACT))
Complementary error function.
Definition: FTpsMath.h:414
Vector_t sigmax_m
void createBunch()
create and initialize local num slices
slice data synchronized with other MPI nodes
Definition: EnvelopeBunch.h:44
beta normalized velocity (total) [-]
Definition: EnvelopeSlice.h:10
void rk4(double y[], int n, double x, double h, void(*derivs)(double, double[], double[]))
Definition: rk.cpp:263
double getGamma(int i)
returns gamma of slice i
double zAvg()
calculate &lt;z&gt; [m]
void setTOffset(double x0, double px0, double y0, double py0)
set transverse offset of bunch
std::vector< std::vector< int > > bins_m
bins for emission
class encpasulating an envelope slice
Definition: EnvelopeSlice.h:36
T::PETE_Expr_t::PETE_Return_t sum(const PETE_Expr< T > &expr)
Definition: PETE.h:1213
double hbin_m
emission bin width
double zHead()
calculate the head of the bunch [m]
double emtbx0_m
intrinsic normalized emittance Bush effect [m rad]
transverse wakes calculated
Definition: EnvelopeBunch.h:47
constexpr double alpha
The fine structure constant, no dimension.
Definition: Physics.h:79
double AvBField()
returns average magnetic field
#define BETA_MIN1
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
Definition: GlobalComm.hpp:55
angular deflection centriod x
Definition: EnvelopeBunch.h:28
pY0 angular deflection centriod y
Definition: EnvelopeSlice.h:26
EnvelopeBunch(const PartData *ref)
Default constructor.
int solver_m
see enum SolverParameters
double Bz0_m
magnetic field on cathode [T]
beam size y [m]
Definition: EnvelopeBunch.h:22
Vector_t minP_m
int dStat_m
see enum DataStatus
constexpr double pi
The value of .
Definition: Physics.h:31
py beam divergence y [rad]
Definition: EnvelopeSlice.h:18
void setTShape(double enx, double eny, double rx, double ry, double b0)
set transverse shape of bunch (initial distribution)
double zTail()
calculate tail of bunch [m]
std::unique_ptr< Vector_t[]> BF
external B fields
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:52
int numSlices_m
number of total slices in bunch
std::unique_ptr< Profile > currentProfile_m
current profile of bunch (fit)
Definition: EnvelopeBunch.h:84
static void startTimer(TimerRef t)
Definition: IpplTimings.h:187
int currentSlice_m
current Slice set in run() &amp; cSpaceCharge() and used in derivs() &amp; zcsI()
double get_sPos()
return reference position
include radial movement in DV
Definition: EnvelopeBunch.h:35
Vector_t Esl_m
electric field
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
double I0avg_m
average current on creation of bunch (see setLshape)
size_t lastEmittedBin_m
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
fields synchronized with other MPI nodes
Definition: EnvelopeBunch.h:43
X0 position centroid x [m].
Definition: EnvelopeSlice.h:20
int getLocalNum()
returns the number of local slices
void linfit(double x[], double y[], int ndata, double sig[], int mwt, double *a, double *b, double *siga, double *sigb, double *chi2, double *q)
Definition: linfit.cpp:167
static MPI_Comm getComm()
Definition: IpplInfo.h:178
slice position [m]
Definition: EnvelopeBunch.h:19
constexpr double e0mc
Definition: Physics.h:149
std::vector< double > Esct_m
Longitudinal Space-charge field.
int activeSlices_m
number of active slices
void calcI()
calculates the current current distribution
double Eavg()
calculate the average energy of the bunch
std::vector< std::shared_ptr< EnvelopeSlice > > slices_m
array of slices
double emission_time_step_m
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
constexpr double Ia
Definition: Physics.h:145
ParticleAttrib< double > dt
beam divergence y
Definition: EnvelopeBunch.h:24
Lorenz factor.
Definition: EnvelopeBunch.h:18
std::vector< double > Ezw_m
longitudinal wake field
EnvelopeBunchShape
Definition: EnvelopeBunch.h:50
void derivs(double tc, double Y[], double dYdt[])
helper function to calculate derivatives need in RH equation
Inform & slprint(Inform &os)
void computeSpaceCharge()
number of slice parameters
Definition: EnvelopeSlice.h:28
longitudinal wakes
Definition: EnvelopeBunch.h:37
double AvEField()
returns average electric field
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
Vector_t norm_emtn_m
normalized velocity (total) [-]
Definition: EnvelopeBunch.h:17
std::vector< double > z_m
synchronized z positions for parallel tracker
constexpr double q_e
The elementary charge in As.
Definition: Physics.h:76
double t_offset_m
accumulated time offset by tReset function
constexpr double e0m
Definition: Physics.h:147
void distributeSlices(int nSlice=101)
distributes nSlice amongst processors and initializes slices
void setBinnedLShape(EnvelopeBunchShape shape, double z0, double w, double frac)
set longitudinal shape of bunch (initial distribution)
Particle Bunch.
Definition: PartBunch.h:30
int odeint(double ystart[], int nvar, double x1, double x2, double eps, double h1, double hmin, int *nok, int *nbad, void(*derivs)(double, double[], double[]))
Definition: rk.cpp:323
beam size x [m]
Definition: EnvelopeBunch.h:21
Y0 position centroid y [m].
Definition: EnvelopeSlice.h:24
void setSolverParameter(int s)
set the DE solver flag
x beam size x (rms) [m]
Definition: EnvelopeSlice.h:12
beam divergence x
Definition: EnvelopeBunch.h:23
double getBeta(int i)
returns beta of slice i
double Q_m
total bunch charge [C]
Vector_t KRsl_m
radial focussing term beam
Vector_t maxX_m
constexpr double epsilon_0
The permittivity of vacuum in As/Vm.
Definition: Physics.h:58
double tReset(double dt=0.0)
constexpr double EMASS
Definition: Physics.h:140
void timeStep(double tStep, double zCat=0.0)
performs a time-step for all active slices (also handles emission)
px beam divergence x [rad]
Definition: EnvelopeSlice.h:14
position centroid y [m]
Definition: EnvelopeBunch.h:27
Vector_t emtn_m
static TimerRef getTimer(const char *nm)
Definition: IpplTimings.h:182
std::vector< double > Eyw_m
transverse wake field y
IpplTimings::TimerRef statParamTimer_m
int nebin_m
number of bins for emission
include off-axis movement in DV
Definition: EnvelopeBunch.h:36
beam divergence z
Definition: EnvelopeBunch.h:25
int getTotalNum()
returns the total number of slices
static void stopTimer(TimerRef t)
Definition: IpplTimings.h:192
double moveZ0(double zC)
move the complete bunch forward such that the head of the bunch matches the cahtode position ...
current [A]
Definition: EnvelopeBunch.h:20
Definition: Inform.h:41
void setEnergy(double, double=0.0)
static Communicate * Comm
Definition: IpplInfo.h:93
Vector_t Bsl_m
magnetic field
transverse wakes
Definition: EnvelopeBunch.h:38
void runStats(EnvelopeBunchParameter sp, double *xAvg, double *xMax, double *xMin, double *rms, int *nValid)
run statistics on slices
Vector_t minX_m
void calcBeamParameters()
calculates envelope statistics
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:95
Vector_t sigmap_m
int firstBinWithValue_m
first bin on processor containing slices
void calcEnergyChirp(double *g0, double *dgdt, double *gInc, int *nValid)
calculate the energy chirp and uncorrelated energy spread
IpplTimings::TimerRef spaceChargeTimer_m
Definition: EnvelopeBunch.h:87
std::unique_ptr< Vector_t[]> KT
define value of transversal kick for each slice
position centroid x [m]
Definition: EnvelopeBunch.h:26
int getNodes() const
Definition: Communicate.h:143
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
size_t mySliceStartOffset_m
first global slice on this processor
double dx0_m
offset of the coordinate system when tracking along the s-axis [m]
solve field outside of DV
Definition: EnvelopeBunch.h:34
std::vector< double > G_m
Transverse Space-charge term: Eq.(9)