SIMION®
The field and particle trajectory simulator
Industry standard charged particle optics software
Refine your design: model > simulate > view > analyze > program > optimize it.
SIMION v8.1.3.0-TEST posted.
About | Documentation | Community/Support | Downloads | Ordering
The SIMION SL™ Toolkit (version 1.2.1.0 - 2004-11-09)

Exporting Electrostatic and Magnetic Field Data from SIMION (and Importing it too)

David Manura, Scientific Instrument Services, Inc. 2004-03-24. Updated: $Date: 2004/07/20 05:23:17 $.

Abstract

A typical usage of SIMION is to create a *.PA or *.PA# potential array file defining an electrode geometry with set voltages potentials on the electrodes, refine the potential array (i.e. solve for the potentials or fields at the non-electrode, space points), and then fly ions through one or more of those refined potential arrays placed in a workbench.

Sometimes, however, you may wish to export the electrostatic or magnetic field calculated by SIMION to an external program or import the field from an external program. For example, you might wish to export a 2D or 3D map of the electric or magnetic field to a data analysis program such as Excel, MATLAB, or Mathcad. Alternately, you may have calculated a field in another program and wish to import it into SIMION.

There are several ways to export a field from SIMION. First, since the field vectors and other parameters effective on an ion are available as variables to user programs during ion flight, you could write a user program that jumps a neutral particle to every point on the 2D or 3D grid and collect the data you desire at those points. This solution given here. A second solution, discussed later in this article, is to read the data directly from a refined and fast adjusted *.PA0 file using the SL Tools utility or from a general purpose programming language, possibly using the SL Libraries (the SL Tools and SL Libraries are only available in the SIMION SL Toolkit).

There are also several ways to import a field into SIMION. One is to write a user program that sets the effective electrostatic or magnetic field variables for each ion at each timestep of the calculation by looking up in a data file the field defined for the ion's current position. This simulates a refined potential array. The second solution, also mentioned here, is to create the refined *.PA0 file directly and then read that *.PA0 file into SIMION as normal. There may also be quite different data import/export needs that can also be satisfied with the techniques described in this article.

Conceptual Solution for Exporting with a User Program

Let's start with a conceptual description of how we're going to use a user program in SIMION to export a 2D electric field map as a text file for importing into another program (e.g. a data plotting program). In this first example, we will extract a 2D map of the electric field from the refined TUNE.PA0 potential array in the "_Tune" example that comes with SIMION:


Figure 1 - 3D Isometric view of the refined TUNE.PA0 potential array (a three-electrode electrostatic array with cylindrical symmetry).

The below picture gives a conceptual view of how this will be done. We will fly a neutral particle over the entire surface of a plane intersecting our 3D geometry. As shown in the X-Y cross-sectional view (right), the particle will follow a zig-zag pattern. The dots are markers. These dots indicate the locations at which we will sample the data. Obviously, a neutral particle will not naturally follow this zig-zag path, so, as described later in this article, we will need to associate a user program with the potential array, such that the user program will force the ion to follow the zig-zag path.


Figure 2 - Trace path of a single neutral particle forced by a user program to traverse all grid points on a rectangle. (Left) 3D isomeric view. (Right) X-Y cross-sectional view.

If, however, you need to collect a 3D map of points, we must instead traverse the neutral particle through an entire 3D rectangular volume as shown below. The trace path here resembles a "space filling curve."


Figure 3 - Trace path of a single neutral particle forced by a user program to traverse all grid points within a 3D box. (Left) 3D isomeric view. (Right) Z-Y cross-sectional view.

Example Steps

To start setting up this example, copy the "_Tune" subdirectory (in the SIMION program directory) to a new directory named "tunemap". We will use the "tunemap" directory for this example so as not to corrupt the original "_Tune" files.

Now, as usual, load the "tunemap\TUNE.PA#" file, refine it, and remove it from memory.

Next, we will replace the tune.prg user program with our own user program that traverses a neutral particle over the area or volume we desire to export a map for. We could author this new tune.prg file directly, or we could generate it from high-level SL code using the SL compiler for SIMION. The latter is easier, so we will do that here. First disable the original tune.prg file by renaming it as "tune_backup.prg". If you have the SL compiler for SIMION, create the below file and name it "tune.sl". When you compile this with SL, the SL compiler regenerates the "tune.prg" file from the contents of the "tune.sl" file. The generated "tune.prg" file is shown two figures below. If you don't have the SL compiler, you can simply copy and paste the PRG code directly into your "tune.prg" file.

#####
# SL program to record field data at all points on a
# 2D or 3D grid.
#####

# The extents and granularity of the grid.
adjustable ion_x_min  = 0.5
adjustable ion_x_max  = 98.5
adjustable ion_x_step = 5

adjustable ion_y_min  = -38.5
adjustable ion_y_max  = 38.5
adjustable ion_y_step = 5

adjustable ion_z_min  = 0
adjustable ion_z_max  = 0
adjustable ion_z_step = 5

static ion_initialized = 0
static ion_jumped = 0

