Actual source code: ex1f.F90

  1: !    Description: A star forest is a simple tree with one root and zero or more leaves.
  2: !    Many common communication patterns can be expressed as updates of rootdata using leafdata and vice-versa.
  3: !     This example creates a star forest, communicates values using the graph  views the graph, then destroys it.
  4: !
  5: !     This is a copy of ex1.c but currently only tests the broadcast operation
  6: #include <petsc/finclude/petscvec.h>
  7: program main
  8:   use petscvec
  9:   implicit none

 11:   PetscErrorCode ierr
 12:   PetscInt i, nroots, nrootsalloc, nleaves, nleavesalloc, mine(6)
 13:   PetscInt, parameter :: stride = 2
 14:   PetscSFNode remote(6)
 15:   PetscMPIInt rank, size
 16:   PetscSF sf
 17:   PetscInt rootdata(6), leafdata(6)
 18:   PetscBool rootbool(6), leafbool(6)

 20: ! used with PetscSFGetGraph()
 21:   PetscSFNode, pointer ::       gremote(:)
 22:   PetscInt, pointer ::          gmine(:)
 23:   PetscInt gnroots, gnleaves

 25:   PetscMPIInt niranks, nranks
 26:   PetscMPIInt, pointer ::       iranks(:), ranks(:)
 27:   PetscInt, pointer ::          ioffset(:), irootloc(:), roffset(:), rmine(:), rremote(:)

 29:   PetscCallA(PetscInitialize(ierr))
 30:   PetscCallMPIA(MPI_Comm_rank(PETSC_COMM_WORLD, rank, ierr))
 31:   PetscCallMPIA(MPI_Comm_size(PETSC_COMM_WORLD, size, ierr))

 33:   nroots = merge(3, 2, rank == 0)
 34:   nrootsalloc = nroots*stride
 35:   nleaves = merge(2, 3, rank == 0)
 36:   nleavesalloc = nleaves*stride

 38:   do i = 1, nleaves
 39:     mine(i) = stride*(i - 1)
 40:   end do

 42: ! Left periodic neighbor
 43:   remote(1)%rank = modulo(rank + size - 1, size)
 44:   remote(1)%index = 1*stride
 45: ! Right periodic neighbor
 46:   remote(2)%rank = modulo(rank + 1, size)
 47:   remote(2)%index = 0*stride
 48:   if (rank > 0) then !               All processes reference rank 0, index
 49:     remote(3)%rank = 0
 50:     remote(3)%index = 2*stride
 51:   end if

 53: ! Create a star forest for communication
 54:   PetscCallA(PetscSFCreate(PETSC_COMM_WORLD, sf, ierr))
 55:   PetscCallA(PetscSFSetFromOptions(sf, ierr))
 56:   PetscCallA(PetscSFSetGraph(sf, nrootsalloc, nleaves, mine, PETSC_COPY_VALUES, remote, PETSC_COPY_VALUES, ierr))
 57:   PetscCallA(PetscSFSetUp(sf, ierr))

 59: ! View graph, mostly useful for debugging purposes.
 60:   PetscCallA(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL, ierr))
 61:   PetscCallA(PetscSFView(sf, PETSC_VIEWER_STDOUT_WORLD, ierr))
 62:   PetscCallA(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD, ierr))

 64: ! Allocate space for send and receive buffers. This example communicates PetscInt, but other types, including
 65: !   * user-defined structures, could also be used.
 66: ! Set rootdata buffer to be broadcast
 67:   rootdata(1:nrootsalloc) = -1
 68:   do i = 1, nroots
 69:     rootdata(1 + (i - 1)*stride) = 100*(rank + 1) + i - 1
 70:   end do

 72: ! Initialize local buffer, these values are never used.
 73:   leafdata(1:nleavesalloc) = -1

 75: ! Broadcast entries from rootdata to leafdata. Computation or other communication can be performed between the begin and end calls.
 76:   PetscCallA(PetscSFBcastBegin(sf, MPIU_INTEGER, rootdata, leafdata, MPI_REPLACE, ierr))
 77:   PetscCallA(PetscSFBcastEnd(sf, MPIU_INTEGER, rootdata, leafdata, MPI_REPLACE, ierr))
 78:   PetscCallA(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_WORLD, '## Bcast Rootdata\n', ierr))
 79:   PetscCallA(PetscIntView(nrootsalloc, rootdata, PETSC_VIEWER_STDOUT_WORLD, ierr))
 80:   PetscCallA(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_WORLD, '## Bcast Leafdata\n', ierr))
 81:   PetscCallA(PetscIntView(nleavesalloc, leafdata, PETSC_VIEWER_STDOUT_WORLD, ierr))

 83: ! Reduce entries from leafdata to rootdata. Computation or other communication can be performed between the begin and end calls.
 84:   PetscCallA(PetscSFReduceBegin(sf, MPIU_INTEGER, leafdata, rootdata, MPI_SUM, ierr))
 85:   PetscCallA(PetscSFReduceEnd(sf, MPIU_INTEGER, leafdata, rootdata, MPI_SUM, ierr))
 86:   PetscCallA(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_WORLD, '## Reduce Leafdata\n', ierr))
 87:   PetscCallA(PetscIntView(nleavesalloc, leafdata, PETSC_VIEWER_STDOUT_WORLD, ierr))
 88:   PetscCallA(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_WORLD, '## Reduce Rootdata\n', ierr))
 89:   PetscCallA(PetscIntView(nrootsalloc, rootdata, PETSC_VIEWER_STDOUT_WORLD, ierr))

 91:   PetscCallA(PetscSFGetGraph(sf, gnroots, gnleaves, gmine, gremote, ierr))
 92:   PetscCheckA(gnleaves == nleaves, PETSC_COMM_WORLD, PETSC_ERR_PLIB, 'nleaves returned from PetscSFGetGraph() does not match that set with PetscSFSetGraph()')
 93:   do i = 1, nleaves
 94:     PetscCheckA(gmine(i) == mine(i), PETSC_COMM_WORLD, PETSC_ERR_PLIB, 'Root from PetscSFGetGraph() does not match that set with PetscSFSetGraph()')
 95:   end do
 96:   do i = 1, nleaves
 97:     PetscCheckA(gremote(i)%index == remote(i)%index, PETSC_COMM_WORLD, PETSC_ERR_PLIB, 'Leaf from PetscSFGetGraph() does not match that set with PetscSFSetGraph()')
 98:   end do
 99:   PetscCallA(PetscSFRestoreGraph(sf, gnroots, gnleaves, gmine, gremote, ierr))

