
/*
  Code for manipulating distributed regular arrays in parallel.
*/

#include <petsc/private/dmdaimpl.h>    /*I   "petscdmda.h"   I*/

PetscErrorCode  VecDuplicate_MPI_DA(Vec g,Vec *gg)
{
  DM             da;
  PetscLayout    map;

  PetscFunctionBegin;
  PetscCall(VecGetDM(g, &da));
  PetscCall(DMCreateGlobalVector(da,gg));
  PetscCall(VecGetLayout(g,&map));
  PetscCall(VecSetLayout(*gg,map));
  PetscFunctionReturn(0);
}

PetscErrorCode  DMCreateGlobalVector_DA(DM da,Vec *g)
{
  DM_DA          *dd = (DM_DA*)da->data;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(da,DM_CLASSID,1);
  PetscValidPointer(g,2);
  PetscCall(VecCreate(PetscObjectComm((PetscObject)da),g));
  PetscCall(VecSetSizes(*g,dd->Nlocal,PETSC_DETERMINE));
  PetscCall(VecSetBlockSize(*g,dd->w));
  PetscCall(VecSetType(*g,da->vectype));
  if (dd->Nlocal < da->bind_below) {
    PetscCall(VecSetBindingPropagates(*g,PETSC_TRUE));
    PetscCall(VecBindToCPU(*g,PETSC_TRUE));
  }
  PetscCall(VecSetDM(*g, da));
  PetscCall(VecSetLocalToGlobalMapping(*g,da->ltogmap));
  PetscCall(VecSetOperation(*g,VECOP_VIEW,(void (*)(void))VecView_MPI_DA));
  PetscCall(VecSetOperation(*g,VECOP_LOAD,(void (*)(void))VecLoad_Default_DA));
  PetscCall(VecSetOperation(*g,VECOP_DUPLICATE,(void (*)(void))VecDuplicate_MPI_DA));
  PetscFunctionReturn(0);
}

/*@
   DMDACreateNaturalVector - Creates a parallel PETSc vector that
   will hold vector values in the natural numbering, rather than in
   the PETSc parallel numbering associated with the DMDA.

   Collective

   Input Parameter:
.  da - the distributed array

   Output Parameter:
.  g - the distributed global vector

   Level: developer

   Note:
   The output parameter, g, is a regular PETSc vector that should be destroyed
   with a call to VecDestroy() when usage is finished.

   The number of local entries in the vector on each process is the same
   as in a vector created with DMCreateGlobalVector().

.seealso: DMCreateLocalVector(), VecDuplicate(), VecDuplicateVecs(),
          DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMGlobalToLocalBegin(),
          DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
@*/
PetscErrorCode  DMDACreateNaturalVector(DM da,Vec *g)
{
  PetscInt       cnt;
  DM_DA          *dd = (DM_DA*)da->data;

  PetscFunctionBegin;
  PetscValidHeaderSpecificType(da,DM_CLASSID,1,DMDA);
  PetscValidPointer(g,2);
  if (dd->natural) {
    PetscCall(PetscObjectGetReference((PetscObject)dd->natural,&cnt));
    if (cnt == 1) { /* object is not currently used by anyone */
      PetscCall(PetscObjectReference((PetscObject)dd->natural));
      *g   = dd->natural;
    } else {
      PetscCall(VecDuplicate(dd->natural,g));
    }
  } else { /* create the first version of this guy */
    PetscCall(VecCreate(PetscObjectComm((PetscObject)da),g));
    PetscCall(VecSetSizes(*g,dd->Nlocal,PETSC_DETERMINE));
    PetscCall(VecSetBlockSize(*g, dd->w));
    PetscCall(VecSetType(*g,da->vectype));
    PetscCall(PetscObjectReference((PetscObject)*g));

    dd->natural = *g;
  }
  PetscFunctionReturn(0);
}
