Sequences
The MAD Sequences are objects convenient to describe accelerators lattices built from a list of elements with increasing s
-positions. The sequences are also containers that provide fast access to their elements by referring to their indexes, s
-positions, or (mangled) names, or by running iterators constrained with ranges and predicates.
The sequence
object is the root object of sequences that store information relative to lattices.
The sequence
module extends the typeid module with the is_sequence
function, which returns true
if its argument is a sequence
object, false
otherwise.
Attributes
The sequence
object provides the following attributes:
- l
A number specifying the length of the sequence
[m]
. Anil
will be replaced by the computed lattice length. A value greater or equal to the computed lattice length will be used to place the$end
marker. Other values will raise an error. (default:nil
).- dir
A number holding one of
1
(forward) or-1
(backward) and specifying the direction of the sequence. [1] (default:~1
)- refer
A string holding one of
"entry"
,"centre"
or"exit"
to specify the default reference position in the elements to use for their placement. An element can override it with itsrefpos
attribute, see element positions for details. (default:nil
\(\equiv\)"centre"
).
- minlen
A number specifying the minimal length
[m]
when checking for negative drifts or when generating implicit drifts between elements in \(s\)-iterators returned by the method:siter
. This attribute is automatically set to \(10^{-6}\) m when a sequence is created within the MADX environment. (default: \(10^{-6}\))- aperture
A mappable specifying the default aperture to consider when it’s missing at element level, e.g. in implicit drift. See Track command for default aperture.
Example:
aperture = {kind='square', 10}
.- beam
An attached
beam
. (default:nil
)
Warning: the following private and read-only attributes are present in all sequences and should never be used, set or changed; breaking this rule would lead to an undefined behavior:
- __dat
A table containing all the private data of sequences.
- __cycle
A reference to the element registered with the
:cycle
method. (default:nil
)
Methods
The sequence
object provides the following methods:
- elem
A method
(idx)
returning the element stored at the positive indexidx
in the sequence, ornil
.- spos
A method
(idx)
returning the \(s\)-position at the entry of the element stored at the positive indexidx
in the sequence, ornil
.- upos
A method
(idx)
returning the \(s\)-position at the user-definedrefpos
offset of the element stored at the positive indexidx
in the sequence, ornil
.- ds
A method
(idx)
returning the length of the element stored at the positive indexidx
in the sequence, ornil
.- align
A method
(idx)
returning a set specifying the misalignment of the element stored at the positive indexidx
in the sequence, ornil
.- index
A method
(idx)
returning a positive index, ornil
. Ifidx
is negative, it is reflected versus the size of the sequence, e.g.-1
becomes#self
, the index of the$end
marker.- name_of
A method
(idx, [ref])
returning a string corresponding to the (mangled) name of the element at the indexidx
ornil
. An element name appearing more than once in the sequence will be mangled with an absolute count, e.g.mq[3]
, or a relative count versus the optional reference elementref
determined by:index_of
, e.g.mq{-2}
.- index_of
A method
(a, [ref], [dir])
returning a number corresponding to the positive index of the element determined by the first argument ornil
. Ifa
is a number (or a string representing a number), it is interpreted as the \(s\)-position of an element and returned as a second number. Ifa
is a string, it is interpreted as the (mangled) name of an element as returned by:name_of
. Finally,a
can be a reference to an element to search for. The argumentref
(default:nil)
specifies the reference element determined by:index_of(ref)
to use for relative \(s\)-positions, for decoding mangled names with relative counts, or as the element to start searching from. The argumentdir
(default:1)
specifies the direction of the search with values1
(forward),-1
(backward), or0
(no direction). Thedir=0
case may return an index at half-integer ifa
is interpreted as an \(s\)-position pointing to an implicit drift.- range_of
A method
([rng], [ref], [dir]
) returning three numbers corresponding to the positive indexes start and end of the range and its direction dir, ornil
for an empty range. Ifrng
is omitted, it returns1
,#self
,1
, or#self
,1
,-1
ifdir
is negative. Ifrng
is a number or a string with no'/'
separator, it is interpreted as both start and end and determined byindex_of
. Ifrng
is a string containing the separator'/'
, it is split in two strings interpreted as start and end, both determined by:index_of
. Ifrng
is a list, it will be interpreted as {start, end,[ref]
,[dir]
}, both determined by:index_of
, unlessref
equals'idx'
then both are determined by:index
(i.e. a number is interpreted as an index instead of a \(s\)-position). The argumentsref
(default:nil
) anddir
(default:1
) are forwarded to all invocations of:index_of
with a higher precedence than ones in the listrng
, and a runtime error is raised if the method returnsnil
, i.e. to disambiguate between a valid empty range and an invalid range.- length_of
A method
([rng], [ntrn], [dir]
) returning a number specifying the length of the range optionally includingntrn
extra turns (default:0
), and calculated from the indexes returned by:range_of([rng], nil, [dir])
.- iter
A method
([rng], [ntrn], [dir])
returning an iterator over the sequence elements. The optional range is determined by:range_of(rng, [dir])
, optionally includingntrn
turns (default:0
). The optional directiondir
specifies the forward1
or the backward-1
direction of the iterator. Ifrng
is not provided and the mtable is cycled, the start and end indexes are determined by:index_of(self.__cycle)
. When used with a genericfor
loop, the iterator returns at each element: its index, the element itself, its \(s\)-position over the running loop and its signed length depending on the direction.- siter
A method
([rng], [ntrn], [dir])
returning an \(s\)-iterator over the sequence elements. The optional range is determined by:range_of([rng], nil, [dir])
, optionally includingntrn
turns (default:0
). The optional directiondir
specifies the forward1
or the backward-1
direction of the iterator. When used with a genericfor
loop, the iterator returns at each iteration: its index, the element itself or an implicitdrift
, its \(s\)-position over the running loop and its signed length depending on the direction. Each implicit drift is built on-the-fly by the iterator with a length equal to the gap between the elements surrounding it and a half-integer index equal to the average of their indexes. The length of implicit drifts is bounded by the maximum between the sequence attributeminlen
and theminlen
from the constant module.- foreach
A method
(act, [rng], [sel], [not])
returning the sequence itself after applying the actionact
on the selected elements. Ifact
is a set representing the arguments in the packed form, the missing arguments will be extracted from the attributesaction
,range
,select
anddefault
. The actionact
must be a callable(elm, idx, [midx])
applied to an element passed as first argument and its index as second argument, the optional third argument being the index of the main element in caseelm
is a sub-element. The optional range is used to generate the loop iterator:iter([rng])
. The optional selectorsel
is a callable(elm, idx, [midx])
predicate selecting eligible elements for the action using the same arguments. The selectorsel
can be specified in other ways, see element selections for details. The optional logicalnot
(default:false
) indicates how to interpret default selection, as all or none, depending on the semantic of the action. [2]- select
A method
([flg], [rng], [sel], [not])
returning the sequence itself after applying the action:select([flg])
to the elements using:foreach(act, [rng], [sel], [not])
. By default sequence have all their elements deselected with only the$end
markerobserved
.- deselect
A method
([flg], [rng], [sel], [not])
returning the sequence itself after applying the action:deselect([flg])
to the elements using:foreach(act, [rng], [sel], [not])
. By default sequence have all their elements deselected with only the$end
markerobserved
.- filter
A method
([rng], [sel], [not])
returning a list containing the positive indexes of the elements determined by:foreach(filt_act, [rng], [sel], [not])
, and its size. The logicalsel.subelem
specifies to select sub-elements too, and the list may contain non-integer indexes encoding their main element index added to their relative position, i.e.midx.sat
. The builtin functionmath.modf(num)
allows to retrieve easily the main elementmidx
and the sub-elementsat
, e.g.midx,sat = math.modf(val)
.- install
A method
(elm, [rng], [sel], [cmp])
returning the sequence itself after installing the elements in the listelm
at their element positions; unlessfrom="selected"
is defined meaning multiple installations at positions relative to each element determined by the method:filter([rng], [sel], true)
. The logicalsel.subelem
is ignored. If the arguments are passed in the packed form, the extra attributeelements
will be used as a replacement for the argumentelm
. The logicalelm.subelem
specifies to install elements with \(s\)-position falling inside sequence elements as sub-elements, and set theirsat
attribute accordingly. The optional callablecmp(elmspos, spos[idx])
(default:"<"
) is used to search for the \(s\)-position of the installation, where equal \(s\)-position are installed after (i.e. before with"<="
), seebsearch
from the miscellaneous module for details. The implicit drifts are checked after each element installation.- replace
A method
(elm, [rng], [sel])
returning the list of replaced elements by the elements in the listelm
placed at their element positions, and the list of their respective indexes, both determined by:filter([rng], [sel], true)
. The listelm
cannot contain instances ofsequence
orbline
elements and will be recycled as many times as needed to replace all selected elements. If the arguments are passed in the packed form, the extra attributeelements
will be used as a replacement for the argumentelm
. The logicalsel.subelem
specifies to replace selected sub-elements too and set theirsat
attribute to the same value. The implicit drifts are checked only once all elements have been replaced.- remove
A method
([rng], [sel])
returning the list of removed elements and the list of their respective indexes, both determined by:filter([rng], [sel], true)
. The logicalsel.subelem
specifies to remove selected sub-elements too.- move
A method
([rng], [sel])
returning the sequence itself after updating the element positions at the indexes determined by:filter([rng], [sel], true)
. The logicalsel.subelem
is ignored. The elements must keep their order in the sequence and surrounding implicit drifts are checked only once all elements have been moved. [3]- update
A method
()
returning the sequence itself after recomputing the positions of all elements.- misalign
A method
(algn, [rng], [sel])
returning the sequence itself after setting the element misalignments fromalgn
at the indexes determined by:filter([rng], [sel], true)
. Ifalgn
is a mappable, it will be used to misalign the filtered elements. Ifalgn
is a iterable, it will be accessed using the filtered elements indexes to retrieve their specific misalignment. Ifalgn
is a callable(idx)
, it will be invoked for each filtered element with their index as solely argument to retrieve their specific misalignment.- reflect
A method
([name])
returning a new sequence from the sequence reversed, and named from the optional stringname
(default:self.name..'_rev'
).- cycle
A method
(a)
returning the sequence itself after checking thata
is a valid reference using:index_of(a)
, and storing it in the__cycle
attribute, itself erased by the methods editing the sequence like:install
,:replace
,:remove
,:share
, and:unique
.- share
A method
(seq2)
returning the list of elements removed from theseq2
and the list of their respective indexes, and replaced by the elements from the sequence with the same name when they are unique in both sequences.- unique
A method
([fmt])
returning the sequence itself after replacing all non-unique elements by new instances sharing the same parents. The optionalfmt
must be a callable(name, cnt, idx)
that returns the mangled name of the new instance build from the elementname
, its countcnt
and its indexidx
in the sequence. If the optionalfmt
is a string, the mangling callable is built by bindingfmt
as first argument to the functionstring.format
from the standard library, see Lua 5.2 §6.4 for details.- publish
A method
(env, [keep])
returning the sequence after publishing all its elements in the environmentenv
. If the logicalkeep
istrue
, the method will preserve existing elements from being overridden. This method is automatically invoked withkeep=true
when sequences are created within theMADX
environment.- copy
A method
([name], [owner])
returning a new sequence from a copy ofself
, with the optionalname
and the optional attributeowner
set. If the sequence is a view, so will be the copy unlessowner == true
.- set_readonly
Set the sequence as read-only, including its columns.
- save_flags
A method
([flgs])
saving the flags of all the elements to the optional iterableflgs
(default:{}
) and return it.- restore_flags
A method
(flgs)
restoring the flags of all the elements from the iterableflgs
. The indexes of the flags must match the indexes of the elements in the sequence.- dumpseq
A method
([fil], [info])
displaying on the optional filefil
(default:io.stdout
) information related to the position and length of the elements. Useful to identify negative drifts and badly positioned elements. The optional argumentinfo
indicates to display extra information like elements misalignments.- check_sequ
A method () checking the integrity of the sequence and its dictionary, for debugging purpose only.
Metamethods
The sequence
object provides the following metamethods:
- __len
A metamethod () called by the length operator
#
to return the size of the sequence, i.e. the number of elements stored including the"$start"
and"$end"
markers.- __index
A metamethod
(key)
called by the indexing operator[key]
to return the value of an attribute determined by key. The key is interpreted differently depending on its type with the following precedence:A number is interpreted as an element index and returns the element or
nil
.Other key types are interpreted as object attributes subject to object model lookup.
If the value associated with key is
nil
, then key is interpreted as an element name and returns either the element or an iterable on the elements with the same name. [4]Otherwise returns
nil
.
- __newindex
A metamethod
(key, val)
called by the assignment operator[key]=val
to create new attributes for the pairs (key, value). If key is a number specifying the index or a string specifying the name of an existing element, the following error is raised:"invalid sequence write access (use replace method)"
- __init
A metamethod () called by the constructor to compute the elements positions. [5]
- __copy
A metamethod () similar to the
:copy
method.
The following attribute is stored with metamethods in the metatable, but has different purpose:
__sequ A unique private reference that characterizes sequences.
Sequences creation
During its creation as an object, a sequence can defined its attributes as any object, and the list of its elements that must form a sequence of increasing \(s\)-positions. When subsequences are part of this list, they are replaced by their respective elements as a sequence element cannot be present inside other sequences. If the length of the sequence is not provided, it will be computed and set automatically. During their creation, sequences compute the \(s\)-positions of their elements as described in the section element positions, and check for overlapping elements that would raise a “negative drift” runtime error.
The following example shows how to create a sequence form a list of elements and subsequences:
local sequence, drift, marker in MAD.element
local df, mk = drift 'df' {l=1}, marker 'mk' {}
local seq = sequence 'seq' {
df 'df1' {}, mk 'mk1' {},
sequence {
sequence { mk 'mk0' {} },
df 'df.s' {}, mk 'mk.s' {}
},
df 'df2' {}, mk 'mk2' {},
} :dumpseq()
Displays:
sequence: seq, l=3
idx kind name l dl spos upos uds
001 marker start 0.000 0 0.000 0.000 0.000
002 drift df1 1.000 0 0.000 0.500 0.500
003 marker mk1 0.000 0 1.000 1.000 0.000
004 marker mk0 0.000 0 1.000 1.000 0.000
005 drift df.s 1.000 0 1.000 1.500 0.500
006 marker mk.s 0.000 0 2.000 2.000 0.000
007 drift df2 1.000 0 2.000 2.500 0.500
008 marker mk2 0.000 0 3.000 3.000 0.000
009 marker end 0.000 0 3.000 3.000 0.000
Element positions
A sequence looks at the following attributes of an element, including sub-sequences, when installing it, and only at that time, to determine its position:
- at
A number holding the position in [m] of the element in the sequence relative to the position specified by the
from
attribute.- from
A string holding one of
"start"
,"prev"
,"next"
,"end"
or"selected"
, or the (mangled) name of another element to use as the reference position, or a number holding a position in [m] from the start of the sequence. (default:"start"
ifat
\(\geq 0\),"end"
ifat
\(<0\), and"prev"
otherwise)- refpos
A string holding one of
"entry"
,"centre"
or"exit"
, or the (mangled) name of a sequence sub-element to use as the reference position, or a number specifying a position [m] from the start of the element, all of them resulting in an offset to substract to theat
attribute to find the \(s\)-position of the element entry. (default:nil
\(\equiv\)self.refer
).- shared
A logical specifying if an element is used at different positions in the same sequence definition, i.e. shared multiple times, through temporary instances to store the many
at
andfrom
attributes needed to specify its positions. Once built, the sequence will drop these temporary instances in favor of their common parent, i.e. the original shared element.
Warning: The at
and from
attributes are not considered as intrinsic properties of the elements and are used only once during installation.
Any reuse of these attributes is the responsibility of the user, including the consistency between at
and from
after updates.
Element selections
The element selection in sequence use predicates in combination with iterators. The sequence iterator manages the range of elements where to apply the selection,
while the predicate says if an element in this range is illegible for the selection. In order to ease the use of methods based on the :foreach
method,
the selector predicate sel
can be built from different types of information provided in a set with the following attributes:
- flag
A number interpreted as a flags mask to pass to the element method
:is_selected
. It should not be confused with the flags passed as argument to methods:select
and:deselect
, as both flags can be used together but with different meanings!- pattern
A string interpreted as a pattern to match the element name using
string.match
from the standard library, see Lua 5.2 §6.4 for details.- class
An element interpreted as a class to pass to the element method
:is_instansceOf
.- list
An iterable interpreted as a list used to build a set and select the elements by their name, i.e. the built predicate will use
tbl[elm.name]
as a logical. If the iterable is a single item, e.g. a string, it will be converted first to a list.- table
A mappable interpreted as a set used to select the elements by their name, i.e. the built predicate will use
tbl[elm.name]
as a logical. If the mappable contains a list or is a single item, it will be converted first to a list and its set part will be discarded.- select
A callable interpreted as the selector itself, which allows to build any kind of predicate or to complete the restrictions already built above.
- subelem
A boolean indicating to include or not the sub-elements in the scanning loop. The predicate and the action receive the sub-element and its sub-index as first and second argument, and the main element index as third argument.
All these attributes are used in the aforementioned order to incrementally build predicates that are combined with logical conjunctions, i.e. and
’ed,
to give the final predicate used by the :foreach
method. If only one of these attributes is needed, it is possible to pass it directly in sel
,
not as an attribute in a set, and its type will be used to determine the kind of predicate to build. For example, self:foreach(act, monitor)
is equivalent
to self:foreach{action=act, class=monitor}
.
Indexes, names and counts
Indexing a sequence triggers a complex look up mechanism where the arguments will be interpreted in various ways as described in the :__index
metamethod.
A number will be interpreted as a relative slot index in the list of elements, and a negative index will be considered as relative to the end of the sequence,
i.e. -1
is the $end
marker. Non-number will be interpreted first as an object key (can be anything), looking for sequence methods or attributes;
then as an element name if nothing was found.
If an element exists but its name is not unique in the sequence, an iterable is returned. An iterable supports the length #
operator to retrieve the
number of elements with the same name, the indexing operator []
waiting for a count \(n\) to retrieve the \(n\)-th element from the start with that name,
and the iterator ipairs
to use with generic for
loops.
The returned iterable is in practice a proxy, i.e. a fake intermediate object that emulates the expected behavior, and any attempt to access the proxy in another manner should raise a runtime error.
Warning: The indexing operator []
interprets a number as a (relative) element index as the method :index
, while the method :index_of
interprets a
number as a (relative) element \(s\)-position [m].
The following example shows how to access to the elements through indexing and the iterable::
local sequence, drift, marker in MAD.element
local seq = sequence {
drift 'df' { id=1 }, marker 'mk' { id=2 },
drift 'df' { id=3 }, marker 'mk' { id=4 },
drift 'df' { id=5 }, marker 'mk' { id=6 },
}
print(seq[ 1].name) -- display: $start (start marker)
print(seq[-1].name) -- display: $end (end marker)
print(#seq.df, seq.df[3].id) -- display: 3 5
for _,e in ipairs(seq.df) do io.write(e.id," ") end -- display: 1 3 5
for _,e in ipairs(seq.mk) do io.write(e.id," ") end -- display: 2 4 6
-- print name of drift with id=3 in absolute and relative to id=6.
print(seq:name_of(4)) -- display: df[2] (2nd df from start)
print(seq:name_of(2, -2)) -- display: df{-3} (3rd df before last mk)
The last two lines of code display the name of the same element but mangled with absolute and relative counts.
Iterators and ranges
Ranging a sequence triggers a complex look up mechanism where the arguments will be interpreted in various ways as described in the :range_of
method,
itself based on the methods :index_of
and :index
. The number of elements selected by a sequence range can be computed by the :length_of
method,
which accepts an extra number of turns to consider in the calculation.
The sequence iterators are created by the methods :iter
and :siter
, and both are based on the :range_of
method as mentioned in their descriptions
and includes an extra number of turns as for the method :length_of
, and a direction 1
(forward) or -1
(backward) for the iteration.
The :siter
differs from the :iter
by its loop, which returns not only the sequence elements but also implicit drifts built on-the-fly when a gap
\(>10^{-10}\) m is detected between two sequence elements. Such implicit drift have half-integer indexes and make the iterator “continuous” in \(s\)-positions.
The method :foreach
uses the iterator returned by :iter
with a range as its sole argument to loop over the elements where to apply the predicate before
executing the action. The methods :select
, :deselect
, :filter
, :install
, :replace
, :remove
, :move
, and :misalign
are all based
directly or indirectly on the :foreach
method. Hence, to iterate backward over a sequence range, these methods have to use either its list form or a numerical range.
For example the invocation seq:foreach(\e -> print(e.name), {2, 2, 'idx', -1)
will iterate backward over the entire sequence seq
excluding the $start
and $end
markers, while the invocation seq:foreach(\e -> print(e.name), 5..2..-1)
will iterate backward over the elements with \(s\)-positions sitting in the
interval \([2,5]\) m.
The tracking commands survey
and track
use the iterator returned by :siter
for their main loop, with their range
, nturn
and dir
attributes as arguments. These commands also save the iterator states in their mflw
to allow the users to run them nstep
by nstep
, see commands survey and track for details.
The following example shows how to access to the elements with the :foreach
method::
local sequence, drift, marker in MAD.element
local observed in MAD.element.flags
local seq = sequence {
drift 'df' { id=1 }, marker 'mk' { id=2 },
drift 'df' { id=3 }, marker 'mk' { id=4 },
drift 'df' { id=5 }, marker 'mk' { id=6 },
}
local act = \e -> print(e.name,e.id)
seq:foreach(act, "df[2]/mk[3]")
-- display:
-- df 3
-- mk 4
-- df 5
-- mk 6
seq:foreach{action=act, range="df[2]/mk[3]", class=marker}
-- display: markers at ids 4 and 6
seq:foreach{action=act, pattern="^[^$]"}
-- display: all elements except $start and $end markers
seq:foreach{action=\e -> e:select(observed), pattern="mk"}
-- same as: seq:select(observed, {pattern="mk"})
local act = \e -> print(e.name, e.id, e:is_observed())
seq:foreach{action=act, range="#s/#e"}
-- display:
-- $start nil false
-- df 1 false
-- mk 2 true
-- df 3 false
-- mk 4 true
-- df 5 false
-- mk 6 true
-- $end nil true
Examples
FODO cell
The following example shows how to build a very simple FODO cell and an arc made of 10 FODO cells.
local sequence, sbend, quadrupole, sextupole, hkicker, vkicker, marker in MAD.element
local mkf = marker 'mkf' {}
local ang=2*math.pi/80
local fodo = sequence 'fodo' { refer='entry',
mkf { at=0, shared=true }, -- mark the start of the fodo
quadrupole 'qf' { at=0, l=1 , k1=0.3 },
sextupole 'sf' { l=0.3, k2=0 },
hkicker 'hk' { l=0.2, kick=0 },
sbend 'mb' { at=2, l=2 , angle=ang },
quadrupole 'qd' { at=5, l=1 , k1=-0.3 },
sextupole 'sd' { l=0.3, k2=0 },
vkicker 'vk' { l=0.2, kick=0 },
sbend 'mb' { at=7, l=2 , angle=ang },
}
local arc = sequence 'arc' { refer='entry', 10*fodo }
fodo:dumpseq() ; print(fodo.mkf, mkf)
Display:
sequence: fodo, l=9
idx kind name l dl spos upos uds
001 marker $start 0.000 0 0.000 0.000 0.000
002 marker mkf 0.000 0 0.000 0.000 0.000
003 quadrupole qf 1.000 0 0.000 0.000 0.000
004 sextupole sf 0.300 0 1.000 1.000 0.000
005 hkicker hk 0.200 0 1.300 1.300 0.000
006 sbend mb 2.000 0 2.000 2.000 0.000
007 quadrupole qd 1.000 0 5.000 5.000 0.000
008 sextupole sd 0.300 0 6.000 6.000 0.000
009 vkicker vk 0.200 0 6.300 6.300 0.000
010 sbend mb 2.000 0 7.000 7.000 0.000
011 marker $end 0.000 0 9.000 9.000 0.000
marker : 'mkf' 0x01015310e8 marker: 'mkf' 0x01015310e8 -- same marker
SPS compact description
The following dummy example shows a compact definition of the SPS mixing elements, beam lines and sequence definitions. The elements are zero-length, so the lattice is too.
local drift, sbend, quadrupole, bline, sequence in MAD.element
-- elements (empty!)
local ds = drift 'ds' {}
local dl = drift 'dl' {}
local dm = drift 'dm' {}
local b1 = sbend 'b1' {}
local b2 = sbend 'b2' {}
local qf = quadrupole 'qf' {}
local qd = quadrupole 'qd' {}
-- subsequences
local pf = bline 'pf' {qf,2*b1,2*b2,ds} -- #: 6
local pd = bline 'pd' {qd,2*b2,2*b1,ds} -- #: 6
local p24 = bline 'p24' {qf,dm,2*b2,ds,pd} -- #: 11 (5+6)
local p42 = bline 'p42' {pf,qd,2*b2,dm,ds} -- #: 11 (6+5)
local p00 = bline 'p00' {qf,dl,qd,dl} -- #: 4
local p44 = bline 'p44' {pf,pd} -- #: 12 (6+6)
local insert = bline 'insert' {p24,2*p00,p42} -- #: 30 (11+2*4+11)
local super = bline 'super' {7*p44,insert,7*p44} -- #: 198 (7*12+30+7*12)
-- final sequence
local SPS = sequence 'SPS' {6*super} -- # = 1188 (6*198)
-- check number of elements and length
print(#SPS, SPS.l) -- display: 1190 0 (no element length provided)
Installing elements I
The following example shows how to install elements and subsequences in an empty initial sequence:
local sequence, drift in MAD.element
local seq = sequence "seq" { l=16, refer="entry", owner=true }
local sseq1 = sequence "sseq1" {
at=5, l=6 , refpos="centre", refer="entry",
drift "df1'" {l=1, at=-4, from="end"},
drift "df2'" {l=1, at=-2, from="end"},
drift "df3'" { at= 5 },
}
local sseq2 = sequence "sseq2" {
at=14, l=6, refpos="exit", refer="entry",
drift "df1''" { l=1, at=-4, from="end"},
drift "df2''" { l=1, at=-2, from="end"},
drift "df3''" { at= 5 },
}
seq:install {
drift "df1" {l=1, at=1},
sseq1, sseq2,
drift "df2" {l=1, at=15},
} :dumpseq()
Display:
sequence: seq, l=16
idx kind name l dl spos upos uds
001 marker $start* 0.000 0 0.000 0.000 0.000
002 drift df1 1.000 0 1.000 1.000 0.000
003 drift df1' 1.000 0 4.000 4.000 0.000
004 drift df2' 1.000 0 6.000 6.000 0.000
005 drift df3' 0.000 0 7.000 7.000 0.000
006 drift df1'' 1.000 0 10.000 10.000 0.000
007 drift df2'' 1.000 0 12.000 12.000 0.000
008 drift df3'' 0.000 0 13.000 13.000 0.000
009 drift df2 1.000 0 15.000 15.000 0.000
010 marker $end 0.000 0 16.000 16.000 0.000
Installing elements II
The following more complex example shows how to install elements and subsequences in a sequence using a selection and the packed form for arguments:
local mk = marker "mk" { }
local seq = sequence "seq" { l = 10, refer="entry",
mk "mk1" { at = 2 },
mk "mk2" { at = 4 },
mk "mk3" { at = 8 },
}
local sseq = sequence "sseq" { l = 3 , at = 5, refer="entry",
drift "df1'" { l = 1, at = 0 },
drift "df2'" { l = 1, at = 1 },
drift "df3'" { l = 1, at = 2 },
}
seq:install {
class = mk,
elements = {
drift "df1" { l = 0.1, at = 0.1, from="selected" },
drift "df2" { l = 0.1, at = 0.2, from="selected" },
drift "df3" { l = 0.1, at = 0.3, from="selected" },
sseq,
drift "df4" { l = 1, at = 9 },
}
}
seq:dumpseq()
Display:
sequence: seq, l=10
idx kind name l dl spos upos uds
001 marker $start 0.000 0 0.000 0.000 0.000
002 marker mk1 0.000 0 2.000 2.000 0.000
003 drift df1 0.100 0 2.100 2.100 0.000
004 drift df2 0.100 0 2.200 2.200 0.000
005 drift df3 0.100 0 2.300 2.300 0.000
006 marker mk2 0.000 0 4.000 4.000 0.000
007 drift df1 0.100 0 4.100 4.100 0.000
008 drift df2 0.100 0 4.200 4.200 0.000
009 drift df3 0.100 0 4.300 4.300 0.000
010 drift df1' 1.000 0 5.000 5.000 0.000
011 drift df2' 1.000 0 6.000 6.000 0.000
012 drift df3' 1.000 0 7.000 7.000 0.000
013 marker mk3 0.000 0 8.000 8.000 0.000
014 drift df1 0.100 0 8.100 8.100 0.000
015 drift df2 0.100 0 8.200 8.200 0.000
016 drift df3 0.100 0 8.300 8.300 0.000
017 drift df4 1.000 0 9.000 9.000 0.000
018 marker $end 0.000 0 10.000 10.000 0.000
Footnotes