sub other_actions
    ion_splat = 0  # prevent ion splats, even on electrodes

    # initialize trace ion
    if ion_initialized == 0
        ion_px_mm = ion_x_min
        ion_py_mm = ion_y_min
        ion_pz_mm = ion_z_min

        ion_charge = 0  # make unaffected by fields
        ion_vx_mm = 0
        ion_vy_mm = 0
        ion_vz_mm = 0

        ion_initialized = 1
        ion_jumped = 1
        exit
    endif

    # ion was jumped
    if ion_jumped == 1
        mark()
        ion_jumped = 0
        exit
    endif

    # jump ion to next position
    if ion_px_mm + ion_x_step < ion_x_max
        ion_px_mm = ion_px_mm + ion_x_step
    else
        ion_px_mm = ion_x_min
        if ion_py_mm + ion_y_step < ion_y_max
            ion_py_mm = ion_py_mm + ion_y_step
        else
            ion_py_mm = ion_y_min
            if ion_pz_mm + ion_x_step < ion_z_max
                ion_pz_mm = ion_pz_mm + ion_z_step
            else
                ion_splat = 1
                exit
            endif
        endif
    endif
    ion_jumped = 1
endsub
Listing 1 - tune.sl - A program for moving a neutral trace particle along an area- or space-filling curve. Marks are set at grid points.

Let's look at the above SL code to see what this user program is doing.

At the top, we define various adjustable variables. The *_min and *_max variables define the x-, y-, and z-extents of a boundary box in which to collect data. These are in mm units and workbench coordinates, but this can be changed in the program. The *_step variables define the width of the grid. Therefore, samples will be taken at the x values of 0.5, 5.5, 10.5, ... up to a value no greater than 98.5. A similar case is for the y and z values. Notice that the boundary box restricts z to the plane z=0, so we are traversing a 2D rectangle, not a 3D rectangular box.

We then define an "other_actions" subroutine. This subroutines is called by SIMION at the end of every time-step. We use this subroutine to jump the ion to the next grid location so that the next sample of data may be collected there. At the top of this subroutine is a block of code that initializes the parameters on the neutral trace particle. This code is only executed the first time that other_actions is called. At the bottom, we have the code that jumps the particle to the next position according to a zig-zag pattern. If the particle was jumped, we call the mark() function (in the center section of code) the next time that other_actions is called. mark() is used to trigger data collection and to draw the dots on the ion trace lines. Note that we don't invoke mark() immediately after changing the ion position variables; we must wait until the next call to other_actions so that SIMION has enough time to recalculate its field variables.

Below is the compiled tune.prg file generated from the SL compiler. It is not important that you understand its contents.

; This PRG file was automatically generated from SL source code
; using the SIS Simplified SIMION Compiler (SL) 1.0.1-2004-01-12.
; WARNING: This file will be overwritten if you recompile.

; #####
; # SL program to record field data at all points on a
; # 2D or 3D grid.
; #####
; 
; # The extents and granularity of the grid.
; adjustable ion_x_min  = 0.5
DEFA ion_x_min 0.5
; 
; adjustable ion_x_max  = 98.5
DEFA ion_x_max 98.5
; 
; adjustable ion_x_step = 5
DEFA ion_x_step 5
; 
; adjustable ion_y_min  = -38.5
DEFA ion_y_min -38.5
; 
; adjustable ion_y_max  = 38.5
DEFA ion_y_max 38.5
; 
; adjustable ion_y_step = 5
DEFA ion_y_step 5
; 
; adjustable ion_z_min  = 0
DEFA ion_z_min 0
; 
; adjustable ion_z_max  = 0
DEFA ion_z_max 0
; 
; adjustable ion_z_step = 5
DEFA ion_z_step 5
; 
; static ion_initialized = 0
DEFS ion_initialized 0
; 
; static ion_jumped = 0
DEFS ion_jumped 0
; 
; sub other_actions
SEG other_actions
    ; ion_splat = 0  # prevent ion splats, even on electrodes
    0 STO ion_splat
    RLUP
    ; 
    ; # initialize trace ion
    ; if ion_initialized == 0
    0
    RCL ion_initialized
    X!=Y
    GTO label19__
    RLUP
    RLUP
        ; ion_px_mm = ion_x_min
        RCL ion_x_min
        STO ion_px_mm
        RLUP
        ; ion_py_mm = ion_y_min
        RCL ion_y_min
        STO ion_py_mm
        RLUP
        ; ion_pz_mm = ion_z_min
        RCL ion_z_min
        STO ion_pz_mm
        RLUP
        ; 
        ; ion_charge = 0  # make unaffected by fields
        0 STO ion_charge
        RLUP
        ; ion_vx_mm = 0
        0 STO ion_vx_mm
        RLUP
        ; ion_vy_mm = 0
        0 STO ion_vy_mm
        RLUP
        ; ion_vz_mm = 0
        0 STO ion_vz_mm
        RLUP
        ; 
        ; ion_initialized = 1
        1 STO ion_initialized
        RLUP
        ; ion_jumped = 1
        1 STO ion_jumped
        RLUP
        ; exit
        EXIT
    ; begin else
    GTO label20__
    LBL label19__
    RLUP
    RLUP
    LBL label20__
    ; end if
    ; 
    ; 
    ; # ion was jumped
    ; if ion_jumped == 1
    1
    RCL ion_jumped
    X!=Y
    GTO label23__
    RLUP
    RLUP
        ; mark()
        MARK
        ; ion_jumped = 0
        0 STO ion_jumped
        RLUP
        ; exit
        EXIT
    ; begin else
    GTO label24__
    LBL label23__
    RLUP
    RLUP
    LBL label24__
    ; end if
    ; 
    ; 
    ; # jump ion to next position
    ; if ion_px_mm + ion_x_step < ion_x_max
    RCL ion_x_max
    RCL ion_px_mm
    RCL ion_x_step
    +
    X>=Y
    GTO label35__
    RLUP
    RLUP
        ; ion_px_mm = ion_px_mm + ion_x_step
        RCL ion_px_mm
        RCL ion_x_step
        +
        STO ion_px_mm
        RLUP
    ; begin else
    GTO label36__
    LBL label35__
    RLUP
    RLUP
        ; ion_px_mm = ion_x_min
        RCL ion_x_min
        STO ion_px_mm
        RLUP
        ; if ion_py_mm + ion_y_step < ion_y_max
        RCL ion_y_max
        RCL ion_py_mm
        RCL ion_y_step
        +
        X>=Y
        GTO label33__
        RLUP
        RLUP
            ; ion_py_mm = ion_py_mm + ion_y_step
            RCL ion_py_mm
            RCL ion_y_step
            +
            STO ion_py_mm
            RLUP
        ; begin else
        GTO label34__
        LBL label33__
        RLUP
        RLUP
            ; ion_py_mm = ion_y_min
            RCL ion_y_min
            STO ion_py_mm
            RLUP
            ; if ion_pz_mm + ion_x_step < ion_z_max
            RCL ion_z_max
            RCL ion_pz_mm
            RCL ion_x_step
            +
            X>=Y
            GTO label31__
            RLUP
            RLUP
                ; ion_pz_mm = ion_pz_mm + ion_z_step
                RCL ion_pz_mm
                RCL ion_z_step
                +
                STO ion_pz_mm
                RLUP
            ; begin else
            GTO label32__
            LBL label31__
            RLUP
            RLUP
                ; ion_splat = 1
                1 STO ion_splat
                RLUP
                ; exit
                EXIT
            LBL label32__
            ; end if
            ; 
        LBL label34__
        ; end if
        ; 
    LBL label36__
    ; end if
    ; 
    ; ion_jumped = 1
    1 STO ion_jumped
    RLUP
    EXIT
