Function Format
An AcuTrace user-defined function has the following form (in C).
#include "acusim.h"
#include "ufp.h"
UFP_PROTOTYPE(usrFunc);
Void usrFunc (
UfpHd ufpHd, /* 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() */
Note:
- The order of the arguments is slightly different than the order in an AcuSolve user-defined function.
- The first argument is "ufpHd" not "udfHd".
- The header file "ufp.h" is included, not "udf.h".
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 AcuTrace are defined. The relevant types
are:
- Integer
- type integer
- Real
- type floating point
- String
- type string
- Void
- type void
The header file "ufp.h" contains the definitions and declarations needed by
the user function:
- The definitions of symbolic constants, such as UFP_PARTICLE_MARKER and UFP_PARTICLE_ID. These constants are used to access data.
- The prototypes of support routines
- The macro UFP_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:
- ufpHd
- 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 pass ufpHd to the
function ufpGetTime(), as in:
Real time ; ... time = ufpGetTime( ufpHd ) ;
- 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.
- vecDim
- This is the second dimension of outVec, which specifies the vector dimension of the particular data.
The following example computes the source term in an evolution equation for particle
energy:
#include "acusim.h"
#include "ufp.h"
UFP_PROTOTYPE(usrEnergy);
Void usrEnergy (
UfpHd ufpHd, /* 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 */
Real* t_fluid ; /* fluid temperature */
Real* h_particle ; /* particle energy */
Real mpXcp ; /* mass * c_p for particle */
Real cond ; /* conductivity */
Real* jac ; /* source jacobian */
usrVals = ufpGetUsrVals( ufpHd ) ;
cond = usrVals[0] ;
mpXcp = usrVals[1] ;
t_fluid = ufpGetFlowData( ufpHd,UFP_FLOW_TEMPERATURE ) ;
h_particle = ufpGetUdfData( ufpHd, 0 ) ;
outVec[0] = -cond * ( h_particle[0] / mpXcp - t_fluid [0] ) ;
jac = ufpGetJac( ufpHd, UFP_JAC_UDF_VARIABLES ) ;
jac[0] = -cond / mpXcp ;
}
AcuTrace 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 AcuTrace. For the
above example the C file could be rewritten
as:
#include "acusim.h"
#include "ufp.h"
UFP_PROTOTYPE(usrEnergy);
Void usrEnergy (
UfpHd ufpHd, /* Opaque handle for accessing data */
Real* outVec, /* Vector dimension of outVec */
Integer nItems, /* Number of items in outVec */
Integer vecDim, /* Vector dimension of outVec */
)
{
Real* usrVals ; /* user values */
Real* t_fluid ; /* fluid temperature */
Real* h_particle ; /* particle energy */
Real* jac ; /* source jacobian */
usrVals = ufpGetUsrVals( ufpHd ) ;
t_fluid = ufpGetFlowData( ufpHd, UFP_FLOW_TEMPERATURE ) ;
h_particle = ufpGetUdfData( ufpHd, 0 ) ;
jac = ufpGetJac( ufpHd, UFP_JAC_UDF_VARIABLES ) ;
usrEnergyF( usrVals, t_fluid, h_particle, jac, outVec ) ;
}
while the Fortran file may
contain:
subroutine usrEnergyF ( usrVals, t_fluid, h_particle, jac, outVec )
real*8 usrVals(2), t_fluid, h_particle, jac, outVec
real*8 cond, mpXcp
cond = usrVals(1)
mpXcp = usrVals(2)
outVec = -cond * ( h_particle / mpXcp – tFluid )
jac = -cond / mpXcp
return
end
Note: You are responsible for Fortran/C name conversion.
The fastest dimension of outVec is nItems, and not
vecDim. For example, to fill outVec with
the flow velocity at the location of particle, you can write the following
code:
#include "acusim.h"
#include "ufp.h"
UFP_PROTOTYPE(usrVel);
Void usrVel (
UfpHd ufpHd, /* Opaque handle for accessing data */
Real* outVec, /* Output Vector */
Integer nItems, /* Number of items in outVec */
Integer vecDim /* Vector dimension of outVec */
)
{
Real *data ;
Integer dir, item ;
if ( vecDim != 3 ) {
printf( "vecDim = %d, but must equal 3 instead\n", vecDim ) ;
exit( 0 ) ;
}
data = ufpGetFlowData( ufpHd, UFP_FLOW_VELOCITY ) ;
for ( dir = 0 ; dir < 3 ; dir++ ) {
for ( item = 0 ; item < nItems; item++ ) {
outVec[item+dir*nItems] = data[dir] ;
}
}
}
In the current uses of AcuTrace user defined functions, nItems always equals 1.