OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
CSRIGFWakeFunction.cpp
Go to the documentation of this file.
4 #include "Filters/Filter.h"
6 #include "Physics/Physics.h"
7 #include "AbsBeamline/RBend.h"
8 #include "AbsBeamline/SBend.h"
9 #include "Utilities/Options.h"
10 #include "Utilities/Util.h"
11 
12 #include <iostream>
13 #include <fstream>
14 
15 extern Inform *gmsg;
16 
17 CSRIGFWakeFunction::CSRIGFWakeFunction(const std::string &name, ElementBase *element, std::vector<Filter *> filters, const unsigned int &N):
18  WakeFunction(name, element, N),
19  filters_m(filters.begin(), filters.end()),
20  lineDensity_m(),
21  dlineDensitydz_m(),
22  bendRadius_m(0.0),
23  totalBendAngle_m(0.0)
24 {
25  if (filters_m.size() == 0) {
26  defaultFilter_m.reset(new SavitzkyGolayFilter(7, 3, 3, 3));
27  filters_m.push_back(defaultFilter_m.get());
28  }
29 
30  diffOp_m = filters_m.back();
31 }
32 
34  Inform msg("CSRWake ");
35 
36  std::pair<double, double> meshInfo;
37  calculateLineDensity(bunch, meshInfo);
38  const double &meshOrigin = meshInfo.first;
39  const double &meshSpacing = meshInfo.second;
40  const unsigned int numOfSlices = lineDensity_m.size();
41 
42  if(Ez_m.size() < numOfSlices) {
43  Ez_m.resize(numOfSlices, 0.0);
44  Chi_m.resize(numOfSlices, 0.0);
45  Grn_m.resize(numOfSlices, 0.0);
46  Psi_m.resize(numOfSlices, 0.0);
47  }
48 
49  for(unsigned int i = 0; i < numOfSlices; ++i) {
50  Ez_m[i] = 0.0;
51  }
52 
53  Vector_t smin, smax;
54  bunch->get_bounds(smin, smax);
55  double minPathLength = smin(2) + bunch->get_sPos() - FieldBegin_m;
56  for(unsigned int i = 1; i < numOfSlices; i++) {
57  double pathLengthOfSlice = minPathLength + i * meshSpacing;
58  double angleOfSlice = pathLengthOfSlice/bendRadius_m;
59  if (angleOfSlice > 0.0 && angleOfSlice <= totalBendAngle_m){
60  calculateGreenFunction(bunch, meshSpacing);
61  }
62  // convolute with line density
63  calculateContributionInside(i, angleOfSlice, meshSpacing);
64  calculateContributionAfter(i, angleOfSlice, meshSpacing);
66  }
67 
68  // calculate the wake field seen by the particles
69  for(unsigned int i = 0; i < bunch->getLocalNum(); ++i) {
70  const Vector_t &R = bunch->R[i];
71  unsigned int indexz = (unsigned int)floor((R(2) - meshOrigin) / meshSpacing);
72  double leverz = (R(2) - meshOrigin) / meshSpacing - indexz;
73  PAssert_LT(indexz + 1, numOfSlices);
74 
75  bunch->Ef[i](2) += (1. - leverz) * Ez_m[indexz] + leverz * Ez_m[indexz + 1];
76  }
77 
78  if(Options::csrDump) {
79  static std::string oldBendName;
80  static unsigned long counter = 0;
81 
82  if(oldBendName != bendName_m) counter = 0;
83 
84  const int every = 1;
85  bool print_criterion = (counter + 1) % every == 0;
86  if(print_criterion) {
87  static unsigned int file_number = 0;
88  if(counter == 0) file_number = 0;
89  double spos = bunch->get_sPos();
90  if (Ippl::myNode() == 0) {
91  std::stringstream filename_str;
92  filename_str << "data/" << bendName_m << "-CSRWake" << std::setw(5) << std::setfill('0') << file_number << ".txt";
93  std::ofstream csr(filename_str.str().c_str());
94  csr << spos << ", " << FieldBegin_m << ", " << smin(2) << ", " << smax(2) << ", " << meshSpacing*64 << std::endl;
95  for(unsigned int i = 0; i < lineDensity_m.size(); ++ i) {
96  csr << i *meshSpacing << "\t"
97  << Ez_m[i] << "\t"
98  << lineDensity_m[i] << std::endl;
99  }
100  csr.close();
101  msg << "** wrote " << filename_str.str() << endl;
102  }
103  ++ file_number;
104  }
105  ++ counter;
106  oldBendName = bendName_m;
107  }
108 }
109 
111  if(ref->getType() == ElementBase::RBEND ||
112  ref->getType() == ElementBase::SBEND) {
113 
114  const Bend2D *bend = static_cast<const Bend2D *>(ref);
115  double End;
116 
117  bendRadius_m = bend->getBendRadius();
118  bend->getDimensions(Begin_m, End);
119  Length_m = bend->getEffectiveLength();
120  FieldBegin_m = bend->getEffectiveCenter() - Length_m / 2.0;
122  bendName_m = bend->getName();
123  }
124 }
125 
126 void CSRIGFWakeFunction::calculateLineDensity(PartBunchBase<double, 3> *bunch, std::pair<double, double> &meshInfo) {
127  bunch->calcLineDensity(nBins_m, lineDensity_m, meshInfo);
128 
129  // the following is only needed for after dipole
130  std::vector<Filter *>::const_iterator fit;
131  for(fit = filters_m.begin(); fit != filters_m.end(); ++ fit) {
132  (*fit)->apply(lineDensity_m);
133  }
134  dlineDensitydz_m.assign(lineDensity_m.begin(), lineDensity_m.end());
135  diffOp_m->calc_derivative(dlineDensitydz_m, meshInfo.second);
136 }
137 
139 {
140  unsigned int numOfSlices = lineDensity_m.size();
141  double gamma = bunch->get_meanKineticEnergy()/(bunch->getM()*1e-6)+1.0;
142  double xmu_const = 3.0 * gamma * gamma * gamma / (2.0 * bendRadius_m);
143  double chi_const = 9.0 / 16.0 * (6.0 - log(27.0 / 4.0));
144 
145  for(unsigned int i = 0; i < numOfSlices; ++i) {
146  Chi_m[i] = 0.0;
147  double z = i * meshSpacing;
148  double xmu = xmu_const * z;
149  double b = sqrt(xmu * xmu + 1.0) + xmu;
150  if(xmu < 1e-3)
151  Chi_m[i] = chi_const + 0.5 * pow(xmu, 2) - 7.0 / 54.0 * pow(xmu, 4) + 140.0 / 2187.0 * pow(xmu, 6);
152  else
153  Chi_m[i] = 9.0 / 16.0 * (3.0 * (-2.0 * xmu * pow(b, 1.0/3.0) + pow(b, 2.0/3.0) + pow(b, 4.0/3.0)) +
154  log(pow((1 - pow(b, 2.0 / 3.0)) / xmu, 2) / (1 + pow(b, 2.0 / 3.0) + pow(b, 4.0 / 3.0))));
155  }
156  double grn_const = -16.0/(27.0 * gamma * gamma * meshSpacing);
157  Grn_m[0] = grn_const * (Chi_m[1] - Chi_m[0]);
158  Grn_m[numOfSlices - 1] = 0.0;
159  for(unsigned int i = 1; i < numOfSlices - 1; ++i) {
160  Grn_m[i] = grn_const * (Chi_m[i + 1] - 2.0 * Chi_m[i] + Chi_m[i - 1]);
161  }
162 }
163 
164 void CSRIGFWakeFunction::calculateContributionInside(size_t sliceNumber, double angleOfSlice, double meshSpacing)
165 {
166  if(angleOfSlice > totalBendAngle_m || angleOfSlice < 0.0) return;
167  int startSliceNum = 0;
168  for(int j = sliceNumber; j >= startSliceNum; j--)
169  Ez_m[sliceNumber] += lineDensity_m[j] * Grn_m[sliceNumber - j];
170 }
171 
172 void CSRIGFWakeFunction::calculateContributionAfter(size_t sliceNumber, double angleOfSlice, double meshSpacing) {
173  if(angleOfSlice <= totalBendAngle_m) return;
174 
175  double Ds_max = bendRadius_m * pow(totalBendAngle_m, 3) / 24. * (4. - 3.* totalBendAngle_m / angleOfSlice);
176 
177  // First do contribution from particles whose retarded position is
178  // prior to the bend.
179  double Ds_max2 = bendRadius_m * pow(totalBendAngle_m, 2) / 6. * (3. * angleOfSlice - 2. * totalBendAngle_m);
180  int j = 0;
181  double frac = 0.0;
182  if(Ds_max2 / meshSpacing < sliceNumber) {
183  j = sliceNumber - static_cast<int>(floor(Ds_max2 / meshSpacing));
184  frac = Ds_max2 / meshSpacing - (sliceNumber - j);
185  Ez_m[sliceNumber] -= (frac * lineDensity_m[j - 1] + (1. - frac) * lineDensity_m[j]) / (2. * angleOfSlice - totalBendAngle_m);
186  }
187 
188  // Now do delta function contribution for particles whose retarded position
189  // is in the bend.
190  if(Ds_max / meshSpacing < sliceNumber) {
191  j = sliceNumber - static_cast<int>(floor(Ds_max / meshSpacing));
192  frac = Ds_max / meshSpacing - (sliceNumber - j);
193  Ez_m[sliceNumber] += (frac * lineDensity_m[j - 1] + (1.0 - frac) * lineDensity_m[j]) / (2. * angleOfSlice - totalBendAngle_m);
194  }
195 
196  // Now do integral contribution for particles whose retarded position is in
197  // the bend.
198 
199  double angleOverlap = angleOfSlice - totalBendAngle_m;
200  int k = sliceNumber;
201  if(Ds_max / meshSpacing < sliceNumber) {
202  k = j;
203  Psi_m[k] = calcPsi(Psi_m[k], angleOverlap, meshSpacing * (k + frac));
204  if(Psi_m[k] > 0 && Psi_m[k] < totalBendAngle_m)
205  Ez_m[sliceNumber] += 0.5 * (frac * dlineDensitydz_m[sliceNumber - k - 1] + (1.0 - frac) * dlineDensitydz_m[sliceNumber - k]) / (Psi_m[k] + 2.0 * angleOverlap);
206  } else {
207  Psi_m[0] = calcPsi(Psi_m[0], angleOverlap, meshSpacing * sliceNumber);
208  if(Psi_m[0] > 0 && Psi_m[0] < totalBendAngle_m)
209  Ez_m[sliceNumber] += 0.5 * dlineDensitydz_m[0] / (Psi_m[0] + 2.0 * angleOverlap);
210  }
211 
212  // Do rest of integral.
213  for(unsigned int l = sliceNumber - k + 1; l < sliceNumber; ++ l) {
214  Psi_m[l] = calcPsi(Psi_m[l], angleOverlap, meshSpacing * (sliceNumber - l));
215  if(Psi_m[l] > 0 && Psi_m[l] < totalBendAngle_m)
216  Ez_m[sliceNumber] += dlineDensitydz_m[l] / (Psi_m[l] + 2.0 * angleOverlap);
217  }
218 
219  // We don't go right to the end as there is a singularity in the numerical integral that we don't quite know
220  // how to deal with properly yet. This introduces a very slight error in the calculation (fractions of a percent).
221  Psi_m[sliceNumber] = calcPsi(Psi_m[sliceNumber], angleOverlap, meshSpacing / 4.0);
222  if(Psi_m[sliceNumber] > 0 && Psi_m[sliceNumber] < totalBendAngle_m)
223  Ez_m[sliceNumber] += 0.5 * dlineDensitydz_m[sliceNumber] / (Psi_m[sliceNumber] + 2.0 * angleOverlap);
224 
225  double prefactor = -4 / bendRadius_m;
226  Ez_m[sliceNumber] *= prefactor;
227 }
228 
229 double CSRIGFWakeFunction::calcPsi(const double &psiInitial, const double &x, const double &Ds) const {
237  const int Nmax = 100;
238  const double eps = 1e-10;
239  double residual = 0.0;
240  double psi = pow(24. * Ds / bendRadius_m, 1. / 3.);
241  if(psiInitial != 0.0) psi = psiInitial;
242 
243  for(int i = 0; i < Nmax; ++i) {
244  residual = bendRadius_m * psi * psi * psi * (psi + 4. * x) - 24. * Ds * psi - 24. * Ds * x;
245  if(std::abs(residual) < eps)
246  return psi;
247  psi -= residual / (4. * bendRadius_m * psi * psi * psi + 12. * x * bendRadius_m * psi * psi - 24. * Ds);
248  }
249  RootFinderForCSR rootFinder(bendRadius_m, 4 * x * bendRadius_m, -24 * Ds, -24 * Ds * x);
250  if (rootFinder.hasPositiveRealRoots()) {
251  return rootFinder.searchRoot(eps);
252  }
253 
254  ERRORMSG("In CSRWakeFunction::calcPsi(): exceed maximum number of iterations!" << endl);
255  return psi;
256 }
257 const std::string CSRIGFWakeFunction::getType() const {
258  return "CSRIGFWakeFunction";
259 }
void initialize(const ElementBase *ref)
std::vector< double > Grn_m
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
std::vector< Filter * > filters_m
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
std::vector< double > Chi_m
LineDensity dlineDensitydz_m
#define ERRORMSG(msg)
Definition: IpplInfo.h:399
Inform * gmsg
Definition: Main.cpp:21
double getM() const
void calculateContributionInside(size_t sliceNumber, double angleOfSlice, double meshSpacing)
double get_meanKineticEnergy() const
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
Tps< T > log(const Tps< T > &x)
Natural logarithm.
Definition: TpsMath.h:182
virtual ElementType getType() const =0
Get element type std::string.
double getEffectiveLength() const
Definition: Bend2D.h:320
double getBendAngle() const
Definition: BendBase.h:86
#define PAssert_LT(a, b)
Definition: PAssert.h:121
void calculateContributionAfter(size_t sliceNumber, double angleOfSlice, double meshSpacing)
virtual const std::string getType() const
double calcPsi(const double &psiInitial, const double &x, const double &Ds) const
constexpr double pi
The value of .
Definition: Physics.h:31
void apply(PartBunchBase< double, 3 > *bunch)
CSRIGFWakeFunction(const std::string &name, ElementBase *element, std::vector< Filter * > filters, const unsigned int &N)
Definition: Bend2D.h:51
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
size_t getLocalNum() const
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
std::shared_ptr< Filter > defaultFilter_m
double searchRoot(const double &tol)
void calculateLineDensity(PartBunchBase< double, 3 > *bunch, std::pair< double, double > &meshInfo)
const std::string name
std::vector< double > Ez_m
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 calculateGreenFunction(PartBunchBase< double, 3 > *bunch, double meshSpacing)
void get_bounds(Vector_t &rmin, Vector_t &rmax)
Definition: Inform.h:41
virtual void calc_derivative(std::vector< double > &histogram, const double &h)=0
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
std::vector< double > Psi_m