DIFSUB

The DIFSUB evaluation subroutine computes a differential-equation value for a DIFF statement (C++ or FORTRAN). DIFSUB is optional. You only need it if you don't want to use a function expression in the DIFF statement.
 
Note:  
Use mixed case names for the Adams subroutine names when using the C style interface. For the default subroutine name capitalize the first letter and have the remaining letters lower case; Difsub for example. Doing this ensures that Adams Solver correctly distinguishes a C style subroutine from Fortran and calls with the appropriate interface.

Use

Corresponding Statement

Calling Sequence

SUBROUTINE DIFSUB (id, time, par, npar, dflag,  iflag, value)

Input Arguments

 
dflag
A logical variable that Adams Solver sets to true when it calls DIFSUB to evaluate partial derivatives of the function. Otherwise, Adams Solver sets dflag to false.
id
An integer variable that provides the identifier of the DIFF statement requesting information from the DIFSUB. From the identifier, Adams Solver automatically knows other information (such as the par argument) available in the corresponding statement.
iflag
An integer variable that Adams Solver sets to indicate why the routine is being called:
Adams Solver sets iflag to 3 when it needs the functional dependency of the user-defined variable. The functional dependencies are set with the same calls to the SYSARY and SYSFNC utility subroutines that are made to compute the value of the user-defined variable. If iflag is 0, Adams Solver computes the value of the user-written variable.
When your user-defined subroutine has static data that needs to be saved and restored to support the Adams Solver commands Save and Reload, then call the serialization functions for your data when iflag is set to 7, and the un-serialization functions when iflag is set to 9.
Note: In simple subroutines where serializing data is not needed, you can declare iflag as a logical variable. In this case you declare your dependencies when Adams Solver sets iflag to true, and compute the subroutine's value when Adams Solver sets iflag to false.
npar
An integer variable that indicates the number of constants specified in the USER parenthetical list. The primary purpose of npar is to provide the DIFSUB evaluation subroutine with the number of values stored in the par array.
par
A double-precision array of constants taken in order from the USER parenthetical list of the DIFF statement.
time
A double-precision variable through which Adams Solver conveys the current simulation time.

Output Argument

 
value
A double-precision variable that returns the value of the differential equation. If the equation is in the explicit form, value contains the derivative. If the equation is in the implicit form, value contains the residual (that is, the error relative to zero) of the implicit equation. In this case, value can be a function of the dependent variable and its time derivative.

Extended Definition

A DIFF statement with a function expression is sufficient for defining most user-defined differential equations. However, if the expression becomes lengthy and awkward or if the definition of the equation requires additional features of FORTRAN-77, you should use the FUNCTION=USER() argument in the DIFF statement, and write a DIFSUB evaluation subroutine to define the differential equation.
DIFSUB allows you to define a differential equation for a variable either explicitly or implicitly:
In an explicit definition, the derivative of the variable is evaluated on the right side of a FORTRAN-77 assignment statement.
In an implicit definition, the right side of the statement is zero.
For further information on implicit and explicit definitions, see the DIFF statement (C++ or FORTRAN).
You can call utility subroutines, such as AKISPL, CUBSPL, SYSARY, and SYSFNC, from DIFSUB to obtain information about system variables, other user-defined variables, and splines.
The SYSARY and SYSFNC utility subroutines automatically set functional dependencies when the DIFSUB argument iflag is not zero. In order for Adams Solver to compute solutions efficiently, it must know on which other variables each user-defined variable directly depends. Adams Solver determines these functional dependencies at the beginning of the simulation by calling a DIFSUB evaluation subroutine with argument iflag set to not zero. Adams Solver does this once for each DIFF statement with a FUNCTION=USER() argument. During each call to the DIFSUB evaluation subroutine, Adams Solver records which calls you make to SYSARY and SYSFNC. Adams Solver assumes that the user-defined variable depends on those system and user-defined variables, and no others.
 
Tip:  
If the SYSARY or SYSFNC utility subroutine is called to access angular displacements, the values returned by DIFSUB may contain discontinuities. These discontinuities occur if there is a Euler singularity. To avoid the Euler singularity (and thus the discontinuities), use the RCNVRT utility subroutine to convert the rotational angles from Euler angles to some other coordinate system that does not encounter a singularity.

If the calculations always use the same SYSARY and SYSFNC calls through the whole simulation, and you have no initialization to do, you do not need to check the iflag argument at all. You can just call SYSARY and/or SYSFNC, compute the user-defined variable value, and return to Adams Solver.
 
Caution:  
When the iflag argument is not zero, be sure to make all the same calls to the SYSARY and SYSFNC utility subroutines that are done when actually computing the value of the user-defined variable. This ensures that Adams Solver has the proper functional dependencies. In general, failure to account for dependencies of the user-defined variables might make it difficult for Adams Solver to converge to a solution, and/or might force Adams Solver to take small integration steps, potentially causing large increases in execution time.
When the iflag argument is not zero, SYSARY and SYSFNC return zero values for system and user-defined variables. Computations that divide by these values result in system errors when Adams Solver is executed. Be sure to check for nonzero values, or the iflag argument set to zero, before dividing by these values.

FORTRAN - Prototype

A sample structure for DIFSUB is shown next. The comments explain how the subroutine works.
     SUBROUTINE DIFSUB ( ID, TIME, PAR, NPAR, DFLAG,
    &                    IFLAG, VALUE )
C
C === Type and dimension statements ==================
C
C - External variable definitions ---------
C
     INTEGER                     ID
     DOUBLE PRECISION            TIME
     DOUBLE PRECISION            PAR( * )
     INTEGER                     NPAR
     LOGICAL                     DFLAG
     INTEGER                     IFLAG
     DOUBLE PRECISION            VALUE
C
C ID      Identifier of calling DIFF statement
C TIME     Current time
C PAR      Array containing passed parameters
C NPAR     Number of passed parameters
C DFLAG    Differencing flag
C IFLAG    Initialization pass flag
C VALUE    Computed value of DIFF returned to ADAMS
C
C - Local variables and parameters definitions ---
C
     ...
C
C === Executable code ================================
C
C Assign readable variable names to passed parameters
C
     ...
C
C Call SYSFNC and/or SYSARY to collect information for
C the following calculations. Note: if IFLAG is
C true, these calls are actually setting
C functional dependencies.
C      CALL SYSFNC ( ... )
C
C Check SYSFNC call through ERRMES utility routine
C
     CALL ERRMES ( ... )
C
C Repeat for all required SYSFNC or SYSARY calls
C
     ...
C
     IF ( IFLAG ) THEN
C
C - Subroutine initialization -----------
C
     ...
C
     ENDIF
C
C - Evaluate differential equation ---------
C
C Your algorithms
C
     ...
C
C Assign a value to the variable VALUE
C
     VALUE = ...
C
     RETURN
     END

C Style - Prototype

typedef void adams_c_DIFSUB(const struct sAdamsDiff* diff, double TIME, int DFLAG, int IFLAG, double* RESULT);
 
struct sAdamsDiff
{
int ID;
int NPAR;
const double* PAR;
int STATIC_HOLD;
int IMPLICIT;
double IC_R1;
double IC_R2;
};
 

Examples

For an example of this subroutine, see difsub.f