### 18.9.1. Junction Box Example 1: Profile Boundary Conditions

#### 18.9.1.1. Problem Setup

A common application of User Subroutines is the specification of a profile boundary condition. In this example, experimental data has been obtained for inflow boundary values at the inlet to a domain. The simulation is that of flow over a backward facing step; the inlet profile is given some step heights upstream of the step.

The experimental data is provided in a two-dimensional table. The first column contains the wall-normal positions and the remaining five columns contain values for the u, v and w velocity components, the turbulent kinetic energy and the turbulent eddy dissipation. The table has 29 wall-normal positions and appears as follows:

    6   29
    1.01724E-01 1.01665E-04 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
    1.05172E-01 2.94293E-04 0.00000E+00 0.00000E+00 9.43200E+00 1.33962E+04
    ........... ........... ........... ........... ........... ...........
    1.94828E-01 2.94293E-04 0.00000E+00 0.00000E+00 8.94000E+00 8046000E+02
    1.98276E-01 1.01665E-04 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00

A Junction Box routine is required to read the data from the file and automatically pass it to the slave processors. The profile boundary is then set by a User CEL Function.

##### 18.9.1.1.1. Creating the Junction Box Routine and User CEL Function

In CFX-Pre, you should create a Junction Box Routine, User CEL Routine and a User CEL Function. Further information on creating these objects in CFX-Pre is available in User Functions in the CFX-Pre User's Guide.

User CEL Routine:

- Routine Name: `U profile Routine`

- Option: `User CEL Function`

- Calling Name: `user_uprofile`

- Library Name: `backstep`

- Library Path: `/home/user/Shared_Libraries`

User CEL Function:

- Function Name: `U profile`

- Option: `User Function`

- User Routine Name: `U Profile Routine`

- Argument List: `[m]`

- Result Units: `[m/s]`

Junction Box Routine:

- Routine Name: `Load Inlet Profiles`

- Option: Junction `Box Routine`

- Calling Name: `user_input`

- Library Name: `backstep`

- Library Path: `/home/user/Shared_Libraries`

- Junction Box Location: `User input`

As can be seen from this example, both routines are stored in the shared library `libbackstep.so` (the prefix and suffix may vary depending on your platform), which can be found in the `/home/user/Shared_Libraries/<architecture>` directory.

##### 18.9.1.1.2. Setting the Boundary Condition

The new User CEL Function can now be used within a boundary condition in CFX-Pre. For example, create an inlet boundary condition using the Cartesian Velocity Components option and then set:

- U = `U profile(y)`

- V = `0.00 [m s^-1]`

- W = `0.00 [m s^-1]`

##### 18.9.1.1.3. Enabling the Junction Box Routine

In order to ensure that the solver calls the declared Junction Box routine, you should:

- Go to the Solver Control panel in CFX-Pre. For details, see Basic Settings Tab in the CFX-Pre User's Guide.

- Select the Junction Box Routines box, and select the Junction Box Load Inlet Profile. For details, see Basic Settings Tab in the CFX-Pre User's Guide.

The following CCL should be added to the CCL File. You can also enter this into the Command Editor dialog box (Tools > Command Editor) in CFX-Pre and click Process.

    USER:
    	# Location of external inlet profiles.
    	Input File = /home/user/u_profile.dat
    	# Printing control. First character should be Y or N
    	User Printing = Yes
    END

The CCL parameter `USER/Input File` automatically becomes the MMS parameter `USER/INPUT_FILE`. This is used in the Fortran subroutines to read in the user data. The `User Printing` parameter becomes the MMS parameter `USER/USER_PRINTING`. This is used in the following subroutines to control printing.

#### 18.9.1.2. User Fortran Junction Box Routines

