Date: 2022-03-04T17:39:15+00:00

Actual source code: ex5f.F90

      1:       !Solves two linear systems in parallel with KSP.  The code
      2:       !illustrates repeated solution of linear systems with the same preconditioner
      3:       !method but different matrices (having the same nonzero structure).  The code
      4:       !also uses multiple profiling stages.  Input arguments are
      5:       !  -m <size> : problem size
      6:       !  -mat_nonsym : use nonsymmetric matrix (default is symmetric)

      8:       !Concepts: KSP^repeatedly solving linear systems;
      9:       !Concepts: PetscLog^profiling multiple stages of code;
     10:       !Processors: n

     12: program main
     13: #include <petsc/finclude/petscksp.h>
     14:       use petscksp

     16:       implicit none
     17:       KSP            :: ksp            ! linear solver context
     18:       Mat            :: C,Ctmp           ! matrix
     19:       Vec            :: x,u,b            ! approx solution, RHS, exact solution
     20:       PetscReal      :: norm             ! norm of solution error
     21:       PetscScalar    :: v
     22:       PetscScalar, parameter :: myNone = -1.0
     23:       PetscInt       :: Ii,JJ,ldim,low,high,iglobal,Istart,Iend
     24:       PetscErrorCode :: ierr
     25:       PetscInt       :: i,j,its,n
     26:       PetscInt       :: m = 3, orthog = 0
     27:       PetscMPIInt    :: size,rank
     28:       PetscBool :: &
     29:         testnewC         = PETSC_FALSE, &
     30:         testscaledMat    = PETSC_FALSE, &
     31:         mat_nonsymmetric = PETSC_FALSE
     32:       PetscBool      :: flg
     33:       PetscRandom    :: rctx
     34:       PetscLogStage,dimension(0:1) :: stages
     35:       character(len=PETSC_MAX_PATH_LEN) :: outputString
     36:       PetscInt,parameter :: one = 1

     38:       call PetscInitialize(PETSC_NULL_CHARACTER,ierr)
     39:       if (ierr /= 0) then
     40:         write(6,*)'Unable to initialize PETSc'
     41:         stop
     42:       endif

     44:       call PetscOptionsGetInt(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,'-orthog',orthog,flg,ierr)
     45:       CHKERRA(ierr)
     46:       call PetscOptionsGetInt(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,'-m',m,flg,ierr)
     47:       CHKERRA(ierr)
     48:       call MPI_Comm_rank(PETSC_COMM_WORLD,rank,ierr)
     49:       CHKERRA(ierr)
     50:       call MPI_Comm_size(PETSC_COMM_WORLD,size,ierr)
     51:       CHKERRA(ierr)
     52:       n=2*size

     54:       ! Set flag if we are doing a nonsymmetric problem; the default is symmetric.

     56:       call PetscOptionsGetBool(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,"-mat_nonsym",mat_nonsymmetric,flg,ierr)
     57:       CHKERRA(ierr)
     58:       call PetscOptionsGetBool(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,"-test_scaledMat",testscaledMat,flg,ierr)
     59:       CHKERRA(ierr)

     61:       ! Register two stages for separate profiling of the two linear solves.
     62:       ! Use the runtime option -log_view for a printout of performance
     63:       ! statistics at the program's conlusion.

     65:       call PetscLogStageRegister("Original Solve",stages(0),ierr)
     66:       CHKERRA(ierr)
     67:       call PetscLogStageRegister("Second Solve",stages(1),ierr)
     68:       CHKERRA(ierr)

     70:       ! -------------- Stage 0: Solve Original System ----------------------
     71:       ! Indicate to PETSc profiling that we're beginning the first stage

     73:       call PetscLogStagePush(stages(0),ierr)
     74:       CHKERRA(ierr)

     76:       ! Create parallel matrix, specifying only its global dimensions.
     77:       ! When using MatCreate(), the matrix format can be specified at
     78:       ! runtime. Also, the parallel partitioning of the matrix is
     79:       ! determined by PETSc at runtime.

     81:       call MatCreate(PETSC_COMM_WORLD,C,ierr)
     82:       CHKERRA(ierr)
     83:       call MatSetSizes(C,PETSC_DECIDE,PETSC_DECIDE,m*n,m*n,ierr)
     84:       CHKERRA(ierr)
     85:       call MatSetFromOptions(C,ierr)
     86:       CHKERRA(ierr)
     87:       call MatSetUp(C,ierr)
     88:       CHKERRA(ierr)

     90:       ! Currently, all PETSc parallel matrix formats are partitioned by
     91:       ! contiguous chunks of rows across the processors.  Determine which
     92:       ! rows of the matrix are locally owned.

     94:       call MatGetOwnershipRange(C,Istart,Iend,ierr)

     96:       ! Set matrix entries matrix in parallel.
     97:       ! - Each processor needs to insert only elements that it owns
     98:       ! locally (but any non-local elements will be sent to the
     99:       ! appropriate processor during matrix assembly).
    100:       !- Always specify global row and columns of matrix entries.

    102:       intitializeC: do Ii=Istart,Iend-1
    103:           v =-1.0; i = Ii/n; j = Ii - i*n
    104:           if (i>0) then
    105:             JJ = Ii - n
    106:             call MatSetValues(C,one,Ii,one,JJ,v,ADD_VALUES,ierr)
    107:             CHKERRA(ierr)
    108:           endif

    110:           if (i<m-1) then
    111:             JJ = Ii + n
    112:             call MatSetValues(C,one,Ii,one,JJ,v,ADD_VALUES,ierr)
    113:             CHKERRA(ierr)
    114:           endif

    116:           if (j>0) then
    117:             JJ = Ii - 1
    118:             call MatSetValues(C,one,Ii,one,JJ,v,ADD_VALUES,ierr)
    119:             CHKERRA(ierr)
    120:           endif

    122:           if (j<n-1) then
    123:             JJ = Ii + 1
    124:             call MatSetValues(C,one,Ii,one,JJ,v,ADD_VALUES,ierr)
    125:             CHKERRA(ierr)
    126:           endif

    128:           v=4.0
    129:           call MatSetValues(C,one,Ii,one,Ii,v,ADD_VALUES,ierr)
    130:           CHKERRA(ierr)

    132:       enddo intitializeC

    134:       ! Make the matrix nonsymmetric if desired
    135:       if (mat_nonsymmetric) then
    136:         do Ii=Istart,Iend-1
    137:           v=-1.5; i=Ii/n
    138:           if (i>1) then
    139:             JJ=Ii-n-1
    140:             call MatSetValues(C,one,Ii,one,JJ,v,ADD_VALUES,ierr)
    141:             CHKERRA(ierr)
    142:           endif
    143:         enddo
    144:       else
    145:         call MatSetOption(C,MAT_SYMMETRIC,PETSC_TRUE,ierr)
    146:         CHKERRA(ierr)
    147:         call MatSetOption(C,MAT_SYMMETRY_ETERNAL,PETSC_TRUE,ierr)
    148:         CHKERRA(ierr)
    149:       endif

    151:       ! Assemble matrix, using the 2-step process:
    152:       ! MatAssemblyBegin(), MatAssemblyEnd()
    153:       ! Computations can be done while messages are in transition
    154:       ! by placing code between these two statements.

    156:       call MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY,ierr)
    157:       CHKERRA(ierr)
    158:       call MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY,ierr)
    159:       CHKERRA(ierr)

    161:       ! Create parallel vectors.
    162:       ! - When using VecSetSizes(), we specify only the vector's global
    163:       !   dimension; the parallel partitioning is determined at runtime.
    164:       ! - Note: We form 1 vector from scratch and then duplicate as needed.

    166:       call  VecCreate(PETSC_COMM_WORLD,u,ierr)
    167:       call  VecSetSizes(u,PETSC_DECIDE,m*n,ierr)
    168:       call  VecSetFromOptions(u,ierr)
    169:       call  VecDuplicate(u,b,ierr)
    170:       call  VecDuplicate(b,x,ierr)

    172:       ! Currently, all parallel PETSc vectors are partitioned by
    173:       ! contiguous chunks across the processors.  Determine which
    174:       ! range of entries are locally owned.

    176:       call  VecGetOwnershipRange(x,low,high,ierr)
    177:       CHKERRA(ierr)

    179:       !Set elements within the exact solution vector in parallel.
    180:       ! - Each processor needs to insert only elements that it owns
    181:       ! locally (but any non-local entries will be sent to the
    182:       ! appropriate processor during vector assembly).
    183:       ! - Always specify global locations of vector entries.

    185:       call VecGetLocalSize(x,ldim,ierr)
    186:       CHKERRA(ierr)
    187:       do i=0,ldim-1
    188:         iglobal = i + low
    189:         v = real(i + 100*rank)
    190:         call VecSetValues(u,one,iglobal,v,INSERT_VALUES,ierr)
    191:         CHKERRA(ierr)
    192:       enddo

    194:       ! Assemble vector, using the 2-step process:
    195:       ! VecAssemblyBegin(), VecAssemblyEnd()
    196:       ! Computations can be done while messages are in transition,
    197:       ! by placing code between these two statements.

    199:       call  VecAssemblyBegin(u,ierr)
    200:       CHKERRA(ierr)
    201:       call  VecAssemblyEnd(u,ierr)
    202:       CHKERRA(ierr)

    204:       ! Compute right-hand-side vector

    206:       call  MatMult(C,u,b,ierr)

    208:       CHKERRA(ierr)

    210:       ! Create linear solver context

    212:       call  KSPCreate(PETSC_COMM_WORLD,ksp,ierr)
    213:       CHKERRA(ierr)
    214:       ! Set operators. Here the matrix that defines the linear system
    215:       ! also serves as the preconditioning matrix.

    217:       call  KSPSetOperators(ksp,C,C,ierr)
    218:       CHKERRA(ierr)
    219:       ! Set runtime options (e.g., -ksp_type <type> -pc_type <type>)

    221:       call  KSPSetFromOptions(ksp,ierr)
    222:       CHKERRA(ierr)
    223:       ! Solve linear system.  Here we explicitly call KSPSetUp() for more
    224:       ! detailed performance monitoring of certain preconditioners, such
    225:       ! as ICC and ILU.  This call is optional, as KSPSetUp() will
    226:       ! automatically be called within KSPSolve() if it hasn't been
    227:       ! called already.

    229:       call  KSPSetUp(ksp,ierr)
    230:       CHKERRA(ierr)

    232:       ! Do not do this in application code, use -ksp_gmres_modifiedgramschmidt or -ksp_gmres_modifiedgramschmidt
    233:       if (orthog .eq. 1) then
    234:          call KSPGMRESSetOrthogonalization(ksp,KSPGMRESModifiedGramSchmidtOrthogonalization,ierr)
    235:       else if (orthog .eq. 2) then
    236:          call KSPGMRESSetOrthogonalization(ksp,KSPGMRESClassicalGramSchmidtOrthogonalization,ierr)
    237:       endif
    238:       CHKERRA(ierr)

    240:       call  KSPSolve(ksp,b,x,ierr)
    241:       CHKERRA(ierr)

    243:       ! Check the error

    245:       call VecAXPY(x,myNone,u,ierr)
    246:       call VecNorm(x,NORM_2,norm,ierr)

    248:       call KSPGetIterationNumber(ksp,its,ierr)
    249:       if (.not. testscaledMat .or. norm > 1.e-7) then
    250:         write(outputString,'(a,f11.9,a,i2.2,a)') 'Norm of error ',norm,', Iterations ',its,'\n'
    251:         call PetscPrintf(PETSC_COMM_WORLD,outputString,ierr)
    252:       endif

    254:       ! -------------- Stage 1: Solve Second System ----------------------

    256:       ! Solve another linear system with the same method.  We reuse the KSP
    257:       ! context, matrix and vector data structures, and hence save the
    258:       ! overhead of creating new ones.

    260:       ! Indicate to PETSc profiling that we're concluding the first
    261:       ! stage with PetscLogStagePop(), and beginning the second stage with
    262:       ! PetscLogStagePush().

    264:       call PetscLogStagePop(ierr)
    265:       CHKERRA(ierr)
    266:       call PetscLogStagePush(stages(1),ierr)
    267:       CHKERRA(ierr)

    269:       ! Initialize all matrix entries to zero.  MatZeroEntries() retains the
    270:       ! nonzero structure of the matrix for sparse formats.

    272:       call MatZeroEntries(C,ierr)
    273:       CHKERRA(ierr)

    275:       ! Assemble matrix again.  Note that we retain the same matrix data
    276:       ! structure and the same nonzero pattern; we just change the values
    277:       ! of the matrix entries.

    279:       do i=0,m-1
    280:         do j=2*rank,2*rank+1
    281:           v =-1.0; Ii=j + n*i
    282:           if (i>0) then
    283:             JJ = Ii - n
    284:             call MatSetValues(C,one,Ii,one,JJ,v,ADD_VALUES,ierr)
    285:             CHKERRA(ierr)
    286:           endif

    288:           if (i<m-1) then
    289:             JJ = Ii + n
    290:             call MatSetValues(C,one,Ii,one,JJ,v,ADD_VALUES,ierr)
    291:             CHKERRA(ierr)
    292:           endif

    294:           if (j>0) then
    295:             JJ = Ii - 1
    296:             call MatSetValues(C,one,Ii,one,JJ,v,ADD_VALUES,ierr)
    297:             CHKERRA(ierr)
    298:           endif

    300:           if (j<n-1) then
    301:             JJ = Ii + 1
    302:             call MatSetValues(C,one,Ii,one,JJ,v,ADD_VALUES,ierr)
    303:             CHKERRA(ierr)
    304:           endif

    306:           v=6.0
    307:           call MatSetValues(C,one,Ii,one,Ii,v,ADD_VALUES,ierr)
    308:           CHKERRA(ierr)

    310:         enddo
    311:       enddo

    313:       ! Make the matrix nonsymmetric if desired

    315:       if (mat_nonsymmetric) then
    316:         do Ii=Istart,Iend-1
    317:           v=-1.5;  i=Ii/n
    318:           if (i>1) then
    319:             JJ=Ii-n-1
    320:             call MatSetValues(C,one,Ii,one,JJ,v,ADD_VALUES,ierr)
    321:             CHKERRA(ierr)
    322:           endif
    323:         enddo
    324:       endif

    326:       ! Assemble matrix, using the 2-step process:
    327:       ! MatAssemblyBegin(), MatAssemblyEnd()
    328:       ! Computations can be done while messages are in transition
    329:       ! by placing code between these two statements.

    331:       call MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY,ierr)
    332:       CHKERRA(ierr)
    333:       call MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY,ierr)
    334:       CHKERRA(ierr)

    336:       if (testscaledMat) then
    337:         ! Scale a(0,0) and a(M-1,M-1)

    339:         if (rank /= 0) then
    340:           v = 6.0*0.00001; Ii = 0; JJ = 0
    341:           call MatSetValues(C,one,Ii,one,JJ,v,INSERT_VALUES,ierr)
    342:           CHKERRA(ierr)
    343:         elseif (rank == size -1) then
    344:           v = 6.0*0.00001; Ii = m*n-1; JJ = m*n-1
    345:           call MatSetValues(C,one,Ii,one,JJ,v,INSERT_VALUES,ierr)

    347:         endif

    349:         call MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY,ierr)
    350:         call MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY,ierr)

    352:         ! Compute a new right-hand-side vector

    354:         call  VecDestroy(u,ierr)
    355:         call  VecCreate(PETSC_COMM_WORLD,u,ierr)
    356:         call  VecSetSizes(u,PETSC_DECIDE,m*n,ierr)
    357:         call  VecSetFromOptions(u,ierr)

    359:         call  PetscRandomCreate(PETSC_COMM_WORLD,rctx,ierr)
    360:         call  PetscRandomSetFromOptions(rctx,ierr)
    361:         call  VecSetRandom(u,rctx,ierr)
    362:         call  PetscRandomDestroy(rctx,ierr)
    363:         call  VecAssemblyBegin(u,ierr)
    364:         call  VecAssemblyEnd(u,ierr)

    366:       endif

    368:       call PetscOptionsGetBool(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,"-test_newMat",testnewC,flg,ierr)
    369:       CHKERRA(ierr)

    371:       if (testnewC) then
    372:       ! User may use a new matrix C with same nonzero pattern, e.g.
    373:       ! ex5 -ksp_monitor -mat_type sbaij -pc_type cholesky -pc_factor_mat_solver_type mumps -test_newMat

    375:         call  MatDuplicate(C,MAT_COPY_VALUES,Ctmp,ierr)
    376:         call  MatDestroy(C,ierr)
    377:         call  MatDuplicate(Ctmp,MAT_COPY_VALUES,C,ierr)
    378:         call  MatDestroy(Ctmp,ierr)
    379:       endif

    381:       call MatMult(C,u,b,ierr);CHKERRA(ierr)

    383:       ! Set operators. Here the matrix that defines the linear system
    384:       ! also serves as the preconditioning matrix.

    386:       call KSPSetOperators(ksp,C,C,ierr);CHKERRA(ierr)

    388:       ! Solve linear system

    390:       call  KSPSetUp(ksp,ierr); CHKERRA(ierr)
    391:       call  KSPSolve(ksp,b,x,ierr); CHKERRA(ierr)

    393:       ! Check the error

    395:       call VecAXPY(x,myNone,u,ierr); CHKERRA(ierr)
    396:       call VecNorm(x,NORM_2,norm,ierr); CHKERRA(ierr)
    397:       call KSPGetIterationNumber(ksp,its,ierr); CHKERRA(ierr)
    398:       if (.not. testscaledMat .or. norm > 1.e-7) then
    399:         write(outputString,'(a,f11.9,a,i2.2,a)') 'Norm of error ',norm,', Iterations ',its,'\n'
    400:         call PetscPrintf(PETSC_COMM_WORLD,outputString,ierr)
    401:       endif

    403:       ! Free work space.  All PETSc objects should be destroyed when they
    404:       ! are no longer needed.

    406:       call  KSPDestroy(ksp,ierr); CHKERRA(ierr)
    407:       call  VecDestroy(u,ierr); CHKERRA(ierr)
    408:       call  VecDestroy(x,ierr); CHKERRA(ierr)
    409:       call  VecDestroy(b,ierr); CHKERRA(ierr)
    410:       call  MatDestroy(C,ierr); CHKERRA(ierr)

    412:       ! Indicate to PETSc profiling that we're concluding the second stage

    414:       call PetscLogStagePop(ierr)
    415:       CHKERRA(ierr)

    417:       call PetscFinalize(ierr)

    419: !/*TEST
    420: !
    421: !   test:
    422: !      args: -pc_type jacobi -ksp_monitor_short -ksp_gmres_cgs_refinement_type refine_always
    423: !
    424: !   test:
    425: !      suffix: 2
    426: !      nsize: 2
    427: !      args: -pc_type jacobi -ksp_monitor_short -ksp_gmres_cgs_refinement_type refine_always -ksp_rtol .000001
    428: !
    429: !   test:
    430: !      suffix: 5
    431: !      nsize: 2
    432: !      args: -ksp_gmres_cgs_refinement_type refine_always -ksp_monitor draw::draw_lg -ksp_monitor_true_residual draw::draw_lg
    433: !      output_file: output/ex5f_5.out
    434: !
    435: !   test:
    436: !      suffix: asm
    437: !      nsize: 4
    438: !      args: -pc_type asm
    439: !      output_file: output/ex5f_asm.out
    440: !
    441: !   test:
    442: !      suffix: asm_baij
    443: !      nsize: 4
    444: !      args: -pc_type asm -mat_type baij
    445: !      output_file: output/ex5f_asm.out
    446: !
    447: !   test:
    448: !      suffix: redundant_0
    449: !      args: -m 1000 -pc_type redundant -pc_redundant_number 1 -redundant_ksp_type gmres -redundant_pc_type jacobi
    450: !
    451: !   test:
    452: !      suffix: redundant_1
    453: !      nsize: 5
    454: !      args: -pc_type redundant -pc_redundant_number 1 -redundant_ksp_type gmres -redundant_pc_type jacobi
    455: !
    456: !   test:
    457: !      suffix: redundant_2
    458: !      nsize: 5
    459: !      args: -pc_type redundant -pc_redundant_number 3 -redundant_ksp_type gmres -redundant_pc_type jacobi
    460: !
    461: !   test:
    462: !      suffix: redundant_3
    463: !      nsize: 5
    464: !      args: -pc_type redundant -pc_redundant_number 5 -redundant_ksp_type gmres -redundant_pc_type jacobi
    465: !
    466: !   test:
    467: !      suffix: redundant_4
    468: !      nsize: 5
    469: !      args: -pc_type redundant -pc_redundant_number 3 -redundant_ksp_type gmres -redundant_pc_type jacobi -psubcomm_type interlaced
    470: !
    471: !   test:
    472: !      suffix: superlu_dist
    473: !      nsize: 15
    474: !      requires: superlu_dist
    475: !      args: -pc_type lu -pc_factor_mat_solver_type superlu_dist -mat_superlu_dist_equil false -m 150 -mat_superlu_dist_r 3 -mat_superlu_dist_c 5 -test_scaledMat
    476: !
    477: !   test:
    478: !      suffix: superlu_dist_2
    479: !      nsize: 15
    480: !      requires: superlu_dist
    481: !      args: -pc_type lu -pc_factor_mat_solver_type superlu_dist -mat_superlu_dist_equil false -m 150 -mat_superlu_dist_r 3 -mat_superlu_dist_c 5 -test_scaledMat -mat_superlu_dist_fact SamePattern_SameRowPerm
    482: !      output_file: output/ex5f_superlu_dist.out
    483: !
    484: !   test:
    485: !      suffix: superlu_dist_3
    486: !      nsize: 15
    487: !      requires: superlu_dist
    488: !      args: -pc_type lu -pc_factor_mat_solver_type superlu_dist -mat_superlu_dist_equil false -m 500 -mat_superlu_dist_r 3 -mat_superlu_dist_c 5 -test_scaledMat -mat_superlu_dist_fact DOFACT
    489: !      output_file: output/ex5f_superlu_dist.out
    490: !
    491: !   test:
    492: !      suffix: superlu_dist_0
    493: !      nsize: 1
    494: !      requires: superlu_dist
    495: !      args: -pc_type lu -pc_factor_mat_solver_type superlu_dist -test_scaledMat
    496: !      output_file: output/ex5f_superlu_dist.out
    497: !
    498: !   test:
    499: !      suffix: orthog1
    500: !      args: -orthog 1 -ksp_view
    501: !
    502: !   test:
    503: !      suffix: orthog2
    504: !      args: -orthog 2 -ksp_view
    505: !
    506: !TEST*/

    508: end program main