userFuncUpdater
Works with VSimBase, VSimEM, VSimPD, VSimPA, and VSimMD licenses.
Sets field values to the result of a user-given function.
The FieldUpdater of kind = userFuncUpdater
is a very flexible updater
that sets a field to the result of a user-given <Expression>
(see expression). The expression
takes as arguments field values and spatial positions, as
well as time and time step.
The userFuncUpdater can be used to do many different things; to understand how it works in some simple cases, it may be easier to skip to the examples at the end of this section.
The userFuncUpdater places iterators at the first cell of each read/writeField. The iterators are then moved from cell to cell; each iterator keeps track of its position and the field value at that position. As the iterators are collectively moved from cell to cell, an update is performed at each cell. An iterator knows its cell index, as well as the exact spatial location of the field value corresponding to that cell index (taking into account the field offset; e.g., the Yee electric field is usually located at the center-edges of a cell).
A userFuncUpdater has one iterator for every writeField, and one for every readField. The userFuncUpdater sets the field-values through the iterators on its writeFields according to a function of, among other things, the iterator positions, and the values of the readFields at their iterators. It then moves all the iterators by one cell and does the same thing, etc.
A userFuncUpdater can also has one or more readScalars. These scalars are read only. They can be used as variables in the function expression. userFuncUpdater can not update any scalars. To updater a scalar, one should use userFuncScalarUpdater.
A userFuncUpdater specifies a function (an Expression) that takes as arguments the values of the read fields, the positions of the read- and write-Field iterators, as well as the time and time step; and the function returns a vector with one value for each writeField (at each cell, each writeField is set to the corresponding value).
The userFuncUpdater
takes the lowerBounds
and
upperBounds
parameters of FieldUpdater, as well as
the following parameters:
readFields (optional string vector, default = [])
The names of the fields to read. A field name can be repeated if multiple iterators are used from a single field.
readScalars (optional string vector, default = [])
The names of the scalars to read. A scalar name can be directly used as a variable in a userFunc expression.
writeFields (required string vector)
The names of the fields to write. A field name can be repeated if multiple iterators are used from a single field.
readComponents (optional integer vector)
The component used for each readField. If any
readFields
are specified, this must be as well, and have
the same number of elements as readFields
.
writeComponents (required integer vector)
The component used for each writeField. This must have the same
length as writeFields
.
readItersShiftInX (optional integer vector)
This has the same length as readFields
; by default
it is all zeros. With this specified, each readFields
iterator is shifted by the corresponding number of cells in the
\(x\) direction. For example, readItersShiftInX = [1
0]
will shift the iterators on the first readFields
by
one cell in the \(+x\) direction, and won’t shift the
iterators on the second readFields
in \(x\).
readItersShiftInY (optional integer vector)
Similar to readItersShiftInX
, but shifts iterators in
\(y\). If the \(y\) direction is not simulated, this is
ignored.
readItersShiftInZ (optional integer vector)
Similar to readItersShiftInX
, but shifts iterators in
\(z\). If the \(z\) direction is not simulated, this is
ignored.
readFieldVarNames (optional string vector)
The variable names given to the value of each field–this is how
the field values will be referenced in the Expression. If any
readFields
are specified, this must be as well, and have
the same number of elements as readFields
. Each name
must be unique; some names are forbidden, such as t
and dt
and n
.
readFieldPosVariables (optional string vector)
The names given to the variables representing the position of the
corresponding readField value; each such variable is an
\(N\)-dimensional vector, where \(N\) is the dimension of
the simulation. However, notUsed
means that the
corresponding field position is not used in the Expression;
ignoring a position in this way can speed up computation. If
pos
is the variable name given to a certain readField, then
the variable pos
(that appears in the Expression) will be an
\(N\)-dimensional vector. For example, in an expression, the
\(x\) position would be accessed by select(pos, 0)
and the
\(y\) position (in 2D or 3D simulation) by select(pos,
1)
. If given, this parameter must be a vector with the same
length as readFields
. If not given, all elements are
set to notUsed
.
writeFieldPosVariables (optional string vector)
Analogous to readFieldPosVariables
, but for
writeFields
.
updateFunction (required parameter block)
A parameter block of type Expression and name
updateFunction
is required to define the function used
to update the writeFields
. This block takes the same
parameters as an expression UserFunc,
except for Input
blocks and the inputOrder
parameter. The input variables for the expression
are
defined by the above parameters, so they are not to be specified
in the updateFunction
block. In addition, the
expression can take the following input valiables:
t
:dt
:n
:(These names are reserved—they cannot be used as variable names
in readFieldVarNames
, readFieldPosVariables
, or
writeFieldPosVariables
.)
The Expression must return a vector with the same length as the number of writeFields—each writeField value will be set to the corresponding component of the return vector.
Here is a userFuncUpdater to set a scalar field \(F\) to a function \(f(x,y,z,t)\):
<FieldUpdater setF>
kind = userFuncUpdater
lowerBounds = [0 0 0]
upperBounds = [NX NY NZ]
writeFields = [F]
writeComponents = [0]
writeFieldPosVariables = [Fpos] # just a choice of name
maxNumEvals = 64
<Expression updateFunction>
$ X = select(Fpos, 0) # makes the function more readable
$ Y = select(Fpos, 1)
expression = sin(kx * X + ky * Y + kz * select(Fpos, 2) - omega * t)
<Term kx>
kind = constant
value = [10.]
</Term>
<Term ky>
kind = constant
value = [20.]
</Term>
<Term kz>
kind = constant
value = [3.]
</Term>
<Term omega>
kind = constant
value = [ $ LIGHTSPEED * math.sqrt(10^2 + 20^2 + 3^2) $ ]
</Term>
</Expression>
</FieldUpdater>
The above could be done equally well with a STFuncUpdater. However, setting a vector field \(\mathbf{F}\) to a field can be done better with a userFuncUpdater, since it can evaluate the function at a different position for each component:
<FieldUpdater setF>
kind = userFuncUpdater
lowerBounds = [0 0 0]
upperBounds = [NX NY NZ]
writeFields = [F F F]
writeComponents = [0 1 2]
writeFieldPosVariables = [FxPos FyPos FzPos]
maxNumEvals = 64
<Expression updateFunction>
kind = expression
$ XPHASE = kx * select(FxPos,0) + ky * select(FxPos, 1) + kz * select(FxPos, 2)
$ YPHASE = kx * select(FyPos,0) + ky * select(FyPos, 1) + kz * select(FyPos, 2)
$ ZPHASE = kx * select(FzPos,0) + ky * select(FzPos, 1) + kz * select(FzPos, 2)
expression = sin( vector(XPHASE, YPHASE, ZPHASE) - omega * t)
<Term kx>
kind = constant
value = [10.]
</Term>
<Term ky>
kind = constant
value = [20.]
</Term>
<Term kz>
kind = constant
value = [3.]
</Term>
<Term omega>
kind = constant
value = [ $ LIGHTSPEED * math.sqrt(10^2 + 20^2 + 3^2) $ ]
</Term>
</Expression>
</FieldUpdater>
Here is a userFuncUpdater that multiplies a 3-vector field \(\mathbf{G}\) by \(\Delta t\) and adds it to a 3-vector field \(\mathbf{F}\) (i.e., \(\mathbf{F}\mapsto\mathbf{F} + \mathbf{G}\Delta t\)):
<FieldUpdater addGdtToF>
kind = userFuncUpdater
lowerBounds = [0 0 0]
upperBounds = [NX NY NZ]
readFields = [F F F G G G]
readComponents = [0 1 2 0 1 2]
readFieldVarNames = [Fx Fy Fz Gx Gy Gz]
writeFields = [F F F]
writeComponents = [0 1 2]
maxNumEvals = 64
<Expression updateFunction>
expression = vector(Fx, Fy, Fz) + dt * vector(Gx, Gy, Gz)
</Expression>
</FieldUpdater>
Here is an example of a userFuncUpdater that uses the values of a History to perform its update (see historyFunc):
# A field updater that sets field values to the x-index of the cell
# with the (most recent) maximum value of a field, by using a History
# that finds that x-index. Of course, one could also use a History
# that calculates voltage to use as feedback.
<FieldUpdater setFieldToIndexOfMax>
kind = userFuncUpdater
lowerBounds = [0 0 0]
upperBounds = [2 2 2]
writeFields = [G]
writeComponents = [0]
<Expression updateFunction>
# Presumably the input file defines a <History max> that records
# the location of the maximum field value;
# This HistoryFunc gets the x-value of that location.
<UserFunc iOfLastMax>
kind = historyFunc
index = [0] # x-index of cell
history = max
</UserFunc>
# get (1000*) x-index of cell with most recent maximum value of field F
expression = 1000 * iOfLastMax(0)
</Expression>
</FieldUpdater>