6 #include <boost/lexical_cast.hpp>
8 #include <boost/numeric/ublas/vector_proxy.hpp>
9 #include <boost/numeric/ublas/matrix_proxy.hpp>
11 #include "flame/constants.h"
13 #include "flame/moment.h"
14 #include "flame/moment_sup.h"
15 #include "flame/rf_cavity.h"
16 #include "flame/chg_stripper.h"
18 #define sqr(x) ((x)*(x))
19 #define cube(x) ((x)*(x)*(x))
21 namespace ub = boost::numeric::ublas;
28 template<
typename ARR>
29 bool load_storage(ARR& to,
const Config& conf,
const std::string& name,
bool T=
true)
32 const std::vector<double>& val(conf.
get<std::vector<double> >(name));
33 if(to.size()!=val.size()) {
34 throw std::invalid_argument(SB()<<
"Array "<<name<<
" must have "<<to.size()<<
" elements, not "<<val.size());
36 std::copy(val.begin(), val.end(), to.begin());
39 }
catch(std::exception&){
41 throw std::invalid_argument(name+
" not defined or has wrong type (must be vector)");
50 std::ostream& operator<<(std::ostream& strm,
const Particle& P)
53 <<
"IonZ="<<std::scientific << std::setprecision(10)<<P.
IonZ
67 MomentState::MomentState(
const Config& c)
71 ,moment0_env(maxsize, 0e0)
72 ,moment0_rms(maxsize, 0e0)
73 ,moment1_env(boost::numeric::ublas::identity_matrix<double>(maxsize))
81 double icstate_f = 0.0;
82 bool have_cstate = c.
tryGet<
double>(
"cstate", icstate_f);
83 size_t icstate = (size_t)icstate_f;
85 std::string vectorname(c.
get<std::string>(
"vector_variable",
"moment0"));
86 std::string matrixname(c.
get<std::string>(
"matrix_variable",
"initial"));
88 std::vector<double> ics, nchg;
89 bool have_ics = c.
tryGet<std::vector<double> >(
"IonChargeStates", ics);
91 ref.IonEs = c.
get<
double>(
"IonEs", 0e0),
92 ref.IonEk = c.
get<
double>(
"IonEk", 0e0),
93 ref.SampleFreq = c.
get<
double>(
"SampleFreq", SampleFreqDefault);
97 ref.IonZ = c.
get<
double>(
"IonZ", 0e0);
98 ref.IonQ = c.
get<
double>(
"IonQ", 1e0);
100 ics.push_back(ref.IonZ);
101 nchg.push_back(ref.IonQ);
105 throw std::invalid_argument(
"IonChargeStates w/ length 0");
106 if(icstate>=ics.size())
107 throw std::invalid_argument(
"IonChargeStates[cstate] is out of bounds");
109 nchg = c.
get<std::vector<double> >(
"NCharge");
110 if(nchg.size()!=ics.size())
111 throw std::invalid_argument(
"NCharge[] and IonChargeStates[] must have equal length");
113 bool have_ionz = c.
tryGet<
double>(
"IonZ", ref.IonZ);
118 bool have_ionq = c.
tryGet<
double>(
"IonQ", ref.IonQ);
132 if(!have_cstate && !have_ics) {
134 }
else if(!have_cstate && have_ics) {
138 }
else if(have_cstate && have_ics) {
142 ics[0] = ics[icstate];
143 nchg[0] = nchg[icstate];
148 throw std::invalid_argument(
"MomentState: must define IonChargeStates and NCharge when cstate is set");
152 real.resize(ics.size());
153 moment0.resize(ics.size());
154 moment1.resize(ics.size());
155 transmat.resize(ics.size());
157 for(
size_t i=0; i<ics.size(); i++) {
158 std::string num(boost::lexical_cast<std::string>(icstate+i));
160 moment0[i].resize(maxsize);
161 moment1[i].resize(maxsize, maxsize);
162 moment1[i] = boost::numeric::ublas::identity_matrix<double>(maxsize);
163 transmat[i].resize(maxsize, maxsize);
164 transmat[i] = boost::numeric::ublas::identity_matrix<double>(maxsize);
166 load_storage(moment0[i].data(), c, vectorname+num);
167 load_storage(moment1[i].data(), c, matrixname+num);
171 real[i].IonZ = ics[i];
172 real[i].IonQ = nchg[i];
174 real[i].phis = moment0[i][PS_S];
175 real[i].IonEk += moment0[i][PS_PS]*MeVtoeV;
186 moment0[0].resize(maxsize);
187 moment1[0].resize(maxsize, maxsize);
188 transmat[0].resize(maxsize, maxsize);
190 load_storage(moment0[0].data(), c, vectorname,
false);
191 load_storage(moment1[0].data(), c, matrixname,
false);
192 transmat[0] = boost::numeric::ublas::identity_matrix<double>(maxsize);
199 MomentState::~MomentState() {}
201 void MomentState::calc_rms()
203 assert(real.size()>0);
204 assert(moment0_env.size()==maxsize);
205 assert(moment0_rms.size()==maxsize);
206 assert(moment1_env.size1()==maxsize);
207 assert(moment1_env.size2()==maxsize);
210 for(
size_t n=0; n<real.size(); n++) {
211 totQ += real[n].IonQ;
213 noalias(moment0_env) = moment0[n]*real[n].IonQ;
215 noalias(moment0_env) += moment0[n]*real[n].IonQ;
220 moment1_env = ub::zero_matrix<double>(state_t::maxsize);
221 boost::numeric::ublas::slice S(0, 1, 6);
222 for(
size_t n=0; n<real.size(); n++) {
223 const double Q = real[n].IonQ;
224 state_t::vector_t m0diff(moment0[n]-moment0_env);
226 ub::project(moment1_env, S, S) += ub::project(Q*(moment1[n]+ub::outer_prod(m0diff, m0diff)), S, S);
230 for(
size_t j=0; j<maxsize; j++) {
231 moment0_rms[j] = sqrt(moment1_env(j,j));
235 MomentState::MomentState(
const MomentState& o, clone_tag t)
241 ,transmat(o.transmat)
242 ,moment0_env(o.moment0_env)
243 ,moment0_rms(o.moment0_rms)
244 ,moment1_env(o.moment1_env)
245 ,last_caviphi0(o.last_caviphi0)
252 throw std::invalid_argument(
"Can't assign State: incompatible types");
255 moment0 = O->moment0;
256 moment1 = O->moment1;
257 transmat = O->transmat;
258 moment0_env = O->moment0_env;
259 moment0_rms = O->moment0_rms;
260 moment1_env = O->moment1_env;
261 last_caviphi0 = O->last_caviphi0;
268 strm<<
"State: empty";
273 strm<<
"State: moment0 mean="<<moment0_env;
276 strm << std::scientific << std::setprecision(8)
277 <<
"\nState:\n energy [eV] =\n" << std::setw(20) << real[0].IonEk <<
"\n moment0 mean =\n ";
278 for (
size_t k = 0; k < MomentState::maxsize; k++)
279 strm << std::scientific << std::setprecision(10) << std::setw(18) << moment0_env(k) <<
",";
280 strm << std::scientific << std::setprecision(10)
281 <<
"\n moment0 rms =\n ";
282 for (
size_t k = 0; k < MomentState::maxsize; k++)
283 strm << std::scientific << std::setprecision(10) << std::setw(18) << moment0_rms(k) <<
",";
284 strm <<
"\n moment1 mean =\n";
285 for (
size_t j = 0; j < MomentState::maxsize; j++) {
287 for (
size_t k = 0; k < MomentState::maxsize; k++) {
288 strm << std::scientific << std::setprecision(10) << std::setw(18) << moment1_env(j, k) <<
",";
290 if (j < MomentState::maxsize-1) strm <<
"\n";
294 strm<<
"\n Reference state:\n "<<ref<<
"\n";
295 for(
size_t k=0; k<
size(); k++) {
296 strm<<
" Charge state "<<k<<
"\n"
298 " moment0 "<<moment0[k]<<
"\n";
301 " moment1 "<<moment1[k]<<
"\n";
309 Info.
name =
"moment1_env";
310 Info.
ptr = &moment1_env(0,0);
311 Info.type = ArrayInfo::Double;
313 Info.
dim[0] = moment1_env.size1();
314 Info.
dim[1] = moment1_env.size2();
315 Info.
stride[0] =
sizeof(double)*moment1_env.size2();
316 Info.
stride[1] =
sizeof(double);
318 }
else if(idx==I++) {
326 static_assert(
sizeof(moment1[0])>=
sizeof(
double)*maxsize*maxsize,
327 "storage assumption violated");
328 Info.
name =
"moment1";
329 Info.
ptr = &moment1[0](0,0);
330 Info.type = ArrayInfo::Double;
332 Info.
dim[0] = moment1[0].size1();
333 Info.
dim[1] = moment1[0].size2();
334 Info.
dim[2] = moment1.size();
335 Info.
stride[0] =
sizeof(double)*moment1_env.size2();
336 Info.
stride[1] =
sizeof(double);
337 Info.
stride[2] =
sizeof(moment1[0]);
339 }
else if(idx==I++) {
340 static_assert(
sizeof(transmat[0])>=
sizeof(
double)*maxsize*maxsize,
341 "storage assumption violated");
342 Info.
name =
"transmat";
343 Info.
ptr = &transmat[0](0,0);
344 Info.type = ArrayInfo::Double;
346 Info.
dim[0] = transmat[0].size1();
347 Info.
dim[1] = transmat[0].size2();
348 Info.
dim[2] = transmat.size();
349 Info.
stride[0] =
sizeof(double)*moment1_env.size2();
350 Info.
stride[1] =
sizeof(double);
351 Info.
stride[2] =
sizeof(transmat[0]);
353 }
else if(idx==I++) {
354 Info.
name =
"moment0_env";
355 Info.
ptr = &moment0_env(0);
356 Info.type = ArrayInfo::Double;
358 Info.
dim[0] = moment0_env.size();
359 Info.
stride[0] =
sizeof(double);
361 }
else if(idx==I++) {
362 Info.
name =
"moment0_rms";
363 Info.
ptr = &moment0_rms(0);
364 Info.type = ArrayInfo::Double;
366 Info.
dim[0] = moment0_rms.size();
367 Info.
stride[0] =
sizeof(double);
369 }
else if(idx==I++) {
371 static_assert(
sizeof(moment0[0])>=
sizeof(
double)*maxsize,
372 "storage assumption violated");
373 Info.
name =
"moment0";
374 Info.
ptr = &moment0[0][0];
375 Info.type = ArrayInfo::Double;
377 Info.
dim[0] = moment0[0].size();
378 Info.
dim[1] = moment0.size();
379 Info.
stride[0] =
sizeof(double);
380 Info.
stride[1] =
sizeof(moment0[0]);
382 }
else if(idx==I++) {
383 Info.
name =
"ref_IonZ";
385 Info.type = ArrayInfo::Double;
388 }
else if(idx==I++) {
389 Info.
name =
"ref_IonQ";
391 Info.type = ArrayInfo::Double;
394 }
else if(idx==I++) {
395 Info.
name =
"ref_IonEs";
397 Info.type = ArrayInfo::Double;
400 }
else if(idx==I++) {
401 Info.
name =
"ref_IonW";
403 Info.type = ArrayInfo::Double;
406 }
else if(idx==I++) {
407 Info.
name =
"ref_gamma";
409 Info.type = ArrayInfo::Double;
412 }
else if(idx==I++) {
413 Info.
name =
"ref_beta";
415 Info.type = ArrayInfo::Double;
418 }
else if(idx==I++) {
419 Info.
name =
"ref_bg";
421 Info.type = ArrayInfo::Double;
424 }
else if(idx==I++) {
425 Info.
name =
"ref_SampleFreq";
427 Info.type = ArrayInfo::Double;
430 }
else if(idx==I++) {
431 Info.
name =
"ref_SampleIonK";
433 Info.type = ArrayInfo::Double;
436 }
else if(idx==I++) {
437 Info.
name =
"ref_phis";
439 Info.type = ArrayInfo::Double;
442 }
else if(idx==I++) {
443 Info.
name =
"ref_IonEk";
445 Info.type = ArrayInfo::Double;
448 }
else if(idx==I++) {
450 Info.
ptr = &real[0].IonZ;
451 Info.type = ArrayInfo::Double;
453 Info.
dim [0] = real.size();
454 Info.
stride[0] =
sizeof(real[0]);
457 }
else if(idx==I++) {
459 Info.
ptr = &real[0].IonEs;
460 Info.type = ArrayInfo::Double;
462 Info.
dim [0] = real.size();
463 Info.
stride[0] =
sizeof(real[0]);
465 }
else if(idx==I++) {
467 Info.
ptr = &real[0].IonW;
468 Info.type = ArrayInfo::Double;
470 Info.
dim [0] = real.size();
471 Info.
stride[0] =
sizeof(real[0]);
473 }
else if(idx==I++) {
475 Info.
ptr = &real[0].gamma;
476 Info.type = ArrayInfo::Double;
478 Info.
dim [0] = real.size();
479 Info.
stride[0] =
sizeof(real[0]);
481 }
else if(idx==I++) {
483 Info.
ptr = &real[0].beta;
484 Info.type = ArrayInfo::Double;
486 Info.
dim [0] = real.size();
487 Info.
stride[0] =
sizeof(real[0]);
489 }
else if(idx==I++) {
491 Info.
ptr = &real[0].bg;
492 Info.type = ArrayInfo::Double;
494 Info.
dim [0] = real.size();
495 Info.
stride[0] =
sizeof(real[0]);
497 }
else if(idx==I++) {
498 Info.
name =
"SampleFreq";
499 Info.
ptr = &real[0].SampleFreq;
500 Info.type = ArrayInfo::Double;
502 Info.
dim [0] = real.size();
503 Info.
stride[0] =
sizeof(real[0]);
505 }
else if(idx==I++) {
506 Info.
name =
"SampleIonK";
507 Info.
ptr = &real[0].SampleIonK;
508 Info.type = ArrayInfo::Double;
510 Info.
dim [0] = real.size();
511 Info.
stride[0] =
sizeof(real[0]);
513 }
else if(idx==I++) {
515 Info.
ptr = &real[0].phis;
516 Info.type = ArrayInfo::Double;
518 Info.
dim [0] = real.size();
519 Info.
stride[0] =
sizeof(real[0]);
521 }
else if(idx==I++) {
523 Info.
ptr = &real[0].IonEk;
524 Info.type = ArrayInfo::Double;
526 Info.
dim [0] = real.size();
527 Info.
stride[0] =
sizeof(real[0]);
529 }
else if(idx==I++) {
531 Info.
ptr = &real[0].IonQ;
532 Info.type = ArrayInfo::Double;
534 Info.
dim [0] = real.size();
535 Info.
stride[0] =
sizeof(real[0]);
538 }
else if(idx==I++) {
539 Info.
name =
"last_caviphi0";
540 Info.
ptr = &last_caviphi0;
541 Info.type = ArrayInfo::Double;
549 MomentElementBase::MomentElementBase(
const Config& c)
551 ,dx (c.get<double>(
"dx", 0e0)*MtoMM)
552 ,dy (c.get<double>(
"dy", 0e0)*MtoMM)
553 ,pitch(c.get<double>(
"pitch", 0e0))
554 ,yaw (c.get<double>(
"yaw", 0e0))
555 ,roll (c.get<double>(
"roll", 0e0))
556 ,skipcache(c.get<double>(
"skipcache", 0.0)!=0.0)
561 MomentElementBase::~MomentElementBase() {}
566 last_real_in = O->last_real_in;
567 last_real_out= O->last_real_out;
568 last_ref_in = O->last_ref_in;
569 last_ref_out = O->last_ref_out;
571 misalign = O->misalign;
572 misalign_inv = O->misalign_inv;
584 using namespace boost::numeric::ublas;
593 void MomentElementBase::get_misalign(
const state_t &ST,
const Particle &real, value_t &M, value_t &IM)
const
596 scl = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize),
602 scl(state_t::PS_S, state_t::PS_S) /= -real.
SampleIonK;
603 scl(state_t::PS_PS, state_t::PS_PS) /= sqr(real.
beta)*real.
gamma*ST.ref.
IonEs/MeVtoeV;
605 inverse(scl_inv, scl);
608 T(state_t::PS_S, 6) = -
length/2e0*MtoMM;
609 T(state_t::PS_PS, 6) = 1e0;
612 RotMat(
dx, dy, pitch, yaw, roll, R);
617 M = prod(scl_inv, M);
622 T(state_t::PS_S, 6) =
length/2e0*MtoMM;
623 T(state_t::PS_PS, 6) = 1e0;
627 IM = prod(R_inv, IM);
628 IM = prod(T_inv, IM);
629 IM = prod(scl_inv, IM);
632 unsigned MomentElementBase::get_flag(
const Config& c,
const std::string& name,
const unsigned& def_value)
638 check_value = boost::lexical_cast<
double>(c.
get<std::string>(
name));
639 }
catch (std::exception&){
641 check_value = c.
get<
double>(
name);
642 }
catch (std::exception&){
643 check_value = boost::lexical_cast<
double>(def_value);
649 read_value = boost::lexical_cast<
unsigned>(check_value);
650 if (boost::lexical_cast<double>(read_value) != check_value)
651 throw std::runtime_error(SB()<< name <<
" must be an unsigned integer");
652 }
catch (std::exception&){
653 throw std::runtime_error(SB()<< name <<
" must be an unsigned integer");
661 using namespace boost::numeric::ublas;
668 last_ref_in = ST.ref;
669 last_real_in = ST.real;
678 for(
size_t k=0; k<last_real_in.size(); k++)
679 ST.real[k].phis += ST.real[k].SampleIonK*
length*MtoMM;
682 for(
size_t k=0; k<last_real_in.size(); k++)
683 ST.real[k].phis -= ST.real[k].SampleIonK*
length*MtoMM;
686 last_ref_out = ST.ref;
687 last_real_out = ST.real;
689 ST.ref = last_ref_out;
690 assert(last_real_out.size()==ST.real.size());
691 std::copy(last_real_out.begin(),
700 for(
size_t k=0; k<last_real_in.size(); k++) {
701 ST.moment0[k] = prod(
transfer[k], ST.moment0[k]);
703 scratch = prod(
transfer[k], ST.moment1[k]);
704 ST.moment1[k] = prod(scratch, trans(
transfer[k]));
712 value_t invmat = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
713 for(
size_t k=0; k<last_real_in.size(); k++) {
716 ST.moment0[k] = prod(invmat, ST.moment0[k]);
718 scratch = prod(invmat, ST.moment1[k]);
719 ST.moment1[k] = prod(scratch, trans(invmat));
721 ST.transmat[k] = invmat;
731 && last_real_in.size()==ST.
size()
732 && last_ref_in==ST.ref
733 && std::equal(last_real_in.begin(),
741 if (last_real_out.size()==ST.
size()) {
742 reals = last_ref_out<=ST.ref;
743 for(
size_t k=0; k<last_real_out.size(); k++) {
744 reals &= last_real_out[k]<=ST.real[k];
755 transfer.resize(ST.real.size(), boost::numeric::ublas::identity_matrix<double>(state_t::maxsize));
756 misalign.resize(ST.real.size(), boost::numeric::ublas::identity_matrix<double>(state_t::maxsize));
757 misalign_inv.resize(ST.real.size(), boost::numeric::ublas::identity_matrix<double>(state_t::maxsize));
764 for(
size_t k=0; k<last_real_in.size(); k++) {
765 transfer[k] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
773 typedef ElementSource self_t;
775 typedef typename base_t::state_t
state_t;
777 ElementSource(
const Config& c): base_t(c), istate(c) {}
787 virtual void show(std::ostream& strm,
int level)
const
790 strm<<
"Initial: "<<istate.moment0_env<<
"\n";
796 virtual ~ElementSource() {}
798 virtual const char*
type_name()
const {
return "source";}
801 base_t::assign(other);
802 const self_t* O=
static_cast<const self_t*
>(other);
803 istate.assign(O->istate);
810 typedef ElementMark self_t;
812 typedef typename base_t::state_t
state_t;
815 virtual ~ElementMark() {}
816 virtual const char*
type_name()
const {
return "marker";}
824 typedef ElementBPM self_t;
826 typedef typename base_t::state_t
state_t;
829 virtual ~ElementBPM() {}
830 virtual const char*
type_name()
const {
return "bpm";}
838 typedef ElementDrift self_t;
840 typedef typename base_t::state_t
state_t;
842 ElementDrift(
const Config& c) : base_t(c) {}
843 virtual ~ElementDrift() {}
844 virtual const char*
type_name()
const {
return "drift";}
852 const double L =
length*MtoMM;
854 for(
size_t i=0; i<last_real_in.size(); i++) {
855 transfer[i] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
856 transfer[i](state_t::PS_X, state_t::PS_PX) = L;
857 transfer[i](state_t::PS_Y, state_t::PS_PY) = L;
858 transfer[i](state_t::PS_S, state_t::PS_PS) =
859 -2e0*M_PI/(ST.real[i].SampleLambda*ST.real[i].IonEs/MeVtoeV*cube(ST.real[i].bg))*L;
867 typedef ElementOrbTrim self_t;
869 typedef typename base_t::state_t
state_t;
871 ElementOrbTrim(
const Config& c) : base_t(c) {
length = 0e0;}
872 virtual ~ElementOrbTrim() {}
873 virtual const char*
type_name()
const {
return "orbtrim";}
880 double theta_x =
conf().
get<
double>(
"theta_x", 0e0),
881 theta_y =
conf().
get<
double>(
"theta_y", 0e0);
882 const double tm_xkick =
conf().
get<
double>(
"tm_xkick", 0e0),
883 tm_ykick =
conf().
get<
double>(
"tm_ykick", 0e0),
884 xyrotate =
conf().
get<
double>(
"xyrotate", 0e0)*M_PI/180e0;
885 const bool realpara =
conf().
get<
double>(
"realpara", 0e0) == 1e0;
888 double ecpi = ST.ref.
IonZ*C0/sqrt(sqr(ST.ref.
IonW) - sqr(ST.ref.
IonEs));
889 theta_x = tm_xkick*ecpi;
890 theta_y = tm_ykick*ecpi;
893 for(
size_t i=0; i<last_real_in.size(); i++) {
894 transfer[i] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
895 transfer[i](state_t::PS_PX, 6) = theta_x*ST.real[i].IonZ/ST.ref.
IonZ;
896 transfer[i](state_t::PS_PY, 6) = theta_y*ST.real[i].IonZ/ST.ref.
IonZ;
898 get_misalign(ST, ST.real[i], misalign[i], misalign_inv[i]);
900 noalias(scratch) = prod(
transfer[i], misalign[i]);
901 noalias(
transfer[i]) = prod(misalign_inv[i], scratch);
903 if (xyrotate != 0e0) {
905 RotMat(0e0, 0e0, 0e0, 0e0, xyrotate, R);
907 noalias(
transfer[i]) = prod(scratch, R);
919 typedef ElementSBend self_t;
921 typedef typename base_t::state_t
state_t;
923 unsigned HdipoleFitMode;
925 ElementSBend(
const Config& c) : base_t(c), HdipoleFitMode(0) {
927 HdipoleFitMode = get_flag(c,
"HdipoleFitMode", 1);
928 if (HdipoleFitMode != 0 && HdipoleFitMode != 1)
929 throw std::runtime_error(SB()<<
"Undefined HdipoleFitMode: " << HdipoleFitMode);
931 virtual ~ElementSBend() {}
932 virtual const char*
type_name()
const {
return "sbend";}
935 base_t::assign(other);
936 const self_t* O=
static_cast<const self_t*
>(other);
937 HdipoleFitMode = O->HdipoleFitMode;
943 using namespace boost::numeric::ublas;
950 last_ref_in = ST.ref;
951 last_real_in = ST.real;
957 last_ref_out = ST.ref;
958 last_real_out = ST.real;
960 ST.ref = last_ref_out;
961 assert(last_real_out.size()==ST.real.size());
962 std::copy(last_real_out.begin(),
972 for(
size_t i=0; i<last_real_in.size(); i++) {
973 double phis_temp = ST.moment0[i][state_t::PS_S];
975 ST.moment0[i] = prod(
transfer[i], ST.moment0[i]);
977 noalias(scratch) = prod(
transfer[i], ST.moment1[i]);
978 noalias(ST.moment1[i]) = prod(scratch, trans(
transfer[i]));
980 double dphis_temp = ST.moment0[i][state_t::PS_S] - phis_temp;
982 ST.real[i].phis += ST.real[i].SampleIonK*
length*MtoMM + dphis_temp;
990 value_t invmat = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
991 for(
size_t i=0; i<last_real_in.size(); i++) {
992 double phis_temp = ST.moment0[i][state_t::PS_S];
995 ST.moment0[i] = prod(invmat, ST.moment0[i]);
997 noalias(scratch) = prod(invmat, ST.moment1[i]);
998 noalias(ST.moment1[i]) = prod(scratch, trans(invmat));
1000 double dphis_temp = ST.moment0[i][state_t::PS_S] - phis_temp;
1002 ST.real[i].phis -= ST.real[i].SampleIonK*
length*MtoMM - dphis_temp;
1003 ST.transmat[i] = invmat;
1013 bool ver =
conf().
get<
double>(
"ver", 0e0) == 1.0;
1014 double L =
conf().
get<
double>(
"L")*MtoMM,
1015 phi =
conf().
get<
double>(
"phi")*M_PI/180e0,
1016 phi1 =
conf().
get<
double>(
"phi1")*M_PI/180e0,
1017 phi2 =
conf().
get<
double>(
"phi2")*M_PI/180e0,
1018 dphi1 =
conf().
get<
double>(
"dphi1", 0e0)*M_PI/180e0,
1019 dphi2 =
conf().
get<
double>(
"dphi2", 0e0)*M_PI/180e0,
1020 K =
conf().
get<
double>(
"K", 0e0)/sqr(MtoMM);
1022 unsigned EFcorrection = get_flag(
conf(),
"EFcorrection", 0);
1024 if (EFcorrection != 0 && EFcorrection != 1)
1025 throw std::runtime_error(SB()<<
"Undefined EFcorrection: " << EFcorrection);
1027 for(
size_t i=0; i<last_real_in.size(); i++) {
1029 transfer[i] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1032 if (!HdipoleFitMode) {
1033 double dip_bg =
conf().
get<
double>(
"bg", ST.ref.
bg),
1034 dip_IonZ =
conf().
get<
double>(
"ref_IonZ", ST.ref.
IonZ),
1035 qmrel = (ST.real[i].IonZ-dip_IonZ)/dip_IonZ,
1037 dip_Ek = (sqrt(sqr(dip_bg)+1e0)-1e0)*ST.ref.
IonEs,
1038 dip_gamma = (dip_Ek+ST.ref.
IonEs)/ST.ref.
IonEs,
1039 dip_beta = sqrt(1e0-1e0/sqr(dip_gamma)),
1040 d = (ST.ref.
gamma-dip_gamma)/(sqr(dip_beta)*dip_gamma) - qmrel,
1043 GetSBendMatrix(L, phi, phi1, phi2, K, ST.ref.
IonEs, ST.ref.
gamma, qmrel,
1044 dphi1, dphi2, EFcorrection, dip_beta, dip_gamma, d, dip_IonK,
transfer[i]);
1046 double qmrel = (ST.real[i].IonZ-ST.ref.
IonZ)/ST.ref.
IonZ;
1047 GetSBendMatrix(L, phi, phi1, phi2, K, ST.ref.
IonEs, ST.ref.
gamma, qmrel,
1048 dphi1, dphi2, EFcorrection, ST.ref.
beta, ST.ref.
gamma, - qmrel,
1055 R = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1056 R(state_t::PS_X, state_t::PS_X) = 0e0;
1057 R(state_t::PS_PX, state_t::PS_PX) = 0e0;
1058 R(state_t::PS_Y, state_t::PS_Y) = 0e0;
1059 R(state_t::PS_PY, state_t::PS_PY) = 0e0;
1060 R(state_t::PS_X, state_t::PS_Y) = -1e0;
1061 R(state_t::PS_PX, state_t::PS_PY) = -1e0;
1062 R(state_t::PS_Y, state_t::PS_X) = 1e0;
1063 R(state_t::PS_PY, state_t::PS_PX) = 1e0;
1065 noalias(scratch) = prod(R,
transfer[i]);
1066 noalias(
transfer[i]) = prod(scratch, trans(R));
1070 get_misalign(ST, ST.real[i], misalign[i], misalign_inv[i]);
1072 noalias(scratch) = prod(
transfer[i], misalign[i]);
1073 noalias(
transfer[i]) = prod(misalign_inv[i], scratch);
1082 typedef ElementQuad self_t;
1084 typedef typename base_t::state_t
state_t;
1086 ElementQuad(
const Config& c) : base_t(c) {}
1087 virtual ~ElementQuad() {}
1088 virtual const char*
type_name()
const {
return "quadrupole";}
1094 const double L =
conf().
get<
double>(
"L")*MtoMM;
1095 const unsigned ncurve = get_flag(
conf(),
"ncurve", 0);
1098 std::vector<std::vector<double> > Curves;
1099 std::vector<double> Scales;
1100 GetCurveData(
conf(), ncurve, Scales, Curves);
1102 for(
size_t i=0; i<last_real_in.size(); i++) {
1104 double dL = L/double(Curves[0].size()),
1105 Brho = ST.real[i].Brho();
1106 transfer[i] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1107 for (
size_t j=0; j<Curves[0].size(); j++){
1109 for (
size_t n=0; n<Curves.size(); n++) K += Scales[n]*Curves[n][j]/Brho/sqr(MtoMM);
1110 value_t tmstep = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1111 GetQuadMatrix(dL, K, (
unsigned)state_t::PS_X, tmstep);
1112 GetQuadMatrix(dL, -K, (
unsigned)state_t::PS_Y, tmstep);
1114 tmstep(state_t::PS_S, state_t::PS_PS) =
1115 -2e0*M_PI/(ST.real[i].SampleLambda*ST.real[i].IonEs/MeVtoeV*cube(ST.real[i].bg))*dL;
1119 get_misalign(ST, ST.real[i], misalign[i], misalign_inv[i]);
1120 noalias(scratch) = prod(
transfer[i], misalign[i]);
1121 noalias(
transfer[i]) = prod(misalign_inv[i], scratch);
1125 const double B2=
conf().
get<
double>(
"B2");
1126 for(
size_t i=0; i<last_real_in.size(); i++) {
1128 transfer[i] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1130 double Brho = ST.real[i].Brho(),
1131 K = B2/Brho/sqr(MtoMM);
1134 GetQuadMatrix(L, K, (
unsigned)state_t::PS_X,
transfer[i]);
1136 GetQuadMatrix(L, -K, (
unsigned)state_t::PS_Y,
transfer[i]);
1139 transfer[i](state_t::PS_S, state_t::PS_PS) =
1140 -2e0*M_PI/(ST.real[i].SampleLambda*ST.real[i].IonEs/MeVtoeV*cube(ST.real[i].bg))*L;
1142 get_misalign(ST, ST.real[i], misalign[i], misalign_inv[i]);
1143 noalias(scratch) = prod(
transfer[i], misalign[i]);
1144 noalias(
transfer[i]) = prod(misalign_inv[i], scratch);
1153 typedef ElementSext self_t;
1155 typedef typename base_t::state_t
state_t;
1157 ElementSext(
const Config& c) : base_t(c) {}
1159 virtual ~ElementSext() {}
1160 virtual const char*
type_name()
const {
return "sextupole";}
1166 const double B3=
conf().
get<
double>(
"B3"),
1167 L =
conf().
get<
double>(
"L")*MtoMM;
1168 const int step =
conf().
get<
double>(
"step", 1.0);
1169 const bool thinlens =
conf().
get<
double>(
"thinlens", 0.0) == 1.0,
1170 dstkick =
conf().
get<
double>(
"dstkick", 1.0) == 1.0;
1173 using namespace boost::numeric::ublas;
1174 value_t invmat = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1178 last_ref_in = ST.ref;
1179 last_real_in = ST.real;
1185 const double dL = L/step;
1187 for(
size_t k=0; k<last_real_in.size(); k++) {
1189 transfer[k] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1192 double Brho = ST.real[k].Brho(),
1193 K = B3/Brho/cube(MtoMM);
1195 get_misalign(ST, ST.real[k], misalign[k], misalign_inv[k]);
1198 ST.moment0[k] = prod(misalign[k], ST.moment0[k]);
1199 noalias(scratch) = prod(misalign[k], ST.moment1[k]);
1200 ST.moment1[k] = prod(scratch, trans(misalign[k]));
1202 inverse(invmat, misalign_inv[k]);
1203 ST.moment0[k] = prod(invmat, ST.moment0[k]);
1204 noalias(scratch) = prod(invmat, ST.moment1[k]);
1205 ST.moment1[k] = prod(scratch, trans(invmat));
1208 for(
int i=0; i<step; i++){
1209 double Dx = ST.moment0[k][state_t::PS_X],
1210 Dy = ST.moment0[k][state_t::PS_Y],
1211 D2x = ST.moment1[k](state_t::PS_X, state_t::PS_X),
1212 D2y = ST.moment1[k](state_t::PS_Y, state_t::PS_Y),
1213 D2xy = ST.moment1[k](state_t::PS_X, state_t::PS_Y);
1215 GetSextMatrix(dL, K, Dx, Dy, D2x, D2y, D2xy, thinlens, dstkick,
transfer[k]);
1217 transfer[k](state_t::PS_S, state_t::PS_PS) =
1218 -2e0*M_PI/(ST.real[k].SampleLambda*ST.real[k].IonEs/MeVtoeV*cube(ST.real[k].bg))*dL;
1221 ST.moment0[k] = prod(
transfer[k], ST.moment0[k]);
1222 noalias(scratch) = prod(
transfer[k], ST.moment1[k]);
1223 ST.moment1[k] = prod(scratch, trans(
transfer[k]));
1224 ST.transmat[k] = prod(
transfer[k], ST.transmat[k]);
1227 ST.moment0[k] = prod(invmat, ST.moment0[k]);
1228 noalias(scratch) = prod(invmat, ST.moment1[k]);
1229 ST.moment1[k] = prod(scratch, trans(invmat));
1230 ST.transmat[k] = prod(invmat, ST.transmat[k]);
1235 ST.moment0[k] = prod(misalign_inv[k], ST.moment0[k]);
1236 noalias(scratch) = prod(misalign_inv[k], ST.moment1[k]);
1237 ST.moment1[k] = prod(scratch, trans(misalign_inv[k]));
1238 noalias(scratch) = prod(ST.transmat[k], misalign[k]);
1239 ST.transmat[k] = prod(misalign_inv[k], scratch);
1241 inverse(invmat, misalign_inv[k]);
1242 noalias(scratch) = prod(ST.transmat[k], invmat);
1243 inverse(invmat, misalign[k]);
1244 ST.transmat[k] = prod(invmat, scratch);
1245 ST.moment0[k] = prod(invmat, ST.moment0[k]);
1246 noalias(scratch) = prod(invmat, ST.moment1[k]);
1247 ST.moment1[k] = prod(scratch, trans(invmat));
1254 for(
size_t k=0; k<last_real_in.size(); k++)
1255 ST.real[k].phis += ST.real[k].SampleIonK*
length*MtoMM;
1259 for(
size_t k=0; k<last_real_in.size(); k++)
1260 ST.real[k].phis -= ST.real[k].SampleIonK*
length*MtoMM;
1265 last_ref_out = ST.ref;
1266 last_real_out = ST.real;
1275 typedef ElementSolenoid self_t;
1277 typedef typename base_t::state_t
state_t;
1279 ElementSolenoid(
const Config& c) : base_t(c) {}
1280 virtual ~ElementSolenoid() {}
1281 virtual const char*
type_name()
const {
return "solenoid";}
1287 const double L =
conf().
get<
double>(
"L")*MtoMM;
1288 const unsigned ncurve = get_flag(
conf(),
"ncurve", 0);
1291 std::vector<std::vector<double> > Curves;
1292 std::vector<double> Scales;
1293 GetCurveData(
conf(), ncurve, Scales, Curves);
1295 for(
size_t i=0; i<last_real_in.size(); i++) {
1297 double dL = L/double(Curves[0].size()),
1298 Brho = ST.real[i].Brho();
1299 transfer[i] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1300 for (
size_t j=0; j<Curves[0].size(); j++){
1302 for (
size_t n=0; n<Curves.size(); n++) K += Scales[n]*Curves[n][j]/(2e0*Brho)/MtoMM;
1303 value_t tmstep = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1305 GetSolMatrix(dL, K, tmstep);
1307 tmstep(state_t::PS_S, state_t::PS_PS) =
1308 -2e0*M_PI/(ST.real[i].SampleLambda*ST.real[i].IonEs/MeVtoeV*cube(ST.real[i].bg))*dL;
1312 get_misalign(ST, ST.real[i], misalign[i], misalign_inv[i]);
1313 noalias(scratch) = prod(
transfer[i], misalign[i]);
1314 noalias(
transfer[i]) = prod(misalign_inv[i], scratch);
1317 const double B =
conf().
get<
double>(
"B");
1318 for(
size_t i=0; i<last_real_in.size(); i++) {
1320 transfer[i] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1322 double Brho = ST.real[i].Brho(),
1323 K = B/(2e0*Brho)/MtoMM;
1327 transfer[i](state_t::PS_S, state_t::PS_PS) =
1328 -2e0*M_PI/(ST.real[i].SampleLambda*ST.real[i].IonEs/MeVtoeV*cube(ST.real[i].bg))*L;
1330 get_misalign(ST, ST.real[i], misalign[i], misalign_inv[i]);
1332 noalias(scratch) = prod(
transfer[i], misalign[i]);
1333 noalias(
transfer[i]) = prod(misalign_inv[i], scratch);
1342 typedef ElementEDipole self_t;
1344 typedef typename base_t::state_t
state_t;
1346 ElementEDipole(
const Config& c) : base_t(c) {}
1347 virtual ~ElementEDipole() {}
1348 virtual const char*
type_name()
const {
return "edipole";}
1358 bool ver =
conf().
get<
double>(
"ver", 0e0) == 1.0;
1359 double L =
conf().
get<
double>(
"L")*MtoMM,
1360 phi =
conf().
get<
double>(
"phi")*M_PI/180e0,
1362 fringe_x =
conf().
get<
double>(
"fringe_x", 0e0)/MtoMM,
1363 fringe_y =
conf().
get<
double>(
"fringe_y", 0e0)/MtoMM,
1364 kappa =
conf().
get<
double>(
"asym_fac", 0e0),
1366 spher =
conf().
get<
double>(
"spher"),
1369 dip_beta =
conf().
get<
double>(
"beta", ST.ref.
beta);
1371 unsigned HdipoleFitMode = get_flag(
conf(),
"HdipoleFitMode", 1);
1373 if (HdipoleFitMode != 0 && HdipoleFitMode != 1)
1374 throw std::runtime_error(SB()<<
"Undefined HdipoleFitMode: " << HdipoleFitMode);
1376 if (HdipoleFitMode) dip_beta = ST.ref.
beta;
1378 for(
size_t i=0; i<last_real_in.size(); i++) {
1379 double eta0 = (1e0/sqrt(1e0 - sqr(dip_beta)) - 1e0)/2e0,
1380 Erho = sqr(ST.real[i].beta)/ST.real[i].IonZ,
1381 Erho0 = sqr(dip_beta)/ST.ref.
IonZ,
1384 Kx = (1e0-spher+sqr(1e0+2e0*eta0))/sqr(rho),
1385 Ky = spher/sqr(rho),
1386 delta_K = (Erho/Erho0 - 1e0) - (ST.real[i].IonEk - ST.ref.
IonEk)/ST.real[i].IonEk,
1387 delta_KZ = ST.ref.
IonZ/ST.real[i].IonZ - 1e0,
1388 SampleIonK = 2e0*M_PI/(ST.real[i].beta*ST.real[i].SampleLambda);
1390 transfer[i] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1393 GetEBendMatrix(eL, phi, fringe_x, fringe_y, kappa, Kx, Ky, ST.ref.
IonEs, ST.real[i].gamma,
1394 eta0, h, delta_K, delta_KZ, SampleIonK,
transfer[i]);
1399 R = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1400 R(state_t::PS_X, state_t::PS_X) = 0e0;
1401 R(state_t::PS_PX, state_t::PS_PX) = 0e0;
1402 R(state_t::PS_Y, state_t::PS_Y) = 0e0;
1403 R(state_t::PS_PY, state_t::PS_PY) = 0e0;
1404 R(state_t::PS_X, state_t::PS_Y) = -1e0;
1405 R(state_t::PS_PX, state_t::PS_PY) = -1e0;
1406 R(state_t::PS_Y, state_t::PS_X) = 1e0;
1407 R(state_t::PS_PY, state_t::PS_PX) = 1e0;
1409 noalias(scratch) = prod(R,
transfer[i]);
1410 noalias(
transfer[i]) = prod(scratch, trans(R));
1414 get_misalign(ST, ST.real[i], misalign[i], misalign_inv[i]);
1416 noalias(scratch) = prod(
transfer[i], misalign[i]);
1417 noalias(
transfer[i]) = prod(misalign_inv[i], scratch);
1426 typedef ElementEQuad self_t;
1428 typedef typename base_t::state_t
state_t;
1430 ElementEQuad(
const Config& c) : base_t(c) {}
1431 virtual ~ElementEQuad() {}
1432 virtual const char*
type_name()
const {
return "equad";}
1438 const double L =
conf().
get<
double>(
"L")*MtoMM;
1439 const unsigned ncurve = get_flag(
conf(),
"ncurve", 0);
1442 std::vector<std::vector<double> > Curves;
1443 std::vector<double> Scales;
1444 GetCurveData(
conf(), ncurve, Scales, Curves);
1446 for(
size_t i=0; i<last_real_in.size(); i++) {
1448 double dL = L/double(Curves[0].size()),
1449 Brho = ST.real[i].Brho();
1450 transfer[i] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1451 for (
size_t j=0; j<Curves[0].size(); j++){
1453 for (
size_t n=0; n<Curves.size(); n++) K += 2e0*Scales[n]*Curves[n][j]/(C0*ST.real[i].beta)/Brho/sqr(MtoMM);
1454 value_t tmstep = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1455 GetQuadMatrix(dL, K, (
unsigned)state_t::PS_X, tmstep);
1456 GetQuadMatrix(dL, -K, (
unsigned)state_t::PS_Y, tmstep);
1458 tmstep(state_t::PS_S, state_t::PS_PS) =
1459 -2e0*M_PI/(ST.real[i].SampleLambda*ST.real[i].IonEs/MeVtoeV*cube(ST.real[i].bg))*dL;
1463 get_misalign(ST, ST.real[i], misalign[i], misalign_inv[i]);
1464 noalias(scratch) = prod(
transfer[i], misalign[i]);
1465 noalias(
transfer[i]) = prod(misalign_inv[i], scratch);
1469 const double V0 =
conf().
get<
double>(
"V"),
1470 R =
conf().
get<
double>(
"radius");
1472 for(
size_t i=0; i<last_real_in.size(); i++) {
1475 transfer[i] = boost::numeric::ublas::identity_matrix<double>(state_t::maxsize);
1477 double Brho = ST.real[i].Brho(),
1478 K = 2e0*V0/(C0*ST.real[i].beta*sqr(R))/Brho/sqr(MtoMM);
1481 GetQuadMatrix(L, K, (
unsigned)state_t::PS_X,
transfer[i]);
1483 GetQuadMatrix(L, -K, (
unsigned)state_t::PS_Y,
transfer[i]);
1487 transfer[i](state_t::PS_S, state_t::PS_PS) =
1488 -2e0*M_PI/(ST.real[i].SampleLambda*ST.real[i].IonEs/MeVtoeV*cube(ST.real[i].bg))*L;
1490 get_misalign(ST, ST.real[i], misalign[i], misalign_inv[i]);
1492 noalias(scratch) = prod(
transfer[i], misalign[i]);
1493 noalias(
transfer[i]) = prod(misalign_inv[i], scratch);
1502 typedef ElementTMatrix self_t;
1504 typedef typename base_t::state_t
state_t;
1506 ElementTMatrix(
const Config& c) : base_t(c) {}
1507 virtual ~ElementTMatrix() {}
1508 virtual const char*
type_name()
const {
return "tmatrix";}
1514 for(
size_t i=0; i<last_real_in.size(); i++) {
1522 void registerMoment()
1524 Machine::registerState<MomentState>(
"MomentMatrix");
1526 Machine::registerElement<ElementSource >(
"MomentMatrix",
"source");
1528 Machine::registerElement<ElementMark >(
"MomentMatrix",
"marker");
1530 Machine::registerElement<ElementBPM >(
"MomentMatrix",
"bpm");
1532 Machine::registerElement<ElementDrift >(
"MomentMatrix",
"drift");
1534 Machine::registerElement<ElementOrbTrim >(
"MomentMatrix",
"orbtrim");
1536 Machine::registerElement<ElementSBend >(
"MomentMatrix",
"sbend");
1538 Machine::registerElement<ElementQuad >(
"MomentMatrix",
"quadrupole");
1540 Machine::registerElement<ElementSext >(
"MomentMatrix",
"sextupole");
1542 Machine::registerElement<ElementSolenoid >(
"MomentMatrix",
"solenoid");
1544 Machine::registerElement<ElementRFCavity >(
"MomentMatrix",
"rfcavity");
1546 Machine::registerElement<ElementStripper >(
"MomentMatrix",
"stripper");
1548 Machine::registerElement<ElementEDipole >(
"MomentMatrix",
"edipole");
1550 Machine::registerElement<ElementEQuad >(
"MomentMatrix",
"equad");
1552 Machine::registerElement<ElementTMatrix >(
"MomentMatrix",
"tmatrix");
double gamma
Gamma for ion. (dependent)
virtual bool check_cache(const state_t &S) const
bool retreat
retreat (backward) simulation flag
virtual bool getArray(unsigned idx, ArrayInfo &Info)
Introspect named parameter of the derived class.
Base class for all simulated elements.
double length
Longitudual length of this element (added to StateBase::pos)
double IonW
Total energy. (dependent)
double IonEk
Kinetic energy.
virtual void show(std::ostream &strm, int level) const
virtual const char * type_name() const =0
The abstract base class for all simulation state objects.
virtual void advance(StateBase &s)
Propogate the given State through this Element.
double phis
Absolute synchrotron phase [rad].
virtual void assign(const ElementVoid *other)=0
virtual bool check_backward(const state_t &S) const
Check input state for backward propagation.
double SampleFreq
Sampling frequency [Hz].
Associative configuration container.
virtual void recompute_matrix(state_t &ST)
recalculate 'transfer' taking into consideration the provided input state
Used with StateBase::getArray() to describe a single parameter.
virtual void assign(const StateBase &other)=0
double pos
absolute longitudinal position at end of Element
virtual void assign(const ElementVoid *other)=0
virtual void assign(const StateBase &other)
const std::string name
Name of this element (unique in its Machine)
size_t dim[maxdims]
Array dimensions in elements.
const Config & conf() const
The Config used to construct this element.
double dx
constituents of misalign
bool skipcache
If set, check_cache() will always return false.
size_t size() const
of charge states
size_t stride[maxdims]
Array strides in bytes.
std::vector< value_t > transfer
final transfer matricies
double beta
Beta for ion. (dependent)
double bg
Beta*gamma. (dependent)
virtual void show(std::ostream &strm, int level) const
bool tryGet(const std::string &name, T &val) const
virtual bool getArray(unsigned index, ArrayInfo &Info)
Introspect named parameter of the derived class.
detail::RT< T >::type get(const std::string &name) const
double SampleIonK
Sample rate; different RF Cavity due to RF frequenies. (dependent)
virtual void show(std::ostream &, int level) const
void resize_cache(const state_t &ST)
const char * name
The parameter name.
An Element which propagates the statistical moments of a bunch.
double SampleLambda
Sampling distance [m].