Navigation

A SIMION geometry file (GEM) defines electrode geometries using
constructive solid geometry (CSG) primitives. CSG operations define
shapes using unions and intersections of other basic shapes (e.g. a
rectangular slab with a cylinder hole cut through it), a bit
similar in concept to machining. GEM files are text files and have
the file name extension of “.GEM”. SIMION can convert a GEM file to
a PA file.

The GEM file appendix in the printed manual is perhaps the first place to start.
See also SIMION Example: geometry for examples.
“courses\advanced” also has some notes on GEM files.
Additional tips are given on this page.

This page is abridged from the full SIMION 8.1.1 "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:

SIMION 8.2 Early Access Mode makes major enhancements to the GEM syntax.
Here is a summary of the new features described in more detail below.

New commands to define shapes easier or with fewer rotations:

cylinder3d() - easily defines a cylinder between two endpoints:
cylinder3d(5,5,0,5,5,10,3).
Use this rather than cylinder since it can be simpler
and avoids locate rotations.

half_space() - defines a volume
below an infinite plane defined by a point and normal vector.
half_space(5,0,0,1,1,1).
Use this rather than than box3d since it is simpler and avoids
rotations.

shape() - defines your own custom shapes from analytical equations
or function.
Example:
e(1){shape(function(x,y,z)returnx^2+y^2>zend) .
Complex surfaces can be defined directly in the GEM file.
No need for doing this outside of a GEM file with
the simion.paspa:fill() API.

New transformations:

extrude_xy(), extrude_yz() and extrude_zx() -
extrudes a 2D image drawn in the given plane.
For example, polyline normally takes an XY plane drawing,
which can then be wrapped in a rotation (locate) to another plane,
but the rotation can be tricky.
These commands make it more clear:
extrude_yz(){polyline(0,0,5,10,10,0)};y,zpoints .
Even XY extrusions can be specified more simply; for example to extrude
from z=3 to z=5:
extrude_xy(3,5){polyline(0,0,5,10,10,0)};x,ypoints .

revolve_xy(), revolve_yz(), revolve_zx() -
define volumes of rotation in any given plane.
These are suggested instead of rotate_fill, which only operates
in the XY plane without subsequent rotation.
This command also defines a shape, so it can be used wherever
shapes can be used, such
as intersections, which is not possible with rotate_fill
(except via the workaround of cutting away from a rotate_fill
using a subsequent n(0){} but that may cut more than the current shape).

rotate_x(), rotate_y(), rotate_z() - rotates contained
objects. They rotate counter-clockwise (CCW) looking down the positive
end of the given axis.
These are recommended over locate commands for clarity.
Many times you can omit rotate_x|y|z as well when the
commands above are used.

Other command improvements:

pa_define() accepts named parameters.
pa_define{101,101,dx=0.1} is equivalent to
pa_define(101,101,1,p,n,e,,0.1,,,,auto).
This is recommended.
Please note that the {} syntax has different defaults than (), such as
planar non-mirror symmetry and the newer surface='auto'.
Another example: pa_define{101,101,1,'planarxy',surface='fractional'}.

pa_define() can accept mm array sizes rather than grid point sizes.
The above example can be rewritten as
pa_define{10*mm,10*mm,dx=0.1} .
It defines a 10 * 10 mm^2 region. This recommended.

e(): and n() can accept a function parameter for defining
gradient voltages over electrodes or analytic potentials in space.

fill and within can be omitted when not necessary, for shorter GEM code.
Use e(1){circle(0,0,50)} rather than
e(1){fill{within{circle(0,0,50)}}} . See omit fill/within commands.

intersect() is a synonym for within.
The name intersect makes the meaning more clear and is recommended.
e(1){intersect{box(0,0,10,10)circle(0,0,10)}} .

inf to represent infinity rather than a large number (e.g. 1e6).
box(-inf,0,inf,2). This is more clear and recommended.

Simpler syntax:

$(...) and # can be omitted around Lua code. They are no longer
necessary:

local w = 2
e(1) {
for i=1,3 do
box(i*10,0, i*10+w, 10)
end
}

Using a Lua style comment -- in the file will disable
compatibility mode supporting older deprecated GEM syntax such as
space-delimited argument lists, + before numbers, and unquoted strings.
New syntax.

The preprocessing syntax $(...) is still supported for compatibility.
But some semantics of preprocessing have changed because it is now part of the
language rather than as a separate preprocessing step that
operatings on strings.
If the old $(...) syntax is used, it is now more strict and may break some
existing code in obscure cases.

This used to be valid but is no longer valid because the if and {
are not properly nested:

Keep in mind $(...) can now only be used in the context of a command or parameter,
and $(x) is usually equivalent to x except when x is a string,
where it is interpreted as GEM code to be compiled.
So $("box(0,0,10,10)") is equivalent to box(0,0,10,10) .
One obscure behavior:

within/intersect is still required if you need to take the intersection (AND)
of two shapes rather than union (OR), as shown above.

Inside a fill the order of notin’s and within’s is not important,
but multiple fill’s are applied in order,
and if fill is omitted, then each within that follows a notin creates
a new fill. Therefore, order can be important when fill is omitted.
This is seen in the example above:
e(1){box(0,0,10,10)notin{box(1,1,9,9)}box(3,3,7,7)notin{box(4,4,6,6)}} -
the notin’s only cuts from the immediately prior within’(s),
not the following ones, nor ones before previous notin’s.

Named parameters require using {...} not (...).
When using named parameters or when compatibility mode is disabled
(using Lua -- comments), string values must
be quoted (single or double quotation marks), like 'planar' and
surface='auto'.

When using the {...} syntax, there are a few differences:

values are checked more strictly:

symmetry must be ‘planar’ (or ‘p’) or ‘cylindrical’ (or ‘c’).
Other abbreviations or capitalization like ‘Plan’ are not allowed.

mirror must be ” (none), ‘x’, ‘y’, ‘z’, ‘xy’, ‘xz’, ‘yz’, or ‘xyz’.

type must be ‘electric’ (or ‘e’) or ‘magnetic’ (or ‘m’).

default values differ:

symmetry defaults to 'planar' (not 'cylindrical').

mirror defaults to ”none’` (not “y”).
So, pa_define(11,11,1,p,n) can now be written pa_define{11,11,1}, and
pa_define(11,11,1) can now be written pa_define{11,11,1,'c'}.

surface defaults to 'auto'.

When using the older (...) syntax, the following enhancements were also made:

symmetry now defaults to planar when nz > 1, rather than raising an error, so
you can now do pa_define(11,11,11), and mirroring will be none in that case.

The following parameters were added in 8.2EA:

gx, gy, gz - number of grid units. These are one less than the number of grid
points. These are requivalent:

This is now a synonym of within but provided for improved readability.
intersect (or within) defines a volume that is inside the all the
listed shapes (i.e. their “intersected” or boolean “and” volume).

Forms a volume of revolution with the given angle (defaults to 360 degrees)
of the XY plane around the X-axis (CCW facing down positive X axis).
This is similar to rotate_fill but can be used in shape context.
The contents inside the brackets can be within’s and notin’s.

Defines the volume below the given plane.
The plane is defined by the point (x1,y1,z1) and surface normal vector (ux,uy,uz) on that plane.
The fill is in the direction opposite the normal vector.
The normal vector length is not important (need not be normalized).

For example, the region x <= 2 is defined by half_space(2,0,0,1,0,0).
The region x + y <= 4 is defined by half_space(2,2,0,1,1,0).

The electrode and non-electrode commands now accept a
function as the parameter, which will be queried to determine the
potential at the current point.
This allows things like defining gradient voltages over electrode
surface or analytical potentials in space.

As of SIMION 8.0.4, the GEM processor incorporates a preprocessor
that allows things like variable expansion and loops (Issue-I296).
which allows GEM files to be more maintainable and easily modified.
(This new feature is not described in the 8.0.4 manual except in a footnote.)

A new example GEM file (examples\geometry\macro.gem) illustrates
the use of this new feature:

When SIMION loads a GEM file containing macros (e.g. macro.gem), it
processes those macros, writes the result to temporary file
(e.g. macro.processed.gem), and loads that temporary file.

It also possible to do your own GEM file preprocessing outside of SIMION with
your own programming tools. This was more popular prior to the introduction of
the above feature but can still be useful in some cases.

The pa_define command has various
extensions: pa_define(nx,ny,nz,symmetry,mirroring,type,ng,dx_mm,dy_mm,dz_mm,gu,surface=fractional)

pa_define allows a PA to be marked “not refinable” by using an underscope
in the pa_define command type argument
(e.g. electric_ or magnetic_). This is equivalent to
setting simion.paspa.refinable to false.
This is useful for PAs that store some type of special field that should not be
automatically refined in the usual manner (e.g. magnetic vector potential,
space-charge, dielectric constants, permeability, gas flow, etc.).
It is used extensively in SIMION Example: magnetic_potential and
SIMION Example: dielectric (Magnetic Potential and Dielectrics).
Added in 8.1.1.0.

This page is abridged from the full SIMION 8.1.1 "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:

Obtaining optimal field accuracy of curved surfaces had been tricky
prior to the addition of the Electrode Surface Enhancement / Fractional Grid Units feature in
SIMION 8.1.1.
Electrode surfaces that did not exactly align to PA grid points had
to be placed instead on nearby grid points, and certain ways of making
this placement were more accurate than others.
Cutout volumes (e.g. notin GEM commands) were also prone to error
(Intersecting within and notin_inside).
Consider the example of defining the field between concentric
spheres of radii 40 and 80 mm.
We can now accurately and simply define this in a GEM file
using the (“fractional”) surface enhancement option like this:

However, perhaps there are still cases where you prefer
not to use surface enhancement.
For whatever the reason (see below),
SIMION 8.1.1.25 supports a new surface=auto
option in the pa_define statement of GEM files to
achieve a more accurate alignment of surfaces in a simple manner
when not using surface enhancement.
It can be used simply like this:

However, without care, surfaces could be off effectively by about
0.5-1.0 grid unit (gu), thereby distorting fields by the
same amount as if the electrodes were misaligned by this distance
in the real physical system (e.g. machining or assembly error).
The above is nearly equivalent to this:

The within and notin commands apply a +0.5 grid unit (gu)
adjustment to the radius of the fill,
which improves field accuracy for the within,
but for the notin we actually want more like a -0.5 gu adjustment.
In fact, electrode #2 in the above two examples is visibily off
slightly when measured in the View screen.
We have typically recommended using notin_inside rather than
notin:

Visually that looks about right if you examine the PA on the View
screen, and the calculated field is reasonably good.
However, the notin_inside (as with within_inside)
actually applies a nearly 0 gu not -0.5 gu adjustment, so
fields are slightly biased.
But even this is not ideal in the case of spheres.
In fact, the optimal adjustment is often not 0.5 gu but
about 0.35 gu, as has been observed for spherical capacitor studies
ref and other internal
studies on flat and curved shapes rasterized to PA’s.

In SIMION 8.1.1.25, a new surface=auto option has been added
that automatically applies the best adjustment to within
and notin fill types. It can be used simply like this:

surface=auto also affects other shape types like
box, parabola, hyperbola, and polyline
by applying approximately 0.35 gu offsets in the
appropriate directions.

surface=auto is even useful when electrodes do exactly align
to PA grid points (like surfaces that are flat, orthogonal to the axes,
and have coordinates that are integral multiples of grid units)
because it will automatically get the surfaces boundary points right.
Consider defining a 4x4 mm box with a 2x2 mm hole inside,
which obviously easily aligns to points on a 1 mm/gu grid.
You might naively try to do it like this:

However, the notin{box(2,2,4,4)} (as is also true when using
notin_inside_or_on) excludes from the cut the PA grid
points on both the inside and border of the 2x2 box.
You want to instead use a notin_inside to only exclude
the grid points on the “inside” (not border) of the 2x2 box:

When surface=auto is enabled
(and this is also true of surface=fractional as of 8.1.1.25),
any PA grid points that precisely align
to an edge of a within or notin fill volume are made to
be electrode points, which is usually what you want.
In other words, a notin inside an e
or a within inside an n (both of which remove electrode
material) will be treated as an “inside” fill to avoid
removing the electrode points from the border.
This largely avoids fiddling with
within_inside/within_inside_or_on/notin_inside/notin_inside_or_on
fill variants since within and notin will now just do the
right thing.
In fact, with surface=auto, it’s not usually needed nor recommended
to use fill types other than within and notin;
for example, the following is not correct but behaves similar to
the “naive” approach mentioned earlier:

Please note, however, that although surface=auto is generally
preferred over surface=none (i.e. the default old behavior in SIMION 7.0/8.0)
for ease and accuracy reasons,
surface=fractional (see Electrode Surface Enhancement / Fractional Grid Units)
is still preferred over both of these.
So, there’s not really a reason to use surface=auto unless
for some reason you don’t want to use surface enhancement.
It’s not really clear what that reason would be except maybe
to generate PA’s that are refinable under SIMION 8.0 or to compare
accuracy differences with/without surface enhancement.
A GEM file using surface=fractional can be quickly switched to
surface=auto without any changes, but switching to surface=none
may cause 1 gu errors unless additional changes are made to within/notin
fill types due to the semantic difference these have under surface=none.
surface=auto is somewhat of an anachronism that behaves between
surface=none and surface=fractional but happened to be
implemented after both for completeness.

8.1.2.4: Macro lines beginning with ‘#’ can now be indented with tabs and spaces.
This allows cleaner indenting of GEM code.

8.1.1.25: A GEM: New surface=auto parameter in pa_define.
This provides a simple way to more accurately position curved surfaces
and cutout (notin) volumes when not using surface enhancement (surface=fractional).
This particularly applies to circle/sphere/cylinder,
hyperbola (Issue-I371), parabola, polyline, notin, and others.
Surface enhancement is still better, but if you don’t want to use
surface enhancement for some reason, then this is better than nothing.
See surface=auto option in pa_define [8.1.1.25].

8.1.1.25: C GEM: within_inside_or_on/notin_inside_or_on now shift
the electrode surface outward by a small 0.0001 gu offset.
(within_inside and notin_inside already apply this offset
but in the reverse redirection.)
This more reliably ensures points “on” the shape boundary are filled
even when small numerical round-off occurs in operations like
polyline and scaling.
Example: fill{within_inside_or_on{box(1,1,5,5)}} and
fill{within_inside_or_on{polyline(1,1,5,1,5,5,1,5)}}
behave identically now, as expected. [*]

x GEM/polyline: polyline GEM command accuracy has been improved.
Previously, the points on the polygon edge might not be optimally filled with
the desired electrode/non-electrode point type.
This particularly affected
within_inside/notin_inside/within_inside_or_on/notin_inside_or_on
rather than within.
However, under surface=fractional, it also affected within/notin
(but is somewhat cosmetic since electrode point types on the surface are not
critical for field accuracy under surface=fractional).
Example: polyline(10,515,515,1020,1020,1515,1515,2010,2010,155,155,1010,10)
(cross).

8.1.1.25: C GEM/Surface: PA grid points that precisely align to an edge of a within/notin
fill volume are made to be electrode points if surface=fractional or surface=auto
is enabled.
In other words, a notin inside an e or a within inside an n
(both of which remove electrode material) will be treated as an “inside” fill to avoid
removing the electrode points from the border.
This largely avoids fiddling with
within_inside/within_inside_or_on/notin_inside/notin_inside_or_on
fill variants since within and notin will now just do the
right thing.
The default option (surface=none) retains the old behavior for compatibility though.
Example: e(1){fill{within{box(1,1,5,5)}notin{box(1,1,5,5)}}}
and e(1){fill{within{box(1,1,5,5)}}}n(0){fill{notin{box(1,1,5,5)}}}
both create a 4x4 hollow box with infinitesimally thin walls under surface=auto or
surface=fractional.
See surface=auto option in pa_define [8.1.1.25].

8.1.1.25: c GEM: polyline, points, and points3d commands can now accept an arbitrary
number of points. Previously these were limited to 100, 100, and 65 points.