userFuncUpdater

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).

userFuncUpdater Parameters

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:
The simulation time (actually, the time to which the updater been told to update its writeFields; c.f. toDtFrac in a MultiField UpdateStep).
dt:
The most recent time step (\(\Delta t\)).
n:
The current simulation step (an integer).

(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.

userFuncUpdater Examples

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>