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
7 changes: 7 additions & 0 deletions manual/construction.tex
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ \chapter{Constructing Lattices}
parameters of qq will not affect any of the copies in the lattice. This is done so that
parameters in the various qq's in the lattice are independent and an therefore differ from each
other.

Branch geometry is inherited from the root line. To use a line with the "wrong" geometry, create
a new line using the old line with the "correct" geometry. EG
ln2 = beamline(ln1.name, [ln1], geometry = CLOSED)
lat = expand([ln2])

Note: OPEN and CLOSED are aliases for BranchGeometry.OPEN and BranchGeometry.CLOSED
2 changes: 1 addition & 1 deletion src/AcceleratorLattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ module AcceleratorLattice
export InfiniteLoop, Branch, Lat, BeamLineEle, superimpose!, multipole_type
export BeamLineItem, BeamLine, Ele, propagate_ele_geometry, ele_floor_transform
export split!, construct_ele_type, LatEleLocation, ele_at_s, add_governor!
export eles, next_ele, ele_at_index
export eles, next_ele, ele_at_offset
export branch, matches_branch, param_groups_list, create_ele_vars
export EleParameterGroup, AlignmentGroup, FloorPositionGroup, BMultipole1, BMultipoleGroup
export EMultipole1, EMultipoleGroup, BendGroup, ApertureGroup, StringGroup, RFGroup, SolenoidGroup
Expand Down
13 changes: 11 additions & 2 deletions src/enum.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,26 @@
"""
enumit(str::AbstractString)

Makes list into a enum group and exports the names
Makes list into a enum group and exports the names.
Also overloads Base.string so that something like `string(Lord.NOT)` will return "Lord.NOT"
instead of just "NOT". Exception: `BranchGeometry.OPEN` and `BranchGeometry.CLOSED` will
return `OPEN` and `CLOSED`.
""" enumit

macro enumit(str::AbstractString)
eval( Meta.parse("@enumx $str") )
str2 = join(split(str), ',')
str_split = split(str)
str2 = join(str_split, ',')
eval( Meta.parse("export $str2") )
s = "Base.string(z::$(str_split[1]).T) = \"$(str_split[1]).\" * string(Symbol(z))"
if str_split[1] != "BranchGeometry"; eval( Meta.parse(s) ); end
end

@enumit("ApertureShape RECTANGULAR ELLIPTICAL")
@enumit("BendType SECTOR RECTANGULAR")
@enumit("BodyLoc ENTRANCE_END CENTER EXIT_END BOTH_ENDS NOWHERE EVERYWHERE")
@enumit("BranchGeometry OPEN CLOSED")
## @enumit("EleGeometry STRAIGHT CIRCULAR ZEROLENGTH PATCH GIRDER CRYSTAL MIRROR")
@enumit("Cavity STANDING_WAVE TRAVELING_WAVE")
@enumit("SlaveControl DELTA ABSOLUTE NOT_SET")
@enumit("FieldCalc MAP STANDARD")
Expand All @@ -32,3 +39,5 @@ end

CLOSED::BranchGeometry.T = BranchGeometry.CLOSED
OPEN::BranchGeometry.T = BranchGeometry.OPEN


150 changes: 116 additions & 34 deletions src/find.jl
Original file line number Diff line number Diff line change
@@ -1,46 +1,94 @@
#---------------------------------------------------------------------------------------------------
# ele_at_index
# ele_at_offset

"""
ele_at_index(branch::Branch, ix_ele::Int; wrap::Bool = true, ele0::Ele = NULL_ELE) -> ele::Ele
ele_at_offset(reference::Union{Ele,Branch}, offset::Int, wrap) -> ele::Ele
ele_at_offset(reference::Union{Ele,Branch}, offset::Int; wrap::Bool = true) -> ele::Ele

Returns element with index `ix_ele` in branch `branch`.
If `ele0` is not `NULL_ELE`, `ix_ele` will be offset by `ele0.ix_ele`.
If `reference` is a `Branch`, this routine returns the element whose index is equal to `offset`.

With `wrap` = `false`, an error is raised if `ix_ele` is out-of-bounds.
If `reference` is an `Ele`, this routine returns the element with index equal to `reference.ix_ele + offset`
in the branch containing `reference`. Exceptions:
- A non-zero `offset` is not legal for `Governor` elements.
- If the `reference` is a `multipass_lord`, return the `multipass_lord` whose slaves are all
`offset` away from the corresponding slaves of `reference`. If no such `mulitpass_lord` exists,
throw an error.
- If the `reference` is a `super_lord` element the index of the returned element is `N + offset` where,
if `offset` is positive, `N` is the index of the last (that is, downstream) `super_slave` element and,
if `index` is negative, `N` is the index of the first (that is, upstream) `super_slave` element.

With `wrap` = `true`, if `ix_ele` is out-of-bounds, will "wrap" around ends of the branch so,
for a branch with `N` elements,
`ix_ele = N+1` will return `branch.ele[1]` and `ix_ele = 0` will return `branch.ele[N]`.
""" ele_at_index
With `wrap` = `false`, an error is raised if the element index is not in the range `[1, end]` where
`end` is the index of the last element in `branch.ele[]` array.