The data table is stored in an ASCII file in /home/user/backstep.user.dat. The user code to read the data from this file is implemented in a user routine shown below. The routine was developed from the template routine jcb_template.F available in `CFXROOT`/examples/.

    #include "cfx5ext.h"
    C=======================================================================
    C
    C Purpose: User Fortran for importing/interpolating external
    C          velocity profile.
    C
    C Junction Box Routines:
    C          USER_INPUT -> USER_INPUT_TABLE
    C
    C User CEL Functions:
    C          USER_UPROFILE -> USER_UPROFILE_CAL -> USER_TABINT
    C                                             -> USER_PRINT_PROFILE
    C
    C Command File data areas used:
    C          /USER/INPUT_FILE
    C          /USER/USER_PRINTING
    C
    C User Input data areas used:
    C          /USER_DATA/NCOL
    C          /USER_DATA/NLIN
    C          /USER_DATA/TABLE(NCOL,NLIN)
    C
    C=======================================================================
    dllexport(user_input)
          SUBROUTINE USER_INPUT ( CZ,DZ,IZ,LZ,RZ )
    CC
    CC --------------------
    CC        Input
    CC --------------------
    CC  none
    CC
    CC --------------------
    CC      Modified
    CC --------------------
    CC
    CC  Stacks possibly.
    CC
    CC --------------------
    CC        Output
    CC --------------------
    CC  none
    CC
    CC --------------------
    CC       Details
    CC --------------------
    CC
    CC  Load a velocity profile from filename given in /USER/INPUT_FILE.
    CC
    CC  This routine is defined with 'Junction Box Location = User Input'.
    CC  It reads data into the directory /USER_DATA.
    CC
    CC  In a parallel run, this routine is only called from the master
    CC  process, but any /USER_DATA data will then be automatically
    CC  copied to the /USER_DATA directory on all slave processes.
    CC======================================================================
    C ------------------------------
    C     Preprocessor includes
    C ------------------------------
    #include "MMS.h"
    #include "stack_point.h"
    C
    C ------------------------------
    C        Argument list
    C ------------------------------
          INTEGER IZ(*)
          CHARACTER CZ(*)*(1)
          DOUBLE PRECISION DZ(*)
          LOGICAL LZ(*)
          REAL RZ(*)
    C
    C ------------------------------
    C        Local Parameters
    C ------------------------------
    C Fortran input channel
          INTEGER NCHANNEL
          PARAMETER (NCHANNEL=59)
    C
    C ------------------------------
    C        Local Variables
    C ------------------------------
    C Result flag
          CHARACTER*4 CRESLT
    C
    C System info
          CHARACTER*(MXPNAM) WHICH_CALL
    C
    C Command file info
          CHARACTER*(MXPNAM) INPUT_FILE
          CHARACTER*(MXPNAM) USER_PRINTING
    C
          INTEGER NCOL, NLIN
    C
    C ------------------------------
    C        Stack pointers
    C ------------------------------
    C
          __stack_point__ pOINT, pTABLE
    C
    C=======================================================================
    C ---------------------------
    C    Executable Statements
    C ---------------------------
    C
    C Look up the system info for junction box calls: WHICH_CALL
          WHICH_CALL = 'Unknown'
          CALL PEEKCS( '/USER/WHICH_CALL', WHICH_CALL, 'SKIP', CRESLT, CZ )
    C
    C Look up command file info: INPUT_FILE, USER_PRINTING.
          INPUT_FILE = 'Unknown'
          CALL PEEKCS( '/USER/INPUT_FILE', INPUT_FILE, 'STOP', CRESLT, CZ )
    C
          USER_PRINTING = 'No'
          CALL PEEKCS( '/USER/USER_PRINTING', USER_PRINTING, 'SKIP',
         &            CRESLT, CZ )
    C
    C Send any diagnostic messages via master process.
          IF ( USER_PRINTING(1:1) .NE. 'N' ) THEN
             CALL MESAGE( 'WRITE', 'Start USER_INPUT')
             CALL MESAGE( 'WRITE', 'WHICH_CALL='//WHICH_CALL )
             CALL MESAGE( 'WRITE', 'INPUT_FILE='//INPUT_FILE )
          END IF
    C
    C Ensure that directory /USER_DATA exists and make this the current directory.
    C
          CALL PSHDIR( '/', 'STOP', CRESLT )
          CALL CHGDIR( 'USER_DATA', 'STOP', CRESLT )
    C
    C Read data from file.
    C
          OPEN( NCHANNEL, FILE=INPUT_FILE )
    C
    C Create space for array sizes NCOL and NLIN
          CALL MAKDAT( 'NCOL', 'INTR', 'STOP', 1, pOINT, CRESLT )
          CALL MAKDAT( 'NLIN', 'INTR', 'STOP', 1, pOINT, CRESLT )
    C
    C Read data in NCOL and NLIN
          READ ( NCHANNEL, * ) NCOL, NLIN
          CALL POKEI( 'NCOL', 1, NCOL, 'STOP', CRESLT, IZ )
          CALL POKEI( 'NLIN', 1, NLIN, 'STOP', CRESLT, IZ )
    C
    C Create space for array TABLE(NCOL,NLIN)
          CALL MAKDAT( 'TABLE', 'REAL', 'STOP', NCOL*NLIN, pTABLE, CRESLT )
    C
    C Read data into TABLE(NLIN,NCOL) located in RZ at pointer pTABLE
          CALL USER_INPUT_TABLE( NCHANNEL, RZ(pTABLE), NCOL, NLIN )
    C
          CLOSE(NCHANNEL)
    C
    C Return to current directory on entry.
    C
          CALL POPDIR( 'STOP', CRESLT )
    C
    C Send any diagnostic messages via master process.
          IF ( USER_PRINTING(1:1) .NE. 'N' ) THEN
             CALL MESAGE( 'WRITE','End USER_INPUT' )
          END IF
    C
          END
    C
    C=======================================================================
          SUBROUTINE USER_INPUT_TABLE( NCHANNEL, TABLE, NCOL, NLIN )
    C     ----------------------------------------------------------
    C Read data into TABLE(NLIN,NCOL)
    C
    C Input arguments
          INTEGER NCHANNEL, NCOL, NLIN
    C
    C Output arguments
          REAL TABLE(NCOL,NLIN)
    C
          READ( NCHANNEL, *, END=900, ERR=900 ) TABLE
          RETURN
    C
    C Error Handling via master process.
     900  CONTINUE
          CALL MESAGE( 'WRITE', 'Unexpected error/end on user file' )
          CALL CFXSTP( 'USER_INPUT_TABLE' )
          END

After the subroutine `USER_INPUT` has been executed, the directory `USER_DATA` exists and contains the following information:

- `/USER_DATA/NLIN`: number of lines in the table.

- `/USER_DATA/NCOL`: number of columns in the table.

- `/USER_DATA/TABLE`: table containing the inflow boundary profiles.

The data specified in the profile table is used to specify the inlet values for the velocity components and the turbulence quantities. Therefore, each of these quantities requires a User CEL Routine to be created. The following routine is for the first velocity component, which refers to the second column of the inflow profile table:

    C=======================================================================
    dllexport(user_uprofile)
          SUBROUTINE USER_UPROFILE (
         & NLOC, NRET, NARG, RET, ARGS, CRESLT, CZ,DZ,IZ,LZ,RZ )
    CC
    CD User routine: interpolate U profile from imported data.
    CC
    CC --------------------
    CC        Input
    CC --------------------
    CC  NLOC   - size of current locale
    CC  NRET   - number of components in result
    CC  NARG   - number of arguments in call
    CC  ARGS() - (NLOC,NARG) argument values
    CC
    CC --------------------
    CC      Modified
    CC --------------------
    CC  Stacks possibly.
    CC
    CC --------------------
    CC        Output
    CC --------------------
    CC  RET()  - (NLOC,NRET) return values
    CC  CRESLT - 'GOOD' for success
    CC
    CC --------------------
    CC       Details
    CC --------------------
    CC  An array of profiles TABLE(NCOL,NLIN) has been read from file
    CC  by junction box routine USER_INPUT. This routine now uses
    CC  the table to return U values for each y value given in the
    CC  first argument.
    CC
    CC======================================================================
    C ------------------------------
    C     Preprocessor includes
    C ------------------------------
    #include "MMS.h"
    #include "stack_point.h"
    C
    C ------------------------------
    C        Argument list
    C ------------------------------
          INTEGER NLOC,NARG,NRET
    C
          CHARACTER CRESLT*(*)
    C
          REAL ARGS(NLOC,NARG), RET(NLOC,NRET)
    C
          INTEGER IZ(*)
          CHARACTER CZ(*)*(1)
          DOUBLE PRECISION DZ(*)
          LOGICAL LZ(*)
          REAL RZ(*)
    C
    C ------------------------------
    C        Local Variables
    C ------------------------------
    C Table info
          INTEGER NCOL, NLIN
    C
    C Command file info
          CHARACTER*(MXPNAM) USER_PRINTING
    C
    C Arguments for LOCDAT call
          CHARACTER*4 CDTYPE
          INTEGER ISIZE
    C
    C ------------------------------
    C        Stack pointers
    C ------------------------------
          __stack_point__ pTABLE
    C
    C=======================================================================
    C ---------------------------
    C    Executable Statements
    C ---------------------------
    C Look up command file info: USER_PRINTING.
          USER_PRINTING = 'No'
          CALL PEEKCS( '/USER/USER_PRINTING', USER_PRINTING, 'SKIP',
         & CRESLT, CZ )
    C
    C Send any diagnostic messages via master process.
          IF ( USER_PRINTING(1:1) .NE. 'N' ) THEN
             CALL MESAGE( 'WRITE','Start USER_UPROFILE' )
          END IF
    C
    C Initialise RET() to zero.
          CALL SET_A_0( RET, NLOC*NRET )
    C
    C Find TABLE(NCOL,NLIN)
          CALL PEEKI( '/USER_DATA/NCOL', 1, NCOL, 'STOP', CRESLT, IZ )
          CALL PEEKI( '/USER_DATA/NLIN', 1, NLIN, 'STOP', CRESLT, IZ )
          CALL LOCDAT( '/USER_DATA/TABLE', CDTYPE, 'STOP', ISIZE,
         &            pTABLE, CRESLT )
    C
    C Compute profile U(N) for Y(N) using TABLE(NCOL,NLIN)
          CALL USER_UPROFILE_CAL(
         & RET, ARGS, NLOC, RZ(pTABLE), NCOL, NLIN, USER_PRINTING )
    C
    C Send any diagnostic messages via master process.
          IF ( USER_PRINTING(1:1) .NE. 'N' ) THEN
             CALL MESAGE( 'WRITE','End USER_UPROFILE' )
          END IF
    C
    C Set success flag.
          CRESLT = 'GOOD'
    C
          END
    C=======================================================================
          SUBROUTINE USER_UPROFILE_CAL(
         & U, Y, N, TABLE, NCOL, NLIN, USER_PRINTING )
    C     ---------------------------------------------
    C Compute profile U(N) for Y(N) using TABLE(NCOL,NLIN)
    C-----------------------
    C 	Input arguments
    C-----------------------
    C number of points
          INTEGER N
    C
    C y coordinate
          REAL Y(N)
    C
    C input table
    C Y values are in the first column of the table.
    C U values are in the second column of the table.
          INTEGER NCOL, NLIN
          REAL TABLE(NCOL,NLIN)
    C
    C printing control
          CHARACTER*(*) USER_PRINTING
    C--------------------------
    C 	Output arguments
    C--------------------------
          REAL U(N)
    C----------------------
    C	 Locals
    C----------------------
          INTEGER I
    C
          DO I = 1, N
    C
    C interpolate U(I) for Y(I)
          CALL USER_TABINT( Y(I), U(I), 1, 2, TABLE, NCOL, NLIN )
    C
    C print I, U(I), Y(I)
    C note that this data is unstructured, not ordered by Y value.
    C
          IF ( USER_PRINTING(1:1) .NE. 'N' ) THEN
             CALL USER_PRINT_PROFILE( I, Y(I), U(I) )
          END IF
    C
          END DO
    C
          END
    C=======================================================================
          SUBROUTINE USER_TABINT( X, Y, IX, IY, TABLE, NCOL, NLIN )
    C     ---------------------------------------------------------
    C Linear interpolation of table data Y in column IY of TABLE(),
    C against an increasing co-ordinate X in column IX of TABLE().
    C---------------
    C	 Inputs:
    C---------------
          REAL X
          INTEGER IX, IY
          INTEGER NCOL, NLIN
          REAL TABLE(NCOL,NLIN)
    C---------------
    C	Outputs:
    C---------------
          REAL Y
    C---------------
    C	Locals:
    C---------------
          INTEGER I, J
          REAL S
    C
    C Find J such that TABLE(IX,J) <= X < TABLE(IX,J+1)
          J = 0
          DO I = 1, NLIN
             IF ( TABLE(IX,I) .GT. X ) GO TO 100
             J = I
          END DO
     100  CONTINUE
    C
    C Linearly interpolate Y
          IF( J .LE. 0 ) THEN
             Y = TABLE(IY,1)
          ELSE IF ( J .GE. NLIN ) THEN
             Y = TABLE(IY,NLIN)
          ELSE
             S = (X-TABLE(IX,J))/(TABLE(IX,J+1)-TABLE(IX,J))
             Y = TABLE(IY,J)*(1.0-S) + TABLE(IY,J+1)*S
          END IF
          END
    C
    C=======================================================================
          SUBROUTINE USER_PRINT_PROFILE( I, Y, U )
    C     ----------------------------------------
    C Print (I, Y, U) via master process.
    C
          INTEGER I
          REAL Y, U
    C
          CHARACTER CFROMI*5, CFROMR*15
          EXTERNAL CFROMI, CFROMR
    C
          CALL MESAGE( 'BUFF-ASIS', CFROMI(I) )
          CALL MESAGE( 'BUFF-ASIS', ' Y(I) = ' )
          CALL MESAGE( 'BUFF-ASIS', CFROMR(Y) )
          CALL MESAGE( 'BUFF-ASIS', ' U(I) = ' )
          CALL MESAGE( 'BUFF-ASIS', CFROMR(U) )
          CALL MESAGE( 'BUFF-OUT', ' ' )
          END

Release 18.2 - © ANSYS, Inc. All rights reserved.