diff --git a/src/AcceleratorLattice.jl b/src/AcceleratorLattice.jl index 29bed7e..12ff19f 100644 --- a/src/AcceleratorLattice.jl +++ b/src/AcceleratorLattice.jl @@ -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 @@ -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 diff --git a/src/accessor.jl b/src/accessor.jl index a8dda61..a91895b 100644 --- a/src/accessor.jl +++ b/src/accessor.jl @@ -470,7 +470,7 @@ 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 @@ -478,7 +478,7 @@ 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 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 @@ -486,7 +486,7 @@ 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 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 @@ -494,7 +494,7 @@ 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 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 @@ -502,7 +502,7 @@ 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).q + return coord_transform(orient_ele, orient_girder).q end error("Parameter $sym is not in the output group $output_group.") diff --git a/src/bookkeeper.jl b/src/bookkeeper.jl index 8658496..e9fbebb 100644 --- a/src/bookkeeper.jl +++ b/src/bookkeeper.jl @@ -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 @@ -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 @@ -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 @@ -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 @@ -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) @@ -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 @@ -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 diff --git a/src/geometry.jl b/src/geometry.jl index 8f2922f..0ae0d30 100644 --- a/src/geometry.jl +++ b/src/geometry.jl @@ -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) @@ -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 diff --git a/src/manipulation.jl b/src/manipulation.jl index 1aafe05..088ca79 100644 --- a/src/manipulation.jl +++ b/src/manipulation.jl @@ -266,8 +266,7 @@ function split!(branch::Branch, s_split::Real; select::Select.T = Select.UPSTREA # representing the original drift in `branch.drift_masters` so that the names of drift slices can # be properly formed using a `!N` suffix where N is an integer. if typeof(slave1) == Drift - slave2 = copy(slave1) - insert!(branch.ele, slave1.ix_ele+1, slave2) # Just after slave1 + slave2 = insert!(branch, slave1.ix_ele+1, slave1) # Just after slave1 if haskey(slave1.pdict, :drift_master) master = slave1.pdict[:drift_master] @@ -295,8 +294,7 @@ function split!(branch::Branch, s_split::Real; select::Select.T = Select.UPSTREA # Split case 2: Element to be split is a super_slave. In this case no new lord is generated. if haskey(slave1.pdict, :super_lords) - slave2 = copy(slave1) - insert!(branch.ele, slave1.ix_ele+1, slave2) # Just after slave1 + slave2 = insert!(branch, slave1.ix_ele+1, slave1) # Just after slave1 slave1.L = s_split - slave1.s slave2.L = slave1.s_downstream - s_split slave1.pdict[:changed][AllGroup] = true @@ -323,16 +321,14 @@ function split!(branch::Branch, s_split::Real; select::Select.T = Select.UPSTREA # Important for multipass control that original slave1 is put in the super lord branch # and the copies are in the tracking branch. - lord = slave1 + lord = copy(slave1) - slave1 = copy(slave1) pop!(slave1.pdict, :multipass_lord, nothing) slave1.pdict[:super_lords] = Vector{Ele}([lord]) slave1.slave_status = Slave.SUPER branch.ele[slave1.ix_ele] = slave1 - slave2 = copy(slave1) - insert!(branch.ele, slave1.ix_ele+1, slave2) + slave2 = insert!(branch, slave1.ix_ele+1, slave1) slave1.L = s_split - lord.s slave2.L = lord.s_downstream - s_split slave1.pdict[:changed][AllGroup] = true diff --git a/src/quaternion.jl b/src/quaternion.jl index a4052e1..9f152ff 100644 --- a/src/quaternion.jl +++ b/src/quaternion.jl @@ -1,17 +1,3 @@ -#--------------------------------------------------------------------------------------------------- -# AxisAngle - -""" - struct AxisAngle - -The `axis` vector is not necessarily normalized. -""" AxisAngle - -struct AxisAngle - angle::Number - axis::Vector{Number} -end - #--------------------------------------------------------------------------------------------------- # rotX, rotY, rotZ @@ -32,16 +18,20 @@ rotZ(angle::Number) = Quaternion(cos(angle/2), [0, 0, sin(angle/2)]) """ Quaternion(aa::AxisAngle) - Quaternion(m::Matrix{T}) - Quaternion(x_rot::Real, y_rot::Real, z_rot::Real) - Quaternion(qv::Vector) # 4-vector + Quaternion(m::Matrix{T}) + Quaternion(x_rot::Number, y_rot::Number, z_rot::Number) + Quaternion(axis::Vector, angle::Number) + Quaternion() -> Unit Quaternion + +`Quaternion` constructors. +- `Quaternion` from axis rotations is computed by `rotY(y_rot) * rotX(x_rot) * rotZ(z_rot)` +- The `axis` vector does not have to be normalized. -Quaternion constructors. """ Quaternion -Quaternion(qv::Vector) = Quaternion(qv[1], qv[2:end]) +Quaternion() = Quaternion(1.0, 0.0, 0.0, 0.0) -Quaternion(x_rot::Real, y_rot::Real, z_rot::Real) = rotY(y_rot) * rotX(x_rot) * rotZ(z_rot) +Quaternion(x_rot::Number, y_rot::Number, z_rot::Number) = rotY(y_rot) * rotX(x_rot) * rotZ(z_rot) function Quaternion(aa::AxisAngle) if aa.angle == 0; return UNIT_QUAT; end @@ -71,20 +61,42 @@ function Quaternion(m::Matrix{T}) where T <: Number end end +function Quaternion(axis::Vector, angle::Number) + axis = axis / norm(axis) + return Quaternion(cos(0.5*angle), axis*sin(0.5*angle)) +end + #--------------------------------------------------------------------------------------------------- const UNIT_QUAT = Quaternion(1.0, [0.0, 0.0, 0.0]) +#--------------------------------------------------------------------------------------------------- +# rot! + +""" + rot!(v::Vector{T}, q::Quaternion) where {T} -> Vector{T} + +Rotation of a 3-vector `v` by a quaternion `q`. +""" rot!(v::Vector{T}, q::Quaternion) where {T} + +function rot!(v::Vector{T}, q::Quaternion) where {T} + vv = q * v / q + v[1] = vv.q1 + v[2] = vv.q2 + v[3] = vv.q3 + return v +end + #--------------------------------------------------------------------------------------------------- # rot """ - rot(q::Quaternion, v::Vector{T}) where {T} -> Vector{T} + rot(v::Vector{T}, q::Quaternion) where {T} -> Vector{T} Rotation of a 3-vector `v` by a quaternion `q`. -""" rot +""" rot(v::Vector{T}, q::Quaternion) where {T} -function rot(q::Quaternion, v::Vector{T}) where {T} +function rot(v::Vector{T}, q::Quaternion) where {T} vv = q * v / q return [vv.q1, vv.q2, vv.q3] end diff --git a/test/bookkeeper_test.jl b/test/bookkeeper_test.jl new file mode 100644 index 0000000..f06ddd9 --- /dev/null +++ b/test/bookkeeper_test.jl @@ -0,0 +1,15 @@ +using AcceleratorLattice, Test + +@ele begin1 = BeginningEle(species_ref = Species("electron"), pc_ref = 1e6) +@ele begin2 = BeginningEle(species_ref = Species("proton"), pc_ref = 1e6) + +@ele b1 = Bend(g = 1, angle = pi/2, Kn2L = 0.1, Bs3 = 0.2, En4 = 0.3, Es5L = 0.4) +b2 = copy(b1) +b2.tilt_ref = pi/2 + +line1 = BeamLine([begin1, b1]) +line2 = BeamLine([begin2, b2]) +lat = Lattice([line1, line2]) + +b1 = lat.branch[1] +b2 = lat.branch[2] \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index b963c80..f6083fe 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,6 +6,10 @@ using AcceleratorLattice, Test include("accessor_test.jl") end + @testset "bookkeeper_test" begin + include("bookkeeper_test.jl") + end + @testset "find_test" begin include("find_test.jl") end diff --git a/test/superimpose_test.jl b/test/superimpose_test.jl index ce7b2a5..7b710cc 100644 --- a/test/superimpose_test.jl +++ b/test/superimpose_test.jl @@ -38,7 +38,6 @@ b2 = lat.branch[2] @test [e.name for e in b1.ele] == ["beginning", "zm1", "zm2", "m1", "zm3", "d1!1", "zs2", "d1!2", "lc1!s1", "zm4", "lc1!s2", "d1!1", "zs2!s1", "m2", "zs2!s2", "d1!2", "d3", "end_ele"] - @test [e.name for e in b2.ele] == ["lc1", "zs2"] @test b1.ele[9].super_lords == [b2.ele[1]] @test b1.ele[11].super_lords == [b2.ele[1]] @@ -47,7 +46,32 @@ 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 + @test [e.slave_status for e in b1.ele] == + [Slave.NOT, Slave.NOT, Slave.NOT, Slave.NOT, Slave.NOT, Slave.NOT, + Slave.NOT, Slave.NOT, Slave.SUPER, Slave.NOT, Slave.SUPER, Slave.NOT, + Slave.SUPER, Slave.NOT, Slave.SUPER, Slave.NOT, Slave.NOT, Slave.NOT] + @test [e.lord_status for e in b1.ele] == + [Lord.NOT, Lord.NOT, Lord.NOT, Lord.NOT, Lord.NOT, Lord.NOT, + Lord.NOT, Lord.NOT, Lord.NOT, Lord.NOT, Lord.NOT, Lord.NOT, + Lord.NOT, Lord.NOT, Lord.NOT, Lord.NOT, Lord.NOT, Lord.NOT] + @test [e.slave_status for e in b2.ele] == [Slave.NOT, Slave.NOT] + @test [e.lord_status for e in b2.ele] == [Lord.SUPER, Lord.SUPER] + + @test isapprox([b1[9].extra_dtime_ref, b1[11].extra_dtime_ref, b2[1].extra_dtime_ref], + [7.0e-9, 3.0e-9, 10.0e-9], rtol = 1e-14) + @test isapprox([b1[9].time_ref, b1[11].time_ref, b2[1].time_ref], + [3.3399931243559422e-9, 1.2676210973138516e-8, 3.3399931243559422e-9], rtol = 1e-14) + @test isapprox([b1[9].time_ref_downstream, b1[11].time_ref_downstream, b2[1].time_ref_downstream], + [ 1.2676210973138516e-8, 1.6677084590208777e-8, 1.6677084590208777e-8], rtol = 1e-14) + @test isapprox([b1[9].dE_ref, b1[11].dE_ref, b2[1].dE_ref], [1.4e7, 6.0e6, 2.0e7], rtol = 1e-14) + @test isapprox([b1[9].E_tot_ref, b1[11].E_tot_ref, b2[1].E_tot_ref], + [1.0013047484537676e7, 2.4013047484537676e7, 1.0013047484537676e7], rtol = 1e-14) + @test isapprox([b1[9].E_tot_ref_downstream, b1[11].E_tot_ref_downstream, b2[1].E_tot_ref_downstream], + [2.4013047484537676e7, 3.001304748453768e7, 3.0013047484537676e7], rtol = 1e-14) + @test isapprox([b1[9].voltage, b1[11].voltage, b2[1].voltage], [7.0e7, 3.0e7, 10.0e7], rtol = 1e-14) + @test isapprox([b1[9].gradient, b1[11].gradient, b2[1].gradient], [1.0e8, 1.0e8, 1.0e8], rtol = 1e-14) + + ##@test end #---------------------------------------------------------------------------------------------------