function ele_at_index(branch::Branch, ix_ele::Int; wrap::Bool = true, ele0::Ele = NULL_ELE)
if ele0 != NULL_ELE; ix_ele = ix_ele + ele0.ix_ele; end
With `wrap` = `true`, if the element index is out-of-bounds, the index will be "wrapped around"
the ends of the branch so, for example, for a branch with `N` elements,
`index = N+1` will return `branch.ele[1]` and `index = 0` will return `branch.ele[N]`.
""" ele_at_offset

function ele_at_offset(reference::Union{Ele,Branch}, offset::Int, wrap::Bool)

if typeof(reference) == Branch
branch = reference
indx = offset

else
branch = reference.branch
indx = reference.ix_ele + offset

if offset != 0
if branch.type == GovernorBranch
error("Non-zero offset ($offset) not allowed for Governor reference elements ($reference.name).")

elseif branch.type == SuperLordBranch
if offset > 0 ? ref = reference.slaves[end] : ref = reference.slaves[1]; end
branch = ref.branch
indx = ref.ix_ele + offset

elseif branch.type == MultipassLordBranch
slaves = [ele_at_offset(slave, offset, wrap) for slave in reference.slaves]
for slave in slaves
if !(get(slave, :multipass_lord, NULL_ELE) === get(slaves[1], :multipass_lord, nothing))
error("Cannot find multipass_lord at offset ($offset) from element ($(ele_name(reference))).")
end
end
return slave.multipass_lord
end
end
end

!

n = length(branch.ele)

if wrap
if n == 0; error(f"BoundsError: " * # Happens with lord branch with no lord elements
f"Element index: {ix_ele} out of range in branch {branch.ix_branch}: {branch.name}"); end
ix_ele = mod(ix_ele-1, n) + 1
return branch.ele[ix_ele]
if n == 0; error("BoundsError: " * # Happens with lord branch with no lord elements
"Element index: $indx out of range in branch $(branch.ix_branch): $(branch.name)"); end
indx = mod(indx-1, n) + 1
return branch.ele[indx]
else
if ix_ele < 1 || ix_ele > n; error(f"BoundsError: " *
f"Element index: {ix_ele} out of range in branch {branch.ix_branch}: {branch.name}"); end
return branch.ele[ix_ele]
if indx < 1 || indx > n; error(f"BoundsError: " *
"Element index: $indx out of range in branch $(branch.ix_branch): $(branch.name)"); end
return branch.ele[indx]
end
end

#

function ele_at_offset(reference::Union{Ele,Branch}, offset::Int; wrap::Bool = true)
return ele_at_offset(reference, offset, wrap)
end

#---------------------------------------------------------------------------------------------------
# eles_base

"""
Internal: function eles_base(where_search::Union{Lat,Branch}, who::Union{AbstractString,Regex})
Internal: function eles_base(where_search::Union{Lat,Branch}, who::Union{AbstractString,Regex};
wrap::Bool = true) -> ele_vector::Ele[]

Internal. Called by `eles` function.
""" eles_base

function eles_base(where_search::Union{Lat,Branch}, who::Union{AbstractString,Regex})
function eles_base(where_search::Union{Lat,Branch}, who::Union{AbstractString,Regex}; wrap::Bool = true)
julia_regex = (typeof(who) == Regex)
who = string(who)
typeof(where_search) == Lat ? branch_vec = where_search.branch : branch_vec = [where_search]
Expand Down Expand Up @@ -68,9 +116,9 @@ function eles_base(where_search::Union{Lat,Branch}, who::Union{AbstractString,Re
for ele in branch.ele
if !haskey(ele.pdict, attrib); continue; end
if julia_regex
if occursin(pattern, ele.pdict[attrib]); push!(eles, ele_offset(ele, offset)); end
if occursin(pattern, ele.pdict[attrib]); push!(eles, ele_at_offset(ele, offset, wrap)); end
else
if str_match(pattern, ele.pdict[attrib]); push!(eles, ele_offset(ele, offset)); end
if str_match(pattern, ele.pdict[attrib]); push!(eles, ele_at_offset(ele, offset, wrap)); end
end
end
end
Expand Down Expand Up @@ -106,7 +154,7 @@ function eles_base(where_search::Union{Lat,Branch}, who::Union{AbstractString,Re
for branch in branch_vec
if !matches_branch(branch_id, branch); continue; end
if ix_ele != -1
push!(eles, ele_at_index(branch, ix_ele+offset, wrap = false))
push!(eles, ele_at_offset(branch, branch.ele[ix_ele], offset, wrap))
continue
end

Expand All @@ -119,7 +167,7 @@ function eles_base(where_search::Union{Lat,Branch}, who::Union{AbstractString,Re
if !str_match(ele_id, ele.name); continue; end
ix_match += 1
if nth_match != -1 && ix_match > nth_match; continue; end
if ix_match == nth_match || nth_match == -1; push!(eles, ele_at_index(branch, offset, ele0=ele)); end
if ix_match == nth_match || nth_match == -1; push!(eles, ele_at_offset(ele, offset, wrap)); end
end
end
end # branch loop
Expand All @@ -132,17 +180,47 @@ end
# eles

"""
function eles(where_search::Union{Lat,Branch}, who::Union{AbstractString,Regex}) -> [ele-array]

