Workbench Program Extensions in SIMION 8.1¶
This page describes SIMION workbench user program capabilities added recently in SIMION 8.1 These features are not yet described in the printed manual. Some capabilities added to latter 8.0.x versions are also described here.
Note
This page is abridged from the full SIMION "Supplemental Documentation" (Help file). The following additional sections can be found in the full version of this page accessible via the "Help > Supplemental Documentation" menu in SIMION 8.1.1 or above:Segment Flow Chart
Segments¶
The following new segments are available.
- segment.flym()¶
The segment.flym
segment is the main routine executed when you
do a Fly’m. It is typically used to implement a loop that performs
a series of runs (invoked by the run()
command). For example:
simion.workbench_program()
local V1
function segment.flym()
for i=1,10 do -- Do 10 runs, stepping through voltages.
V1 = 100*i
run()
end
end
function segment.initialize_run()
print('running with V1=', V1)
end
function segment.fast_adjust()
adj_elect01 = V1
end
You can place nearly whatever you want inside the flym
segment. For example,
function segment.flym() print 'Hello.' end
will print “Hello.
” and
not fly any trajectories. However, typically, the flym
segment
will contain at least one run()
command, which does an entire particle tracing
run, including invoking all necessary segments from segment.initialize_run()
to segment.terminate_run()
and everything in-between. If the particle tracing
run fails, then run()
will raise an error. run()
can only be called inside
a flym
segment (and will raise an error otherwise). You may also wish to
do things like invoke Refine (simion.pas pa:refine()
) between runs.
If the flym
segment is not specified, then the Fly’m behavior is roughly equivalent
to the following code:
function segment.flym()
repeat
run() -- This may set sim_rerun_flym to 1 or 0.
until sim_rerun_flym == 0
end
Note also that this:
function segment.flym()
for i =1, 3 do
f()
run()
g()
end
end
is similar to this:
function segment.flym()
for i = 1, 3 do
run()
end
end
function segment.initialize_run()
f()
end
function segment.terminate_run()
g()
end
The following reserved variables are accessible from the flym
segment:
sim_trajectory_image_control
(read/write) – affects nextrun()
sim_rerun_flym
(read/write) – affects nextrun()
sim_trajectory_quality
(read/write)sim_repulsion
(read/write)sim_repulsion_amount
(read/write)ion_run
(read) – number of previousrun()
. 0 ifrun()
not yet calledsim_retain_changed_potentials
(write) – retains from previousrun()
Note: no PA instance or ion specific variables are accessible from the flym
segment.
It can be useful to disable retaining trajectories across runs (to avoid filling the disk and screen):
function segment.flym()
sim_trajectory_image_control = 1 -- view but not retain trajectories
for i=1,10 do
run()
end
sim_trajectory_image_control = 0 -- view and retain trajectories for next run
run()
end
A similar but not identical code is
function segment.flym()
sim_rerun_flym = 1 -- enable "rerun" mode
for i=1,10 do
run()
end
sim_rerun_flym = 0 -- disable "rerun" mode
run()
end
Note: in “rerun” mode, trajectories are not retained either
(regardless what sim_trajectory_image_control
is set to)
and data recording is not saved to disk. Furthermore, enabling
rerun mode will clear any trajectores that may have previously been retained.
The SIMION Example: geometry_optimization and SIMION Example: tune: take these points
into account.
In previous versions of SIMION (e.g. 8.0), the control logic for the for i=1,10 do
in examples above had to instead be incorporated into the initialize
and terminate
segments like this:
-- initialize_run/terminate_run example
-- (which can be written more simply just using `flym`)
simion.workbench_program()
local V1
local nrun = 0
function segment.initialize_run()
nrun = nrun + 1
V1 = 100*nrun
print('running with V1=', V1)
end
function segment.fast_adjust()
adj_elect01 = V1
end
function segment.terminate_run()
sim_rerun_flym = (nrun < 10) and 1 or 0
end
-- Note: In 8.0, initialize_run/terminate_run also had to be
-- rewritten in terms of initialize/terminate segments.
-- Note: In 8.1, ion_run is incremented automatically.
which can be more awkward, especially for more complicated, nested loops. In SIMION 8.0
it was actually possible to rewrite that with Lua coroutines to invert the
control logic to make it more similar to the SIMION 8.1 flym
segment, but this
was rarely done and still is not as simple nor as general
(e.g. doesn’t support zero iterations of the loop):
-- coroutine example
-- (which can be written more simply just using `flym`)
simion.workbench_program()
local V1
local mycoroutine = coroutine.wrap(function()
for i=1,10 do
V1 = i
coroutine.yield()
end
end)
function segment.initialize_run()
mycoroutine()
end
function segment.fast_adjust()
adj_elect01 = V1
end
-- Note: In 8.0, initialize_run/terminate_run also had to be
-- rewritten in terms of initialize/terminate segments.
Compatibility: The flym
segment was added in 8.1.0.40. Previous versions
would raise an error on attempt to define this segment. Supported in
old PRG in 8.1.1.0 (with new RUN
command).
- segment.initialize_run()¶
The initialize_run
segment is called exactly once prior
to the start of each run (or rerun).
It is called before any calls to the initialize
segment are made.
In contrast, the initialize
segment is called each time a
particle is initialized inside a PA instance and (unlike the
initialize_run
segment) has access to reserved
variables pertaining to those particles and PA instances. The initialize_run
segment is suitable for initialization code that must be called exactly
once, whereas the initialize
segment is suitable for code that
reads/writes particle data via reserved variables.
For example:
simion.workbench_program()
function segment.initialize_run()
print 'begin1'
end
function segment.initialize()
print('begin2', ion_instance, ion_number)
end
The 'begin1'
is printed exactly once on the beginning of the run.
However, the number of times 'begin2'
is printed is less clear. If you
have 10 particles all created inside an electrostatic PA instance, 'begin2'
will
be printed 10 times (i.e. once per particle). If all particles are inside a
magnetic PA instance as well, 'begin2'
will be printed 20 times.
If, however, all particles are started outside of PA instances or if you
have zero particles, then 'begin2'
is never printed.
Note also that the initialize
segment has access to reserved variables
pertaining to the current particle (e.g. ion_number
) and current
PA instance (e.g. ion_instance
). The initialize_run
segment
does not have the concept of current particle and current PA instance
because it is always called exactly once regardless of the number of particles
and which (if any) PA instances those particles are located in. The
intialize_run
segment does, however, have access to these reserved
variables:
sim_trajectory_image_control
(read/write)sim_rerun_flym
(read/write)sim_trajectory_quality
(read/write)sim_repulsion
(read/write)sim_repulsion_amount
(read/write)ion_run
(read)
The main advantage of initialize_run
is that you can be sure it is called
exactly once. This can make certain types of initialization code simpler and
more robust. In previous (8.0) versions of SIMION, a workaround was to do things
like this:
simion.workbench_program()
function segment.initialize()
if ion_instance == 1 and ion_number == 1 then
print 'begin1'
end
-- warning: This SIMION 8.0 workaround fails if particle #1 is
-- not created inside PA instance #1.
end
Compatibility: The initialize_run
segment was added in 8.1.0.40. Previous versions
would raise an error on attempt to define this segment.
- segment.terminate_run()¶
The terminate_run
segment is called exactly once
after the end of each run (or rerun).
It is called after any calls to the terminate
segment are made.
The relationship between terminate_run
and terminate
segments
is analogous to the relationship between initialize_run
and initialize
, so
see the segment.initialize_run()
documentation for further details.
The terminate_run
segment has access to these reserved variables:
sim_trajectory_image_control
(read/write)sim_rerun_flym
(read/write)sim_trajectory_quality
(read/write)sim_repulsion_amount
(read/write)ion_run
(read)sim_retain_changed_potentials
(write)
Compatibility: The terminate_run
segment was added in 8.1.0.40. Previous versions
would raise an error on attempt to define this segment.
- segment.load()¶
The load
segment is only called when the workbench IOB file is first
loaded, which occurs prior to any number of Fly’m(s).
In particular, unlike most other segments,
the load
segment is never called during the Fly’m.
Note that at the end of a Fly’m, some variables like sim_rerun_flym
and adjustable
variables are reset to their values prior to the Fly’m, which
can include values set in a load
segment.
A load
segment is useful for performing on the workbench some initial
configuation that does not need to be redone
each time the Fly’m button is pressed. Perhaps you are setting up
a default option that the user should still be able to change prior each Fly’m.
For example, you might set sim_trajectory_quality
(T.Qual) in a load
segment rather than in an initialize_run
segment since the former will
set T.Qual to a recommended initial value upon loading the IOB,
whereas the latter will force the value regardless regardless what the
user later selects for T.Qual on the Particles tab on the View screen.
The load
segment may also be useful for performing computationally intensive
things like refining a PA in a special way (simion.pas pa:refine()
) that
should not be performed on each Fly’m. Establishing a connection to Excel
may be another case. Beware, however, that unless you have good reason otherwise,
you should probably prefer to place code inside an initialize_run
segment
rather than a load
segment since the former tends to ensure that clicking
the Fly’m button more than once will tend to give reproducible results because
execution will depend less on past history.
If the IOB is loaded during a fly
batch mode command
(e.g. from simion.command
or the command line),
any adjustable variable values passed to it via the --adjustable
argument
are applied prior to the execution of segment.load()
.
The load
segment has access to these reserved variables:
sim_trajectory_image_control
(read/write)sim_rerun_flym
(read/write)sim_trajectory_quality
(read/write)sim_repulsion
(read/write)sim_repulsion_amount
(read/write)
Compatibility: The load
segment was added in 8.1.1.0. Previous versions
would raise an error on attempt to define this segment.
- segment.instance_adjust()¶
The instance_adjust
segment always you to reorder the PA instance
priorities during a run.
Background: Normally when PA instances overlap, the particle only sees the highest priority electric PA instance and highest priority magnetic PA instance (if any) the particle is located within. PA instances priority is controlled via the L-/L+ buttons on the View screen PAs tab.
Why might you want to reorder PA instances?
One possibility is that you represent a certain region of your electrodes
within two PA instances that overlap, but the far ends of the
overlap region (where the PA’s are cut) the fields might not be accurate.
But you can use an instance_adjust
segment to suppress those inaccurate
regions.
For example, if you have two partially overlapping PA instances (PA instance #2 partly overlaps #1), you might do something like this:
simion.workbench_program()
function segment.instance_adjust()
if ion_instance == 2 then
if ion_px_mm > 10 then
ion_instance = 0 -- suppress
end
end
end
What that means is that if the current particle finds itself inside PA instance #2
and the particle position is in the region x > 10 mm, then the PA instance #2
will be suppressed at that location.
SIMION will then try then next available PA instance (#1) containing the particle
and since the instance_adjust
segment does not suppress instance #1 in that region, SIMION is free to show that
to the particle.
SIMION will proceed to use instance #1 to calculate the field and can consult
segments (e.g. fast_adjust
, efield_adjust
, mfield_adjust
) to
help compute that field for the particle.
The ion_instance
variable is initially set to the currently
inferred PA instance number (positive integer).
Setting it to 0 will suppress the current PA instance.
It is invalid to set ion_instance
to any other value.
If you want a certain PA instance to be active, suppress all PA instances
called by ion_instance
having higher higher priority numbers.
There is never a need to suppress PA instance #1 unless you want
a particle to see no PA instances (empty space).
The following reserved variables are accessible from this segment:
Simulation (read):
sim_grouped, sim_relativity, sim_repulsion_amount, sim_trajectory_quality,
sim_segment_global, sim_repulsion
Flym/Run properties (read):
ion_run, sim_ions_count
PA instance variables (read/write):
ion_instance
Particle properties (read):
ion_color
ion_charge
ion_cwf
ion_mass
ion_number
ion_px_mm, ion_py_mm, ion_pz_mm
ion_time_of_flight
Compatibility: Added in 8.2EA-20170214.
Reserved Variables¶
The following new reserved variables are now supported.
- ion_cwf¶
The ion_cwf
reserved variables represents the charge weighting factor (CWF)
for the current particle. CWF values, which are normally used for the
charge repulsion feature and default to 1, are originally defined
in the particle definitions.
Permissions: ion_cwf
has the same segment access
permissions as ion_charge
.
Tip:
As of SIMION 8.0.4-TEST19, the CWF can also be selected for data recording.
The REC format has been extended to support this selection.
This capability also allows the following useful trick. Any CWF
specified in the particle definitions is readable/writable via the
user program ion_cwf
reserved variable and also carries over to the CWF
field in the Data Recording output. This is true even if charge
repulsion effects are disabled, in which case SIMION otherwise
ignores the CWF field, but you may use the CWF field for your own
purpose to carrying over user-defined data concerning individual
particles into the user program and/or data recording output.
Compatibility: Added in 8.0.4-TEST19. Added in PRG in 8.0.5-TEST8. Issue-I 452. Documented in the 8.0.4 manual.
- ion_effective_charge¶
The ion_effective_charge
variable represents the real (physical) charge
represented by the particle in elementary charge units.
It only differs from ion_charge
only when
using the charge repulsion features.
In comparison, the ion_charge
variable, which is the same as the charge
specified in the particle definitions, contains the per-particle charge in
elementary charge units (e.g. Carbon is 12 e).
However, when charge repulsion features
are used (Beam, Coulombic, or Factor repulsion), each traced
particle can represent more than one real particle (possibly
millions). The precise number is controlled by the global charge
repulsion amount on the Particles tab (or sim_repulsion_amount
)
and the charge-weighting-factors on the
individual particles (or ion_cwf
). The ion_effective_charge
variable takes these into account.
When Coulombic or Factor repulsion is used, each particle traced
represents a point (or cloud) of charges, and ion_effective_charge
represents the total charge, in elementary charge units, of that
point.
When Beam repulsion is used, each particle trajectory instead
represents a beam of current (in A). Current is a charge per
time (where time=distance/velocity), so it’s not as clear how best to define
ion_effective_charge
. We choose ion_effective_charge
to represent
the charge, in elementary charge units, in the current time-step.
Current (in A) can be obtained by
1.6021773349E-19 C * ion_effective_charge / (ion_time_step * 1E-6 s)
.
(In the initialize
segment,
ion_time_step
is not defined; but we arbitrary treat it as 1 microsecond
in the above formula.)
Permissions: ion_effective_charge
can be read anywhere ion_charge
can be read.
It is not writable.
Compatibility: Added in 8.1.0.0. Issue-I 452.3
- ion_ke¶
This contains the kinetic energy (in eV) of the current particle.
The particle kinetic energy can be read from or written to this variable.
If it is written to, the ion_vx_mm
, ion_vy_mm
, and ion_vz_mm
are updated accordingly.
Permissions: ion_ke
has the same permissions as ion_vx_mm
.
Writing a non-zero value to ion_ke
when ion_ke
is zero will raise an error
because a zero KE does not define a velocity direction.
Reading ion_ke
is a short-hand for this:
speed_to_ke(math.sqrt(ion_vx_mm^2 + ion_vy_mm^2 + ion_vz_mm^2), ion_mass)
See also Get/set kinetic energy of current particle.
Compatibility: Added in 8.2.
- ion_run¶
The ion_run
reserved variable represents the current run number (integer >= 1).
It is incremented automatically on each rerun.
Permissions: It is readable in all segments and writable in none.
ion_run
should not be used at the top-level (which is prior to the first run),
although presently it equals 0 in that case.
Example:
simion.workbench_program()
function segment.initialize_run()
print('run number=', ion_run)
sim_rerun_flym = 1
end
The ion_run
variable can also be used in the data recording settings
to splitting data recording output into multiple files (see Issue-I 231).
Earlier (8.0) versions of SIMION without this variable may use the following workaround:
simion.workbench_program()
local nrun = 0
function segment.initialize()
if ion_number == 1 and ion_instance == 1 then
nrun = nrun + 1
print('run number=', nrun)
end
end
-- warning: This SIMION 8.0 workaround fails if particle #1 is
-- not created inside PA instance #1.
Compatibility: Added in 8.1.0.0. Issue-I 529.
- sim_grouped¶
The sim_grouped
reserved variable is 1 if Grouped particle flying
is enabled (i.e. all particles flown at the same time)
or 0 if Grouped flying is disabled (i.e. particles flown one after another).
Permissions: Reading is allowed in all segments.
Writing is allowed in the top-level, load
, flym
, and initialize_run
segments (i.e. before particles are created).
Setting this variable to 0 will automatically change sim_repulsion
to 'none'
(i.e. disable repulsion effects).
Note: The grouped mode can also be set via the fly --grouped
batch mode parameter (see Appendix M of the manual).
Compatibility: Added in SIMION 8.1.0.43.
- sim_relativity¶
The sim_relativity
defines whether relativistic effects are on (1=yes, 0=no)
for the Fly’m and functions like
simion.speed_to_ke()
and simion.ke_to_speed()
.
This is also tied to the “omit relativistic effects” option on the
Particles Tab “more” panel.
Permissions: Reading is allowed in all segments.
Writing is allowed in the top-level, load
, flym
, and initialize_run
segments (i.e. before particles are created). Inaccessible from PRG.
Note: The relativity can also be set via the fly --omit-relativistic-effects
batch mode parameter (see Appendix M of the manual).
Compatibility: Added in 8.2. Not accessible in PRG.
- sim_repulsion¶
The sim_repulsion
reserved variable contains the charge repulsion method
currently selected: 'none'
, 'beam'
, 'coulomb'
, or 'factor'
.
Permissions: Reading is allowed in all segments.
Writing is allowed in the top-level, load
, flym
, and initialize_run
segments (i.e. before particles are created). Inaccessible from PRG.
Setting this variable to anything other than 'none'
, will automatically
change sim_grouped
to 1.
Note: The repulsion type can also be set via the fly --repulsion
batch mode parameter (see Appendix M of the manual).
Compatibility: Added in SIMION 8.1.0.43. Not accessible in PRG.
- sim_repulsion_amount¶
The sim_repulsion_amount
reserved variable
represents the charge repulsion amount
in the charge repulsion options. It’s meaning depends on the current
value of sim_repulsion
and you should set this variable only
after after setting sim_repulsion
. The behavior of this variable
is unspecified if sim_repulsion
is 'none'
.
Permissions: Reading is allowed in all segments.
Writing is allowed in the top-level, load
, flym
,
initialize
/initialize_run
, other_actions
,
and terminate
/terminate_run
segments.
Note: The repulsion amount can also be set via the fly --repulsion-amount
batch mode parameter (see Appendix M of the manual).
Compatibility: Added in SIMION 8.1.0.0. Issue-I 452.2
- sim_trajectory_quality¶
The sim_trajectory_quality
represents the
trajectory quality factor (“T.Qual”). It has a range -500 to +500.
Permissions: Reading is allowed in all segments.
Writing is allowed in the top-level, load
,
initialize
/initialize_run
, other_actions
,
and terminate
/terminate_run
segments.
Compatibility: Added in 8.0.3. Access from PRG added in 8.0.5-TEST8. Access from top-level added in 8.0.5-TEST10. Issue-I 370.
- sim_ions_count¶
The sim_ions_count
contains the current number of particles
in the Fly’m.
Particles splatted or not yet born are included in this count.
See also Counting number of particles.
Permissions: Reading is allowed in all segments except load
,
flym
, and the top-level.
Writing is not allowed, but its value can be affected by
simion.experimental.add_particles()
(but such changes are not seen until the next time-step).
Compatibility: Added in 8.2.
A typical use is this:
simion.workbench_program()
local nhit = 0
function segment.terminate()
if ion_px_mm > -5 and ion_py_mm < 5 then -- acceptance region
nhit = nhit + 1
end
end
function segment.terminate_run()
print('% transmission:', nhit / sim_ions_count * 100)
end
- sim_segment_global¶
This allows program segments to be called outside even when particles are outside PA instance volumes by setting this variable to 1. Normally this is 0, which uses traditional SIMION behavior of only calling segments for particles inside PA instance volumes.
A typical example is this is to ensure that the terminate
segment
is called for all particles, regardless whether they terminate inside
a PA instance volume:
simion.workbench_program()
sim_segment_global = 1
function segment.terminate()
print(ion_number, ion_px_mm)
end
function segment.terminate_run()
print('all done')
end
Note: segment.terminate
is called for each particle and will
be called zero times if there are no particles.
That differs from segment.terminate_run
, which
is always called exactly once and is not affected by this variable.
terminate
is appropriate when you need to access information
(e.g. ion_px_mm
) for each particle terminating, and
terminate_run
is appropriate when you want to do something exactly
once at the end of a run.
Another use is to define a magnetic field without using a “dummy” magnetic PA instance:
simion.workbench_program()
sim_segment_global = 1
function segment.mfield_adjust()
ion_bfieldx_gu = 100
end
Outside of PA instances, ion_instance
is defined as 0,
ion_mm_per_grid_unit
is defined as 1,
and ion_px_mm
is identical to ion_px_gu
and ion_pz_gu_abs
(and so forth).
Permissions: Reading is allowed in all segments.
Writing is allowed in the top-level, load
, flym
, and initialize_run
segments (i.e. before particles are created).
This variable also can affect
simion.wb:efield()
and simion.wb:bfield()
.
Compatibility: Added in 8.2EA-20170214.
Note
This page is abridged from the full SIMION "Supplemental Documentation" (Help file). The following additional sections can be found in the full version of this page accessible via the "Help > Supplemental Documentation" menu in SIMION 8.1.1 or above:Reserved Variables Full List
Particle Creation API
Load Functions
PRG (Old Interface)¶
New segments and variables mentioned above generally are available in (old SIMION 7.0 style) PRG code as well:
seg load
mess ; loading
seg initialize_run
rcl ion_run
mess ; run=#
seg flym
run
run