; end segment
Listing 2 - tune.prg - PRG program compiled from tune.sl. This is understood by SIMION.

For the next step, to load the TUNE.IOB file. Then in the PAs tab, select "Fadj" to perform a fast electrode voltage adjust. For this demonstration, let's set the voltages on the electrodes to 100V, 90V, and 0V respectively from left to right:


Figure 4 - Fast adjusting potential array.

This generates the following potential energy map in the X-Y potential energy view (PE View tab). Notice that there is 100:90:0 ratio as expected on the heights of the three electrode potentials and that there is a slight potential energy curvature in the center of the middle electrode.


Figure 5 - X-Y potential energy display.

Now let's set up the data recording. First, click the "Def" button under the "Normal" tab to define your ions:


Figure 6 - Initial ion trajectory configuration.

We only need one ion flying to act as the neutral trace particle, so let's not confuse things by flying multiple ions. Ensure that there is only one "Trajectory Group" (the original example has two, so do a "Cut Grp" on the second) and that the number of ions (N) is set to "1 Ions". It is not important what the charge and kinetic energy (KE) are set to here because the user program will reset these both to zero. One thing that is important is for the ion's initial (X, Y, Z) position to to be within your potential array and not touching an electrode. Otherwise, the ion will not be controlled by the user program associated with your potential array, or the ion will "splat" before it even gets the chance to fly.

Next we'll set up data recording. In the "To Dev/File" box, enter the file name that data will be saved to (e.g. "data.txt") and enable the "Record" button. To configure data recording, click the "Define" button:


Figure 7 - Data recording configuration.

The screen has three parts: the parameters to record, when to record the parameters, and the format in which to record the parameters. Here, we record the X, Y, and Z positions along with the three compontents of the voltage potential gradient (i.e. electric field) denoted by dE/dx, dE/dy, and dE/dz. Ensure that "All Markers" is selected to record data after each mark() call in the user program. "Delimited" rather than "Verbose" should be selected so that the data file outputted is easier to import into Excel or another program. Click "OK" twice to exit.

Now we are ready to fly ions. Ensure that the "Vew RD" and "Dots" are not enabled, otherwise the run will be slowed down. Click "Fly'm". You will be afforded the option to adjust any of the adjustable variables in the user program at the time. For now, there is no need to do so, so click "Fly." An ion trace will be drawn.


Figure 8 - Ion trace after the Fly'm.

The simulation will append data to the data.txt file. The contents of the generated data.txt are shown below:

