// ------------------------------------------------------------- // MatCreateDenseGA // ------------------------------------------------------------- PetscErrorCode MatCreateDenseGA(MPI_Comm comm, PetscInt m,PetscInt n,PetscInt M,PetscInt N, Mat *A) { PetscErrorCode ierr = 0; struct MatGACtx *ctx; int lrows, grows, lcols, gcols; ierr = PetscMalloc(sizeof(struct MatGACtx), &ctx); CHKERRQ(ierr); ierr = MPIComm2GApgroup(comm, &(ctx->gaGroup)); CHKERRQ(ierr); lrows = m; lcols = n; grows = M; gcols = N; if (lrows == PETSC_DECIDE || lrows == PETSC_DETERMINE || grows == PETSC_DECIDE || grows == PETSC_DETERMINE) { ierr = PetscSplitOwnership(comm, &lrows, &grows); CHKERRXX(ierr); } if (lcols == PETSC_DECIDE || lcols == PETSC_DETERMINE || gcols == PETSC_DECIDE || gcols == PETSC_DETERMINE) { ierr = PetscSplitOwnership(comm, &lcols, &gcols); CHKERRXX(ierr); } ierr = CreateMatGA(ctx->gaGroup, lrows, lcols, grows, gcols, &(ctx->ga)); CHKERRQ(ierr); ierr = MatCreateShell(comm, lrows, lcols, grows, gcols, ctx, A); CHKERRQ(ierr); ierr = MatSetOperations_DenseGA(*A); return ierr; }
PetscErrorCode PETSCVEC_DLLEXPORT PetscLayoutSetUp(PetscLayout map) { PetscMPIInt rank,size; PetscInt p; PetscErrorCode ierr; PetscFunctionBegin; if (map->bs <=0) {SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"BlockSize not yet set");} if ((map->n >= 0) && (map->N >= 0) && (map->range)) PetscFunctionReturn(0); ierr = MPI_Comm_size(map->comm, &size);CHKERRQ(ierr); ierr = MPI_Comm_rank(map->comm, &rank);CHKERRQ(ierr); if (map->n > 0) map->n = map->n/map->bs; if (map->N > 0) map->N = map->N/map->bs; ierr = PetscSplitOwnership(map->comm,&map->n,&map->N);CHKERRQ(ierr); map->n = map->n*map->bs; map->N = map->N*map->bs; if (!map->range) { ierr = PetscMalloc((size+1)*sizeof(PetscInt), &map->range);CHKERRQ(ierr); } ierr = MPI_Allgather(&map->n, 1, MPIU_INT, map->range+1, 1, MPIU_INT, map->comm);CHKERRQ(ierr); map->range[0] = 0; for(p = 2; p <= size; p++) { map->range[p] += map->range[p-1]; } map->rstart = map->range[rank]; map->rend = map->range[rank+1]; PetscFunctionReturn(0); }
PetscErrorCode PetscLayoutSetUp(PetscLayout map) { PetscMPIInt rank,size; PetscInt p; PetscErrorCode ierr; PetscFunctionBegin; if (map->bs <= 0) map->bs = 1; if ((map->n >= 0) && (map->N >= 0) && (map->range)) PetscFunctionReturn(0); ierr = MPI_Comm_size(map->comm, &size);CHKERRQ(ierr); ierr = MPI_Comm_rank(map->comm, &rank);CHKERRQ(ierr); if (map->n > 0) map->n = map->n/map->bs; if (map->N > 0) map->N = map->N/map->bs; ierr = PetscSplitOwnership(map->comm,&map->n,&map->N);CHKERRQ(ierr); map->n = map->n*map->bs; map->N = map->N*map->bs; if (!map->range) { ierr = PetscMalloc((size+1)*sizeof(PetscInt), &map->range);CHKERRQ(ierr); } ierr = MPI_Allgather(&map->n, 1, MPIU_INT, map->range+1, 1, MPIU_INT, map->comm);CHKERRQ(ierr); map->range[0] = 0; for (p = 2; p <= size; p++) map->range[p] += map->range[p-1]; map->rstart = map->range[rank]; map->rend = map->range[rank+1]; #if defined(PETSC_THREADCOMM_ACTIVE) /* Set the thread ownership ranges */ ierr = PetscThreadCommGetOwnershipRanges(map->comm,map->n,&map->trstarts);CHKERRQ(ierr); #endif PetscFunctionReturn(0); }
/*@ PetscLayoutSetUp - given a map where you have set either the global or local size sets up the map so that it may be used. Collective on MPI_Comm Input Parameters: . map - pointer to the map Level: developer Notes: Typical calling sequence $ PetscLayoutCreate(MPI_Comm,PetscLayout *); $ PetscLayoutSetBlockSize(PetscLayout,1); $ PetscLayoutSetSize(PetscLayout,n) or PetscLayoutSetLocalSize(PetscLayout,N); or both $ PetscLayoutSetUp(PetscLayout); $ PetscLayoutGetSize(PetscLayout,PetscInt *); If the local size, global size are already set and range exists then this does nothing. .seealso: PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutDestroy(), PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutCreate() @*/ PetscErrorCode PetscLayoutSetUp(PetscLayout map) { PetscMPIInt rank,size; PetscInt p; PetscErrorCode ierr; PetscFunctionBegin; if ((map->n >= 0) && (map->N >= 0) && (map->range)) PetscFunctionReturn(0); if (map->n > 0 && map->bs > 1) { if (map->n % map->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Local matrix size %D must be divisible by blocksize %D",map->n,map->bs); } if (map->N > 0 && map->bs > 1) { if (map->N % map->bs) SETERRQ2(map->comm,PETSC_ERR_PLIB,"Global matrix size %D must be divisible by blocksize %D",map->N,map->bs); } ierr = MPI_Comm_size(map->comm, &size);CHKERRQ(ierr); ierr = MPI_Comm_rank(map->comm, &rank);CHKERRQ(ierr); if (map->n > 0) map->n = map->n/PetscAbs(map->bs); if (map->N > 0) map->N = map->N/PetscAbs(map->bs); ierr = PetscSplitOwnership(map->comm,&map->n,&map->N);CHKERRQ(ierr); map->n = map->n*PetscAbs(map->bs); map->N = map->N*PetscAbs(map->bs); if (!map->range) { ierr = PetscMalloc1(size+1, &map->range);CHKERRQ(ierr); } ierr = MPI_Allgather(&map->n, 1, MPIU_INT, map->range+1, 1, MPIU_INT, map->comm);CHKERRQ(ierr); map->range[0] = 0; for (p = 2; p <= size; p++) map->range[p] += map->range[p-1]; map->rstart = map->range[rank]; map->rend = map->range[rank+1]; PetscFunctionReturn(0); }
/*@C VecCreateGhostBlockWithArray - Creates a parallel vector with ghost padding on each processor; the caller allocates the array space. Indices in the ghost region are based on blocks. Collective on MPI_Comm Input Parameters: + comm - the MPI communicator to use . bs - block size . n - local vector length . N - global vector length (or PETSC_DECIDE to have calculated if n is given) . nghost - number of local ghost blocks . ghosts - global indices of ghost blocks (or PETSC_NULL if not needed), counts are by block not by index, these do not need to be in increasing order (sorted) - array - the space to store the vector values (as long as n + nghost*bs) Output Parameter: . vv - the global vector representation (without ghost points as part of vector) Notes: Use VecGhostGetLocalForm() to access the local, ghosted representation of the vector. n is the local vector size (total local size not the number of blocks) while nghost is the number of blocks in the ghost portion, i.e. the number of elements in the ghost portion is bs*nghost Level: advanced Concepts: vectors^creating ghosted Concepts: vectors^creating with array .seealso: VecCreate(), VecGhostGetLocalForm(), VecGhostRestoreLocalForm(), VecCreateGhost(), VecCreateSeqWithArray(), VecCreateMPIWithArray(), VecCreateGhostWithArray(), VecCreateGhostBlock() @*/ PetscErrorCode VecCreateGhostBlockWithArray(MPI_Comm comm,PetscInt bs,PetscInt n,PetscInt N,PetscInt nghost,const PetscInt ghosts[],const PetscScalar array[],Vec *vv) { PetscErrorCode ierr; Vec_MPI *w; PetscScalar *larray; IS from,to; ISLocalToGlobalMapping ltog; PetscInt rstart,i,nb,*indices; PetscFunctionBegin; *vv = 0; if (n == PETSC_DECIDE) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must set local size"); if (nghost == PETSC_DECIDE) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must set local ghost size"); if (nghost < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Ghost length must be >= 0"); if (n % bs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Local size must be a multiple of block size"); ierr = PetscSplitOwnership(comm,&n,&N);CHKERRQ(ierr); /* Create global representation */ ierr = VecCreate(comm,vv);CHKERRQ(ierr); ierr = VecSetSizes(*vv,n,N);CHKERRQ(ierr); ierr = VecSetBlockSize(*vv,bs);CHKERRQ(ierr); ierr = VecCreate_MPI_Private(*vv,PETSC_TRUE,nghost*bs,array);CHKERRQ(ierr); w = (Vec_MPI *)(*vv)->data; /* Create local representation */ ierr = VecGetArray(*vv,&larray);CHKERRQ(ierr); ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,bs,n+bs*nghost,larray,&w->localrep);CHKERRQ(ierr); ierr = PetscLogObjectParent(*vv,w->localrep);CHKERRQ(ierr); ierr = VecRestoreArray(*vv,&larray);CHKERRQ(ierr); /* Create scatter context for scattering (updating) ghost values */ ierr = ISCreateBlock(comm,bs,nghost,ghosts,PETSC_COPY_VALUES,&from);CHKERRQ(ierr); ierr = ISCreateStride(PETSC_COMM_SELF,bs*nghost,n,1,&to);CHKERRQ(ierr); ierr = VecScatterCreate(*vv,from,w->localrep,to,&w->localupdate);CHKERRQ(ierr); ierr = PetscLogObjectParent(*vv,w->localupdate);CHKERRQ(ierr); ierr = ISDestroy(&to);CHKERRQ(ierr); ierr = ISDestroy(&from);CHKERRQ(ierr); /* set local to global mapping for ghosted vector */ nb = n/bs; ierr = PetscMalloc((nb+nghost)*sizeof(PetscInt),&indices);CHKERRQ(ierr); ierr = VecGetOwnershipRange(*vv,&rstart,PETSC_NULL);CHKERRQ(ierr); for (i=0; i<nb; i++) { indices[i] = rstart + i*bs; } for (i=0; i<nghost; i++) { indices[nb+i] = ghosts[i]; } ierr = ISLocalToGlobalMappingCreate(comm,nb+nghost,indices,PETSC_OWN_POINTER,<og);CHKERRQ(ierr); ierr = VecSetLocalToGlobalMappingBlock(*vv,ltog);CHKERRQ(ierr); ierr = ISLocalToGlobalMappingDestroy(<og);CHKERRQ(ierr); PetscFunctionReturn(0); }
EXTERN_C_END #undef __FUNCT__ #define __FUNCT__ "VecCreateMPIWithArray" /*@C VecCreateMPIWithArray - Creates a parallel, array-style vector, where the user provides the array space to store the vector values. Collective on MPI_Comm Input Parameters: + comm - the MPI communicator to use . bs - block size, same meaning as VecSetBlockSize() . n - local vector length, cannot be PETSC_DECIDE . N - global vector length (or PETSC_DECIDE to have calculated) - array - the user provided array to store the vector values Output Parameter: . vv - the vector Notes: Use VecDuplicate() or VecDuplicateVecs() to form additional vectors of the same type as an existing vector. If the user-provided array is PETSC_NULL, then VecPlaceArray() can be used at a later stage to SET the array for storing the vector values. PETSc does NOT free the array when the vector is destroyed via VecDestroy(). The user should not free the array until the vector is destroyed. Level: intermediate Concepts: vectors^creating with array .seealso: VecCreateSeqWithArray(), VecCreate(), VecDuplicate(), VecDuplicateVecs(), VecCreateGhost(), VecCreateMPI(), VecCreateGhostWithArray(), VecPlaceArray() @*/ PetscErrorCode VecCreateMPIWithArray(MPI_Comm comm,PetscInt bs,PetscInt n,PetscInt N,const PetscScalar array[],Vec *vv) { PetscErrorCode ierr; PetscFunctionBegin; if (n == PETSC_DECIDE) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must set local size of vector"); ierr = PetscSplitOwnership(comm,&n,&N);CHKERRQ(ierr); ierr = VecCreate(comm,vv);CHKERRQ(ierr); ierr = VecSetSizes(*vv,n,N);CHKERRQ(ierr); ierr = VecSetBlockSize(*vv,bs);CHKERRQ(ierr); ierr = VecCreate_MPI_Private(*vv,PETSC_FALSE,0,array);CHKERRQ(ierr); PetscFunctionReturn(0); }
PETSC_EXTERN PetscErrorCode VecCreate_Shared(Vec vv) { PetscErrorCode ierr; PetscScalar *array; PetscFunctionBegin; ierr = PetscSplitOwnership(PetscObjectComm((PetscObject)vv),&vv->map->n,&vv->map->N);CHKERRQ(ierr); ierr = PetscSharedMalloc(PetscObjectComm((PetscObject)vv),vv->map->n*sizeof(PetscScalar),vv->map->N*sizeof(PetscScalar),(void**)&array);CHKERRQ(ierr); ierr = VecCreate_MPI_Private(vv,PETSC_FALSE,0,array);CHKERRQ(ierr); vv->ops->duplicate = VecDuplicate_Shared; PetscFunctionReturn(0); }
/*@C VecCreateMPIWithArray - Creates a parallel, array-style vector, where the user provides the array space to store the vector values. Collective on MPI_Comm Input Parameters: + comm - the MPI communicator to use . bs - block size, same meaning as VecSetBlockSize() . n - local vector length, cannot be PETSC_DECIDE . N - global vector length (or PETSC_DECIDE to have calculated) - array - the user provided array to store the vector values Output Parameter: . vv - the vector Notes: Use VecDuplicate() or VecDuplicateVecs() to form additional vectors of the same type as an existing vector. If the user-provided array is NULL, then VecPlaceArray() can be used at a later stage to SET the array for storing the vector values. PETSc does NOT free the array when the vector is destroyed via VecDestroy(). The user should not free the array until the vector is destroyed. Level: intermediate Concepts: vectors^creating with array .seealso: VecCreateSeqWithArray(), VecCreate(), VecDuplicate(), VecDuplicateVecs(), VecCreateGhost(), VecCreateMPI(), VecCreateGhostWithArray(), VecPlaceArray() @*/ PetscErrorCode VecCreateMPIWithArray(MPI_Comm comm,PetscInt bs,PetscInt n,PetscInt N,const PetscScalar array[],Vec *vv) { PetscErrorCode ierr; PetscFunctionBegin; if (n == PETSC_DECIDE) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must set local size of vector"); ierr = PetscSplitOwnership(comm,&n,&N);CHKERRQ(ierr); ierr = VecCreate(comm,vv);CHKERRQ(ierr); ierr = VecSetSizes(*vv,n,N);CHKERRQ(ierr); ierr = VecSetBlockSize(*vv,bs);CHKERRQ(ierr); ierr = VecCreate_MPI_Private(*vv,PETSC_FALSE,0,array);CHKERRQ(ierr); PetscFunctionReturn(0); }
EXTERN_C_BEGIN #undef __FUNCT__ #define __FUNCT__ "VecCreate_Shared" PetscErrorCode VecCreate_Shared(Vec vv) { PetscErrorCode ierr; PetscScalar *array; PetscFunctionBegin; ierr = PetscSplitOwnership(((PetscObject)vv)->comm,&vv->map->n,&vv->map->N);CHKERRQ(ierr); ierr = PetscSharedMalloc(((PetscObject)vv)->comm,vv->map->n*sizeof(PetscScalar),vv->map->N*sizeof(PetscScalar),(void**)&array);CHKERRQ(ierr); ierr = VecCreate_MPI_Private(vv,PETSC_FALSE,0,array);CHKERRQ(ierr); vv->ops->duplicate = VecDuplicate_Shared; PetscFunctionReturn(0); }
PETSC_EXTERN void PETSC_STDCALL petscsplitownership_(MPI_Fint * comm,PetscInt *n,PetscInt *N, int *__ierr ){ *__ierr = PetscSplitOwnership( MPI_Comm_f2c( *(comm) ),n,N); }
int main(int argc,char *argv[]) { char mat_type[256] = "aij"; /* default matrix type */ PetscErrorCode ierr; MPI_Comm comm; PetscMPIInt rank,size; DM slice; PetscInt i,bs=1,N=5,n,m,rstart,ghosts[2],*d_nnz,*o_nnz,dfill[4]={1,0,0,1},ofill[4]={1,1,1,1}; PetscReal alpha =1,K=1,rho0=1,u0=0,sigma=0.2; PetscBool useblock=PETSC_TRUE; PetscScalar *xx; Mat A; Vec x,b,lf; ierr = PetscInitialize(&argc,&argv,0,help);CHKERRQ(ierr); comm = PETSC_COMM_WORLD; ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); ierr = PetscOptionsBegin(comm,0,"Options for DMSliced test",0);CHKERRQ(ierr); { ierr = PetscOptionsInt("-n","Global number of nodes","",N,&N,NULL);CHKERRQ(ierr); ierr = PetscOptionsInt("-bs","Block size (1 or 2)","",bs,&bs,NULL);CHKERRQ(ierr); if (bs != 1) { if (bs != 2) SETERRQ(PETSC_COMM_WORLD,1,"Block size must be 1 or 2"); ierr = PetscOptionsReal("-alpha","Inverse time step for wave operator","",alpha,&alpha,NULL);CHKERRQ(ierr); ierr = PetscOptionsReal("-K","Bulk modulus of compressibility","",K,&K,NULL);CHKERRQ(ierr); ierr = PetscOptionsReal("-rho0","Reference density","",rho0,&rho0,NULL);CHKERRQ(ierr); ierr = PetscOptionsReal("-u0","Reference velocity","",u0,&u0,NULL);CHKERRQ(ierr); ierr = PetscOptionsReal("-sigma","Width of Gaussian density perturbation","",sigma,&sigma,NULL);CHKERRQ(ierr); ierr = PetscOptionsBool("-block","Use block matrix assembly","",useblock,&useblock,NULL);CHKERRQ(ierr); } ierr = PetscOptionsString("-sliced_mat_type","Matrix type to use (aij or baij)","",mat_type,mat_type,sizeof(mat_type),NULL);CHKERRQ(ierr); } ierr = PetscOptionsEnd();CHKERRQ(ierr); /* Split ownership, set up periodic grid in 1D */ n = PETSC_DECIDE; ierr = PetscSplitOwnership(comm,&n,&N);CHKERRQ(ierr); rstart = 0; ierr = MPI_Scan(&n,&rstart,1,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr); rstart -= n; ghosts[0] = (N+rstart-1)%N; ghosts[1] = (rstart+n)%N; ierr = PetscMalloc2(n,PetscInt,&d_nnz,n,PetscInt,&o_nnz);CHKERRQ(ierr); for (i=0; i<n; i++) { if (size > 1 && (i==0 || i==n-1)) { d_nnz[i] = 2; o_nnz[i] = 1; } else { d_nnz[i] = 3; o_nnz[i] = 0; } } ierr = DMSlicedCreate(comm,bs,n,2,ghosts,d_nnz,o_nnz,&slice);CHKERRQ(ierr); /* Currently does not copy X_nnz so we can't free them until after DMSlicedGetMatrix */ if (!useblock) {ierr = DMSlicedSetBlockFills(slice,dfill,ofill);CHKERRQ(ierr);} /* Irrelevant for baij formats */ ierr = DMSetMatType(slice,mat_type);CHKERRQ(ierr); ierr = DMCreateMatrix(slice,&A);CHKERRQ(ierr); ierr = PetscFree2(d_nnz,o_nnz);CHKERRQ(ierr); ierr = MatSetOption(A,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); ierr = DMCreateGlobalVector(slice,&x);CHKERRQ(ierr); ierr = VecDuplicate(x,&b);CHKERRQ(ierr); ierr = VecGhostGetLocalForm(x,&lf);CHKERRQ(ierr); ierr = VecGetSize(lf,&m);CHKERRQ(ierr); if (m != (n+2)*bs) SETERRQ2(PETSC_COMM_SELF,1,"size of local form %D, expected %D",m,(n+2)*bs); ierr = VecGetArray(lf,&xx);CHKERRQ(ierr); for (i=0; i<n; i++) { PetscInt row[2],col[9],im,ip; PetscScalar v[12]; const PetscReal xref = 2.0*(rstart+i)/N - 1; /* [-1,1] */ const PetscReal h = 1.0/N; /* grid spacing */ im = (i==0) ? n : i-1; ip = (i==n-1) ? n+1 : i+1; switch (bs) { case 1: /* Laplacian with periodic boundaries */ col[0] = im; col[1] = i; col[2] = ip; v[0] = -h; v[1] = 2*h; v[2] = -h; ierr = MatSetValuesLocal(A,1,&i,3,col,v,INSERT_VALUES);CHKERRQ(ierr); xx[i] = sin(xref*PETSC_PI); break; case 2: /* Linear acoustic wave operator in variables [rho, u], central differences, periodic, timestep 1/alpha */ v[0] = -0.5*u0; v[1] = -0.5*K; v[2] = alpha; v[3] = 0; v[4] = 0.5*u0; v[5] = 0.5*K; v[6] = -0.5/rho0; v[7] = -0.5*u0; v[8] = 0; v[9] = alpha; v[10] = 0.5/rho0; v[11] = 0.5*u0; if (useblock) { row[0] = i; col[0] = im; col[1] = i; col[2] = ip; ierr = MatSetValuesBlockedLocal(A,1,row,3,col,v,INSERT_VALUES);CHKERRQ(ierr); } else { row[0] = 2*i; row[1] = 2*i+1; col[0] = 2*im; col[1] = 2*im+1; col[2] = 2*i; col[3] = 2*ip; col[4] = 2*ip+1; v[3] = v[4]; v[4] = v[5]; /* pack values in first row */ ierr = MatSetValuesLocal(A,1,row,5,col,v,INSERT_VALUES);CHKERRQ(ierr); col[2] = 2*i+1; v[8] = v[9]; v[9] = v[10]; v[10] = v[11]; /* pack values in second row */ ierr = MatSetValuesLocal(A,1,row+1,5,col,v+6,INSERT_VALUES);CHKERRQ(ierr); } /* Set current state (gaussian density perturbation) */ xx[2*i] = 0.2*exp(-PetscSqr(xref)/(2*PetscSqr(sigma))); xx[2*i+1] = 0; break; default: SETERRQ1(PETSC_COMM_SELF,1,"not implemented for block size %D",bs); } } ierr = VecRestoreArray(lf,&xx);CHKERRQ(ierr); ierr = VecGhostRestoreLocalForm(x,&lf);CHKERRQ(ierr); ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatMult(A,x,b);CHKERRQ(ierr); ierr = MatView(A,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecView(x,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecView(b,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); /* Update the ghosted values, view the result on rank 0. */ ierr = VecGhostUpdateBegin(b,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecGhostUpdateEnd(b,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); if (!rank) { ierr = VecGhostGetLocalForm(b,&lf);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF,"Local form of b on rank 0, last two nodes are ghost nodes\n");CHKERRQ(ierr); ierr = VecView(lf,PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr); ierr = VecGhostRestoreLocalForm(b,&lf);CHKERRQ(ierr); } ierr = DMDestroy(&slice);CHKERRQ(ierr); ierr = VecDestroy(&x);CHKERRQ(ierr); ierr = VecDestroy(&b);CHKERRQ(ierr); ierr = MatDestroy(&A);CHKERRQ(ierr); ierr = PetscFinalize(); return 0; }