// // Class: ThickTracker // Tracks using thick-lens algorithm. // ------------------------------------------------------------------------ // // Copyright (c) 2018, Philippe Ganz, ETH Zürich // All rights reserved // // Implemented as part of the Master thesis // "s-based maps from TPS & Lie-Series applied to Proton-Therapy Gantries" // // This file is part of OPAL. // // OPAL is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // You should have received a copy of the GNU General Public License // along with OPAL. If not, see . // #ifndef OPAL_ThickTracker_HH #define OPAL_ThickTracker_HH #include "Algorithms/Tracker.h" #include "Structure/DataSink.h" #include "Hamiltonian.h" #include "MapAnalyser.h" #include "Algorithms/IndexMap.h" #include "AbsBeamline/BeamBeam.h" #include "AbsBeamline/BeamStripping.h" #include "AbsBeamline/CCollimator.h" #include "AbsBeamline/Corrector.h" #include "AbsBeamline/Diagnostic.h" #include "AbsBeamline/Degrader.h" #include "AbsBeamline/Drift.h" #include "AbsBeamline/FlexibleCollimator.h" #include "AbsBeamline/ElementBase.h" #include "AbsBeamline/Lambertson.h" #include "AbsBeamline/Marker.h" #include "AbsBeamline/Monitor.h" #include "AbsBeamline/Multipole.h" #include "AbsBeamline/ParallelPlate.h" #include "AbsBeamline/Probe.h" #include "AbsBeamline/RFCavity.h" #include "AbsBeamline/RFQuadrupole.h" #include "AbsBeamline/RBend.h" #include "AbsBeamline/RBend3D.h" #include "AbsBeamline/SBend.h" #include "AbsBeamline/Separator.h" #include "AbsBeamline/Septum.h" #include "AbsBeamline/Solenoid.h" #include "AbsBeamline/TravelingWave.h" #include "Elements/OpalBeamline.h" #include "Structure/Beam.h" //#include #include #include class BMultipoleField; template class PartBunchBase; /// Track using thick-lens algorithm. // [p] // Phase space coordinates numbering: // [tab 3 b] // [row]number [&]name [&]unit [/row] // [row]0 [&]$x$ [&]metres [/row] // [row]1 [&]$p_x/p_r$ [&]1 [/row] // [row]2 [&]$y$ [&]metres [/row] // [row]3 [&]$p_y/p_r$ [&]1 [/row] // [row]4 [&]$v*delta_t$ [&]metres [/row] // [row]5 [&]$delta_p/p_r$ [&]1 [/row] // [/tab][p] // Where $p_r$ is the constant reference momentum defining the reference // frame velocity, $m$ is the rest mass of the particles, and $v$ is the // instantaneous velocity of the particle. // [p] // Other units used: // [tab 2 b] // [row]quantity [&]unit [/row] // [row]reference momentum [&]electron-volts [/row] // [row]velocity [&]metres/second [/row] // [row]accelerating voltage [&]volts [/row] // [row]separator voltage [&]volts [/row] // [row]frequencies [&]hertz [/row] // [row]phase lags [&]$2*pi$ [/row] // [/tab][p] // Approximations used: // [ul] // [li] // [li] // [li] // [/ul] // // On going through an element, we use the following steps: // To complete the map, we propagate the closed orbit and add that to the map. class ThickTracker: public Tracker { public: typedef Hamiltonian::series_t series_t; typedef MapAnalyser::fMatrix_t fMatrix_t; typedef MapAnalyser::cfMatrix_t cfMatrix_t; typedef FVps map_t; typedef FVector particle_t; typedef std::tuple tuple_t; typedef std::list beamline_t; public: /// Constructor. // The beam line to be tracked is "bl". // The particle reference data are taken from "data". // The particle bunch tracked is initially empty. // If [b]revBeam[/b] is true, the beam runs from s = C to s = 0. // If [b]revTrack[/b] is true, we track against the beam. explicit ThickTracker(const Beamline &bl, const PartData &data, bool revBeam, bool revTrack); /// Constructor. // The beam line to be tracked is "bl". // The particle reference data are taken from "data". // The particle bunch tracked is taken from [b]bunch[/b]. // If [b]revBeam[/b] is true, the beam runs from s = C to s = 0. // If [b]revTrack[/b] is true, we track against the beam. explicit ThickTracker(const Beamline &bl, PartBunchBase *bunch, Beam &beam, DataSink &ds, const PartData &data, bool revBeam, bool revTrack, const std::vector &maxSTEPS, double zstart, const std::vector &zstop, const std::vector &dt, const int& truncOrder); virtual ~ThickTracker(); virtual void visitAlignWrapper(const AlignWrapper &); /// Apply the algorithm to a BeamBeam. virtual void visitBeamBeam(const BeamBeam &); /// Apply the algorithm to a BeamStripping. virtual void visitBeamStripping(const BeamStripping &); /// Apply the algorithm to a collimator. virtual void visitCCollimator(const CCollimator &); /// Apply the algorithm to a Corrector. virtual void visitCorrector(const Corrector &); /// Apply the algorithm to a Degrader. virtual void visitDegrader(const Degrader &); /// Apply the algorithm to a Diagnostic. virtual void visitDiagnostic(const Diagnostic &); /// Apply the algorithm to a Drift. virtual void visitDrift(const Drift &); /// Apply the algorithm to a flexible collimator virtual void visitFlexibleCollimator(const FlexibleCollimator &); /// Apply the algorithm to a Lambertson. virtual void visitLambertson(const Lambertson &); /// Apply the algorithm to a Marker. virtual void visitMarker(const Marker &); /// Apply the algorithm to a Monitor. virtual void visitMonitor(const Monitor &); /// Apply the algorithm to a Multipole. virtual void visitMultipole(const Multipole &); /// Apply the algorithm to a Probe. virtual void visitProbe(const Probe &); /// Apply the algorithm to a RBend. virtual void visitRBend(const RBend &); /// Apply the algorithm to a RFCavity. virtual void visitRFCavity(const RFCavity &); /// Apply the algorithm to a RFCavity. virtual void visitTravelingWave(const TravelingWave &); /// Apply the algorithm to a RFQuadrupole. virtual void visitRFQuadrupole(const RFQuadrupole &); /// Apply the algorithm to a SBend. virtual void visitSBend(const SBend &); /// Apply the algorithm to a Separator. virtual void visitSeparator(const Separator &); /// Apply the algorithm to a Septum. virtual void visitSeptum(const Septum &); /// Apply the algorithm to a Solenoid. virtual void visitSolenoid(const Solenoid &); /// Apply the algorithm to a ParallelPlate. virtual void visitParallelPlate(const ParallelPlate &); /// Apply the algorithm to a beam line. // overwrite the execute-methode from DefaultVisitor virtual void visitBeamline(const Beamline &); /// Apply the algorithm to the top-level beamline. // overwrite the execute-methode from DefaultVisitor virtual void execute(); void prepareSections(); /* void insertFringeField(SBend* pSBend, std::list& mBL, double& beta0, double& gamma0, double& P0, double& q, std::array& entrFringe, std::string e); */ private: // Not implemented. ThickTracker() = delete; ThickTracker(const ThickTracker &) = delete; void operator=(const ThickTracker &) = delete; void throwElementError_m(std::string element) { throw LogicalError("ThickTracker::execute()", "Element '" + element + "' not supported."); } /*! * Tests the order of the elements in the beam line according to their position */ void checkElementOrder_m(); /*! * Inserts Drift maps in undefined beam line sections */ void fillGaps_m(); /*! * Tracks itsBunch_m trough beam line */ void track_m(); particle_t particleToVector_m(const Vector_t& R, const Vector_t& P) const; void vectorToParticle_m(const particle_t& particle, Vector_t& R, Vector_t& P) const; /*! * Advances itsBunch_m trough map * @param map Map of slice */ void advanceParticles_m(const map_t& map); /*! * Applies map on particle * @param particle tracked particle * @param map Map of slice */ void updateParticle_m(particle_t& particle, const map_t& map); /*! * Dumps bunch in .stat or .h5 files */ void dump_m(); /*! * Updates itsBunch_m * @param spos position of tracking * @param step stepsize of applied map */ void update_m(const double& spos, const std::size_t& step); /*! * Writes map (Transfermap) in .map file * @map text for .map file */ void write_m(const map_t& map); /*! * Concatenate map x and y * \f[ * y = x \circ y * \f] * @param x * @param y is result */ void concatenateMaps_m(const map_t& x, map_t& y); /*! * Tracks Dispersion along beam line * writes it in .dispersion file. * * \f[ * \begin{pmatrix} \eta_{x} \\ \eta_{p_x} \end{pmatrix}_{s_1} * = * \begin{pmatrix} R_{11} & R_{12} \\ R_{21} & R_{22} \end{pmatrix} * \cdot * \begin{pmatrix} \eta_{x} \\ \eta_{p_x} \end{pmatrix}_{s_0} * + * \begin{pmatrix} R_{16} \\ R_{26} \end{pmatrix} * \f] * * @param tempMatrix accumulated Transfer map \f$R\f$ at pos * @param initialVal initial Dispersion { \f$\eta_{x0},\, \eta_{p_x0},\, \eta_{y0},\, \eta_{p_y0} \f$} * @param pos position of tracking */ void advanceDispersion_m(fMatrix_t tempMatrix, FMatrix initialVal, double pos); /*! :TODO: * Fringe fields for entrance of SBEND. * * @param edge * @param curve * @param field * @param scale */ void applyEntranceFringe(double edge, double curve, const BMultipoleField &field, double scale); /*! :TODO: * Fringe fields for exit of SBEND. * * @param edge * @param curve * @param field * @param scale */ void applyExitFringe(double edge, double curve, const BMultipoleField &field, double scale); Hamiltonian hamiltonian_m; MapAnalyser mapAnalyser_m; Vector_t RefPartR_m; Vector_t RefPartP_m; DataSink *itsDataSink_m; OpalBeamline itsOpalBeamline_m; double zstart_m; ///< Start of beam line double zstop_m; ///< End of beam line double threshold_m; ///< Threshold for element overlaps and gaps beamline_t elements_m; ///< elements in beam line CoordinateSystemTrafo referenceToLabCSTrafo_m; int truncOrder_m; ///< truncation order of map tracking IpplTimings::TimerRef mapCreation_m; ///< creation of elements_m IpplTimings::TimerRef mapCombination_m; ///< map accumulation along elements_m -> Transfermap IpplTimings::TimerRef mapTracking_m; ///< track particles trough maps of elements_m }; inline void ThickTracker::visitAlignWrapper(const AlignWrapper &/*wrap*/) { // itsOpalBeamline_m.visit(wrap, *this, itsBunch_m); this->throwElementError_m("AlignWrapper"); } inline void ThickTracker::visitBeamBeam(const BeamBeam &/*bb*/) { // itsOpalBeamline_m.visit(bb, *this, itsBunch_m); this->throwElementError_m("BeamBeam"); } inline void ThickTracker::visitBeamStripping(const BeamStripping &bstp) { itsOpalBeamline_m.visit(bstp, *this, itsBunch_m); } inline void ThickTracker::visitCCollimator(const CCollimator &/*coll*/) { // itsOpalBeamline_m.visit(coll, *this, itsBunch_m); this->throwElementError_m("CCollimator"); } inline void ThickTracker::visitCorrector(const Corrector &/*coll*/) { // itsOpalBeamline_m.visit(corr, *this, itsBunch_m); this->throwElementError_m("Corrector"); } inline void ThickTracker::visitDegrader(const Degrader &/*deg*/) { // itsOpalBeamline_m.visit(deg, *this, itsBunch_m); this->throwElementError_m("Degrader"); } inline void ThickTracker::visitDiagnostic(const Diagnostic &/*diag*/) { // itsOpalBeamline_m.visit(diag, *this, itsBunch_m); this->throwElementError_m("Diagnostic"); } inline void ThickTracker::visitDrift(const Drift &drift) { itsOpalBeamline_m.visit(drift, *this, itsBunch_m); double gamma = itsReference.getGamma(); std::size_t nSlices = drift.getNSlices(); double length = drift.getElementLength(); elements_m.push_back(std::make_tuple(hamiltonian_m.drift(gamma), nSlices, length)); } inline void ThickTracker::visitFlexibleCollimator(const FlexibleCollimator &/*coll*/) { // itsOpalBeamline_m.visit(coll, *this, itsBunch_m); this->throwElementError_m("FlexibleCollimator"); } inline void ThickTracker::visitLambertson(const Lambertson &/*lamb*/) { // itsOpalBeamline_m.visit(lamb, *this, itsBunch_m); this->throwElementError_m("Lambertson"); } inline void ThickTracker::visitMarker(const Marker &/*marker*/) { // itsOpalBeamline_m.visit(marker, *this, itsBunch_m); // this->throwElementError_m("Marker"); } inline void ThickTracker::visitMonitor(const Monitor &/*mon*/) { // itsOpalBeamline_m.visit(mon, *this, itsBunch_m); this->throwElementError_m("Monitor"); } inline void ThickTracker::visitMultipole(const Multipole &mult) { itsOpalBeamline_m.visit(mult, *this, itsBunch_m); std::size_t nSlices = mult.getNSlices(); double length = mult.getElementLength(); double gamma = itsReference.getGamma(); double p0 = itsReference.getP(); double q = itsReference.getQ(); // particle change [e] double gradB = mult.getField().getNormalComponent(2) * ( Physics::c/ p0 ); // [T / m] //FIXME remove the next line gradB = std::round(gradB*1e6)*1e-6; double k1 = gradB * q *Physics::c / p0; // [1 / m^2] elements_m.push_back(std::make_tuple(hamiltonian_m.quadrupole(gamma, q, k1), nSlices, length)); } inline void ThickTracker::visitProbe(const Probe &/*probe*/) { // itsOpalBeamline_m.visit(prob, *this, itsBunch_m); this->throwElementError_m("Probe"); } inline void ThickTracker::visitRBend(const RBend &/*bend*/) { // itsOpalBeamline_m.visit(bend, *this, itsBunch_m); this->throwElementError_m("RBend"); } inline void ThickTracker::visitRFCavity(const RFCavity &/*as*/) { // itsOpalBeamline_m.visit(as, *this, itsBunch_m); this->throwElementError_m("RFCavity"); } inline void ThickTracker::visitTravelingWave(const TravelingWave &/*as*/) { // itsOpalBeamline_m.visit(as, *this, itsBunch_m); this->throwElementError_m("TravelingWave"); } inline void ThickTracker::visitRFQuadrupole(const RFQuadrupole &/*rfq*/) { // itsOpalBeamline_m.visit(rfq, *this, itsBunch_m); this->throwElementError_m("RFQuadrupole"); } inline void ThickTracker::visitSBend(const SBend &bend) { itsOpalBeamline_m.visit(bend, *this, itsBunch_m); double q = itsReference.getQ(); // particle change [e] double ekin = bend.getDesignEnergy(); double m = itsReference.getM(); // eV / c^2 double gamma = ekin / m + 1.0; double beta = std::sqrt(1.0 - 1.0 / ( gamma * gamma ) ); double p0 = gamma * beta * m; // eV / c double B = bend.getB() * Physics::c / p0; // T = V * s / m^2 double r = std::abs(p0 / ( q * B * Physics::c )); // m double k0 = B * q * Physics::c / p0; // V * s * e * m / (m^2 * s * c ) // [1/m] double h = 1.0 / r; double L = bend.getElementLength(); if ( k0 < 0.0 ) h *= -1.0; std::size_t nSlices = bend.getNSlices(); double arclength = 2.0 * r * std::asin( L / ( 2.0 * r ) ); //bend.getEffectiveLength(); // Fringe fields currently not working //FIXME e1 not initialised //insert Entrance Fringefield double e1 = bend.getEntranceAngle(); if (std::abs(e1) > 1e-6){ elements_m.push_back(std::make_tuple(hamiltonian_m.fringeField(e1, h), 1, 0.0)); } //insert Dipole "body" elements_m.push_back(std::make_tuple(hamiltonian_m.sbend(gamma, h, k0), nSlices, arclength)); //FIXME e2 not initialised //insert Exit Fringe field double e2 = bend.getExitAngle(); if (std::abs(e2) > 1e-6){ elements_m.push_back(std::make_tuple(hamiltonian_m.fringeField(e2, h), 1, 0.0)); } } inline void ThickTracker::visitSeparator(const Separator &/*sep*/) { // itsOpalBeamline_m.visit(sep, *this, itsBunch_m); this->throwElementError_m("Separator"); } inline void ThickTracker::visitSeptum(const Septum &/*sept*/) { // itsOpalBeamline_m.visit(sept, *this, itsBunch_m); this->throwElementError_m("Septum"); } inline void ThickTracker::visitSolenoid(const Solenoid &/*solenoid*/) { // itsOpalBeamline_m.visit(solenoid, *this, itsBunch_m); this->throwElementError_m("Solenoid"); } inline void ThickTracker::visitParallelPlate(const ParallelPlate &/*pplate*/) { // itsOpalBeamline_m.visit(pplate, *this, itsBunch_m); this->throwElementError_m("ParallelPlate"); } #endif // OPAL_ThickTracker_HH