------ Begin Next Fly'm ------
0.5,-38.5,0,0,0,0
5.5,-38.5,0,-0.278991,-9.13219e-006,0
10.5,-38.5,0,-0.278852,-4.01533e-005,0
15.5,-38.5,0,-0.278547,-7.34804e-005,0
20.5,-38.5,0,-0.278079,-0.000105288,0
25.5,-38.5,0,-0.277488,-0.000123462,0
30.5,-38.5,0,-0.276886,-0.000111344,0
35.5,-38.5,0,-0.27644,-6.18776e-005,0
40.5,-38.5,0,0,0,0
45.5,-38.5,0,0,0,0
50.5,-38.5,0,0,0,0
55.5,-38.5,0,0,0,0
60.5,-38.5,0,-2.31121,-0.00346198,0
65.5,-38.5,0,-2.28817,-0.0052536,0
70.5,-38.5,0,-2.26196,-0.00496627,0
75.5,-38.5,0,-2.23998,-0.00380204,0
80.5,-38.5,0,-2.22422,-0.00257529,0
85.5,-38.5,0,-2.2141,-0.00155748,0
90.5,-38.5,0,-2.20848,-0.000750902,0
95.5,-38.5,0,-2.20649,-6.59663e-005,0
0.5,-33.5,0,0,0,0
5.5,-33.5,0,-0.27911,-6.33095e-005,0
10.5,-33.5,0,-0.278978,-0.00028001,0
15.5,-33.5,0,-0.278676,-0.00050965,0
20.5,-33.5,0,-0.278184,-0.000730146,0
25.5,-33.5,0,-0.27751,-0.00086432,0
30.5,-33.5,0,-0.276761,-0.000781595,0
35.5,-33.5,0,-0.276196,-0.000428521,0
40.5,-33.5,0,0,0,0
45.5,-33.5,0,0,0,0
50.5,-33.5,0,0,0,0
55.5,-33.5,0,0,0,0
60.5,-33.5,0,-2.32302,-0.0263515,0
65.5,-33.5,0,-2.28964,-0.0373788,0
70.5,-33.5,0,-2.25806,-0.0333549,0
75.5,-33.5,0,-2.23508,-0.0246132,0
80.5,-33.5,0,-2.22001,-0.0163149,0
85.5,-33.5,0,-2.21082,-0.00974569,0
90.5,-33.5,0,-2.20585,-0.00466664,0
95.5,-33.5,0,-2.20412,-0.000409193,0
0.5,-28.5,0,0,0,0
5.5,-28.5,0,-0.27942,-0.000122759,0
10.5,-28.5,0,-0.279312,-0.000550141,0
15.5,-28.5,0,-0.279041,-0.00103212,0
20.5,-28.5,0,-0.278523,-0.00155814,0
25.5,-28.5,0,-0.277642,-0.00198206,0
30.5,-28.5,0,-0.27641,-0.00192053,0
35.5,-28.5,0,-0.275413,-0.000982163,0
40.5,-28.5,0,0,0,0
45.5,-28.5,0,0,0,0
50.5,-28.5,0,0,0,0
55.5,-28.5,0,0,0,0
60.5,-28.5,0,-2.35783,-0.0808194,0
65.5,-28.5,0,-2.28606,-0.0923306,0
70.5,-28.5,0,-2.24316,-0.0711283,0
75.5,-28.5,0,-2.22071,-0.0483006,0
80.5,-28.5,0,-2.20886,-0.0305946,0
85.5,-28.5,0,-2.20256,-0.0178336,0
90.5,-28.5,0,-2.19941,-0.00843505,0
95.5,-28.5,0,-2.19836,-0.000736579,0
0.5,-23.5,0,0,0,0
5.5,-23.5,0,-0.279931,-0.000181043,0
10.5,-23.5,0,-0.279888,-0.000826939,0
15.5,-23.5,0,-0.279742,-0.00162472,0
20.5,-23.5,0,-0.279327,-0.00265697,0
25.5,-23.5,0,-0.278276,-0.00386608,0
30.5,-23.5,0,-0.27593,-0.00455823,0
35.5,-23.5,0,-0.272602,-0.00190491,0
40.5,-23.5,0,0,0,0
45.5,-23.5,0,0,0,0
50.5,-23.5,0,0,0,0
55.5,-23.5,0,0,0,0
60.5,-23.5,0,-2.39008,-0.2708,0
65.5,-23.5,0,-2.24277,-0.187416,0
70.5,-23.5,0,-2.20392,-0.116819,0
75.5,-23.5,0,-2.19281,-0.0717227,0
80.5,-23.5,0,-2.1899,-0.0430923,0
85.5,-23.5,0,-2.18944,-0.0244072,0
90.5,-23.5,0,-2.18955,-0.0113757,0
95.5,-23.5,0,-2.18965,-0.000988397,0
0.5,-18.5,0,0,0,0
5.5,-18.5,0,-0.280617,-0.000224068,0
10.5,-18.5,0,-0.280708,-0.00104426,0
15.5,-18.5,0,-0.280871,-0.00215438,0
20.5,-18.5,0,-0.280963,-0.00386668,0
25.5,-18.5,0,-0.2805,-0.00664765,0
30.5,-18.5,0,-0.277762,-0.0110268,0
35.5,-18.5,0,-0.265168,-0.0162149,0
40.5,-18.5,0,-0.174422,-0.0474932,0
45.5,-18.5,0,-0.147528,-0.286583,0
50.5,-18.5,0,-0.298707,-0.677306,0
55.5,-18.5,0,-1.17031,-1.30726,0
60.5,-18.5,0,-2.05017,-0.581398,0
65.5,-18.5,0,-2.10426,-0.275132,0
70.5,-18.5,0,-2.13131,-0.150602,0
75.5,-18.5,0,-2.15082,-0.0865227,0
80.5,-18.5,0,-2.1642,-0.0499965,0
85.5,-18.5,0,-2.17269,-0.0276633,0
90.5,-18.5,0,-2.1774,-0.0127294,0
95.5,-18.5,0,-2.17907,-0.001101,0
0.5,-13.5,0,0,0,0
5.5,-13.5,0,-0.281394,-0.000230872,0
10.5,-13.5,0,-0.281684,-0.00109313,0
15.5,-13.5,0,-0.282377,-0.00235655,0
20.5,-13.5,0,-0.283586,-0.00457495,0
25.5,-13.5,0,-0.285418,-0.0089318,0
30.5,-13.5,0,-0.287716,-0.0183902,0
35.5,-13.5,0,-0.289839,-0.0420459,0
40.5,-13.5,0,-0.300982,-0.109608,0
45.5,-13.5,0,-0.38922,-0.258448,0
50.5,-13.5,0,-0.657992,-0.468081,0
55.5,-13.5,0,-1.18682,-0.596075,0
60.5,-13.5,0,-1.69251,-0.447586,0
65.5,-13.5,0,-1.93302,-0.260687,0
70.5,-13.5,0,-2.04401,-0.147289,0
75.5,-13.5,0,-2.10272,-0.0839641,0
80.5,-13.5,0,-2.13603,-0.0478064,0
85.5,-13.5,0,-2.15498,-0.0261138,0
90.5,-13.5,0,-2.16487,-0.011916,0
95.5,-13.5,0,-2.16827,-0.00102739,0
0.5,-8.5,0,0,0,0
5.5,-8.5,0,-0.282108,-0.000184012,0
10.5,-8.5,0,-0.282616,-0.000882569,0
15.5,-8.5,0,-0.28394,-0.0019637,0
20.5,-8.5,0,-0.286615,-0.0040057,0
25.5,-8.5,0,-0.29189,-0.00832703,0
30.5,-8.5,0,-0.30277,-0.0181475,0
35.5,-8.5,0,-0.327307,-0.0410087,0
40.5,-8.5,0,-0.387568,-0.0901095,0
45.5,-8.5,0,-0.528175,-0.17294,0
50.5,-8.5,0,-0.795584,-0.267461,0
55.5,-8.5,0,-1.17882,-0.31153,0
60.5,-8.5,0,-1.55574,-0.263591,0
65.5,-8.5,0,-1.81796,-0.177358,0
70.5,-8.5,0,-1.97292,-0.107394,0
75.5,-8.5,0,-2.06129,-0.0625832,0
80.5,-8.5,0,-2.1116,-0.0357115,0
85.5,-8.5,0,-2.13978,-0.0194317,0
90.5,-8.5,0,-2.15426,-0.00883244,0
95.5,-8.5,0,-2.15918,-0.000760016,0
0.5,-3.5,0,0,0,0
5.5,-3.5,0,-0.282574,-8.59383e-005,0
10.5,-3.5,0,-0.283243,-0.000415615,0
15.5,-3.5,0,-0.28504,-0.00094064,0
20.5,-3.5,0,-0.288855,-0.00196479,0
25.5,-3.5,0,-0.29684,-0.00417787,0
30.5,-3.5,0,-0.314089,-0.00915266,0
35.5,-3.5,0,-0.35218,-0.0199979,0
40.5,-3.5,0,-0.433901,-0.0407835,0
45.5,-3.5,0,-0.59163,-0.072089,0
50.5,-3.5,0,-0.847145,-0.104281,0
55.5,-3.5,0,-1.17713,-0.118244,0
60.5,-3.5,0,-1.50563,-0.103912,0
65.5,-3.5,0,-1.76257,-0.0743883,0
70.5,-3.5,0,-1.93284,-0.0470257,0
75.5,-3.5,0,-2.03624,-0.0279528,0
80.5,-3.5,0,-2.09648,-0.0160462,0
85.5,-3.5,0,-2.13035,-0.00873328,0
90.5,-3.5,0,-2.1477,-0.00396367,0
95.5,-3.5,0,-2.15358,-0.000340933,0
0.5,1.5,0,0,0,0
5.5,1.5,0,-0.282657,3.75428e-005,0
10.5,1.5,0,-0.283356,0.000181588,0
15.5,1.5,0,-0.285243,0.000412104,0
20.5,1.5,0,-0.289275,0.000864917,0
25.5,1.5,0,-0.297773,0.00184626,0
30.5,1.5,0,-0.316181,0.00404465,0
35.5,1.5,0,-0.356543,0.00878299,0
40.5,1.5,0,-0.441485,0.0177099,0
45.5,1.5,0,-0.601378,0.0309219,0
50.5,1.5,0,-0.854583,0.0442923,0
55.5,1.5,0,-1.17698,0.0500417,0
60.5,1.5,0,-1.49848,0.044205,0
65.5,1.5,0,-1.75393,0.0319375,0
70.5,1.5,0,-1.92616,0.0203356,0
75.5,1.5,0,-2.03192,0.012133,0
80.5,1.5,0,-2.09384,0.00697427,0
85.5,1.5,0,-2.12869,0.00379701,0
90.5,1.5,0,-2.14655,0.00172301,0
95.5,1.5,0,-2.1526,0.000148167,0
0.5,6.5,0,0,0,0
5.5,6.5,0,-0.282333,0.000149931,0
10.5,6.5,0,-0.282918,0.000722035,0
15.5,6.5,0,-0.284465,0.00162048,0
20.5,6.5,0,-0.287676,0.00334571,0
25.5,6.5,0,-0.294229,0.00704111,0
30.5,6.5,0,-0.308161,0.0154128,0
35.5,6.5,0,-0.339441,0.0342874,0
40.5,6.5,0,-0.410892,0.0724863,0
45.5,6.5,0,-0.560982,0.133262,0
50.5,6.5,0,-0.822958,0.198995,0
55.5,6.5,0,-1.17779,0.22841,0
60.5,6.5,0,-1.52902,0.197273,0
65.5,6.5,0,-1.78951,0.137115,0
70.5,6.5,0,-1.9529,0.0848222,0
75.5,6.5,0,-2.04896,0.0498929,0
80.5,6.5,0,-2.1042,0.0285434,0
85.5,6.5,0,-2.13517,0.0155294,0
90.5,6.5,0,-2.15105,0.00705352,0
95.5,6.5,0,-2.15644,0.000606807,0
0.5,11.5,0,0,0,0
5.5,11.5,0,-0.281698,0.000218852,0
10.5,11.5,0,-0.282076,0.00104266,0
15.5,11.5,0,-0.283023,0.00228029,0
20.5,11.5,0,-0.284809,0.0045314,0
25.5,11.5,0,-0.287977,0.00913303,0
30.5,11.5,0,-0.293639,0.0194668,0
35.5,11.5,0,-0.305295,0.0448289,0
40.5,11.5,0,-0.340376,0.107439,0
45.5,11.5,0,-0.455956,0.227968,0
50.5,11.5,0,-0.728956,0.382124,0
55.5,11.5,0,-1.18227,0.463138,0
60.5,11.5,0,-1.62157,0.371183,0
65.5,11.5,0,-1.87896,0.231929,0
70.5,11.5,0,-2.01237,0.134877,0
75.5,11.5,0,-2.08468,0.0774609,0
80.5,11.5,0,-2.12545,0.0440864,0
85.5,11.5,0,-2.1484,0.0240248,0
90.5,11.5,0,-2.16027,0.0109405,0
95.5,11.5,0,-2.16432,0.00094251,0
0.5,16.5,0,0,0,0
5.5,16.5,0,-0.280925,0.000232475,0
10.5,16.5,0,-0.281088,0.00109015,0
15.5,16.5,0,-0.28144,0.00229193,0
20.5,16.5,0,-0.281907,0.0042579,0
25.5,16.5,0,-0.28214,0.00776362,0
30.5,16.5,0,-0.280641,0.0144126,0
35.5,16.5,0,-0.270748,0.0289706,0
40.5,16.5,0,-0.230968,0.0893611,0
45.5,16.5,0,-0.256623,0.286003,0
50.5,16.5,0,-0.482854,0.604512,0
55.5,16.5,0,-1.19687,0.903941,0
60.5,16.5,0,-1.86891,0.553408,0
65.5,16.5,0,-2.03231,0.28211,0
70.5,16.5,0,-2.09624,0.154371,0
75.5,16.5,0,-2.1316,0.0878715,0
80.5,16.5,0,-2.15289,0.0503347,0
85.5,16.5,0,-2.16554,0.0276713,0
90.5,16.5,0,-2.17231,0.0126831,0
95.5,16.5,0,-2.17467,0.00109539,0
0.5,21.5,0,0,0,0
5.5,21.5,0,-0.280187,0.000200938,0
10.5,21.5,0,-0.280189,0.000926703,0
15.5,21.5,0,-0.28014,0.00185643,0
20.5,21.5,0,-0.279862,0.00315107,0
25.5,21.5,0,-0.27889,0.00490158,0
30.5,21.5,0,-0.276048,0.00658494,0
35.5,21.5,0,-0.269265,0.00352703,0
40.5,21.5,0,0,0,0
45.5,21.5,0,0,0,0
50.5,21.5,0,0,0,0
55.5,21.5,0,0,0,0
60.5,21.5,0,-2.32751,0.429983,0
65.5,21.5,0,-2.19934,0.230423,0
70.5,21.5,0,-2.17857,0.133487,0
75.5,21.5,0,-2.17746,0.0792581,0
80.5,21.5,0,-2.18026,0.0467579,0
85.5,21.5,0,-2.18305,0.0262084,0
90.5,21.5,0,-2.18487,0.0121476,0
95.5,21.5,0,-2.18556,0.00105343,0
0.5,26.5,0,0,0,0
5.5,26.5,0,-0.279601,0.000146858,0
10.5,26.5,0,-0.279512,0.000662556,0
15.5,26.5,0,-0.279275,0.00126503,0
20.5,26.5,0,-0.27877,0.00196594,0
25.5,26.5,0,-0.277794,0.00261967,0
30.5,26.5,0,-0.276201,0.00268742,0
35.5,26.5,0,-0.274762,0.00127187,0
40.5,26.5,0,0,0,0
45.5,26.5,0,0,0,0
50.5,26.5,0,0,0,0
55.5,26.5,0,0,0,0
60.5,26.5,0,-2.37817,0.128762,0
65.5,26.5,0,-2.27704,0.125471,0
70.5,26.5,0,-2.23127,0.0890701,0
75.5,26.5,0,-2.21136,0.058064,0
80.5,26.5,0,-2.20222,0.0359978,0
85.5,26.5,0,-2.19785,0.0207422,0
90.5,26.5,0,-2.19583,0.00975352,0
95.5,26.5,0,-2.19518,0.000850022,0
0.5,31.5,0,0,0,0
5.5,31.5,0,-0.27921,8.65756e-005,0
10.5,31.5,0,-0.279084,0.000384959,0
15.5,31.5,0,-0.278789,0.000707476,0
20.5,31.5,0,-0.278283,0.001031,0
25.5,31.5,0,-0.277539,0.00124742,0
30.5,31.5,0,-0.276651,0.00114913,0
35.5,31.5,0,-0.275972,0.00062115,0
40.5,31.5,0,0,0,0
45.5,31.5,0,0,0,0
50.5,31.5,0,0,0,0
55.5,31.5,0,0,0,0
60.5,31.5,0,-2.33368,0.0415904,0
65.5,31.5,0,-2.28981,0.0554188,0
70.5,31.5,0,-2.25402,0.0471428,0
75.5,31.5,0,-2.2307,0.0338053,0
80.5,31.5,0,-2.21645,0.0220522,0
85.5,31.5,0,-2.20812,0.0130593,0
90.5,31.5,0,-2.20373,0.00622616,0
95.5,31.5,0,-2.20221,0.000545148,0
0.5,36.5,0,0,0,0
5.5,36.5,0,-0.279017,3.01866e-005,0
10.5,36.5,0,-0.27888,0.000132425,0
15.5,36.5,0,-0.278575,0.000239169,0
20.5,36.5,0,-0.278102,0.000338183,0
25.5,36.5,0,-0.277493,0.000393187,0
30.5,36.5,0,-0.276859,0.000351519,0
35.5,36.5,0,-0.276388,0.000194264,0
40.5,36.5,0,0,0,0
45.5,36.5,0,0,0,0
50.5,36.5,0,0,0,0
55.5,36.5,0,0,0,0
60.5,36.5,0,-2.31374,0.011099,0
65.5,36.5,0,-2.2886,0.0166011,0
70.5,36.5,0,-2.26118,0.0154935,0
75.5,36.5,0,-2.23893,0.0117628,0
80.5,36.5,0,-2.22329,0.00792593,0
85.5,36.5,0,-2.21336,0.0047775,0
90.5,36.5,0,-2.20788,0.00229828,0
95.5,36.5,0,-2.20596,0.000201823,0
Listing 3 - data.txt - Generated data file containing a field map: x, y, z, E_x, E_y, E_z.

