diff --git a/README.md b/README.md index 99f53d6..03008d0 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Ele: "qf" (b1>>2) Quadrupole 1 false 0.0 0.34 Kn1 0.0 Ks1 (1/m^2) -0.011341179236737171 Bn1 -0.0 Bs1 (T/m^1) EMultipoleGroup: No electric multipoles - FloorPositionGroup: + OrientationGroup: r (r_floor) [0.0, 0.0, 0.0] m q (q_floor) 1.0 + 0.0⋅i + 0.0⋅j + 0.0⋅k theta (theta_floor) 0.0 rad diff --git a/manual/attic/Notes.txt b/manual/attic/Notes.txt index 02178f9..74e269e 100644 --- a/manual/attic/Notes.txt +++ b/manual/attic/Notes.txt @@ -71,7 +71,7 @@ Note: Could also have defined parameters to be Union{Float64,Missing} but this p * Implementation note: Bookkeeping is element-by-element rather then parameter group by parameter group since the parameter groups are not necessarily independent. For example, the reference time will depend upon -the FloorPositionGroup if the lattice contains a flexible patch. +the OrientationGroup if the lattice contains a flexible patch. * Using Strings for the keys of ele.pdict[] would have worked instead of Symbols. Using Symbols gives a slightly cleaner look to the code. diff --git a/manual/coordinates.tex b/manual/coordinates.tex index 8f8748d..ff71903 100644 --- a/manual/coordinates.tex +++ b/manual/coordinates.tex @@ -114,7 +114,7 @@ \section{Branch Coordinates Construction} branch coordinate system starts at the \vn{BeginningEle} element (\sref{s:begin.ele}) at the start of a branch. If the branch is a \vn{root} branch (\sref{s:lattice.def}), The orientation of the beginning element within the floor coordinate system (\sref{s:coords}) can be fixed by setting -\vn{FloorPositionGroup parameters} (\sref{s:floor.position.g}) in the \vn{BeginningEle} element. +\vn{OrientationGroup parameters} (\sref{s:orientationition.g}) in the \vn{BeginningEle} element. If the branch is not a \vn{root} branch, the position of the beginning element is determined by the position of the \vn{Fork} element from which the branch forks from. The default value of $s$ at the \vn{BeginningEle} element is zero diff --git a/manual/ele-anatomy.tex b/manual/ele-anatomy.tex index 1dd71de..17c7bb9 100644 --- a/manual/ele-anatomy.tex +++ b/manual/ele-anatomy.tex @@ -87,7 +87,7 @@ \section{Element Parameter Groups} • ApertureGroup -> Vacuum chamber aperture. • BMultipoleGroup -> Magnetic multipoles. • EMultipoleGroup -> Electric multipoles. - • FloorPositionGroup -> Floor position and orientation. + • OrientationGroup -> Floor position and orientation. • LengthGroup -> Length and s-position parameters. • LordSlaveGroup -> Element lord and slave status. • MasterGroup -> Contains field_master parameter. @@ -135,7 +135,7 @@ \section{Element Parameters} \begin{example} julia> info(:theta) User name: theta_floor - Stored in: FloorPositionGroup.theta + Stored in: OrientationGroup.theta Parameter type: Number Units: rad Description: Element floor theta angle orientation @@ -145,9 +145,9 @@ \section{Element Parameters} @ele bg = BeginningEle(theta_floor = 0.3) # Set at element definition time. bg.theta_floor = 2.7 # Or set after definition. \end{example} -But the component in the \vn{FloorPositionGroup} is \vn{theta} so +But the component in the \vn{OrientationGroup} is \vn{theta} so \begin{example} - bg.FloorPositionGroup.theta = 2.7 # Equivalent to the set above. + bg.OrientationGroup.theta = 2.7 # Equivalent to the set above. \end{example} %--------------------------------------------------------------------------------------------------- diff --git a/manual/ele-param-groups.tex b/manual/ele-param-groups.tex index de9cac3..4a4c3d1 100644 --- a/manual/ele-param-groups.tex +++ b/manual/ele-param-groups.tex @@ -12,18 +12,18 @@ \chapter{Element Parameter Groups} \begin{tabular}{llll} \toprule {\it Group} & {\it Section} & {\it Group} & {\it Section} \\ \midrule - ACKickerGroup & \sref{s:ackicker.g} & InitParticleGroup & \sref{s:init.particle.g} \\ - AlignmentGroup & \sref{s:alignment.g} & LengthGroup & \sref{s:length.g} \\ - ApertureGroup & \sref{s:aperture.g} & LordSlaveStatusGroup & \sref{s:lord.slave.g} \\ - BMultipoleGroup & \sref{s:bmultipole.g} & MasterGroup & \sref{s:master.g} \\ + ACKickerGroup & \sref{s:ackicker.g} & LengthGroup & \sref{s:length.g} \\ + AlignmentGroup & \sref{s:alignment.g} & LordSlaveStatusGroup & \sref{s:lord.slave.g} \\ + ApertureGroup & \sref{s:aperture.g} & MasterGroup & \sref{s:master.g} \\ + BMultipoleGroup & \sref{s:bmultipole.g} & OrientationGroup & \sref{s:orientation.g} \\ BeamBeamGroup & \sref{s:beam.beam.g} & OriginEleGroup & \sref{s:origin.ele.g} \\ BendGroup & \sref{s:bend.g} & PatchGroup & \sref{s:patch.g} \\ DescriptionGroup & \sref{s:descrip.g} & RFGroup & \sref{s:rf.g} \\ DownstreamReferenceGroup & \sref{s:dreference.g} & RFAutoGroup & \sref{s:rfauto.g} \\ EMultipoleGroup & \sref{s:emultipole.g} & ReferenceGroup & \sref{s:reference.g} \\ - FloorPositionGroup & \sref{s:floor.pos.g} & SolenoidGroup & \sref{s:solenoid.g} \\ - ForkGroup & \sref{s:fork.g} & TrackingGroup & \sref{s:tracking.g} \\ - GirderGroup & \sref{s:girder.g} & TwissGroup & \sref{s:twiss.g} \\ + ForkGroup & \sref{s:fork.g} & SolenoidGroup & \sref{s:solenoid.g} \\ + GirderGroup & \sref{s:girder.g} & TrackingGroup & \sref{s:tracking.g} \\ + InitParticleGroup & \sref{s:init.particle.g} & TwissGroup & \sref{s:twiss.g} \\ \bottomrule \end{tabular} } @@ -771,21 +771,6 @@ \section{EMultipoleGroup} Similarly, the setting of the \vn{field_master} parmeter (\sref{s:master.g}) will determine whether normalized or unnormalized quantities will stay constant if the reference energy is varied. -%--------------------------------------------------------------------------------------------------- -\section{FloorPositionGroup} -\label{s:floor.pos.g} - -The \vn{FloorPositionGroup} stores the nominal (calculated without alignment shifts) -position and orientation in the floor coordinates of the upstream end of the element. -system. The components of this group are: -\begin{example} - r::Vector - [x,y,z] position. Accessed using \vn{r_floor} - q::Quaternion - Quaternion orientation. Accessed using \vn{q_floor}. -\end{example} - - - - %--------------------------------------------------------------------------------------------------- \section{ForkGroup} \label{s:fork.g} @@ -883,6 +868,21 @@ \section{MasterGroup} field_master::Bool = false # Does field or normalized field stay constant with energy changes? \end{example} +%--------------------------------------------------------------------------------------------------- +\section{OrientationGroup} +\label{s:orientation.g} + +The \vn{OrientationGroup} stores the nominal (calculated without alignment shifts) +position and angular orientation in the floor coordinates of the upstream end of the element. +system. The components of this group are: +\begin{example} + r::Vector - [x,y,z] position. Accessed using \vn{r_floor} + q::Quaternion - Quaternion orientation. Accessed using \vn{q_floor}. +\end{example} + + + + %--------------------------------------------------------------------------------------------------- \section{OriginEleGroup} \label{s:origin.ele.g} diff --git a/manual/ele-types.tex b/manual/ele-types.tex index 7a0c2f5..42a82a9 100644 --- a/manual/ele-types.tex +++ b/manual/ele-types.tex @@ -52,7 +52,7 @@ \section{ACKicker} AlignmentGroup -> Element position/orientation shift. \sref{s:align.g} ApertureGroup -> Vacuum chamber aperture. \sref{s:aperture.g} BMultipoleGroup -> Magnetic multipoles. \sref{s:bmultipole.g} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} LordSlaveGroup -> Element lord and slave status. \sref{s:lord.slave.g} MasterGroup -> Contains field_master parameter. \sref{s:master.g} @@ -88,7 +88,7 @@ \section{BeamBeam} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} LordSlaveGroup -> Element lord and slave status. \sref{s:lord.slave.g} DescriptionGroup -> Element descriptive strings. \sref{s:descrip.g} @@ -111,7 +111,7 @@ \section{BeginningEle} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} InitParticleGroup -> Initial particle position and spin. \sref{s:init.particle.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} LordSlaveGroup -> Element lord and slave status. \sref{s:lord.slave.g} @@ -148,7 +148,7 @@ \section{Bend} BMultipoleGroup -> Magnetic multipoles. \sref{s:bmultipole.g} BendGroup -> Bend element parameters. \sref{s:bend.g} EMultipoleGroup -> Electric multipoles. \sref{s:emultipole.g} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} LordSlaveGroup -> Element lord and slave status. \sref{s:lord.slave.g} MasterGroup -> Contains field_master parameter. \sref{s:master.g} @@ -195,7 +195,7 @@ \section{Collimator} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} LordSlaveGroup -> Element lord and slave status. \sref{s:lord.slave.g} DescriptionGroup -> Element descriptive strings. \sref{s:descrip.g} @@ -217,7 +217,7 @@ \section{Converter} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} LordSlaveGroup -> Element lord and slave status. \sref{s:lord.slave.g} DescriptionGroup -> Element descriptive strings. \sref{s:descrip.g} @@ -240,7 +240,7 @@ \section{CrabCavity} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} LordSlaveGroup -> Element lord and slave status. \sref{s:lord.slave.g} DescriptionGroup -> Element descriptive strings. \sref{s:descrip.g} @@ -260,7 +260,7 @@ \section{Drift} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} LordSlaveGroup -> Element lord and slave status. \sref{s:lord.slave.g} DescriptionGroup -> Element descriptive strings. \sref{s:descrip.g} @@ -282,7 +282,7 @@ \section{EGun} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} LordSlaveGroup -> Element lord and slave status. \sref{s:lord.slave.g} DescriptionGroup -> Element descriptive strings. \sref{s:descrip.g} @@ -306,7 +306,7 @@ \section{Fiducial} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} LordSlaveGroup -> Element lord and slave status. \sref{s:lord.slave.g} DescriptionGroup -> Element descriptive strings. \sref{s:descrip.g} @@ -361,7 +361,7 @@ \section{Fork} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} DescriptionGroup -> Element descriptive strings. \sref{s:descrip.g} TrackingGroup -> Default tracking settings. \sref{s:tracking.g} @@ -559,7 +559,7 @@ \section{Girder} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorPositionGroup -> Floor floor position and orientation. \sref{s:floor.pos.g} + OrientationGroup -> Floor floor position and orientation. \sref{s:orientation.g} LengthGroup -> Length and s-position parameters. \sref{s:length.g} DescriptionGroup -> Element descriptive strings. \sref{s:descrip.g} AlignmentGroup -> Alignment with respect to the reference. \sref{s:alignment.g} diff --git a/manual/introduction.tex b/manual/introduction.tex index 1b1b663..a7f7f67 100644 --- a/manual/introduction.tex +++ b/manual/introduction.tex @@ -148,8 +148,9 @@ \section{Lattice Branches} All tracking branches have a name \vn{Branch.name} inherited from the \vn{BeamLine} that defines the branch in the lattice file and branches contains an array of elements \vn{Branch.ele[]}. If the \vn{BeamLine} used to instantiate a tracking branch does not have a name, The default name -is used. The default name is \vn{"bN"} where \vn{N} is the index of the -branch in the \vn{Lattice.branch} array. +is used. The default name is \vn{"Bn"} where \vn{n} is the index of the +branch in the \vn{Lattice.branch} array. For example, \vn{"B2"} would be the default name of +\vn{lat.branch[2]} (assuming that this is a tracking branch). %--------------------------------------------------------------------------- \section{Lattices} @@ -182,11 +183,11 @@ \section{Lattices} Similarly, lattice elements can be accessed by name or by index. For example, if \vn{lat} is a lattice instance, and \vn{"q1"} is the name of an element or -elements that are in a branch named "b2", the following are equivalent: +elements that are in a branch named "B2", the following are equivalent: \begin{example} elist = lat["q1"] elist = find(lat, "q1") - b2 = lat.branch["b2"]; elist = b2["q1"] + b2 = lat.branch["B2"]; elist = b2["q1"] \end{example} \vn{elist} will be a vector of elements since a name may match to multiple elements. diff --git a/manual/new-ele.tex b/manual/new-ele.tex index a6c28ff..61629ec 100644 --- a/manual/new-ele.tex +++ b/manual/new-ele.tex @@ -31,9 +31,9 @@ \section{Defining a New Element} * If the element has a new type of geometry, extend the \vn{propagate_ele_geometry()} function to handle the new type of geometry. Example: \begin{example} - function propagate_ele_geometry(::Type{CORKSCREW}, fstart::FloorPositionGroup, ele::Ele) + function propagate_ele_geometry(::Type{CORKSCREW}, fstart::OrientationGroup, ele::Ele) ... - return floor_end # FloorPositionGroup at the downstream end of the element. + return floor_end # OrientationGroup at the downstream end of the element. end \end{example} diff --git a/src/AcceleratorLattice.jl b/src/AcceleratorLattice.jl index 2a37507..29bed7e 100644 --- a/src/AcceleratorLattice.jl +++ b/src/AcceleratorLattice.jl @@ -70,7 +70,7 @@ export split!, construct_ele_type, ele_at_s, toggle_integrated! export eles_search, eles_substitute_lords!, eles_sort! export next_ele, ele_at_offset, ele_param_value_str, strip_AL, ele_param_group_symbols export branch, matches_branch, create_ele_vars, eval_str, Vertex1, LatticeGlobal -export EleParameterGroup, AlignmentGroup, FloorPositionGroup, BMultipole, BMultipoleGroup, BeamBeamGroup +export EleParameterGroup, AlignmentGroup, OrientationGroup, BMultipole, BMultipoleGroup, BeamBeamGroup export EMultipole, EMultipoleGroup, BendGroup, ApertureGroup, DescriptionGroup, RFGroup, SolenoidGroup export TrackingGroup, LengthGroup, ReferenceGroup, DownstreamReferenceGroup, ForkGroup export MasterGroup, LordSlaveStatusGroup, ACKickerGroup diff --git a/src/accessor.jl b/src/accessor.jl index e8f140a..71b5d8c 100644 --- a/src/accessor.jl +++ b/src/accessor.jl @@ -454,40 +454,40 @@ function output_parameter(sym::Symbol, ele::Ele, output_group::Type{T}) where T if :AlignmentGroup ∉ keys(ele.pdict); return NaN; end if isnothing(girder(ele)); return ele.offset; end ag = ele.pdict[:AlignmentGroup] - orient_girder = FloorPositionGroup(girder(ele).offset_tot, girder(ele).q_align_tot) - orient_ele = FloorPositionGroup(ele.offset, ele.q_align) + orient_girder = OrientationGroup(girder(ele).offset_tot, girder(ele).q_align_tot) + orient_ele = OrientationGroup(ele.offset, ele.q_align) return floor_transform(orient_ele, orient_girder).r elseif sym == :x_rot_tot if :AlignmentGroup ∉ keys(ele.pdict); return NaN; end if isnothing(girder(ele)); return ele.x_rot; end ag = ele.pdict[:AlignmentGroup] - orient_girder = FloorPositionGroup(girder(ele).offset_tot, girder(ele).q_align_tot) - orient_ele = FloorPositionGroup(ele.offset, ele.q_align) + orient_girder = OrientationGroup(girder(ele).offset_tot, girder(ele).q_align_tot) + orient_ele = OrientationGroup(ele.offset, ele.q_align) return rot_angles(floor_transform(orient_ele, orient_girder).q)[1] elseif sym == :y_rot_tot if :AlignmentGroup ∉ keys(ele.pdict); return NaN; end if isnothing(girder(ele)); return ele.y_rot; end ag = ele.pdict[:AlignmentGroup] - orient_girder = FloorPositionGroup(girder(ele).offset_tot, girder(ele).q_align_tot) - orient_ele = FloorPositionGroup(ele.offset, ele.q_align) + orient_girder = OrientationGroup(girder(ele).offset_tot, girder(ele).q_align_tot) + orient_ele = OrientationGroup(ele.offset, ele.q_align) return rot_angles(floor_transform(orient_ele, orient_girder).q)[2] elseif sym == :z_rot_tot if :AlignmentGroup ∉ keys(ele.pdict); return NaN; end if isnothing(girder(ele)); return ele.z_rot; end ag = ele.pdict[:AlignmentGroup] - orient_girder = FloorPositionGroup(girder(ele).offset_tot, girder(ele).q_align_tot) - orient_ele = FloorPositionGroup(ele.offset, ele.q_align) + orient_girder = OrientationGroup(girder(ele).offset_tot, girder(ele).q_align_tot) + orient_ele = OrientationGroup(ele.offset, ele.q_align) return rot_angles(floor_transform(orient_ele, orient_girder).q)[3] elseif sym == :q_align_tot if :AlignmentGroup ∉ keys(ele.pdict); return NaN; end if isnothing(girder(ele)); return ele.q_align; end ag = ele.pdict[:AlignmentGroup] - orient_girder = FloorPositionGroup(girder(ele).offset_tot, girder(ele).q_align_tot) - orient_ele = FloorPositionGroup(ele.offset, ele.q_align) + orient_girder = OrientationGroup(girder(ele).offset_tot, girder(ele).q_align_tot) + orient_ele = OrientationGroup(ele.offset, ele.q_align) return floor_transform(orient_ele, orient_girder).q end diff --git a/src/bookkeeper.jl b/src/bookkeeper.jl index 638ce82..a6054ae 100644 --- a/src/bookkeeper.jl +++ b/src/bookkeeper.jl @@ -196,10 +196,12 @@ Internal bookkeeping for a non-`UnionEle` super slave. function bookkeeper_superslave!(slave::Ele, changed::ChangedLedger, previous_ele::Ele) # A non-UnionEle super slave has only one lord lord = slave.super_lords[1] + L_rel = slave.L / lord.L + ix_slave = slave_index(slave) # Bookkeeping of the superlord is only done if the slave is the first superslave of the lord. # Here the ReferenceGroup of the slave needs to be bookkeeped first. - if lord.slaves[1] === slave + if ix_slave == 1 elegroup_bookkeeper!(slave, ReferenceGroup, changed, previous_ele) bookkeeper_ele!(lord, changed, previous_ele) end @@ -211,10 +213,58 @@ function bookkeeper_superslave!(slave::Ele, changed::ChangedLedger, previous_ele if isnothing(pinfo); continue; end group = pinfo.parent_group if group ∉ keys(ELE_PARAM_GROUP_INFO); continue; end # Ignore custom stuff + if group == LengthGroup; continue; end # Do not modify length of slave - if group == ReferenceGroup; continue; end # Slave ReferenceGroup independent of lord - if group == DownstreamReferenceGroup; continue; end + if group == ReferenceGroup + slave.dE_ref = lord.dE_ref * L_rel + slave.extra_dtime_ref = lord.extra_dtime_ref * L_rel + end + + if group == RFGroup + slave.voltage = lord.voltage * L_rel + end + + if group == BMultipoleGroup + for (ix, mlord) in enumerate(lord.param[:BMultipoleGroup].pole) + if !mlord.integrated; continue; end + mslave = slave.param[:BMultipole].pole[ix] + mslave.Kn = mlord.Kn * L_rel + mslave.Bn = mlord.Bn * L_rel + mslave.Ks = mlord.Ks * L_rel + mslave.Bs = mlord.Bs * L_rel + end + end + + if group == EMultipoleGroup + for (ix, elord) in enumerate(lord.param[:EMultipoleGroup].pole) + if !elord.integrated; continue; end + eslave = slave.param[:EMultipole].pole[ix] + eslave.En = elord.En * L_rel + eslave.Es = elord.Es * L_rel + end + end + + if group == BendGroup + sbend = slave.pdict[:BendGroup] + sbend.angle = lord.angle * L_rel + if ix_slave < length(lord.slaves) + sbend.e2 = 0 + sbend.e2_rect = 0.5 * sbend.angle + elseif ix_slave > 1 + sbend.e1 = 0 + sbend.e1_rect = 0.5 * sbend.angle + end + end + + if group == TrackingGroup + if lord.num_steps > 0 + slave.num_steps = nint(lord.num_steps * L_rel) + end + end + + if group == DownstreamReferenceGroup; continue; end + if group == OrientationGroup; continue; end slave.pdict[Symbol(group)] = lord.pdict[Symbol(group)] slave.pdict[:changed][group] = "changed" end @@ -582,19 +632,19 @@ function elegroup_bookkeeper!(ele::Ele, group::Type{ReferenceGroup}, changed::Ch end #--------------------------------------------------------------------------------------------------- -# elegroup_bookkeeper!(ele::Ele, group::Type{FloorPositionGroup}, ...) -# FloorPositionGroup bookkeeper +# elegroup_bookkeeper!(ele::Ele, group::Type{OrientationGroup}, ...) +# OrientationGroup bookkeeper -function elegroup_bookkeeper!(ele::Ele, group::Type{FloorPositionGroup}, +function elegroup_bookkeeper!(ele::Ele, group::Type{OrientationGroup}, changed::ChangedLedger, previous_ele::Ele) - fpg = ele.FloorPositionGroup + fpg = ele.OrientationGroup cdict = ele.changed - if has_changed(ele, FloorPositionGroup) || changed.this_ele_length; changed.floor_position = true; end + if has_changed(ele, OrientationGroup) || changed.this_ele_length; changed.floor_position = true; end if !changed.floor_position; return; end - ele.FloorPositionGroup = propagate_ele_geometry(previous_ele) - clear_changed!(ele, FloorPositionGroup) + ele.OrientationGroup = propagate_ele_geometry(previous_ele) + clear_changed!(ele, OrientationGroup) return end diff --git a/src/find.jl b/src/find.jl index 9f27c8b..984bf13 100644 --- a/src/find.jl +++ b/src/find.jl @@ -82,31 +82,49 @@ end """ Internal: eles_atomic(where_search, who, branch_id, ele_type, param_id, - match_str, offset, wrap) -> ele_vector::Ele[] + match_str, wrap) -> ele_vector::Ele[] -Internal function. Called by the `eles_search_a_group` function which in turn is called by `eles`. +Internal function. Find all elements that match an "atomic" construct. +Called by the `eles_search_a_block` function which in turn is called by `eles_search`. """ eles_atomic -function eles_atomic(where_search, who, branch_id, ele_type, param_id, match_str, offset, wrap) +function eles_atomic(where_search, who, branch_id, ele_type, param_id, match_str, wrap) + + # Parse out offset + + chunks = str_split(match_str, ["+", "-"]) + offset = 0 + + if length(chunks) > 1 + if length(chunks) != 3; error("Malformed element ID: $who"); end + match_str = chunks[1] + offset = integer(chunks[2] * chunks[3]) + end + + # What branches to search? ele_list = Ele[] ix_ele = integer(match_str, -1) - branches_searched = [] if typeof(where_search) == Lattice lat = where_search - branch_vec = lat.branch + if ix_ele != -1 && branch_id == "" + branch_vec = [lat.branch[1]] + else + branch_vec = lat.branch + end + else branch_vec = collect(where_search) end - # Search branches + # Search for element for branch in branch_vec if !matches_branch(branch_id, branch); continue; end - push!(branches_searched, branch) if ix_ele != -1 && param_id == :name + if ix_ele > length(branch.ele); error("Element index above branch.ele[] range: $(who)"); end push!(ele_list, ele_at_offset(branch.ele[ix_ele], offset, wrap)) else for ele in branch.ele @@ -121,38 +139,36 @@ function eles_atomic(where_search, who, branch_id, ele_type, param_id, match_str end #--------------------------------------------------------------------------------------------------- -# eles_search_a_group +# eles_search_a_block """ - Internal: eles_search_a_group(where_search::Union{Lattice,Branch}, who::Union{AbstractString,Regex}; - wrap::Bool = true) + Internal: eles_search_a_block(where_search::Union{Lattice,Branch}, + who::Union{AbstractString,Regex}; wrap::Bool = true) -Internal routine called by `eles` to search for matches to a string that represents a single "group". -A string representing a single group is a string that does not contain, ",", "&", nor "~". +Internal routine called by `eles` to search for matches to a string that represents a single "block". +A string representing a single block is a string that does not contain, ",", "&", nor "~". See the `eles` documentation for details. Returned is a list that is naturally sorted by index. -""" eles_search_a_group +""" eles_search_a_block -function eles_search_a_group(where_search::Union{Lattice,Branch}, who::Union{AbstractString,Regex}, +function eles_search_a_block(where_search::Union{Lattice,Branch}, who::Union{AbstractString,Regex}, wrap::Bool = true) # Julia regex is simple - if typeof(who) == Regex; return eles_search_a_group(where_search, who); end + if typeof(who) == Regex; return eles_search_a_block(where_search, who); end # Not Julia regex ele_type = nothing branch_id = "" # Branch ID used with "branch_id>>ele_id" construct param_id = :name match_str = "" - offset = 0 - # Parse `who` + # Parse `who`. Will accept constructs of the form "branch>>type::name" or "type::branch>>name" this_who = replace(who, "'" => "\'") - chunks = str_split(this_who, [">>", "::", ":", "+", "-", "=", "`", " "]) + chunks = str_split(this_who, [">>", "::", ":", "=", "`", " "]) if length(chunks) > 2 && chunks[2] == "::" - ele_type = Symbol(chunks[1]) - if ele_type ∉ Symbol.(subtypes(Ele)); error("Element type not recognized: $ele_type"); end + ele_type = chunks[1] chunks = chunks[3:end] end @@ -161,6 +177,16 @@ function eles_search_a_group(where_search::Union{Lattice,Branch}, who::Union{Abs chunks = chunks[3:end] end + if length(chunks) > 2 && chunks[2] == "::" # Need this test for "branch>>type::name" construct + ele_type = chunks[1] + chunks = chunks[3:end] + end + + if !isnothing(ele_type) + ele_type = Symbol(ele_type) + if ele_type ∉ Symbol.(subtypes(Ele)); error("Element type not recognized: $ele_type"); end + end + if length(chunks) > 4 && chunks[2] == "=" if chunks[3] != "`" || chunks[5] != "`" error("Malformed back ticks in element match string: $who"); end param_id = Symbol(chunks[1]) @@ -171,50 +197,37 @@ function eles_search_a_group(where_search::Union{Lattice,Branch}, who::Union{Abs chunks = chunks[2:end] end - if length(chunks) > 0 && (chunks[1] == "-" || chunks[1] == "+") - if length(chunks) == 1; error("Malformed `-` or `+` character in element match string: $who"); end - offset = integer(chunks[1] * chunks[2]) - chunks = chunks[3:end] - end - # Non-range construct if length(chunks) == 0 - return eles_atomic(where_search, who, branch_id, ele_type, param_id, match_str, offset, wrap) + return eles_atomic(where_search, who, branch_id, ele_type, param_id, match_str, wrap) end # Range construct # Note: ele_type not used in search for range end points. - ele_vec = eles_atomic(where_search, who, branch_id, nothing, param_id, match_str, offset, wrap) + ele_vec = eles_atomic(where_search, who, branch_id, nothing, param_id, match_str, wrap) - if chunks[1] != ":"; error("Malformed group: $who"); end + if chunks[1] != ":"; error("Malformed construct: $who"); end if length(ele_vec) == 0; error("First element in range construct does not match anything in the lattice: $who"); end if length(ele_vec) > 1; error("First element in range construct matches multiple elements: $who"); end param_id = :name match_str = "" - offset = 0 - if length(chunks) > 4 && chunks[2] == "=" - if chunks[3] != "`" || chunks[5] != "`" error("Malformed back ticks in element match string: $who"); end - param_id = Symbol(chunks[1]) - match_str = chunks[4] - chunks = chunks[6:end] + if length(chunks) > 5 && chunks[3] == "=" + if chunks[4] != "`" || chunks[6] != "`" error("Malformed back ticks in element match string: $who"); end + param_id = Symbol(chunks[2]) + match_str = chunks[5] + chunks = chunks[7:end] else - match_str = chunks[1] - chunks = chunks[2:end] - end - - if length(chunks) > 0 && (chunks[1] == "-" || chunks[1] == "+") - if length(chunks) == 1; error("Malformed `-` or `+` character in element match string: $who"); end - offset = integer(chunks[1] * chunks[2]) + match_str = chunks[2] chunks = chunks[3:end] end - if length(chunks) > 0; error("Extra stuff in group construct: $who"); end + if length(chunks) > 0; error("Extra stuff in search string: $who"); end - ele_vec2 = eles_atomic(where_search, who, branch_id, nothing, param_id, match_str, offset, wrap) + ele_vec2 = eles_atomic(where_search, who, branch_id, nothing, param_id, match_str, wrap) if length(ele_vec2) == 0; error("Second element in range construct does not match anything in the lattice: $who"); end if length(ele_vec2) > 1; error("Second element in range construct matches multiple elements: $who"); end @@ -238,7 +251,7 @@ function eles_search_a_group(where_search::Union{Lattice,Branch}, who::Union{Abs if isnothing(ele_type) return ele_vec else - return ele_vec[typeof(ele_vec) .== ele_type] + return ele_vec[Symbol.(typeof.(ele_vec)) .== ele_type] end end @@ -246,10 +259,11 @@ end # eles_search """ - eles_search(where_search, who::Union{AbstractString,Regex}; - order::Order.T = Order.NONE, substitute_lords = false, wrap::Bool = true) -> Ele[] + eles_search(where_search, who::Union{AbstractString,Regex}; order::Order.T = Order.NONE, + substitute_lords = false, wrap::Bool = true, scalar = false) -> Union{Ele[], Ele, Nothing} -Returns a vector of all elements that match `who`. +Returns a vector of all elements that match `who`. +If the last character of ## Arguments - `where_search` Where to search. Either a lattice (all branches searched), lattice branch, or @@ -262,6 +276,10 @@ Returns a vector of all elements that match `who`. - `substitute_lords` If `true`, for every matched element that is a slave, remove the slave and add to the output list the slave's super or multipass lords. - `wrap` Used if there is an `offset` specified in the search string (see below). +- `scalar` If `false`, return vector of elements (which may have zero length), + If `true`, return a single element if `who` matches to a single element or otherwise return `nothing`. + As a shortcut, if the last character of `who` is a `#` character, remove this character and set + `scalar` to `true`. ## AL Regex @@ -269,26 +287,32 @@ The "AcceleratorLattice" (AL) regex syntax has wild card characters `“*”` an The `“*”` character will match any number of characters (including zero) while `“%”` maches to any single character. -AL regex expressions are built up from "atomic" expressions which are of the form: +AL regex expressions are built up from "blocks" which are of the form: ``` {branch_id>>}ele_id{+/-offset} ``` Curly brackets `{...}` denote optional fields. - `branch_id` Optional lattice branch index or name. Alternative is to specify the branch using the `where_search` argument. A branch is searched if it matches both `where_search` - and `branch_id`. -- `ele_id` Element name (which can contain wild card characters), index, or - `parameter='match_str'` construct. + and `branch_id`. If `ele_id` is an integer and `branch_id` is not present, branch 1 is + is used. +- `ele_id` Element name. See below. - `+/-offset` If present, return element(s) whose index is offset from the elements matched to. -A `group` is either an `atom` with an optional `type` prefix or a `"range"` construct: +A `ele_id` is of the form: ``` {ele_type::}atom # or - {ele_type::}atom1:atom2 # Range construct + {ele_type::}atom1:atom2 # range construct ``` - -where `ele_type` is an optional element type (EG: `Quadrupole`, `Drift`, etc.). +where `ele_type` is an optional element type (EG: `Quadrupole`, `Drift`, etc.) and `atom` +is an element name (which can contain wild card characters), index, or +`parameter='match_str'` construct. Here `parameter` is the name of any string component of +an element. Standard string components are +• `type` Example: `type = 'abc'` \\ +• `class` Example: `class = 'abc'` \\ +• `ID` Example: `ID = 'abc'` \\ +Notice that here strings to be matched to use single quotes. With the range construct, `atom1` and `atom2` must both evaluate to a single element in the same branch. @@ -303,11 +327,11 @@ same branch. at the range ends do not have to be of type `ele_type`. Group expressions may be combined using the operators `","` (union), `"~"` (negation) or `"&"` (intersection): -If there are more than two group expressions involved, evaluation is left to right. For example: +If there are more than two block expressions involved, evaluation is left to right. For example: ``` - ", " # Union of and . - ", & " # Intersection of with the union of and . - " ~" # All elements in that are not in . + ", " # Union of and . + ", & " # Intersection of with the union of and . + " ~" # All elements in that are not in . ``` ## Notes @@ -321,10 +345,17 @@ If there are more than two group expressions involved, evaluation is left to rig ## Examples ``` eles_search(lat, "r>>d") # All elements named "d" in the branch with name "r". - eles_search(lat, "Marker::*") # All Marker elements + eles_search(lat, "Bend::* ~*!*") # All Bend elements which are not multipass nor super slaves. + # This works since all slaves have a "!" in their name. eles_search(lat, "Marker::%5-1") # All elements just before Marker elements with two character names - # ending in the digit "5" - eles_search(lat.branch["super"], "ID=`abc`") + # ending in the digit "5". + eles_search(lat.branch["super"], "ID=`abc`") # All super lord elements with ID string equal to "abc". + eles_search(lat, "1>>Patch::4:10") # All Patch elements in branch 1 between elements 4 through 10. + eles_search(lat, "Patch::1>>4:10") # Same as above + eles_search(lat, "Qa+1:Qb+2") # All elements between the element after "Qa" through the + # element that is second after "Qb", + eles_search(lat, "34") # Element with index 34 in branch 1. Notice that if the + # ele ID is not an integer, all branches are searched. ``` Note: The index operator `[...]` is overloaded so that `branch[who]` where `branch` is a `Branch` @@ -333,13 +364,23 @@ instance, or `lat[who]` where `lat` is a """ eles_search function eles_search(where_search::Union{Lattice,Branch}, who::Union{AbstractString,Regex}; - order::Order.T = Order.NONE, substitute_lords = false, wrap::Bool = true) + order::Order.T = Order.NONE, substitute_lords = false, wrap::Bool = true, scalar = false) + + # See if end of `who` is a "#" character + + if length(who) > 0 && who[end] == '#' + who = who[1:end-1] + scalar = true + end + + # Break `who` into blocks for searching + if typeof(who) == Regex - ele_list = eles_search_a_group(where_search, who, wrap) + ele_list = eles_search_a_block(where_search, who, wrap) else list = str_split(who, "~&,") - ele_list = eles_search_a_group(where_search, list[1]) + ele_list = eles_search_a_block(where_search, list[1]) list = list[2:end] while true @@ -349,21 +390,13 @@ function eles_search(where_search::Union{Lattice,Branch}, who::Union{AbstractStr list2 = eles_search(where_search, list[2], wrap = wrap) if list[1] == "&" - combo_list = Ele[] - for ele1 in ele_list - if ele1 in list2; push!(combo_list, ele1); continue; end - end - ele_list = combo_list + ele_list = intersect(ele_list, list2) elseif list[1] == "~" - combo_list = Ele[] - for ele1 in ele_list - if ele1 ∉ list2; push!(combo_list, ele1); continue; end - end - ele_list = combo_list + ele_list = setdiff(ele_list, list2) elseif list[1] == "," - ele_list = append!(ele_list, list2) + ele_list = unique(append!(ele_list, list2)) else error("ParseError: Cannot parse: $who") @@ -373,8 +406,19 @@ function eles_search(where_search::Union{Lattice,Branch}, who::Union{AbstractStr end end + # End stuff + if substitute_lords; eles_substitute_lords!(ele_list); end - return eles_sort!(ele_list, order = order) + + if scalar + if length(ele_list) == 1 + return ele_list[1] + else + return nothing + end + else + return eles_sort!(ele_list, order = order) + end end #--------------------------------------------------------------------------------------------------- diff --git a/src/geometry.jl b/src/geometry.jl index 57b6c45..8f2922f 100644 --- a/src/geometry.jl +++ b/src/geometry.jl @@ -2,7 +2,7 @@ # propagate_ele_geometry """ - propagate_ele_geometry(floor_start::FloorPositionGroup, ele::Ele) + propagate_ele_geometry(floor_start::OrientationGroup, ele::Ele) propagate_ele_geometry(ele::Ele) Returns the floor position at the end of the element given the floor position at the beginning. @@ -16,32 +16,32 @@ That is, the coordinates are the `machine` coordinates and not the `body` coordi """ propagate_ele_geometry function propagate_ele_geometry(ele::Ele) - return propagate_ele_geometry(ele_geometry(ele), ele.FloorPositionGroup, ele) + return propagate_ele_geometry(ele_geometry(ele), ele.OrientationGroup, ele) end -function propagate_ele_geometry(fstart::FloorPositionGroup, ele::Ele) +function propagate_ele_geometry(fstart::OrientationGroup, ele::Ele) return propagate_ele_geometry(ele_geometry(ele), fstart, ele) end -function propagate_ele_geometry(::Type{ZERO_LENGTH}, fstart::FloorPositionGroup, ele::Ele) +function propagate_ele_geometry(::Type{ZERO_LENGTH}, fstart::OrientationGroup, ele::Ele) return fstart end -function propagate_ele_geometry(::Type{STRAIGHT}, fstart::FloorPositionGroup, ele::Ele) +function propagate_ele_geometry(::Type{STRAIGHT}, fstart::OrientationGroup, ele::Ele) r_floor = fstart.r + rot(fstart.q, [0.0, 0.0, ele.L]) - return FloorPositionGroup(r_floor, fstart.q) + return OrientationGroup(r_floor, fstart.q) end -function propagate_ele_geometry(::Type{CIRCULAR}, fstart::FloorPositionGroup, ele::Ele) +function propagate_ele_geometry(::Type{CIRCULAR}, fstart::OrientationGroup, ele::Ele) df = floor_transform(ele.BendGroup, ele.L) return floor_transform(fstart, df) end -function propagate_ele_geometry(::Type{PATCH_GEOMETRY}, fstart::FloorPositionGroup, ele::Ele) +function propagate_ele_geometry(::Type{PATCH_GEOMETRY}, fstart::OrientationGroup, ele::Ele) error("Not yet implemented!") end -function propagate_ele_geometry(::Type{CRYSTAL_GEOMETRY}, fstart::FloorPositionGroup, ele::Ele) +function propagate_ele_geometry(::Type{CRYSTAL_GEOMETRY}, fstart::OrientationGroup, ele::Ele) error("Not yet implemented!") end @@ -49,7 +49,7 @@ end # floor_transform """ - floor_transform(bend::BendGroup, L::Number) -> FloorPositionGroup + floor_transform(bend::BendGroup, L::Number) -> OrientationGroup Returns the transformation of the coordinates from the beginning of a bend to the end of the bend. @@ -63,10 +63,10 @@ function floor_transform(bend::BendGroup, L) r_vec = [-L * sinc(bend.angle/(2*pi)) * sin(bend.angle), 0.0, L * sinc(bend.angle/pi)] if bend.tilt_ref == 0 - return FloorPositionGroup(r_vec, qa) + return OrientationGroup(r_vec, qa) else qt = rotZ(-bend.tilt_ref) - return FloorPositionGroup(rot(qt, r_vec), qt * qa * inv(qt)) + return OrientationGroup(rot(qt, r_vec), qt * qa * inv(qt)) end end @@ -74,26 +74,26 @@ end # floor_transform """ - floor_transform(floor0::FloorPositionGroup, dfloor::FloorPositionGroup) -> FloorPositionGroup + floor_transform(floor0::OrientationGroup, dfloor::OrientationGroup) -> OrientationGroup Returns coordinate transformation of `dfloor` applied to `floor0`. -""" floor_transform(floor0::FloorPositionGroup, dfloor::FloorPositionGroup) +""" floor_transform(floor0::OrientationGroup, dfloor::OrientationGroup) -function floor_transform(floor0::FloorPositionGroup, dfloor::FloorPositionGroup) +function floor_transform(floor0::OrientationGroup, dfloor::OrientationGroup) r_floor = floor0.r + rot(floor0.q, dfloor.r) q_floor = floor0.q * dfloor.q - return FloorPositionGroup(r_floor, q_floor) + return OrientationGroup(r_floor, q_floor) end #--------------------------------------------------------------------------------------------------- # rot """ - rot(floor0::FloorPositionGroup, q::Quaternion) -> FloorPositionGroup + rot(floor0::OrientationGroup, q::Quaternion) -> OrientationGroup Rotates by `q` the floor position `floor0`. """ -function rot(floor0::FloorPositionGroup, q::Quaternion) - return FloorPositionGroup(r = rot(q, floor0.r), q = q * floor0.q) +function rot(floor0::OrientationGroup, q::Quaternion) + return OrientationGroup(r = rot(q, floor0.r), q = q * floor0.q) end diff --git a/src/lat_construction.jl b/src/lat_construction.jl index 9a1d86a..c2292e6 100644 --- a/src/lat_construction.jl +++ b/src/lat_construction.jl @@ -249,7 +249,7 @@ function new_tracking_branch!(lat::Lattice, bline::BeamLine) branch.pdict[:ix_branch] = length(lat.branch) branch.pdict[:type] = TrackingBranch - if branch.name == ""; branch.name = "b" * string(length(lat.branch)); end + if branch.name == ""; branch.name = "B" * string(length(lat.branch)); end info = LatticeConstructionInfo([], bline.pdict[:orientation], 0) if haskey(bline.pdict, :species_ref); branch.ele[1].species_ref = bline.pdict[:species_ref]; end diff --git a/src/parameters.jl b/src/parameters.jl index 8c7d3e2..a29d7c4 100644 --- a/src/parameters.jl +++ b/src/parameters.jl @@ -135,14 +135,11 @@ ELE_PARAM_INFO_DICT = Dict( :β_ref_downstream => ParamInfo(DownstreamReferenceGroup, Number, "Reference velocity/c at downstream end.", "", OutputGroup), :γ_ref_downstream => ParamInfo(DownstreamReferenceGroup, Number, "Reference relativistic gamma factor at downstream end.", "", OutputGroup), - :r_floor => ParamInfo(FloorPositionGroup, Vector{Number}, "3-vector of element floor position.", "m", nothing, :r), - :q_floor => ParamInfo(FloorPositionGroup, Quaternion, "Element quaternion orientation.", "", nothing, :q), - :to_line => ParamInfo(ForkGroup, Union{BeamLine, Nothing}, "Beamline forked to."), :to_ele => ParamInfo(ForkGroup, Union{String,Ele}, "Lattice element forked to."), :direction => ParamInfo(ForkGroup, Int, "Direction (forwards or backwards) of injection."), - :supported => ParamInfo(GirderGroup, Vector{Ele}, "Array of elements supported by a Girder."), + :supported => ParamInfo(GirderGroup, Vector{Ele}, "Array of elements supported by a Girder."), :L => ParamInfo(LengthGroup, Number, "Element length.", "m"), :orientation => ParamInfo(LengthGroup, Int, "Longitudinal orientation of element. May be +1 or -1."), @@ -155,6 +152,9 @@ ELE_PARAM_INFO_DICT = Dict( :is_on => ParamInfo(MasterGroup, Bool, "Element fields on/off."), :field_master => ParamInfo(MasterGroup, Bool, "True: fields are fixed and normalized values change when varying ref energy."), + :r_floor => ParamInfo(OrientationGroup, Vector{Number}, "3-vector of element floor position.", "m", nothing, :r), + :q_floor => ParamInfo(OrientationGroup, Quaternion, "Element quaternion orientation.", "", nothing, :q), + :origin_ele => ParamInfo(OriginEleGroup, Ele, "Coordinate reference element."), :origin_ele_ref_pt => ParamInfo(OriginEleGroup, Loc.T, "Reference location on reference element. Default is Loc.CENTER."), @@ -247,7 +247,7 @@ List of names (symbols) of parameters associated with element parameter group st Associated parameters are the fields of the struct plus any associated output parameters. If the "user name" is different from the group field name, the user name is used. -For example, for a `FloorPositionGroup`, `r_floor` will be in the name list instead of `r`. +For example, for a `OrientationGroup`, `r_floor` will be in the name list instead of `r`. """ associated_names function associated_names(group::Type{T}) where T <: EleParameterGroup @@ -605,7 +605,7 @@ Order is important. Bookkeeping routines rely on: """ PARAM_GROUPS_LIST base_group_list = [LengthGroup, LordSlaveStatusGroup, DescriptionGroup, ReferenceGroup, - DownstreamReferenceGroup, FloorPositionGroup, TrackingGroup, AlignmentGroup, ApertureGroup] + DownstreamReferenceGroup, OrientationGroup, TrackingGroup, AlignmentGroup, ApertureGroup] multipole_group_list = [MasterGroup, BMultipoleGroup, EMultipoleGroup] general_group_list = [base_group_list..., multipole_group_list...] @@ -619,11 +619,11 @@ PARAM_GROUPS_LIST = Dict( CrabCavity => [base_group_list...], Drift => [base_group_list...], EGun => [general_group_list...], - Fiducial => [DescriptionGroup, FloorPositionGroup, AlignmentGroup, OriginEleGroup], - FloorShift => [DescriptionGroup, FloorPositionGroup, AlignmentGroup, OriginEleGroup], + Fiducial => [DescriptionGroup, OrientationGroup, AlignmentGroup, OriginEleGroup], + FloorShift => [DescriptionGroup, OrientationGroup, AlignmentGroup, OriginEleGroup], Foil => [base_group_list...], Fork => [base_group_list..., ForkGroup], - Girder => [LengthGroup, DescriptionGroup, FloorPositionGroup, AlignmentGroup, OriginEleGroup, GirderGroup], + Girder => [LengthGroup, DescriptionGroup, OrientationGroup, AlignmentGroup, OriginEleGroup, GirderGroup], Instrument => [base_group_list...], Kicker => [general_group_list...], LCavity => [base_group_list..., MasterGroup, RFAutoGroup, RFGroup], @@ -661,7 +661,6 @@ ELE_PARAM_GROUP_INFO = Dict( DownstreamReferenceGroup => EleParameterGroupInfo("Downstream element end reference energy and species.", false), EMultipoleGroup => EleParameterGroupInfo("Electric multipoles.", false), EMultipole => EleParameterGroupInfo("Electric multipole of given order. Substructure contained in `EMultipoleGroup`.", false), - FloorPositionGroup => EleParameterGroupInfo("Global floor position and orientation.", true), ForkGroup => EleParameterGroupInfo("Fork element parameters", false), GirderGroup => EleParameterGroupInfo("Girder parameters.", false), InitParticleGroup => EleParameterGroupInfo("Initial particle position and spin.", false), @@ -669,6 +668,7 @@ ELE_PARAM_GROUP_INFO = Dict( LengthGroup => EleParameterGroupInfo("Length and s-position parameters.", true), LordSlaveStatusGroup => EleParameterGroupInfo("Element lord and slave status.", false), MasterGroup => EleParameterGroupInfo("Contains field_master parameter.", false), + OrientationGroup => EleParameterGroupInfo("Global floor position and orientation.", true), OriginEleGroup => EleParameterGroupInfo("Defines coordinate origin for Girder, FloorShift and Fiducial elements.", false), PatchGroup => EleParameterGroupInfo("Patch parameters.", false), ReferenceGroup => EleParameterGroupInfo("Reference energy and species.", true), diff --git a/src/query.jl b/src/query.jl index 1098b67..2f60fa8 100644 --- a/src/query.jl +++ b/src/query.jl @@ -152,6 +152,37 @@ function matches_branch(name::AbstractString, branch::Branch) end end +#--------------------------------------------------------------------------------------------------- +# slave_index + +""" + slave_index(slave::Ele) -> Int + +For a super or multipass slave element, returns the index of the slave in the `lord.slaves[]` +array. Exception: A `UnionEle` super slave has multiple lords. In this case, zero is returned. +""" slave_index + +function slave_index(slave::Ele) + if slave.slave_status == Slave.SUPER + if typeof(slave) == UnionEle; return 0; end + lord = slave.super_lords[1] + for ix in 1:length(lord.slaves) + if lord.slaves[ix].ix_ele == slave.ix_ele; return ix; end + end + + elseif slave.slave_status == Slave.MULTIPASS + lord = slave.multipass_lord[1] + for ix in 1:length(lord.slaves) + if lord.slaves[ix].ix_ele == slave.ix_ele; return ix; end + end + + else + error("Element is not a super nor a multipass slave.") + end + + error("Bookkeeping error! Please contact an AcceleratorLattice maintainer!") +end + #--------------------------------------------------------------------------------------------------- # girder diff --git a/src/show.jl b/src/show.jl index 955c6b8..fddaae6 100644 --- a/src/show.jl +++ b/src/show.jl @@ -9,12 +9,12 @@ second column when displaying the elements of an element parameter group using t Example `show_column2` key/value pair: ```julia - FloorPositionGroup => Dict{Symbol,Symbol}( + OrientationGroup => Dict{Symbol,Symbol}( :r => :q, :phi => :psi, ) ``` -In this example, when printing the `FloorPositionGroup`, in the line showing the `.r` component, +In this example, when printing the `OrientationGroup`, in the line showing the `.r` component, the `.r` component will be in the first column and the `.q` component will be in the second column. @@ -53,7 +53,7 @@ show_column2 = Dict{Type{T} where T <: BaseEleParameterGroup, Dict{Symbol,Symbol :eta => :etap, ), - FloorPositionGroup => Dict{Symbol,Symbol}( + OrientationGroup => Dict{Symbol,Symbol}( :r => :q, ), @@ -493,7 +493,7 @@ end """ full_parameter_name(field::Symbol, group::Type{T}) where T <: BaseEleParameterGroup -For fields where the user name is different (EG: `r_floor` and `r` in a FloorPositionGroup), +For fields where the user name is different (EG: `r_floor` and `r` in a OrientationGroup), return the string `struct_name (user_name)` (EG: `r (r_floor)`). Also add `(output)` to names of output parameters. """ full_parameter_name diff --git a/src/struct.jl b/src/struct.jl index 7238509..fdc6eca 100644 --- a/src/struct.jl +++ b/src/struct.jl @@ -335,7 +335,7 @@ Dispersion parameters for a single axis. end #--------------------------------------------------------------------------------------------------- -# EMultipole +# EMultipole subgroup """ mutable struct EMultipole <: EleParameterSubGroup @@ -704,26 +704,6 @@ Vector of Electric multipoles. pole::Vector{EMultipole} = Vector{EMultipole}([]) # Vector of multipoles. end -#--------------------------------------------------------------------------------------------------- -# FloorPositionGroup - -""" - mutable struct FloorPositionGroup <: EleParameterGroup - -Position and orientation in global coordinates. -In a lattice element this group gives the coordinates at the entrance end of the element -ignoring misalignments. - -# Fields -• `r::Vector` - `[x,y,z]` position. \\ -• `q::Quaternion{Number}` - Quaternion orientation. \\ -""" FloorPositionGroup - -@kwdef mutable struct FloorPositionGroup <: EleParameterGroup - r::Vector = [0.0, 0.0, 0.0] - q::Quaternion{Number} = Quaternion(1.0, 0.0, 0.0, 0.0) -end - #--------------------------------------------------------------------------------------------------- # ForkGroup @@ -836,6 +816,26 @@ and normalized field strengths willbe varied. And vice versa when `field_master` field_master::Bool = false # Does field or normalized field stay constant with energy changes? end +#--------------------------------------------------------------------------------------------------- +# OrientationGroup + +""" + mutable struct OrientationGroup <: EleParameterGroup + +Position and angular orientation. +In a lattice element, this group gives the orientation at the entrance end of the element +ignoring alignment shifts. + +# Fields +• `r::Vector` - `[x,y,z]` position. \\ +• `q::Quaternion{Number}` - Quaternion orientation. \\ +""" OrientationGroup + +@kwdef mutable struct OrientationGroup <: EleParameterGroup + r::Vector = [0.0, 0.0, 0.0] + q::Quaternion{Number} = Quaternion(1.0, 0.0, 0.0, 0.0) +end + #--------------------------------------------------------------------------------------------------- # OriginEleGroup diff --git a/src/superimpose.jl b/src/superimpose.jl index 8771cc9..46ccd9a 100644 --- a/src/superimpose.jl +++ b/src/superimpose.jl @@ -358,7 +358,7 @@ function initial_superlord_bookkeeping(lord::Ele) if haskey(lord.pdict, :BendGroup) # Need transformation from lord alignment point to slave alignment point # Translate from lord alignment point to beginning of lord point - floor = FloorPositionGroup(r = [0, 0, -0.5*lord.l_chord]) + floor = OrientationGroup(r = [0, 0, -0.5*lord.l_chord]) # Rotate from z parallel to lord chord to z tangent to bend curve. if lord.ref_tilt != 0 q = [] diff --git a/test/find_test.jl b/test/find_test.jl index 432dfb5..7d06386 100644 --- a/test/find_test.jl +++ b/test/find_test.jl @@ -29,12 +29,6 @@ superimpose!(z1, eles_search(lat, "1>>d")[1], offset = 0.1) b = lat.branch[1] bsuper = lat.branch["super"] -eles_search(lat, "z2") -eles_search(bsuper, "z2") - -# !!! Test ele_at_offset with, EG multipass - - @testset "ele_at_s" begin @test ele_at_s(b, b.ele[4].s, select = Select.UPSTREAM) === b.ele[2] @test ele_at_s(b, b.ele[4].s, select = Select.DOWNSTREAM) === b.ele[4] @@ -54,7 +48,7 @@ end @test eles_search(lat, "multipass>>d") == eles_search(lat, "multipass>>2") @test eles_search(lat, "%d") == eles_search(lat, "fodo>>22, multipass>>1, multipass>>3") @test eles_search(lat, "z1-1") == eles_search(lat, "1>>4") - @test eles_search(lat, "z1+1") == eles_search(lat, "fodo>>6") + @test eles_search(b, "z1+1") == eles_search(lat, "fodo>>6") @test eles_search(lat, "z2-1") == eles_search(lat, "ln3>>2") @test eles_search(lat, "ID=`z1`") == eles_search(lat, "fodo>>7, fodo>>9, fodo>>15, fodo>>21") @test eles_search(lat, "ID=`z1` ~fodo>>9 ~fodo>>22") == eles_search(lat, "fodo>>7, fodo>>15, fodo>>21") @@ -62,9 +56,15 @@ end @test bsuper["z2"] == eles_search(lat, "super>>1") @test eles_search(lat, "Quadrupole::* ~*!*") == eles_search(lat, "fodo>>7, fodo>>9, fodo>>15, fodo>>21, fodo>>22, multipass>>1, multipass>>3") - @test_throws ErrorException eles_search(lat, "quadrupole::*") + @test eles_search(lat, "2>>2:4 ~Quadrupole::*") == [lat.branch[2].ele[3]] + @test eles_search(lat, "2>>2:4") == lat.branch[2].ele[2:4] + @test_throws ErrorException eles_search(lat, "quadrupole::*") # quadrupole should be capitalized. end +# !!! Test ele_at_offset with, EG multipass + + + # Function to print right-hand-side for "eles_search" testset. Used to create new tests. Just use the LHS as the argument. # #function toe(vec) diff --git a/test/superimpose_test.jl b/test/superimpose_test.jl index b611a13..107a105 100644 --- a/test/superimpose_test.jl +++ b/test/superimpose_test.jl @@ -8,7 +8,7 @@ using AcceleratorLattice, Test En1L = 1, Etilt1 = 2, Es2 = 3, Etilt2 = 4) q2 = Quadrupole(L = 0.6, Kn1 = -0.3); d1 = Drift(L = 1.0); - lc1 = LCavity(L = 1.0, dE_ref = 2e7); + lc1 = LCavity(L = 1.0, dE_ref = 2e7, voltage = 10e7); d3 = Drift(L = 1.0); m1 = Marker(); m2 = Marker(); @@ -50,6 +50,7 @@ b2 = lat.branch[2] @test b2.ele[1].slaves == [b1.ele[9], b1.ele[11]] @test b2.ele[2].slaves == [b1.ele[13], b1.ele[15]] @test length.([sup_m1, sup_sm1, sup_zs2, sup_zm4, sup_m2, sup_zm2, sup_zm3]) == [1, 1, 2, 1, 1, 1, 1] + #@test end #---------------------------------------------------------------------------------------------------