static char help[] = "Newton methods to solve u'' + u^{2} = f in parallel.\n\ This example employs a user-defined monitoring routine and optionally a user-defined\n\ routine to check candidate iterates produced by line search routines.\n\ The command line options include:\n\ -pre_check_iterates : activate checking of iterates\n\ -post_check_iterates : activate checking of iterates\n\ -check_tol : set tolerance for iterate checking\n\ -user_precond : activate a (trivial) user-defined preconditioner\n\n"; /*T Concepts: SNES^basic parallel example Concepts: SNES^setting a user-defined monitoring routine Processors: n T*/ /* Include "petscdraw.h" so that we can use distributed arrays (DMDAs). Include "petscdraw.h" so that we can use PETSc drawing routines. Include "petscsnes.h" so that we can use SNES solvers. Note that this file automatically includes: petscsys.h - base PETSc routines petscvec.h - vectors petscmat.h - matrices petscis.h - index sets petscksp.h - Krylov subspace methods petscviewer.h - viewers petscpc.h - preconditioners petscksp.h - linear solvers */ #include #include #include /* User-defined routines. */ PetscErrorCode FormJacobian1(SNES,Vec,Mat,Mat,void*); PetscErrorCode FormJacobian2(SNES,Vec,Mat,Mat,void*); PetscErrorCode FormFunction1(SNES,Vec,Vec,void*); PetscErrorCode FormFunction2(SNES,Vec,Vec,void*); PetscErrorCode FormInitialGuess(Vec); /* User-defined application context */ typedef struct { DM da; /* distributed array */ Vec F; /* right-hand-side of PDE */ PetscMPIInt rank; /* rank of processor */ PetscMPIInt size; /* size of communicator */ PetscReal h; /* mesh spacing */ } ApplicationCtx; /* User-defined context for monitoring */ typedef struct { PetscViewer viewer; } MonitorCtx; /* User-defined context for checking candidate iterates that are determined by line search methods */ typedef struct { Vec last_step; /* previous iterate */ PetscReal tolerance; /* tolerance for changes between successive iterates */ ApplicationCtx *user; } StepCheckCtx; typedef struct { PetscInt its0; /* num of prevous outer KSP iterations */ } SetSubKSPCtx; int main(int argc,char **argv) { SNES snes1,snes2; /* SNES context */ Mat J1,J2; /* Jacobian matrix */ ApplicationCtx ctx; /* user-defined context */ Vec x,r,U,F; /* vectors */ PetscScalar xp,*FF,*UU,none = -1.0; PetscErrorCode ierr; PetscInt its,N = 5,i,xs,xm; PetscReal norm; ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr; ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&ctx.rank);CHKERRQ(ierr); ierr = MPI_Comm_size(PETSC_COMM_WORLD,&ctx.size);CHKERRQ(ierr); ierr = PetscOptionsGetInt(NULL,NULL,"-n",&N,NULL);CHKERRQ(ierr); ctx.h = 1.0/(N-1); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create nonlinear solver context - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create vector data structures; set function evaluation routine - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Create distributed array (DMDA) to manage parallel grid and vectors */ ierr = DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,N,1,1,NULL,&ctx.da);CHKERRQ(ierr); ierr = DMSetFromOptions(ctx.da);CHKERRQ(ierr); ierr = DMSetUp(ctx.da);CHKERRQ(ierr); /* Extract global and local vectors from DMDA; then duplicate for remaining vectors that are the same types */ ierr = DMCreateGlobalVector(ctx.da,&x);CHKERRQ(ierr); ierr = VecDuplicate(x,&r);CHKERRQ(ierr); ierr = VecDuplicate(x,&F);CHKERRQ(ierr); ctx.F = F; ierr = VecDuplicate(x,&U);CHKERRQ(ierr); ierr = DMCreateMatrix(ctx.da,&J1);CHKERRQ(ierr); ierr = MatSetFromOptions(J1);CHKERRQ(ierr); ierr = DMCreateMatrix(ctx.da,&J2);CHKERRQ(ierr); ierr = MatSetFromOptions(J2);CHKERRQ(ierr); /* ierr = SNESCreate(PETSC_COMM_WORLD,&snes1);CHKERRQ(ierr); ierr = SNESSetFunction(snes1,r,FormFunction1,&ctx);CHKERRQ(ierr); ierr = SNESSetDM(snes1,ctx.da);CHKERRQ(ierr); ierr = SNESSetFromOptions(snes1);CHKERRQ(ierr); ierr = SNESSetJacobian(snes1,J1,J1,FormJacobian1,&ctx);CHKERRQ(ierr); ierr = SNESCreate(PETSC_COMM_WORLD,&snes2);CHKERRQ(ierr); ierr = SNESSetFunction(snes2,r,FormFunction2,&ctx);CHKERRQ(ierr); ierr = SNESSetDM(snes2,ctx.da);CHKERRQ(ierr); ierr = SNESSetFromOptions(snes2);CHKERRQ(ierr); ierr = SNESSetJacobian(snes2,J2,J2,FormJacobian2,&ctx);CHKERRQ(ierr); */ ierr = SNESCreate(PETSC_COMM_WORLD,&snes1);CHKERRQ(ierr); ierr = SNESSetFunction(snes1,r,FormFunction1,&ctx);CHKERRQ(ierr); ierr = SNESSetJacobian(snes1,J1,J1,FormJacobian1,&ctx);CHKERRQ(ierr); ierr = SNESSetDM(snes1,ctx.da);CHKERRQ(ierr); ierr = SNESSetFromOptions(snes1);CHKERRQ(ierr); ierr = SNESCreate(PETSC_COMM_WORLD,&snes2);CHKERRQ(ierr); ierr = SNESSetFunction(snes2,r,FormFunction2,&ctx);CHKERRQ(ierr); ierr = SNESSetJacobian(snes2,J2,J2,FormJacobian2,&ctx);CHKERRQ(ierr); ierr = SNESSetDM(snes2,ctx.da);CHKERRQ(ierr); ierr = SNESSetFromOptions(snes2);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject)x,"Approximate Solution");CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject)U,"Exact Solution");CHKERRQ(ierr); ierr = DMDAGetCorners(ctx.da,&xs,NULL,NULL,&xm,NULL,NULL);CHKERRQ(ierr); ierr = DMDAVecGetArray(ctx.da,F,&FF);CHKERRQ(ierr); ierr = DMDAVecGetArray(ctx.da,U,&UU);CHKERRQ(ierr); /* Compute local vector entries */ xp = ctx.h*xs; for (i=xs; iF,&FF);CHKERRQ(ierr); /* Get local grid boundaries (for 1-dimensional DMDA): xs, xm - starting grid index, width of local grid (no ghost points) */ ierr = DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL);CHKERRQ(ierr); ierr = DMDAGetInfo(da,NULL,&M,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);CHKERRQ(ierr); /* Set function values for boundary points; define local interior grid point range: xsi - starting interior grid index xei - ending interior grid index */ if (xs == 0) { /* left boundary */ ff[0] = xx[0]; xs++;xm--; } if (xs+xm == M) { /* right boundary */ ff[xs+xm-1] = xx[xs+xm-1] - 1.0; xm--; } /* Compute function over locally owned part of the grid (interior points only) */ d = 1.0/(user->h*user->h); for (i=xs; iF,&FF);CHKERRQ(ierr); ierr = DMRestoreLocalVector(da,&xlocal);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode FormFunction2(SNES snes,Vec x,Vec f,void *ctx) { ApplicationCtx *user = (ApplicationCtx*) ctx; DM da; PetscScalar *xx,*ff,*FF,d; PetscErrorCode ierr; PetscInt i,M,xs,xm; Vec xlocal; PetscFunctionBeginUser; ierr = PetscPrintf(PETSC_COMM_WORLD,"This is FormFunction2\n");CHKERRQ(ierr); ierr = SNESGetDM(snes,&da);CHKERRQ(ierr); ierr = DMGetLocalVector(da,&xlocal);CHKERRQ(ierr); /* Scatter ghost points to local vector, using the 2-step process DMGlobalToLocalBegin(), DMGlobalToLocalEnd(). By placing code between these two statements, computations can be done while messages are in transition. */ ierr = DMGlobalToLocalBegin(da,x,INSERT_VALUES,xlocal);CHKERRQ(ierr); ierr = DMGlobalToLocalEnd(da,x,INSERT_VALUES,xlocal);CHKERRQ(ierr); /* Get pointers to vector data. - The vector xlocal includes ghost point; the vectors x and f do NOT include ghost points. - Using DMDAVecGetArray() allows accessing the values using global ordering */ ierr = DMDAVecGetArray(da,xlocal,&xx);CHKERRQ(ierr); ierr = DMDAVecGetArray(da,f,&ff);CHKERRQ(ierr); ierr = DMDAVecGetArray(da,user->F,&FF);CHKERRQ(ierr); /* Get local grid boundaries (for 1-dimensional DMDA): xs, xm - starting grid index, width of local grid (no ghost points) */ ierr = DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL);CHKERRQ(ierr); ierr = DMDAGetInfo(da,NULL,&M,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);CHKERRQ(ierr); /* Set function values for boundary points; define local interior grid point range: xsi - starting interior grid index xei - ending interior grid index */ if (xs == 0) { /* left boundary */ ff[0] = xx[0]; xs++;xm--; } if (xs+xm == M) { /* right boundary */ ff[xs+xm-1] = xx[xs+xm-1] - 1.0; xm--; } /* Compute function over locally owned part of the grid (interior points only) */ d = 1.0/(user->h*user->h); for (i=xs; iF,&FF);CHKERRQ(ierr); ierr = DMRestoreLocalVector(da,&xlocal);CHKERRQ(ierr); PetscFunctionReturn(0); } /* ------------------------------------------------------------------- */ /* FormJacobian - Evaluates Jacobian matrix. Input Parameters: . snes - the SNES context . x - input vector . dummy - optional user-defined context (not used here) Output Parameters: . jac - Jacobian matrix . B - optionally different preconditioning matrix . flag - flag indicating matrix structure */ PetscErrorCode FormJacobian1(SNES snes,Vec x,Mat jac,Mat B,void *ctx) { ApplicationCtx *user = (ApplicationCtx*) ctx; PetscScalar *xx,d,A[3]; PetscErrorCode ierr; PetscInt i,j[3],M,xs,xm; DM da; PetscFunctionBeginUser; ierr = PetscPrintf(PETSC_COMM_WORLD,"This is FormJacobian1\n");CHKERRQ(ierr); ierr = SNESGetDM(snes,&da);CHKERRQ(ierr); /* Get pointer to vector data */ ierr = DMDAVecGetArrayRead(da,x,&xx);CHKERRQ(ierr); ierr = DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL);CHKERRQ(ierr); /* Get range of locally owned matrix */ ierr = DMDAGetInfo(da,NULL,&M,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);CHKERRQ(ierr); /* Determine starting and ending local indices for interior grid points. Set Jacobian entries for boundary points. */ if (xs == 0) { /* left boundary */ i = 0; A[0] = 1.0; ierr = MatSetValues(jac,1,&i,1,&i,A,INSERT_VALUES);CHKERRQ(ierr); xs++;xm--; } if (xs+xm == M) { /* right boundary */ i = M-1; A[0] = 1.0; ierr = MatSetValues(jac,1,&i,1,&i,A,INSERT_VALUES);CHKERRQ(ierr); xm--; } /* Interior grid points - Note that in this case we set all elements for a particular row at once. */ d = 1.0/(user->h*user->h); for (i=xs; ih*user->h); for (i=xs; i