So what can we do with this data? For demonstration, below is an example of importing the data into the gnuplot plotting program (after replacing the commas with spaces as expected by the program). This graph displays the X and Y vector field lines on the X-Y plane. Each vector corresponds to a row in the above data.txt file, where the (X, Y, Delta-X, Delta-Y) values for the vectors are taken from columns numbered (1, 2, 4, 5) in data.txt.


Figure 9 - Electrostatic field map generated by the gnuplot program. The lines are field vectors.

Notice that the above field is the mathematical gradient of the potential map given in SIMION:


Figure 10 - Electrostatic potential energy map in SIMION.

Reading a Field Directly from the *.PA0 File

As mentioned in the introduction, there is another way to extract the field information other than to fly a neutral particle though the entire field: from the PA0 file directly.

One way, that does not require any programming, is to use the "PA --> Text" function in the SL Tools program in the SL Toolkit.

Another way, described below, is to write a C++, Python, or Perl program that will read the field values directly from the refined and fast-adjusted *.PA0 file. This can be accomplished with the SL Libraries that come with the SL Toolkit.

A SIMION potential array file is stored as a bitmap of the voltage potentials at all electrode and non-electrode points. These potential values can be queried directly with the SL Libraries. However, what we really want here is the electric field at all points, which is the gradient of the potential. Starting with SL v. 1.2, the SL Libraries has a functions built-in for computing the gradient according to the calculation methods described starting on p. E-9 of the printed manual. Here is a preview of some Perl code to accomplish the generation of the data.txt file:

