This example illustrates how to use
FMS
to build
two systems of equations concurrently. The matrix and vector data
is generated in parallel using FMS or OpenMP.
C-----------------------------------------------------------------------
C DECLARATIONS
C-----------------------------------------------------------------------
C E X A M P L E 23
C
C FMS Parameters:
INTEGER LUPR
INTEGER MAXCPU
INTEGER MAXMD
INTEGER MDUSED
C
C Subroutines called in parallel:
EXTERNAL COLUMN
EXTERNAL RHS
C
C Name of this program:
CHARACTER*10 MYNAME
PARAMETER (MYNAME='EXAMPLE_23')
C
C Input Data functions:
LOGICAL ASK
INTEGER ASK_I
C
C Problem size parameters:
INTEGER NUMEQ1, NUMEQ2, NRHS
C
C Use OpenMP to fill matrix:
LOGICAL OMP_FILL
C
C Use OpenMP MUTEX locks:
COMMON/MYDATA/OMP_MUTEX
LOGICAL OMP_MUTEX
C
C Scale factor for input matrices to CNDAF:
COMPLEX*16 ALPHA(1)
DATA ALPHA(1)/(1.0D0,0.0D0)/
C
C Number of initialization matrices:
INTEGER NUMAI
DATA NUMAI/1/
C
C Number of submatrices:
INTEGER NUMSF
DATA NUMSF/0/
C
C Number of vectors to reduce during factoring:
INTEGER NUMRED
DATA NUMRED/0/
C
C Skip operations during solving (no):
INTEGER ISKIP
DATA ISKIP/0/
C
C Dummy Complex argument to FMSCOL:
COMPLEX*16 CDUMMY
DATA CDUMMY/(0.0D0,0.0D0)/
C
C FMS matrix and vector file attributes:
C Matrix file:
INTEGER LUA(25,2)
C Vector file:
INTEGER LUX(25,2)
C Dummy submatrix file:
INTEGER LUS(25)
C Dummy output matrix file:\
INTEGER LUA0(25)
DATA LUA0(1)/0/
C
C Data type:
INTEGER IDTYPE
C Complex*16:
PARAMETER (IDTYPE=2)
C
C FMS profile vector:
C LOWEQ(1)=-1 flags a full matrix:
INTEGER LOWEQ(1)
DATA LOWEQ/-1/
C
C Constants used for this test matrix:
COMPLEX*16 CZERO, CONE, ANSWER
PARAMETER (CZERO = (0.0D0, 0.0D0))
PARAMETER (ANSWER = (0.5D0,-0.5D0))
C
C Variables used to check answer:
REAL*8 ERROR, ETEST
C
C Local variables:
INTEGER L_X, LENX
INTEGER MDLEFT, MDINC
INTEGER LOCD
INTEGER LENVEC1, LENVEC2
C
C Work queue variables (shared):
INTEGER NXCOL, NXRHS
C
C FMS memory management requires the following arrays:
POINTER (CMD_PTR, CMD)
POINTER (RMD_PTR, RMD)
POINTER (IMD_PTR, IMD)
COMPLEX*16 CMD(0:1)
REAL*8 RMD(0:1)
INTEGER IMD(0:1)
C-----------------------------------------------------------------------
C (1) Initialize FMS:
C-----------------------------------------------------------------------
CALL FMSINI
CALL FMSPSH (MYNAME)
CALL FMSIGT ('LOGTIM', LOGTIM)
IF(LOGTIM .LT. 3) CALL FMSIST ('LOGTIM', 3)
CALL FMSIST ('IPRF' , 1026)
C Loop back to here to do next problem:
100 CONTINUE
NUMEQ1 = ASK_I('Enter the number of equations in matrix 1')
NUMEQ2 = ASK_I('Enter the number of equations in matrix 2')
NRHS = ASK_I('Enter the number of solution vectors')
OMP_FILL = ASK('Do you want to use OpenMP to generate data')
IF(OMP_FILL) THEN
C Can use OpenMP or FMS locks:
OMP_MUTEX= ASK('Do you want to use OpenMP MUTEX locks')
ELSE
C Must use FMS locks:
OMP_MUTEX = .FALSE.
END IF
WRITE (6,*) 'You may now alter any FMS parameter.'
WRITE (6,*) 'When you are finished, type the letters RETURN'
CALL FMSSET
CALL FMSIGT ('MEMPTR', CMD_PTR)
CALL FMSIGT ('LUPR', LUPR)
CALL FMSIGT ('MAXCPU', MAXCPU)
C-----------------------------------------------------------------------
C (2) Open FMS files:
C-----------------------------------------------------------------------
CALL CNDI (LOWEQ, NUMEQ1, 'Matrix1', LUA(1,1))
CALL CNDI (LOWEQ, NUMEQ2, 'Matrix2', LUA(1,2))
PRINT *,'Opening Vector file 1'
CALL FMSOV (NUMEQ1, IDTYPE, NRHS, 'Vectors1', LUX(1,1))
PRINT *,'Opening Vector file 2'
CALL FMSOV (NUMEQ2, IDTYPE, NRHS, 'Vectors2', LUX(1,2))
C-----------------------------------------------------------------------
C (3) Write data to FMS files:
C-----------------------------------------------------------------------
C
C Initialize FMSCOL for two matrices built simultaneously:
C
C Divide the remaining memory between the two matrix files:
CALL FMSIGT ('MAXMD', MAXMD)
CALL FMSIGT ('MDUSED', MDUSED)
MDLEFT = MAXMD - MDUSED
MDINC = MDLEFT/2
C Save the existing value of MAXMD:
MAXMD_S = MAXMD
C
C Initialize FMSCOL for the first file:
MAXMD = MDUSED + MDINC
CALL FMSIST ('MAXMD', MAXMD)
PRINT *,'Initializing FMSCOL for Matrix 1'
CALL FMSCOL (-1, CDUMMY, LUA(1,1))
C
C Initialize FMSCOL for the second file:
PRINT *,'Initializing FMSCOL for Matrix 2'
CALL FMSIST ('MAXMD', MAXMD_S)
CALL FMSCOL (-1, CDUMMY, LUA(1,2))
C
C Generate matrix elements in parallel
C ====================================
WRITE(LUPR,2000)
NXCOL = 0
IF(OMP_FILL) THEN
C Use OpenMP to fill in parallel:
!$OMP PARALLEL DO DEFAULT(SHARED) NUM_THREADS(MAXCPU)
DO ICPU = 1,MAXCPU
CALL COLUMN(LUA,NXCOL)
END DO
!$OMP END PARALLEL DO
ELSE
C Use FMS to fill in parallel:
C Loop over children processes:
DO ICPU = 2,MAXCPU
CALL FMSPAR (2, COLUMN, LUA, NXCOL)
END DO
C
C Start the children running:
IF(MAXCPU .GT. 1) CALL FMSRUN
C
C Do parent's part:
CALL COLUMN(LUA,NXCOL)
C
C Wait for the children to complete:
IF(MAXCPU .GT. 1) CALL FMSYNC
END IF
C
C End FMSCOL:
PRINT *,'Ending FMSCOL for Matrix 1'
CALL FMSCOL (NUMEQ1+1, CDUMMY, LUA(1,1))
PRINT *,'Ending FMSCOL for Matrix 2'
CALL FMSCOL (NUMEQ2+1, CDUMMY, LUA(1,2))
C
C Generate the RHS vectors in parallel
C ====================================
WRITE(LUPR,2001)
NXRHS = 0
IF(OMP_FILL) THEN
C Use OpenMP to fill in parallel:
!$OMP PARALLEL DO DEFAULT(SHARED) NUM_THREADS(MAXCPU)
DO ICPU = 1,MAXCPU
CALL RHS(LUX,NXRHS)
END DO
!$OMP END PARALLEL DO
ELSE
C Use FMS to fill in parallel:
C Loop over children processes:
DO ICPU = 2,MAXCPU
CALL FMSPAR (2, RHS, LUX, NXRHS)
END DO
C
C Start the children running:
IF(MAXCPU .GT. 1) CALL FMSRUN
C
C Do parent's part:
CALL RHS (LUX,NXRHS)
C
C Wait for the children to complete:
IF(MAXCPU .GT. 1) CALL FMSYNC
END IF
C-----------------------------------------------------------------------
C (4) Perform matrix algebra:
C-----------------------------------------------------------------------
CALL CNDF (LUA(1,1), ALPHA, NUMAI, LUS, NUMSF, LUA0,
1 LUA(1,1), LUX, LUX, NUMRED)
CALL CNDF (LUA(1,2), ALPHA, NUMAI, LUS, NUMSF, LUA0,
1 LUA(1,2), LUX, LUX, NUMRED)
CALL CNDS (LUA(1,1), LUX(1,1), LUX(1,1), NRHS, ISKIP)
CALL CNDS (LUA(1,2), LUX(1,2), LUX(1,2), NRHS, ISKIP)
C-----------------------------------------------------------------------
C (5) Read data from FMS files:
C-----------------------------------------------------------------------
LENVEC1 = LUX(4,1)
LENVEC2 = LUX(4,2)
IF(LENVEC1 .GT. LOENVEC2) THEN
LENX = LENVEC1/2
ELSE
LENX = LENVEC2/2
END IF
CALL FMSCMG (CMD, L_X, LENX)
C
C Check system 1:
LOCD = 1
ERROR = 0.0D0
DO IVEC = 1,NRHS
CALL FMSRED (LUX(1,1), LOCD, CMD(L_X), LENVEC1)
LOCD = LOCD + LUX(4,1)
DO I=1,NUMEQ1
ETEST = ABS( CMD(L_X + I - 1) - ANSWER )
IF(ETEST .GT. ERROR) ERROR = ETEST
END DO
END DO
PRINT *,'MAXIMUM ERROR IN SYSTEM 1=', ERROR
C
C Check system 2:
LOCD = 1
ERROR = 0.0D0
DO IVEC = 1,NRHS
CALL FMSRED (LUX(1,2), LOCD, CMD(L_X), LENVEC2)
LOCD = LOCD + LUX(4,2)
DO I=1,NUMEQ2
ETEST = ABS( CMD(L_X + I - 1) - ANSWER )
IF(ETEST .GT. ERROR) ERROR = ETEST
END DO
END DO
PRINT *,'MAXIMUM ERROR IN SYTSTEM 2=', ERROR
CALL FMSCMR (CMD, L_X, LENX)
C-----------------------------------------------------------------------
C (6) End FMS:
C-----------------------------------------------------------------------
C Do the next problem.
CALL FMSCV (LUX(1,1))
CALL FMSCV (LUX(1,2))
CALL FMSCM (LUA(1,1))
CALL FMSCM (LUA(1,2))
IF(ASK('Do you want another solution?')) GO TO 100
CALL FMSPOP (MYNAME)
CALL FMSEND
C-----------------------------------------------------------------------
C FORMAT STATEMENTS
C-----------------------------------------------------------------------
2000 FORMAT (/
1 ' Writing the Columns in parallel'/
2 ' ===============================')
2001 FORMAT (/
1 ' Writing the RHS vectors in parallel'/
2 ' ===================================')
END
C=======================================================================
SUBROUTINE COLUMN (LUA, NXCOL)
C-----------------------------------------------------------------------
C DESCRIPTION:
C This subroutine computes the matrix elements.
C It is designed to be run in parallel.
C
C FORMAL PARAMETERS:
C (R ) LUA(25,2) = Matrix file attribute lists
C
C (RW) NXCOL = Next column to process (shared)
C-----------------------------------------------------------------------
C Formal Parameters
C-----------------------------------------------------------------------
INTEGER LUA(25,2)
INTEGER NXCOL
C-----------------------------------------------------------------------
C Local Variables
C-----------------------------------------------------------------------
INTEGER MYCOL
INTEGER NUMEQ1, NUMEQ2
INTEGER L_A1, L_A2
LOGICAL IDO_1, IDO_2
INTEGER MY_TOTAL
INTEGER MYNODE, LUPR
COMPLEX*16 CZERO, DIA, OFFDIA
COMMON/MYDATA/OMP_MUTEX
LOGICAL OMP_MUTEX
DATA CZERO /( 0.0D0, 0.0D0)/
DATA DIA /( 1.0D0, 1.0D0)/
DATA OFFDIA/(-1.0D0,-1.0D0)/
CHARACTER*6 MYNAME
PARAMETER (MYNAME='COLUMN')
COMPLEX*16 CMD(0:1)
POINTER (CMD_PTR,CMD)
C-----------------------------------------------------------------------
CALL FMSPSH (MYNAME)
CALL FMSIGT ('MYNODE', MYNODE)
CALL FMSIGT ('LUPR', LUPR)
IDO_1 = .TRUE.
IDO_2 = .TRUE.
MY_TOTAL = 0
NUMEQ1 = LUA(8,1)
NUMEQ2 = LUA(8,2)
C
C Get temporary storage to hold a column:
CALL FMSIGT ('MEMPTR', CMD_PTR)
CALL FMSCMG (CMD, L_A1, NUMEQ1)
CALL FMSCMG (CMD, L_A2, NUMEQ2)
C
C Loop over columns:
100 CONTINUE
C Get your next column number:
C Critical Section
C ================
IF(OMP_MUTEX) THEN
!$OMP CRITICAL
MYCOL = INTINC(NXCOL)
!$OMP END CRITICAL
ELSE
CALL FMSONE
MYCOL = INTINC(NXCOL)
CALL FMSALL
END IF
C End of Critical Section
C =======================
IF(MYCOL .GT. NUMEQ1) IDO_1 = .FALSE.
IF(MYCOL .GT. NUMEQ2) IDO_2 = .FALSE.
IF((.NOT.IDO_1) .AND.
1 (.NOT.IDO_2) ) THEN
C This process is done.
CALL FMSCMR (CMD, L_A1, NUMEQ1)
CALL FMSCMR (CMD, L_A2, NUMEQ2)
C Report your total work:
IF(OMP_MUTEX) THEN
!$OMP CRITICAL
WRITE(LUPR,2000) MYNODE, MY_TOTAL
!$OMP END CRITICAL
ELSE
CALL FMSONE
WRITE(LUPR,2000) MYNODE, MY_TOTAL
CALL FMSALL
END IF
CALL FMSPOP (MYNAME)
RETURN
ELSE
MY_TOTAL = MY_TOTAL + 1
END IF
C
IF(IDO_1) THEN
IF(MYCOL .EQ. 1) THEN
CMD(L_A1) = DCMPLX(NUMEQ1,NUMEQ1)
DO I=2,NUMEQ1
CMD(L_A1+I-1) = OFFDIA
END DO
ELSE
CMD(L_A1) = OFFDIA
DO I=2,NUMEQ1
CMD(L_A1+I-1) = CZERO
END DO
CMD(L_A1+MYCOL-1) = DIA
END IF
CALL FMSCOL (MYCOL, CMD(L_A1), LUA(1,1))
END IF
C
IF(IDO_2) THEN
IF(MYCOL .EQ. 1) THEN
CMD(L_A2) = DCMPLX(NUMEQ2,NUMEQ2)
DO I=2,NUMEQ2
CMD(L_A2+I-1) = OFFDIA
END DO
ELSE
CMD(L_A2) = OFFDIA
DO I=2,NUMEQ2
CMD(L_A2+I-1) = CZERO
END DO
CMD(L_A2+MYCOL-1) = DIA
END IF
CALL FMSCOL (MYCOL, CMD(L_A2), LUA(1,2))
END IF
C
C Do the next column:
GO TO 100
2000 FORMAT (' Process',I3,' computed',I5,' Columns.')
END
C=======================================================================
SUBROUTINE RHS (LUX, NXRHS)
C=======================================================================
C
C DESCRIPTION:
C This subroutine computes the RHS vectors.
C It is designed to be run in parallel.
C
C FORMAL PARAMETERS:
C (R ) LUX(25,2) = FMS vector file attributes
C (RW) NXRHS = Next RHS to process (shared)
C-----------------------------------------------------------------------
C Formal Parameters:
C-----------------------------------------------------------------------
INTEGER LUX(25,2)
INTEGER NXRHS
C-----------------------------------------------------------------------
C Local Variables
C-----------------------------------------------------------------------
INTEGER MYRHS
LOGICAL IDO_1, IDO_2
INTEGER MY_TOTAL
INTEGER MYNODE, LUPR
CHARACTER*3 MYNAME
PARAMETER (MYNAME='RHS')
INTEGER NUMEQ1, NUMEQ2
INTEGER NUMVEC1, NUMVEC2
COMMON/MYDATA/OMP_MUTEX
LOGICAL OMP_MUTEX
COMPLEX*16 CZERO, CONE
DATA CZERO/(0.0D0,0.0D0)/
DATA CONE /(1.0D0,0.0D0)/
COMPLEX*16 CMD(0:1)
POINTER (CMD_PTR,CMD)
C
CALL FMSPSH (MYNAME)
CALL FMSIGT ('MYNODE', MYNODE)
CALL FMSIGT ('LUPR', LUPR)
IDO_1 = .TRUE.
IDO_2 = .TRUE.
MY_TOTAL = 0
NUMEQ1 = LUX( 3,1)
LENVEC1 = LUX( 4,1)
NUMVEC1 = LUX( 6,1)
NUMEQ2 = LUX( 3,2)
LENVEC2 = LUX( 4,2)
NUMVEC2 = LUX( 6,2)
C
C Get temporary storage to hold the longest vector record:
CALL FMSIGT ('MEMPTR', CMD_PTR)
IF(LENVEC1 .GT. LENVEC2) THEN
LENX = LENVEC1/2
ELSE
LENX = LENVEC2/2
END IF
CALL FMSCMG (CMD, L_X, LENX)
C
C Populate the vector with test data:
DO I=2,LENX
CMD(L_X+I-1) = CZERO
END DO
CMD(L_X) = CONE
C
C Loop over the RHS vectors:
100 CONTINUE
C Get your next RHS vector number:
C Critical Section
C ================
IF(OMP_MUTEX) THEN
!$OMP CRITICAL
MYRHS = INTINC(NXRHS)
!$OMP END CRITICAL
ELSE
CALL FMSONE
MYRHS = INTINC(NXRHS)
CALL FMSALL
END IF
C End of Critical Section
C =======================
IF(MYRHS .GT. NUMVEC1) IDO_1 = .FALSE.
IF(MYRHS .GT. NUMVEC2) IDO_2 = .FALSE.
IF((.NOT.IDO_1) .AND.
1 (.NOT.IDO_2) ) THEN
C This process is done.
CALL FMSCMR (CMD, L_X, LENX)
C Report your total work:
IF(OMP_MUTEX) THEN
!$OMP CRITICAL
WRITE(LUPR,2000) MYNODE, MY_TOTAL
!$OMP END CRITICAL
ELSE
CALL FMSONE
WRITE(LUPR,2000) MYNODE, MY_TOTAL
CALL FMSALL
END IF
CALL FMSPOP (MYNAME)
RETURN
ELSE
MY_TOTAL = MY_TOTAL + 1
END IF
C
IF(IDO_1) THEN
LDISK = 1 + LENVEC1*(MYRHS-1)
CALL FMSWRT (LUX(1,1), LDISK, CMD(L_X), LENVEC1)
END IF
C
IF(IDO_2) THEN
LDISK = 1 + LENVEC2*(MYRHS-1)
CALL FMSWRT (LUX(1,1), LDISK, CMD(L_X), LENVEC2)
END IF
GO TO 100
2000 FORMAT (' Process',I3,' computed',I5,' RHS vectors.')
END
C=======================================================================
INTEGER FUNCTION INTINC (I)
C-----------------------------------------------------------------------
C This function increments a volatile shared variable. It is
C placed in a subroutine to prevent some compilers from storing
C the value in a register and not updating it.
INTEGER I
I = I + 1
INTINC = I
RETURN
END
C=======================================================================
LOGICAL FUNCTION ASK(QUESTION)
C=======================================================================
CHARACTER* (*) QUESTION
CHARACTER*1 IYN
WRITE(6,2000) QUESTION
READ (5,1000) IYN
IF( (IYN .EQ. 'Y') .OR. (IYN .EQ. 'y') ) THEN
ASK = .TRUE.
ELSE
ASK = .FALSE.
END IF
RETURN
1000 FORMAT (A)
2000 FORMAT (1X,A,' (y,n)>')
END
C=======================================================================
INTEGER FUNCTION ASK_I(STRING)
C=======================================================================
CHARACTER* (*) STRING
WRITE(6,2000) STRING
READ (5,*) ASK_I
RETURN
2000 FORMAT (1X,A,'>')
END