19.8.2. User CEL Example 2: Using Gradients for an Additional Variable Source

For some applications, the source terms for the transport equations might depend on local gradients. Gradients can be accessed directly within CEL. However, gradients of most variables can also be accessed in CEL expressions through the use of user CEL functions. This is achieved by calling the utility USER_GETVAR with the ‘Gradient’ operator attached to the variable name.

The following example shows the use of a source term that depends on the gradients of one Additional Variable, , in the transport equation of another Additional Variable, .

(19–1)

(19–2)

For this demonstration density is constant, the flow is uniform and is a simple algebraic variable:

(19–3)

so that the solution along a streamline can be trivially verified as:

(19–4)

where is the distance from the inlet and is the flow speed.

A user CEL function is given the coefficient as an argument and computes the whole of the source term, . The variables and have dimensions of length, so their gradients are therefore dimensionless. The coefficient has the same dimensions as the source term, which are those of density times velocity.

19.8.2.1. Problem Setup

19.8.2.1.1. Creating the Additional Variables

Before creating a domain, define two Additional Variables:

  • Create an Additional Variable called phi1 of Type Unspecified with Units of [m]

  • Create an Additional Variable called phi2 of Type Specific with Units of [m]

19.8.2.1.2. Creating the Domain

Create a domain that includes both Additional Variables phi1 and phi2:

  • Declare phi1 of Type Algebraic, and type in the expression to define it

  • Declare phi2 of Type Transport Equation. Do not set a Kinematic Diffusivity

Create a domain that includes both Additional Variables, solved using a transport equation. Do not set a kinematic diffusivity.

19.8.2.1.3. Creating the User CEL Routine and Function

In CFX-Pre, you should create a User Routine and then a User Function. For details, see User Routine Details View in the CFX-Pre User's Guide. Additional information on creating a User CEL Function in CFX-Pre is available; for details, see User Functions in the CFX-Pre User's Guide.

The User Routine takes the following form:

  • Routine Name: UserSource2Routine

  • Option: User CEL Function

  • Calling Name: user_source2

  • Library Name: AdVarSource

  • Library Path: /home/cfxuser/shared_libraries

and the User Function is set up as follows:

  • Function Name: UserSource2

  • Option: User Function

  • User Routine Name: UserSource2Routine

  • Argument List: [kg m^-2 s^-1]

  • Result Units: [kg m^-2 s^-1]

In this example, the user subroutine AdVarSource.F is stored in the shared library libAdVarSource.so (the prefix and suffix may vary depending on your platform), which can be found under the /home/cfxuser/shared_libraries/<architecture> directory.

19.8.2.1.4. Defining the Source Term

The new User CEL Function can now be used to set the Additional Variable source within the subdomain as follows:

  • Create a subdomain and set the Additional Variable Source Value as: UserSource2(1000 [kg m^-2 s^-1]).

This is accessed from the Subdomain Sources form. For details, see Sources Tab in the CFX-Pre User's Guide.

The coefficient a in the nonlinear source term has been set to a constant value of 1000 [kg m^-2 s^-1].

19.8.2.2. User Fortran Routine

The subroutine was developed from the template routine ucf_template.F available in <CFXROOT>/examples/. Note that some commented sections of the routine have not been included here. This routine contains a call to USER_GETVAR to access variable data. For details, see Utility Routines for User Functions. Note that USER_GETVAR requires the fluid prefix for user-supplied variable names. For a one-off application it is possible simply to call USER_GETVAR with an assumed name for the working fluid, for example, for a single phase problem using "Water":

      CALL USER_GETVAR (‘Water,phi1.Gradient’, CRESLT, pGRAD_PHI,
     &                   CZ,DZ,IZ,LZ,RZ)

However, to make it applicable in general, the example given here uses USER_ASSEMBLE_INFO to extract the equation and principal names, and GET_PHASE_FROM_VAR followed by CONVERT_NAME_S2U to extract the user’s phase name. Hence, it works on any problem, independently of the choice of fluids.

The routine AdVarSource.F has the following form:

#include "cfx5ext.h"
dllexport(user_source2)
      SUBROUTINE USER_SOURCE2 (
     & NLOC,NRET,NARG,RET,ARGS,CRESLT,CZ,DZ,IZ,LZ,RZ)