use strict;
use SIMION::PA;

my $pa = new SIMION::PA(file => 'c:/sim7/_tune/tune.pa0');
open(my $fh, ">pdata.txt") or die $!;

my $z = 0;
for(my $y = -38.5; $y < 38.5 - 1; $y += 5) {
    for(my $x = 0.5; $x < 98.5 - 1; $x += 5) {
        print $fh "$x, $y, $z, ",
                  join(', ', $pa->field_real($x, $y, $z)), "\n";
    }
}
Listing 4 - field.pl - Perl program using the SL Libraries for Perl to generate a data file containing the electrostatic field map directly from a potential array file. This code requires the SL Toolkit 1.2 or above.

Below is a snippet of the results. Compare this to the previous data.txt file.

0.5, -38.5, 0, 0, 0, 0
5.5, -38.5, 0, -0.278990594992763, -9.13218690357098e-06, -0
10.5, -38.5, 0, -0.278852413169545, -4.01533280296462e-05, -0
15.5, -38.5, 0, -0.278547491586551, -7.34803709292464e-05, -0
...
Listing 5 - Electrostatic field data file generated from field.pl.

Note that coordinates here are in grid units with respect to the potential array, not workbench coordinates as before. In this example, both coordinate systems overlap, so no difference is evident.

Importing a Field into SIMION

