source: TRACY3/trunk/tracy/tracy/src/nsls-ii_lib.cc @ 32

Last change on this file since 32 was 32, checked in by zhangj, 10 years ago

active the transport of the twiss functions and orbits of the transfer line.

  • Property svn:executable set to *
File size: 150.0 KB
Line 
1/* NSLS-II specific library
2
3   J. Bengtsson  NSLS-II, BNL  2004 -       
4
5   T. Shaftan, I. Pinayev, Y. Luo, C. Montag, B. Nash
6
7*/
8/* Current revision $Revision: 1.18 $
9 On branch $Name:  $
10 Latest change by $Author: zhang $
11*/
12
13// global params
14
15bool    DA_bare       = false,  // dynamic aperture
16        freq_map      = false, // include frequency map
17        tune_shift    = false; // to calculate tune shift with amplitude and energy
18int     n_aper        =  15, // no of dynamical aperture points
19        n_track       = 512, // no of turns for tracking
20        n_orbit       = 3,  //number of integration for orbit correction
21        n_scale       = 1; //number to scale the random orbit error
22
23bool    bba           = false;   // beam based alignment
24int     n_lin         =  3,
25        SQ_per_scell  =  2,
26        BPM_per_scell = 12,
27        HCM_per_scell = 12,
28        VCM_per_scell = 12;
29double  kick          = 0.01e-3; // 0.01 mrad kick for trims
30int     n_stat        = 1;       // number of statistics;when set the random error;
31
32double  VDweight      = 1e3,     // weight for vertical dispersion
33        HVweight      = 1e0,     // weight for coupling Htrim vertical BPM
34        VHweight      = 1e0;     // weight for coupling Vtrim horizontal BPM
35
36
37double  delta_DA_  = 5.0e-2; // Parameters for dynamic aperture
38
39// Parameters for frequency map
40// Note NTURN is set to 10000 (2*NTURN for diffusion)) in "naffutils.h".
41int     n_x = 50, n_y = 30, n_dp = 25, n_tr = 2064;
42double  x_max_FMA = 20e-3, y_max_FMA = 6e-3, delta_FMA = 3e-2;
43//double  x_max_FMA = 20e-3, y_max_FMA = 3e-3, delta_FMA = 3e-2;
44
45const int  max_corr = 100;
46const int  max_bpm  = 200;
47
48int     h_corr[max_corr], v_corr[max_corr], bpm_loc[max_bpm]; //non-global varible
49
50int     Fnum_Cart, n_iter_Cart;
51
52double  u_Touschek;  // argument for Touschek D(ksi)
53double  chi_m;       // argument for IBS D(ksi)
54
55char    in_dir[max_str]          = "";
56
57// Computation result files
58const char  beam_envelope_file[] = "beam_envelope.out";
59
60// Lattice error and correction files
61const char  CodCorLatFileName[]  = "codcorlat.out";
62
63const char  SkewMatFileName[]    = "skewmat.out";
64const char  eta_y_FileName[]     = "eta_y.out";
65const char  deta_y_FileName[]    = "deta_y.out";
66 
67
68const int  max_elem = Cell_nLocMax;
69
70
71
72char     ae_file[max_str], fe_file[max_str], ap_file[max_str];
73int      N_BPM, N_HCOR, N_VCOR, N_SKEW, N_COUPLE;
74
75/* ID correction**********/
76// maximum number of quadrupole families used for ID correction
77const int  N_Fam_max = 15;
78// ID correction params
79int N_calls = 1, N_steps = 1, N_Fam, Q_Fam[N_Fam_max]; 
80// Weights for ID correction
81double  scl_nux = 1e2, scl_nuy = 1e2, scl_dbetax = 1e0, scl_dbetay = 1e0;
82double  scl_dnux = 0.1, scl_dnuy = 0.1, ID_step = 0.7;
83
84int      n_sext, sexts[max_elem];
85double   beta0_[max_elem][2], nu0s[max_elem][2], nu0_[2], b2[N_Fam_max];
86double   **SkewRespMat, *VertCouple, *SkewStrengthCorr, *eta_y;
87double   *b, *w, **V, **U;
88double   disp_wave_y;
89Vector2  beta_ref;
90
91char lat_FileName[max_str];
92
93// ID_corr global variables
94
95const int  n_b2_max    = 500;  // max no of quad corrector families
96const int  n_b3_max    = 1000; // max no of sextupoles
97const int  max_ID_Fams = 25;   // max no of ID families
98
99int           Nsext, Nquad, Nconstr, NconstrO, quad_prms[n_b2_max], id_loc;
100int           n_ID_Fams, ID_Fams[max_ID_Fams];
101double        Ss[n_b3_max], Sq[n_b2_max], sb[2][n_b3_max], sNu[2][n_b3_max];
102double        qb[2][n_b2_max], qb0[2][n_b2_max], sNu0[2][n_b3_max];
103double        qNu0[2][n_b2_max], qNu[2][n_b2_max], IDb[2], IDNu[2];
104double        Nu_X, Nu_Y, Nu_X0, Nu_Y0;
105double        **A1, *Xsext, *Xsext0, *b2Ls_, *w1, **U1, **V1;
106double        *Xoct, *b4s, **Aoct;
107Vector2       dnu0, nu_0;
108
109ss_vect<tps>  map;
110MNF_struct    MNF;
111 
112
113// conversion
114
115void lwr_case(char str[])
116{
117  int  k;
118
119  for (k = 0; k < (int)strlen(str); k++)
120    str[k] = tolower(str[k]);
121}
122
123
124void upr_case(char str[])
125{
126  int  k;
127
128  for (k = 0; k < (int)strlen(str); k++)
129    str[k] = toupper(str[k]);
130}
131
132
133// only supported by Redhat
134#if 0
135// generate backtrace
136void prt_trace (void)
137{
138  const int  max_entries = 20;
139
140  void    *array[max_entries];
141  size_t  size;
142  char    **strings;
143  size_t  i;
144     
145  size = backtrace(array, max_entries);
146  strings = backtrace_symbols(array, size);
147     
148  printf("prt_trace: obtained %zd stack frames\n", size);
149     
150  for (i = 0; i < size; i++)
151    printf ("%s\n", strings[i]);
152     
153  free (strings);
154}
155#endif
156
157
158// file I/O
159
160// C++
161
162void file_rd(ifstream &inf, const char file_name[])
163{
164
165  inf.open(file_name, ios::in);
166  if (!inf.is_open()) {
167    printf("File not found: %s\n", file_name);
168    exit_(-1);
169  }
170}
171
172
173void file_wr(ofstream &outf, const char file_name[])
174{
175
176  outf.open(file_name, ios::out);
177  if (!outf.is_open()) {
178    printf("Could not create file: %s\n", file_name);
179    exit_(-1);
180  }
181}
182
183
184// C
185/***********************************************
186FILE* file_read(const char file_name[])
187
188   Purpose:
189      Open a file, and return the file ID
190************************************************/
191FILE* file_read(const char file_name[])
192{
193  FILE      *fp;
194 
195  fp = fopen(file_name, "r");
196  if (fp == NULL) {
197    printf("File not found: %s\n", file_name);
198    exit_(-1);
199  } else
200    return(fp);
201    // avoid compiler warning
202    return NULL;
203}
204
205
206FILE* file_write(const char file_name[])
207{
208  FILE      *fp;
209 
210  fp = fopen(file_name, "w");
211  if (fp == NULL) {
212    printf("Could not create file: %s\n", file_name);
213    exit_(-1);
214    // avoid compiler warning
215    return NULL;
216  } else
217    return(fp);
218}
219
220/* Check for closed orbit if not exit the program*/
221void chk_cod(const bool cod, const char *proc_name)
222{
223
224  if (!cod) {
225    printf("%s: closed orbit not found\n", proc_name);
226    exit_(1);
227  }
228}
229
230
231void no_sxt(void)
232{
233  int       k;
234
235  cout << endl;
236  cout << "zeroing sextupoles" << endl;
237  for (k = 0; k <= globval.Cell_nLoc; k++)
238    if ((Cell[k].Elem.Pkind == Mpole) && (Cell[k].Elem.M->Porder >= Sext))
239      SetKpar(Cell[k].Fnum, Cell[k].Knum, Sext, 0.0);
240}
241
242
243void get_map(void)
244{
245  long int  lastpos;
246
247
248  getcod(0.0, lastpos);
249
250  map.identity(); map += globval.CODvect;
251  Cell_Pass(0, globval.Cell_nLoc, map, lastpos);
252  map -= globval.CODvect;
253}
254
255
256#if ORDER > 1
257
258tps get_h(void)
259{
260  ss_vect<tps>  map1, R;
261
262  // Parallel transport nonlinear kick to start of lattice,
263  // assumes left to right evaluation.
264
265  if (true)
266    // Dragt-Finn factorization
267    return LieFact_DF(Inv(MNF.A0*MNF.A1)*map*MNF.A0*MNF.A1, R)*R;
268  else {
269    // single Lie exponent
270    danot_(1); map1 = map; danot_(no_tps);
271    return LieFact(Inv(MNF.A0*MNF.A1)*map*Inv(map1)*MNF.A0*MNF.A1);
272  }
273}
274
275#endif
276
277void get_m2(const ss_vect<tps> &ps, tps m2[])
278{
279  int  i, j, k;
280
281  k = 0;
282  for (i = 0; i < 2*nd_tps; i++)
283    for (j = i; j < 2*nd_tps; j++) {
284      k++; m2[k-1] = ps[i]*ps[j];
285    }
286}
287
288
289ss_vect<tps> get_S(const int n_DOF)
290{
291  int           j;
292  ss_vect<tps>  S;
293
294  S.zero();
295  for (j = 0; j < n_DOF; j++) {
296    S[2*j] = tps(0.0, 2*j+2); S[2*j+1] = -tps(0.0, 2*j+1);
297  }
298
299  return S;
300}
301
302
303ss_vect<tps> tp_S(const int n_DOF, const ss_vect<tps> &A)
304{
305  int           j, jj[ss_dim];
306  ss_vect<tps>  S;
307
308  for (j = 1; j <= ss_dim; j++)
309    jj[j-1] = (j <= 2*n_DOF)? 1 : 0;
310
311  S = get_S(n_DOF);
312
313  return -S*PInv(A, jj)*S;
314}
315
316
317void get_dnu(const ss_vect<tps> &A, double dnu[])
318{
319  int  k;
320
321  for (k = 0; k <= 1; k++) {
322    dnu[k] = atan2(A[2*k][2*k+1], A[2*k][2*k])/(2.0*M_PI);
323    if (dnu[k] < 0.0) dnu[k] += 1.0;
324  }
325}
326
327
328ss_vect<tps> get_A_CS(const ss_vect<tps> &A, double dnu[])
329{
330  int           k;
331  double        c, s;
332  ss_vect<tps>  Id, R;
333
334  Id.identity(); R.identity(); get_dnu(A, dnu);
335  for (k = 0; k <= 1; k++) {
336
337    c = cos(2.0*M_PI*dnu[k]); s = sin(2.0*M_PI*dnu[k]);
338    R[2*k] = c*Id[2*k] - s*Id[2*k+1]; R[2*k+1] = s*Id[2*k] + c*Id[2*k+1];
339  }
340
341  return A*R;
342}
343
344
345void get_twoJ(const int n_DOF, const ss_vect<double> &ps,
346              const ss_vect<tps> &A, double twoJ[])
347{
348  int              j;
349  iVector          jj;
350  ss_vect<double>  z;
351
352  for (j = 0; j < nv_tps; j++)
353    jj[j] = (j < 2*n_DOF)? 1 : 0;
354
355  z = (PInv(A, jj)*ps).cst();
356
357  for (j = 0; j < n_DOF; j++)
358    twoJ[j] = sqr(z[2*j]) + sqr(z[2*j+1]);
359}
360
361
362double get_curly_H(const double alpha_x, const double beta_x,
363                   const double eta_x, const double etap_x)
364{
365  double  curly_H, gamma_x;
366
367  gamma_x = (1.0+pow(alpha_x, 2))/beta_x;
368
369  curly_H = gamma_x*sqr(eta_x) + 2.0*alpha_x*eta_x*etap_x + beta_x*sqr(etap_x);
370
371  return curly_H;
372}
373
374
375double get_eps_x(void)
376{
377  bool             cav, emit;
378  long int         lastpos;
379  double           eps_x;
380  ss_vect<tps>     A;
381
382  /* Note:
383
384        T
385       M  J M = J,
386
387        -1       T           |  0  I |        T   | beta   -alpha |
388       A   = -J A  J,    J = |       |,    A A  = |               |
389                             | -I  0 |            | -alpha  gamma |
390
391     Transform to Floquet Space:
392
393        -1           T
394       A   eta = -J A  J eta,
395
396               -1      T  -1                T    T
397       H~ = ( A   eta )  A   eta = ( J eta )  A A  ( J eta )
398
399  */
400
401  cav = globval.Cavity_on; emit = globval.emittance;
402
403  globval.Cavity_on = false; globval.emittance = false;
404
405  Ring_GetTwiss(false, 0.0);
406
407  putlinmat(6, globval.Ascr, A); A += globval.CODvect;
408
409  globval.emittance = true;
410
411  Cell_Pass(0, globval.Cell_nLoc, A, lastpos);
412
413  eps_x = 1470.0*pow(globval.Energy, 2)*I5/(I2-I4);
414
415  printf("\n");
416  printf("eps_x = %5.3f nm.rad\n", eps_x);
417  printf("J_x   = %5.3f, J_z = %5.3f\n", 1.0-I4/I2, 2.0+I4/I2);
418
419  globval.Cavity_on = cav; globval.emittance = emit;
420
421  return eps_x;
422}
423
424/****************************************************************************/
425/* void GetEmittance(const int Fnum, const bool prt)
426
427   Purpose:
428       get the emittance
429
430   Input:
431      Fnum  family index
432      prt   bool flag, true = print the calcuate information
433   Output:
434       none
435
436   Return:
437       emittance
438       
439   Global variables:
440       
441
442   specific functions:
443       
444
445   Comments:
446       
447
448****************************************************************************/
449void GetEmittance(const int Fnum, const bool prt)
450{
451  bool          emit, rad, cav, path;
452  int           i, j, h_RF;
453  long int      lastpos, loc;
454  double        C, theta, V_RF, phi0, alpha_z, beta_z, gamma_z;
455  double        sigma_s, sigma_delta;
456  Vector3       nu;
457  Matrix        Ascr;
458  ss_vect<tps>  Ascr_map;
459
460  // save state
461  rad = globval.radiation; emit = globval.emittance;
462  cav = globval.Cavity_on; path = globval.pathlength;
463
464  C = Cell[globval.Cell_nLoc].S; /* Circumference of the ring*/
465
466  // damped system
467  globval.radiation = true; globval.emittance  = true;
468  globval.Cavity_on = true; globval.pathlength = false;
469
470  Ring_GetTwiss(false, 0.0);
471
472  // radiation loss is computed in Cav_Pass
473
474  // Sum_k( alpha_k) = 2 * U_0 / E
475//  printf("\n");
476//  printf("%24.16e %24.16e\n",
477//       globval.dE,
478//       (globval.alpha_rad[X_]+globval.alpha_rad[Y_]
479//       +globval.alpha_rad[Z_])/2.0);
480
481  globval.U0 = 1e9*globval.dE*globval.Energy;
482  V_RF = Cell[Elem_GetPos(Fnum, 1)].Elem.C->Pvolt; //RF voltage
483  h_RF = Cell[Elem_GetPos(Fnum, 1)].Elem.C->Ph;  // RF cavity harmonic number
484  phi0 = fabs(asin(globval.U0/V_RF));
485  globval.delta_RF =
486    sqrt(-V_RF*cos(M_PI-phi0)*(2.0-(M_PI-2.0*(M_PI-phi0))
487    *tan(M_PI-phi0))/(abs(globval.Alphac)*M_PI*h_RF*1e9*globval.Energy));
488
489  // compute diffusion coeffs. for eigenvectors [sigma_xx, sigma_yy, sigma_zz]
490  putlinmat(6, globval.Ascr, Ascr_map); Ascr_map += globval.CODvect;
491
492  Cell_Pass(0, globval.Cell_nLoc, Ascr_map, lastpos);
493
494  for (i = 0; i < DOF; i++) {
495    // partition numbers
496    globval.J[i] = 2.0*(1.0+globval.CODvect[delta_])*globval.alpha_rad[i]
497                   /globval.dE;
498    // damping times
499    globval.tau[i] = -C/(c0*globval.alpha_rad[i]);
500    // diffusion coeff. and emittance
501    globval.eps[i] = -globval.D_rad[i]/(2.0*globval.alpha_rad[i]);
502    // fractional tunes
503    nu[i]  = atan2(globval.wi[i*2], globval.wr[i*2])/(2.0*M_PI);
504    if (nu[i] < 0.0) nu[i] = 1.0 + nu[i];
505  }
506
507  // Note, J_x + J_y + J_z not exactly 4 (1st order perturbations)
508//  printf("\n");
509//  printf("%24.16e\n", globval.J[X_]+globval.J[Y_]+globval.J[Z_]);
510 
511  // undamped system
512  globval.radiation = false; globval.emittance = false;
513
514  Ring_GetTwiss(false, 0.0);
515
516  /* compute the sigmas arround the lattice:
517
518       sigma = A diag[J_1, J_1, J_2, J_2, J_3, J_3] A^T
519
520  */
521  for (i = 0; i < 6; i++) {
522    Ascr_map[i] = tps(globval.CODvect[i]);
523    for (j = 0; j < 6; j++)
524      Ascr_map[i] += globval.Ascr[i][j]*sqrt(globval.eps[j/2])*tps(0.0, j+1);
525  }
526  for (loc = 0; loc <= globval.Cell_nLoc; loc++) {
527    Elem_Pass(loc, Ascr_map);
528    // sigma = A x A^tp
529    getlinmat(6, Ascr_map, Cell[loc].sigma); TpMat(6, Cell[loc].sigma);
530    getlinmat(6, Ascr_map, Ascr); MulLMat(6, Ascr, Cell[loc].sigma);
531  }
532
533  theta = atan2(2e0*Cell[0].sigma[x_][y_],
534          (Cell[0].sigma[x_][x_]-Cell[0].sigma[y_][y_]))/2e0;
535
536  // longitudinal alpha and beta
537  alpha_z =
538    -globval.Ascr[ct_][ct_]*globval.Ascr[delta_][ct_]
539    - globval.Ascr[ct_][delta_]*globval.Ascr[delta_][delta_];
540  beta_z = sqr(globval.Ascr[ct_][ct_]) + sqr(globval.Ascr[ct_][delta_]);
541  gamma_z = (1.0+sqr(alpha_z))/beta_z;
542
543  // bunch size
544  sigma_s = sqrt(beta_z*globval.eps[Z_]);
545  sigma_delta = sqrt(gamma_z*globval.eps[Z_]);
546
547  if (prt) {
548    printf("\n");
549    printf("Emittance:\n");
550    printf("\n");
551    printf("Energy loss per turn [keV]:     "
552           "U0          = %3.1f\n",
553           1e-3*globval.U0);
554    printf("Synchronous phase [deg]:        "
555           "phi0        = 180 - %4.2f\n",
556           phi0*180.0/M_PI);
557    printf("RF bucket height [%%]:           "
558           "delta_RF    = %4.2f\n", 1e2*globval.delta_RF);
559    printf("\n");
560    printf("Equilibrium emittance [m.rad]:  "
561           "eps_x       = %9.3e, eps_y  = %9.3e, eps_z  = %9.3e\n",
562            globval.eps[X_], globval.eps[Y_], globval.eps[Z_]);
563    printf("Bunch length [mm]:              "
564           "sigma_s     = %5.3f\n", 1e3*sigma_s);
565    printf("Momentum spread:                "
566           "sigma_delta = %9.3e\n", sigma_delta);
567    printf("Partition numbers:              "
568           "J_x         = %5.3f,     J_y    = %5.3f,     J_z    = %5.3f\n",
569            globval.J[X_], globval.J[Y_], globval.J[Z_]);
570    printf("Damping times [msec]:           "
571           "tau_x       = %3.1f,      tau_y  = %3.1f,      tau_z  = %3.1f\n",
572           1e3*globval.tau[X_], 1e3*globval.tau[Y_], 1e3*globval.tau[Z_]);
573    printf("\n");
574    printf("alphac:                         "
575           "alphac      = %8.4e\n", globval.Alphac); 
576    printf("\n");
577    printf("Fractional tunes:               "
578           "nu_x        = %7.5f, nu_y   = %7.5f, nu_z   = %7.5f\n",
579           nu[X_], nu[Y_], nu[Z_]);
580    printf("                                "
581           "1-nu_x      = %7.5f, 1-nu_y = %7.5f, 1-nu_z = %7.5f\n",
582           1e0-nu[X_], 1e0-nu[Y_], 1e0-nu[Z_]);
583    printf("\n");
584    printf("sigmas:                         "
585           "sigma_x     = %5.1f microns, sigma_px    = %5.1f urad\n",
586           1e6*sqrt(Cell[0].sigma[x_][x_]), 1e6*sqrt(Cell[0].sigma[px_][px_]));
587    printf("                                "
588           "sigma_y     = %5.1f microns, sigma_py    = %5.1f urad\n",
589           1e6*sqrt(Cell[0].sigma[y_][y_]), 1e6*sqrt(Cell[0].sigma[py_][py_]));
590    printf("                                "
591           "sigma_s     = %5.2f mm,      sigma_delta = %8.2e\n",
592           1e3*sqrt(Cell[0].sigma[ct_][ct_]),
593           sqrt(Cell[0].sigma[delta_][delta_]));
594
595    printf("\n");
596    printf("Beam ellipse twist [rad]:       tw = %5.3f\n", theta);
597    printf("                   [deg]:       tw = %5.3f\n", theta*180.0/M_PI);
598  }
599
600  // restore state
601  globval.radiation = rad; globval.emittance  = emit;
602  globval.Cavity_on = cav; globval.pathlength = path;
603}
604
605
606// output
607
608void prt_lat(const char *fname, const int Fnum, const bool all)
609{
610  long int      i = 0;
611  double        I2, I5, code = 0.0;
612  FILE          *outf;
613
614  outf = file_write(fname);
615  fprintf(outf, "#        name           s   code"
616                "  alphax  betax   nux   etax   etapx");
617  fprintf(outf, "  alphay  betay   nuy   etay   etapy    I5\n");
618  fprintf(outf, "#                      [m]"
619                "                 [m]           [m]");
620  fprintf(outf, "                   [m]           [m]\n");
621  fprintf(outf, "#\n");
622
623  I2 = 0.0; I5 = 0.0;
624  for (i = 0; i <= globval.Cell_nLoc; i++) {
625    if (all || (Cell[i].Fnum == Fnum)) {
626      switch (Cell[i].Elem.Pkind) {
627      case drift:
628        code = 0.0;
629        break;
630      case Mpole:
631        if (Cell[i].Elem.M->Pirho != 0.0)
632          code = 0.5;
633        else if (Cell[i].Elem.M->PBpar[Quad+HOMmax] != 0)
634          code = sgn(Cell[i].Elem.M->PBpar[Quad+HOMmax]);
635        else if (Cell[i].Elem.M->PBpar[Sext+HOMmax] != 0)
636          code = 1.5*sgn(Cell[i].Elem.M->PBpar[Sext+HOMmax]);
637        else if (Cell[i].Fnum == globval.bpm)
638          code = 2.0;
639        else
640          code = 0.0;
641        break;
642      default:
643        code = 0.0;
644        break;
645      }
646      fprintf(outf, "%4ld %15s %6.2f %4.1f"
647              " %7.3f %6.3f %6.3f %6.3f %6.3f"
648              " %7.3f %6.3f %6.3f %6.3f %6.3f  %8.2e\n",
649              i, Cell[i].Elem.PName, Cell[i].S, code,
650              Cell[i].Alpha[X_], Cell[i].Beta[X_], Cell[i].Nu[X_],
651              Cell[i].Eta[X_], Cell[i].Etap[X_],
652              Cell[i].Alpha[Y_], Cell[i].Beta[Y_], Cell[i].Nu[Y_],
653              Cell[i].Eta[Y_], Cell[i].Etap[Y_], I5);
654    }
655  }
656
657//  fprintf(outf, "\n");
658//  fprintf(outf, "# emittance: %5.3f nm.rad\n", get_eps_x());
659
660  fclose(outf);
661}
662
663
664void prt_chrom_lat(void)
665{
666  long int  i;
667  double    dbeta_ddelta[Cell_nLocMax][2], detax_ddelta[Cell_nLocMax];
668  double    ksi[Cell_nLocMax][2];
669  double    code = 0.0;
670  FILE      *outf;
671
672  printf("\n");
673  printf("prt_chrom_lat: calling Ring_GetTwiss with delta != 0\n");
674  Ring_GetTwiss(true, globval.dPcommon);
675  for (i = 0; i <= globval.Cell_nLoc; i++) {
676    dbeta_ddelta[i][X_] = Cell[i].Beta[X_];
677    dbeta_ddelta[i][Y_] = Cell[i].Beta[Y_];
678    detax_ddelta[i] = Cell[i].Eta[X_];
679  }
680  printf("prt_chrom_lat: calling Ring_GetTwiss with delta != 0\n");
681  Ring_GetTwiss(true, -globval.dPcommon);
682  ksi[0][X_] = 0.0; ksi[0][Y_] = 0.0;
683  for (i = 0; i <= globval.Cell_nLoc; i++) {
684    dbeta_ddelta[i][X_] -= Cell[i].Beta[X_];
685    dbeta_ddelta[i][Y_] -= Cell[i].Beta[Y_];
686    detax_ddelta[i] -= Cell[i].Eta[X_];
687    dbeta_ddelta[i][X_] /= 2.0*globval.dPcommon;
688    dbeta_ddelta[i][Y_] /= 2.0*globval.dPcommon;
689    detax_ddelta[i] /= 2.0*globval.dPcommon;
690    if (i != 0) {
691      ksi[i][X_] = ksi[i-1][X_]; ksi[i][Y_] = ksi[i-1][Y_];
692    }
693    if (Cell[i].Elem.Pkind == Mpole) {
694        ksi[i][X_] -= Cell[i].Elem.M->PBpar[Quad+HOMmax]
695                     *Cell[i].Elem.PL*Cell[i].Beta[X_]/(4.0*M_PI);
696        ksi[i][Y_] += Cell[i].Elem.M->PBpar[Quad+HOMmax]
697                     *Cell[i].Elem.PL*Cell[i].Beta[Y_]/(4.0*M_PI);
698    }
699  }
700
701  outf = file_write("chromlat.out");
702  fprintf(outf, "#     name              s    code"
703                "  bx*ex  sqrt(bx*by)  dbx/dd*ex  bx*dex/dd"
704                "  by*ex  dby/dd*ex by*dex/dd  ksix  ksiy"
705                "  dbx/dd  bx/dd dex/dd\n");
706  fprintf(outf, "#                      [m]          [m]"
707                "      [m]          [m]       [m]");
708  fprintf(outf, "       [m]      [m]       [m]\n");
709  fprintf(outf, "#\n");
710  for (i = 0; i <= globval.Cell_nLoc; i++) {
711    switch (Cell[i].Elem.Pkind) {
712    case drift:
713      code = 0.0;
714      break;
715    case Mpole:
716      if (Cell[i].Elem.M->Pirho != 0)
717        code = 0.5;
718      else if (Cell[i].Elem.M->PBpar[Quad+HOMmax] != 0)
719        code = sgn(Cell[i].Elem.M->PBpar[Quad+HOMmax]);
720      else if (Cell[i].Elem.M->PBpar[Sext+HOMmax] != 0)
721        code = 1.5*sgn(Cell[i].Elem.M->PBpar[Sext+HOMmax]);
722      else if (Cell[i].Fnum == globval.bpm)
723        code = 2.0;
724      else
725        code = 0.0;
726      break;
727    default:
728      code = 0.0;
729      break;
730    }
731    fprintf(outf, "%4ld %15s %6.2f %4.1f"
732                  "  %6.3f  %8.3f    %8.3f   %8.3f"
733                  "   %6.3f %8.3f   %8.3f  %5.2f  %5.2f"
734                  "  %6.3f  %6.3f  %6.3f\n",
735            i, Cell[i].Elem.PName, Cell[i].S, code,
736            Cell[i].Beta[X_]*Cell[i].Eta[X_],
737            sqrt(Cell[i].Beta[X_]*Cell[i].Beta[Y_]),
738            dbeta_ddelta[i][X_]*Cell[i].Eta[X_],
739            detax_ddelta[i]*Cell[i].Beta[X_],
740            Cell[i].Beta[Y_]*Cell[i].Eta[X_],
741            dbeta_ddelta[i][Y_]*Cell[i].Eta[X_],
742            detax_ddelta[i]*Cell[i].Beta[Y_],
743            ksi[i][X_], ksi[i][Y_],
744            dbeta_ddelta[i][X_], dbeta_ddelta[i][Y_], detax_ddelta[i]);
745  }
746  fclose(outf);
747}
748
749/****************************************************************************/
750/* void prt_cod(const char *file_name, const int Fnum, const bool all)
751
752   Purpose:
753       print the location, twiss parameters, displacement errors and close orbit
754       at the the location of Fnum or all lattice elements
755
756   Input:
757      file_name    file to save the data
758                    code in the file:
759                      0   drfit
760                      0.5  dipole
761                      -1    defocusing quadrupole
762                      1     focusing quadrupole
763                      1.5  sextupole
764                      2.0  bpm
765      Fnum        family index of the BPM.
766      all         true, print the cod at all elements
767                  false, print the cod at the BPM elements, the name of the BPM must be defined in the "*.prm" file.
768   Output:
769       none
770
771   Return:
772       none
773       
774   Global variables:
775       
776
777   specific functions:
778       
779
780   Comments:
781       
782
783****************************************************************************/
784void prt_cod(const char *file_name, const int Fnum, const bool all)
785{
786  long      i=0L;
787  double    code = 0.0;
788  FILE      *outf;
789  long      FORLIM=0L;
790  struct    tm *newtime;
791
792  outf = file_write(file_name);
793
794  /* Get time and date */
795  newtime = GetTime();
796
797  fprintf(outf,"# TRACY III -- %s -- %s \n",
798          file_name, asctime2(newtime));
799
800  fprintf(outf, "#       name             s  code  betax   nux   betay   nuy"
801          "   xcod   ycod    dSx    dSy   dipx   dipy\n");
802  fprintf(outf, "#                       [m]        [m]           [m]       "
803          "   [mm]   [mm]    [mm]   [mm] [mrad]  [mrad]\n");
804  fprintf(outf, "#\n");
805
806  FORLIM = globval.Cell_nLoc;
807  for (i = 0L; i <= FORLIM; i++) {
808    if (all || (Cell[i].Fnum == Fnum)) {
809      switch (Cell[i].Elem.Pkind) {
810      case drift:
811        code = 0.0;
812        break;
813      case Mpole:
814        if (Cell[i].Elem.M->Pirho != 0)
815          code = 0.5;
816        else if (Cell[i].Elem.M->PBpar[Quad+HOMmax] != 0)
817          code = sgn(Cell[i].Elem.M->PBpar[Quad+HOMmax]);
818        else if (Cell[i].Elem.M->PBpar[Sext+HOMmax] != 0)
819          code = 1.5*sgn(Cell[i].Elem.M->PBpar[Sext+HOMmax]);
820        else if (Cell[i].Fnum == globval.bpm)
821          code = 2.0;
822        else
823          code = 0.0;
824        break;
825      default:
826        code = 0.0;
827        break;
828      }
829      /* COD is in local coordinates */
830      fprintf(outf, "%4ld %.*s %6.2f %4.1f %6.4f %6.4f %6.4f %6.4f"
831              " %6.4f %6.4f %6.4f %6.4f %6.4f %6.4f\n",
832              i, SymbolLength, Cell[i].Elem.PName, Cell[i].S, code,
833              Cell[i].Beta[X_], Cell[i].Nu[X_],
834              Cell[i].Beta[Y_], Cell[i].Nu[Y_], 
835              1e3*Cell[i].BeamPos[x_], 1e3*Cell[i].BeamPos[y_],
836              1e3*Cell[i].dS[X_], 1e3*Cell[i].dS[Y_], //displacement error
837              -1e3*Elem_GetKval(Cell[i].Fnum, Cell[i].Knum, Dip),  //H kick angle, for correctors
838              1e3*Elem_GetKval(Cell[i].Fnum, Cell[i].Knum, -Dip)); //kick angle, for correctors
839    }
840  }
841  fclose(outf);
842}
843
844/****************************************************************
845 * void prt_beampos(const char *file_name)
846 *
847 *  print the orbits at all lattice elements.
848 *
849 * Comments:   
850 *     To use this command, the BPM name should be defined in the
851 *  "*.prm" file with the command
852 *                bpm_name   BPM_names
853 *
854 *
855 ****************************************************************/
856
857void prt_beampos(const char *file_name)
858{
859  int       i=0;
860  ofstream  outf;
861
862  file_wr(outf, file_name);
863
864  outf << "#   i     name              s[m]     x[mm]   px    y[mm]   py   delta ct" << endl;
865  outf << "#" << endl;
866
867 
868  for (i = 0; i <= globval.Cell_nLoc; i++){
869   if (Cell[i].Fnum == globval.bpm)
870        outf << scientific << setprecision(4)
871          << setw(5) << i << setw(20) << Cell[i].Elem.PName
872          << setw(5) << Cell[i].S
873          << setw(13) << Cell[i].BeamPos*1e3 << endl;
874  }     
875  outf.close();
876}
877
878
879/****************************************************************
880void CheckAlignTol(const char *OutputFile)
881
882  Purpose:
883    check aligment errors of individual magnets on giders
884    the dT and roll angle are all printed out
885****************************************************************/
886// misalignments
887void CheckAlignTol(const char *OutputFile)
888  // check aligment errors of individual magnets on giders
889  // the dT and roll angle are all printed out
890{
891  int i=0,j=0;
892  int  n_girders=0;
893  int  gs_Fnum=0, ge_Fnum=0;
894  int  gs_nKid=0, ge_nKid=0;
895  int  dip_Fnum=0,dip_nKid=0;
896  int  loc=0, loc_gs=0, loc_ge=0;
897  char * name;
898  double s=0.0;
899  double PdSsys[2], PdSrms[2], PdSrnd[2], dS[2], dT[2];
900  fstream fout;
901 
902  gs_Fnum = globval.gs;   gs_nKid = GetnKid(gs_Fnum);
903  ge_Fnum = globval.ge;   ge_nKid = GetnKid(ge_Fnum);
904  if (gs_nKid == ge_nKid)
905    n_girders= gs_nKid;
906  else {
907    cout << " The numbers of GS and GE not same. " << endl;
908    exit (1);
909  }
910
911  fout.open(OutputFile,ios::out);
912  if(!fout) {
913    cout << "error in opening the file  " << endl;
914    exit_(0);
915  }
916 
917  fout << "Girders, Quads, Sexts:  " << endl; 
918  for (i = 1; i <= n_girders; i++){
919    fout << i << ":" << endl;
920    loc_gs = Elem_GetPos(gs_Fnum, i); loc_ge = Elem_GetPos(ge_Fnum, i);
921   
922    loc = loc_gs;
923    PdSsys[X_] = Cell[loc].Elem.M->PdSsys[X_];
924    PdSsys[Y_] = Cell[loc].Elem.M->PdSsys[Y_];
925    PdSrms[X_] = Cell[loc].Elem.M->PdSrms[X_];
926    PdSrms[Y_] = Cell[loc].Elem.M->PdSrms[Y_];
927    PdSrnd[X_] = Cell[loc].Elem.M->PdSrnd[X_];
928    PdSrnd[Y_] = Cell[loc].Elem.M->PdSrnd[Y_];
929    dS[X_] = Cell[loc].dS[X_]; dS[Y_] = Cell[loc].dS[Y_];
930    dT[0] = Cell[loc].dT[0]; dT[1] = Cell[loc].dT[1];
931    s = Cell[loc].S; name = Cell[loc].Elem.PName;
932    fout << "  " << name << "  " << loc << "   " << s
933         << "  " <<  PdSsys[X_] << "  " <<  PdSsys[Y_]
934         << "   " << PdSrms[X_] << "  " <<  PdSrms[Y_]
935         << "   " << PdSrnd[X_] << "  " <<  PdSrnd[Y_]
936         << "   " << Cell[loc].Elem.M->PdTrms << "  "
937         << Cell[loc].Elem.M->PdTrnd << "   " << dS[X_]     << "  " <<  dS[Y_]
938         << "   " << atan2( dT[1], dT[0] )  << endl;
939   
940    for (j = loc_gs+1; j < loc_ge; j++) {
941      if ((Cell[j].Elem.Pkind == Mpole) &&
942          (Cell[j].Elem.M->n_design >= Quad || 
943           Cell[j].Elem.M->n_design >= Sext)) {
944        loc = j;
945        PdSsys[X_] = Cell[loc].Elem.M->PdSsys[X_];
946        PdSsys[Y_] = Cell[loc].Elem.M->PdSsys[Y_];
947        PdSrms[X_] = Cell[loc].Elem.M->PdSrms[X_];
948        PdSrms[Y_] = Cell[loc].Elem.M->PdSrms[Y_];
949        PdSrnd[X_] = Cell[loc].Elem.M->PdSrnd[X_];
950        PdSrnd[Y_] = Cell[loc].Elem.M->PdSrnd[Y_];
951        dS[X_] = Cell[loc].dS[X_]; dS[Y_] = Cell[loc].dS[Y_];
952        dT[0] = Cell[loc].dT[0];   dT[1] = Cell[loc].dT[1];
953        s = Cell[loc].S; name=Cell[loc].Elem.PName;
954        fout << "  " << name << "  " << loc << "   " << s
955             << "  " <<  PdSsys[X_] << "  " <<  PdSsys[Y_]
956             << "   " << PdSrms[X_] << "  " <<  PdSrms[Y_]
957             << "   " << PdSrnd[X_] << "  " <<  PdSrnd[Y_]
958             << "   " << Cell[loc].Elem.M->PdTrms << "  "
959             << Cell[loc].Elem.M->PdTrnd
960             << "   " << dS[X_] << "  " <<  dS[Y_]
961             << "   " << atan2( dT[1], dT[0] )  << endl;
962      }
963    }
964   
965    loc = loc_ge;
966    PdSsys[X_] = Cell[loc].Elem.M->PdSsys[X_];
967    PdSsys[Y_] = Cell[loc].Elem.M->PdSsys[Y_];
968    PdSrms[X_] = Cell[loc].Elem.M->PdSrms[X_];
969    PdSrms[Y_] = Cell[loc].Elem.M->PdSrms[Y_];
970    PdSrnd[X_] = Cell[loc].Elem.M->PdSrnd[X_];
971    PdSrnd[Y_] = Cell[loc].Elem.M->PdSrnd[Y_];
972    dS[X_] = Cell[loc].dS[X_]; dS[Y_] = Cell[loc].dS[Y_];
973    dT[0] = Cell[loc].dT[0]; dT[1] = Cell[loc].dT[1];
974    s=Cell[loc].S; name=Cell[loc].Elem.PName;
975    fout << "  " << name << "  " << loc << "   " << s
976         << "  " <<  PdSsys[X_] << "  " <<  PdSsys[Y_]
977         << "   " << PdSrms[X_] << "  " <<  PdSrms[Y_]
978         << "   " << PdSrnd[X_] << "  " <<  PdSrnd[Y_]
979         << "   " << Cell[loc].Elem.M->PdTrms
980         << "  " << Cell[loc].Elem.M->PdTrnd
981         << "   " << dS[X_]     << "  " <<  dS[Y_]
982         << "   " << atan2( dT[1], dT[0] )  << endl;
983
984  }
985
986  fout << "  " << endl; 
987  fout << "Dipoles:  " << endl;
988  dip_Fnum = ElemIndex("B1"); dip_nKid = GetnKid(dip_Fnum);
989  for (i = 1; i <= dip_nKid; i++){
990    loc = Elem_GetPos(dip_Fnum, i);
991    PdSsys[X_] = Cell[loc].Elem.M->PdSsys[X_];
992    PdSsys[Y_] = Cell[loc].Elem.M->PdSsys[Y_];
993    PdSrms[X_] = Cell[loc].Elem.M->PdSrms[X_];
994    PdSrms[Y_] = Cell[loc].Elem.M->PdSrms[Y_];
995    PdSrnd[X_] = Cell[loc].Elem.M->PdSrnd[X_];
996    PdSrnd[Y_] = Cell[loc].Elem.M->PdSrnd[Y_];
997    dS[X_] = Cell[loc].dS[X_]; dS[Y_] = Cell[loc].dS[Y_];
998    dT[0] = Cell[loc].dT[0]; dT[1] = Cell[loc].dT[1];
999    s = Cell[loc].S; name = Cell[loc].Elem.PName;
1000    fout << "  " << name << "  " << loc << "   " << s
1001         << "  " <<  PdSsys[X_] << "  " <<  PdSsys[Y_]
1002         << "   " << PdSrms[X_] << "  " <<  PdSrms[Y_]
1003         << "   " << PdSrnd[X_] << "  " <<  PdSrnd[Y_]
1004         << "   " << Cell[loc].Elem.M->PdTrms
1005         << "  " << Cell[loc].Elem.M->PdTrnd
1006         << "   " << dS[X_]     << "  " <<  dS[Y_]
1007         << "   " << atan2( dT[1], dT[0] )  << endl;
1008  }
1009 
1010  fout.close();
1011} 
1012
1013/*********************************************************************
1014void misalign_rms_elem(const int Fnum, const int Knum,
1015                       const double dx_rms, const double dy_rms,
1016                       const double dr_rms, const bool new_rnd)
1017                       
1018  Purpose:
1019     Set random misalignment to the element with Fnum and Knum
1020 
1021  Input:   
1022     Fnum          family number
1023     Knum          kid number
1024     dx_rms         rms value of the error in x
1025     dy_rms         rms value of the error in y
1026     dr_rms         rms value of the error in rotation around s
1027     new_rnd        flag to turn on/off using the new random seed
1028     
1029**********************************************************************/
1030void misalign_rms_elem(const int Fnum, const int Knum,
1031                       const double dx_rms, const double dy_rms,
1032                       const double dr_rms, const bool new_rnd)
1033{
1034  long int   loc;
1035  MpoleType  *mp;
1036
1037  const bool  normal = true;
1038
1039  loc = Elem_GetPos(Fnum, Knum); mp = Cell[loc].Elem.M;
1040
1041  mp->PdSrms[X_] = dx_rms; mp->PdSrms[Y_] = dy_rms; mp->PdTrms = dr_rms; 
1042  if (new_rnd) {
1043    if (normal) {
1044      mp->PdSrnd[X_] = normranf(); mp->PdSrnd[Y_] = normranf();
1045      mp->PdTrnd = normranf();
1046    } else {
1047      mp->PdSrnd[X_] = ranf(); mp->PdSrnd[Y_] = ranf();
1048      mp->PdTrnd = ranf();
1049    }
1050  }
1051
1052  Mpole_SetdS(Fnum, Knum); Mpole_SetdT(Fnum, Knum);
1053}
1054
1055
1056/*********************************************************************
1057void misalign_sys_elem(const int Fnum, const int Knum,
1058                       const double dx_sys, const double dy_sys,
1059                       const double dr_sys)
1060                       
1061  Purpose:
1062     Set systematic misalignment to the elements in "type"
1063 
1064  Input:   
1065     Fnum          family number
1066     Knum          kid number         
1067     dx_sys         sys value of the error in x
1068     dy_sys         sys value of the error in y
1069     dr_sys         sys value of the error in rotation around s
1070     
1071**********************************************************************/
1072void misalign_sys_elem(const int Fnum, const int Knum,
1073                       const double dx_sys, const double dy_sys,
1074                       const double dr_sys)
1075{
1076  long int   loc;
1077  MpoleType  *mp;
1078
1079  loc = Elem_GetPos(Fnum, Knum); mp = Cell[loc].Elem.M;
1080
1081  mp->PdSsys[X_] = dx_sys; mp->PdSsys[Y_] = dy_sys; mp->PdTsys = dr_sys; 
1082
1083  Mpole_SetdS(Fnum, Knum); Mpole_SetdT(Fnum, Knum);
1084}
1085
1086/*********************************************************************
1087void misalign_rms_fam(const int Fnum,
1088                      const double dx_rms, const double dy_rms,
1089                      const double dr_rms, const bool new_rnd)
1090                       
1091  Purpose:
1092     Set systematic misalignment to the elements on the girders
1093 
1094  Input:   
1095     Fnum           family number                     
1096     dx_rms         rms value of the error in x
1097     dy_rms         rms value of the error in y
1098     dr_rms         rms value of the error in rotation around s
1099     new_rnd        flag to generate random number
1100**********************************************************************/
1101void misalign_rms_fam(const int Fnum,
1102                      const double dx_rms, const double dy_rms,
1103                      const double dr_rms, const bool new_rnd)
1104{
1105  int  i;
1106
1107  for (i = 1; i <= GetnKid(Fnum); i++)
1108    misalign_rms_elem(Fnum, i, dx_rms, dy_rms, dr_rms, new_rnd);
1109}
1110
1111void misalign_sys_fam(const int Fnum,
1112                      const double dx_sys, const double dy_sys,
1113                      const double dr_sys)
1114{
1115  int  i;
1116
1117  for (i = 1; i <= GetnKid(Fnum); i++)
1118    misalign_sys_elem(Fnum, i, dx_sys, dy_sys, dr_sys);
1119}
1120
1121/*********************************************************************
1122void misalign_rms_type(const int type,
1123                       const double dx_rms, const double dy_rms,
1124                       const double dr_rms, const bool new_rnd)
1125                       
1126  Purpose:
1127     Set random misalignment to the elements in "type"
1128 
1129  Input:   
1130     type           element type,has the following value
1131                       All
1132                       dipole
1133                       quad
1134                       sext
1135                       bpm
1136                       girder
1137                       
1138     dx_rms         rms value of the error in x
1139     dy_rms         rms value of the error in y
1140     dr_rms         rms value of the error in rotation around s
1141     new_rnd        flag to turn on/off using the new random seed
1142     
1143**********************************************************************/
1144void misalign_rms_type(const int type,
1145                       const double dx_rms, const double dy_rms,
1146                       const double dr_rms, const bool new_rnd)
1147{
1148  long int   k;
1149
1150  if ((type >= All) && (type <= HOMmax)) {
1151    for (k = 1; k <= globval.Cell_nLoc; k++) {
1152      if ((Cell[k].Elem.Pkind == Mpole) &&
1153          ((type == Cell[k].Elem.M->n_design) ||
1154          ((type == All) &&
1155           ((Cell[k].Fnum != globval.gs) && (Cell[k].Fnum != globval.ge))))) {
1156        // if all: skip girders
1157        misalign_rms_elem(Cell[k].Fnum, Cell[k].Knum,
1158                          dx_rms, dy_rms, dr_rms, new_rnd);
1159      }
1160    }
1161  } else {
1162    printf("misalign_rms_type: incorrect type %d\n", type); exit_(1);
1163  }
1164}
1165
1166/*********************************************************************
1167void misalign_sys_type(const int type,
1168                       const double dx_sys, const double dy_sys,
1169                       const double dr_sys)
1170                       
1171  Purpose:
1172     Set systematic misalignment to the elements in "type"
1173 
1174  Input:   
1175     type           element type,has the following value
1176                       All
1177                       dipole
1178                       quad
1179                       sext
1180                       bpm
1181                       girder
1182                       
1183     dx_sys         sys value of the error in x
1184     dy_sys         sys value of the error in y
1185     dr_sys         sys value of the error in rotation around s
1186     
1187**********************************************************************/
1188void misalign_sys_type(const int type,
1189                       const double dx_sys, const double dy_sys,
1190                       const double dr_sys)
1191{
1192  long int   k;
1193
1194  if ((type >= All) && (type <= HOMmax)) {
1195    for (k = 1; k <= globval.Cell_nLoc; k++) {
1196      if ((Cell[k].Elem.Pkind == Mpole) &&
1197          ((type == Cell[k].Elem.M->n_design) ||
1198          ((type == All) &&
1199           ((Cell[k].Fnum != globval.gs) && (Cell[k].Fnum != globval.ge))))) {
1200        // if all: skip girders
1201        misalign_sys_elem(Cell[k].Fnum, Cell[k].Knum,
1202                          dx_sys, dy_sys, dr_sys);
1203      }
1204    }
1205  } else {
1206    printf("misalign_sys_type: incorrect type %d\n", type); exit_(1);
1207  }
1208}
1209
1210/*********************************************************************
1211void misalign_rms_girders(const int gs, const int ge,
1212                          const double dx_rms, const double dy_rms,
1213                          const double dr_rms, const bool new_rnd)
1214                       
1215  Purpose:
1216     Set systematic misalignment to the elements on the girders
1217 
1218  Input:   
1219     gs             girder start marker
1220     ge             girder end marker                 
1221     dx_rms         rms value of the error in x
1222     dy_rms         rms value of the error in y
1223     dr_rms         rms value of the error in rotation around s
1224     
1225**********************************************************************/
1226void misalign_rms_girders(const int gs, const int ge,
1227                          const double dx_rms, const double dy_rms,
1228                          const double dr_rms, const bool new_rnd)
1229{
1230  int       i, k, n_girders, n_ge, n_gs;
1231  long int  loc_gs, loc_ge, j;
1232  double    s_gs, s_ge, dx_gs[2], dx_ge[2], s;
1233
1234  n_gs = GetnKid(gs); n_ge = GetnKid(ge);
1235
1236  if (n_gs == n_ge)
1237    n_girders = n_gs;
1238  else {
1239    cout << "set_girders: no of GS != no of GE" << endl;
1240    exit (1);
1241  }
1242 
1243  misalign_rms_fam(gs, dx_rms, dy_rms, dr_rms, new_rnd);
1244  misalign_rms_fam(ge, dx_rms, dy_rms, dr_rms, new_rnd);
1245
1246  for (i = 1; i <= n_girders; i++) {
1247    loc_gs = Elem_GetPos(gs, i); loc_ge = Elem_GetPos(ge, i);
1248    s_gs = Cell[loc_gs].S; s_ge = Cell[loc_ge].S;
1249
1250    // roll for a rigid boby
1251    // Note, girders needs to be introduced as gs->ge pairs
1252    Cell[loc_ge].Elem.M->PdTrnd = Cell[loc_gs].Elem.M->PdTrnd;
1253    Mpole_SetdT(ge, i);
1254
1255    for (k = 0; k <= 1; k++) {
1256      dx_gs[k] = Cell[loc_gs].dS[k]; dx_ge[k] = Cell[loc_ge].dS[k];
1257    }
1258
1259    // move elements onto mis-aligned girder
1260    for (j = loc_gs+1; j < loc_ge; j++) {
1261      if ((Cell[j].Elem.Pkind == Mpole) || (Cell[j].Fnum == globval.bpm)) {
1262        s = Cell[j].S;
1263        for (k = 0; k <= 1; k++)
1264          Cell[j].Elem.M->PdSsys[k]
1265            = dx_gs[k] + (dx_ge[k]-dx_gs[k])*(s-s_gs)/(s_ge-s_gs);
1266        Cell[j].Elem.M->PdTsys = 
1267          Cell[loc_gs].Elem.M->PdTrms*Cell[loc_gs].Elem.M->PdTrnd;
1268      }
1269    }
1270  }
1271}
1272
1273/*********************************************************************
1274void misalign_sys_girders(const int gs, const int ge,
1275                          const double dx_sys, const double dy_sys,
1276                          const double dr_sys)
1277                       
1278  Purpose:
1279     Set systematic misalignment to the elements on the girders
1280 
1281  Input:   
1282     gs             girder start marker
1283     ge             girder end marker                 
1284     dx_sys         sys value of the error in x
1285     dy_sys         sys value of the error in y
1286     dr_sys         sys value of the error in rotation around s
1287     
1288**********************************************************************/
1289void misalign_sys_girders(const int gs, const int ge,
1290                          const double dx_sys, const double dy_sys,
1291                          const double dr_sys)
1292{
1293  int       i, k, n_girders, n_ge, n_gs;
1294  long int  loc_gs, loc_ge, j;
1295  double    s_gs, s_ge, dx_gs[2], dx_ge[2], s;
1296
1297  n_gs = GetnKid(gs); n_ge = GetnKid(ge);
1298
1299  if (n_gs == n_ge)
1300    n_girders = n_gs;
1301  else {
1302    cout << "set_girders: no of GS != no of GE" << endl;
1303    exit (1);
1304  }
1305 
1306  misalign_sys_fam(gs, dx_sys, dy_sys, dr_sys);
1307  misalign_sys_fam(ge, dx_sys, dy_sys, dr_sys);
1308
1309  for (i = 1; i <= n_girders; i++) {
1310    loc_gs = Elem_GetPos(gs, i); loc_ge = Elem_GetPos(ge, i);
1311    s_gs = Cell[loc_gs].S; s_ge = Cell[loc_ge].S;
1312
1313    // roll for a rigid boby
1314    // Note, girders needs to be introduced as gs->ge pairs
1315    Cell[loc_ge].Elem.M->PdTrnd = Cell[loc_gs].Elem.M->PdTrnd;
1316    Mpole_SetdT(ge, i);
1317
1318    for (k = 0; k <= 1; k++) {
1319      dx_gs[k] = Cell[loc_gs].dS[k]; dx_ge[k] = Cell[loc_ge].dS[k];
1320    }
1321
1322    // move elements onto mis-aligned girder
1323    for (j = loc_gs+1; j < loc_ge; j++) {
1324      if ((Cell[j].Elem.Pkind == Mpole) || (Cell[j].Fnum == globval.bpm)) {
1325        s = Cell[j].S;
1326        for (k = 0; k <= 1; k++)
1327          Cell[j].Elem.M->PdSsys[k]
1328            = dx_gs[k] + (dx_ge[k]-dx_gs[k])*(s-s_gs)/(s_ge-s_gs);
1329        Cell[j].Elem.M->PdTsys = 
1330          Cell[loc_gs].Elem.M->PdTrms*Cell[loc_gs].Elem.M->PdTrnd;
1331      }
1332    }
1333  }
1334}
1335
1336/***************************************************************************
1337void LoadAlignTol(const char *AlignFile, const bool Scale_it,
1338                  const double Scale, const bool new_rnd, const int k)
1339
1340  Purpose:
1341        Load misalignment error from an external file, then set the error
1342        to the corresponding elements.
1343 
1344  Input:
1345      AlignFile    file from which the misalignment error is readed                       
1346      Scale_it     flag to turn on/off the scale of the error
1347      Scale        value to scale the error
1348      new_rnd      use new random number or not
1349      k   
1350     
1351      15/10/2013 Jianfeng Zhang @ LAL
1352                  Replace fgets() by getline() to fix the bug to read line of
1353                  arbritrary length.
1354                 
1355****************************************************************************/
1356void LoadAlignTol(const char *AlignFile, const bool Scale_it,
1357                  const double Scale, const bool new_rnd, const int k)
1358{
1359  char    Name[max_str]=" ",  type[max_str]=" ";
1360  char    *line = NULL;
1361  size_t   len = 0;
1362  ssize_t  read;
1363  int     Fnum = 0, seed_val = 0, LineNum = 0;
1364  double  dx = 0.0, dy = 0.0, dr = 0.0;  // x and y misalignments [m] and roll error [rad]
1365  double  dr_deg = 0.0;
1366  bool    rms = false, set_rnd = false;
1367  bool    prt = false;
1368  FILE    *fp;
1369
1370  fp = file_read(AlignFile);
1371  if(fp == NULL){
1372    printf("LoadAlignTol(): Error! Failure to read file %s !\n",AlignFile);
1373    exit_(1);
1374  }
1375
1376  if (new_rnd)
1377    printf("set alignment errors\n");
1378  else
1379    printf("scale alignment errors: %4.2f\n", Scale);
1380
1381  while ((read=getline(&line, &len, fp)) != -1) {
1382   
1383    LineNum++;
1384    if(!prt){
1385      printf("Line # %ld \n",LineNum);
1386      printf("Retrieved line of length %zu : \n",read);
1387      printf("%s \n",line);
1388    }
1389
1390    //check for whether to set seed
1391    if ((strstr(line, "#") == NULL) && line[0] != '\n' &&
1392        line[0]!='\r' && (strcmp(line, "\r\n") != 0)) {
1393      sscanf(line, "%s", Name);
1394      if (strcmp("seed", Name) == 0) {
1395        set_rnd = true;
1396        sscanf(line, "%*s %d", &seed_val);
1397        seed_val += 2*k;
1398        printf("setting random seed to %d\n", seed_val);
1399        iniranf(seed_val); 
1400      } else {
1401        sscanf(line,"%*s %s %lf %lf %lf", type, &dx, &dy, &dr);
1402        dr_deg = dr*180.0/M_PI;
1403
1404        if (strcmp(type, "rms") == 0){
1405          rms = true;
1406        }
1407        else if (strcmp(type, "sys") == 0){
1408          rms = false;
1409        }
1410        else {
1411          printf("LoadAlignTol(): Error! Need to specify misalignment error type: <rms> or <sys> of element %s! \n",
1412                 Name);
1413          exit_(1);
1414        }
1415
1416        if (rms && !set_rnd) {
1417          printf("LoadAlignTol(): Error! Seed of <rms> errors is not defined \n");
1418          exit_(1);
1419        }
1420
1421        if (Scale_it) {
1422          dx *= Scale; dy *= Scale; dr *= Scale;
1423        } 
1424
1425        if(!prt){
1426          printf("Set <%s> misalignment errors to: [%s] \n",type, Name);
1427          printf("dx = %e, dy = %e, dr = %e \n \n",dx,dy,dr);
1428        }
1429       
1430        if (strcmp("all", Name) == 0) {
1431       
1432          if(rms)
1433            misalign_rms_type(All, dx, dy, dr_deg, new_rnd);
1434          else
1435            misalign_sys_type(All, dx, dy, dr_deg);
1436        } else if (strcmp("girder", Name) == 0) {
1437       
1438          if (rms)
1439            misalign_rms_girders(globval.gs, globval.ge, dx, dy, dr_deg,
1440                                 new_rnd);
1441          else
1442            misalign_sys_girders(globval.gs, globval.ge, dx, dy, dr_deg);
1443        } else if (strcmp("dipole", Name) == 0) {
1444         
1445          if (rms)
1446            misalign_rms_type(Dip, dx, dy, dr_deg, new_rnd);
1447          else
1448            misalign_sys_type(Dip, dx, dy, dr_deg);
1449        } else if (strcmp("quad", Name) == 0) {
1450       
1451          if (rms)
1452            misalign_rms_type(Quad, dx, dy, dr_deg, new_rnd);
1453          else
1454            misalign_sys_type(Quad, dx, dy, dr_deg);
1455        } else if (strcmp("sext", Name) == 0) {
1456       
1457          if (rms)
1458            misalign_rms_type(Sext, dx, dy, dr_deg, new_rnd);
1459          else
1460            misalign_sys_type(Sext, dx, dy, dr_deg);
1461        } else if (strcmp("bpm", Name) == 0) {
1462       
1463          if (rms)
1464            misalign_rms_fam(globval.bpm, dx, dy, dr_deg, new_rnd);
1465          else
1466            misalign_sys_fam(globval.bpm, dx, dy, dr_deg);
1467        } else {
1468          Fnum = ElemIndex(Name);
1469          if(Fnum > 0) {
1470            if (rms)
1471              misalign_rms_fam(Fnum, dx, dy, dr_deg, new_rnd);
1472            else
1473              misalign_sys_fam(Fnum, dx, dy, dr_deg);
1474          } else{
1475            printf("LoadAlignTol(): Error! Undefined element: %s \n", Name);
1476            exit_(1);
1477          }
1478        }
1479      }
1480    } else
1481      continue;
1482  }
1483  free(line);
1484  fclose(fp);
1485}
1486
1487/****************************************************************************/
1488/* void set_aper_elem(const int Fnum, const int Knum,
1489                   const double Dxmin, const double Dxmax,
1490                   const double Dymin, const double Dymax)
1491
1492   Purpose:
1493      Define vacuum chamber to the element 
1494     
1495
1496   Input:
1497      none
1498
1499   Output:
1500       none
1501
1502   Return:
1503       none
1504
1505   Global variables:
1506       none
1507
1508   Specific functions:
1509       none
1510
1511   Comments:
1512      Add k=0 for the default start point "start" in tracy.
1513
1514****************************************************************************/
1515// apertures
1516
1517void set_aper_elem(const int Fnum, const int Knum, 
1518                   const double Dxmin, const double Dxmax, 
1519                   const double Dymin, const double Dymax) 
1520{ 
1521  int  k; 
1522 
1523  if(Fnum==0 && Knum==0)
1524    k=0;
1525  else
1526    k = Elem_GetPos(Fnum, Knum);
1527     
1528    Cell[k].maxampl[X_][0] = Dxmin; 
1529    Cell[k].maxampl[X_][1] = Dxmax; 
1530    Cell[k].maxampl[Y_][0] = Dymin; 
1531    Cell[k].maxampl[Y_][1] = Dymax; 
1532 } 
1533
1534 /****************************************************************************/
1535/* void set_aper_fam(const int Fnum,
1536                  const double Dxmin, const double Dxmax,
1537                  const double Dymin, const double Dymax)
1538   Purpose:
1539      Define vacuum chamber to the family "Fnum" 
1540     
1541
1542   Input:
1543      none
1544     
1545   Output:
1546       none
1547
1548   Return:
1549       none
1550
1551   Global variables:
1552       none
1553
1554   Specific functions:
1555       none
1556
1557   Comments:
1558       Enumeration of special variables:
1559                 enum { All = 0, Dip = 1, Quad = 2, Sext = 3, Oct = 4, Dec = 5, Dodec = 6 }
1560
1561****************************************************************************/
1562void set_aper_fam(const int Fnum,
1563                  const double Dxmin, const double Dxmax, 
1564                  const double Dymin, const double Dymax)
1565{
1566  int k;
1567
1568  for (k = 1; k <= GetnKid(Fnum); k++)
1569    set_aper_elem(Fnum, k, Dxmin, Dxmax, Dymin, Dymax);
1570}
1571
1572/****************************************************************************/
1573/* void set_aper_type(const int type, const double Dxmin, const double Dxmax,
1574                   const double Dymin, const double Dymax)
1575
1576   Purpose:
1577      Define vacuum chamber to the elements with the same "type", either for "all" element, or "quad","sext", etc. 
1578     
1579
1580   Input:
1581       none
1582       
1583   Output:
1584       none
1585
1586   Return:
1587       none
1588
1589   Global variables:
1590       none
1591
1592   Specific functions:
1593       none
1594
1595   Comments:
1596      1) Enumeration of special variables:
1597                 enum { All = 0, Dip = 1, Quad = 2, Sext = 3, Oct = 4, Dec = 5, Dodec = 6 }
1598      2) change the start point from k=1 to k=0, in order to set the aperture for
1599         the default start point "begin" which is not a lattice element.
1600
1601****************************************************************************/
1602void set_aper_type(const int type, const double Dxmin, const double Dxmax, 
1603                   const double Dymin, const double Dymax)
1604{
1605  long int   k;
1606
1607  if (type >= All && type <= HOMmax) 
1608    {
1609 //   for(k = 1; k <= globval.Cell_nLoc; k++)
1610      for(k = 0; k <= globval.Cell_nLoc; k++)
1611        if (((Cell[k].Elem.Pkind == Mpole) &&
1612           (Cell[k].Elem.M->n_design == type)) || (type == All))
1613        set_aper_elem(Cell[k].Fnum, Cell[k].Knum, Dxmin, Dxmax, Dymin, Dymax);
1614     } 
1615  else
1616    printf("set_aper_type: bad design type %d\n", type);
1617}
1618
1619
1620/****************************************************************************/
1621/* void LoadApers(const char *AperFile, const double scl_x, const double scl_y)
1622
1623   Purpose:
1624      Read vacuum chamber from file "AperFile", and scale the values with scl_x and scl_y.
1625      Assign vacuum chamber to all elements, if there are definition of
1626      chamber at quad and sext, then assign the specific values at these elements.
1627     
1628
1629   Input:
1630       AperFile:  file with chamber definition
1631       scl_x   :  scale factor of x limitation
1632       scl_y   : scale factor of y limitation
1633
1634   Output:
1635       none
1636
1637   Return:
1638       none
1639
1640   Global variables:
1641       none
1642
1643   Specific functions:
1644       none
1645
1646   Comments:
1647       Enumeration of special variables:
1648                 enum { All = 0, Dip = 1, Quad = 2, Sext = 3, Oct = 4, Dec = 5, Dodec = 6 }
1649                 
1650    10/2010   Comments by Jianfeng Zhang
1651
1652****************************************************************************/
1653void LoadApers(const char *AperFile, const double scl_x, const double scl_y) 
1654{
1655  char    line[max_str], Name[max_str];
1656  int     Fnum; 
1657  double  dxmin, dxmax, dymin, dymax;  // min and max x and apertures
1658  FILE    *fp;
1659
1660  bool  prt = true;
1661
1662  fp = file_read(AperFile);
1663
1664  printf("\n");
1665  printf("...Load and Set Apertures.\n");
1666
1667  while (fgets(line, max_str, fp) != NULL) {
1668    if (strstr(line, "#") == NULL) 
1669    {
1670      sscanf(line,"%s %lf %lf %lf %lf",
1671             Name, &dxmin, &dxmax, &dymin, &dymax);
1672      dxmin *= scl_x; 
1673      dxmax *= scl_x; 
1674      dymin *= scl_y; 
1675      dymax *= scl_y;
1676     
1677      if (strcmp("all", Name)==0) {
1678        if(prt)
1679          printf("setting all apertures to"
1680                 " dxmin = %e, dxmax = %e, dymin = %e, dymax = %e\n",
1681                 dxmin, dxmax, dymin, dymax);
1682        set_aper_type(All, dxmin, dxmax, dymin, dymax);
1683        //      ini_aper(dxmin, dxmax, dymin, dymax);
1684       }
1685       
1686      else if (strcmp("quad", Name)==0) {
1687        if(prt)
1688          printf("setting apertures at all quads to"
1689                 " dxmin = %e, dxmax = %e, dymin = %e, dymax = %e\n",
1690                 dxmin, dxmax, dymin, dymax); 
1691        set_aper_type(Quad, dxmin, dxmax, dymin, dymax);
1692       }
1693       
1694      else if (strcmp("sext", Name) == 0) {
1695        if(prt)
1696          printf("setting apertures at all sextupoles to"
1697                 " dxmin = %e, dxmax = %e, dymin = %e, dymax = %e\n",
1698                 dxmin, dxmax, dymin, dymax);
1699        set_aper_type(Sext, dxmin, dxmax, dymin, dymax);
1700       }
1701       
1702      else {
1703        Fnum = ElemIndex(Name);
1704        if(Fnum > 0) {
1705          if(prt)
1706            printf("setting apertures at all %s to"
1707                   " dxmin = %e, dxmax = %e, dymin = %e, dymax = %e\n",
1708                   Name, dxmin, dxmax, dymin, dymax);
1709          set_aper_fam(Fnum, dxmin, dxmax, dymin, dymax);
1710          } 
1711         else 
1712          printf("LoadApers: lattice does not contain element %s\n", Name);
1713      }
1714    } 
1715   else
1716      printf("%s", line);
1717  }
1718   
1719  fclose(fp);
1720}
1721
1722
1723double get_L(const int Fnum, const int Knum)
1724{
1725  return Cell[Elem_GetPos(Fnum, Knum)].Elem.PL;
1726}
1727
1728
1729void set_L(const int Fnum, const int Knum, const double L)
1730{
1731
1732  Cell[Elem_GetPos(Fnum, Knum)].Elem.PL = L;
1733}
1734
1735
1736void set_L(const int Fnum, const double L)
1737{
1738  int  k;
1739
1740  for (k = 1; k <= GetnKid(Fnum); k++)
1741    set_L(Fnum, k, L);
1742}
1743
1744
1745void set_dL(const int Fnum, const int Knum, const double dL)
1746{
1747
1748  Cell[Elem_GetPos(Fnum, Knum)].Elem.PL += dL;
1749}
1750
1751
1752// multipole components
1753/*************************************************************
1754void get_bn_design_elem(const int Fnum, const int Knum,
1755                        const int n, double &bn, double &an)
1756                       
1757   Purpose:
1758       Get the n-th order design value (bn, an) of the element
1759       with family index "Fnum" and the kid number "Knum".
1760       
1761  Input:
1762      Fnum:   family index
1763      Knum:   kid index
1764         n:   n-th design order of the element
1765        bn:   bn component of the element
1766        an:   an component of the element
1767
1768 Output:
1769    None
1770   
1771 Return:
1772          bn, an
1773         
1774 Comments:
1775 
1776            11/2010 comments by jianfeng Zhang
1777**************************************************************/
1778void get_bn_design_elem(const int Fnum, const int Knum,
1779                        const int n, double &bn, double &an)
1780{
1781  elemtype  elem;
1782
1783  elem = Cell[Elem_GetPos(Fnum, Knum)].Elem;
1784
1785  bn = elem.M->PBpar[HOMmax+n]; an = elem.M->PBpar[HOMmax-n];
1786}
1787
1788
1789void get_bnL_design_elem(const int Fnum, const int Knum,
1790                         const int n, double &bnL, double &anL)
1791{
1792  elemtype  elem;
1793
1794  elem = Cell[Elem_GetPos(Fnum, Knum)].Elem;
1795
1796  bnL = elem.M->PBpar[HOMmax+n]; anL = elem.M->PBpar[HOMmax-n];
1797
1798  if (elem.PL != 0.0) {
1799    bnL *= elem.PL; anL *= elem.PL;
1800  }
1801}
1802
1803
1804void set_bn_design_elem(const int Fnum, const int Knum,
1805                        const int n, const double bn, const double an)
1806{
1807  elemtype  elem;
1808
1809  elem = Cell[Elem_GetPos(Fnum, Knum)].Elem;
1810
1811  elem.M->PBpar[HOMmax+n] = bn; elem.M->PBpar[HOMmax-n] = an;
1812
1813  Mpole_SetPB(Fnum, Knum, n); Mpole_SetPB(Fnum, Knum, -n);
1814}
1815
1816
1817void set_dbn_design_elem(const int Fnum, const int Knum,
1818                         const int n, const double dbn, const double dan)
1819{
1820  elemtype  elem;
1821
1822  elem = Cell[Elem_GetPos(Fnum, Knum)].Elem;
1823
1824  elem.M->PBpar[HOMmax+n] += dbn; elem.M->PBpar[HOMmax-n] += dan;
1825
1826  Mpole_SetPB(Fnum, Knum, n); Mpole_SetPB(Fnum, Knum, -n);
1827}
1828
1829
1830void set_bn_design_fam(const int Fnum,
1831                       const int n, const double bn, const double an)
1832{
1833  int k;
1834
1835  for (k = 1; k <= GetnKid(Fnum); k++)
1836    set_bn_design_elem(Fnum, k, n, bn, an);
1837}
1838
1839
1840void set_dbn_design_fam(const int Fnum,
1841                        const int n, const double dbn, const double dan)
1842{
1843  int k;
1844
1845  for (k = 1; k <= GetnKid(Fnum); k++)
1846    set_dbn_design_elem(Fnum, k, n, dbn, dan);
1847}
1848
1849
1850void set_bnL_design_elem(const int Fnum, const int Knum,
1851                         const int n, const double bnL, const double anL)
1852{
1853  elemtype  elem;
1854
1855  elem = Cell[Elem_GetPos(Fnum, Knum)].Elem;
1856
1857  if (elem.PL != 0.0) {
1858    elem.M->PBpar[HOMmax+n] = bnL/elem.PL;
1859    elem.M->PBpar[HOMmax-n] = anL/elem.PL;
1860  } else {
1861    // thin kick
1862    elem.M->PBpar[HOMmax+n] = bnL; elem.M->PBpar[HOMmax-n] = anL;
1863  }
1864
1865  Mpole_SetPB(Fnum, Knum, n); Mpole_SetPB(Fnum, Knum, -n);
1866}
1867
1868
1869void set_dbnL_design_elem(const int Fnum, const int Knum,
1870                          const int n, const double dbnL, const double danL)
1871{
1872  elemtype  elem;
1873
1874  elem = Cell[Elem_GetPos(Fnum, Knum)].Elem;
1875
1876  if (elem.PL != 0.0) {
1877    elem.M->PBpar[HOMmax+n] += dbnL/elem.PL;
1878    elem.M->PBpar[HOMmax-n] += danL/elem.PL;
1879  } else {
1880    // thin kick
1881    elem.M->PBpar[HOMmax+n] += dbnL; elem.M->PBpar[HOMmax-n] += danL;
1882  }
1883
1884  Mpole_SetPB(Fnum, Knum, n); Mpole_SetPB(Fnum, Knum, -n);
1885}
1886
1887
1888void set_dbnL_design_fam(const int Fnum,
1889                         const int n, const double dbnL, const double danL)
1890{
1891  int k;
1892
1893  for (k = 1; k <= GetnKid(Fnum); k++)
1894    set_bnL_design_elem(Fnum, k, n, dbnL, danL);
1895}
1896
1897
1898void set_bnL_design_fam(const int Fnum,
1899                        const int n, const double bnL, const double anL)
1900{
1901  int k;
1902
1903  for (k = 1; k <= GetnKid(Fnum); k++)
1904    set_bnL_design_elem(Fnum, k, n, bnL, anL);
1905}
1906
1907
1908void set_bnL_design_type(const int type,
1909                         const int n, const double bnL, const double anL)
1910{
1911  long int  k;
1912
1913  if ((type >= Dip) && (type <= HOMmax)) {
1914    for (k = 1; k <= globval.Cell_nLoc; k++)
1915      if ((Cell[k].Elem.Pkind == Mpole) && (Cell[k].Elem.M->n_design == type))
1916        set_bnL_design_elem(Cell[k].Fnum, Cell[k].Knum, n, bnL, anL);
1917  } else 
1918    printf("Bad type argument to set_bnL_design_type()\n");
1919}
1920
1921/***********************************************************************
1922void set_bnL_sys_elem(const int Fnum, const int Knum,
1923                      const int n, const double bnL, const double anL)
1924                         
1925   Purpose:
1926       Set field error to the kid of a family, errors are absolute
1927        integrated field strength, replace the previous value!!!
1928       
1929   
1930   Input:
1931      Fnum           family index
1932      Knum           kids index   
1933      n              order of the error
1934      bnL            absolute integrated B component for the n-th error
1935      anL            absolute integrated A component for the n-th error
1936           
1937
1938     
1939   Output:
1940      None
1941     
1942  Return:
1943      None
1944     
1945  Global variables
1946      None
1947   
1948  Specific functions:
1949     None   
1950     
1951 Comments:
1952     None
1953**********************************************************************/
1954void set_bnL_sys_elem(const int Fnum, const int Knum,
1955                      const int n, const double bnL, const double anL)
1956{
1957  elemtype  elem;
1958
1959  const bool  prt = false;
1960
1961  elem = Cell[Elem_GetPos(Fnum, Knum)].Elem;
1962
1963  if (elem.PL != 0.0) {
1964    elem.M->PBsys[HOMmax+n] = bnL/elem.PL;
1965    elem.M->PBsys[HOMmax-n] = anL/elem.PL;
1966  } else {
1967    // thin kick
1968    elem.M->PBsys[HOMmax+n] = bnL; elem.M->PBsys[HOMmax-n] = anL;
1969  }
1970 
1971  Mpole_SetPB(Fnum, Knum, n);    //set for Bn component
1972  Mpole_SetPB(Fnum, Knum, -n);   //set for An component
1973
1974  if (prt)
1975    printf("set the n=%d component of %s to %e %e\n",
1976           n, Cell[Elem_GetPos(Fnum, Knum)].Elem.PName,
1977           bnL, elem.M->PBsys[HOMmax+n]);
1978}
1979
1980/***********************************************************************
1981void set_bnL_sys_fam(const int Fnum,
1982                     const int n, const double bnL, const double anL)
1983                         
1984   Purpose:
1985       Set field error to all the kids of a family,errors are absolute
1986        integrated field strength
1987       
1988       
1989   
1990   Input:
1991      Fnum           family index
1992      n              order of the error
1993      bnL            absolute integrated B component for the n-th error
1994      anL            absolute integrated A component for the n-th error
1995           
1996
1997     
1998   Output:
1999      None
2000     
2001  Return:
2002      None
2003     
2004  Global variables
2005      None
2006   
2007  Specific functions:
2008     None   
2009     
2010 Comments:
2011     None
2012**********************************************************************/
2013void set_bnL_sys_fam(const int Fnum,
2014                     const int n, const double bnL, const double anL)
2015{
2016  int k;
2017
2018  for (k = 1; k <= GetnKid(Fnum); k++)
2019    set_bnL_sys_elem(Fnum, k, n, bnL, anL);
2020}
2021
2022/***********************************************************************
2023void set_bnL_sys_type(const int type,
2024                      const int n, const double bnL, const double anL)
2025                         
2026   Purpose:
2027       Set field error to the type, errors are absolute
2028        integrated field strength
2029   
2030       
2031       
2032   Input:
2033      type          type name
2034      n             order of the error
2035      bnL           absolute integrated B component for the n-th error
2036      anL           absolute integrated A component for the n-th error
2037           
2038
2039     
2040   Output:
2041      None
2042     
2043  Return:
2044      None
2045     
2046  Global variables
2047      None
2048   
2049  Specific functions:
2050     None   
2051     
2052 Comments:
2053      Attension:
2054          This code has a bug, in the for loop, when looking for the
2055          quadrupole family, it will also find the skew quadrupole family,
2056          since their Pkind == Mpole & n_design =2.
2057          It means the multipole error is additionally set N times,
2058          and N is the number of skew quadrupole in the lattice.
2059         
2060                 10/2010   Comments by Jianfeng Zhang
2061     
2062**********************************************************************/
2063void set_bnL_sys_type(const int type,
2064                      const int n, const double bnL, const double anL)
2065{
2066  long int   k;
2067
2068  if (type >= Dip && type <= HOMmax) {
2069    for(k = 1; k <= globval.Cell_nLoc; k++)
2070      if ((Cell[k].Elem.Pkind == Mpole) && (Cell[k].Elem.M->n_design == type))
2071        set_bnL_sys_elem(Cell[k].Fnum, Cell[k].Knum, n, bnL, anL);
2072  } else
2073    printf("Bad type argument to set_bnL_sys_type()\n");
2074}
2075
2076
2077void set_bnL_rms_elem(const int Fnum, const int Knum,
2078                      const int n, const double bnL, const double anL,
2079                      const bool new_rnd)
2080{
2081  elemtype  elem;
2082
2083  bool  normal = true, prt = false;
2084 
2085  elem = Cell[Elem_GetPos(Fnum, Knum)].Elem;
2086
2087  if (elem.PL != 0.0) {
2088    elem.M->PBrms[HOMmax+n] = bnL/elem.PL;
2089    elem.M->PBrms[HOMmax-n] = anL/elem.PL;
2090  } else {
2091    // thin kick
2092    elem.M->PBrms[HOMmax+n] = bnL; elem.M->PBrms[HOMmax-n] = anL;
2093  }
2094
2095  if(new_rnd){
2096    if (normal) {
2097      elem.M->PBrnd[HOMmax+n] = normranf();
2098      elem.M->PBrnd[HOMmax-n] = normranf();
2099    } else {
2100      elem.M->PBrnd[HOMmax+n] = ranf(); elem.M->PBrnd[HOMmax-n] = ranf();
2101    }
2102  }
2103 
2104  if (prt)
2105    printf("set_bnL_rms_elem:  Fnum = %d, Knum = %d"
2106           ", bnL = %e, anL = %e %e %e\n",
2107           Fnum, Knum, bnL, anL,
2108           elem.M->PBrms[HOMmax+n], elem.M->PBrms[HOMmax-n]);
2109
2110  Mpole_SetPB(Fnum, Knum, n); Mpole_SetPB(Fnum, Knum, -n);
2111}
2112
2113
2114void set_bnL_rms_fam(const int Fnum,
2115                     const int n, const double bnL, const double anL,
2116                     const bool new_rnd)
2117{
2118  int k;
2119
2120  for (k = 1; k <= GetnKid(Fnum); k++)
2121    set_bnL_rms_elem(Fnum, k, n, bnL, anL, new_rnd);
2122}
2123
2124
2125void set_bnL_rms_type(const int type,
2126                      const int n, const double bnL, const double anL,
2127                      const bool new_rnd)
2128{
2129  long int   k;
2130 
2131  if (type >= Dip && type <= HOMmax) {
2132    for(k = 1; k <= globval.Cell_nLoc; k++)
2133      if ((Cell[k].Elem.Pkind == Mpole) && (Cell[k].Elem.M->n_design == type))
2134        set_bnL_rms_elem(Cell[k].Fnum, Cell[k].Knum, n, bnL, anL, new_rnd);
2135  } else
2136    printf("Bad type argument to set_bnL_rms_type()\n");
2137}
2138
2139/***********************************************************************
2140void set_bnr_sys_elem(const int Fnum, const int Knum,
2141                      const int n, const double bnr, const double anr)
2142                         
2143   Purpose:
2144       Set field error to the kid of a family, errors are relative to
2145        design values for (Dip, Quad, Sext, ...)
2146   
2147        If r0 != 0, call this function
2148       
2149   Input:
2150      Fnum           family index
2151      Knum           kids index   
2152      n              order of the error
2153      bnL            relative integrated B component for the n-th error
2154      anL            relative integrated A component for the n-th error
2155           
2156
2157     
2158   Output:
2159      None
2160     
2161  Return:
2162      None
2163     
2164  Global variables
2165      None
2166   
2167  Specific functions:
2168     None   
2169     
2170 Comments:
2171      !!!!!!!!!
2172      This function desn't work for dipole, since   
2173      mp->PBpar[HOMmax+1] is not assigned a value when dipole is
2174      read in t2lat.cc. 
2175     
2176      comments by Jianfeng Zhang  10/2010  @ soleil   
2177**********************************************************************/
2178void set_bnr_sys_elem(const int Fnum, const int Knum,
2179                      const int n, const double bnr, const double anr)
2180{
2181  int        nd;
2182  MpoleType  *mp;
2183  bool prt = false;
2184
2185  mp = Cell[Elem_GetPos(Fnum, Knum)].Elem.M; nd = mp->n_design;
2186  // errors are relative to design values for (Dip, Quad, Sext, ...)
2187  mp->PBsys[HOMmax+n] = bnr*mp->PBpar[HOMmax+nd];
2188  mp->PBsys[HOMmax-n] = anr*mp->PBpar[HOMmax+nd];
2189  //update the total field strength PB and maximum order p_order
2190  Mpole_SetPB(Fnum, Knum, n); Mpole_SetPB(Fnum, Knum, -n);
2191
2192  if (prt)
2193    printf("set the n=%d component of %s to %e %e %e\n",
2194           n, Cell[Elem_GetPos(Fnum, Knum)].Elem.PName,
2195           bnr, mp->PBpar[HOMmax+nd], mp->PBsys[HOMmax+n]);
2196}
2197
2198/***********************************************************************
2199void set_bnr_sys_fam(const int Fnum,
2200                     const int n, const double bnr, const double anr)
2201                         
2202   Purpose:
2203       Set field error to all the kids of a family, errors are relative
2204        to design values for (Dip, Quad, Sext, ...).
2205       
2206        If r0 != 0, call this function
2207   
2208   Input:
2209      Fnum           family index
2210      n              order of the error
2211      bnL            relative integrated B component for the n-th error
2212      anL            relative integrated A component for the n-th error
2213           
2214
2215     
2216   Output:
2217      None
2218     
2219  Return:
2220      None
2221     
2222  Global variables
2223      None
2224   
2225  Specific functions:
2226     None   
2227     
2228 Comments:
2229     None
2230**********************************************************************/
2231void set_bnr_sys_fam(const int Fnum,
2232                     const int n, const double bnr, const double anr)
2233{
2234  int k;
2235
2236  for (k = 1; k <= GetnKid(Fnum); k++)
2237    set_bnr_sys_elem(Fnum, k, n, bnr, anr);
2238}
2239
2240/***********************************************************************
2241void set_bnr_sys_type(const int type,
2242                      const int n, const double bnr, const double anr)
2243                         
2244   Purpose:
2245       Set field error to the type, errors are relative
2246        to design values for (Dip, Quad, Sext, ...)
2247   
2248        If r0 != 0, call this function
2249       
2250   Input:
2251      type          type name
2252      n             order of the error
2253      bnL           relative integrated B component for the n-th error
2254      anL           relative integrated A component for the n-th error
2255           
2256
2257     
2258   Output:
2259      None
2260     
2261  Return:
2262      None
2263     
2264  Global variables
2265      None
2266   
2267  Specific functions:
2268     None   
2269     
2270 Comments:
2271     None
2272**********************************************************************/
2273void set_bnr_sys_type(const int type,
2274                      const int n, const double bnr, const double anr)
2275{
2276  long int   k;
2277
2278  if (type >= Dip && type <= HOMmax) {
2279    for(k = 1; k <= globval.Cell_nLoc; k++)
2280      if ((Cell[k].Elem.Pkind == Mpole) && (Cell[k].Elem.M->n_design == type))
2281        set_bnr_sys_elem(Cell[k].Fnum, Cell[k].Knum, n, bnr, anr);
2282  } else
2283    printf("Bad type argument to set_bnr_sys_type()\n");
2284}
2285
2286/***********************************************************************
2287void set_bnr_rms_elem(const int Fnum, const int Knum,
2288                      const int n, const double bnr, const double anr,
2289                      const bool new_rnd)
2290                         
2291   Purpose:
2292       Update rms field error PBrms and random value of the rms field error PBrnd
2293       to a elment, errors are relative to design values PBpar for (Dip, Quad,
2294       Sext, ...).
2295       
2296        If r0 != 0, call this function
2297   
2298   Input:
2299      Fnum           family index
2300      Knum           kid index
2301      n              order of the error
2302      bnL            relative integrated B component for the n-th error
2303      anL            relative integrated A component for the n-th error
2304      new_rnd        true, generate random value for the rms field error
2305                     false, NOT generate random value for the rms field error       
2306                     
2307   Output:
2308      None
2309     
2310  Return:
2311      None
2312     
2313  Global variables
2314      None
2315   
2316  Specific functions:
2317     None   
2318     
2319 Comments:
2320     None
2321**********************************************************************/
2322void set_bnr_rms_elem(const int Fnum, const int Knum,
2323                      const int n, const double bnr, const double anr,
2324                      const bool new_rnd)
2325{
2326  int        nd;
2327  MpoleType  *mp;
2328
2329  bool  normal = true, prt = false;
2330 
2331  mp = Cell[Elem_GetPos(Fnum, Knum)].Elem.M; nd = mp->n_design;
2332  // errors are relative to design values for (Dip, Quad, Sext, ...)
2333  mp->PBrms[HOMmax+n] = bnr*mp->PBpar[HOMmax+nd];
2334  mp->PBrms[HOMmax-n] = anr*mp->PBpar[HOMmax+nd];
2335  if(new_rnd){
2336    if (normal) {
2337      mp->PBrnd[HOMmax+n] = normranf(); mp->PBrnd[HOMmax-n] = normranf();
2338    } else {
2339      mp->PBrnd[HOMmax+n] = ranf(); mp->PBrnd[HOMmax-n] = ranf();
2340    }
2341  }
2342 
2343  if (prt)
2344    printf("set_bnr_rms_elem:  Fnum = %d, Knum = %d"
2345           ", bnr = %e, anr = %e %e %e\n",
2346           Fnum, Knum, bnr, anr, mp->PBrms[HOMmax+n], mp->PBrms[HOMmax-n]);
2347
2348  Mpole_SetPB(Fnum, Knum, n); Mpole_SetPB(Fnum, Knum, -n);
2349}
2350
2351/***********************************************************************
2352void set_bnr_rms_fam(const int Fnum,
2353                     const int n, const double bnr, const double anr,
2354                     const bool new_rnd)
2355                         
2356   Purpose:
2357       Update rms field error PBrms and random value of the rms field error PBrnd
2358       to all the kid elments in a family, errors are relative to design values PBpar
2359       for (Dip, Quad, Sext, ...).
2360       
2361        If r0 != 0, call this function
2362   
2363   Input:
2364      Fnum           family index
2365      n              order of the error
2366      bnr            relative integrated B component for the n-th error
2367      anr            relative integrated A component for the n-th error
2368      new_rnd        true, generate random value for the rms field error
2369                     false, NOT generate random value for the rms field error       
2370                     
2371   Output:
2372      None
2373     
2374  Return:
2375      None
2376     
2377  Global variables
2378      None
2379   
2380  Specific functions:
2381     None   
2382     
2383 Comments:
2384     None
2385**********************************************************************/
2386void set_bnr_rms_fam(const int Fnum,
2387                     const int n, const double bnr, const double anr,
2388                     const bool new_rnd)
2389{
2390  int k;
2391
2392  for (k = 1; k <= GetnKid(Fnum); k++)
2393    set_bnr_rms_elem(Fnum, k, n, bnr, anr, new_rnd);
2394}
2395
2396/***********************************************************************
2397void set_bnr_rms_type(const int type,
2398                      const int n, const double bnr, const double anr,
2399                      const bool new_rnd)
2400                         
2401   Purpose:
2402       Update rms field error PBrms and random value of the rms field error PBrnd
2403       to all the kid elments in a family, errors are relative to design values PBpar
2404       for (Dip, Quad, Sext, ...).
2405       
2406        If r0 != 0, call this function
2407   
2408   Input:
2409      type           type of the elment,maybe 'dipole', 'quadrupole', 'sextupole', 'all'
2410      n              order of the error
2411      bnr            relative integrated B component for the n-th error
2412      anr            relative integrated A component for the n-th error
2413      new_rnd        true, generate random value for the rms field error
2414                     false, NOT generate random value for the rms field error       
2415                     
2416   Output:
2417      None
2418     
2419  Return:
2420      None
2421     
2422  Global variables
2423      None
2424   
2425  Specific functions:
2426     None   
2427     
2428 Comments:
2429     None
2430**********************************************************************/
2431void set_bnr_rms_type(const int type,
2432                      const int n, const double bnr, const double anr,
2433                      const bool new_rnd)
2434{
2435  long int   k;
2436 
2437  if (type >= Dip && type <= HOMmax) {
2438    for(k = 1; k <= globval.Cell_nLoc; k++)
2439      if ((Cell[k].Elem.Pkind == Mpole) && (Cell[k].Elem.M->n_design == type))
2440        set_bnr_rms_elem(Cell[k].Fnum, Cell[k].Knum, n, bnr, anr, new_rnd);
2441  } else
2442    printf("Bad type argument to set_bnr_rms_type()\n");
2443}
2444
2445
2446double get_Wiggler_BoBrho(const int Fnum, const int Knum)
2447{
2448  return Cell[Elem_GetPos(Fnum, Knum)].Elem.W->BoBrhoV[0];
2449}
2450
2451/****************************************************************************/
2452/* void set_Wiggler_BoBrho(const int Fnum, const int Knum, const double BoBrhoV)
2453
2454   Purpose:
2455       Set the integrated field strength for the specific element in the family
2456       of wiggers.       
2457       
2458   Input:
2459       Fnum     family name
2460       BoBrhoV  integrated field strength
2461
2462   Output:
2463      none
2464
2465   Return:
2466       none
2467
2468   Global variables:
2469       none
2470
2471   Specific functions:
2472       none
2473
2474   Comments:
2475       Called by set_Wiggler_BoBrho(const int Fnum, const double BoBrhoV)
2476       
2477****************************************************************************/
2478void set_Wiggler_BoBrho(const int Fnum, const int Knum, const double BoBrhoV)
2479{
2480  Cell[Elem_GetPos(Fnum, Knum)].Elem.W->BoBrhoV[0] = BoBrhoV;
2481  Cell[Elem_GetPos(Fnum, Knum)].Elem.W->PBW[HOMmax+Quad] = -sqr(BoBrhoV)/2.0;
2482  Wiggler_SetPB(Fnum, Knum, Quad);
2483}
2484
2485/****************************************************************************/
2486/* void set_Wiggler_BoBrho(const int Fnum, const double BoBrhoV)
2487
2488   Purpose:
2489       Set the integrated field strength for the family of wiggers       
2490
2491   Input:
2492       Fnum     family name
2493       BoBrhoV  integrated field strength
2494
2495   Output:
2496      none
2497
2498   Return:
2499       none
2500
2501   Global variables:
2502       none
2503
2504   Specific functions:
2505       none
2506
2507   Comments:
2508       none
2509       
2510****************************************************************************/
2511void set_Wiggler_BoBrho(const int Fnum, const double BoBrhoV)
2512{
2513  int  k;
2514
2515  for (k = 1; k <= GetnKid(Fnum); k++)
2516    set_Wiggler_BoBrho(Fnum, k, BoBrhoV);
2517}
2518
2519/****************************************************************************/
2520/* void set_ID_scl(const int Fnum, const int Knum, const double scl)
2521
2522   Purpose:
2523       Set the scale factor for the spicified element of wigger, insertion devices,
2524       or fieldMap.
2525       Called by set_ID_scl(const int Fnum, const double scl).       
2526
2527   Input:
2528       Fnum  family name
2529       Knum  kid index of Fname
2530       scl   scaling factor
2531
2532   Output:
2533      none
2534
2535   Return:
2536       none
2537
2538   Global variables:
2539       none
2540
2541   Specific functions:
2542       none
2543
2544   Comments:
2545       none
2546       
2547****************************************************************************/
2548void set_ID_scl(const int Fnum, const int Knum, const double scl)
2549{
2550  int           k;
2551  WigglerType*  W;
2552
2553  switch (Cell[Elem_GetPos(Fnum, Knum)].Elem.Pkind) {
2554  case Wigl:
2555    // scale the ID field
2556    W = Cell[Elem_GetPos(Fnum, Knum)].Elem.W;
2557    for (k = 0; k < W->n_harm; k++) {
2558      W->BoBrhoH[k] = scl*ElemFam[Fnum-1].ElemF.W->BoBrhoH[k];
2559      W->BoBrhoV[k] = scl*ElemFam[Fnum-1].ElemF.W->BoBrhoV[k];
2560    }
2561    break;
2562  case Insertion:
2563    Cell[Elem_GetPos(Fnum, Knum)].Elem.ID->scaling1 = scl;
2564    Cell[Elem_GetPos(Fnum, Knum)].Elem.ID->scaling2 = scl;
2565    break;
2566  case FieldMap:
2567    Cell[Elem_GetPos(Fnum, Knum)].Elem.FM->scl = scl;
2568    break;
2569  default:
2570    cout << "set_ID_scl: unknown element type" << endl;
2571    exit_(1);
2572    break;
2573  }
2574}
2575
2576/****************************************************************************/
2577/* void set_ID_scl(const int Fnum, const double scl)
2578
2579   Purpose:
2580       Set the scale factor for the specified wigger, insertion devices, or fieldMap.       
2581
2582   Input:
2583       Fnum  family name
2584       scl   scaling factor
2585
2586   Output:
2587      none
2588
2589   Return:
2590       none
2591
2592   Global variables:
2593       none
2594
2595   Specific functions:
2596       none
2597
2598   Comments:
2599       none
2600       
2601****************************************************************************/
2602void set_ID_scl(const int Fnum, const double scl)
2603{
2604  int  k;
2605
2606  for (k = 1; k <= GetnKid(Fnum); k++)
2607    set_ID_scl(Fnum, k, scl);
2608}
2609
2610/***********************************************************************
2611void SetFieldValues_fam(const int Fnum, const bool rms, const double r0,
2612                        const int n, const double Bn, const double An,
2613                        const bool new_rnd)
2614                         
2615   Purpose:
2616       Set field error to all the kids in a family
2617   
2618   Input:
2619      Fnum            family name
2620      rms             flag to set rms field error
2621      r0              radius at which error is measured
2622      n               order of the error
2623      Bn              integrated B component for the n-th error
2624      An              integrated A component for the n-th error
2625      new_rnd         bool flag to set new random number           
2626
2627     
2628   Output:
2629      None
2630     
2631  Return:
2632      None
2633     
2634  Global variables
2635      None
2636   
2637  Specific functions:
2638     None   
2639     
2640 Comments:
2641     None
2642**********************************************************************/
2643void SetFieldValues_fam(const int Fnum, const bool rms, const double r0,
2644                        const int n, const double Bn, const double An,
2645                        const bool new_rnd)
2646{
2647  int     N;
2648  double  bnr, anr;
2649
2650  N = Cell[Elem_GetPos(Fnum, 1)].Elem.M->n_design;
2651  if (r0 == 0.0) {
2652    // input is: (b_n L), (a_n L)
2653    if(rms)
2654      set_bnL_rms_fam(Fnum, n, Bn, An, new_rnd);
2655    else
2656      set_bnL_sys_fam(Fnum, n, Bn, An);
2657  } else {
2658    bnr = Bn/pow(r0, n-N); anr = An/pow(r0, n-N);
2659    if(rms)
2660      set_bnr_rms_fam(Fnum, n, bnr, anr, new_rnd);
2661    else
2662      set_bnr_sys_fam(Fnum, n, bnr, anr);
2663  }
2664}
2665
2666
2667/***********************************************************************
2668void SetFieldValues_type(const int N, const bool rms, const double r0,
2669                         const int n, const double Bn, const double An,
2670                         const bool new_rnd)
2671                         
2672   Purpose:
2673       Set field error to the type
2674   
2675   Input:
2676      N            type name
2677      rms          flag to set rms field error
2678      r0           radius at which error is measured
2679      n            order of the error
2680      Bn           integrated B component for the n-th error
2681      An           integrated A component for the n-th error
2682      new_rnd      bool flag to set new random number       
2683
2684     
2685   Output:
2686      None
2687     
2688  Return:
2689      None
2690     
2691  Global variables
2692      None
2693   
2694  Specific functions:
2695     None   
2696     
2697 Comments:
2698     None
2699**********************************************************************/
2700void SetFieldValues_type(const int N, const bool rms, const double r0,
2701                         const int n, const double Bn, const double An,
2702                         const bool new_rnd)
2703{
2704  double  bnr, anr;
2705
2706  if (r0 == 0.0) {
2707    // input is: (b_n L), (a_n L)
2708    if(rms)
2709      set_bnL_rms_type(N, n, Bn, An, new_rnd);
2710    else
2711      set_bnL_sys_type(N, n, Bn, An);
2712  } else {
2713    bnr = Bn/pow(r0, n-N); anr = An/pow(r0, n-N);
2714    if(rms)
2715      set_bnr_rms_type(N, n, bnr, anr, new_rnd);
2716    else
2717      set_bnr_sys_type(N, n, bnr, anr);
2718  }
2719}
2720
2721
2722/***********************************************************************
2723void SetFieldErrors(const char *name, const bool rms, const double r0,
2724                    const int n, const double Bn, const double An,
2725                    const bool new_rnd)
2726                   
2727   Purpose:
2728       Set field error to the type or element
2729   
2730   Input:
2731      name         type name or element name
2732      rms          flag to set rms field error
2733      r0           radius at which error is measured
2734      n            order of the error
2735      Bn           integrated B component for the n-th error
2736      An           integrated A component for the n-th error
2737      new_rnd      flag to set new random number for the error     
2738
2739     
2740   Output:
2741      None
2742     
2743  Return:
2744      None
2745     
2746  Global variables
2747      None
2748   
2749  Specific functions:
2750     None   
2751     
2752 Comments:
2753       10/2010   Comments by Jianfeng Zhang
2754**********************************************************************/
2755void SetFieldErrors(const char *name, const bool rms, const double r0,
2756                    const int n, const double Bn, const double An,
2757                    const bool new_rnd) 
2758{
2759  int     Fnum;
2760
2761  if (strcmp("all", name) == 0) {
2762    printf("all: not yet implemented\n");
2763  } else if (strcmp("dip", name) == 0) {
2764    SetFieldValues_type(Dip, rms, r0, n, Bn, An, new_rnd);
2765  } else if (strcmp("quad", name) == 0) {
2766    SetFieldValues_type(Quad, rms, r0, n, Bn, An, new_rnd);
2767  } else if (strcmp("sext", name) == 0) {
2768    SetFieldValues_type(Sext, rms, r0, n, Bn, An, new_rnd);
2769  } else {
2770    Fnum = ElemIndex(name);
2771    if(Fnum > 0)
2772      SetFieldValues_fam(Fnum, rms, r0, n, Bn, An, new_rnd);
2773    else 
2774      printf("SetFieldErrors: undefined element %s\n", name);
2775  }
2776}
2777
2778
2779
2780/********************************************************************
2781char* get_prm(void)
2782
2783    Purpose:
2784        Find the stoke talbe symbol "\t" in the string, and
2785        then saved and return the position of the pointer.
2786     
2787    symbol for end of the line:
2788        \n   
2789    Comments:
2790       10/2010  By Jianfeng Zhang
2791        Fix the bug for reading the end of line symbol "\n" , "\r",'\r\n'
2792        at different operation system
2793*********************************************************************/
2794char* get_prm(void)
2795{
2796  char  *prm;
2797
2798  prm = strtok(NULL, " \t");
2799
2800  //if ((prm == NULL) || (strcmp(prm, "\r\n") == 0)) {
2801  if ((prm == NULL) || (strcmp(prm, "\n") == 0)|| (strcmp(prm, "\r") == 0)|| (strcmp(prm, "\r\n") == 0)) {
2802    printf("get_prm: incorrect format\n");
2803    exit_(1);
2804  }
2805
2806  return prm;
2807}
2808
2809/**************************************************************************
2810 * void LoadFieldErr(const char *FieldErrorFile, const bool Scale_it,
2811                  const double Scale, const bool new_rnd)
2812 *
2813 *
2814 *
2815 **************************************************************************/
2816void LoadFieldErr(const char *FieldErrorFile, const bool Scale_it,
2817                  const double Scale, const bool new_rnd) 
2818{ 
2819  bool    rms, set_rnd;
2820  char    line[max_str], name[max_str], type[max_str], *prm;
2821  int     k, n, seed_val;
2822  double  Bn, An, r0;
2823  FILE    *inf;
2824
2825  const bool  prt = true;
2826
2827  inf = file_read(FieldErrorFile);
2828
2829  set_rnd = false; 
2830  printf("\n");
2831  while (fgets(line, max_str, inf) != NULL) {
2832    if (strstr(line, "#") == NULL) {
2833      // check for whether to set new seed
2834      sscanf(line, "%s", name); 
2835      if (strcmp("seed", name) == 0) {
2836        set_rnd = true;
2837        sscanf(line, "%*s %d", &seed_val); 
2838//      printf("setting random seed to %d\n", seed_val);
2839//      iniranf(seed_val);
2840        printf("\n");
2841        printf("setting new random numbers (%d)\n", seed_val);
2842      } else {
2843        sscanf(line, "%*s %s %lf", type, &r0);
2844        printf("%-4s %3s %7.1le", name, type, r0);
2845        rms = (strcmp("rms", type) == 0)? true : false;
2846        if (rms && !set_rnd) {
2847          printf("LoadFieldErr: seed not defined\n");
2848          exit_(1);
2849        }
2850        // skip first three parameters
2851        strtok(line, " \t");
2852        for (k = 1; k <= 2; k++)
2853          strtok(NULL, " \t");
2854        while (((prm = strtok(NULL, " \t")) != NULL) &&
2855               (strcmp(prm, "\r\n") != 0)) {
2856          sscanf(prm, "%d", &n);
2857          prm = get_prm();
2858          sscanf(prm, "%lf", &Bn);
2859          prm = get_prm(); 
2860          sscanf(prm, "%lf", &An);
2861          if (Scale_it)
2862            {Bn *= Scale; An *= Scale;}
2863          if (prt)
2864            printf(" %2d %9.1e %9.1e\n", n, Bn, An);
2865          // convert to normalized multipole components
2866          SetFieldErrors(name, rms, r0, n, Bn, An, true);
2867        }
2868      }
2869    } else
2870      printf("%s", line);
2871  }
2872
2873  fclose(inf);
2874}
2875
2876
2877// correction algorithms
2878
2879// control of orbit
2880
2881// closed orbit correction by n_orbit iterations
2882bool CorrectCOD(int n_orbit)
2883{
2884  bool      cod;
2885  int       i;
2886  long int  lastpos;
2887  Vector2   mean, sigma, max;
2888
2889  cod = getcod(0.0, lastpos);
2890  if (cod) {
2891    codstat(mean, sigma, max, globval.Cell_nLoc, false); // get orbit stats
2892    printf("\n");
2893    printf("Initial RMS orbit (BPMs):   x = %7.1e mm, y = %7.1e mm\n",
2894           1e3*sigma[X_], 1e3*sigma[Y_]);
2895    codstat(mean, sigma, max, globval.Cell_nLoc, true);
2896    printf("Initial RMS orbit (all):    x = %7.1e mm, y = %7.1e mm\n",
2897           1e3*sigma[X_], 1e3*sigma[Y_]);
2898
2899    for (i = 0; i < n_orbit; i++){
2900      lsoc(1, globval.bpm, globval.hcorr, 1); // correct horizontal orbit
2901      lsoc(1, globval.bpm, globval.vcorr, 2); // correct vertical orbit
2902      cod = getcod(0.0, lastpos);             // find closed orbit
2903      if (!cod) break;
2904    }
2905
2906    if (cod) {
2907      codstat(mean, sigma, max, globval.Cell_nLoc, false);
2908      printf("Corrected RMS orbit (BPMs): x = %7.1e mm, y = %7.1e mm\n",
2909             1e3*sigma[X_], 1e3*sigma[Y_]);
2910      codstat(mean, sigma, max, globval.Cell_nLoc, true);
2911      printf("Corrected RMS orbit (all):  x = %7.1e mm, y = %7.1e mm\n",
2912             1e3*sigma[X_], 1e3*sigma[Y_]);
2913    }
2914  }
2915
2916  return cod;
2917}
2918
2919
2920void Align_BPMs(const int n)
2921{
2922  // Align BPMs to adjacent multipoles.
2923
2924  bool      aligned;
2925  int       i, j, k;
2926  long int  loc;
2927
2928  const int  n_step = 5;
2929
2930  printf("\n");
2931  for (i = 1; i <= GetnKid(globval.bpm); i++) {
2932    loc = Elem_GetPos(globval.bpm, i);
2933
2934    if ((loc == 1) || (loc == globval.Cell_nLoc)) {
2935      printf("Align_BPMs: BPM at entrance or exit of lattice: %ld\n", loc);
2936      exit_(1);
2937    }
2938
2939    j = 1; aligned = false;
2940    do {
2941      if ((Cell[loc-j].Elem.Pkind == Mpole) &&
2942          (Cell[loc-j].Elem.M->n_design == n)) {
2943        for (k = 0; k <= 1; k++)
2944          Cell[loc].Elem.M->PdSsys[k] = Cell[loc-j].dS[k];
2945        printf("aligned BPM no %1d to %s\n", i, Cell[loc-j].Elem.PName);
2946        aligned = true; break;
2947      } else if ((Cell[loc+j].Elem.Pkind == Mpole) &&
2948                 (Cell[loc+j].Elem.M->n_design == n)) {
2949        for (k = 0; k <= 1; k++)
2950          Cell[loc].Elem.M->PdSsys[k] = Cell[loc+j].dS[k];
2951        printf("aligned BPM no %1d to %s\n", i, Cell[loc+j].Elem.PName);
2952        aligned = true; break;
2953      }
2954
2955      j++;
2956    } while (j <= n_step);
2957     
2958    if (aligned)
2959      Mpole_SetdS(globval.bpm, i);
2960    else
2961      printf("Align_BPMs: no multipole adjacent to BPM no %d\n", i);
2962  }
2963}
2964
2965/* *****************************************************
2966 void get_bare()
2967 
2968  Purpose:
2969           store values of the optics function at the sextupoles
2970*/
2971void get_bare()
2972{
2973  long int  j, k;
2974
2975  n_sext = 0;
2976  for (j = 0; j <= globval.Cell_nLoc; j++) {
2977    if ((Cell[j].Elem.Pkind == Mpole) && (Cell[j].Elem.M->n_design >= Sext)) {
2978      n_sext++; sexts[n_sext-1] = j;
2979      for (k = 0; k <= 1; k++) {
2980        beta0_[n_sext-1][k] = Cell[j].Beta[k];
2981        nu0s[n_sext-1][k] = Cell[j].Nu[k];
2982      }
2983    }
2984  }
2985
2986  // beta-functions for normalization
2987  beta_ref[X_] = Cell[globval.Cell_nLoc].Beta[X_];
2988  beta_ref[Y_] = Cell[globval.Cell_nLoc].Beta[Y_];
2989
2990  nu0_[X_] = globval.TotalTune[X_]; nu0_[Y_] = globval.TotalTune[Y_];
2991}
2992
2993
2994void get_dbeta_dnu(double m_dbeta[], double s_dbeta[],
2995                   double m_dnu[], double s_dnu[])
2996{
2997  int       k;
2998  long int  j, ind;
2999  double    dbeta, dnu;
3000
3001  Ring_GetTwiss(false, 0.0);
3002 
3003  for (k = 0; k <= 1; k++) {
3004    m_dbeta[k] = 0.0; s_dbeta[k] = 0.0; m_dnu[k] = 0.0; s_dnu[k] = 0.0;
3005  }
3006 
3007  for (j = 0; j < n_sext; j++) {
3008    ind = sexts[j];
3009    for (k = 0; k <= 1; k++) {
3010      dbeta = (Cell[ind].Beta[k]-beta0_[j][k])/beta0_[j][k];
3011      m_dbeta[k] += dbeta; s_dbeta[k] += sqr(dbeta);
3012      dnu = Cell[ind].Nu[k] - nu0s[j][k];
3013      m_dnu[k] += dnu; s_dnu[k] += sqr(dnu);
3014    }
3015  }
3016
3017  for (k = 0; k <= 1; k++) {
3018    m_dbeta[k] /= n_sext; m_dnu[k] /= n_sext;
3019    s_dbeta[k] = sqrt((s_dbeta[k]-n_sext*sqr(m_dbeta[k]))/(n_sext-1));
3020    s_dnu[k] = sqrt((s_dnu[k]-n_sext*sqr(m_dnu[k]))/(n_sext-1));
3021  }
3022}
3023
3024
3025bool CorrectCOD_N(const char *ae_file, const int n_orbit,
3026                  const int n, const int k)
3027{
3028  bool    cod = false;
3029  int     i;
3030  double  m_dbeta[2], s_dbeta[2], m_dnu[2], s_dnu[2];
3031
3032  // Clear trim setpoints
3033  set_bnL_design_fam(globval.hcorr, Dip, 0.0, 0.0);
3034  set_bnL_design_fam(globval.vcorr, Dip, 0.0, 0.0);
3035
3036  // load misalignments
3037  LoadAlignTol(ae_file, true, 1.0, true, k);
3038  for (i = 1; i <= n; i++) {
3039    // Scale the rms values
3040    LoadAlignTol(ae_file, true, (double)i/(double)n, false, k);
3041   
3042    if (bba) {
3043      // Beam based alignment
3044      Align_BPMs(Quad);
3045    }
3046
3047    cod = CorrectCOD(n_orbit); 
3048   
3049    if (!cod) break;
3050   
3051    get_dbeta_dnu(m_dbeta, s_dbeta, m_dnu, s_dnu);
3052    printf("\n");
3053    printf("RMS dbeta_x/beta_x = %4.2f%%,   dbeta_y/beta_y = %4.2f%%\n",
3054           1e2*s_dbeta[X_], 1e2*s_dbeta[Y_]);
3055    printf("RMS dnu_x          = %7.5f, dnu_y          = %7.5f\n",
3056           s_dnu[X_], s_dnu[Y_]);
3057  }
3058
3059  return cod;
3060}
3061
3062
3063// Control of vertical beam size
3064
3065void FindSQ_SVDmat(double **SkewRespMat, double **U, 
3066                   double **V, double *w, int N_COUPLE, int N_SKEW)
3067{
3068  int i, j;
3069
3070  const double  cut = 1e-10; // cut value for SVD singular values
3071
3072  for (i = 1; i <= N_COUPLE; i++)
3073    for (j = 1; j <= N_SKEW; j++)
3074      U[i][j] = SkewRespMat[i][j];
3075
3076  // prepare matrices for SVD
3077  dsvdcmp(U, N_COUPLE, N_SKEW, w, V);
3078
3079  // zero singular values
3080  printf("\n");
3081  printf("singular values:\n");
3082  printf("\n");
3083  for (i = 1; i <= N_SKEW; i++) {
3084    printf("%11.3e", w[i]);
3085    if (w[i] < cut ) {
3086      w[i] = 0.0;
3087      printf(" (zeroed)");
3088      if (i % 8 == 0) printf("\n");
3089    }
3090  }
3091  if (i % 8 != 0) printf("\n");
3092}
3093
3094
3095void FindMatrix(double **SkewRespMat, const double deta_y_max)
3096{
3097  //  Ring_GetTwiss(true, 0.0) should be called in advance
3098  int       i, j, k;
3099  long int  loc;
3100  double    nuX, nuY, alpha, eta_y_max;
3101  double    *etaSQ;
3102  double    **betaSQ, **nuSQ, **betaBPM, **nuBPM;
3103  double    **betaHC, **nuHC, **betaVC, **nuVC;
3104  FILE      *SkewMatFile, *fp;
3105
3106  const int     Xi = 1, Yi = 2;
3107  const double  pi = M_PI, twopi = 2.0*M_PI;
3108
3109
3110  etaSQ = dvector(1, N_SKEW); betaSQ = dmatrix(1, N_SKEW, 1, 2);
3111  nuSQ = dmatrix(1, N_SKEW, 1, 2);
3112  betaBPM = dmatrix(1, N_BPM, 1, 2); nuBPM = dmatrix(1, N_BPM, 1, 2);
3113  betaHC = dmatrix(1, N_HCOR, 1, 2); nuHC = dmatrix(1, N_HCOR, 1, 2);
3114  betaVC = dmatrix(1, N_VCOR, 1, 2); nuVC = dmatrix(1, N_VCOR, 1, 2);
3115
3116  nuX = globval.TotalTune[X_]; nuY = globval.TotalTune[Y_];
3117
3118  for (i = 1; i <= N_SKEW; i++) {
3119    loc = Elem_GetPos(globval.qt, i);
3120    etaSQ[i] = Cell[loc].Eta[X_];
3121    betaSQ[i][Xi] = Cell[loc].Beta[X_]; betaSQ[i][Yi] = Cell[loc].Beta[Y_];
3122    nuSQ[i][Xi] = Cell[loc].Nu[X_]; nuSQ[i][Yi] = Cell[loc].Nu[Y_];
3123  } // for i=1..N_SKEW
3124
3125  for (i = 1; i <= N_BPM; i++) {
3126    betaBPM[i][Xi] = Cell[bpm_loc[i-1]].Beta[X_];
3127    betaBPM[i][Yi] = Cell[bpm_loc[i-1]].Beta[Y_];
3128    nuBPM[i][Xi] = Cell[bpm_loc[i-1]].Nu[X_];
3129    nuBPM[i][Yi] = Cell[bpm_loc[i-1]].Nu[Y_];
3130  } // for i=1..N_BPM
3131
3132  for (i = 1; i <= N_HCOR; i++) {
3133    betaHC[i][Xi] = Cell[h_corr[i-1]].Beta[X_];
3134    betaHC[i][Yi] = Cell[h_corr[i-1]].Beta[Y_];
3135    nuHC[i][Xi] = Cell[h_corr[i-1]].Nu[X_];
3136    nuHC[i][Yi] = Cell[h_corr[i-1]].Nu[Y_];
3137  } // for i=1..N_HCOR
3138
3139  for (i = 1; i <= N_VCOR; i++) {
3140    betaVC[i][Xi] = Cell[v_corr[i-1]].Beta[X_];
3141    betaVC[i][Yi] = Cell[v_corr[i-1]].Beta[Y_];
3142    nuVC[i][Xi] = Cell[v_corr[i-1]].Nu[X_];
3143    nuVC[i][Yi] = Cell[v_corr[i-1]].Nu[Y_];
3144  } // for i=1..N_VCOR
3145
3146
3147  for (i = 1; i <= N_SKEW; i++) {
3148    // looking for term for vertical dispersion
3149    alpha = etaSQ[i];
3150    // printf("For skew quad %3d kick is %9.2e\n",i,alpha);
3151    for (j = 1; j <= N_BPM; j++) {
3152      SkewRespMat[j][i] = VDweight*0.5*alpha*sqrt(betaSQ[i][Yi]*betaBPM[j][Yi])
3153        *cos(twopi*fabs(nuSQ[i][Yi]-nuBPM[j][Yi])-pi*nuY)/sin(pi*nuY);
3154    } // for (j=1; j<=N_BPM; j++)
3155
3156    // loking for coupling of horizontal trim to vertical BPM
3157    for (k = 1; k <= N_HCOR; k++) {
3158      // find v-kick by i-th skew quad due to the k-th h-trim
3159      alpha = 0.5*sqrt(betaSQ[i][Xi]*betaHC[k][Xi])*
3160        cos(twopi*fabs(nuSQ[i][Xi]-nuHC[k][Xi])-pi*nuX)/sin(pi*nuX);
3161      // find vertical orbit due to the kick
3162      for (j = 1; j <= N_BPM; j++) 
3163        SkewRespMat[N_BPM+(k-1)*N_HCOR+j][i] = 
3164          HVweight*0.5*alpha*sqrt(betaSQ[i][Yi]*betaBPM[j][Yi])*
3165          cos(twopi*fabs(nuSQ[i][Yi]-nuBPM[j][Yi])-pi*nuY)/sin(pi*nuY);
3166    } //for (k=1; k<=N_HCOR; k++)
3167
3168   //loking for coupling of vertical trim to horizontal BPM
3169    for (k = 1; k <= N_VCOR; k++) {
3170      // find h-kick by i-th skew quad due to the k-th v-trim
3171      alpha = 0.5*sqrt(betaSQ[i][Yi]*betaVC[k][Yi])*
3172        cos(twopi*fabs(nuSQ[i][Yi]-nuVC[k][Yi])-pi*nuY)/sin(pi*nuY);
3173      // find horizontal orbit due to the kick
3174      for (j = 1; j <= N_BPM; j++) 
3175        SkewRespMat[N_BPM+N_BPM*N_HCOR+(k-1)*N_VCOR+j][i] = 
3176          VHweight*0.5*alpha*sqrt(betaSQ[i][Xi]*betaBPM[j][Xi])*
3177          cos(twopi*fabs(nuSQ[i][Xi]-nuBPM[j][Xi])-pi*nuX)/sin(pi*nuX);
3178    } //for (k=1; k<=N_VCOR; k++)
3179  } // for i=1..N_SKEW
3180
3181
3182  SkewMatFile = file_write(SkewMatFileName);
3183  for (i = 1; i <= N_SKEW; i++) {
3184    for (j = 1; j <= N_COUPLE; j++) 
3185      fprintf(SkewMatFile, "%9.2e ", SkewRespMat[j][i]);
3186    fprintf(SkewMatFile, "\n");
3187  }
3188  fclose(SkewMatFile);
3189
3190  fp = file_write(deta_y_FileName);
3191  eta_y_max = 0.0;
3192  for (j = 1; j <= N_BPM; j++) {
3193    eta_y[j] = 0.0;
3194    for (i = 1; i <= N_SKEW; i++)
3195      if (i % SQ_per_scell == 0) {
3196        eta_y[j] += 0.5*etaSQ[i]*sqrt(betaSQ[i][Yi]*betaBPM[j][Yi])
3197            *cos(twopi*fabs(nuSQ[i][Yi]-nuBPM[j][Yi])-pi*nuY)/sin(pi*nuY);
3198      }
3199    eta_y_max = max(fabs(eta_y[j]), eta_y_max);
3200  }
3201  for (j = 1; j <= N_BPM; j++)
3202    eta_y[j] /= eta_y_max;
3203
3204  for (j = 1; j <= N_BPM; j++) {
3205    eta_y[j] *= deta_y_max;
3206    fprintf(fp, "%6.3f %10.3e\n", Cell[bpm_loc[j-1]].S, 1e3*eta_y[j]);
3207  }
3208  fclose(fp);
3209
3210  free_dvector(etaSQ, 1, N_SKEW); free_dmatrix(betaSQ, 1, N_SKEW, 1, 2);
3211  free_dmatrix(nuSQ, 1, N_SKEW, 1, 2);
3212  free_dmatrix(betaBPM, 1, N_BPM, 1, 2); free_dmatrix(nuBPM, 1, N_BPM, 1, 2);
3213  free_dmatrix(betaHC, 1, N_HCOR, 1, 2); free_dmatrix(nuHC, 1, N_HCOR, 1, 2);
3214  free_dmatrix(betaVC, 1, N_VCOR, 1, 2); free_dmatrix(nuVC, 1, N_VCOR, 1, 2);
3215} // FindMatrix
3216
3217
3218void ini_skew_cor(const double deta_y_max)
3219{
3220  int  k;
3221
3222  // No of skew quads, BPMs, and correctors
3223  N_SKEW = GetnKid(globval.qt);
3224
3225  N_BPM = 0;
3226  for (k = 1; k <= GetnKid(globval.bpm); k++) {
3227    N_BPM++;
3228
3229    if (N_BPM > max_bpm) {
3230      printf("ini_skew_cor: max no of BPMs exceeded %d (%d)\n",
3231             N_BPM, max_bpm);
3232      exit_(1);
3233    }
3234
3235    bpm_loc[N_BPM-1] = Elem_GetPos(globval.bpm, k);
3236  }
3237
3238  N_HCOR = 0;
3239  h_corr[N_HCOR++] = Elem_GetPos(globval.hcorr, 1);
3240  h_corr[N_HCOR++] = Elem_GetPos(globval.hcorr, GetnKid(globval.hcorr)/3);
3241  h_corr[N_HCOR++] = Elem_GetPos(globval.hcorr, 2*GetnKid(globval.hcorr)/3);
3242
3243  N_VCOR = 0;
3244  v_corr[N_VCOR++] = Elem_GetPos(globval.vcorr, 1);
3245  v_corr[N_VCOR++] = Elem_GetPos(globval.vcorr, GetnKid(globval.vcorr)/3);
3246  v_corr[N_VCOR++] = Elem_GetPos(globval.vcorr, 2*GetnKid(globval.vcorr)/3);
3247
3248  N_COUPLE = N_BPM*(1+N_HCOR+N_VCOR);
3249
3250  SkewRespMat = dmatrix(1, N_COUPLE, 1, N_SKEW);
3251  VertCouple = dvector(1, N_COUPLE);
3252  SkewStrengthCorr = dvector(1, N_SKEW);
3253  b = dvector(1, N_COUPLE); w = dvector(1, N_SKEW);
3254  V = dmatrix(1, N_SKEW, 1, N_SKEW); U = dmatrix(1, N_COUPLE, 1, N_SKEW);
3255  eta_y = dvector(1, N_BPM);
3256
3257  printf("\n");
3258  printf("Number of trims:                   horizontal = %d, vertical = %d\n",
3259         N_HCOR, N_VCOR);
3260  printf("Number of BPMs:                    %6d\n", N_BPM);
3261  printf("Number of skew quads:              %6d\n", N_SKEW);
3262  printf("Number of elements in skew vector: %6d\n", N_COUPLE);
3263
3264  // find matrix
3265  Ring_GetTwiss(true, 0.0);
3266
3267  printf("\n");
3268  printf("Looking for response matrix\n");   
3269  FindMatrix(SkewRespMat, deta_y_max);
3270
3271  printf("Looking for SVD matrices\n"); 
3272  FindSQ_SVDmat(SkewRespMat, U, V, w, N_COUPLE, N_SKEW);
3273}
3274
3275
3276void FindCoupVector(double *VertCouple)
3277{
3278  bool      cod;
3279  long      i,j;
3280  long      lastpos;
3281  double    *orbitP, *orbitN;
3282
3283  orbitP = dvector(1, N_BPM); orbitN = dvector(1, N_BPM);
3284
3285  // Find vertical dispersion
3286  Cell_Geteta(0, globval.Cell_nLoc, true, 0e0);
3287
3288  for (i = 1; i <= N_BPM; i++)
3289    VertCouple[i] = VDweight*Cell[bpm_loc[i-1]].Eta[Y_];
3290  // Finished finding vertical dispersion
3291
3292  // Find off diagonal terms for horizontal trims
3293  for (j = 1; j <= N_HCOR; j++) {
3294    // positive kick: "+Dip" for horizontal
3295    SetdKLpar(Cell[h_corr[j-1]].Fnum, Cell[h_corr[j-1]].Knum, +Dip, kick);
3296    cod = getcod(0.0, lastpos); chk_cod(cod, "FindCoupVector");
3297    for (i = 1; i <= N_BPM; i++)
3298      orbitP[i] = Cell[bpm_loc[i-1]].BeamPos[y_];
3299
3300    //negative kick: "+Dip" for horizontal
3301    SetdKLpar(Cell[h_corr[j-1]].Fnum, Cell[h_corr[j-1]].Knum, +Dip, -2*kick);
3302    cod = getcod(0.0, lastpos); chk_cod(cod, "FindCoupVector");
3303    for (i = 1; i <= N_BPM; i++)
3304      orbitN[i] = Cell[bpm_loc[i-1]].BeamPos[y_];
3305
3306    // restore trim valueL: "+Dip" for horizontal
3307    SetdKLpar(Cell[h_corr[j-1]].Fnum, Cell[h_corr[j-1]].Knum, +Dip, kick);
3308
3309    for (i = 1; i <= N_BPM; i++)
3310      VertCouple[N_BPM+(j-1)*N_HCOR+i] = 
3311        HVweight*(orbitN[i]-orbitP[i])*0.5/kick; // sign reversal
3312  } // hcorr cycle
3313
3314
3315  // Find off diagonal terms for vertical trims
3316  for (j = 1; j <= N_VCOR; j++){
3317    // positive kick: "-Dip" for vertical
3318    SetdKLpar(Cell[v_corr[j-1]].Fnum, Cell[v_corr[j-1]].Knum, -Dip, kick);
3319    cod = getcod(0.0, lastpos); chk_cod(cod, "FindCoupVector");
3320    for (i = 1;  i <= N_BPM; i++)
3321      orbitP[i] = Cell[bpm_loc[i-1]].BeamPos[x_];
3322
3323    // negative kick: "-Dip" for vertical
3324    SetdKLpar(Cell[v_corr[j-1]].Fnum, Cell[v_corr[j-1]].Knum, -Dip, -2*kick);
3325    cod = getcod(0.0, lastpos); chk_cod(cod, "FindCoupVector");
3326    for (i = 1; i <= N_BPM; i++)
3327      orbitN[i] = Cell[bpm_loc[i-1]].BeamPos[x_];
3328
3329    // restore corrector: "-Dip" for vertical
3330    SetdKLpar(Cell[v_corr[j-1]].Fnum, Cell[v_corr[j-1]].Knum, -Dip, kick);
3331
3332    for (i = 1; i <= N_BPM; i++) 
3333      VertCouple[N_BPM+N_BPM*N_HCOR+(j-1)*N_VCOR+i] = 
3334        VHweight*(orbitP[i]-orbitN[i])*0.5/kick;
3335  } // vcorr cycle
3336
3337  free_dvector(orbitP, 1, N_BPM); free_dvector(orbitN, 1, N_BPM);
3338} // FindCoupVector
3339
3340
3341void SkewStat(double VertCouple[])
3342{
3343  int     i;
3344  double  max, rms, sk;
3345
3346  // statistics for skew quadrupoles
3347  max = 0.0; rms = 0.0;
3348  for(i = 1; i <= N_SKEW; i++) {
3349    sk = GetKLpar(globval.qt, i, -Quad);
3350    if (fabs(sk) > max) max = fabs(sk);
3351    rms += sqr(sk);
3352  }
3353  rms = sqrt(rms/N_SKEW);
3354  printf("Rms skew strength:       %8.2e+/-%8.2e\n", max, rms);
3355
3356  // statistics for vertical dispersion function
3357  max = 0.0; rms = 0.0;
3358  for(i = 1; i <= N_BPM; i++) {
3359    if (fabs(VertCouple[i]) > max) max = fabs(VertCouple[i]/VDweight);
3360    rms += sqr(VertCouple[i]/VDweight);
3361  }
3362  rms = sqrt(rms/N_BPM);
3363  printf("Max vertical dispersion: %8.2e+/-%8.2e mm\n", 1e3*max, 1e3*rms);
3364
3365  // statistics for off diagonal terms of response matrix (trims->bpms)
3366  max = 0.0; rms = 0.0;
3367  for(i = N_BPM+1; i <= N_BPM*(1+N_HCOR); i++) {
3368    if (fabs(VertCouple[i]) > max) max = fabs(VertCouple[i]/HVweight);
3369    rms += sqr(VertCouple[i]/HVweight);
3370  }
3371  rms = sqrt(rms/(N_HCOR*N_BPM));
3372  printf("Max horizontal coupling: %8.2e+/-%8.2e mm/mrad\n", max, rms);
3373
3374  max = 0.0; rms = 0.0;
3375  for(i = N_BPM*(1+N_HCOR)+1; i <= N_COUPLE; i++) {
3376    if (fabs(VertCouple[i]) > max) max = fabs(VertCouple[i]/VHweight);
3377    rms += sqr(VertCouple[i]/VHweight);
3378  }
3379  rms = sqrt(rms/(N_VCOR*N_BPM));
3380  printf("Max vertical coupling:   %8.2e+/-%8.2e mm/mrad\n", max, rms);
3381}
3382
3383
3384void corr_eps_y(void)
3385{
3386  int   i, j;
3387  FILE  *outf;
3388
3389  // Clear skew quad setpoints
3390  set_bnL_design_fam(globval.qt, Quad, 0.0, 0.0);
3391
3392  // Find coupling vector
3393  printf("\n");
3394  printf("Looking for coupling error\n");
3395  FindCoupVector(VertCouple);
3396
3397  //Find and print coupling statistics
3398  printf("\n");
3399  printf("Before correction\n");
3400  SkewStat(VertCouple);
3401
3402  // Coupling Correction
3403  printf("\n");
3404  for (i = 1; i <= n_lin; i++) {
3405    printf("Looking for correction\n");
3406
3407    //Find Correcting Settings to skew quadrupoles
3408    for (j = 1; j <= N_BPM; j++)
3409      b[j] = VDweight*eta_y[j] - VertCouple[j];
3410
3411    for (j = N_BPM+1; j <= N_COUPLE; j++)
3412      b[j] = -VertCouple[j];
3413
3414    dsvbksb(U, w, V, N_COUPLE, N_SKEW, b, SkewStrengthCorr);
3415
3416    printf("Applying correction\n");
3417    // Add correction
3418    for (j = 1; j <= N_SKEW; j++) 
3419      SetdKLpar(globval.qt, j, -Quad, SkewStrengthCorr[j]);
3420
3421    printf("\n");
3422    printf("Looking for coupling error\n");
3423    // Find coupling vector
3424    FindCoupVector(VertCouple);
3425
3426    printf("\n");
3427    printf("After run %d of correction\n", i);
3428    // Find and print coupling statistics
3429    SkewStat(VertCouple);
3430  } // End of coupling Correction
3431
3432  outf = file_write(eta_y_FileName);
3433  for (i = 0; i <= globval.Cell_nLoc; i++)
3434    fprintf(outf, "%4d %7.3f %s %6.3f %10.3e %10.3e\n",
3435            i, Cell[i].S, Cell[i].Elem.PName,
3436            Cell[i].Nu[Y_], 1e3*Cell[i].Eta[Y_], 1e3*Cell[i].Etap[Y_]);
3437  fclose(outf);
3438
3439  FindCoupVector(VertCouple);
3440}
3441
3442
3443/*******************************************************************
3444void get_IDs(void)
3445
3446  Purpose:
3447    Get the ID.
3448 
3449  Input:
3450     none
3451   
3452  Output:
3453    none   
3454 
3455  Comments:
3456    Print out the scaling 2 of Insertion.
3457   
3458********************************************************************/
3459// Control of IDs
3460
3461void get_IDs(void)
3462{
3463  int  k;
3464
3465  printf("\n");
3466  n_ID_Fams = 0;
3467  for (k = 0; k < globval.Elem_nFam; k++)
3468    switch (ElemFam[k].ElemF.Pkind) {
3469    case Wigl:
3470      printf("found ID family:   %s %12.5e\n",
3471             ElemFam[k].ElemF.PName, ElemFam[k].ElemF.W->BoBrhoV[0]);
3472      n_ID_Fams++; ID_Fams[n_ID_Fams-1] = k + 1;
3473      break;
3474    case Insertion:
3475      printf("found ID family:   %s scaling1 = %12.5e,  scaling2 = %12.5e\n",
3476             ElemFam[k].ElemF.PName, ElemFam[k].ElemF.ID->scaling1, ElemFam[k].ElemF.ID->scaling2);
3477      n_ID_Fams++; ID_Fams[n_ID_Fams-1] = k + 1;
3478      break;
3479    case FieldMap:
3480      printf("found ID family:   %s %12.5e\n",
3481             ElemFam[k].ElemF.PName, ElemFam[k].ElemF.FM->scl);
3482      n_ID_Fams++; ID_Fams[n_ID_Fams-1] = k + 1;
3483      break;
3484    default:
3485      break;
3486    }
3487}
3488
3489/****************************************************************************/
3490/* void set_IDs(const double scl)
3491
3492   Purpose:
3493       Set the scale factor for all the wigger, insertion devices, or fieldMap.       
3494
3495   Input:
3496       scl   scaling factor
3497
3498   Output:
3499      none
3500
3501   Return:
3502       none
3503
3504   Global variables:
3505       none
3506
3507   Specific functions:
3508       none
3509
3510   Comments:
3511       See also:
3512                 set_ID_scl(const int Fnum, const double scl)
3513                 set_ID_scl(const int Fnum, const int knum, const double scl)
3514       
3515****************************************************************************/
3516void set_IDs(const double scl)
3517{
3518  int  k;
3519
3520  printf("\n");
3521  for (k = 0; k < n_ID_Fams; k++) {
3522    switch (ElemFam[ID_Fams[k]-1].ElemF.Pkind) {
3523    case Wigl:
3524      printf("setting ID family: %s %12.5e\n",
3525             ElemFam[ID_Fams[k]-1].ElemF.PName,
3526             scl*ElemFam[ID_Fams[k]-1].ElemF.W->BoBrhoV[0]);
3527
3528      set_Wiggler_BoBrho(ID_Fams[k],
3529                         scl*ElemFam[ID_Fams[k]-1].ElemF.W->BoBrhoV[0]);
3530      break;
3531    case Insertion:
3532      printf("setting ID family: %s %12.5e\n",
3533             ElemFam[ID_Fams[k]-1].ElemF.PName, scl);
3534
3535      set_ID_scl(ID_Fams[k], scl);
3536      break;
3537    case FieldMap:
3538      printf("setting ID family: %s %12.5e\n",
3539             ElemFam[ID_Fams[k]-1].ElemF.PName, scl);
3540
3541      set_ID_scl(ID_Fams[k], scl);
3542      break;
3543    default:
3544      cout << "set_IDs: unknown element type" << endl;
3545      exit_(1);
3546      break;
3547    }
3548  }
3549}
3550
3551
3552void reset_quads(void)
3553{
3554  int       k;
3555
3556  if (N_Fam > N_Fam_max) {
3557    printf("reset_quads: N_Fam > N_Fam_max: %d (%d)\n", N_Fam, N_Fam_max);
3558    exit_(0);
3559  }
3560
3561  for (k = 0; k < N_Fam; k++) {
3562    // Note, actual values can differ from the original values
3563/*    printf("setting quad family: %s %12.5e\n",
3564           ElemFam[Q_Fam[k]-1].ElemF.PName,
3565           ElemFam[Q_Fam[k]-1].ElemF.M->PBpar[HOMmax+Quad]);
3566
3567    set_bn_design_fam(Q_Fam[k], Quad,
3568                       ElemFam[Q_Fam[k]-1].ElemF.M->PBpar[HOMmax+Quad], 0.0);*/
3569
3570    printf("setting quad family: %s %12.5e\n",
3571           ElemFam[Q_Fam[k]-1].ElemF.PName, b2[k]);
3572
3573    set_bn_design_fam(Q_Fam[k], Quad, b2[k], 0.0);
3574  }
3575}
3576
3577
3578void SVD(const int m, const int n, double **M, double beta_nu[],
3579         double b2Ls_[], const double s_cut, const bool first)
3580{
3581  int     i, j;
3582
3583  const bool    prt   = true;
3584
3585  if (first) {
3586    for (i = 1; i <= m; i++)
3587      for (j = 1; j <= n; j++)
3588        U1[i][j] = M[i][j];
3589
3590    dsvdcmp(U1, m, n, w1, V1);
3591
3592    if (prt) { 
3593      printf("\n");
3594      printf("singular values:\n");
3595      printf("\n");
3596    }
3597
3598    for (i = 1; i <= n; i++) {
3599      if (prt) printf("%11.3e", w1[i]);
3600      if (w1[i] < s_cut) {
3601        w1[i] = 0.0;
3602        if (prt) printf(" (zeroed)");
3603      }
3604      if (prt) if (i % 8 == 0) printf("\n");
3605    }
3606    if (prt) if (n % 8 != 0) printf("\n");
3607  }
3608 
3609  dsvbksb(U1, w1, V1, m, n, beta_nu, b2Ls_);
3610}
3611
3612
3613void quad_config()
3614{
3615  int     i, j;
3616  double  an;
3617
3618  if (N_Fam > N_Fam_max) {
3619    printf("quad_config: N_Fam > N_Fam_max: %d (%d)\n", N_Fam, N_Fam_max);
3620    exit_(0);
3621  }
3622
3623  Nquad = 0;
3624  for (i = 0; i < N_Fam; i++) {
3625    for (j = 1; j <= GetnKid(Q_Fam[i]); j++) {
3626      Nquad++;
3627
3628      if (Nquad > n_b2_max) {
3629        printf("quad_config: max no of quadrupoles exceeded %d (%d)\n",
3630               Nquad, n_b2_max);
3631        exit_(1);
3632      }
3633
3634      quad_prms[Nquad-1] = Elem_GetPos(Q_Fam[i], j);
3635
3636      if (j == 1) get_bn_design_elem(Q_Fam[i], j, Quad, b2[i], an);
3637    }
3638  }
3639
3640  printf("\n");
3641  printf("quad_config: Nquad = %d\n", Nquad);
3642}
3643
3644
3645bool get_SQ(void)
3646{
3647  int      j, k;
3648  Vector2  alpha3[3], beta3[3], nu3[3], eta3[3], etap3[3];
3649  FILE     *outf;
3650
3651  const bool  prt = false;
3652 
3653  /* Note, IDs are split for evaluation of the driving terms at the center:
3654       id1  1, 2
3655       id2  1, 2
3656       ...                                                                  */
3657
3658  // Get Twiss params, no dispersion
3659  Ring_GetTwiss(false, 0.0);
3660
3661  if (!status.codflag || !globval.stable) return false;
3662
3663  // Get global tunes
3664  Nu_X = globval.TotalTune[X_]; Nu_Y = globval.TotalTune[Y_];
3665
3666  if (prt) {
3667    printf("\n");
3668    printf("nu_x = %8.12f, nu_y = %8.12f\n", Nu_X, Nu_Y);
3669
3670    // Get Twiss params in sext
3671    printf("\n");
3672    printf("listing lattice functions at sextupoles\n");
3673    printf("\n");
3674
3675    outf = file_write("latfunS.out");
3676
3677    fprintf(outf, "s betax nux betay nuy\n");
3678  }
3679
3680  printf("\n");
3681  Nsext = 0;
3682  for (k = 0; k < globval.Cell_nLoc; k++) {
3683    if ((Cell[k].Elem.Pkind == Mpole) && (Cell[k].Elem.M->n_design == Sext)) {
3684      Nsext++;
3685
3686      if (Nsext > n_b3_max) {
3687        printf("get_SQ: max no of sextupoles exceeded %d (%d)\n",
3688               Nsext, n_b3_max);
3689        exit_(1);
3690      }
3691
3692      Ss[Nsext-1] = Cell[k].S;
3693
3694      for (j = 0; j <= 1; j++) {
3695        sb[j][Nsext-1] = Cell[k].Beta[j];
3696        sNu[j][Nsext-1] = Cell[k].Nu[j] - nu_0[j];
3697      }
3698
3699      if (prt) {
3700        printf("%s %6.3f %8.5f %8.5f %8.5f %8.5f\n",
3701               Cell[k].Elem.PName, Ss[Nsext-1],
3702               sb[X_][Nsext-1], sNu[X_][Nsext-1]-nu_0[X_],
3703               sb[Y_][Nsext-1], sNu[Y_][Nsext-1]-nu_0[Y_]);
3704        fprintf(outf, "%s %6.3f %8.5f %8.5f %8.5f %8.5f\n",
3705                Cell[k].Elem.PName, Ss[Nsext-1],
3706                sb[X_][Nsext-1], sNu[X_][Nsext-1]-nu_0[X_],
3707                sb[Y_][Nsext-1], sNu[Y_][Nsext-1]-nu_0[Y_]);
3708      }
3709    }
3710  }
3711
3712  if (prt) fclose(outf);
3713
3714  // Number of sexts in the ring
3715  printf("No of sextupoles = %d\n", Nsext);
3716
3717  if (prt) {
3718    // Get Twiss params in quads
3719    printf("\n");
3720    printf("listing lattice functions at quadrupoles\n");
3721    printf("\n");
3722
3723    outf = file_write("latfunQ.out");
3724
3725    fprintf(outf, "s name betax nux betay nuy\n");
3726  }
3727
3728  for (k = 0; k < Nquad; k++) {
3729    Sq[k] = Cell[quad_prms[k]].S;
3730    for (j = 0; j <= 1; j++) {
3731      if (Cell[quad_prms[k]].Elem.M->Pthick == thick) {
3732        get_twiss3(quad_prms[k], alpha3, beta3, nu3, eta3, etap3);
3733        qb[j][k] = beta3[Y_][j]; qNu[j][k] = nu3[Y_][j] - nu_0[j];
3734      } else {
3735        qb[j][k] = Cell[quad_prms[k]].Beta[j];
3736        qNu[j][k] = Cell[quad_prms[k]].Nu[j] - nu_0[j];
3737      }
3738    }
3739
3740    if (prt) {
3741      printf("%s %6.3f %8.5f %8.5f %8.5f %8.5f\n",
3742             Cell[quad_prms[k]].Elem.PName, Sq[k], qb[X_][k],
3743             qNu[X_][k], qb[Y_][k], qNu[Y_][k]);
3744
3745      fprintf(outf, "%s %6.3f %8.5f %8.5f %8.5f %8.5f\n",
3746              Cell[quad_prms[k]].Elem.PName, Sq[k], qb[X_][k],
3747              qNu[X_][k], qb[Y_][k], qNu[Y_][k]);
3748    }
3749  }
3750
3751  if (prt) fclose(outf);
3752
3753  // Number of quads in the ring
3754  printf("No of quads      = %d\n", Nquad);
3755
3756  return true;
3757}
3758
3759
3760double Bet(double bq, double nus, double nuq, double NuQ)
3761{
3762  return bq*cos(2.0*M_PI*(2.0*fabs(nus-nuq)-NuQ))/(2.0*sin(2.0*M_PI*NuQ));
3763}
3764
3765
3766double Nus(double bq, double nus, double nuq, double NuQ)
3767{
3768  double  Nu, sgn;
3769
3770  sgn = ((nus-nuq) <= 0)? -1: 1;
3771
3772  Nu = -bq*sgn*(sin(2.0*M_PI*NuQ)+sin(2.0*M_PI*(2.0*fabs(nus-nuq)-NuQ)))
3773       /(8.0*M_PI*sin(2.0*M_PI*NuQ));
3774
3775  return Nu;
3776}
3777
3778/*****************************************************************
3779void A_matrix(void)
3780
3781Purpose:
3782    solove A in the matrix  b = A.x
3783    using SVD.
3784    Used for ID correction.
3785
3786    Comments:
3787      change scl_dbeta  to  scl_dbetax  and scl_dbetay
3788      change scl_dnu  to  scl_dnux  and scl_dnuy
3789      change scl_nu  to  scl_nux  and scl_nuy
3790 
3791     
3792      See also X_vector ()   
3793******************************************************************/     
3794void A_matrix(void)
3795{
3796  int     k, j;
3797  double  BtX, BtY, NuX, NuY;
3798
3799  const bool  prt = false;
3800
3801  // Defining Twiss in undisturbed quads
3802  for (k = 0; k < Nquad; k++)
3803    for (j = 0; j <= 1; j++) {
3804      qb0[j][k] = qb[j][k]; 
3805      qNu0[j][k] = qNu[j][k];
3806    }
3807 
3808  // Defining Twiss in undisturbed sexts
3809  for (k = 0; k < Nsext; k++)
3810    for (j = 0; j <= 1; j++)
3811      sNu0[j][k] = sNu[j][k];
3812 
3813  // Now creating matrix A in X=A*B2L
3814  for (k = 1; k <= Nsext; k++) {
3815    for (j = 1; j <= Nquad; j++) {
3816      BtX = Bet(qb0[X_][j-1], sNu0[X_][k-1], qNu0[X_][j-1], Nu_X0);
3817      NuX = -Nus(qb0[X_][j-1], sNu0[X_][k-1], qNu0[X_][j-1], Nu_X0);
3818      BtY = -Bet(qb0[Y_][j-1], sNu0[Y_][k-1], qNu0[Y_][j-1], Nu_Y0);
3819      NuY = Nus(qb0[Y_][j-1], sNu0[Y_][k-1], qNu0[Y_][j-1], Nu_Y0);
3820      A1[k][j] = scl_dbetax*BtX;
3821      A1[k+Nsext][j] = scl_dbetay*BtY;
3822      A1[k+2*Nsext][j] = scl_dnux*NuX;
3823      A1[k+3*Nsext][j] = scl_dnuy*NuY;
3824    }
3825  }
3826  // Now adding 2 more constraints for global tunes
3827  for (j = 1; j <= Nquad; j++) {
3828    A1[4*Nsext+1][j] = -scl_nux*qb0[X_][j-1]/(4.0*M_PI);
3829    A1[4*Nsext+2][j] =  scl_nuy*qb0[Y_][j-1]/(4.0*M_PI);
3830  }
3831
3832  if (prt) {
3833    printf("\n");
3834    printf("AA:\n");
3835    printf("\n");
3836    for (k = 1; k <= Nconstr; k++) {
3837      for (j = 1; j <= Nquad; j++)
3838        printf(" %10.3e", A1[k][j]);
3839      printf("\n");
3840    }
3841  }
3842}
3843
3844/****************************************************
3845void X_vector(const bool first)
3846
3847  Purpose:
3848    solove x in the matrix  b = A.x
3849    using SVD.
3850    Used for ID correction.
3851
3852    Comments:
3853      change scl_dbeta  to  scl_dbetax  and scl_dbetay
3854      change scl_dnu  to  scl_dnux  and scl_dnuy
3855      change scl_nu  to  scl_nux  and scl_nuy
3856   
3857      See also: 
3858      void A_matrix(void)
3859*****************************************************/
3860void X_vector(const bool first)
3861{
3862  int  k;
3863
3864  const bool  prt = false;
3865
3866  dnu0[X_] = globval.TotalTune[X_] - Nu_X0;
3867  dnu0[Y_] = globval.TotalTune[Y_] - Nu_Y0;
3868
3869  if (first) {
3870    // Initial fill of X
3871    for (k = 1; k <= Nsext; k++) {
3872      Xsext0[k]         = sb[X_][k-1];  Xsext0[k+Nsext]   = sb[Y_][k-1];
3873      Xsext0[k+2*Nsext] = sNu[X_][k-1]; Xsext0[k+3*Nsext] = sNu[Y_][k-1];
3874    }
3875    Xsext0[4*Nsext+1] = 0.0; Xsext0[4*Nsext+2] = 0.0;
3876  } else { 
3877    // Now substracting from X in X=A*B2L
3878    for (k = 1; k <= Nsext; k++) {
3879      Xsext[k]         = scl_dbetax*(Xsext0[k]-sb[X_][k-1])/sb[X_][k-1];
3880      Xsext[k+Nsext]   = scl_dbetay*(Xsext0[k+Nsext]-sb[Y_][k-1])/sb[Y_][k-1];
3881      Xsext[k+2*Nsext] = scl_dnux*(Xsext0[k+2*Nsext]-sNu[X_][k-1]+dnu0[X_]/2.0);
3882      Xsext[k+3*Nsext] = scl_dnuy*(Xsext0[k+3*Nsext]-sNu[Y_][k-1]+dnu0[Y_]/2.0);
3883    }
3884    Xsext[4*Nsext+1] = scl_nux*(Nu_X0-globval.TotalTune[X_]);
3885    Xsext[4*Nsext+2] = scl_nuy*(Nu_Y0-globval.TotalTune[Y_]);
3886  }
3887
3888  if (prt) {
3889    printf("\n");
3890    printf("X:\n");
3891    printf("\n");
3892    if (first) {
3893      for (k = 1; k <= Nconstr; k++) {
3894        printf(" %10.3e", Xsext0[k]);
3895        if (k % 10 == 0)  printf("\n");
3896      }
3897      if (Nconstr % 10 != 0) printf("\n");
3898    } else {
3899      for (k = 1; k <= Nconstr; k++) {
3900        printf(" %10.3e", Xsext[k]);
3901        if (k % 10 == 0)  printf("\n");
3902      }
3903      if (Nconstr % 10 != 0) printf("\n");
3904    }
3905  }
3906}
3907
3908
3909/*
3910void ini_ID_corr(void)
3911
3912  Purpose:
3913    Initial ID, used for insertion Device correction
3914
3915   
3916*/
3917void ini_ID_corr(void)
3918{
3919
3920  // store ID families
3921  get_IDs();
3922
3923  // zero ID's
3924  set_IDs(0.0);
3925
3926  // Configuring quads (1 --> C means thin quads located in the middle of 1s)
3927  quad_config();
3928
3929  // Configuring quads (1 --> C means thin quads located in the middle of 1s)
3930  // Read Betas and Nus
3931  get_SQ(); 
3932  Nconstr = 4*Nsext + 2;
3933
3934  // Note, allocated vectors and matrices are deallocated in ID_corr
3935  Xsext = dvector(1, Nconstr); Xsext0 = dvector(1, Nconstr);
3936  b2Ls_ = dvector(1, Nquad); A1 = dmatrix(1, Nconstr, 1, Nquad);
3937  U1 = dmatrix(1, Nconstr, 1, Nquad); w1 = dvector(1, Nquad);
3938  V1 = dmatrix(1, Nquad, 1, Nquad);
3939
3940  // shift zero point to center of ID
3941//  nu_0[X_] = Cell[id_loc].Nu[X_]; nu_0[Y_] = Cell[id_loc].Nu[Y_];
3942  nu_0[X_] = 0.0; nu_0[Y_] = 0.0;
3943
3944  // Defining undisturbed tunes
3945  Nu_X0 = globval.TotalTune[X_]; Nu_Y0 = globval.TotalTune[Y_];
3946
3947  // Set-up matrix A in X=A*b2Ls_
3948  A_matrix();
3949
3950  // Now fill the X in X=A*b2Ls_
3951  X_vector(true);
3952}
3953
3954
3955void W_diag(void)
3956{
3957  double    bxf, byf, nxf, nyf, b2Lsum;
3958  int       k;
3959
3960  bxf = 0.0; byf = 0.0; nxf = 0.0; nyf = 0.0;
3961  for (k = 1; k <= Nsext; k++) {
3962    bxf += sqr(Xsext[k]);
3963    byf += sqr(Xsext[k+Nsext]);
3964    nxf += sqr(Xsext[k+2*Nsext]);
3965    nyf += sqr(Xsext[k+3*Nsext]);
3966  }
3967
3968  dnu0[X_] = globval.TotalTune[X_] - Nu_X0;
3969  dnu0[Y_] = globval.TotalTune[Y_] - Nu_Y0;
3970
3971  b2Lsum = 0.0;
3972  for (k = 1; k <= Nquad; k++) 
3973    b2Lsum += sqr(b2Ls_[k]);
3974
3975  printf("\n");
3976  printf("Residuals: beta [%%], dnu : \n");
3977  printf("dbeta_x: %6.2f dbeta_y: %6.2f nu_x: %12.6e nu_y: %12.6e\n",
3978         sqrt(bxf)/Nsext*1e2, sqrt(byf)/Nsext*1e2,
3979         sqrt(nxf)/Nsext, sqrt(nyf)/Nsext);
3980  printf("tune shift: dnu_x = %8.5f, dnu_y = %8.5f\n", dnu0[X_], dnu0[Y_]);
3981  printf("Sum b2Ls_: %12.6e\n", sqrt(b2Lsum)/Nquad);
3982}
3983
3984
3985
3986
3987
3988
3989/*
3990   For ID correction, from Mao-Sen Qiu at Taiwan light source.
3991*/
3992
3993bool ID_corr0(void)
3994{
3995  int     i, j, k;
3996  double  b2, a2;
3997  FILE    *outf;
3998
3999  printf("\n");
4000  printf("Before correction!\n");
4001
4002  set_IDs(1.0);
4003  //set_IDs((double) i);
4004
4005  get_SQ();                               // Read Betas and Nus
4006  X_vector(false);                        // Fill in dX in dX=A*db2Ls_
4007  W_diag();                               // Get statistics
4008
4009  outf = file_write("ID_before_corr.out");
4010  fprintf(outf, "# dbeta_x/beta_x  dbeta_y/beta_y  dnu_x  dnu_y\n");
4011  fprintf(outf, "#      [%%]             [%%]\n");
4012  fprintf(outf, "#\n");
4013  for (k = 1; k <= Nsext; k++)
4014    fprintf(outf, "%6.1f %6.2f %6.2f %10.3e %10.3e\n", Ss[k-1], 1e2*Xsext[k], 1e2*Xsext[k+Nsext], Xsext[k+2*Nsext], Xsext[k+3*Nsext]);
4015  fclose(outf);
4016
4017  // Allow for repeated calls to ID_corr, allocation is done in ini_ID_corr.
4018  if (true) {
4019    free_dvector(Xsext, 1, Nconstr);
4020    free_dvector(Xsext0, 1, Nconstr);
4021    free_dvector(b2Ls_, 1, Nquad); 
4022    free_dmatrix(A1, 1, Nconstr, 1, Nquad);
4023    free_dmatrix(U1, 1, Nconstr, 1, Nquad); 
4024    free_dvector(w1, 1, Nquad);
4025    free_dmatrix(V1, 1, Nquad, 1, Nquad);
4026  }
4027
4028  printf("\n");
4029  printf("End of before correction!\n");
4030
4031  return true;
4032}
4033
4034
4035/******************************************************************
4036bool ID_corr(const int N_calls, const int N_steps)
4037
4038  Purpose:
4039    Compensate the field error introduced by insertion device.
4040 
4041******************************************************************/
4042bool ID_corr(const int N_calls, const int N_steps)
4043{
4044  int     i, j, k;
4045  double  b2, a2;
4046  FILE    *outf;
4047
4048  printf("\n");
4049  printf("ID matching begins!\n");
4050
4051  outf = file_write("ID_corr.out");
4052  for (i = 1; i <= N_steps; i++) { //This brings ID strength in steps
4053    set_IDs((double)i/(double)N_steps);
4054
4055    get_SQ();                               // Read Betas and Nus
4056    X_vector(false);                        // Fill in dX in dX=A*db2Ls_
4057    W_diag();                               // Get statistics
4058    for (j = 1; j <= N_calls; j++) {
4059      SVD(Nconstr, Nquad, A1, Xsext, b2Ls_, 1e0, j == 1);
4060
4061      if ((i == N_steps) && (j == N_calls)) {
4062        fprintf(outf, "b_2:\n");
4063        fprintf(outf, "\n");
4064      }
4065
4066      // add quad strengths (db2Ls_)
4067      for (k = 1; k <= Nquad; k++) {
4068        set_dbnL_design_elem(Cell[quad_prms[k-1]].Fnum,
4069                             Cell[quad_prms[k-1]].Knum, Quad,
4070                             -ID_step*b2Ls_[k], 0.0);
4071
4072        if ((i == N_steps) && (j == N_calls)) {
4073          get_bn_design_elem(Cell[quad_prms[k-1]].Fnum,
4074                             Cell[quad_prms[k-1]].Knum, Quad, b2, a2);
4075          fprintf(outf, "%10s %2d %8.5f\n",
4076                  Cell[quad_prms[k-1]].Elem.PName, k, b2);
4077        }
4078      }
4079
4080      printf("\n");
4081      printf("Iteration: %2d\n", j);
4082      if (get_SQ()) {
4083        X_vector(false);                    // Fill in dX in dX=A*db2Ls_
4084        W_diag();                           // Get statistics
4085
4086        printglob();
4087      } else {
4088        printf("ID_corr: correction failed\n");
4089        // restore lattice
4090        set_IDs(0.0); reset_quads();
4091        return false;
4092      }
4093    }
4094  }
4095  fclose(outf);
4096
4097  outf = file_write("ID_corr_res.out");
4098  fprintf(outf, "# dbeta_x/beta_x  dbeta_y/beta_y  dnu_x  dnu_y\n");
4099  fprintf(outf, "#      [%%]             [%%]\n");
4100  fprintf(outf, "#\n");
4101  for (k = 1; k <= Nsext; k++)
4102    fprintf(outf, "%6.1f %6.2f %6.2f %10.3e %10.3e\n",
4103            Ss[k-1], 1e2*Xsext[k], 1e2*Xsext[k+Nsext],
4104            Xsext[k+2*Nsext], Xsext[k+3*Nsext]);
4105  fclose(outf);
4106
4107  // Allow for repeated calls to ID_corr, allocation is done in ini_ID_corr.
4108  if (false) {
4109    free_dvector(Xsext, 1, Nconstr); free_dvector(Xsext0, 1, Nconstr);
4110    free_dvector(b2Ls_, 1, Nquad); free_dmatrix(A1, 1, Nconstr, 1, Nquad);
4111    free_dmatrix(U1, 1, Nconstr, 1, Nquad); free_dvector(w1, 1, Nquad);
4112    free_dmatrix(V1, 1, Nquad, 1, Nquad);
4113  }
4114
4115  printf("\n");
4116  printf("ID matching ends!\n");
4117
4118  return true;
4119}
4120
4121/*  End ID correction functions *****/
4122
4123
4124void get_param(const char *param_file)
4125/*
4126 * Read parameter file in input file xxxx.prm
4127 *
4128 */
4129{
4130  char    line[max_str], name[max_str], str[max_str], s_prm[max_str];
4131  char    lat_file[max_str], flat_file[max_str], IDCq_name[max_str][8];
4132  int     k;
4133  double  f_prm;
4134  FILE    *inf;
4135
4136  const bool  prt = true;
4137
4138  if (prt) {
4139    printf("\n");
4140    printf("reading in %s\n", param_file);
4141  }
4142
4143  inf = file_read(param_file);
4144
4145  // read parameter file
4146  // initialization
4147  strcpy(ae_file, ""); strcpy(fe_file, ""); strcpy(ap_file, "");
4148
4149  if (prt) printf("\n");
4150  // loop over all lines of the file
4151  while (fgets(line, max_str, inf) != NULL) {
4152    if (prt) printf("%s", line);
4153    if (strstr(line, "#") == NULL) {
4154      // get initial command token
4155      sscanf(line, "%s", name);
4156        // input files *************************************
4157      if (strcmp("in_dir", name) == 0)
4158        sscanf(line, "%*s %s", in_dir);
4159      else if (strcmp("ae_file", name) == 0){ 
4160        sscanf(line, "%*s %s", str);
4161        sprintf(ae_file,"%s/%s", in_dir, str);
4162      } else if (strcmp("fe_file", name) == 0) { 
4163        sscanf(line, "%*s %s", str);
4164        sprintf(fe_file, "%s/%s", in_dir, str);
4165      } else if (strcmp("ap_file", name) == 0) {
4166        sscanf(line, "%*s %s", str);
4167        sprintf(ap_file, "%s/%s", in_dir, str);
4168      } else if (strcmp("lat_file", name) == 0) {
4169        sscanf(line, "%*s %s", lat_file);
4170        sprintf(lat_FileName, "%s/%s", in_dir, lat_file);
4171        Read_Lattice(lat_FileName);
4172      } else if (strcmp("flat_file", name) == 0) {
4173        sscanf(line, "%*s %s", flat_file);
4174        strcat(flat_file, "flat_file.dat"); rdmfile(flat_file);
4175      // **********< parameters >****************************
4176      } else if (strcmp("s_cut", name) == 0) {
4177        sscanf(line, "%*s %lf", &f_prm);
4178        setrancut(f_prm);
4179      } else if (strcmp("n_stat", name) == 0)
4180        sscanf(line, "%*s %d", &n_stat);
4181      else if (strcmp("n_scale", name) == 0)
4182        sscanf(line, "%*s %d", &n_scale);
4183      else if (strcmp("n_orbit", name) == 0)
4184        sscanf(line, "%*s %d", &n_orbit);
4185      else if (strcmp("bpm_name", name) == 0) {
4186        sscanf(line, "%*s %s", s_prm);
4187        globval.bpm = ElemIndex(s_prm);
4188      } else if (strcmp("h_corr", name) == 0) {
4189        sscanf(line, "%*s %s", s_prm);
4190        globval.hcorr = ElemIndex(s_prm);
4191      } else if (strcmp("v_corr", name) == 0) {
4192        sscanf(line, "%*s %s", s_prm);
4193        globval.vcorr = ElemIndex(s_prm);
4194      } else if (strcmp("gs", name) == 0) {
4195        sscanf(line, "%*s %s", s_prm);
4196        globval.gs = ElemIndex(s_prm);
4197      } else if (strcmp("ge", name) == 0) {
4198        sscanf(line, "%*s %s", s_prm);
4199        globval.ge = ElemIndex(s_prm);
4200      } else if (strcmp("DA_bare", name) == 0) {
4201        sscanf(line, "%*s %s", s_prm);
4202        DA_bare = (strcmp(s_prm, "true") == 0)? true : false;
4203      } else if (strcmp("delta", name) == 0) { 
4204        sscanf(line, "%*s %lf", &delta_DA_);
4205      } else if (strcmp("freq_map", name) == 0) {
4206        sscanf(line, "%*s %s %d %d %d %d %lf %lf %lf",
4207               s_prm, &n_x, &n_y, &n_dp, &n_tr,
4208               &x_max_FMA, &y_max_FMA, &delta_FMA);
4209        freq_map = (strcmp(s_prm, "true") == 0)? true : false;
4210      } else if (strcmp("tune_shift", name) == 0) {
4211        sscanf(line, "%*s %s", s_prm);
4212        tune_shift = (strcmp(s_prm, "true") == 0)? true : false;
4213      } else if (strcmp("qt", name) == 0) {
4214        sscanf(line, "%*s %s", s_prm);
4215        globval.qt = ElemIndex(s_prm);
4216      } else if (strcmp("disp_wave_y", name) == 0) 
4217        sscanf(line, "%*s %lf", &disp_wave_y);
4218      else if (strcmp("n_lin", name) == 0)
4219        sscanf(line, "%*s %d", &n_lin);
4220      else if (strcmp("VDweight", name) == 0) 
4221        sscanf(line, "%*s %lf", &VDweight);
4222      else if (strcmp("HVweight", name) == 0) 
4223        sscanf(line, "%*s %lf", &HVweight);
4224      else if (strcmp("VHweight", name) == 0)
4225        sscanf(line, "%*s %lf", &VHweight);
4226      else if (strcmp("N_calls", name) == 0) // ID correction parameters
4227        sscanf(line, "%*s %d", &N_calls);
4228      else if (strcmp("N_steps", name) == 0)
4229        sscanf(line, "%*s %d", &N_steps);
4230      else if (strcmp("N_Fam", name) == 0)
4231        sscanf(line, "%*s %d", &N_Fam);
4232      else if (strcmp("IDCquads", name) == 0) {
4233        sscanf(line, "%*s %s %s %s %s %s %s %s %s",
4234               IDCq_name[0], IDCq_name[1], IDCq_name[2], IDCq_name[3],
4235               IDCq_name[4], IDCq_name[5], IDCq_name[6], IDCq_name[7]);
4236//      } else if (strcmp("scl_nu", name) == 0)
4237//      sscanf(line, "%*s %lf", &scl_nu);
4238      } else {
4239        printf("bad line in %s: %s\n", param_file, line);
4240        exit_(1);
4241      }
4242    } else
4243      printf("%s", line);
4244  }
4245
4246  fclose(inf);
4247
4248  if (N_calls > 0) {
4249    if (N_Fam > N_Fam_max) {
4250      printf("get_param: N_Fam > N_Fam_max: %d (%d)\n",
4251             N_Fam, N_Fam_max);
4252      exit_(0);
4253    }
4254
4255    for (k = 0; k < N_Fam; k++)
4256      Q_Fam[k] = ElemIndex(IDCq_name[k]);
4257  }
4258}
4259
4260
4261// control of vertical beam size
4262
4263// output procedures
4264
4265// Finding statistics on orbit in the sextupoles and maximal trim settings
4266void Orb_and_Trim_Stat(void)
4267{
4268  int     i, j, N;
4269  int     SextCounter = 0;
4270  int     bins[5] = { 0, 0, 0, 0, 0 };
4271  double  bin = 40.0e-6; // bin size for stat
4272  double  tr; // trim strength
4273
4274  Vector2   Sext_max, Sext_sigma, TrimMax, orb;
4275 
4276  Sext_max[X_] = 0.0; Sext_max[Y_] = 0.0; 
4277  Sext_sigma[X_] = 0.0; Sext_sigma[Y_] = 0.0;
4278  TrimMax[X_] = 0.0; TrimMax[Y_] = 0.0;
4279  N = globval.Cell_nLoc; SextCounter = 0;
4280  for (i = 0; i <= N; i++) {
4281    if ((Cell[i].Elem.Pkind == Mpole) && (Cell[i].Elem.M->n_design == Sext)) {
4282      SextCounter++;
4283      orb[X_] = Cell[i].BeamPos[x_]; orb[Y_] = Cell[i].BeamPos[y_];
4284      Sext_sigma[X_] += orb[X_]*orb[X_]; Sext_sigma[Y_] += orb[Y_]*orb[Y_];
4285      if (fabs(orb[X_]) > Sext_max[X_]) Sext_max[X_] = fabs(orb[X_]);
4286      if (fabs(orb[Y_]) > Sext_max[Y_]) Sext_max[Y_] = fabs(orb[Y_]);
4287      j = (int) (sqrt(orb[X_]*orb[X_]+orb[Y_]*orb[Y_])/bin);
4288      if (j > 4) j = 4;
4289      bins[j]++;
4290    } // sextupole handling
4291
4292    if (Cell[i].Fnum == globval.hcorr) {
4293      tr = Cell[i].Elem.M->PBpar[HOMmax+Dip];
4294      if (fabs(tr) > TrimMax[X_]) TrimMax[X_] = fabs(tr);
4295    } // horizontal trim handling
4296    if (Cell[i].Fnum == globval.vcorr) {
4297      tr = Cell[i].Elem.M->PBpar[HOMmax-Dip];
4298      if (fabs(tr) > TrimMax[Y_]) TrimMax[Y_] = fabs(tr);
4299    } // vertical trim handling
4300  } // looking throught the cells
4301
4302  Sext_sigma[X_] = sqrt(Sext_sigma[X_]/SextCounter);
4303  Sext_sigma[Y_] = sqrt(Sext_sigma[Y_]/SextCounter);
4304   
4305  printf("In sextupoles maximal horizontal orbit is:"
4306         " %5.3f mm with sigma %5.3f mm\n",
4307          1e3*Sext_max[X_], 1e3*Sext_sigma[X_]);
4308  printf("and maximal vertical orbit is:            "
4309         " %5.3f mm with sigma %5.3f mm.\n",
4310         1e3*Sext_max[Y_], 1e3*Sext_sigma[Y_]);
4311
4312  for (i = 0; i < 4;  i++) {
4313    printf("There are %3d sextupoles with offset between ", bins[i]);
4314    printf(" %5.3f mm and %5.3f mm\n", i*bin*1e3, (i+1)*bin*1e3);
4315  }
4316  printf("There are %3d sextupoles with offset ", bins[4]);
4317  printf("more than %5.3f mm \n", 4e3*bin);
4318  printf("Maximal hcorr is %6.3f mrad, maximal vcorr is %6.3f mrad\n",
4319         1e3*TrimMax[X_], 1e3*TrimMax[Y_]);
4320}
4321
4322
4323void prt_codcor_lat(void)
4324{
4325  int   i;
4326  FILE  *CodCorLatFile;
4327
4328
4329  CodCorLatFile = file_write(CodCorLatFileName);
4330
4331  fprintf(CodCorLatFile, "#    name     s   sqrt(BxBy) betaX    nuX"
4332          "    betaY    nuY     etaX etaX*betaY nuX-nuY \n");
4333  fprintf(CodCorLatFile, "#            [m]     [m]      [m]             [m]"
4334          "              [m]     [m*m] \n");
4335
4336  for (i = 0; i <= globval.Cell_nLoc; i++){
4337    fprintf(CodCorLatFile, "%4d:", i);
4338
4339    if (i == 0)
4340      fprintf(CodCorLatFile, "%.*s", 6, "begin ");
4341    else
4342      fprintf(CodCorLatFile, "%.*s", 6, Cell[i].Elem.PName);
4343
4344    fprintf(CodCorLatFile, "%7.3f  %5.2f    %5.2f  %7.4f  %5.2f  %7.4f"
4345            "  %6.3f  %6.3f  %6.3f\n",
4346            Cell[i].S, sqrt(Cell[i].Beta[X_]*Cell[i].Beta[Y_]), 
4347            Cell[i].Beta[X_], Cell[i].Nu[X_], Cell[i].Beta[Y_], Cell[i].Nu[Y_],
4348            Cell[i].Eta[X_], Cell[i].Eta[X_]*Cell[i].Beta[Y_],
4349            Cell[i].Nu[X_]-Cell[i].Nu[Y_]);
4350  }
4351  fclose(CodCorLatFile);
4352}
4353
4354void prt_beamsizes()
4355{
4356  int   k;
4357  FILE  *fp;
4358
4359  fp = file_write(beam_envelope_file);
4360
4361  fprintf(fp,"# k  s  name s_xx s_pxpx s_xpx s_yy s_pypy s_ypy theta_xy\n");
4362  for(k = 0; k <= globval.Cell_nLoc; k++){
4363    fprintf(fp,"%4d %10s %e %e %e %e %e %e %e %e\n",
4364            k, Cell[k].Elem.PName, Cell[k].S,
4365            Cell[k].sigma[x_][x_], Cell[k].sigma[px_][px_],
4366            Cell[k].sigma[x_][px_],
4367            Cell[k].sigma[y_][y_], Cell[k].sigma[py_][py_],
4368            Cell[k].sigma[y_][py_],
4369            atan2(2e0*Cell[k].sigma[x_][y_],
4370                  Cell[k].sigma[x_][x_]-Cell[k].sigma[y_][y_])/2e0*180.0/M_PI);
4371  }
4372
4373  fclose(fp);
4374}
4375
4376
4377float f_int_Touschek(const float u)
4378{
4379  double  f;
4380
4381  if (u > 0.0)
4382    f = (1.0/u-log(1.0/u)/2.0-1.0)*exp(-u_Touschek/u); 
4383  else
4384    f = 0.0;
4385
4386  return f;
4387} 
4388
4389/****************************************************************************/
4390/* double Touschek(const double Qb, const double delta_RF,
4391                const double eps_x, const double eps_y,
4392                const double sigma_delta, const double sigma_s)
4393
4394   Purpose:
4395       Calculate Touschek lifetime
4396       using the normal theoretical formula
4397       the momentum acceptance is RF acceptance delta_RF
4398     
4399   Parameters:   
4400             Qb  electric charge per bunch
4401       delta_RF  RF momentum acceptance
4402          eps_x  emittance x
4403          eps_y  emittance y
4404    sigma_delta  longitudinal beam size
4405        sigma_s   
4406   
4407   Input:
4408       none
4409               
4410   Output:
4411       
4412
4413   Return:
4414      Touschek lifetime [second]
4415
4416   Global variables:
4417       
4418
4419   Specific functions:
4420     
4421
4422   Comments:
4423       none
4424
4425****************************************************************************/
4426double Touschek(const double Qb, const double delta_RF,
4427                const double eps_x, const double eps_y,
4428                const double sigma_delta, const double sigma_s)
4429{
4430  long int  k;
4431  double    tau, sigma_x, sigma_y, sigma_xp, L, curly_H;
4432
4433  const double  gamma = 1e9*globval.Energy/m_e, N_e = Qb/q_e;
4434
4435  printf("\n");
4436  printf("Qb = %4.2f nC, delta_RF = %4.2f%%"
4437         ", eps_x = %9.3e nm.rad, eps_y = %9.3e nm.rad\n",
4438         1e9*Qb, 1e2*delta_RF, 1e9*eps_x, 1e9*eps_y);
4439  printf("sigma_delta = %8.2e, sigma_s = %4.2f mm\n",
4440         sigma_delta, 1e3*sigma_s);
4441
4442  tau = 0.0;
4443  for(k = 1; k <= globval.Cell_nLoc; k++) {
4444    L = Cell[k].S - Cell[k-1].S;
4445
4446    curly_H = get_curly_H(Cell[k].Alpha[X_], Cell[k].Beta[X_],
4447                          Cell[k].Eta[X_], Cell[k].Etap[X_]);
4448
4449    // compute estimated beam sizes for given
4450    // hor.,  ver. emittance, sigma_s, and sigma_delta (x ~ 0)
4451    sigma_x = sqrt(Cell[k].Beta[X_]*eps_x+sqr(sigma_delta*Cell[k].Eta[X_])); 
4452    sigma_y = sqrt(Cell[k].Beta[Y_]*eps_y); 
4453    sigma_xp = (eps_x/sigma_x)*sqrt(1.0+curly_H*sqr(sigma_delta)/eps_x); 
4454
4455    u_Touschek = sqr(delta_RF/(gamma*sigma_xp));
4456
4457    tau += qromb(f_int_Touschek, 0.0, 1.0)/(sigma_x*sigma_y*sigma_xp)*L; 
4458    fflush(stdout);
4459  }
4460
4461  tau *= N_e*sqr(r_e)*c0/(8.0*M_PI*cube(gamma)*sigma_s)
4462         /(sqr(delta_RF)*Cell[globval.Cell_nLoc].S);
4463
4464  printf("\n"); 
4465  printf("Touschek lifetime [hrs]: %10.3e\n", 1.0/(3600.0*tau)); 
4466  return(1.0/(tau));
4467}
4468
4469/****************************************************************************/
4470/* void mom_aper(double &delta, double delta_RF, const long int k,
4471              const int n_turn, const bool positive)
4472
4473
4474   Purpose:
4475      Using Binary search to determine momentum aperture at location k.
4476      If the particle is stable at the last step of tracking, so the
4477      momentum acceptance is RF momentum accpetance.
4478     
4479   Input:
4480           delta       particle energy deviation
4481           delta_RF    RF momentum acceptance
4482           k           element index
4483           n_turn      number of tracking turns 
4484
4485   Output:
4486           none
4487   Return:
4488           delta       searched momentum acceptance
4489
4490   Global variables:
4491         none
4492
4493   specific functions:
4494       Cell_Pass
4495
4496   Comments:
4497       nsls-ii version.
4498       See also:
4499       soleil version MomentumAcceptance( ) in soleillib.cc
4500       
4501****************************************************************************/
4502void mom_aper(double &delta, double delta_RF, const long int k,
4503              const int n_turn, const bool positive)
4504{
4505  // Binary search to determine momentum aperture at location k.
4506  int       j;
4507  long int  lastpos;
4508  double    delta_min, delta_max;
4509  Vector    x;
4510
4511  const double  eps = 1e-4;
4512
4513  delta_min = 0.0; 
4514  delta_max = positive ? fabs(delta_RF) : -fabs(delta_RF);
4515 
4516  while (fabs(delta_max-delta_min) > eps) 
4517  {
4518    delta = (delta_max+delta_min)/2.0; /* binary serach*/
4519   
4520    // propagate initial conditions
4521    CopyVec(6, globval.CODvect, x); Cell_Pass(0, k, x, lastpos); 
4522    // generate Touschek event
4523    x[delta_] += delta;
4524    // complete one turn
4525    Cell_Pass(k, globval.Cell_nLoc, x, lastpos); 
4526   
4527    if (lastpos < globval.Cell_nLoc)
4528      // particle lost
4529      delta_max = delta;
4530    else { 
4531      // track
4532      for(j = 0; j < n_turn; j++) {
4533        Cell_Pass(0, globval.Cell_nLoc, x, lastpos); 
4534
4535        if ((delta_max > delta_RF) || (lastpos < globval.Cell_nLoc)) { 
4536          // particle lost
4537          delta_max = delta; 
4538          break; 
4539        }
4540      }
4541     
4542      if ((delta_max <= delta_RF) && (lastpos == globval.Cell_nLoc))
4543        // particle not lost
4544        delta_min = delta; 
4545    }
4546  } 
4547}
4548
4549/****************************************************************************/
4550/* double Touschek(const double Qb, const double delta_RF,const bool consistent,
4551                const double eps_x, const double eps_y,
4552                const double sigma_delta, double sigma_s,
4553                const int n_turn, const bool aper_on,
4554                double sum_delta[][2], double sum2_delta[][2])
4555
4556   Purpose:
4557        Calculate the Touschek lifetime
4558        using the normal theoretical formula
4559        the momentum acceptance is determined by the RF acceptance delta_RF
4560        and the momentum aperture at each element location
4561        which is tracked over n turns,
4562        the vacuum chamber limitation is read from a outside file 
4563     
4564   Parameters:   
4565             Qb  electric charge per bunch
4566       delta_RF  RF momentum acceptance
4567     consistent
4568          eps_x  emittance x
4569          eps_y  emittance y
4570    sigma_delta  longitudinal beam size
4571        sigma_s
4572         n_turn  number of turns for tracking 
4573        aper_on   must be TRUE
4574                 to indicate vacuum chamber setting is read from a outside file         
4575 sum_delta[][2]
4576sum2_delta[][2]         
4577                 
4578   
4579   Input:
4580       none
4581               
4582   Output:
4583       
4584
4585   Return:
4586       Touschek lifetime [second]
4587
4588   Global variables:
4589       
4590
4591   Specific functions:
4592      mom_aper
4593
4594   Comments:
4595       none
4596
4597****************************************************************************/
4598double Touschek(const double Qb, const double delta_RF,const bool consistent,
4599                const double eps_x, const double eps_y,
4600                const double sigma_delta, double sigma_s,
4601                const int n_turn, const bool aper_on,
4602                double sum_delta[][2], double sum2_delta[][2])
4603{
4604  bool      cav, aper;
4605  long int  k;
4606  double    rate, delta_p, delta_m, curly_H0, curly_H1, L;
4607  double    sigma_x, sigma_y, sigma_xp;
4608
4609  const bool  prt = false;
4610
4611  //  const char  file_name[] = "Touschek.out";
4612  const double  eps = 1e-5, gamma = 1e9*globval.Energy/m_e, N_e = Qb/q_e;
4613
4614  cav = globval.Cavity_on; aper = globval.Aperture_on;
4615
4616  globval.Cavity_on = true;
4617
4618  Ring_GetTwiss(true, 0.0);
4619
4620  globval.Aperture_on = aper_on;
4621
4622  printf("\n");
4623  printf("Qb = %4.2f nC, delta_RF = %4.2f%%"
4624         ", eps_x = %9.3e m.rad, eps_y = %9.3e m.rad\n",
4625         1e9*Qb, 1e2*delta_RF, eps_x, eps_y);
4626  printf("sigma_delta = %8.2e, sigma_s = %4.2f mm\n",
4627         sigma_delta, 1e3*sigma_s);
4628
4629  printf("\n");
4630  printf("Momentum aperture:" );
4631  printf("\n");
4632
4633  delta_p = delta_RF; mom_aper(delta_p, delta_RF, 0, n_turn, true);
4634  delta_m = -delta_RF; mom_aper(delta_m, delta_RF, 0, n_turn, false);
4635  delta_p = min(delta_RF, delta_p); delta_m = max(-delta_RF, delta_m);
4636  sum_delta[0][0] += delta_p; sum_delta[0][1] += delta_m;
4637  sum2_delta[0][0] += sqr(delta_p); sum2_delta[0][1] += sqr(delta_m);
4638 
4639  rate = 0.0; curly_H0 = -1e30;
4640  for (k = 1; k <= globval.Cell_nLoc; k++) {
4641    L = Cell[k].S - Cell[k-1].S;
4642
4643    curly_H1 = get_curly_H(Cell[k].Alpha[X_], Cell[k].Beta[X_],
4644                           Cell[k].Eta[X_], Cell[k].Etap[X_]);
4645
4646    if (fabs(curly_H0-curly_H1) > eps) {
4647      mom_aper(delta_p, delta_RF, k, n_turn, true);
4648      delta_m = -delta_p; mom_aper(delta_m, delta_RF, k, n_turn, false);
4649      delta_p = min(delta_RF, delta_p); delta_m = max(-delta_RF, delta_m);
4650      printf("%4ld %6.2f %3.2lf%% %3.2lf%%\n",
4651             k, Cell[k].S, 1e2*delta_p, 1e2*delta_m);
4652      curly_H0 = curly_H1;
4653    }
4654
4655    sum_delta[k][0] += delta_p; 
4656    sum_delta[k][1] += delta_m;
4657    sum2_delta[k][0] += sqr(delta_p); 
4658    sum2_delta[k][1] += sqr(delta_m);
4659   
4660    if (prt)
4661      printf("%4ld %6.2f %3.2lf %3.2lf\n",
4662             k, Cell[k].S, 1e2*delta_p, 1e2*delta_m);
4663
4664    if (!consistent) {
4665      // compute estimated beam sizes for given
4666      // hor.,  ver. emittance, sigma_s, and sigma_delta (x ~ 0)
4667      sigma_x = sqrt(Cell[k].Beta[X_]*eps_x+sqr(sigma_delta*Cell[k].Eta[X_]));
4668      sigma_y = sqrt(Cell[k].Beta[Y_]*eps_y);
4669      sigma_xp = (eps_x/sigma_x)*sqrt(1.0+curly_H1*sqr(sigma_delta)/eps_x);
4670    } else {
4671      // use self-consistent beam sizes
4672      sigma_x = sqrt(Cell[k].sigma[x_][x_]);
4673      sigma_y = sqrt(Cell[k].sigma[y_][y_]);
4674      sigma_xp = sqrt(Cell[k].sigma[px_][px_]);
4675      sigma_s = sqrt(Cell[k].sigma[ct_][ct_]);
4676    }
4677
4678    u_Touschek = sqr(delta_p/(gamma*sigma_xp));
4679
4680    rate += qromb(f_int_Touschek, 0.0, 1.0)
4681            /(sigma_x*sigma_xp*sigma_y*sqr(delta_p))*L;
4682
4683    fflush(stdout);
4684  }
4685
4686  rate *= N_e*sqr(r_e)*c0/(8.0*M_PI*cube(gamma)*sigma_s)
4687         /Cell[globval.Cell_nLoc].S;
4688
4689  printf("\n");
4690  printf("Touschek lifetime [hrs]: %4.2f\n", 1.0/(3600.0*rate));
4691
4692  globval.Cavity_on = cav; globval.Aperture_on = aper;
4693
4694  return 1/rate;
4695}
4696
4697
4698double f_IBS(const double chi_m)
4699{
4700  // Interpolated
4701
4702  double  f, ln_chi_m;
4703
4704  const double A = 1.0, B = 0.579, C = 0.5;
4705
4706  ln_chi_m = log(chi_m); f = A + B*ln_chi_m + C*sqr(ln_chi_m);
4707
4708  return f;
4709}
4710
4711
4712float f_int_IBS(const float chi)
4713{
4714  // Integrated
4715
4716  double  f;
4717
4718  f = exp(-chi)*log(chi/chi_m)/chi;
4719
4720  return f;
4721}
4722
4723
4724void IBS(const double Qb,
4725         const double eps_SR[], double eps[],
4726         const double alpha_z, const double beta_z)
4727{
4728  /* The equilibrium emittance is given by:
4729
4730       sigma_delta^2 = tau_delta*(D_delta_IBS + D_delta_SR)
4731
4732       D_x = <D_delta*curly_H> =>
4733
4734       eps_x = eps_x_SR + eps_x_IBS,    D_x_IBS ~ 1/eps_x
4735
4736     i.e., the 2nd term is essentially constant.  From
4737
4738       eps_x^2 = eps_x*eps_x_SR + eps_x*eps_x_IBS
4739
4740     one obtains the IBS limited emittance (eps_x_SR = 0, eps_x^2=eps_x_IBS*tau_x*D_x_IBS->cst):
4741
4742       eps_x,IBS = sqrt(tau_x*(eps_x*D_x_IBS)
4743
4744     and by solving for eps_x
4745
4746       eps_x = eps_x_SR/2 + sqrt(eps_x_SR^2/4+eps_x_IBS^2)
4747
4748  */
4749
4750  long int  k;
4751  double    D_x, D_delta, b_max, L, gamma_z;
4752  double    sigma_x, sigma_xp, sigma_y, sigma_p, sigma_s, sigma_delta;
4753  double    incr, C, curly_H, eps_IBS[3], eps_x_tot, sigma_E;
4754  double    sigma_s_SR, sigma_delta_SR, sigma_delta_IBS;
4755
4756  const bool    integrate = false;
4757  const double  gamma = 1e9*globval.Energy/m_e, N_e = Qb/q_e;
4758
4759  // bunch size
4760  gamma_z = (1.0+sqr(alpha_z))/beta_z;
4761  sigma_s_SR = sqrt(beta_z*eps_SR[Z_]);
4762  sigma_delta_SR = sqrt(gamma_z*eps_SR[Z_]);
4763
4764  sigma_s = sqrt(beta_z*eps[Z_]); sigma_delta = sqrt(gamma_z*eps[Z_]);
4765
4766  printf("\n");
4767  printf("Qb             = %4.2f nC\n", 1e9*Qb);
4768  printf("eps_x_SR       = %9.3e m.rad, eps_x       = %9.3e m.rad\n",
4769         eps_SR[X_], eps[X_]);
4770  printf("eps_y_SR       = %9.3e m.rad, eps_y       = %9.3e m.rad\n",
4771         eps_SR[Y_], eps[Y_]);
4772  printf("eps_z_SR       = %9.3e,       eps_z       = %9.3e\n",
4773         eps_SR[Z_], eps[Z_]);
4774  printf("alpha_z        = %9.3e,       beta_z      = %9.3e\n",
4775         alpha_z, beta_z);
4776  printf("sigma_s_SR     = %9.3e mm,    sigma_s     = %9.3e mm\n",
4777         1e3*sigma_s_SR, 1e3*sigma_s);
4778  printf("sigma_delta_SR = %9.3e,       sigma_delta = %9.3e\n",
4779         sigma_delta_SR, sigma_delta);
4780
4781  D_delta = 0.0; D_x = 0.0;
4782  for(k = 1; k <= globval.Cell_nLoc; k++) {
4783    L = Cell[k].Elem.PL;
4784
4785    curly_H = get_curly_H(Cell[k].Alpha[X_], Cell[k].Beta[X_],
4786                          Cell[k].Eta[X_], Cell[k].Etap[X_]);
4787
4788    // compute estimated beam sizes for given
4789    // hor.,  ver. emittance, sigma_s, and sigma_delta (x ~ 0)
4790    sigma_x = sqrt(Cell[k].Beta[X_]*eps[X_]+sqr(sigma_delta*Cell[k].Eta[X_])); 
4791    sigma_y = sqrt(Cell[k].Beta[Y_]*eps[Y_]);
4792    sigma_xp = (eps[X_]/sigma_x)*sqrt(1.0+curly_H*sqr(sigma_delta)/eps[X_]);
4793
4794    sigma_E = gamma*m_e*q_e*sigma_delta;
4795    sigma_p = gamma*m_e*q_e*sigma_xp;
4796
4797//    b_max = sqrt(2.0*M_PI)/pow(N_e/(sigma_x*sigma_y*sigma_s), 1.0/3.0);
4798    b_max = 2.0*sqrt(M_PI)/pow(N_e/(sigma_x*sigma_y*sigma_s), 1.0/3.0);
4799
4800    chi_m = r_e*sqr(m_e*q_e/sigma_E)/b_max;
4801//    chi_m = r_e*sqr(m_e*q_e/sigma_p)/b_max;
4802
4803    if (!integrate)
4804      incr = f_IBS(chi_m)/sigma_y*L;
4805    else
4806      incr = qromb(f_int_IBS, chi_m, 1e5*chi_m)/sigma_y*L;
4807
4808    D_delta += incr; D_x += incr*curly_H;
4809  }
4810
4811  C = Cell[globval.Cell_nLoc].S;
4812
4813  if (true) {
4814    eps_x_tot = 1.0;
4815    D_delta *= N_e*sqr(r_e)*c0/(32.0*M_PI*cube(gamma)*eps_x_tot*sigma_s*C);
4816    D_x *= N_e*sqr(r_e)*c0/(32.0*M_PI*cube(gamma)*eps_x_tot*sigma_s*C);
4817    eps_IBS[X_] = sqrt(globval.tau[X_]*D_x);
4818    eps_x_tot = eps_SR[X_]*(1.0+sqrt(1.0+4.0*sqr(eps_IBS[X_]/eps_SR[X_])))/2.0;
4819    D_delta /= eps_x_tot; D_x /= eps_x_tot;
4820    sigma_delta_IBS = sqrt(globval.tau[Z_]*D_delta);
4821    eps[X_] = eps_x_tot;
4822
4823    eps[Y_] = eps_SR[Y_]/eps_SR[X_]*eps[X_];
4824    sigma_delta = sqrt(sqr(sigma_delta_SR)+sqr(sigma_delta_IBS));
4825    eps_IBS[Z_] = sigma_s*sigma_delta;
4826    eps[Z_] = eps_SR[Z_] + eps_IBS[Z_];
4827  } else {
4828    D_delta *= N_e*sqr(r_e)*c0/(32.0*M_PI*cube(gamma)*eps[X_]*sigma_s*C);
4829    D_x *= N_e*sqr(r_e)*c0/(32.0*M_PI*cube(gamma)*eps[X_]*sigma_s*C);
4830    eps_IBS[X_] = globval.tau[X_]*D_x;
4831    eps_IBS[Z_] = globval.tau[Z_]*D_delta;
4832    eps[X_] = eps_SR[X_] + eps_IBS[X_];
4833    eps[Y_] = eps_SR[Y_]/eps_SR[X_]*eps[X_];
4834    sigma_delta_IBS = sqrt(globval.tau[Z_]*D_delta);
4835    sigma_delta = sqrt(sqr(sigma_delta_SR)+sqr(sigma_delta_IBS));
4836    // approx.
4837    eps_IBS[Z_] = sigma_s*sigma_delta;
4838    eps[Z_] = eps_SR[Z_] + eps_IBS[Z_];
4839  }
4840
4841  // bunch size
4842  sigma_s = sqrt(beta_z*eps[Z_]);
4843  sigma_delta = sqrt(gamma_z*eps[Z_]);
4844
4845  printf("\n");
4846  printf("D_x,IBS         = %9.3e\n", D_x);
4847  printf("eps_x,IBS       = %5.3f nm.rad\n", 1e9*eps_IBS[X_]);
4848  printf("eps_x,tot       = %5.3f nm.rad\n", 1e9*eps[X_]);
4849  printf("eps_y,tot       = %5.3f nm.rad\n", 1e9*eps[Y_]);
4850  printf("eps_z,tot       = %9.3e\n", eps[Z_]);
4851  printf("D_delta,IBS     = %9.3e\n", D_delta);
4852  printf("sigma_delta,IBS = %9.3e\n", sigma_delta_IBS);
4853  printf("sigma_delta,tot = %9.3e\n", sigma_delta);
4854  printf("sigma_s,tot     = %9.3e\n", sigma_s);
4855}
4856
4857
4858void rm_space(char *name)
4859{
4860  int  i, k;
4861
4862  i = 0;
4863  while (name[i] == ' ')
4864    i++;
4865
4866  for (k = i; k <= (int)strlen(name)+1; k++)
4867    name[k-i] = name[k];
4868}
4869
4870/****************************************************************
4871 * void get_bn(char file_name[], int n, const bool prt)
4872 *
4873 *
4874 ****************************************************************/
4875void get_bn(char file_name[], int n, const bool prt)
4876{
4877  char      line[max_str], str[max_str], str1[max_str], *token, *name;
4878  int       n_prm, Fnum, Knum, order;
4879  double    bnL, bn, C, L;
4880  FILE      *inf, *fp_lat;
4881
4882  inf = file_read(file_name); fp_lat = file_write("get_bn.lat");
4883
4884  // if n = 0: go to last data set
4885  if (n == 0) {
4886    while (fgets(line, max_str, inf) != NULL )
4887      if (strstr(line, "n = ") != NULL) sscanf(line, "n = %d", &n);
4888
4889    fclose(inf); inf = file_read(file_name);
4890  }
4891
4892  if (prt) {
4893    printf("\n");
4894    printf("reading values (n=%d): %s\n", n, file_name);
4895    printf("\n");
4896  }
4897
4898  sprintf(str, "n = %d", n);
4899  do
4900    fgets(line, max_str, inf);
4901  while (strstr(line, str) == NULL);
4902
4903  fprintf(fp_lat, "\n");
4904  n_prm = 0;
4905  while (fgets(line, max_str, inf) != NULL) {
4906    if (strcmp(line, "\n") == 0) break;
4907    n_prm++;
4908    name = strtok(line, "(");
4909    rm_space(name);
4910    strcpy(str, name); Fnum = ElemIndex(str);
4911    strcpy(str1, name); upr_case(str1);
4912    token = strtok(NULL, ")"); sscanf(token, "%d", &Knum);
4913    strtok(NULL, "="); token = strtok(NULL, "\n");
4914    sscanf(token, "%lf %d", &bnL, &order);
4915    if (prt) printf("%6s(%2d) = %10.6f %d\n", name, Knum, bnL, order);
4916   if (Fnum != 0) {
4917      if (order == 0)
4918        SetL(Fnum, bnL);
4919      else
4920        SetbnL(Fnum, order, bnL);
4921   
4922      L = GetL(Fnum, 1);
4923      if (Knum == 1)
4924        if (order == 0)
4925          fprintf(fp_lat, "%s: Drift, L = %8.6f;\n", str1, bnL);
4926        else {
4927          bn = (L != 0.0)? bnL/L : bnL;
4928          if (order == Quad)
4929            fprintf(fp_lat, "%s: Quadrupole, L = %8.6f, K = %10.6f, N = Nquad"
4930                    ", Method = Meth;\n", str1, L, bn);
4931          else if (order == Sext)
4932            fprintf(fp_lat, "%s: Sextupole, L = %8.6f, K = %10.6f"
4933                    ", N = 1, Method = Meth;\n", str1, L, bn);
4934          else {
4935            fprintf(fp_lat, "%s: Multipole, L = %8.6f"
4936                    ", N = 1, Method = Meth,\n", str1, L);
4937            fprintf(fp_lat, "     HOM = (%d, %13.6f, %3.1f);\n",
4938                    order, bn, 0.0);
4939          }
4940        }
4941    } else {
4942      printf("element %s not found\n", name);
4943      exit_(1);
4944    }
4945  }
4946  if (prt) printf("\n");
4947
4948  C = Cell[globval.Cell_nLoc].S; recalc_S();
4949  if (prt)
4950    printf("New Cell Length: %5.3f (%5.3f)\n", Cell[globval.Cell_nLoc].S, C);
4951
4952  fclose(inf); fclose(fp_lat);
4953}
4954
4955
4956double get_dynap(const double delta)
4957{
4958  char      str[max_str];
4959  int       i;
4960  double    x_aper[n_aper], y_aper[n_aper], DA;
4961  FILE      *fp;
4962
4963  const int  prt = true;
4964
4965  fp = file_write("dynap.out");
4966  dynap(fp, 5e-3, 0.0, 0.1e-3, n_aper, n_track, x_aper, y_aper, false, prt);
4967  fclose(fp);
4968  DA = get_aper(n_aper, x_aper, y_aper);
4969
4970  if (true) {
4971    sprintf(str, "dynap_dp%3.1f.out", 1e2*delta);
4972    fp = file_write(str);
4973    dynap(fp, 5e-3, delta, 0.1e-3, n_aper, n_track,
4974          x_aper, y_aper, false, prt);
4975    fclose(fp);
4976    DA += get_aper(n_aper, x_aper, y_aper);
4977
4978    for (i = 0; i < nv_; i++)
4979      globval.CODvect[i] = 0.0;
4980    sprintf(str, "dynap_dp%3.1f.out", -1e2*delta);
4981    fp = file_write(str);
4982    dynap(fp, 5e-3, -delta, 0.1e-3, n_aper,
4983          n_track, x_aper, y_aper, false, prt);
4984    fclose(fp);
4985    DA += get_aper(n_aper, x_aper, y_aper);
4986  }
4987
4988  return DA/3.0;
4989}
4990
4991
4992double get_chi2(long int n, double x[], double y[], long int m, Vector b)
4993{
4994  /* Compute chi2 for polynomial fit */
4995
4996  int     i, j;
4997  double  sum, z;
4998 
4999  sum = 0.0;
5000  for (i = 0; i < n; i++) {
5001    z = 0.0;
5002    for (j = 0; j <= m; j++)
5003      z += b[j]*pow(x[i], j);
5004    sum += pow(y[i]-z, 2);
5005  }
5006  return(sum/n);
5007}
5008
5009
5010void pol_fit(int n, double x[], double y[], int order, Vector &b,
5011             double &sigma)
5012{
5013  /* Polynomial fit by linear chi-square */
5014
5015  int     i, j, k;
5016  Matrix  T1;
5017  bool   prt = false;
5018 
5019  const double sigma_k = 1.0, chi2 = 4.0;
5020
5021  /* initialization */
5022  for (i = 0; i <= order; i++) {
5023    b[i] = 0.0;
5024    for (j = 0; j <= order; j++)
5025      T1[i][j] = 0.0;
5026  }
5027
5028  /* polynomal fiting */
5029  for (i = 0; i < n; i++)
5030    for (j = 0; j <= order; j++) {
5031      b[j] += y[i]*pow(x[i], j)/pow(sigma_k, 2);
5032      for (k = 0; k <= order; k++)
5033        T1[j][k] += pow(x[i], j+k)/pow(sigma_k, 2);
5034    }
5035
5036  if (InvMat(order+1, T1)) {
5037    LinTrans(order+1, T1, b); sigma = get_chi2(n, x, y, order, b);
5038    if(prt){
5039      printf("\n");
5040      printf("  n    Coeff.\n");
5041      for (i = 0; i <= order; i++)
5042        printf("%3d %10.3e+/-%8.2e\n", i, b[i], sigma*sqrt(chi2*T1[i][i]));
5043    }   
5044  } else {
5045    printf("pol_fit: Matrix is singular\n");
5046    exit_(1);
5047  }
5048}
5049
5050
5051void get_ksi2(const double d_delta)
5052{
5053  const int     n_points = 20, order = 5;
5054
5055  int       i, n;
5056  double    delta[2*n_points+1], nu[2][2*n_points+1], sigma;
5057  Vector    b;
5058  FILE      *fp;
5059 
5060  fp = file_write("chrom2.out");
5061  n = 0;
5062  for (i = -n_points; i <= n_points; i++) {
5063    n++; delta[n-1] = i*(double)d_delta/(double)n_points;
5064    Ring_GetTwiss(false, delta[n-1]);
5065    nu[0][n-1] = globval.TotalTune[X_]; nu[1][n-1] = globval.TotalTune[Y_];
5066    fprintf(fp, "%5.2f %8.5f %8.5f\n", 1e2*delta[n-1], nu[0][n-1], nu[1][n-1]);
5067  }
5068  printf("\n");
5069  printf("Horizontal chromaticity:\n");
5070  pol_fit(n, delta, nu[0], order, b, sigma);
5071  printf("\n");
5072  printf("Vertical chromaticity:\n");
5073  pol_fit(n, delta, nu[1], order, b, sigma);
5074  printf("\n");
5075  fclose(fp);
5076}
5077
5078
5079bool find_nu(const int n, const double nus[], const double eps, double &nu)
5080{
5081  bool  lost;
5082  int   k;
5083
5084  const bool  prt = false;
5085
5086  if (prt) printf("\n");
5087  k = 0;
5088  while ((k < n) && (fabs(nus[k]-nu) > eps)) {
5089    if (prt) printf("nu = %7.5f(%7.5f) eps = %7.1e\n", nus[k], nu, eps);
5090    k++;
5091  }
5092
5093  if (k < n) {
5094    if (prt) printf("nu = %7.5f(%7.5f)\n", nus[k], nu);
5095    nu = nus[k]; lost = false;
5096  } else {
5097    if (prt) printf("lost\n");
5098    lost = true;
5099  }
5100
5101  return !lost;
5102}
5103
5104
5105bool get_nu(const double Ax, const double Ay, const double delta,
5106            const double eps, double &nu_x, double &nu_y)
5107{
5108  const int  n_turn = 512, n_peaks = 5;
5109
5110  bool      lost, ok_x, ok_y;
5111  char      str[max_str];
5112  int       i;
5113  long int  lastpos, lastn, n;
5114  double    x[n_turn], px[n_turn], y[n_turn], py[n_turn];
5115  double    nu[2][n_peaks], A[2][n_peaks];
5116  Vector    x0;
5117  FILE     *fp;
5118
5119  const bool   prt = false;
5120  const char   file_name[] = "track.out";
5121
5122  // complex FFT in Floquet space
5123  x0[x_] = Ax; x0[px_] = 0.0; x0[y_] = Ay; x0[py_] = 0.0;
5124  LinTrans(4, globval.Ascrinv, x0);
5125  track(file_name, x0[x_], x0[px_], x0[y_], x0[py_], delta,
5126        n_turn, lastn, lastpos, 1, 0.0);
5127  if (lastn == n_turn) {
5128    GetTrack(file_name, &n, x, px, y, py);
5129    sin_FFT((int)n, x, px); sin_FFT((int)n, y, py);
5130
5131    if (prt) {
5132      strcpy(str, file_name); strcat(str, ".fft");
5133      fp = file_write(str);
5134      for (i = 0; i < n; i++)
5135        fprintf(fp, "%5.3f %12.5e %8.5f %12.5e %8.5f\n",
5136                (double)i/(double)n, x[i], px[i], y[i], py[i]);
5137      fclose(fp);
5138    }
5139   
5140    GetPeaks1(n, x, n_peaks, nu[X_], A[X_]);
5141    GetPeaks1(n, y, n_peaks, nu[Y_], A[Y_]);
5142
5143    ok_x = find_nu(n_peaks, nu[X_], eps, nu_x);
5144    ok_y = find_nu(n_peaks, nu[Y_], eps, nu_y);
5145
5146    lost = !ok_x || !ok_y;
5147  } else
5148    lost = true;
5149 
5150  return !lost;
5151}
5152
5153
5154// tune shift with amplitude
5155void dnu_dA(const double Ax_max, const double Ay_max, const double delta)
5156{
5157  bool      ok;
5158  int       i;
5159  double    nu_x, nu_y, Ax, Ay, Jx, Jy;
5160  Vector    ps;
5161  FILE      *fp;
5162
5163  const int     n_ampl = 25;
5164  const double  A_min  = 1e-3;
5165//  const double  eps0   = 0.04, eps   = 0.02;
5166//  const double  eps0   = 0.025, eps   = 0.02;
5167  const double  eps0   = 0.04, eps   = 0.015;
5168
5169  Ring_GetTwiss(false, 0.0);
5170
5171  ok = false;
5172  fp = file_write("dnu_dAx.out");
5173  fprintf(fp, "#   x[mm]        y[mm]        J_x        J_y      nu_x    nu_y\n");
5174  fprintf(fp, "#\n");
5175  for (i = -n_ampl; i <= n_ampl; i++) {
5176    Ax = i*Ax_max/n_ampl;
5177    if (Ax == 0.0) Ax = A_min;
5178    Ay = A_min;
5179    ps[x_] = Ax; ps[px_] = 0.0; ps[y_] = Ay; ps[py_] = 0.0; getfloqs(ps);
5180    Jx = (sqr(ps[x_])+sqr(ps[px_]))/2.0; Jy = (sqr(ps[y_])+sqr(ps[py_]))/2.0;
5181    if (!ok) {
5182      nu_x = fract(globval.TotalTune[X_]); nu_y = fract(globval.TotalTune[Y_]);
5183      ok = get_nu(Ax, Ay, delta, eps0, nu_x, nu_y);
5184    } else
5185      ok = get_nu(Ax, Ay, delta, eps, nu_x, nu_y);
5186    if (ok)
5187      fprintf(fp, "%10.3e %10.3e %10.3e %10.3e %7.5f %7.5f\n",
5188              1e3*Ax, 1e3*Ay, 1e6*Jx, 1e6*Jy, fract(nu_x), fract(nu_y));
5189    else
5190      fprintf(fp, "# %10.3e %10.3e particle lost\n", 1e3*Ax, 1e3*Ay);
5191  }
5192  fclose(fp);
5193
5194  ok = false;
5195  fp = file_write("dnu_dAy.out");
5196  fprintf(fp, "#   x[mm]        y[mm]      J_x        J_y      nu_x    nu_y\n");
5197  fprintf(fp, "#\n");
5198  for (i = -n_ampl; i <= n_ampl; i++) {
5199    Ax = A_min; Ay = i*Ay_max/n_ampl;
5200    Jx = pow(Ax, 2)/(2.0*Cell[globval.Cell_nLoc].Beta[X_]);
5201    if (Ay == 0.0) Ay = A_min;
5202    Jy = pow(Ay, 2)/(2.0*Cell[globval.Cell_nLoc].Beta[Y_]);
5203//    if (i == 1) exit_(0);
5204    if (!ok) {
5205      nu_x = fract(globval.TotalTune[X_]); nu_y = fract(globval.TotalTune[Y_]);
5206      ok = get_nu(Ax, Ay, delta, eps0, nu_x, nu_y);
5207    } else
5208      ok = get_nu(Ax, Ay, delta, eps, nu_x, nu_y);
5209    if (ok)
5210      fprintf(fp, "%10.3e %10.3e %10.3e %10.3e %7.5f %7.5f\n",
5211              1e3*Ax, 1e3*Ay, 1e6*Jx, 1e6*Jy, fract(nu_x), fract(nu_y));
5212    else
5213      fprintf(fp, "# %10.3e %10.3e particle lost\n", 1e3*Ax, 1e3*Ay);
5214  }
5215  fclose(fp);
5216}
5217
5218
5219bool orb_corr(const int n_orbit)
5220{
5221  bool      cod = false;
5222  int       i;
5223  long      lastpos;
5224  Vector2   xmean, xsigma, xmax;
5225
5226  printf("\n");
5227
5228//  FitTune(qf, qd, nu_x, nu_y);
5229//  printf("\n");
5230//  printf("  qf = %8.5f qd = %8.5f\n",
5231//         GetKpar(qf, 1, Quad), GetKpar(qd, 1, Quad));
5232
5233  globval.CODvect.zero();
5234  for (i = 1; i <= n_orbit; i++) {
5235    cod = getcod(0.0, lastpos);
5236    if (cod) {
5237      codstat(xmean, xsigma, xmax, globval.Cell_nLoc, false);
5238      printf("\n");
5239      printf("RMS orbit [mm]: (%8.1e+/-%7.1e, %8.1e+/-%7.1e)\n", 
5240             1e3*xmean[X_], 1e3*xsigma[X_], 1e3*xmean[Y_], 1e3*xsigma[Y_]);
5241      lsoc(1, globval.bpm, globval.hcorr, 1);
5242      lsoc(1, globval.bpm, globval.vcorr, 2);
5243      cod = getcod(0.0, lastpos);
5244      if (cod) {
5245        codstat(xmean, xsigma, xmax, globval.Cell_nLoc, false);
5246        printf("RMS orbit [mm]: (%8.1e+/-%7.1e, %8.1e+/-%7.1e)\n", 
5247               1e3*xmean[X_], 1e3*xsigma[X_], 1e3*xmean[Y_], 1e3*xsigma[Y_]);
5248      } else
5249        printf("orb_corr: failed\n");
5250    } else
5251      printf("orb_corr: failed\n");
5252  }
5253 
5254  prt_cod("orb_corr.out", globval.bpm, true);
5255
5256  return cod;
5257}
5258
5259
5260double get_code(CellType &Cell)
5261{
5262  double  code = 0.0;
5263
5264  switch (Cell.Elem.Pkind) {
5265  case drift:
5266    code = 0.0;
5267    break;
5268  case Mpole:
5269    if (Cell.Elem.M->Pirho != 0.0) {
5270      code = 0.5;
5271    } else if (Cell.Elem.M->PBpar[Quad+HOMmax] != 0)
5272      code = sgn(Cell.Elem.M->PBpar[Quad+HOMmax]);
5273    else if (Cell.Elem.M->PBpar[Sext+HOMmax] != 0)
5274      code = 1.5*sgn(Cell.Elem.M->PBpar[Sext+HOMmax]);
5275    else if (Cell.Fnum == globval.bpm)
5276      code = 2.0;
5277    else
5278      code = 0.0;
5279    break;
5280  default:
5281    code = 0.0;
5282    break;
5283  }
5284
5285  return code;
5286}
5287
5288
5289void get_alphac(void)
5290{
5291  CellType  Cell;
5292
5293  getelem(globval.Cell_nLoc, &Cell);
5294  globval.Alphac = globval.OneTurnMat[ct_][delta_]/Cell.S;
5295}
5296
5297/******************************************************************
5298void get_alphac2(void)
5299
5300  Purpose:
5301           Calculate momentum compact factor up to third order.
5302           Method:
5303           track the orbit offset c*tau at the first element,
5304           at 11 different energy offset(-10-3 to 10-3), then
5305           use polynomal to fit the momentum compact faction factor
5306           up to 3rd order.
5307          The initial coorinates are (x_co,px_co,y_co,py_co,delta,0).
5308         
5309 Input:
5310       none
5311
5312   Output:
5313       none
5314
5315   Return:
5316      alphac
5317
5318   specific functions:
5319      none
5320
5321   Comments:
5322       change the initial coorinates from (0 0 0 0 delta 0) to
5323              (x_co,px_co,y_co,py_co,delta,0).  i.e., track
5324       around the off-momentum close orbit but not zero orbit.     
5325
5326*******************************************************************/
5327
5328void get_alphac2(void)
5329{
5330  /* Note, do not extract from M[5][4], i.e. around delta
5331     dependent fixed point.                                */
5332
5333  const int     n_points = 5;
5334  const double  d_delta  = 1e-3;
5335 //const double  d_delta  = 1e-4;
5336
5337  int       i=0, n=0;
5338  long int  lastpos=0L;  // last tracking position when the particle is stable
5339  double    delta[2*n_points+1], alphac[2*n_points+1], sigma=0.0;
5340  Vector    x, b;
5341  CellType  Cell;
5342  bool      cod=false;
5343 
5344  globval.pathlength = false;
5345  getelem(globval.Cell_nLoc, &Cell); 
5346 
5347  for (i = -n_points; i <= n_points; i++) {
5348    n++; 
5349    delta[n-1] = i*(double)d_delta/(double)n_points;
5350   
5351   // for (j = 0; j < nv_; j++)
5352    //  x[j] = 0.0;
5353    //   x[delta_] = delta[n-1];
5354   
5355    cod = getcod(delta[n-1], lastpos);   
5356    x =  globval.CODvect;
5357     
5358   
5359      Cell_Pass(0, globval.Cell_nLoc, x, lastpos);
5360      alphac[n-1] = x[ct_]/Cell.S; // this is not mcf but DT/T
5361  }
5362  pol_fit(n, delta, alphac, 3, b, sigma);
5363  printf("Momentum compaction factor:\n");
5364  printf("   alpha1 = %10.4e  alpha2 = %10.4e  alpha3 = %10.4e\n",
5365         b[1], b[2], b[3]);
5366}
5367
5368
5369/**********************************************************
5370 * float f_bend(float b0L[])
5371 *
5372 *
5373 *
5374 **********************************************************/
5375float f_bend(float b0L[])
5376{
5377  long int  lastpos;
5378  Vector    ps;
5379
5380  const int   n_prt = 10;
5381
5382  n_iter_Cart++;
5383
5384  SetbnL_sys(Fnum_Cart, Dip, b0L[1]);
5385
5386  ps.zero();
5387  Cell_Pass(Elem_GetPos(Fnum_Cart, 1)-1, Elem_GetPos(Fnum_Cart, 1),
5388            ps, lastpos);
5389
5390  if (n_iter_Cart % n_prt == 0)
5391    cout << scientific << setprecision(3)
5392         << setw(4) << n_iter_Cart
5393         << setw(11) << ps[x_] << setw(11) << ps[px_] << setw(11) << ps[ct_]
5394         << setw(11) << b0L[1] << endl;
5395
5396  return sqr(ps[x_]) + sqr(ps[px_]);
5397}
5398
5399
5400void bend_cal_Fam(const int Fnum)
5401{
5402  /* Adjusts b1L_sys to zero the orbit for a given gradient. */
5403  const int  n_prm = 1;
5404
5405  int       iter;
5406  float     *b0L, **xi, fret;
5407  Vector    ps;
5408
5409  const float  ftol = 1e-15;
5410
5411  b0L = vector(1, n_prm); xi = matrix(1, n_prm, 1, n_prm);
5412
5413  cout << endl;
5414  cout << "bend_cal: " << ElemFam[Fnum-1].ElemF.PName << ":" << endl;
5415
5416  Fnum_Cart = Fnum;  b0L[1] = 0.0; xi[1][1] = 1e-3;
5417
5418  cout << endl;
5419  n_iter_Cart = 0;
5420  powell(b0L, xi, n_prm, ftol, &iter, &fret, f_bend);
5421
5422  free_vector(b0L, 1, n_prm); free_matrix(xi, 1, n_prm, 1, n_prm);
5423}
5424
5425
5426void bend_cal(void)
5427{
5428  long int  k;
5429
5430  for (k = 1; k <= globval.Elem_nFam; k++)
5431    if ((ElemFam[k-1].ElemF.Pkind == Mpole) &&
5432        (ElemFam[k-1].ElemF.M->Pirho != 0.0) &&
5433        (ElemFam[k-1].ElemF.M->PBpar[Quad+HOMmax] != 0.0))
5434      if (ElemFam[k-1].nKid > 0) bend_cal_Fam(k);
5435}
5436
5437
5438double h_ijklm(const tps &h, const int i, const int j, const int k,
5439               const int l, const int m)
5440{
5441  int      i1;
5442  iVector  jj;
5443
5444  for (i1 = 0; i1 < nv_tps; i1++)
5445    jj[i1] = 0;
5446  jj[x_] = i; jj[px_] = j; jj[y_] = k; jj[py_] = l; jj[delta_] = m;
5447  return h[jj];
5448}
5449
5450
5451ss_vect<tps> get_A(const double alpha[], const double beta[],
5452                   const double eta[], const double etap[])
5453{
5454  ss_vect<tps>  A, Id;
5455
5456  Id.identity();
5457
5458  A.identity();
5459  A[x_]  = sqrt(beta[X_])*Id[x_];
5460  A[px_] = -alpha[X_]/sqrt(beta[X_])*Id[x_] + 1.0/sqrt(beta[X_])*Id[px_];
5461  A[y_]  = sqrt(beta[Y_])*Id[y_];
5462  A[py_] = -alpha[Y_]/sqrt(beta[Y_])*Id[y_] + 1.0/sqrt(beta[Y_])*Id[py_];
5463
5464  A[x_] += eta[X_]*Id[delta_]; A[px_] += etap[X_]*Id[delta_];
5465
5466  return A;
5467}
5468
5469
5470void get_ab(const ss_vect<tps> &A,
5471            double alpha[], double beta[], double eta[], double etap[])
5472{
5473  int           k;
5474  ss_vect<tps>  A_Atp;
5475
5476  A_Atp = A*tp_S(2, A);
5477
5478  for (k = 0; k <= 1; k++) {
5479      eta[k] = A[2*k][delta_]; 
5480     etap[k] = A[2*k+1][delta_];
5481    alpha[k] = -A_Atp[2*k][2*k+1]; 
5482     beta[k] = A_Atp[2*k][2*k];
5483  }
5484}
5485
5486
5487void set_tune(const char file_name1[], const char file_name2[], const int n)
5488{
5489  const int  n_b2 = 8;
5490
5491  char      line[max_str], names[n_b2][max_str];
5492  int       j, k, Fnum;
5493  double    b2s[n_b2], nu[2];
5494  ifstream  inf1, inf2;
5495  FILE      *fp_lat;
5496
5497  file_rd(inf1, file_name1); file_rd(inf2, file_name2);
5498
5499  // skip 1st and 2nd line
5500  inf1.getline(line, max_str); inf2.getline(line, max_str);
5501  inf1.getline(line, max_str); inf2.getline(line, max_str);
5502 
5503  inf1.getline(line, max_str);
5504  sscanf(line, "%*s %*s %*s %s %s %s %s",
5505         names[0], names[1], names[2], names[3]);
5506  inf2.getline(line, max_str);
5507  sscanf(line, "%*s %*s %*s %s %s %s %s",
5508         names[4], names[5], names[6], names[7]);
5509
5510  printf("\n");
5511  printf("quads:");
5512  for (k = 0; k <  n_b2; k++) {
5513    lwr_case(names[k]); rm_space(names[k]);
5514    printf(" %s", names[k]);
5515  }
5516  printf("\n");
5517
5518  // skip 4th line
5519  inf1.getline(line, max_str); inf2.getline(line, max_str);
5520
5521  fp_lat = file_write("set_tune.lat");
5522  while (inf1.getline(line, max_str) != NULL) {
5523    sscanf(line, "%d%lf %lf %lf %lf %lf %lf",
5524           &j, &nu[X_], &nu[Y_], &b2s[0], &b2s[1], &b2s[2], &b2s[3]);
5525    inf2.getline(line, max_str);
5526    sscanf(line, "%d%lf %lf %lf %lf %lf %lf",
5527           &j, &nu[X_], &nu[Y_], &b2s[4], &b2s[5], &b2s[6], &b2s[7]);
5528
5529    if (j == n) {
5530      printf("\n");
5531      printf("%3d %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f\n",
5532             n,
5533             b2s[0], b2s[1], b2s[2], b2s[3], b2s[4], b2s[5], b2s[6], b2s[7]);
5534
5535      for (k = 0; k <  n_b2; k++) {
5536        Fnum = ElemIndex(names[k]);
5537        set_bn_design_fam(Fnum, Quad, b2s[k], 0.0);
5538
5539        fprintf(fp_lat, "%s: Quadrupole, L = %8.6f, K = %10.6f, N = Nquad"
5540                ", Method = Meth;\n",
5541                names[k], ElemFam[Fnum-1].ElemF.PL, b2s[k]);
5542      }
5543      break;
5544    }
5545  }
5546
5547  fclose(fp_lat);
5548}
5549
5550
5551
5552
5553
Note: See TracBrowser for help on using the repository browser.