OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
Micado.cpp
Go to the documentation of this file.
1 // ------------------------------------------------------------------------
2 // $RCSfile: Micado.cpp,v $
3 // ------------------------------------------------------------------------
4 // $Revision: 1.2 $
5 // ------------------------------------------------------------------------
6 // Copyright: see Copyright.readme
7 // ------------------------------------------------------------------------
8 //
9 // Class: Micado
10 // The abstract class Micado implements the interface for a table buffer
11 // holding lattice function.
12 //
13 // ------------------------------------------------------------------------
14 //
15 // $Date: 2001/08/13 15:25:22 $
16 // $Author: jowett $
17 //
18 // ------------------------------------------------------------------------
19 
20 #include "Tables/Micado.h"
24 #include "Algebra/Matrix.h"
25 #include "Algebra/Vector.h"
26 #include "Algorithms/ThickMapper.h"
28 #include "Algorithms/ThinMapper.h"
29 #include "Attributes/Attributes.h"
30 #include "Structure/Beam.h"
31 #include "Tables/Flatten.h"
33 #include "Utilities/Options.h"
34 #include "Utilities/Round.h"
35 #include <iomanip>
36 #include <iostream>
37 #include <string>
38 #include <vector>
39 
40 
41 // Class Micado
42 // ------------------------------------------------------------------------
43 
45  CorrectionBase(SIZE, "MICADO",
46  "The \"MICADO\" command makes a correction "
47  "using the \"MICADO\" algorithm.") {
49  ("METHOD", "The method used for orbit tracking", "LINEAR");
51  ("TOL", "The tolerance for the r.m.s closed orbit.");
53  ("ITERATIONS", "The number of iterations");
55  ("CORRECTORS", "The number of correctors to be used");
57  ("PLANE", "The plane(s) for which a Correction is desired", "BOTH");
59  ("LISTC1", "List the correctors before correction");
61  ("LISTC", "List the correctors during correction");
63  ("LISTC2", "List the correctors after correction");
65  ("LISTM1", "List the monitors before correction");
67  ("LISTM2", "List the monitors after correction");
68 
70 }
71 
72 
73 Micado::Micado(const std::string &name, Micado *parent):
74  CorrectionBase(name, parent)
75 {}
76 
77 
79 {}
80 
81 
82 Micado *Micado::clone(const std::string &name) {
83  return new Micado(name, this);
84 }
85 
86 
88  // Find Table definition.
89  const std::string &lineName = Attributes::getString(itsAttr[LINE]);
90  BeamSequence *use = BeamSequence::find(lineName);
91 
92  // Find Beam data.
93  const std::string &beamName = Attributes::getString(itsAttr[BEAM]);
94  Beam *beam = Beam::find(beamName);
95  reference = beam->getReference();
96 
97  // Get the data for correction.
99  int iterations = int(Round(Attributes::getReal(itsAttr[ITERATIONS])));
100  bool listm1 = Attributes::getBool(itsAttr[LISTM1]);
101  bool listm2 = Attributes::getBool(itsAttr[LISTM2]);
102  bool listc1 = Attributes::getBool(itsAttr[LISTC1]);
103  bool listc2 = Attributes::getBool(itsAttr[LISTC2]);
104 
105  // Make sure all is up-to-date.
107 
108  // Create flat line for correction.
109  Flatten<Row> flattener(*use->fetchLine(), itsLine, range);
110  flattener.execute();
111 
112  if(itsLine.empty() && Options::warn) {
113  std::cerr << "\n### Warning ### \"MICADO\" table \""
114  << lineName << "\" contains no elements.\n" << std::endl;
115  }
116 
117  // Decode the plane name.
118  const std::string &planeName = Attributes::getString(itsAttr[PLANE]);
119  bool planes[2] = { false, false };
120  if(planeName == "BOTH") {
121  planes[0] = planes[1] = true;
122  } else if(planeName == "X") {
123  planes[0] = true;
124  } else if(planeName == "Y") {
125  planes[1] = true;
126  } else {
127  throw OpalException("Micado::execute()",
128  "Plane name \"" + planeName + "\" is unknown.");
129  }
130 
131  // Decode the method name.
132  const std::string &methodName = Attributes::getString(itsAttr[METHOD]);
133  // Create the mapper to be used.
135  if(methodName == "THICK") {
136  itsMapper = new ThickMapper(itsLine, reference, false, false);
137  } else if(methodName == "THIN") {
138  itsMapper = new ThinMapper(itsLine, reference, false, false);
139  } else if(methodName == "LINEAR") {
140  itsMapper = new LinearMapper(itsLine, reference, false, false);
141  } else {
142  throw OpalException("Micado::execute()",
143  "Method name \"" + methodName + "\" is unknown.");
144  }
145 
146  // Set up the tables of correctors and monitors.
147  setupTables();
148 
149  // Perform correction.
150  for(int iteration = 1; iteration <= iterations; ++iteration) {
151  std::cout << "\n\"MICADO\" iteration " << iteration << ":\n";
152 
153  for(int plane = 0; plane < 2; ++plane) {
154  if(planes[plane]) {
155  // Store the current closed orbit.
156  findClosedOrbit();
157  listCorrectors(listc1, plane);
158  listMonitors(listm1, plane);
159 
160  // The A matrix.
161  // Each row corresponds to one monitor reading,
162  // Each column corresponds to one corrector setting.
163  int numberMonitors = monitorTable[plane].size();
164  int numberCorrectors = correctorTable[plane].size();
165  Matrix<double> A(numberMonitors, numberCorrectors);
166  setupInfluence(plane, A);
167 
168  // The monitor readings.
169  Vector<double> B(numberMonitors);
170  setupReadings(plane, B);
171 
172  // Solve the system of equations.
173  solve(plane, A, B);
174  }
175  }
176  }
177 
178  if(listc2 || listm2) {
179  std::cout << "\"MICADO\" finished:\n";
180  for(int plane = 0; plane < 2; ++plane) {
181  listCorrectors(listc2, plane);
182  listMonitors(listm2, plane);
183  }
184  }
185 }
186 
187 
189  static const int iteration_limit = 20;
190  static const double itsTolerance = 1.0e-8;
191 
192  for(int count = 0; count < iteration_limit; ++count) {
193  // Initial guess for closed orbit.
194  LinearMap<double, 6> identity;
195  LinearMap<double, 6> currentMap;
196 
197  // Compute the one-turn map around the closed orbit.
198  itsMapper->setMap(identity + orbitGuess);
199  for(TLine::iterator iter = itsLine.begin();
200  iter != itsLine.end(); ++iter) {
201  iter->accept(*itsMapper);
202  itsMapper->getMap(currentMap);
203  iter->orbit = currentMap.constantTerm();
204  }
205 
206  // Get system of equations for fixed point.
207  FMatrix<double, 6, 6> A = currentMap.linearTerms();
208  FVector<double, 6> Error = currentMap.constantTerm() - orbitGuess;
209  double error = 0.0;
210 
211  if(currentMap[5] == LinearFun<double, 6>::makeVariable(5)) {
212  // Finding static fixed point.
213  for(int i = 0; i < 4; i++) {
214  A(i, i) -= 1.0;
215  if(std::abs(Error(i)) > error) error = std::abs(Error(i));
216  }
217 
218  for(int i = 4; i < 6; i++) {
219  for(int j = 0; j < 6; j++) A(i, j) = A(j, i) = 0.0;
220  A(i, i) = 1.0;
221  Error(i) = 0.0;
222  }
223  } else {
224  // Finding dynamic fixed point.
225  for(int i = 0; i < 6; i++) {
226  A(i, i) -= 1.0;
227  if(std::abs(Error(i)) > error) error = std::abs(Error(i));
228  }
229  }
230 
231  // Correction for fixed point.
232  FLUMatrix<double, 6> lu(A);
233  lu.backSubstitute(Error);
234  orbitGuess -= Error;
235  if(error < itsTolerance) break;
236  }
237 }
238 
239 
241  // Prepare one turn matrix.
242  FMatrix<double, 6, 6> tmat = itsLine.back().matrix;
243 
244  // Invert the 4 by 4 block for transverse motion.
246  for(int i = 0; i < 4; ++i) {
247  for(int j = 0; j < 4; ++j) {
248  R(i, j) = tmat(i, j);
249  }
250  }
251  FMatrix<double, 4, 4> R1(R - 1.0);
252  R1 = - FLUMatrix<double, 4>(R1).inverse();
253  FMatrix<double, 6, 6> tmat1;
254  for(int i = 0; i < 4; ++i) {
255  for(int j = 0; j < 4; ++j) {
256  tmat1(i, j) = R1(i, j);
257  }
258  }
259  tmat1(4, 4) = tmat1(5, 5) = 1.0;
260 
261  const int q = 2 * plane;
262 
263  // Loop over the correctors.
264  LocalIter cBegin = correctorTable[plane].begin();
265  LocalIter cEnd = correctorTable[plane].end();
266  LocalIter mBegin = monitorTable[plane].begin();
267  LocalIter mEnd = monitorTable[plane].end();
268 
269  int corr = 0;
270  for(LocalIter cIter = cBegin; cIter != cEnd; ++cIter) {
271  // Transform kick to begin of line.
272  FVector<double, 6> initialOrbit;
273  FMatrix<double, 6, 6> cmat = (*cIter)->matrix;
274 
275  for(int j = 0; j < 6; j += 2) {
276  initialOrbit[j] = - cmat(q, j + 1);
277  initialOrbit[j+1] = cmat(q, j);
278  }
279 
280  // Loop over the monitors.
281  int moni = 0;
282  for(LocalIter mIter = mBegin; mIter != mEnd; ++mIter) {
283  FVector<double, 6> orbit;
284 
285  if((*mIter)->arc >= (*cIter)->arc) {
286  orbit = (*mIter)->matrix * (tmat1 * initialOrbit);
287  } else {
288  orbit = (*mIter)->matrix * (tmat1 * (tmat * initialOrbit));
289  }
290 
291  A(moni, corr) = orbit[q];
292  ++moni;
293  }
294 
295  ++corr;
296  }
297 }
298 
299 
301  const int q = 2 * plane;
302  int moni = 0;
303 
304  for(LocalIter mIter = monitorTable[plane].begin();
305  mIter != monitorTable[plane].end(); ++mIter) {
306  FVector<double, 6> orbit = (*mIter)->orbit;
307  B(moni) = orbit[q];
308  ++moni;
309  }
310 }
311 
312 
313 void Micado::solve(int plane, Matrix<double> &A, Vector<double> &B) {
314  // Set r.m.s. to a huge value in case of failure.
315  bool list = Attributes::getBool(itsAttr[LISTC]);
316  int m = A.nrows();
317  int n = A.ncols();
318  Vector<double> x(n);
319  Vector<double> r(m);
320  Vector<double> sqr(n);
321  Vector<double> dot(n);
322  std::vector<Row *>
323  index(correctorTable[plane].begin(), correctorTable[plane].end());
324 
325  // Find scalar products sqr[k] = A[k].A[k] and dot[k] = A[k].b.
326  double sum = 0.0;
327  for(int k = 0; k < n; ++k) {
328  double hh = 0.0;
329  double gg = 0.0;
330  for(int i = 0; i < m; ++i) {
331  hh += A(i, k) * A(i, k);
332  gg += A(i, k) * B[i];
333  }
334  sum += sum;
335  sqr[k] = hh;
336  dot[k] = gg;
337  }
338  double sqrmin = 1.e-8 * sum / double(n);
339 
340  // Begin of iteration loop.
341  double tol = Attributes::getReal(itsAttr[TOL]);
342  int correctors = int(Round(Attributes::getReal(itsAttr[CORRECTORS])));
343  if(correctors > n || correctors == 0) correctors = n;
344  int corr = 0;
345  while(true) {
346  int k = corr;
347 
348  // Search the columns not yet used for largest scaled change vector.
349  double maxChange = 0.0;
350  int changeIndex = -1;
351  for(int j = k; j < n; ++j) {
352  if(sqr[j] > sqrmin) {
353  double change = dot[j] * dot[j] / sqr[j];
354  if(change > maxChange) {
355  changeIndex = j;
356  maxChange = change;
357  }
358  }
359  }
360 
361  // Stop iterations, if no suitable column found.
362  if(changeIndex < 0) break;
363 
364  // Move the column just found to next position.
365  if(changeIndex > k) {
366  std::swap(sqr[k], sqr[changeIndex]);
367  std::swap(dot[k], dot[changeIndex]);
368  std::swap(index[k], index[changeIndex]);
369  A.swapColumns(k, changeIndex);
370  }
371 
372  // Find beta, sigma, and vector u[k].
373  double hh = 0.0;
374  for(int i = k; i < m; ++i) hh += A(i, k) * A(i, k);
375  double sigma = (A(k, k) > 0.0) ? sqrt(hh) : (- sqrt(hh));
376  sqr[k] = - sigma;
377  A(k, k) = A(k, k) + sigma;
378  double beta = 1.0 / (A(k, k) * sigma);
379 
380  // Transform remaining columns of A.
381  for(int j = k + 1; j < n; ++j) {
382  double hh = 0.0;
383  for(int i = k; i < m; ++i) hh += A(i, k) * A(i, j);
384  hh *= beta;
385  for(int i = k; i < m; ++i) A(i, j) -= A(i, k) * hh;
386  }
387 
388  // Transform vector b.
389  hh = 0.0;
390  for(int i = k; i < m; ++i) hh += A(i, k) * B[i];
391  hh *= beta;
392  for(int i = k; i < m; ++i) B[i] -= A(i, k) * hh;
393 
394  // Update scalar products sqr[j]=A[j]*A[j] and dot[j]=A[j]*b.
395  for(int j = k + 1; j < n; ++j) {
396  sqr[j] -= A(k, j) * A(k, j);
397  dot[j] -= A(k, j) * B[k];
398  }
399 
400  // Recalculate solution vector x.
401  x[k] = B[k] / sqr[k];
402  for(int i = k - 1; i >= 0; --i) {
403  x[i] = B[i];
404  for(int j = i + 1; j < k; ++j) x[i] -= A(i, j) * x[j];
405  x[i] /= sqr[i];
406  }
407 
408  // Find original residual vector by backward transformation.
409  for(int i = 0; i < m; ++i) r[i] = B[i];
410  for(int j = k; j >= 0; --j) {
411  r[j] = 0.0;
412  double hh = 0.0;
413  for(int i = j; i < m; ++i) hh += A(i, j) * r[i];
414  hh /= sqr[j] * A(j, j);
415  for(int i = j; i < m; ++i) {
416  r[i] += A(i, j) * hh;
417  }
418  }
419 
420  // Check for convergence.
421  hh = r(0) * r(0);
422  for(int i = 1; i < m; ++i) hh += r[i] * r[i];
423  hh = sqrt(hh / double(std::max(m, 1)));
424  ++corr;
425 
426  // Give listing of correctors for this iteration.
427  if(list) {
428  std::cout << "\nCorrector increment r.m.s.";
429  for(int k = 0; k < corr; ++k) {
430  const std::string &name = index[k]->getElement()->getName();
431  std::cout << '\n' << name << std::string(20 - name.length(), ' ')
432  << std::setw(12) << (- x[k]);
433  }
434  std::cout << std::setw(20) << hh << std::endl;
435  }
436 
437  // Check for convergence.
438  if(hh < tol) break;
439  if(corr > correctors) break;
440  }
441 
442  // End of iteration loop. Assign corrector strengths.
443  for(int k = 0; k < corr; ++k) {
444  addKick(plane, *index[k], - x[k]);
445  }
446 }
void swapColumns(int c1, int c2)
Exchange columns.
Definition: Array2D.h:459
double Round(double value)
Round the double argument.
Definition: Round.cpp:23
Abstract base class for all orbit correction commands.
void solve(int plane, Matrix< double > &A, Vector< double > &B)
Definition: Micado.cpp:313
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
OwnPtr< AbstractMapper > itsMapper
Definition: Micado.h:91
RangeRep getRange(const Attribute &attr)
Get range value.
Definition: Attributes.cpp:177
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
virtual ~Micado()
Definition: Micado.cpp:78
void setupInfluence(int mode, Matrix< double > &)
Definition: Micado.cpp:240
int ncols() const
Get number of columns.
Definition: Array2D.h:307
Flatten a beamline.
Definition: Flatten.h:42
void update()
Update all objects.
Definition: OpalData.cpp:723
std::vector< Attribute > itsAttr
The object attributes (see Attribute.hh).
Definition: Object.h:214
Build a map using a linear map for each element.
Definition: LinearMapper.h:68
bool warn
Warn flag.
Definition: Options.cpp:10
LocalList monitorTable[2]
T::PETE_Expr_t::PETE_Return_t sum(const PETE_Expr< T > &expr)
Definition: PETE.h:1213
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
Construct thin lens map.
Definition: ThinMapper.h:43
bool getBool(const Attribute &attr)
Return logical value.
Definition: Attributes.cpp:66
void listCorrectors(bool list, int plane)
List correctors before or after correction.
static OpalData * getInstance()
Definition: OpalData.cpp:209
static BeamSequence * find(const std::string &name)
Find a BeamSequence by name.
FVector< T, N > constantTerm(const FVector< T, N > &P) const
Evaluate map at point [b]P[/b].
Definition: LinearMap.hpp:220
A templated representation of a LU-decomposition.
Definition: FLUMatrix.h:42
void listMonitors(bool list, int plane)
List monitors before or after correction.
TLine itsLine
The flat beam line on which the correction is done.
virtual Micado * clone(const std::string &name)
Make clone.
Definition: Micado.cpp:82
static Beam * find(const std::string &name)
Find named BEAM.
Definition: Beam.cpp:150
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
Definition: Object.cpp:194
virtual Beamline * fetchLine() const =0
Return the embedded CLASSIC beam line.
LocalList::iterator LocalIter
Micado()
Exemplar constructor.
Definition: Micado.cpp:44
LocalList correctorTable[2]
void backSubstitute(FVector< T, N > &B) const
Back substitution.
Definition: FLUMatrix.h:222
virtual void setMap(const LinearMap< double, 6 > &)=0
Reset the linear part of the accumulated map for restart.
virtual void execute()
Apply the algorithm to the top-level beamline.
Definition: Flatten.h:92
PartData reference
The particle reference data.
Representation of a range within a beam line or sequence.
Definition: RangeRep.h:34
FVector< double, 6 > orbitGuess
The closed orbit guess.
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
Class Micado.
Definition: Micado.h:33
The base class for all OPAL beam lines and sequences.
Definition: BeamSequence.h:32
const PartData & getReference() const
Return the embedded CLASSIC PartData.
Definition: Beam.cpp:183
The BEAM definition.
Definition: Beam.h:35
Attribute makeBool(const std::string &name, const std::string &help)
Make logical attribute.
Definition: Attributes.cpp:56
static void setGlobalTruncOrder(int order)
Set the global truncation order.
Definition: FTps.hpp:419
const std::string name
FMatrix< T, N, N > linearTerms() const
Extract linear terms at origin.
Definition: LinearMap.hpp:243
void findClosedOrbit()
Definition: Micado.cpp:188
std::string::iterator iterator
Definition: MSLang.h:16
Linear function in N variables of type T.
Definition: LinearFun.h:39
double getReal(const Attribute &attr)
Return real value.
Definition: Attributes.cpp:217
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
Definition: Attributes.cpp:296
void setupReadings(int mode, Vector< double > &B)
Definition: Micado.cpp:300
int nrows() const
Get number of rows.
Definition: Array2D.h:301
void setupTables()
Set up the corrector and monitor tables.
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
Definition: Attributes.cpp:205
Build a map using a finite-length lens for each element.
Definition: ThickMapper.h:84
void addKick(int plane, Row &, double kick)
Add to kicker strength.
virtual void execute()
Check validity of the table definition.
Definition: Micado.cpp:87
virtual void getMap(LinearMap< double, 6 > &) const =0
Return the linear part of the accumulated map.
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
std::string getString(const Attribute &attr)
Get string value.
Definition: Attributes.cpp:307