19
BASEparticle::BASEparticle() : TransferMatrixGenerator("BASEparticle"), usingLattice(false) {
20
Matrix<double> TransferMatrixGenerator::getKineticMatrix() const {
21
Matrix<double> shift(4,4,0.0);
22
shift(1,1) = 1.0/sigma;
23
shift(2,2) = 1.0/sigma;
24
shift(3,3) = 1.0/refMomentum;
25
shift(4,4) = 1.0/refMomentum;
26
shift(3,2) = -getIntegrator()->getBField(getZIn())*lightSpeed*muonCharge/(2.e6*refMomentum);
27
shift(4,1) = getIntegrator()->getBField(getZIn())*lightSpeed*muonCharge/(2.e6*refMomentum);
29
Matrix<double> back(4,4,0.0);
32
back(3,3) = refMomentum;
33
back(4,4) = refMomentum;
34
back(3,2) = getIntegrator()->getBField(getZOut())*lightSpeed*muonCharge/2.e6;
35
back(4,1) = -getIntegrator()->getBField(getZOut())*lightSpeed*muonCharge/2.e6;
37
Matrix<double> tran = getTransferMatrix();
39
return back * tran * shift;
42
BASEparticle::BASEparticle(double zIn, double zOut, double refMom) : TransferMatrixGenerator("BASEparticle",zIn,zOut,refMom), usingLattice(false) {
20
43
getCurrentStream() << "Constructing BASEparticle" << std::endl;
22
45
particlesRun = false;
79
void BASEparticle::runParticles(double zOut) {
102
void BASEparticle::runParticles() {
80
103
if (usingLattice) {
81
104
getCurrentStream() << "Running reference particle" << std::endl;
82
105
trackedReference = new double[8];
83
106
for (int i = 0; i < 8; i++)
84
107
trackedReference[i] = inReference[i];
85
BTTracker::integrate(zOut,trackedReference,getLattice()->getFieldGroup(),BTTracker::z, stepSize, 1.0);
108
BTTracker::integrate(getZOut(),trackedReference,getLattice()->getFieldGroup(),BTTracker::z, stepSize, -1.0);
86
109
getCurrentStream() << "Running all particles" << std::endl;
87
110
trackedParticles = new double[8*numberOfParticles];
88
111
for (int i = 0; i < 8*numberOfParticles; i++)
89
112
trackedParticles[i] = inParticles[i];
90
113
for (int i = 0; i < numberOfParticles; i++)
91
BTTracker::integrate(zOut,trackedParticles + (i*8),getLattice()->getFieldGroup(),BTTracker::z, stepSize, 1.0);
114
BTTracker::integrate(getZOut(),trackedParticles + (i*8),getLattice()->getFieldGroup(),BTTracker::z, stepSize, -1.0);
92
115
particlesRun = true;
94
117
for (int i = 0; i < numberOfParticles; i++) {
306
329
properCoords[0] = 0.;
307
330
properCoords[1] = coordsIn[0]*sigma;
308
331
properCoords[2] = coordsIn[1]*sigma;
309
std::vector<double> A1 = integrator->getVectorPotentialAnalytic(properCoords[0],properCoords[1],zIn);
310
properCoords[3] = zIn;
332
std::vector<double> A1 = integrator->getVectorPotentialAnalytic(properCoords[0],properCoords[1],getZIn());
333
properCoords[3] = getZIn();
311
334
properCoords[4] = refEnergy;
312
335
properCoords[5] = coordsIn[2]*refMomentum - A1[0]*lightSpeed/1.0e-6;
313
336
properCoords[6] = coordsIn[3]*refMomentum - A1[1]*lightSpeed/1.0e-6;
314
337
properCoords[7] = std::sqrt(refEnergy*refEnergy - properCoords[5]*properCoords[5] - properCoords[6]*properCoords[6]);
315
BTTracker::integrate(zOut,properCoords,getLattice()->getFieldGroup(),BTTracker::z, stepSize, 1.0);
316
std::vector<double> A2 = integrator->getVectorPotentialAnalytic(properCoords[0],properCoords[1],zOut);
338
BTTracker::integrate(getZOut(),properCoords,getLattice()->getFieldGroup(),BTTracker::z, stepSize, 1.0);
339
std::vector<double> A2 = integrator->getVectorPotentialAnalytic(properCoords[0],properCoords[1],getZOut());
317
340
coordsOut[0] = properCoords[1]/sigma;
318
341
coordsOut[1] = properCoords[2]/sigma;
319
342
coordsOut[2] = (properCoords[5] + A2[0]*lightSpeed/1.0e-6)/sigma;
396
419
double py2 = v_hit2["momentum"]["y"].asDouble();
397
420
double z2 = v_hit2["position"]["z"].asDouble();
399
//conversion to canonical momenta
400
std::vector<double> A1 = integrator->getVectorPotentialAnalytic(x1,y1,z1);
401
std::vector<double> A2 = integrator->getVectorPotentialAnalytic(x2,y2,z2);
403
//from T m * {fundamental charge unit} -> MeV/c is lightSpeed (m s^-1) / 1,000,000
404
px1 += A1[0] * lightSpeed / 1.0e6;
405
py1 += A1[1] * lightSpeed / 1.0e6;
406
px2 += A2[0] * lightSpeed / 1.0e6;
407
py2 += A2[1] * lightSpeed / 1.0e6;
409
//rescaling to dimensionless MARYLIE variables
419
/*getCurrentStream() << "Particle IN: z = " << step1["position"]["z"] << std::endl;
420
getCurrentStream() << "x = " << x1 << " y = " << y1 << " px = " << px1 << " py = " << py1 << std::endl;
421
getCurrentStream() << "Particle OUT: z = " << step2["position"]["z"] << std::endl;
422
getCurrentStream() << "x = " << x2 << " y = " << y2 << " px = " << px2 << " py = " << py2 << "\n" << std::endl;*/
424
std::vector<double> phaseCoordIn(4);
425
std::vector<double> phaseCoordOut(4);
427
phaseCoordIn[0] = x1;
428
phaseCoordIn[1] = y1;
429
phaseCoordIn[2] = px1;
430
phaseCoordIn[3] = py1;
432
phaseCoordOut[0] = x2;
433
phaseCoordOut[1] = y2;
434
phaseCoordOut[2] = px2;
435
phaseCoordOut[3] = py2;
422
std::vector<double> phaseCoordIn = convertToPhaseSpaceCoords(x1,y1,px1,py1,z1,refMom,integrator);
423
std::vector<double> phaseCoordOut = convertToPhaseSpaceCoords(x2,y2,px2,py2,z2,refMom,integrator);
437
425
std::pair<std::vector<double>, std::vector<double> > retval(phaseCoordIn, phaseCoordOut);
454
443
double py2 = particlesOut[6];
455
444
double z2 = particlesOut[3];
457
//conversion to canonical momenta
458
std::vector<double> A1 = integrator->getVectorPotentialAnalytic(x1,y1,z1);
459
std::vector<double> A2 = integrator->getVectorPotentialAnalytic(x2,y2,z2);
461
//from T m * {fundamental charge unit} -> MeV/c is lightSpeed (m s^-1) / 1,000,000
462
px1 += A1[0] * lightSpeed / 1.0e6;
463
py1 += A1[1] * lightSpeed / 1.0e6;
464
px2 += A2[0] * lightSpeed / 1.0e6;
465
py2 += A2[1] * lightSpeed / 1.0e6;
467
//rescaling to dimensionless MARYLIE variables
477
/*getCurrentStream() << "Particle IN: z = " << step1["position"]["z"] << std::endl;
478
getCurrentStream() << "x = " << x1 << " y = " << y1 << " px = " << px1 << " py = " << py1 << std::endl;
479
getCurrentStream() << "Particle OUT: z = " << step2["position"]["z"] << std::endl;
480
getCurrentStream() << "x = " << x2 << " y = " << y2 << " px = " << px2 << " py = " << py2 << "\n" << std::endl;*/
447
std::vector<double> phaseCoordIn = convertToPhaseSpaceCoords(x1,y1,px1,py1,z1,refMom,integrator);
448
std::vector<double> phaseCoordOut = convertToPhaseSpaceCoords(x2,y2,px2,py2,z2,refMom,integrator);
450
std::pair<std::vector<double>, std::vector<double> > retval(phaseCoordIn, phaseCoordOut);
482
453
std::vector<double> phaseCoordIn(4);
483
454
std::vector<double> phaseCoordOut(4);
456
phaseCoordIn[0] = particlesIn[1];
457
phaseCoordIn[1] = particlesIn[2];
458
phaseCoordIn[2] = particlesIn[5];
459
phaseCoordIn[3] = particlesIn[6];
461
//final kinetic variables
462
phaseCoordOut[0] = particlesOut[1];
463
phaseCoordOut[1] = particlesOut[2];
464
phaseCoordOut[2] = particlesOut[5];
465
phaseCoordOut[3] = particlesOut[6];
467
std::pair<std::vector<double>, std::vector<double> > retval(phaseCoordIn, phaseCoordOut);
473
std::vector<double> BASEparticle::convertToPhaseSpaceCoords(double x, double y, double px, double py, double z, double refMom, BfieldIntegrator* integ) {
474
std::vector<double> phaseCoord(4);
475
//conversion to canonical momenta
476
std::vector<double> A = integ->getVectorPotential(x,y,z);
478
//from T m * {fundamental charge unit} -> MeV/c is lightSpeed (m s^-1) / 1,000,000
479
px += muonCharge * A[0] * lightSpeed / 1.0e6;
480
py += muonCharge * A[1] * lightSpeed / 1.0e6;
482
//rescaling to dimensionless MARYLIE variables
496
std::vector<double> BASEparticle::convertToPhaseSpaceCoords(std::vector<double> v, double z, double refMom, BfieldIntegrator* integ) {
497
return convertToPhaseSpaceCoords(v[0],v[1],v[2],v[3],z,refMom,integ);
500
std::vector<double> BASEparticle::convertToKineticCoords(double x, double y, double px, double py, double z, double refMom, BfieldIntegrator* integ) {
501
std::vector<double> kinCoord(4);
502
//conversion to canonical momenta
503
std::vector<double> A = integ->getVectorPotential(x,y,z);
485
phaseCoordIn[0] = x1;
486
phaseCoordIn[1] = y1;
487
phaseCoordIn[2] = px1;
488
phaseCoordIn[3] = py1;
510
//from T m * {fundamental charge unit} -> MeV/c is lightSpeed (m s^-1) / 1,000,000
511
px -= muonCharge * A[0] * lightSpeed / 1.0e6;
512
py -= muonCharge * A[1] * lightSpeed / 1.0e6;
514
//rescaling to dimensionless MARYLIE variables
490
phaseCoordOut[0] = x2;
491
phaseCoordOut[1] = y2;
492
phaseCoordOut[2] = px2;
493
phaseCoordOut[3] = py2;
495
std::pair<std::vector<double>, std::vector<double> > retval(phaseCoordIn, phaseCoordOut);
525
std::vector<double> BASEparticle::convertToKineticCoords(std::vector<double> v, double z, double refMom, BfieldIntegrator* integ) {
526
return convertToKineticCoords(v[0],v[1],v[2],v[3],z,refMom,integ);
511
Matrix<double> TransferMatrixGenerator::getFirstOrderEllipse() {
512
return EmittanceCalculator::getEllipseFromMap(getTransferMatrix());
515
std::pair<double,double> TransferMatrixGenerator::getActionAngleCoordinates(double x, double px) {
516
Matrix<double> ellipse = getFirstOrderEllipse();
517
std::pair<Vector<complex>, Matrix<complex> > eig = eigensystem(ellipse);
518
Vector<double> realVal = real(eig.first);
519
Vector<double> imagVal = real(eig.first);
520
Matrix<double> realOrth = real(eig.second);
521
Matrix<double> imagOrth = real(eig.second);
522
for (int i = 1; i <= 4; i++) {
523
if (imagVal(i) != 0.0) throw std::runtime_error("LieMap::getActionAngleCoordinates() - eigenvalues are not pure real");
524
for (int j = 1; j <= 4; j++) {
525
if (imagOrth(i,j) != 0.0) throw std::runtime_error("LieMap::getActionAngleCoordinates() - eigenvectors are not pure real");
540
double TransferMatrixGenerator::getEmittance(double x, double y, double px, double py) {
541
Matrix<double> mat = getKineticMatrix();
542
double phi = std::acos((mat(1,1) + mat(3,3))/2.);
543
if (mat(1,3) < 0.0) phi = 2.*M_PI - phi;
544
double alpha = (mat(1,1) - mat(3,3))/(2.*std::sin(phi));
545
double beta = mat(1,3)/std::sin(phi);
546
double gamma = -mat(3,1)/std::sin(phi);
547
if (std::abs(beta*gamma - alpha*alpha - 1.) > 1.e-9) {
548
std::cerr << "beta*gamma - alpha*alpha = " << beta*gamma - alpha*alpha << std::endl;
549
throw std::runtime_error("Symplectic condition beta*gamma = 1 + alpha^2 not satisfied - was there an overal Larmor rotation (method only currently implemented for cells which have a null integral of Bfield)");
528
Vector<double> coords(2,0.0);
531
Vector<double> ellipseCoords = realOrth * coords;
532
Vector<double> circleCoords(2,0.0);
533
circleCoords(1) = ellipseCoords(1) * std::sqrt(realVal(1));
534
circleCoords(2) = ellipseCoords(2) * std::sqrt(realVal(2));
535
std::pair<double, double> ret;
536
ret.first = circleCoords(1)*circleCoords(1) + circleCoords(2)*circleCoords(2);
537
ret.second = std::atan(circleCoords(2)/circleCoords(1));
551
double emx = gamma*x*x + 2.*alpha*x*px + beta*px*px;
552
double emy = gamma*y*y + 2.*alpha*y*py + beta*py*py;
553
double em = std::sqrt(emx + emy);
554
//std::cerr << "alpha = " << alpha << " beta = " << beta << " gamma = " << gamma << " emittance = " << em << std::endl;
558
double TransferMatrixGenerator::getEmittance(std::vector<double> v) {
559
return this->getEmittance(v[0],v[1],v[2],v[3]);
562
double TransferMatrixGenerator::getPhaseAdvance() {
563
Matrix<double> mat = getKineticMatrix();
564
double phi = std::acos((mat(1,1) + mat(3,3))/2.);
565
return (mat(1,3) > 0.) ? phi : (2.*M_PI - phi);
541
568
void saveEllipseDataToFile(TransferMatrixGenerator* map, double zIn, double zOut, std::vector<double> initialScales, const char* filename) {
553
580
double* coords = new double[4];
554
581
coords[0] = initialScales[i];
556
coords[2] = initialScales[i];
583
coords[2] = initialScales[i]/1.414;
584
coords[3] = -initialScales[i]/1.414;
558
585
double* coordsOut = new double[4];
559
586
for (int j = 0; j <= timesRoundEllipse; j++) {
560
map->advanceCell(coords, coordsOut,zIn,zOut);
562
if (coordsOut[0] > 1. || coordsOut[2] > 1.) break;
563
std::pair<double, double> actAng = map->getActionAngleCoordinates(coordsOut[0],coordsOut[2]);
564
stream << coordsOut[0]*std::cos(coordsOut[2]) << "\t" << coordsOut[0]*std::sin(coordsOut[2]) << "\n";
587
map->advanceCell(coords, coordsOut);
589
std::vector<double> kinCoords = BASEparticle::convertToKineticCoords(std::vector<double>(coordsOut,coordsOut+4),zOut,refMomentum,map->getIntegrator());
590
double emittance = map->getEmittance(kinCoords);
591
if (std::isnan(emittance)) break;
592
double phase = atan2(kinCoords[2], kinCoords[0]);
593
if (j == 0) std::cerr << "Phase advance = " << phase << std::endl;
594
stream << emittance*std::cos(phase) << "\t" << emittance*std::sin(phase) << "\n";
567
597
coords = coordsOut;