101: ! Test PetscSFGet{Leaf,Root}Ranks
102:   PetscCallA(PetscSFGetLeafRanks(sf, niranks, iranks, ioffset, irootloc, ierr))
103:   PetscCallA(PetscSFGetRootRanks(sf, nranks, ranks, roffset, rmine, rremote, ierr))

105: ! Broadcast a PetscBool buffer using MPI_C_BOOL to exercise the Fortran -> C datatype conversion.
106: ! Every leaf references an active root slot, so each populated leaf slot must receive PETSC_TRUE.
107:   rootbool(1:nrootsalloc) = PETSC_FALSE
108:   rootbool(1 + ([(i, i=0, nroots - 1)])*stride) = PETSC_TRUE
109:   leafbool(1:nleavesalloc) = PETSC_FALSE
110:   PetscCallA(PetscSFBcastBegin(sf, MPI_C_BOOL, rootbool, leafbool, MPI_REPLACE, ierr))
111:   PetscCallA(PetscSFBcastEnd(sf, MPI_C_BOOL, rootbool, leafbool, MPI_REPLACE, ierr))
112:   do i = 1, nleaves
113:     PetscCheckA(leafbool(mine(i) + 1), PETSC_COMM_WORLD, PETSC_ERR_PLIB, 'PetscSFBcast with MPI_C_BOOL did not deliver expected value')
114:   end do

116: !    Clean storage for star forest.
117:   PetscCallA(PetscSFDestroy(sf, ierr))

119: !  Create a star forest with continuous leaves and hence no buffer
120:   PetscCallA(PetscSFCreate(PETSC_COMM_WORLD, sf, ierr))
121:   PetscCallA(PetscSFSetFromOptions(sf, ierr))
122:   PetscCallA(PetscSFSetGraph(sf, nrootsalloc, nleaves, PETSC_NULL_INTEGER_ARRAY, PETSC_COPY_VALUES, remote, PETSC_COPY_VALUES, ierr))
123:   PetscCallA(PetscSFSetUp(sf, ierr))

125: !   View graph, mostly useful for debugging purposes.
126:   PetscCallA(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL, ierr))
127:   PetscCallA(PetscSFView(sf, PETSC_VIEWER_STDOUT_WORLD, ierr))
128:   PetscCallA(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD, ierr))

130:   PetscCallA(PetscSFGetGraph(sf, gnroots, gnleaves, gmine, gremote, ierr))
131:   PetscCheckA(loc(gmine) == loc(PETSC_NULL_INTEGER), PETSC_COMM_WORLD, PETSC_ERR_PLIB, 'Leaves from PetscSFGetGraph() not null as expected')
132:   PetscCallA(PetscSFRestoreGraph(sf, gnroots, gnleaves, gmine, gremote, ierr))
133:   PetscCallA(PetscSFDestroy(sf, ierr))
134:   PetscCallA(PetscFinalize(ierr))
135: end

137: !/*TEST
138: !
139: !  test:
140: !    nsize: 3
141: !
142: !TEST*/