diff --git a/manual/ele-types.tex b/manual/ele-types.tex index dda69c8..820a247 100644 --- a/manual/ele-types.tex +++ b/manual/ele-types.tex @@ -361,7 +361,7 @@ \section{Fork} Element parameter groups associated with this element type are: \TOPrule \begin{example} - FloorParams -> Floor floor position and orientation. \sref{s:orientation.g} + FloorParams -> Floor floor position and orientation. \sref{s:orientation.g} LengthParams -> Length and s-position parameters. \sref{s:length.g} DescriptionParams -> Element descriptive strings. \sref{s:descrip.g} TrackingParams -> Default tracking settings. \sref{s:tracking.g} @@ -381,12 +381,13 @@ \section{Fork} The components of this group are: \begin{example} - to_line::Union{BeamLine,Branch} - Beam line to fork to - to_ele::Union{String,Ele} - Element forked to. + to_line::Union{BeamLine,Nothing} - Beam line to fork to. Default: nothing. + to_ele::Union{String,Ele,Nothing} - Element forked to. Default: nothing. direction::Int - Longitudinal Direction of injected beam. \end{example} - +If \vn{to_line} is set to a \vn{BeamLine} -> New branch +Otherwise the fork is to an existing lattice element. diff --git a/src/bookkeeper.jl b/src/bookkeeper.jl index 64a65df..96129f4 100644 --- a/src/bookkeeper.jl +++ b/src/bookkeeper.jl @@ -591,6 +591,7 @@ function ele_paramgroup_bookkeeper!(ele::Ele, group::Type{ForkParams}, changed::ChangedLedger, previous_ele::Ele) fg = ele.ForkParams rg = ele.ReferenceParams + clear_changed!(ele, ForkParams) to_ele = fg.to_ele to_ele.ix_ele != 1 && return @@ -608,8 +609,6 @@ function ele_paramgroup_bookkeeper!(ele::Ele, group::Type{ForkParams}, to_ele.pc_ref = rg.pc_ref set_branch_min_max_changed!(to_ele.branch, 1) - clear_changed!(ele, ForkParams) - return end @@ -955,35 +954,50 @@ Adds the `Branch` that is forked to to the lattice. """ fork_bookkeeper function fork_bookkeeper(fork::Ele) - # No to_line means fork to existing element. - if isnothing(fork.to_line) - if typeof(fork.to_ele) != Ele; error("Since to_line is not specified for fork $(fork.name),\n" * - "to_ele must be an actual element in a lattice."); end - lat = lattice(ele) - if isnothing(lat); error("Since to_line is not specified for fork $(fork.name),\n" * - "to_ele must be in a lattice and not external."); end - - # Fork to new branch - else - lat = fork.branch.lat + isnothing(fork.to_ele) && isnothing(fork.to_line) && + error("Neither to_ele nor to_line set for Fork element $(fork.name)") + isnothing(fork.to_ele) && typeof(fork.to_line) == Lattice && + error("to_ele not set for fork element $(fork.name)") + + lat = fork.branch.lat + + # If to_line is a BeamLine then forking to a new branch + if typeof(fork.to_line) == BeamLine + typeof(fork.to_ele) == Ele && !isnothing(lattice(fork.to_ele)) && error( + "Confusion: to_line is a BeamLine and to_ele is associated with a Lattice for fork element $(fork.name).") + to_branch = new_tracking_branch!(lat, fork.to_line) - if typeof(fork.to_ele) == Ele; error( - "Since to_line is specified, to_ele must be something (String, Regex) that can be used with \n" * - "the `find` function to locate the element in the new branch and cannot be an existing element."); end - if fork.to_ele == "" + if isnothing(fork.to_ele) fork.to_ele = to_branch[1] else - to_ele = eles_search(lat, fork.to_ele) - if length(to_ele) == 0; error("to_ele ($(fork.to_ele)) not found in new branch for fork $(fork.name)."); end - if length(to_ele) > 1; error("Multiple elements matched to to_ele ($(fork.to_ele)) for fork $(fork.name)."); end - fork.to_ele = to_ele[1] - end + if typeof(fork.to_ele) == Ele + name = fork.to_ele.name + else # String + name = fork.to_ele + end - to_ele = fork.to_ele - if to_ele.ix_ele == 1 - to_ele.from_forks = [fork] + to_eles = eles_search(to_branch, name) + if length(to_eles) == 0; error("to_ele $name not found in new branch for fork $(fork.name)."); end + if length(to_eles) > 1; error("Multiple elements matched to to_ele $name) for fork $(fork.name)."); end + fork.to_ele = to_eles[1] end + + # to_line is nothing means fork to existing element. + elseif typeof(fork.to_ele) == String + to_eles = eles_search(lat, fork.to_ele) + if length(to_eles) == 0; error("to_ele $name not found in new branch for fork $(fork.name)."); end + if length(to_eles) > 1; error("Multiple elements matched to to_ele $name) for fork $(fork.name)."); end + fork.to_ele = to_eles[1] + end + + # + + to_ele = fork.to_ele + if haskey(to_ele.pdict, :from_forks) + push!(to_ele.pdict[:from_forks], fork) + else + to_ele.pdict[:from_forks] = Vector{Ele}([fork]) end return diff --git a/src/lat_construction.jl b/src/lat_construction.jl index e1c0747..0d15e13 100644 --- a/src/lat_construction.jl +++ b/src/lat_construction.jl @@ -242,14 +242,17 @@ function new_tracking_branch!(lat::Lattice, bline::BeamLine) for outer ib in reverse(1:length(lat.branch)) if lat.branch[ib].type == TrackingBranch; break; end end + ib += 1 - insert!(lat.branch, ib+1, Branch(name = bline.pdict[:name], lat = lat, + insert!(lat.branch, ib, Branch(name = bline.pdict[:name], lat = lat, pdict = Dict{Symbol,Any}(:geometry => bline.pdict[:geometry]))) - branch = lat.branch[ib+1] + for ix in ib:length(lat.branch) + lat.branch[ix].pdict[:ix_branch] = ix + end - branch.pdict[:ix_branch] = length(lat.branch) + branch = lat.branch[ib] branch.pdict[:type] = TrackingBranch - if branch.name == ""; branch.name = "B" * string(length(lat.branch)); end + if branch.name == ""; branch.name = "B" * string(ib); end info = LatticeConstructionInfo([], bline.pdict[:orientation], 0) if haskey(bline.pdict, :species_ref); branch.ele[1].species_ref = bline.pdict[:species_ref]; end @@ -262,7 +265,7 @@ function new_tracking_branch!(lat::Lattice, bline::BeamLine) add_beamline_ele_to_branch!(branch, BeamLineItem(bline.pdict[:end_ele])) else @ele end_ele = Marker() - end_ele.pdict[:name] = "end$(length(lat.branch))" + end_ele.pdict[:name] = "end$(ib)" add_beamline_ele_to_branch!(branch, BeamLineItem(end_ele)) end diff --git a/src/query.jl b/src/query.jl index c505395..0ec9122 100644 --- a/src/query.jl +++ b/src/query.jl @@ -96,17 +96,19 @@ function ele_geometry(ele::Ele) end #--------------------------------------------------------------------------------------------------- -# is_null(ele), is_null(branch) +# is_null(ele), is_null(branch), is_null(species """ is_null(ele::Ele) is_null(branch::Branch + is_null(species::Species) -Test if argument is either of the `NULL_ELE` or `NULL_BRANCH` constants. +Test if argument is either of the `NULL_ELE`, `NULL_BRANCH`, or null species. constants. """ is_null -is_null(ele::Ele) = return (ele.name == "NULL_ELE") -is_null(branch::Branch) = return (branch.name == "NULL_BRANCH") +is_null(ele::Ele) = (ele.name == "NULL_ELE") +is_null(branch::Branch) = (branch.name == "NULL_BRANCH") +is_null(species::Species) = (species == Species()) #--------------------------------------------------------------------------------------------------- # s_inbounds diff --git a/src/struct.jl b/src/struct.jl index 1c6345f..188c932 100644 --- a/src/struct.jl +++ b/src/struct.jl @@ -732,17 +732,17 @@ end Fork element parameters. ## Fields -• `to_line::Union{BeamLine,Nothing}` - Beam line to fork to. \\ -• `to_ele::Union{String,Ele}` - On input: Element ID or element itself. \\ -• `direction::Int` - Longitudinal Direction of injected beam. \\ -• `propagate_reference::Bool` - Propagate reference species and energy? \\ +• `to_line::Union{BeamLine,Nothing}` - Beam line to fork to. \\ +• `to_ele::Union{String,Ele,Nothing}` - On input: Element ID or element itself. \\ +• `direction::Int` - Longitudinal Direction of injected beam. \\ +• `propagate_reference::Bool` - Propagate reference species and energy? \\ """ ForkParams @kwdef mutable struct ForkParams <: EleParams to_line::Union{BeamLine,Nothing} = nothing - to_ele::Union{String,Ele} = "" + to_ele::Union{String,Ele,Nothing} = nothing direction::Int = +1 propagate_reference::Bool = true end diff --git a/src/utilities.jl b/src/utilities.jl index 7e9d653..abaadf4 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -7,11 +7,8 @@ """ lat_sanity_check(lat::Lattice) - Internal: lat_sanity_check(lat::Lattice, base_ele::Ele, pointed_ele::Ele, err_string::String) Does some self consistency checks on a lattice and throws an error if there is a problem. - -The internal version of `lat_sanity_check` is called by the public version and is not usable otherwise. """ lat_sanity_check function lat_sanity_check(lat::Lattice) @@ -40,43 +37,43 @@ function lat_sanity_check(lat::Lattice) end if haskey(pdict, :girder) - lat_sanity_check(lat, ele, pdict[:girder], "girder") + check_pointed(lat, ele, pdict[:girder], "girder") end if haskey(pdict, :multipass_lord) - lat_sanity_check(lat, ele, pdict[:multipass_lord], "multipass lord") + check_pointed(lat, ele, pdict[:multipass_lord], "multipass lord") end if haskey(pdict, :ForkParams) - lat_sanity_check(lat, ele, pdict[:ForkParams].to_ele, "a forked-to element") + check_pointed(lat, ele, pdict[:ForkParams].to_ele, "a forked-to element") if ele.L != 0; error("A Fork element may not have a non-zero length: $(ele_name(ele))"); end end if haskey(pdict, :OriginEleParams) - lat_sanity_check(lat, ele, pdict[:OriginEleParams].origin_ele, "the element's origin element") + check_pointed(lat, ele, pdict[:OriginEleParams].origin_ele, "the element's origin element") end if haskey(pdict, :super_lords) for lord in pdict[:super_lords] - lat_sanity_check(lat, ele, lord, "super lord") + check_pointed(lat, ele, lord, "super lord") end end if haskey(pdict, :slaves) for slave in pdict[:slaves] - lat_sanity_check(lat, ele, slave, "slave") + check_pointed(lat, ele, slave, "slave") end end if haskey(pdict, :from_forks) for fork in pdict[:from_forks] - lat_sanity_check(lat, ele, fork, "a fork that is forking to this element") + check_pointed(lat, ele, fork, "a fork that is forking to this element") end end if haskey(pdict, :GirderParams) for slave in pdict[:GirderParams].supported - lat_sanity_check(lat, ele, slave, "supported element") + check_pointed(lat, ele, slave, "supported element") end end @@ -85,12 +82,15 @@ function lat_sanity_check(lat::Lattice) end #------------------- -# Internal lat_sanity_check method +# Internal check_pointed method -function lat_sanity_check(lat::Lattice, base_ele::Ele, pointed_ele::Ele, err_string::String) +""" + Internal: check_pointed(lat::Lattice, base_ele::Ele, pointed_ele::Ele, err_string::String) +""" +function check_pointed(lat::Lattice, base_ele::Ele, pointed_ele::Ele, err_string::String) pele = lat.branch[pointed_ele.branch.ix_branch].ele[pointed_ele.ix_ele] if !(pointed_ele === pele) - error("Element $(ele_name(ele)) has a $err_string pointer to $(ele_name(pele)) but this\n" * + error("Element $(ele_name(base_ele)) has a $err_string pointer to $(ele_name(pele)) but this\n" * " pointed to element is in a different lattice!!!") end end diff --git a/test/fork_test.jl b/test/fork_test.jl index 7a3efcb..c0e4378 100644 --- a/test/fork_test.jl +++ b/test/fork_test.jl @@ -1,30 +1,42 @@ using AcceleratorLattice, Test @ele begin1 = BeginningEle(species_ref = Species("electron"), pc_ref = 1e6) -@ele begin2 = BeginningEle() - +@ele begin2 = BeginningEle(species_ref = Species("proton"), pc_ref = 1e7) +@ele begin3 = BeginningEle(species_ref = Species("photon"), E_tot_ref = 1e3) +@ele mk1 = Marker() @ele bend1 = Bend(g = 1, angle = pi/2, Kn2L = 0.1, Bs3 = 0.2, En4 = 0.3, Es5L = 0.4) +@ele dft = Drift(L = 2) bend2 = copy(bend1) bend2.name = "bend2" bend2.tilt_ref = pi/2 @ele fork1 = Fork() +@ele fork2 = Fork(propagate_reference = false) +@ele fork3 = Fork(to_ele = "mk1") -line1 = BeamLine([begin1, bend1, fork1]) +line1 = BeamLine([begin1, bend1, fork1, mk1]) line2 = BeamLine([begin2, bend2]) +line3 = BeamLine([begin3, dft, fork3]) + fork1.to_line = line2 +fork2.to_line = line3 lat = Lattice([line1]) +superimpose!(fork2, lat["bend2"], offset = 0.2) + b1 = lat.branch[1] b2 = lat.branch[2] + + @testset "bend_bookkeeping" begin end # test fork superimpose +# test fork with multipass # test fork to existing branch. # make sure finite L throws error. # check that forked to branch inherits reference energy from fork.