C--------------------
C       Details
C --------------------
C  ARGS(1:NLOC,1) holds parameter ’a’ evaluated at all locations
C  RET(1:NLOC,1)  will hold return result
C ------------------------------
C     Preprocessor includes
C ------------------------------
#include "MMS.h"
#include "stack_point.h"
C ------------------------------
C        Argument list
C ------------------------------
      INTEGER NLOC,NARG,NRET
      CHARACTER CRESLT*(*)
      REAL ARGS(NLOC,NARG), RET(NLOC,NRET)
      INTEGER IZ(*)
      CHARACTER CZ(*)*(1)
      DOUBLE PRECISION DZ(*)
      LOGICAL LZ(*)
      REAL RZ(*)
C ------------------------------
C        External routines
C ------------------------------
      INTEGER LENACT
      EXTERNAL LENACT
C ------------------------------
C        Local Variables
C ------------------------------
      CHARACTER*(MXDNAM) ACTION,CGROUP,CEQN,CTERM,CPVAR,
     & CLVAR,CPATCH,CRESLOC,CPHASE
      CHARACTER*120 User_Phase_Name, User_Variable_Name
C ------------------------------
C        Stack pointers
C ------------------------------
      __stack_point__ pGRAD_PHI
C ---------------------------
C    Executable Statements
C ---------------------------
C  Initialise success flag.
      CRESLT = 'GOOD'
C  Initialise RET to zero.
      CALL SET_A_0 ( RET, NLOC*NRET )
C
C---- Determine user’s phase name for use in USER_GETVAR
C
C  Use USER_ASSEMBLE_INFO to determine solver equation and principal
C  variable names CEQN, CPVAR.
      ACTION = 'GET'
      CALL USER_ASSEMBLE_INFO (ACTION,CGROUP,CEQN,CTERM,CPVAR,
     &  CLVAR,CPATCH,CRESLOC,
     & CZ,DZ,IZ,LZ,RZ)
      IF (CRESLOC.NE.'GOOD' .AND. CRESLOC.NE.'SOME') THEN
         CRESLT = 'FAIL'
         GO TO 999
      ENDIF
C  Extract phase name from principal variable
      CALL GET_PHASE_FROM_VAR (CPVAR, CPHASE)
C  Convert solver phase name to user phase name.
      CALL CONVERT_NAME_S2U('Phase',CPHASE,' ',User_Phase_Name,
     & CRESLT, CZ,DZ,IZ,LZ,RZ)
      IF (CRESLT .NE. 'GOOD') GO TO 999
C
C---- Obtain grad(phi1)
C     in array shape GRAD_PHI(1:3,1:NLOC) located at RZ(pGRAD_PHI)
C
      User_Variable_Name = User_Phase_Name(1:LENACT(User_Phase_Name))
     & // '.phi1.Gradient'
      CALL USER_GETVAR (User_Variable_Name, CRESLT, pGRAD_PHI,
     & CZ,DZ,IZ,LZ,RZ)
      IF (CRESLT .NE. 'GOOD') GO TO 999
C
C---- Calculate source expression in RET(1:NLOC,1)
C
      CALL USER_SOURCE_CAL( RET(1,1), ARGS(1,1), RZ(pGRAD_PHI), NLOC )
C
  999 CONTINUE
C
C  Send any diagnostics or stop requests via leader processor
      IF (CRESLT .NE. 'GOOD') THEN
         CALL MESAGE( 'BUFF', 'USER_SOURCE2 returned error:' )
         CALL MESAGE( 'BUFF', CRESLT )
         CALL MESAGE( 'BUFF-OUT', ' ' )
      END IF
C
C=======================================================================
      END
      SUBROUTINE USER_SOURCE_CAL (SOURCE, A, GRAD_PHI, NLOC)
C
C  Purpose: Source = a * grad(phi).grad(phi)
C
C  Inputs
      INTEGER NLOC
      REAL A(NLOC), GRAD_PHI(3,NLOC)
C  Outputs
      REAL SOURCE(NLOC)
C  Locals
      INTEGER ILOC
C
      DO ILOC = 1, NLOC
          SOURCE(ILOC) = A(ILOC) * ( GRAD_PHI(1,ILOC)**2
     &     + GRAD_PHI(2,ILOC)**2
     &     + GRAD_PHI(3,ILOC)**2 )
      END DO
C
      END