Returns a vector of all elements that match `who`.
function eles(where_search::Union{Lat,Branch}, who::Union{AbstractString,Regex}; wrap::Bool = True)
-> ele_vector::Ele[]

Returns a vector of all elements that match `who`.

There are two types of `who`.
On type uses a Julia `Regex` expression to match to element names. For example:
```
who = r"q\\d" # Matches "qN" where "N" is a digit 0-9.
```
See the Julia regex documentation for more information.

The other types of matches are those using the "AcceleratorLattice" (AL) regex syntax.
This syntax has wild card characters “*” and “%”.
The “*” character will match any number of characters (including zero) while “%” maches to any single character.

All AL regex expressions are built up from "atomic" expressions. Atomic expressions are of
one of two forms: One atomic form is:
```
{branch_id>>}{ele_class::}ele_id{#N}{+/-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.
- `ele_class` Optional element class (EG: `Quadrupole`).
- `ele_id` Element name with or element index. The element name can contain wild card characters.
- `#N` If present, return only the Nth instance matched to.
- `+/-offset` If present, return element(s) whose index is offset from the elements matched to.

Examples:
```
eles(lat, "d") All elements named "d"
eles(lat, "Marker::*")
eles(lat, "Marker::*-1")
eles(lat, "m1#2")
eles(lat, "m1#2+1")
```

#


Returns a vector of all lattice elements that match element `who` which is in the form:
`{branch_id>>}{key::}ele_id{#N}{+/-offset}`
or
`{branch_id>>}attribute->match_str{+/-offset}`
`{branch_id>>}attribute->'match_str'{+/-offset}`
where `attribute` is something like `alias`, `description`, `type`, or any custom field.

key selection EG: "Quadrupole::<list>"
Expand All @@ -151,12 +229,16 @@ where `attribute` is something like `alias`, `description`, `type`, or any custo
intersection EG: "<list1> & <list2>"
Note: negation and intersection evaluated left to right

### Input
## Input

- `where_search` `Lat` or `Branch` to search.
- `who` `String` or `Regex` to use in the search.

## Notes:

- Element order is not guaranteed. Use
"""
function eles(where_search::Union{Lat,Branch}, who::Union{AbstractString,Regex})
function eles(where_search::Union{Lat,Branch}, who::Union{AbstractString,Regex}; wrap::Bool = true)
# Julia regex is simple
if typeof(who) == Regex; return eles_base(where_search, who); end

Expand Down
2 changes: 1 addition & 1 deletion src/init_bookkeeper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ end
# init_superimpose!(Branch, superimpose)

function init_superimpose!(branch::Branch, superimpose::Vector{T}) where T <: Ele
if branch.pdict[:type] == LordBranch; return; end
if branch.pdict[:type] <: LordBranch; return; end

changed = ChangedLedger(false, true, true, true, true)
previous_ele = nothing
Expand Down
4 changes: 2 additions & 2 deletions src/lat_construction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ All parameters are optional.
function beamline(name::AbstractString, line::Vector{T}; kwargs...) where T <: BeamLineItem
bline = BeamLine(name, BeamLineItem.(line), Dict{Symbol,Any}(kwargs))
if !haskey(bline.pdict, :orientation); bline.pdict[:orientation] = +1; end
if !haskey(bline.pdict, :geometry); bline.pdict[:geometry] = open; end
if !haskey(bline.pdict, :geometry); bline.pdict[:geometry] = OPEN; end
if !haskey(bline.pdict, :multipass); bline.pdict[:multipass] = false; end

for (ix, item) in enumerate(bline.line)
Expand Down Expand Up @@ -243,7 +243,7 @@ Used by the `expand` function.

function new_tracking_branch!(lat::Lat, bline::Union{BeamLine, Tuple})
if typeof(bline) == Tuple{BeginningEle, BeamLine}
bline = beamline(bline[2].name, [bline[1], bline[2]])
bline = beamline(bline[2].name, [bline[1], bline[2]], geometry = bline[2].pdict[:geometry])
end

push!(lat.branch, Branch(bline.name, Vector{Ele}(), Dict{Symbol,Any}(:geometry => bline.pdict[:geometry])))
Expand Down
Loading
Loading