#include #include #include static const char help[] = "Parallel version of the minimum surface area problem in 2D using DMDA.\n\ It solves a system of nonlinear equations in mixed\n\ complementarity form.This example is based on a\n\ problem from the MINPACK-2 test suite. Given a rectangular 2-D domain and\n\ boundary values along the edges of the domain, the objective is to find the\n\ surface with the minimal area that satisfies the boundary conditions.\n\ This application solves this problem using complimentarity -- We are actually\n\ solving the system (grad f)_i >= 0, if x_i == l_i \n\ (grad f)_i = 0, if l_i < x_i < u_i \n\ (grad f)_i <= 0, if x_i == u_i \n\ where f is the function to be minimized. \n\ \n\ The command line options are:\n\ -da_grid_x , where = number of grid points in the 1st coordinate direction\n\ -da_grid_y , where = number of grid points in the 2nd coordinate direction\n\ -start , where =0 for zero vector, and an average of the boundary conditions otherwise\n\ -lb , lower bound on the variables\n\ -ub , upper bound on the variables\n\n"; /* User-defined application context - contains data needed by the application-provided call-back routines, FormJacobian() and FormFunction(). */ /* This is a new version of the ../tests/ex8.c code Run, for example, with the options ./ex58 -snes_vi_monitor -ksp_monitor -mg_levels_ksp_monitor -pc_type mg -pc_mg_levels 2 -pc_mg_galerkin pmat -ksp_type fgmres Or to run with grid sequencing on the nonlinear problem (note that you do not need to provide the number of multigrid levels, it will be determined automatically based on the number of refinements done) ./ex58 -pc_type mg -ksp_monitor -snes_view -pc_mg_galerkin pmat -snes_grid_sequence 3 -mg_levels_ksp_monitor -snes_vi_monitor -mg_levels_pc_type sor -pc_mg_type full */ typedef struct { PetscScalar *bottom, *top, *left, *right; PetscScalar lb,ub; } AppCtx; /* -------- User-defined Routines --------- */ extern PetscErrorCode FormBoundaryConditions(SNES,AppCtx**); extern PetscErrorCode DestroyBoundaryConditions(AppCtx**); extern PetscErrorCode ComputeInitialGuess(SNES, Vec,void*); extern PetscErrorCode FormGradient(SNES, Vec, Vec, void*); extern PetscErrorCode FormJacobian(SNES, Vec, Mat, Mat, void*); extern PetscErrorCode FormBounds(SNES,Vec,Vec); int main(int argc, char **argv) { PetscErrorCode ierr; /* used to check for functions returning nonzeros */ Vec x,r; /* solution and residual vectors */ SNES snes; /* nonlinear solver context */ Mat J; /* Jacobian matrix */ DM da; ierr = PetscInitialize(&argc, &argv, (char*)0, help);if (ierr) return ierr; /* Create distributed array to manage the 2d grid */ ierr = DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE,DMDA_STENCIL_BOX,4,4,PETSC_DECIDE,PETSC_DECIDE,1,1,NULL,NULL,&da);CHKERRQ(ierr); ierr = DMSetFromOptions(da);CHKERRQ(ierr); ierr = DMSetUp(da);CHKERRQ(ierr); /* Extract global vectors from DMDA; */ ierr = DMCreateGlobalVector(da,&x);CHKERRQ(ierr); ierr = VecDuplicate(x, &r);CHKERRQ(ierr); ierr = DMSetMatType(da,MATAIJ);CHKERRQ(ierr); ierr = DMCreateMatrix(da,&J);CHKERRQ(ierr); /* Create nonlinear solver context */ ierr = SNESCreate(PETSC_COMM_WORLD,&snes);CHKERRQ(ierr); ierr = SNESSetDM(snes,da);CHKERRQ(ierr); /* Set function evaluation and Jacobian evaluation routines */ ierr = SNESSetFunction(snes,r,FormGradient,NULL);CHKERRQ(ierr); ierr = SNESSetJacobian(snes,J,J,FormJacobian,NULL);CHKERRQ(ierr); ierr = SNESSetComputeApplicationContext(snes,(PetscErrorCode (*)(SNES,void**))FormBoundaryConditions,(PetscErrorCode (*)(void**))DestroyBoundaryConditions);CHKERRQ(ierr); ierr = SNESSetComputeInitialGuess(snes,ComputeInitialGuess,NULL);CHKERRQ(ierr); ierr = SNESVISetComputeVariableBounds(snes,FormBounds);CHKERRQ(ierr); ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); /* Solve the application */ ierr = SNESSolve(snes,NULL,x);CHKERRQ(ierr); /* Free memory */ ierr = VecDestroy(&x);CHKERRQ(ierr); ierr = VecDestroy(&r);CHKERRQ(ierr); ierr = MatDestroy(&J);CHKERRQ(ierr); ierr = SNESDestroy(&snes);CHKERRQ(ierr); /* Free user-created data structures */ ierr = DMDestroy(&da);CHKERRQ(ierr); ierr = PetscFinalize(); return ierr; } /* -------------------------------------------------------------------- */ /* FormBounds - sets the upper and lower bounds Input Parameters: . snes - the SNES context Output Parameters: . xl - lower bounds . xu - upper bounds */ PetscErrorCode FormBounds(SNES snes, Vec xl, Vec xu) { PetscErrorCode ierr; AppCtx *ctx; PetscFunctionBeginUser; ierr = SNESGetApplicationContext(snes,&ctx);CHKERRQ(ierr); ierr = VecSet(xl,ctx->lb);CHKERRQ(ierr); ierr = VecSet(xu,ctx->ub);CHKERRQ(ierr); PetscFunctionReturn(0); } /* -------------------------------------------------------------------- */ /* FormGradient - Evaluates gradient of f. Input Parameters: . snes - the SNES context . X - input vector . ptr - optional user-defined context, as set by SNESSetFunction() Output Parameters: . G - vector containing the newly evaluated gradient */ PetscErrorCode FormGradient(SNES snes, Vec X, Vec G, void *ptr) { AppCtx *user; int ierr; PetscInt i,j; PetscInt mx, my; PetscScalar hx,hy, hydhx, hxdhy; PetscScalar f1,f2,f3,f4,f5,f6,d1,d2,d3,d4,d5,d6,d7,d8,xc,xl,xr,xt,xb,xlt,xrb; PetscScalar df1dxc,df2dxc,df3dxc,df4dxc,df5dxc,df6dxc; PetscScalar **g, **x; PetscInt xs,xm,ys,ym; Vec localX; DM da; PetscFunctionBeginUser; ierr = SNESGetDM(snes,&da);CHKERRQ(ierr); ierr = SNESGetApplicationContext(snes,(void**)&user);CHKERRQ(ierr); ierr = DMDAGetInfo(da,PETSC_IGNORE,&mx,&my,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);CHKERRQ(ierr); hx = 1.0/(mx+1);hy=1.0/(my+1); hydhx=hy/hx; hxdhy=hx/hy; ierr = VecSet(G,0.0);CHKERRQ(ierr); /* Get local vector */ ierr = DMGetLocalVector(da,&localX);CHKERRQ(ierr); /* Get ghost points */ ierr = DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);CHKERRQ(ierr); ierr = DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);CHKERRQ(ierr); /* Get pointer to local vector data */ ierr = DMDAVecGetArray(da,localX, &x);CHKERRQ(ierr); ierr = DMDAVecGetArray(da,G, &g);CHKERRQ(ierr); ierr = DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL);CHKERRQ(ierr); /* Compute function over the locally owned part of the mesh */ for (j=ys; j < ys+ym; j++) { for (i=xs; i< xs+xm; i++) { xc = x[j][i]; xlt=xrb=xl=xr=xb=xt=xc; if (i==0) { /* left side */ xl = user->left[j+1]; xlt = user->left[j+2]; } else xl = x[j][i-1]; if (j==0) { /* bottom side */ xb = user->bottom[i+1]; xrb = user->bottom[i+2]; } else xb = x[j-1][i]; if (i+1 == mx) { /* right side */ xr = user->right[j+1]; xrb = user->right[j]; } else xr = x[j][i+1]; if (j+1==0+my) { /* top side */ xt = user->top[i+1]; xlt = user->top[i]; } else xt = x[j+1][i]; if (i>0 && j+10 && i+1left[j+1]; xlt = user->left[j+2]; } else xl = x[j][i-1]; /* Bottom */ if (j==0) { xb =user->bottom[i+1]; xrb = user->bottom[i+2]; } else xb = x[j-1][i]; /* Right */ if (i+1 == mx) { xr =user->right[j+1]; xrb = user->right[j]; } else xr = x[j][i+1]; /* Top */ if (j+1==my) { xt =user->top[i+1]; xlt = user->top[i]; } else xt = x[j+1][i]; /* Top left */ if (i>0 && j+10 && i+10) { v[k] =hb; col[k].i = i; col[k].j=j-1; k++; } /* Bottom right */ if (j>0 && i < mx -1) { v[k] =hbr; col[k].i = i+1; col[k].j = j-1; k++; } /* left */ if (i>0) { v[k] = hl; col[k].i = i-1; col[k].j = j; k++; } /* Centre */ v[k]= hc; col[k].i= row.i; col[k].j = row.j; k++; /* Right */ if (i < mx-1) { v[k] = hr; col[k].i= i+1; col[k].j = j;k++; } /* Top left */ if (i>0 && j < my-1) { v[k] = htl; col[k].i = i-1;col[k].j = j+1; k++; } /* Top */ if (j < my-1) { v[k] = ht; col[k].i = i; col[k].j = j+1; k++; } ierr = MatSetValuesStencil(H,1,&row,k,col,v,INSERT_VALUES);CHKERRQ(ierr); } } /* Assemble the matrix */ ierr = MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = DMDAVecRestoreArray(da,localX,&x);CHKERRQ(ierr); ierr = MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = DMRestoreLocalVector(da,&localX);CHKERRQ(ierr); ierr = PetscLogFlops(199.0*mx*my);CHKERRQ(ierr); PetscFunctionReturn(0); } /* ------------------------------------------------------------------- */ /* FormBoundaryConditions - Calculates the boundary conditions for the region. Input Parameter: . user - user-defined application context Output Parameter: . user - user-defined application context */ PetscErrorCode FormBoundaryConditions(SNES snes,AppCtx **ouser) { PetscErrorCode ierr; PetscInt i,j,k,limit=0,maxits=5; PetscInt mx,my; PetscInt bsize=0, lsize=0, tsize=0, rsize=0; PetscScalar one =1.0, two=2.0, three=3.0; PetscScalar det,hx,hy,xt=0,yt=0; PetscReal fnorm, tol=1e-10; PetscScalar u1,u2,nf1,nf2,njac11,njac12,njac21,njac22; PetscScalar b=-0.5, t=0.5, l=-0.5, r=0.5; PetscScalar *boundary; AppCtx *user; DM da; PetscFunctionBeginUser; ierr = SNESGetDM(snes,&da);CHKERRQ(ierr); ierr = PetscNew(&user);CHKERRQ(ierr); *ouser = user; user->lb = .05; user->ub = PETSC_INFINITY; ierr = DMDAGetInfo(da,PETSC_IGNORE,&mx,&my,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);CHKERRQ(ierr); /* Check if lower and upper bounds are set */ ierr = PetscOptionsGetScalar(NULL,NULL, "-lb", &user->lb, 0);CHKERRQ(ierr); ierr = PetscOptionsGetScalar(NULL,NULL, "-ub", &user->ub, 0);CHKERRQ(ierr); bsize=mx+2; lsize=my+2; rsize=my+2; tsize=mx+2; ierr = PetscMalloc1(bsize, &user->bottom);CHKERRQ(ierr); ierr = PetscMalloc1(tsize, &user->top);CHKERRQ(ierr); ierr = PetscMalloc1(lsize, &user->left);CHKERRQ(ierr); ierr = PetscMalloc1(rsize, &user->right);CHKERRQ(ierr); hx= (r-l)/(mx+1.0); hy=(t-b)/(my+1.0); for (j=0; j<4; j++) { if (j==0) { yt = b; xt = l; limit = bsize; boundary = user->bottom; } else if (j==1) { yt = t; xt = l; limit = tsize; boundary = user->top; } else if (j==2) { yt = b; xt = l; limit = lsize; boundary = user->left; } else { /* if (j==3) */ yt = b; xt = r; limit = rsize; boundary = user->right; } for (i=0; ibottom);CHKERRQ(ierr); ierr = PetscFree(user->top);CHKERRQ(ierr); ierr = PetscFree(user->left);CHKERRQ(ierr); ierr = PetscFree(user->right);CHKERRQ(ierr); ierr = PetscFree(*ouser);CHKERRQ(ierr); PetscFunctionReturn(0); } /* ------------------------------------------------------------------- */ /* ComputeInitialGuess - Calculates the initial guess Input Parameters: . user - user-defined application context . X - vector for initial guess Output Parameters: . X - newly computed initial guess */ PetscErrorCode ComputeInitialGuess(SNES snes, Vec X,void *dummy) { PetscErrorCode ierr; PetscInt i,j,mx,my; DM da; AppCtx *user; PetscScalar **x; PetscInt xs,xm,ys,ym; PetscFunctionBeginUser; ierr = SNESGetDM(snes,&da);CHKERRQ(ierr); ierr = SNESGetApplicationContext(snes,(void**)&user);CHKERRQ(ierr); ierr = DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL);CHKERRQ(ierr); ierr = DMDAGetInfo(da,PETSC_IGNORE,&mx,&my,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);CHKERRQ(ierr); /* Get pointers to vector data */ ierr = DMDAVecGetArray(da,X,&x);CHKERRQ(ierr); /* Perform local computations */ for (j=ys; jbottom[i+1]+(my-j+1.0)*user->top[i+1])/(my+2.0)+((i+1.0)*user->left[j+1]+(mx-i+1.0)*user->right[j+1])/(mx+2.0))/2.0; } } /* Restore vectors */ ierr = DMDAVecRestoreArray(da,X,&x);CHKERRQ(ierr); PetscFunctionReturn(0); } /*TEST test: args: -snes_type vinewtonrsls -pc_type mg -ksp_monitor_short -pc_mg_galerkin pmat -da_refine 5 -snes_vi_monitor -pc_mg_type full -snes_max_it 100 -snes_converged_reason requires: !single test: suffix: 2 args: -snes_type vinewtonssls -pc_type mg -ksp_monitor_short -pc_mg_galerkin pmat -da_refine 5 -snes_vi_monitor -pc_mg_type full -snes_max_it 100 -snes_converged_reason requires: !single TEST*/