Now that we have discussed exporting a field from SIMION, how do we import a field into SIMION? As before, there are several ways.

One way is to associate a user program with your potential array and have the user program adjust the observed electrostatic or magnetic field variables on each ion at each timestep of the calculation by looking up in a (ASCII) data file the field defined for the current ion position. Field values for points not defined in the data file are interpolated from surrounding points. This solution uses the efield_adjust and mfield_adjust program segments and the ion_bfield_* and ion_dvolts_* variables as described on page I-21 and I-28 of the printed SIMION manual. See the "Measured Magnetic Fields" section of the "Advanced SIMION Ion Opics: An ASMS Course" (also distributed on the SIMION CD) for a full explanation of this method.

The bfield.prg program in the "Measured Magnetic Fields" lab is written in PRG code. For elucidation, the below listing shows the bfield.prg converted to a high-level SL program. Here, the field for a given ion position is computed from a data file ("bfield.dat"), which is read into the bfield array in memory. If the ion is not located on a point defined in the bfield array, linear interpolation is used with respect to the four surrounding points defined in the bfield array. Notice that we use some array index computations since the bfield array is one-dimensional, but it is storing two-dimensional data.

# Define a field from a data file.
# (instance scaling 1 mm/gu)

static x_size =    21
static y_size =    40
static grid_size = 5

