OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
CSRWakeFunction.cpp
Go to the documentation of this file.
3 
5 #include "Filters/Filter.h"
7 #include "Physics/Physics.h"
8 #include "AbsBeamline/RBend.h"
9 #include "AbsBeamline/SBend.h"
10 #include "Utilities/Options.h"
11 #include "Utilities/Util.h"
12 
13 #include <iostream>
14 #include <fstream>
15 
16 extern Inform *gmsg;
17 
18 CSRWakeFunction::CSRWakeFunction(const std::string &name, ElementBase *element, std::vector<Filter *> filters, const unsigned int &N):
19  WakeFunction(name, element, N),
20  filters_m(filters.begin(), filters.end()),
21  lineDensity_m(),
22  dlineDensitydz_m(),
23  bendRadius_m(0.0),
24  totalBendAngle_m(0.0)
25 {
26  if (filters_m.size() == 0) {
27  defaultFilter_m.reset(new SavitzkyGolayFilter(7, 3, 3, 3));
28  filters_m.push_back(defaultFilter_m.get());
29  }
30 
31  diffOp_m = filters_m.back();
32 }
33 
35  Inform msg("CSRWake ");
36 
37  const double sPos = bunch->get_sPos();
38  std::pair<double, double> meshInfo;
39  calculateLineDensity(bunch, meshInfo);
40  const double &meshSpacing = meshInfo.second;
41  const double &meshOrigin = meshInfo.first + 0.5 * meshSpacing;
42 
43  if(Ez_m.size() < lineDensity_m.size()) {
44  Ez_m.resize(lineDensity_m.size(), 0.0);
45  Psi_m.resize(lineDensity_m.size(), 0.0);
46  }
47 
48  Vector_t smin, smax;
49  bunch->get_bounds(smin, smax);
50  double minPathLength = smin(2) + sPos - FieldBegin_m;
51  if (sPos + smax(2) < FieldBegin_m) return;
52 
53  Ez_m[0] = 0.0;
54  // calculate wake field of bunch
55  for(unsigned int i = 1; i < lineDensity_m.size(); ++i) {
56  Ez_m[i] = 0.0;
57 
58  double angleOfSlice = 0.0;
59  double pathLengthOfSlice = minPathLength + i * meshSpacing;
60  if(pathLengthOfSlice > 0.0)
61  angleOfSlice = pathLengthOfSlice / bendRadius_m;
62 
63  calculateContributionInside(i, angleOfSlice, meshSpacing);
64  calculateContributionAfter(i, angleOfSlice, meshSpacing);
65 
66  Ez_m[i] /= (4. * Physics::pi * Physics::epsilon_0);
67  }
68 
69  // calculate the wake field seen by the particles
70  for(unsigned int i = 0; i < bunch->getLocalNum(); ++i) {
71  const Vector_t &R = bunch->R[i];
72  double distanceToOrigin = (R(2) - meshOrigin) / meshSpacing;
73 
74  unsigned int indexz = (unsigned int)floor(distanceToOrigin);
75  double leverz = distanceToOrigin - indexz;
76  PAssert_LT(indexz, lineDensity_m.size() - 1);
77 
78  bunch->Ef[i](2) += (1. - leverz) * Ez_m[indexz] + leverz * Ez_m[indexz + 1];
79  }
80 
81  if(Options::csrDump) {
82  static std::string oldBendName;
83  static unsigned long counter = 0;
84 
85  if(oldBendName != bendName_m) counter = 0;
86 
87  const int every = 1;
88  bool print_criterion = (counter + 1) % every == 0;
89  if(print_criterion) {
90  static unsigned int file_number = 0;
91  if(counter == 0) file_number = 0;
92  if (Ippl::myNode() == 0) {
93  std::stringstream filename_str;
94  filename_str << "data/" << bendName_m << "-CSRWake" << std::setw(5) << std::setfill('0') << file_number << ".txt";
95 
96  std::ofstream csr(filename_str.str().c_str());
97  csr << std::setprecision(8);
98  csr << "# " << sPos + smin(2) - FieldBegin_m << "\t" << sPos + smax(2) - FieldBegin_m << std::endl;
99  for(unsigned int i = 0; i < lineDensity_m.size(); ++ i) {
100  csr << i *meshSpacing << "\t"
101  << Ez_m[i] << "\t"
102  << lineDensity_m[i] << "\t"
103  << dlineDensitydz_m[i] << std::endl;
104  }
105  csr.close();
106  msg << "** wrote " << filename_str.str() << endl;
107  }
108  ++ file_number;
109  }
110  ++ counter;
111  oldBendName = bendName_m;
112  }
113 }
114 
116  if(ref->getType() == ElementBase::RBEND ||
117  ref->getType() == ElementBase::SBEND) {
118 
119  const Bend2D *bend = static_cast<const Bend2D *>(ref);
120  double End;
121 
122  bendRadius_m = bend->getBendRadius();
123  bend->getDimensions(Begin_m, End);
124  Length_m = bend->getEffectiveLength();
125  FieldBegin_m = bend->getEffectiveCenter() - Length_m / 2.0;
127  bendName_m = bend->getName();
128  }
129 }
130 
131 void CSRWakeFunction::calculateLineDensity(PartBunchBase<double, 3> *bunch, std::pair<double, double> &meshInfo) {
132  bunch->calcLineDensity(nBins_m, lineDensity_m, meshInfo);
133 
134  std::vector<Filter *>::const_iterator fit;
135  for(fit = filters_m.begin(); fit != filters_m.end(); ++ fit) {
136  (*fit)->apply(lineDensity_m);
137  }
138 
139  dlineDensitydz_m.assign(lineDensity_m.begin(), lineDensity_m.end());
140  diffOp_m->calc_derivative(dlineDensitydz_m, meshInfo.second);
141 }
142 
143 void CSRWakeFunction::calculateContributionInside(size_t sliceNumber, double angleOfSlice, double meshSpacing) {
144  if(angleOfSlice > totalBendAngle_m || angleOfSlice < 0.0) return;
145 
146  const double meshSpacingsup = pow(meshSpacing, -1. / 3.);
147  double SlippageLength = pow(angleOfSlice, 3) * bendRadius_m / 24.;
148  double relativeSlippageLength = SlippageLength / meshSpacing;
149  if(relativeSlippageLength > sliceNumber) {
150 
151  /*
152  Break integral into sum of integrals between grid points, then
153  use linear interpolation between each grid point.
154  */
155 
156  double dx1 = pow(sliceNumber, 2. / 3.);
157  double dx2 = pow(sliceNumber, 5. / 3.);
158  double dx3 = pow(sliceNumber - 1., 5. / 3.);
159  Ez_m[sliceNumber] += 0.3 * meshSpacingsup * dlineDensitydz_m[0] * (5. * dx1 - 3. * dx2 + 3. * dx3);
160  for(unsigned int j = 1; j < sliceNumber; ++ j) {
161  dx1 = dx2;
162  dx2 = dx3;
163  dx3 = pow(sliceNumber - j - 1., 5. / 3.);
164  Ez_m[sliceNumber] += 0.9 * meshSpacingsup * dlineDensitydz_m[j] * (dx1 - 2.* dx2 + dx3);
165  }
166  Ez_m[sliceNumber] += 0.9 * meshSpacingsup * dlineDensitydz_m[sliceNumber];
167 
168  } else if(relativeSlippageLength < 1) {
169 
170  // First do transient term.
171  if(4.0 * relativeSlippageLength <= 1) {
172 
173  Ez_m[sliceNumber] += 3.0 * pow(SlippageLength, 2.0 / 3.0) * (lineDensity_m[sliceNumber] - lineDensity_m[sliceNumber - 1]) / meshSpacing;
174  } else {
175 
176  if(4.0 * relativeSlippageLength < sliceNumber) {
177 
178  int j = sliceNumber - static_cast<int>(floor(4.0 * relativeSlippageLength));
179  double frac = 4.0 * relativeSlippageLength - (sliceNumber - j);
180  Ez_m[sliceNumber] -= (frac * lineDensity_m[j - 1] + (1. - frac) * lineDensity_m[j]) / pow(SlippageLength, 1. / 3.);
181 
182  }
183 
184  Ez_m[sliceNumber] += (relativeSlippageLength * lineDensity_m[sliceNumber - 1] + (1. - relativeSlippageLength) * lineDensity_m[sliceNumber]) / pow(SlippageLength, 1. / 3.);
185 
186  }
187 
188  // Now do steady state term.
189  Ez_m[sliceNumber] += (0.3 / meshSpacing) * pow(SlippageLength, 2. / 3.) * (5. * dlineDensitydz_m[sliceNumber] - 2. * relativeSlippageLength * (dlineDensitydz_m[sliceNumber] - dlineDensitydz_m[sliceNumber - 1]));
190 
191  } else {
192 
193  if(4. * relativeSlippageLength < sliceNumber) {
194 
195  int j = sliceNumber - static_cast<int>(floor(4. * relativeSlippageLength));
196  double frac = 4. * relativeSlippageLength - (sliceNumber - j);
197  Ez_m[sliceNumber] -= (frac * lineDensity_m[j - 1] + (1. - frac) * lineDensity_m[j]) / pow(SlippageLength, 1. / 3.);
198 
199  }
200 
201  int j = sliceNumber - static_cast<int>(floor(SlippageLength / meshSpacing));
202  double frac = relativeSlippageLength - (sliceNumber - j);
203  Ez_m[sliceNumber] += (frac * lineDensity_m[j - 1] + (1. - frac) * lineDensity_m[j]) / pow(SlippageLength, 1. / 3.);
204 
205  double dx1 = pow(sliceNumber - j + frac, 2. / 3.);
206  double dx2 = pow(sliceNumber - j, 2. / 3.);
207  double dx3 = pow(sliceNumber - j + frac, 5. / 3.);
208  double dx4 = pow(sliceNumber - j, 5. / 3.);
209 
210  Ez_m[sliceNumber] += 1.5 * meshSpacingsup * dlineDensitydz_m[j - 1] * (dx1 - dx2);
211  Ez_m[sliceNumber] += 0.3 * meshSpacingsup * (dlineDensitydz_m[j] - dlineDensitydz_m[j - 1]) * (5.*(dx1 - dx2) + 3.*(dx3 - dx4));
212 
213  dx1 = dx2;
214  dx2 = dx4;
215  dx3 = pow(sliceNumber - j - 1., 5. / 3.);
216  Ez_m[sliceNumber] += 0.3 * meshSpacingsup * dlineDensitydz_m[j] * (5.*dx1 - 3.*dx2 + 3.*dx3);
217  for(unsigned int k = j + 1; k < sliceNumber; ++ k) {
218  dx1 = dx2;
219  dx2 = dx3;
220  dx3 = pow(sliceNumber - k - 1., 5. / 3.);
221  Ez_m[sliceNumber] += 0.9 * meshSpacingsup * dlineDensitydz_m[k] * (dx1 - 2.*dx2 + dx3);
222  }
223  Ez_m[sliceNumber] += 0.9 * meshSpacingsup * dlineDensitydz_m[sliceNumber];
224  }
225  double prefactor = -2. / pow(3. * bendRadius_m * bendRadius_m, 1. / 3.);
226  Ez_m[sliceNumber] *= prefactor;
227 }
228 
229 void CSRWakeFunction::calculateContributionAfter(size_t sliceNumber, double angleOfSlice, double meshSpacing) {
230  if(angleOfSlice <= totalBendAngle_m) return;
231 
232  double Ds_max = bendRadius_m * pow(totalBendAngle_m, 3) / 24. * (4. - 3.* totalBendAngle_m / angleOfSlice);
233 
234  // First do contribution from particles whose retarded position is
235  // prior to the bend.
236  double Ds_max2 = bendRadius_m * pow(totalBendAngle_m, 2) / 6. * (3. * angleOfSlice - 2. * totalBendAngle_m);
237  int j = 0;
238  double frac = 0.0;
239  if(Ds_max2 / meshSpacing < sliceNumber) {
240  j = sliceNumber - static_cast<int>(floor(Ds_max2 / meshSpacing));
241  frac = Ds_max2 / meshSpacing - (sliceNumber - j);
242  Ez_m[sliceNumber] -= (frac * lineDensity_m[j - 1] + (1. - frac) * lineDensity_m[j]) / (2. * angleOfSlice - totalBendAngle_m);
243  }
244 
245  // Now do delta function contribution for particles whose retarded position
246  // is in the bend.
247  if(Ds_max / meshSpacing < sliceNumber) {
248  j = sliceNumber - static_cast<int>(floor(Ds_max / meshSpacing));
249  frac = Ds_max / meshSpacing - (sliceNumber - j);
250  Ez_m[sliceNumber] += (frac * lineDensity_m[j - 1] + (1.0 - frac) * lineDensity_m[j]) / (2. * angleOfSlice - totalBendAngle_m);
251  }
252 
253  // Now do integral contribution for particles whose retarded position is in
254  // the bend.
255 
256  double angleOverlap = angleOfSlice - totalBendAngle_m;
257  int k = sliceNumber;
258  if(Ds_max / meshSpacing < sliceNumber) {
259  k = j;
260  Psi_m[k] = calcPsi(Psi_m[k], angleOverlap, meshSpacing * (k + frac));
261  if(Psi_m[k] > 0 && Psi_m[k] < totalBendAngle_m)
262  Ez_m[sliceNumber] += 0.5 * (frac * dlineDensitydz_m[sliceNumber - k - 1] + (1.0 - frac) * dlineDensitydz_m[sliceNumber - k]) / (Psi_m[k] + 2.0 * angleOverlap);
263  } else {
264  Psi_m[0] = calcPsi(Psi_m[0], angleOverlap, meshSpacing * sliceNumber);
265  if(Psi_m[0] > 0 && Psi_m[0] < totalBendAngle_m)
266  Ez_m[sliceNumber] += 0.5 * dlineDensitydz_m[0] / (Psi_m[0] + 2.0 * angleOverlap);
267  }
268 
269  // Do rest of integral.
270  for(unsigned int l = sliceNumber - k + 1; l < sliceNumber; ++ l) {
271  Psi_m[l] = calcPsi(Psi_m[l], angleOverlap, meshSpacing * (sliceNumber - l));
272  if(Psi_m[l] > 0 && Psi_m[l] < totalBendAngle_m)
273  Ez_m[sliceNumber] += dlineDensitydz_m[l] / (Psi_m[l] + 2.0 * angleOverlap);
274  }
275 
276  // We don't go right to the end as there is a singularity in the numerical integral that we don't quite know
277  // how to deal with properly yet. This introduces a very slight error in the calculation (fractions of a percent).
278  Psi_m[sliceNumber] = calcPsi(Psi_m[sliceNumber], angleOverlap, meshSpacing / 4.0);
279  if(Psi_m[sliceNumber] > 0 && Psi_m[sliceNumber] < totalBendAngle_m)
280  Ez_m[sliceNumber] += 0.5 * dlineDensitydz_m[sliceNumber] / (Psi_m[sliceNumber] + 2.0 * angleOverlap);
281 
282  double prefactor = -4 / bendRadius_m;
283  Ez_m[sliceNumber] *= prefactor;
284 }
285 
286 double CSRWakeFunction::calcPsi(const double &psiInitial, const double &x, const double &Ds) const {
294  const int Nmax = 100;
295  const double eps = 1e-10;
296 
297  double residual = 0.0;
298  double psi = pow(24. * Ds / bendRadius_m, 1. / 3.);
299  if(psiInitial != 0.0) psi = psiInitial;
300 
301  for(int i = 0; i < Nmax; ++i) {
302  residual = bendRadius_m * psi * psi * psi * (psi + 4. * x) - 24. * Ds * psi - 24. * Ds * x;
303  if(std::abs(residual) < eps)
304  return psi;
305 
306  psi -= residual / (4. * bendRadius_m * psi * psi * psi + 12. * x * bendRadius_m * psi * psi - 24. * Ds);
307  }
308 
309  RootFinderForCSR rootFinder(bendRadius_m, 4 * x * bendRadius_m, -24 * Ds, -24 * Ds * x);
310  if (rootFinder.hasPositiveRealRoots()) {
311  return rootFinder.searchRoot(eps);
312  }
313 
314  ERRORMSG("In CSRWakeFunction::calcPsi(): exceed maximum number of iterations!" << endl);
315  return psi;
316 }
317 
318 const std::string CSRWakeFunction::getType() const {
319  return "CSRWakeFunction";
320 }
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
void calculateContributionInside(size_t sliceNumber, double angleOfSlice, double meshSpacing)
constexpr double e
The value of .
Definition: Physics.h:40
virtual void getDimensions(double &sBegin, double &sEnd) const
Definition: Bend2D.h:304
ParticleAttrib< Vector_t > Ef
const unsigned int nBins_m
Definition: WakeFunction.hh:27
Interface for basic beam line object.
Definition: ElementBase.h:128
CSRWakeFunction(const std::string &name, ElementBase *element, std::vector< Filter * > filters, const unsigned int &N)
#define ERRORMSG(msg)
Definition: IpplInfo.h:399
Inform * gmsg
Definition: Main.cpp:21
double getBendRadius() const
Definition: Bend2D.h:310
static int myNode()
Definition: IpplInfo.cpp:794
virtual const std::string & getName() const
Get element name.
Definition: ElementBase.cpp:95
std::shared_ptr< Filter > defaultFilter_m
void initialize(const ElementBase *ref)
virtual ElementType getType() const =0
Get element type std::string.
double getEffectiveLength() const
Definition: Bend2D.h:320
std::vector< Filter * > filters_m
double getBendAngle() const
Definition: BendBase.h:86
#define PAssert_LT(a, b)
Definition: PAssert.h:121
std::vector< double > Psi_m
constexpr double pi
The value of .
Definition: Physics.h:31
std::string bendName_m
void calculateContributionAfter(size_t sliceNumber, double angleOfSlice, double meshSpacing)
Definition: Bend2D.h:51
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
std::vector< double > Ez_m
double calcPsi(const double &psiInitial, const double &x, const double &Ds) const
size_t getLocalNum() const
LineDensity dlineDensitydz_m
double searchRoot(const double &tol)
void calculateLineDensity(PartBunchBase< double, 3 > *bunch, std::pair< double, double > &meshInfo)
const std::string name
constexpr double epsilon_0
The permittivity of vacuum in As/Vm.
Definition: Physics.h:58
ParticlePos_t & R
double getEffectiveCenter() const
Definition: Bend2D.h:315
void get_bounds(Vector_t &rmin, Vector_t &rmax)
LineDensity lineDensity_m
Definition: Inform.h:41
virtual const std::string getType() const
virtual void calc_derivative(std::vector< double > &histogram, const double &h)=0
void apply(PartBunchBase< double, 3 > *bunch)
void calcLineDensity(unsigned int nBins, std::vector< double > &lineDensity, std::pair< double, double > &meshInfo)
calculates the 1d line density (not normalized) and append it to a file.
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition: PETE.h:816
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
bool csrDump
Definition: Options.cpp:12