Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/AcceleratorLattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export memloc, beamline, @ele, @eles, @construct_ele_type, enum, enum_add
export ele_name, show_name, show_ele, msng, E_kinetic, pc, β, β1, γ
export show_lat, show_branch, show_beamline, bookkeeper!, set_param!
export Branch, Lattice, BeamLineEle, superimpose!, multipole_type
export BeamLineItem, BeamLine, Ele, propagate_ele_geometry, ele_floor_transform
export BeamLineItem, BeamLine, Ele, propagate_ele_geometry, coord_transform
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
Expand All @@ -83,5 +83,12 @@ export machine_location, body_location, EleRegion, holy_traits, output_parameter
export BranchType, LordBranch, TrackingBranch, MultipassBranch, SuperBranch, transform
export str_split, str_match, str_unquote, str_quote, str_to_int, associated_names
export ELE_PARAM_GROUP_INFO, ELE_TYPE_INFO, PARAM_GROUPS_LIST, OPEN, CLOSED
export rotX, rotY, rotZ, rot, rot!

# From LinearAlgebra
export norm

# From SimUtils
export cos_one

end # module
10 changes: 5 additions & 5 deletions src/accessor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -470,39 +470,39 @@ function output_parameter(sym::Symbol, ele::Ele, output_group::Type{T}) where T
ag = ele.pdict[:AlignmentGroup]
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
return coord_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 = 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]
return rot_angles(coord_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 = 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]
return rot_angles(coord_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 = 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]
return rot_angles(coord_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 = 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
return coord_transform(orient_ele, orient_girder).q
end

error("Parameter $sym is not in the output group $output_group.")
Expand Down
88 changes: 49 additions & 39 deletions src/bookkeeper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -195,48 +195,67 @@ function bookkeeper_superslave!(slave::Ele, changed::ChangedLedger, previous_ele
if group == LengthGroup; continue; end # Do not modify length of slave
if group == DownstreamReferenceGroup; continue; end
if group == OrientationGroup; continue; end
if group == LordSlaveStatusGroup; continue; end

if has_changed(lord, group); slave.pdict[Symbol(group)] = copy(group); end
group_changed = has_changed(lord, group)
if group_changed && group != AlginmentGroup
slave.pdict[Symbol(group)] = copy(lord.pdict[Symbol(group)])
slave.pdict[:changed][group] = "changed"
end

# Note: BodyLoc.CENTER cannot be handled.
# Possible solution: Add aperture_offset parameter to group.
if group == ApertureGroup && group_changed && length(lord.slaves) > 1
lord.orientation == 1 ? ixs = ix_slave : ixs = length(lord.slaves) + 1 - ix_slave
if slave.aperture_at == BodyLoc.ENTRANCE_END
if ixs > 1; slave.aperture_at = BodyLoc.NOWHERE; end
elseif slave.aperture_at == BodyLoc.EXIT_END
if ixs > length(lord.slaves); slave.aperture_at = BodyLoc.NOWHERE; end
elseif slave.aperture_at == BodyLoc.BOTH_ENDS
if ixs == 1
slave.aperture_at = BodyLoc.ENTRANCE_END
elseif ixs == length(lord.slaves)
slave.aperture_at = BodyLoc.EXIT_END
else
slave.aperture_at = BodyLoc.NOWHERE
end
end
end

if group == EMultipoleGroup
if group == EMultipoleGroup && (group_changed ||changed.this_ele_length)
for (ix, elord) in enumerate(lord.pdict[:EMultipoleGroup].pole)
if !elord.integrated; continue; end
eslave = slave.param[:EMultipole].pole[ix]
if !elord.Eintegrated; continue; end
eslave = deepcopy(slave.pdict[:EMultipoleGroup].pole[ix])
eslave.En = elord.En * L_rel
eslave.Es = elord.Es * L_rel
end
end

if group == TrackingGroup
if group == TrackingGroup && (group_changed ||changed.this_ele_length)
if lord.num_steps > 0
slave.num_steps = nint(lord.num_steps * L_rel)
end
end

# alignment bookkeeping
if has_changed(lord, AlignmentGroup)
dL = 0.5 * slave.L + slave.s - lord.s

if group == AlignmentGroup && (group_changed ||changed.this_ele_length)
if haskey(lord.pdict, :BendGroup)
bgl = lord.pdict[:BendGroup]
bgs = slave.pdict[:BendGroup]
# Need transformation from lord alignment point to slave alignment point
# Translate from lord alignment point to beginning of lord point
floor = OrientationGroup(r = [0, 0, -0.5*lord.l_chord])
ct = OrientationGroup(r = [0.0, 0.0, -0.5*bgl.l_chord])
# Rotate from z parallel to lord chord to z tangent to bend curve.
if lord.ref_tilt != 0
q = []
end
# On the bend curve: From beginning of lord point to beginning of slave point
# From z tangent to bend curve to z parallel to slave chord.
# Translate from beginning of slave point to slave alignment point.
ct = rot(ct, bend_quaternion(-0.5*bgl.angle, bg.ref_tilt))
# Transform from beginning of lord to beginning of slave
ct = coord_transform(slave.s - lord.s, bgl.g, bgl.ref_tilt)
# Rotate from z tangent to bend curve to z parallel to slave chord.
ct = rot(ct, bend_quaternion(0.5*bgs.angle, bg.ref_tilt))
# translate from beginning of slave to center of slave chord.
ct.r = ct.r + [0.0, 0.0, 0.5*bgs.l_chord]
# Apply total transformation of AlignmentGroup.

else
slave.r_floor = lord.r_floor + dL * rot(lord.q_floor, [0.0, 0.0, dL])
slave.AlignmentGroup = coord_transform(lord.pdict[:AlignmentGroup], ct)
end
end

slave.pdict[Symbol(group)] = lord.pdict[Symbol(group)]
slave.pdict[:changed][group] = "changed"
end

# Now bookkeep the slave
Expand Down Expand Up @@ -275,7 +294,7 @@ function bookkeeper_multipass_slave!(slave::Ele, changed::ChangedLedger, previou
if group == ReferenceGroup; continue; end # Slave ReferenceGroup independent of lord
if group == DownstreamReferenceGroup; continue; end

slave.pdict[Symbol(group)] = lord.pdict[Symbol(group)]
slave.pdict[Symbol(group)] = deepcopy(lord.pdict[Symbol(group)])
slave.pdict[:changed][group] = "changed"
end

Expand Down Expand Up @@ -371,15 +390,15 @@ function elegroup_bookkeeper!(ele::Ele, group::Type{BMultipoleGroup}, changed::C
if ele.slave_status == Slave.SUPER
lord = ele.super_lords[1]
L_rel = ele.L / lord.L
for (ix, lpole) in enumerate(lord.param[:BMultipoleGroup].pole)
epole = ele.param[:BMultipole].pole[ix]
for (ix, lpole) in enumerate(lord.pdict[:BMultipoleGroup].pole)
epole = deepcopy(ele.pdict[:BMultipoleGroup].pole[ix])
if lpole.integrated
epole.Kn = lpole.Kn * L_rel
epole.Bn = lpole.Bn * L_rel
epole.Ks = lpole.Ks * L_rel
epole.Bs = lpole.Bs * L_rel
else
ele.param[:BMultipole].pole[ix] = copy(lpole)
ele.pdict[:BMultipoleGroup].pole[ix] = deepcopy(lpole)
end
end

Expand Down Expand Up @@ -431,7 +450,7 @@ function elegroup_bookkeeper!(ele::Ele, group::Type{BendGroup}, changed::Changed
if ele.slave_status == Slave.SUPER
lord = ele.super_lords[1]
L_rel = ele.L / lord.L
ix_slave = slave_index(slave)
ix_slave = slave_index(ele)
ele.BendGroup = copy(lord.BendGroup)
bg = ele.BendGroup
bg.angle = lord.angle * L_rel
Expand Down Expand Up @@ -665,16 +684,7 @@ function elegroup_bookkeeper!(ele::Ele, group::Type{ReferenceGroup}, changed::Ch
end
end

# Super lord bookkeeping if this is the first (upstream) slave of the lord.

if ele.slave_status == Slave.SUPER
lord = ele.super_lords[1]
if lord.pdict[:slaves][1] === ele
lord.ReferenceGroup = rg
haskey(lord.pdict, :changed) ? lord.changed = Dict(ReferenceGroup => "changed") :
lord.changed[ReferenceGroup] = "changed"
end
end
# End stuff

clear_changed!(ele, ReferenceGroup)
changed.ref_group = (old_drg != drg)
Expand Down Expand Up @@ -761,7 +771,7 @@ function has_changed(ele::Ele, group::Type{T}) where T <: EleParameterGroup
for param in keys(lord.changed)
if param == AllGroup; return true; end
if param == group; return true; end
info = lord_param_info(param, lord, throw_error = false)
info = ele_param_info(param, lord, throw_error = false)
if isnothing(info); continue; end
if info.parent_group == group; return true; end
end
Expand Down Expand Up @@ -939,7 +949,7 @@ these parameters to the corresponding arguments if the arguments are not `nothin

function push_bookkeeping_state!(lat::Lattice; auditing_enabled::Union{Bool,Nothing} = nothing,
autobookkeeping::Union{Bool,Nothing} = nothing)
push!(lat.private[:bookkeeping_state], lat.pdict)
push!(lat.private[:bookkeeping_state], copy(lat.pdict))
if !isnothing(auditing_enabled); lat.pdict[:auditing_enabled] = auditing_enabled; end
if !isnothing(autobookkeeping); lat.pdict[:autobookkeeping] = autobookkeeping; end
end
Expand Down
94 changes: 67 additions & 27 deletions src/geometry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ function propagate_ele_geometry(::Type{ZERO_LENGTH}, fstart::OrientationGroup, e
end

function propagate_ele_geometry(::Type{STRAIGHT}, fstart::OrientationGroup, ele::Ele)
r_floor = fstart.r + rot(fstart.q, [0.0, 0.0, ele.L])
r_floor = fstart.r + rot([0.0, 0.0, ele.L], fstart.q)
return OrientationGroup(r_floor, fstart.q)
end

function propagate_ele_geometry(::Type{CIRCULAR}, fstart::OrientationGroup, ele::Ele)
df = floor_transform(ele.BendGroup, ele.L)
return floor_transform(fstart, df)
df = coord_transform(ele.L, ele.BendGroup.angle, ele.BendGroup.tilt_ref)
return coord_transform(fstart, df)
end

function propagate_ele_geometry(::Type{PATCH_GEOMETRY}, fstart::OrientationGroup, ele::Ele)
Expand All @@ -46,54 +46,94 @@ function propagate_ele_geometry(::Type{CRYSTAL_GEOMETRY}, fstart::OrientationGro
end

#---------------------------------------------------------------------------------------------------
# floor_transform
# coord_transform

"""
floor_transform(bend::BendGroup, L::Number) -> OrientationGroup
coord_transform(ds::Number, g::Number, tilt_ref::Number = 0) -> OrientationGroup

Returns the transformation of the coordinates from the beginning of a bend to the end of the bend.
Returns the coordinate transformation from one point on the arc with radius `1/g` of a Bend to another
point that is an arc distance `ds` from the first point.

The transformation is
r_end = r_start + rot(q_start, dr)
r_end = r_start + rot(dr, q_start)
q_end = q_start * dq
""" floor_transform(bend::BendGroup, L::Number)
""" coord_transform(ds::Number, g::Number, tilt_ref::Number)

function floor_transform(bend::BendGroup, L)
qa = rotY(bend.angle)
r_vec = [-L * sinc(bend.angle/(2*pi)) * sin(bend.angle), 0.0, L * sinc(bend.angle/pi)]
function coord_transform(ds::Number, g::Number, tilt_ref::Number)
if g == 0
return OrientationGroup([0.0, 0.0, ds], Quaternion())

if bend.tilt_ref == 0
return OrientationGroup(r_vec, qa)
else
qt = rotZ(-bend.tilt_ref)
return OrientationGroup(rot(qt, r_vec), qt * qa * inv(qt))
angle = ds/g
r_vec = [-ds * sinc(angle/(2*pi)) * sin(angle), 0.0, ds * sinc(angle/(2*pi))]

qa = rotY(-angle)
if tilt_ref == 0
return OrientationGroup(r_vec, qa)
else
qt = rotZ(-tilt_ref)
return OrientationGroup(rot(r_vec, qt), qt * qa * inv(qt))
end
end
end

#---------------------------------------------------------------------------------------------------
# floor_transform
# coord_transform

"""
floor_transform(floor0::OrientationGroup, dfloor::OrientationGroup) -> OrientationGroup
coord_transform(coord0::OrientationGroup, dcoord::OrientationGroup) -> OrientationGroup

Returns coordinate transformation of `dfloor` applied to `floor0`.
""" floor_transform(floor0::OrientationGroup, dfloor::OrientationGroup)
Returns coordinate transformation of `dcoord` applied to `coord0`.
""" coord_transform(coord0::OrientationGroup, dcoord::OrientationGroup)

function floor_transform(floor0::OrientationGroup, dfloor::OrientationGroup)
r_floor = floor0.r + rot(floor0.q, dfloor.r)
q_floor = floor0.q * dfloor.q
return OrientationGroup(r_floor, q_floor)
function coord_transform(coord0::OrientationGroup, dcoord::OrientationGroup)
r_coord = coord0.r + rot(dcoord.r, coord0.q)
q_coord = coord0.q * dcoord.q
return OrientationGroup(r_coord, q_coord)
end

#---------------------------------------------------------------------------------------------------
# bend_quaternion

"""
bend_quaternion(angle::Number, tilt_ref::Number) -> Quaternion

Quaternion representing the coordinate rotation for a bend through an angle `angle` with
a `tilt_ref` reference tilt.
""" bend_quaternion

return bend_quaternion(angle::Number, tilt_ref::Number)
if tilt_ref == 0
return rotY(-angle)
else
qt = rotZ(-tilt_ref)
return qt * rotY(-angle) * inv(qt)
end
end

#---------------------------------------------------------------------------------------------------
# rot!

"""
rot!(coord::OrientationGroup, q::Quaternion) -> OrientationGroup

Rotates coordinate position `coord` by `q`.
"""
function rot!(coord::OrientationGroup, q::Quaternion)
coord.r = rot(coord.r, q)
coord.q = q * coord.q
return coord
end

#---------------------------------------------------------------------------------------------------
# rot

"""
rot(floor0::OrientationGroup, q::Quaternion) -> OrientationGroup
rot(coord::OrientationGroup, q::Quaternion) -> OrientationGroup

Rotates by `q` the floor position `floor0`.
Rotates coordinate position `coord` by `q`.
"""
function rot(floor0::OrientationGroup, q::Quaternion)
return OrientationGroup(r = rot(q, floor0.r), q = q * floor0.q)
function rot(coord::OrientationGroup, q::Quaternion)
return OrientationGroup(r = rot(coord0.r, q), q = q * coord0.q)
end

Loading
Loading