!
! Description: Demonstrates using a local ordering to set values into a parallel vector
!

program main
#include <petsc/finclude/petscvec.h>
  use petscvec

  implicit none

  PetscErrorCode ierr
  PetscMPIInt rank
  PetscInt    ::   i, ng, rstart, rend, M
  PetscInt, pointer, dimension(:) :: gindices
  PetscScalar, parameter :: sone = 1.0
  Vec   ::         x
  ISLocalToGlobalMapping :: ltog
  PetscInt, parameter :: one = 1

  PetscCallA(PetscInitialize(ierr))
  PetscCallMPIA(MPI_Comm_rank(PETSC_COMM_WORLD, rank, ierr))

!
!     Create a parallel vector.
!      - In this case, we specify the size of each processor's local
!        portion, and PETSc computes the global size.  Alternatively,
!        PETSc could determine the vector's distribution if we specify
!        just the global size.
!
  PetscCallA(VecCreate(PETSC_COMM_WORLD, x, ierr))
  PetscCallA(VecSetSizes(x, rank + one, PETSC_DECIDE, ierr))
  PetscCallA(VecSetFromOptions(x, ierr))

  PetscCallA(VecSet(x, sone, ierr))

!
!     Set the local to global ordering for the vector. Each processor
!     generates a list of the global indices for each local index. Note that
!     the local indices are just whatever is convenient for a particular application.
!     In this case we treat the vector as lying on a one dimensional grid and
!     have one ghost point on each end of the blocks owned by each processor.
!

  PetscCallA(VecGetSize(x, M, ierr))
  PetscCallA(VecGetOwnershipRange(x, rstart, rend, ierr))
  ng = rend - rstart + 2
  allocate (gindices(0:ng - 1))
  gindices(0) = rstart - 1

  do i = 0, ng - 2
    gindices(i + 1) = gindices(i) + 1
  end do

! map the first and last point as periodic

  if (gindices(0) == -1) gindices(0) = M - 1

  if (gindices(ng - 1) == M) gindices(ng - 1) = 0

  PetscCallA(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, one, ng, gindices, PETSC_COPY_VALUES, ltog, ierr))
  PetscCallA(VecSetLocalToGlobalMapping(x, ltog, ierr))
  PetscCallA(ISLocalToGlobalMappingDestroy(ltog, ierr))
  deallocate (gindices)

  ! Set the vector elements.
  ! - In this case set the values using the local ordering
  ! - Each processor can contribute any vector entries,
  !   regardless of which processor "owns" them; any nonlocal
  !   contributions will be transferred to the appropriate processor
  !   during the assembly process.
  ! - In this example, the flag ADD_VALUES indicates that all
  !   contributions will be added together.

  do i = 0, ng - 1
    PetscCallA(VecSetValuesLocal(x, one, [i], [sone], ADD_VALUES, ierr))
  end do

  !
  ! Assemble vector, using the 2-step process:
  ! VecAssemblyBegin(), VecAssemblyEnd()
  ! Computations can be done while messages are in transition
  ! by placing code between these two statements.
  !
  PetscCallA(VecAssemblyBegin(x, ierr))
  PetscCallA(VecAssemblyEnd(x, ierr))
  !
  ! View the vector; then destroy it.
  !
  PetscCallA(VecView(x, PETSC_VIEWER_STDOUT_WORLD, ierr))
  PetscCallA(VecDestroy(x, ierr))
  PetscCallA(PetscFinalize(ierr))

end program

!/*TEST
!
!     test:
!       nsize: 4
!       output_file: output/ex8_1.out
!
!TEST*/