# Field data file.
#   bx, by; 21x by 40y array; first point is 0,0;
#   scan lines in x then y every grid_size.
adjustable[1680] bfield      # 1680 = 21 * 40 * 2

adjustable field_loaded = 0

sub mfield_adjust
    # load field from file
    if field_loaded == 0
        array_load(bfield, "bfield.dat")
        field_loaded = 1
    endif

    # use pa B values if first ion
    if ion_number == 1
        exit
    endif

    # assume initially that fields are zero
    ion_bfieldx_gu = 0
    ion_bfieldy_gu = 0
    ion_bfieldz_gu = 0

    # exit if ion beyond data array limits
    if ion_px_abs_gu > (x_size - 2) * grid_size
        exit
    endif
    if ion_py_abs_gu > (y_size - 2) * grid_size
        exit
    endif

    x = ion_px_abs_gu / grid_size   # convert to data array spacings
    xint  = int(x)                  # convert to integer and fraction components
    xfrac = frac(x)
    xlfrac = 1 - xfrac

    y = ion_py_abs_gu / grid_size   # convert to data array spacings
    yint = int(y)                   # convert to integer and fraction components
    yfrac = frac(y)
    ylfrac = 1 - yfrac

    idx = yint * 21 + xint          # offset to lower-left (LL) corner point
    llnbx = idx*2 + 1               # index of LL corner of bx
    llnby = idx*2 + 2               # index of LL corner of by

    # calculate ion's B_x field by linear interpolation
    ion_bfieldx_gu =
          bfield[llnbx]                * xlfrac * ylfrac
        + bfield[llnbx + 2]            * xfrac  * ylfrac
        + bfield[llnbx + x_size*2]     * xlfrac * yfrac
        + bfield[llnbx + x_size*2 + 2] * xfrac  * yfrac

    # calculate ion's B_r field by linear interpolation
    bfieldr =
          bfield[llnby]                * xlfrac * ylfrac
        + bfield[llnby + 2]            * xfrac  * ylfrac
        + bfield[llnby + x_size*2]     * xlfrac * yfrac
        + bfield[llnby + x_size*2 + 2] * xfrac  * yfrac

    # set field
    (radius, theta)                  = rect_to_polar(ion_py_gu, ion_pz_gu)
    radius = bfieldr
    (ion_bfieldy_gu, ion_bfieldz_gu) = polar_to_rect(radius, theta)
endsub
Listing 6 - bfield.sl - SL program to generate a magnetic field in SIMION simulation. This is a drop-in replacement for to the bfield.prg program.

Things can be much simpler if the field can be defined exactly by an equation as shown below. In such case, no data interpolation is needed.

sub mfield_adjust
    ion_bfieldx_gu = ion_px_gu * 2 + ion_py_gu
    ion_bfieldy_gu = ion_px_gu     + ion_py_gu * ion_py_gu
    ion_bfieldz_gu = 0
endsub
Listing 7 - example SL program for generating a magnetic field during a SIMION simulation and according to a closed-form equation.

Writing a Field Directly to a *.PA0 File

The alternate to importing a field using user programs is to create the refined *.PA0 file directly yourself and then read that *.PA0 file into SIMION as normal. This would be the more natural and SIMION-ish solution because you can then fully visualize the potential array even when no ions are flying.

However, since a PA file is stored as a bitmap of scalar electrostatic or magnetic potentials--not vector fields--you will have to first compute the scalar potential map corresponding to your field by computing a line integral over vector field. The resultant potential map can then be stored in the *.PA0 file using the PA Tools. This integration step is performed automatically by the "Text --> PA" function in SL Tools. (See p. 2-10 of the printed SIMION manual for further discussion on potentials v.s. fields.)

A related solution is to use the "field" method in the SL Libraries to write the field from a general purpose programming language. Here is an example:

 use strict;
 use SIMION::PA;

 #-- create a magnetic field from scratch
 my $pa3 = new SIMION::PA(nx => 50, ny => 50, field_type => 'magnetic');
 my $z = 0;
 for my $x (0..$pa3->nx-1) {
 for my $y (0..$pa3->ny-1) {
     my $ex = $x;
     my $ey = $y**2;
     my $ez = 0;
     $pa3->field($x, $y, $z, $ex, $ey, $ez);
 }}
 $pa3->save('mag1.pa');

See the SL Libraries documentation for details since there are some requirements on on how the field is set (the points must be traversed in "lexographic" order).

The last two solutions may or may not be more accurate than the first because it relies on SIMION to do the field interpolation near electrode boundaries. The previous bfield.sl program does not (although it could) handle electrode boundaries specially when it implements its own linear interpolation. SIMION's method provides some special handling of electrode boundaries as described on page E-7 of the printed SIMION manual. (If anyone can explain to me what the somewhat ambiguous "If one of the four points..." paragraph on p. E-7 is talking about, I'd be interested in knowing.)

Conclusion

We have demonstrated how to export/import the electrostatic/magnetic fields calculated by SIMION to/from an ASCII text file for use in an external program.

(c) 2004 Scientific Instrument Services, Inc.
--Supplies and Services for Mass Spectrometers, Gas Chromatographs and Liquid Chromatographs.

The SIMION SL Toolkit™ and documentation is (c) 2003-2004 Scientific Instrument Services, Inc. All Rights Reserved.
Any comments on this web page? (will be sent to SIS SIMION Support)
[Optional] Your name: email: phone/fax:
The SL Tookit™ and documentation is (c) 2003 Scientific Instrument Services, Inc. All Rights Reserved.