Function Format

A user-defined function has the following form (in C).

#include "acusim.h"
#include "udf.h"
UDF_PROTOTYPE(usrFunc) ;
Void usrFunc (
         UdfHd   udfHd, /* Opaque handle for accessing data  */
         Real*   outVec, /* Output vector                     */
         Integer nItems, /* Number of items in outVec         */
         Integer vecDim /* Vector dimension of outVec        */
 ) {
         ...
         outVec[0] = ... ;
 } /* end of usrFunc() */
The header file acusim.h defines the standard C header file, such as stdio.h and stdarg.h. In addition, the data types used by AcuSolve are defined. The relevant types are:
Integer
Type integer
Real
Type floating point
String
Type string
Void
Type void
The header file udf.h contains the definitions and declarations needed by the user function:
  • The definitions of symbolic constants, such as UDF_VISCOSITY and UDF_ELM_VELOCITY. These constants are used to access data.
  • The prototypes of support routines
  • The macro UDF_PROTOTYPE(), which may be used to prototype the user function

In addition, it contains the useful macros min(a,b), max(a,b), and abs(a) for the computation of minimum, maximum, and absolute value of integers or floating point numbers.

The user-function name (generically called usrFunc above) may be any name supported in C that starts with the letters usr. This naming convention avoids any potential conflict in function name space.

Four arguments are passed to a user-defined function:
Table 1.
  • udfHd:
This is an opaque handle (pointer) which contains the necessary information for accessing various data. All supporting routines require this argument. For example, to access the current time step pass udfHd to the function udfGetTimeStep(), as in:
Integer time_step ;
...
time_step = udfGetTimeStep( udfHd ) ;
  • outVec:
This is the resulting vector of the user function. You must fill this vector before returning. On input this array contains all zeros.
  • nItems:
This is the first dimension of outVec, which specifies the number of items that needs to be filled. The value of this parameter depends on command category. In particular:
Table 1.
Command Category nItems Definition
Multiplier Function 1
Mesh Motion 1
Body Force Number of Elements
Material Model Number of Elements
Component Model Number of Elements
Element Output Number of Elements
Element Boundary Condition Number of Surfaces
Nodal Boundary Condition Number of Nodes
Periodic Boundary Condition Number of Nodal Pairs

where the "Number of Elements" is the number of elements in a block, "Number of Nodes" is the number of nodes in a block, "Number of Surfaces" is the number of surfaces in a block, and "Number of Nodal Pairs" is the number of pairs of nodes in a block.

  • vecDim:
This is the second dimension of outVec, which specifies the vector dimension of the particular data. The value of this parameter also depends on command category. In particular:
Table 2.
Command Category vecDim Definition
Multiplier Function 1
Mesh Motion 12
Body Force (gravity) 3
Body Force (other) 1
Material Model 1
Component Model 1
Element Output 1
Element Boundary Condition (tangential_traction) 3
Element Boundary Condition (Other) 1
Nodal Boundary Condition 1
Periodic Boundary Condition 1
Note that the fastest dimension of outVec is nItems, and not vecDim. For example, to fill in a constant gravity given via user values, you may write the following code:
#include "acusim.h"
#include "udf.h"
UDF_PROTOTYPE(usrGrav) ;
Void usrGrav (
         UdfHd   udfHd, /* Opaque handle for accessing data  */
         Real*   outVec, /* Output vector                     */
         Integer nItems, /* Number of items in outVec         */
         Integer vecDim /* Vector dimension of outVec        */
 ) {
         Integer dir ; /* a running direction index         */
         Integer elem ; /* a running element index           */
         Real*   usrVals ; /* user values                       */
         udfCheckNumUsrVals( udfHd, 3 ) ; /* check for error   */
         usrVals = udfGetUsrVals( udfHd ) ; /* get the user vals */
         for ( dir = 0 ; dir < vecDim ; dir++ ) {
               for ( elem = 0 ; elem < nItems ; elem++ ) {
                   outVec[elem+dir*nItems] = usrVals[dir] ;
               }
          }
} /* end of usrGrav() */
The corresponding input file command may be:
GRAVITY( "my gravity" ) {
             type = user_function
             user_function = "usrGrav"
             user_values = { 0, 0, -9.81 }
}
AcuSolve only accesses user-defined functions that are written in C. To write a user-function in Fortran, you must write a C cover function via which Fortran routine(s) are called. This cover function is accessed by AcuSolve. For the above example the C file may contain:
#include "acusim.h"
#include "udf.h"
UDF_PROTOTYPE(usrGrav) ;
#define usrGravF usrgravf_          /* FORTRAN name conversion           */
Void usrGrav (
         UdfHd   udfHd,             /* Opaque handle for accessing data  */
         Real*   outVec,            /* Output vector                     */
         Integer nItems,            /* Number of items in outVec         */
         Integer vecDim             /* Vector dimension of outVec        */
) {
         Real*   usrVals ;          /* user values                        */
         udfCheckNumUsrVals( udfHd, 3 ) ; /* check for error               */
         usrVals = udfGetUsrVals( udfHd ) ; /* get the user vals           */
         usrGravF( outVec, usrVals, &nItems ) ;
} /* end of usrGrav() */
While the Fortran file may contain:
         subroutine usrGravF ( grav, usrVals, nElems )
         integer nElems
         real*8 grav (nElems, 3), usrVals (3)
         integer i, j
c
c ...   fill in the vector
c
           do j = 1, 3
              do i = 1, nElems
                 grav(i,j) = usrVals (j)
              enddo
            enddo
c
c         return
c
              return
              end

Note that you are responsible for Fortran/C name conversion.