static PetscErrorCode PCSetUp_Eisenstat(PC pc) { PetscErrorCode ierr; PetscInt M,N,m,n; PC_Eisenstat *eis = (PC_Eisenstat*)pc->data; PetscFunctionBegin; if (!pc->setupcalled) { ierr = MatGetSize(pc->mat,&M,&N);CHKERRQ(ierr); ierr = MatGetLocalSize(pc->mat,&m,&n);CHKERRQ(ierr); ierr = MatCreate(((PetscObject)pc)->comm,&eis->shell);CHKERRQ(ierr); ierr = MatSetSizes(eis->shell,m,n,M,N);CHKERRQ(ierr); ierr = MatSetType(eis->shell,MATSHELL);CHKERRQ(ierr); ierr = MatSetUp(eis->shell);CHKERRQ(ierr); ierr = MatShellSetContext(eis->shell,(void*)pc);CHKERRQ(ierr); ierr = PetscLogObjectParent(pc,eis->shell);CHKERRQ(ierr); ierr = MatShellSetOperation(eis->shell,MATOP_MULT,(void(*)(void))PCMult_Eisenstat);CHKERRQ(ierr); } if (!eis->usediag) PetscFunctionReturn(0); if (!pc->setupcalled) { ierr = MatGetVecs(pc->pmat,&eis->diag,0);CHKERRQ(ierr); ierr = PetscLogObjectParent(pc,eis->diag);CHKERRQ(ierr); } ierr = MatGetDiagonal(pc->pmat,eis->diag);CHKERRQ(ierr); PetscFunctionReturn(0); }
/* RHSMatrixLaplacian - User-provided routine to compute the right-hand-side matrix for the Laplacian operator Input Parameters: ts - the TS context t - current time (ignored) X - current solution (ignored) dummy - optional user-defined context, as set by TSetRHSJacobian() Output Parameters: AA - Jacobian matrix BB - optionally different matrix from which the preconditioner is built str - flag indicating matrix structure */ PetscErrorCode RHSMatrixLaplaciangllDM(TS ts,PetscReal t,Vec X,Mat A,Mat BB,void *ctx) { PetscReal **temp; PetscReal vv; AppCtx *appctx = (AppCtx*)ctx; /* user-defined application context */ PetscErrorCode ierr; PetscInt i,xs,xn,l,j; PetscInt *rowsDM; PetscBool flg = PETSC_FALSE; ierr = PetscOptionsGetBool(NULL,NULL,"-gll_mf",&flg,NULL);CHKERRQ(ierr); if (!flg) { /* Creates the element stiffness matrix for the given gll */ ierr = PetscGLLElementLaplacianCreate(&appctx->SEMop.gll,&temp);CHKERRQ(ierr); /* workarround for clang analyzer warning: Division by zero */ if (appctx->param.N <= 1) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Spectral element order should be > 1"); /* scale by the size of the element */ for (i=0; i<appctx->param.N; i++) { vv=-appctx->param.mu*2.0/appctx->param.Le; for (j=0; j<appctx->param.N; j++) temp[i][j]=temp[i][j]*vv; } ierr = MatSetOption(A,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE);CHKERRQ(ierr); ierr = DMDAGetCorners(appctx->da,&xs,NULL,NULL,&xn,NULL,NULL);CHKERRQ(ierr); xs = xs/(appctx->param.N-1); xn = xn/(appctx->param.N-1); ierr = PetscMalloc1(appctx->param.N,&rowsDM);CHKERRQ(ierr); /* loop over local elements */ for (j=xs; j<xs+xn; j++) { for (l=0; l<appctx->param.N; l++) { rowsDM[l] = 1+(j-xs)*(appctx->param.N-1)+l; } ierr = MatSetValuesLocal(A,appctx->param.N,rowsDM,appctx->param.N,rowsDM,&temp[0][0],ADD_VALUES);CHKERRQ(ierr); } ierr = PetscFree(rowsDM);CHKERRQ(ierr); ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = VecReciprocal(appctx->SEMop.mass);CHKERRQ(ierr); ierr = MatDiagonalScale(A,appctx->SEMop.mass,0);CHKERRQ(ierr); ierr = VecReciprocal(appctx->SEMop.mass);CHKERRQ(ierr); ierr = PetscGLLElementLaplacianDestroy(&appctx->SEMop.gll,&temp);CHKERRQ(ierr); } else { ierr = MatSetType(A,MATSHELL);CHKERRQ(ierr); ierr = MatSetUp(A);CHKERRQ(ierr); ierr = MatShellSetContext(A,appctx);CHKERRQ(ierr); ierr = MatShellSetOperation(A,MATOP_MULT,(void (*)(void))MatMult_Laplacian);CHKERRQ(ierr); } return 0; }
/*@C MatCreateShell - Creates a new matrix class for use with a user-defined private data storage format. Collective on MPI_Comm Input Parameters: + comm - MPI communicator . m - number of local rows (must be given) . n - number of local columns (must be given) . M - number of global rows (may be PETSC_DETERMINE) . N - number of global columns (may be PETSC_DETERMINE) - ctx - pointer to data needed by the shell matrix routines Output Parameter: . A - the matrix Level: advanced Usage: $ extern int mult(Mat,Vec,Vec); $ MatCreateShell(comm,m,n,M,N,ctx,&mat); $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); $ [ Use matrix for operations that have been set ] $ MatDestroy(mat); Notes: The shell matrix type is intended to provide a simple class to use with KSP (such as, for use with matrix-free methods). You should not use the shell type if you plan to define a complete matrix class. Fortran Notes: The context can only be an integer or a PetscObject unfortunately it cannot be a Fortran array or derived type. PETSc requires that matrices and vectors being used for certain operations are partitioned accordingly. For example, when creating a shell matrix, A, that supports parallel matrix-vector products using MatMult(A,x,y) the user should set the number of local matrix rows to be the number of local elements of the corresponding result vector, y. Note that this is information is required for use of the matrix interface routines, even though the shell matrix may not actually be physically partitioned. For example, $ $ Vec x, y $ extern int mult(Mat,Vec,Vec); $ Mat A $ $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); $ VecGetLocalSize(y,&m); $ VecGetLocalSize(x,&n); $ MatCreateShell(comm,m,n,M,N,ctx,&A); $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); $ MatMult(A,x,y); $ MatDestroy(A); $ VecDestroy(y); VecDestroy(x); $ .keywords: matrix, shell, create .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext() @*/ PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) { PetscErrorCode ierr; PetscFunctionBegin; ierr = MatCreate(comm,A);CHKERRQ(ierr); ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr); ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); ierr = MatSetUp(*A);CHKERRQ(ierr); PetscFunctionReturn(0); }
static PetscErrorCode MatCopy_User(Mat A,Mat B,MatStructure str) { User userA,userB; PetscErrorCode ierr; PetscFunctionBegin; ierr = MatShellGetContext(A,&userA);CHKERRQ(ierr); if (userA) { ierr = PetscNew(&userB);CHKERRQ(ierr); ierr = MatDuplicate(userA->A,MAT_COPY_VALUES,&userB->A);CHKERRQ(ierr); ierr = MatShellSetContext(B, userB);CHKERRQ(ierr); } PetscFunctionReturn(0); }
/* RHSMatrixAdvection - User-provided routine to compute the right-hand-side matrix for the Advection (gradient) operator. Input Parameters: ts - the TS context t - current time global_in - global input vector dummy - optional user-defined context, as set by TSetRHSJacobian() Output Parameters: AA - Jacobian matrix BB - optionally different preconditioning matrix str - flag indicating matrix structure */ PetscErrorCode RHSMatrixAdvectiongllDM(TS ts,PetscReal t,Vec X,Mat A,Mat BB,void *ctx) { PetscReal **temp; AppCtx *appctx = (AppCtx*)ctx; /* user-defined application context */ PetscErrorCode ierr; PetscInt xs,xn,l,j; PetscInt *rowsDM; PetscBool flg = PETSC_FALSE; ierr = PetscOptionsGetBool(NULL,NULL,"-gll_mf",&flg,NULL);CHKERRQ(ierr); if (!flg) { /* Creates the advection matrix for the given gll */ ierr = PetscGLLElementAdvectionCreate(&appctx->SEMop.gll,&temp);CHKERRQ(ierr); ierr = MatSetOption(A,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE);CHKERRQ(ierr); ierr = DMDAGetCorners(appctx->da,&xs,NULL,NULL,&xn,NULL,NULL);CHKERRQ(ierr); xs = xs/(appctx->param.N-1); xn = xn/(appctx->param.N-1); ierr = PetscMalloc1(appctx->param.N,&rowsDM);CHKERRQ(ierr); for (j=xs; j<xs+xn; j++) { for (l=0; l<appctx->param.N; l++) { rowsDM[l] = 1+(j-xs)*(appctx->param.N-1)+l; } ierr = MatSetValuesLocal(A,appctx->param.N,rowsDM,appctx->param.N,rowsDM,&temp[0][0],ADD_VALUES);CHKERRQ(ierr); } ierr = PetscFree(rowsDM);CHKERRQ(ierr); ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = VecReciprocal(appctx->SEMop.mass);CHKERRQ(ierr); ierr = MatDiagonalScale(A,appctx->SEMop.mass,0);CHKERRQ(ierr); ierr = VecReciprocal(appctx->SEMop.mass);CHKERRQ(ierr); ierr = PetscGLLElementAdvectionDestroy(&appctx->SEMop.gll,&temp);CHKERRQ(ierr); } else { ierr = MatSetType(A,MATSHELL);CHKERRQ(ierr); ierr = MatSetUp(A);CHKERRQ(ierr); ierr = MatShellSetContext(A,appctx);CHKERRQ(ierr); ierr = MatShellSetOperation(A,MATOP_MULT,(void (*)(void))MatMult_Advection);CHKERRQ(ierr); } return 0; }
int main(int argc, char **argv) { SNES snes; /* nonlinear solver */ DM dm; /* problem definition */ Vec u,r; /* solution, residual vectors */ Mat A,J; /* Jacobian matrix */ MatNullSpace nullSpace; /* May be necessary for pressure */ AppCtx user; /* user-defined work context */ JacActionCtx userJ; /* context for Jacobian MF action */ PetscInt its; /* iterations for convergence */ PetscReal error = 0.0; /* L_2 error in the solution */ PetscInt numComponents = 0, f; PetscErrorCode ierr; ierr = PetscInitialize(&argc, &argv, NULL, help);CHKERRQ(ierr); ierr = ProcessOptions(PETSC_COMM_WORLD, &user);CHKERRQ(ierr); ierr = SNESCreate(PETSC_COMM_WORLD, &snes);CHKERRQ(ierr); ierr = CreateMesh(PETSC_COMM_WORLD, &user, &dm);CHKERRQ(ierr); ierr = SNESSetDM(snes, dm);CHKERRQ(ierr); ierr = SetupElement(dm, &user);CHKERRQ(ierr); for (f = 0; f < NUM_FIELDS; ++f) { PetscInt numComp; ierr = PetscFEGetNumComponents(user.fe[f], &numComp);CHKERRQ(ierr); numComponents += numComp; } ierr = PetscMalloc(NUM_FIELDS * sizeof(void (*)(const PetscReal[], PetscScalar *)), &user.exactFuncs);CHKERRQ(ierr); user.fem.bcFuncs = (void (**)(const PetscReal[], PetscScalar *)) user.exactFuncs; ierr = SetupExactSolution(dm, &user);CHKERRQ(ierr); ierr = SetupSection(dm, &user);CHKERRQ(ierr); ierr = DMPlexCreateClosureIndex(dm, NULL);CHKERRQ(ierr); ierr = DMCreateGlobalVector(dm, &u);CHKERRQ(ierr); ierr = VecDuplicate(u, &r);CHKERRQ(ierr); ierr = DMSetMatType(dm,MATAIJ);CHKERRQ(ierr); ierr = DMCreateMatrix(dm, &J);CHKERRQ(ierr); if (user.jacobianMF) { PetscInt M, m, N, n; ierr = MatGetSize(J, &M, &N);CHKERRQ(ierr); ierr = MatGetLocalSize(J, &m, &n);CHKERRQ(ierr); ierr = MatCreate(PETSC_COMM_WORLD, &A);CHKERRQ(ierr); ierr = MatSetSizes(A, m, n, M, N);CHKERRQ(ierr); ierr = MatSetType(A, MATSHELL);CHKERRQ(ierr); ierr = MatSetUp(A);CHKERRQ(ierr); ierr = MatShellSetOperation(A, MATOP_MULT, (void (*)(void))FormJacobianAction);CHKERRQ(ierr); userJ.dm = dm; userJ.J = J; userJ.user = &user; ierr = DMCreateLocalVector(dm, &userJ.u);CHKERRQ(ierr); ierr = DMPlexProjectFunctionLocal(dm, user.fe, user.exactFuncs, INSERT_BC_VALUES, userJ.u);CHKERRQ(ierr); ierr = MatShellSetContext(A, &userJ);CHKERRQ(ierr); } else { A = J; } ierr = CreatePressureNullSpace(dm, &user, &nullSpace);CHKERRQ(ierr); ierr = MatSetNullSpace(J, nullSpace);CHKERRQ(ierr); if (A != J) { ierr = MatSetNullSpace(A, nullSpace);CHKERRQ(ierr); } ierr = DMSNESSetFunctionLocal(dm, (PetscErrorCode (*)(DM,Vec,Vec,void*))DMPlexComputeResidualFEM,&user);CHKERRQ(ierr); ierr = DMSNESSetJacobianLocal(dm, (PetscErrorCode (*)(DM,Vec,Mat,Mat,MatStructure*,void*))DMPlexComputeJacobianFEM,&user);CHKERRQ(ierr); ierr = SNESSetJacobian(snes, A, J, NULL, NULL);CHKERRQ(ierr); ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); ierr = DMPlexProjectFunction(dm, user.fe, user.exactFuncs, INSERT_ALL_VALUES, u);CHKERRQ(ierr); if (user.showInitial) {ierr = DMVecViewLocal(dm, u, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);} if (user.runType == RUN_FULL) { ierr = DMPlexProjectFunction(dm, user.fe, user.initialGuess, INSERT_VALUES, u);CHKERRQ(ierr); if (user.showInitial) {ierr = DMVecViewLocal(dm, u, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);} if (user.debug) { ierr = PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");CHKERRQ(ierr); ierr = VecView(u, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } ierr = SNESSolve(snes, NULL, u);CHKERRQ(ierr); ierr = SNESGetIterationNumber(snes, &its);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %D\n", its);CHKERRQ(ierr); ierr = DMPlexComputeL2Diff(dm, user.fe, user.exactFuncs, u, &error);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %.3g\n", error);CHKERRQ(ierr); if (user.showSolution) { ierr = PetscPrintf(PETSC_COMM_WORLD, "Solution\n");CHKERRQ(ierr); ierr = VecChop(u, 3.0e-9);CHKERRQ(ierr); ierr = VecView(u, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } } else { PetscReal res = 0.0; /* Check discretization error */ ierr = PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");CHKERRQ(ierr); ierr = VecView(u, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = DMPlexComputeL2Diff(dm, user.fe, user.exactFuncs, u, &error);CHKERRQ(ierr); if (error >= 1.0e-11) { ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %g\n", error);CHKERRQ(ierr); } else { ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: < 1.0e-11\n", error);CHKERRQ(ierr); } /* Check residual */ ierr = SNESComputeFunction(snes, u, r);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Initial Residual\n");CHKERRQ(ierr); ierr = VecChop(r, 1.0e-10);CHKERRQ(ierr); ierr = VecView(r, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecNorm(r, NORM_2, &res);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Residual: %g\n", res);CHKERRQ(ierr); /* Check Jacobian */ { Vec b; MatStructure flag; PetscBool isNull; ierr = SNESComputeJacobian(snes, u, &A, &A, &flag);CHKERRQ(ierr); ierr = MatNullSpaceTest(nullSpace, J, &isNull);CHKERRQ(ierr); if (!isNull) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid."); ierr = VecDuplicate(u, &b);CHKERRQ(ierr); ierr = VecSet(r, 0.0);CHKERRQ(ierr); ierr = SNESComputeFunction(snes, r, b);CHKERRQ(ierr); ierr = MatMult(A, u, r);CHKERRQ(ierr); ierr = VecAXPY(r, 1.0, b);CHKERRQ(ierr); ierr = VecDestroy(&b);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Au - b = Au + F(0)\n");CHKERRQ(ierr); ierr = VecChop(r, 1.0e-10);CHKERRQ(ierr); ierr = VecView(r, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecNorm(r, NORM_2, &res);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Linear L_2 Residual: %g\n", res);CHKERRQ(ierr); } } if (user.runType == RUN_FULL) { PetscViewer viewer; Vec uLocal; const char *name; ierr = PetscViewerCreate(PETSC_COMM_WORLD, &viewer);CHKERRQ(ierr); ierr = PetscViewerSetType(viewer, PETSCVIEWERVTK);CHKERRQ(ierr); ierr = PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_VTK);CHKERRQ(ierr); ierr = PetscViewerFileSetName(viewer, "ex62_sol.vtk");CHKERRQ(ierr); ierr = DMGetLocalVector(dm, &uLocal);CHKERRQ(ierr); ierr = PetscObjectGetName((PetscObject) u, &name);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) uLocal, name);CHKERRQ(ierr); ierr = DMGlobalToLocalBegin(dm, u, INSERT_VALUES, uLocal);CHKERRQ(ierr); ierr = DMGlobalToLocalEnd(dm, u, INSERT_VALUES, uLocal);CHKERRQ(ierr); ierr = VecView(uLocal, viewer);CHKERRQ(ierr); ierr = DMRestoreLocalVector(dm, &uLocal);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); } ierr = PetscFree(user.exactFuncs);CHKERRQ(ierr); ierr = DestroyElement(&user);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr); if (user.jacobianMF) { ierr = VecDestroy(&userJ.u);CHKERRQ(ierr); } if (A != J) { ierr = MatDestroy(&A);CHKERRQ(ierr); } ierr = MatDestroy(&J);CHKERRQ(ierr); ierr = VecDestroy(&u);CHKERRQ(ierr); ierr = VecDestroy(&r);CHKERRQ(ierr); ierr = SNESDestroy(&snes);CHKERRQ(ierr); ierr = DMDestroy(&dm);CHKERRQ(ierr); ierr = PetscFinalize(); return 0; }
int main(int argc, char **argv) { SNES snes; /* nonlinear solver */ Vec u,r; /* solution, residual vectors */ Mat A,J; /* Jacobian matrix */ MatNullSpace nullSpace; /* May be necessary for pressure */ AppCtx user; /* user-defined work context */ JacActionCtx userJ; /* context for Jacobian MF action */ PetscInt its; /* iterations for convergence */ PetscReal error = 0.0; /* L_2 error in the solution */ const PetscInt numComponents = NUM_BASIS_COMPONENTS_TOTAL; PetscErrorCode ierr; ierr = PetscInitialize(&argc, &argv, NULL, help);CHKERRQ(ierr); ierr = ProcessOptions(PETSC_COMM_WORLD, &user);CHKERRQ(ierr); ierr = SNESCreate(PETSC_COMM_WORLD, &snes);CHKERRQ(ierr); ierr = CreateMesh(PETSC_COMM_WORLD, &user, &user.dm);CHKERRQ(ierr); ierr = SNESSetDM(snes, user.dm);CHKERRQ(ierr); ierr = SetupExactSolution(user.dm, &user);CHKERRQ(ierr); ierr = SetupQuadrature(&user);CHKERRQ(ierr); ierr = SetupSection(user.dm, &user);CHKERRQ(ierr); ierr = DMCreateGlobalVector(user.dm, &u);CHKERRQ(ierr); ierr = VecDuplicate(u, &r);CHKERRQ(ierr); ierr = DMCreateMatrix(user.dm, MATAIJ, &J);CHKERRQ(ierr); if (user.jacobianMF) { PetscInt M, m, N, n; ierr = MatGetSize(J, &M, &N);CHKERRQ(ierr); ierr = MatGetLocalSize(J, &m, &n);CHKERRQ(ierr); ierr = MatCreate(PETSC_COMM_WORLD, &A);CHKERRQ(ierr); ierr = MatSetSizes(A, m, n, M, N);CHKERRQ(ierr); ierr = MatSetType(A, MATSHELL);CHKERRQ(ierr); ierr = MatSetUp(A);CHKERRQ(ierr); ierr = MatShellSetOperation(A, MATOP_MULT, (void (*)(void))FormJacobianAction);CHKERRQ(ierr); userJ.dm = user.dm; userJ.J = J; userJ.user = &user; ierr = DMCreateLocalVector(user.dm, &userJ.u);CHKERRQ(ierr); ierr = DMPlexProjectFunctionLocal(user.dm, numComponents, user.exactFuncs, INSERT_BC_VALUES, userJ.u);CHKERRQ(ierr); ierr = MatShellSetContext(A, &userJ);CHKERRQ(ierr); } else { A = J; } ierr = CreatePressureNullSpace(user.dm, &user, &nullSpace);CHKERRQ(ierr); ierr = MatSetNullSpace(J, nullSpace);CHKERRQ(ierr); if (A != J) { ierr = MatSetNullSpace(A, nullSpace);CHKERRQ(ierr); } ierr = DMSNESSetFunctionLocal(user.dm, (PetscErrorCode (*)(DM,Vec,Vec,void*))DMPlexComputeResidualFEM,&user);CHKERRQ(ierr); ierr = DMSNESSetJacobianLocal(user.dm, (PetscErrorCode (*)(DM,Vec,Mat,Mat,MatStructure*,void*))DMPlexComputeJacobianFEM,&user);CHKERRQ(ierr); ierr = SNESSetJacobian(snes, A, J, NULL, NULL);CHKERRQ(ierr); ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); ierr = DMPlexProjectFunction(user.dm, numComponents, user.exactFuncs, INSERT_ALL_VALUES, u);CHKERRQ(ierr); if (user.showInitial) {ierr = DMVecViewLocal(user.dm, u, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);} if (user.runType == RUN_FULL) { PetscScalar (*initialGuess[numComponents])(const PetscReal x[]); PetscInt c; for (c = 0; c < numComponents; ++c) initialGuess[c] = zero; ierr = DMPlexProjectFunction(user.dm, numComponents, initialGuess, INSERT_VALUES, u);CHKERRQ(ierr); if (user.showInitial) {ierr = DMVecViewLocal(user.dm, u, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);} if (user.debug) { ierr = PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");CHKERRQ(ierr); ierr = VecView(u, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } ierr = SNESSolve(snes, NULL, u);CHKERRQ(ierr); ierr = SNESGetIterationNumber(snes, &its);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %D\n", its);CHKERRQ(ierr); ierr = DMPlexComputeL2Diff(user.dm, user.fem.quad, user.exactFuncs, u, &error);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %.3g\n", error);CHKERRQ(ierr); if (user.showSolution) { ierr = PetscPrintf(PETSC_COMM_WORLD, "Solution\n");CHKERRQ(ierr); ierr = VecChop(u, 3.0e-9);CHKERRQ(ierr); ierr = VecView(u, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } } else { PetscReal res = 0.0; /* Check discretization error */ ierr = PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");CHKERRQ(ierr); ierr = VecView(u, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = DMPlexComputeL2Diff(user.dm, user.fem.quad, user.exactFuncs, u, &error);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %g\n", error);CHKERRQ(ierr); /* Check residual */ ierr = SNESComputeFunction(snes, u, r);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Initial Residual\n");CHKERRQ(ierr); ierr = VecChop(r, 1.0e-10);CHKERRQ(ierr); ierr = VecView(r, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecNorm(r, NORM_2, &res);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Residual: %g\n", res);CHKERRQ(ierr); /* Check Jacobian */ { Vec b; MatStructure flag; PetscBool isNull; ierr = SNESComputeJacobian(snes, u, &A, &A, &flag);CHKERRQ(ierr); ierr = MatNullSpaceTest(nullSpace, J, &isNull);CHKERRQ(ierr); if (!isNull) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid."); ierr = VecDuplicate(u, &b);CHKERRQ(ierr); ierr = VecSet(r, 0.0);CHKERRQ(ierr); ierr = SNESComputeFunction(snes, r, b);CHKERRQ(ierr); ierr = MatMult(A, u, r);CHKERRQ(ierr); ierr = VecAXPY(r, 1.0, b);CHKERRQ(ierr); ierr = VecDestroy(&b);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Au - b = Au + F(0)\n");CHKERRQ(ierr); ierr = VecChop(r, 1.0e-10);CHKERRQ(ierr); ierr = VecView(r, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecNorm(r, NORM_2, &res);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Linear L_2 Residual: %g\n", res);CHKERRQ(ierr); } } if (user.runType == RUN_FULL) { PetscViewer viewer; Vec uLocal; ierr = PetscViewerCreate(PETSC_COMM_WORLD, &viewer);CHKERRQ(ierr); ierr = PetscViewerSetType(viewer, PETSCVIEWERVTK);CHKERRQ(ierr); ierr = PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_VTK);CHKERRQ(ierr); ierr = PetscViewerFileSetName(viewer, "ex62_sol.vtk");CHKERRQ(ierr); ierr = DMGetLocalVector(user.dm, &uLocal);CHKERRQ(ierr); ierr = DMGlobalToLocalBegin(user.dm, u, INSERT_VALUES, uLocal);CHKERRQ(ierr); ierr = DMGlobalToLocalEnd(user.dm, u, INSERT_VALUES, uLocal);CHKERRQ(ierr); ierr = PetscObjectReference((PetscObject) user.dm);CHKERRQ(ierr); /* Needed because viewer destroys the DM */ ierr = PetscObjectReference((PetscObject) uLocal);CHKERRQ(ierr); /* Needed because viewer destroys the Vec */ ierr = PetscViewerVTKAddField(viewer, (PetscObject) user.dm, DMPlexVTKWriteAll, PETSC_VTK_POINT_FIELD, (PetscObject) uLocal);CHKERRQ(ierr); ierr = DMRestoreLocalVector(user.dm, &uLocal);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); } ierr = DestroyQuadrature(&user);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr); if (user.jacobianMF) { ierr = VecDestroy(&userJ.u);CHKERRQ(ierr); } if (A != J) { ierr = MatDestroy(&A);CHKERRQ(ierr); } ierr = MatDestroy(&J);CHKERRQ(ierr); ierr = VecDestroy(&u);CHKERRQ(ierr); ierr = VecDestroy(&r);CHKERRQ(ierr); ierr = SNESDestroy(&snes);CHKERRQ(ierr); ierr = DMDestroy(&user.dm);CHKERRQ(ierr); ierr = PetscFinalize(); return 0; }
/*@C SNESMatrixFreeCreate2 - Creates a matrix-free matrix context for use with a SNES solver. This matrix can be used as the Jacobian argument for the routine SNESSetJacobian(). Input Parameters: . snes - the SNES context . x - vector where SNES solution is to be stored. Output Parameter: . J - the matrix-free matrix Level: advanced Notes: The matrix-free matrix context merely contains the function pointers and work space for performing finite difference approximations of Jacobian-vector products, J(u)*a, via $ J(u)*a = [J(u+h*a) - J(u)]/h, $ where by default $ h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} $ = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise $ where $ error_rel = square root of relative error in $ function evaluation $ umin = minimum iterate parameter $ Alternatively, the differencing parameter, h, can be set using $ Jorge's nifty new strategy if one specifies the option $ -snes_mf_jorge The user can set these parameters via MatMFFDSetFunctionError(). See the <A href="../../docs/manual.pdf#nameddest=ch_snes">SNES chapter of the users manual</A>. The user should call MatDestroy() when finished with the matrix-free matrix context. Options Database Keys: $ -snes_mf_err <error_rel> $ -snes_mf_unim <umin> $ -snes_mf_compute_err $ -snes_mf_freq_err <freq> $ -snes_mf_jorge .keywords: SNES, default, matrix-free, create, matrix .seealso: MatDestroy(), MatMFFDSetFunctionError() @*/ PetscErrorCode SNESDefaultMatrixFreeCreate2(SNES snes,Vec x,Mat *J) { MPI_Comm comm; MFCtx_Private *mfctx; PetscErrorCode ierr; PetscInt n,nloc; PetscBool flg; char p[64]; PetscFunctionBegin; ierr = PetscNewLog(snes,&mfctx);CHKERRQ(ierr); mfctx->sp = 0; mfctx->snes = snes; mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON; mfctx->umin = 1.e-6; mfctx->h = 0.0; mfctx->need_h = PETSC_TRUE; mfctx->need_err = PETSC_FALSE; mfctx->compute_err = PETSC_FALSE; mfctx->compute_err_freq = 0; mfctx->compute_err_iter = -1; mfctx->compute_err = PETSC_FALSE; mfctx->jorge = PETSC_FALSE; ierr = PetscOptionsGetReal(((PetscObject)snes)->prefix,"-snes_mf_err",&mfctx->error_rel,NULL);CHKERRQ(ierr); ierr = PetscOptionsGetReal(((PetscObject)snes)->prefix,"-snes_mf_umin",&mfctx->umin,NULL);CHKERRQ(ierr); ierr = PetscOptionsGetBool(((PetscObject)snes)->prefix,"-snes_mf_jorge",&mfctx->jorge,NULL);CHKERRQ(ierr); ierr = PetscOptionsGetBool(((PetscObject)snes)->prefix,"-snes_mf_compute_err",&mfctx->compute_err,NULL);CHKERRQ(ierr); ierr = PetscOptionsGetInt(((PetscObject)snes)->prefix,"-snes_mf_freq_err",&mfctx->compute_err_freq,&flg);CHKERRQ(ierr); if (flg) { if (mfctx->compute_err_freq < 0) mfctx->compute_err_freq = 0; mfctx->compute_err = PETSC_TRUE; } if (mfctx->compute_err) mfctx->need_err = PETSC_TRUE; if (mfctx->jorge || mfctx->compute_err) { ierr = SNESDiffParameterCreate_More(snes,x,&mfctx->data);CHKERRQ(ierr); } else mfctx->data = 0; ierr = PetscOptionsHasName(NULL,"-help",&flg);CHKERRQ(ierr); ierr = PetscStrcpy(p,"-");CHKERRQ(ierr); if (((PetscObject)snes)->prefix) PetscStrcat(p,((PetscObject)snes)->prefix); if (flg) { ierr = PetscPrintf(PetscObjectComm((PetscObject)snes)," Matrix-free Options (via SNES):\n");CHKERRQ(ierr); ierr = PetscPrintf(PetscObjectComm((PetscObject)snes)," %ssnes_mf_err <err>: set sqrt of relative error in function (default %g)\n",p,(double)mfctx->error_rel);CHKERRQ(ierr); ierr = PetscPrintf(PetscObjectComm((PetscObject)snes)," %ssnes_mf_umin <umin>: see users manual (default %g)\n",p,(double)mfctx->umin);CHKERRQ(ierr); ierr = PetscPrintf(PetscObjectComm((PetscObject)snes)," %ssnes_mf_jorge: use Jorge More's method\n",p);CHKERRQ(ierr); ierr = PetscPrintf(PetscObjectComm((PetscObject)snes)," %ssnes_mf_compute_err: compute sqrt or relative error in function\n",p);CHKERRQ(ierr); ierr = PetscPrintf(PetscObjectComm((PetscObject)snes)," %ssnes_mf_freq_err <freq>: frequency to recompute this (default only once)\n",p);CHKERRQ(ierr); ierr = PetscPrintf(PetscObjectComm((PetscObject)snes)," %ssnes_mf_noise_file <file>: set file for printing noise info\n",p);CHKERRQ(ierr); } ierr = VecDuplicate(x,&mfctx->w);CHKERRQ(ierr); ierr = PetscObjectGetComm((PetscObject)x,&comm);CHKERRQ(ierr); ierr = VecGetSize(x,&n);CHKERRQ(ierr); ierr = VecGetLocalSize(x,&nloc);CHKERRQ(ierr); ierr = MatCreate(comm,J);CHKERRQ(ierr); ierr = MatSetSizes(*J,nloc,n,n,n);CHKERRQ(ierr); ierr = MatSetType(*J,MATSHELL);CHKERRQ(ierr); ierr = MatShellSetContext(*J,mfctx);CHKERRQ(ierr); ierr = MatShellSetOperation(*J,MATOP_MULT,(void (*)(void))SNESMatrixFreeMult2_Private);CHKERRQ(ierr); ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void (*)(void))SNESMatrixFreeDestroy2_Private);CHKERRQ(ierr); ierr = MatShellSetOperation(*J,MATOP_VIEW,(void (*)(void))SNESMatrixFreeView2_Private);CHKERRQ(ierr); ierr = PetscLogObjectParent((PetscObject)*J,(PetscObject)mfctx->w);CHKERRQ(ierr); ierr = PetscLogObjectParent((PetscObject)snes,(PetscObject)*J);CHKERRQ(ierr); PetscFunctionReturn(0); }
EXTERN_C_END #undef __FUNCT__ #define __FUNCT__ "MatCreateShell" /*@C MatCreateShell - Creates a new matrix class for use with a user-defined private data storage format. Collective on MPI_Comm Input Parameters: + comm - MPI communicator . m - number of local rows (must be given) . n - number of local columns (must be given) . M - number of global rows (may be PETSC_DETERMINE) . N - number of global columns (may be PETSC_DETERMINE) - ctx - pointer to data needed by the shell matrix routines Output Parameter: . A - the matrix Level: advanced Usage: $ extern int mult(Mat,Vec,Vec); $ MatCreateShell(comm,m,n,M,N,ctx,&mat); $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); $ [ Use matrix for operations that have been set ] $ MatDestroy(mat); Notes: The shell matrix type is intended to provide a simple class to use with KSP (such as, for use with matrix-free methods). You should not use the shell type if you plan to define a complete matrix class. Fortran Notes: The context can only be an integer or a PetscObject unfortunately it cannot be a Fortran array or derived type. PETSc requires that matrices and vectors being used for certain operations are partitioned accordingly. For example, when creating a shell matrix, A, that supports parallel matrix-vector products using MatMult(A,x,y) the user should set the number of local matrix rows to be the number of local elements of the corresponding result vector, y. Note that this is information is required for use of the matrix interface routines, even though the shell matrix may not actually be physically partitioned. For example, $ $ Vec x, y $ extern int mult(Mat,Vec,Vec); $ Mat A $ $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); $ VecGetLocalSize(y,&m); $ VecGetLocalSize(x,&n); $ MatCreateShell(comm,m,n,M,N,ctx,&A); $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); $ MatMult(A,x,y); $ MatDestroy(A); $ VecDestroy(y); VecDestroy(x); $ .keywords: matrix, shell, create .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext() @*/ PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) { PetscErrorCode ierr; PetscFunctionBegin; ierr = MatCreate(comm,A);CHKERRQ(ierr); ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr); ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); ierr = MatSetUp(*A);CHKERRQ(ierr); PetscFunctionReturn(0); }
int main(int argc, char **argv) { DM dm; /* Problem specification */ DM dmAux; /* Material specification */ SNES snes; /* nonlinear solver */ Vec u,r; /* solution, residual vectors */ Mat A,J; /* Jacobian matrix */ MatNullSpace nullSpace; /* May be necessary for Neumann conditions */ AppCtx user; /* user-defined work context */ JacActionCtx userJ; /* context for Jacobian MF action */ PetscInt its; /* iterations for convergence */ PetscReal error = 0.0; /* L_2 error in the solution */ PetscInt numComponents; PetscErrorCode ierr; ierr = PetscInitialize(&argc, &argv, NULL, help);CHKERRQ(ierr); ierr = ProcessOptions(PETSC_COMM_WORLD, &user);CHKERRQ(ierr); ierr = SNESCreate(PETSC_COMM_WORLD, &snes);CHKERRQ(ierr); ierr = CreateMesh(PETSC_COMM_WORLD, &user, &dm);CHKERRQ(ierr); ierr = SNESSetDM(snes, dm);CHKERRQ(ierr); ierr = DMSetApplicationContext(dm, &user);CHKERRQ(ierr); user.fem.fe = user.fe; ierr = PetscFECreateDefault(dm, user.dim, 1, PETSC_TRUE, NULL, -1, &user.fe[0]);CHKERRQ(ierr); if (user.bcType != NEUMANN) { user.fem.feBd = NULL; user.feBd[0] = NULL; } else { user.fem.feBd = user.feBd; ierr = PetscFECreateDefault(dm, user.dim-1, 1, PETSC_TRUE, "bd_", -1, &user.feBd[0]);CHKERRQ(ierr); } ierr = PetscFEGetNumComponents(user.fe[0], &numComponents);CHKERRQ(ierr); ierr = PetscMalloc(NUM_FIELDS * sizeof(void (*)(const PetscReal[], PetscScalar *, void *)), &user.exactFuncs);CHKERRQ(ierr); ierr = SetupProblem(dm, &user);CHKERRQ(ierr); ierr = SetupSection(dm, &user);CHKERRQ(ierr); /* Setup Material */ ierr = DMClone(dm, &dmAux);CHKERRQ(ierr); ierr = DMPlexCopyCoordinates(dm, dmAux);CHKERRQ(ierr); if (user.variableCoefficient != COEFF_FIELD) { user.fem.feAux = NULL; user.feAux[0] = NULL; } else { PetscQuadrature q; user.fem.feAux = user.feAux; ierr = PetscFECreateDefault(dmAux, user.dim, 1, PETSC_TRUE, "mat_", -1, &user.feAux[0]);CHKERRQ(ierr); ierr = PetscFEGetQuadrature(user.fe[0], &q);CHKERRQ(ierr); ierr = PetscFESetQuadrature(user.feAux[0], q);CHKERRQ(ierr); } ierr = SetupMaterialSection(dmAux, &user);CHKERRQ(ierr); ierr = SetupMaterial(dm, dmAux, &user);CHKERRQ(ierr); ierr = DMDestroy(&dmAux);CHKERRQ(ierr); ierr = DMCreateGlobalVector(dm, &u);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) u, "potential");CHKERRQ(ierr); ierr = VecDuplicate(u, &r);CHKERRQ(ierr); ierr = DMSetMatType(dm,MATAIJ);CHKERRQ(ierr); ierr = DMCreateMatrix(dm, &J);CHKERRQ(ierr); if (user.jacobianMF) { PetscInt M, m, N, n; ierr = MatGetSize(J, &M, &N);CHKERRQ(ierr); ierr = MatGetLocalSize(J, &m, &n);CHKERRQ(ierr); ierr = MatCreate(PETSC_COMM_WORLD, &A);CHKERRQ(ierr); ierr = MatSetSizes(A, m, n, M, N);CHKERRQ(ierr); ierr = MatSetType(A, MATSHELL);CHKERRQ(ierr); ierr = MatSetUp(A);CHKERRQ(ierr); #if 0 ierr = MatShellSetOperation(A, MATOP_MULT, (void (*)(void))FormJacobianAction);CHKERRQ(ierr); #endif userJ.dm = dm; userJ.J = J; userJ.user = &user; ierr = DMCreateLocalVector(dm, &userJ.u);CHKERRQ(ierr); ierr = DMPlexProjectFunctionLocal(dm, user.fe, user.exactFuncs, NULL, INSERT_BC_VALUES, userJ.u);CHKERRQ(ierr); ierr = MatShellSetContext(A, &userJ);CHKERRQ(ierr); } else { A = J; } if (user.bcType == NEUMANN) { ierr = MatNullSpaceCreate(PetscObjectComm((PetscObject) dm), PETSC_TRUE, 0, NULL, &nullSpace);CHKERRQ(ierr); ierr = MatSetNullSpace(J, nullSpace);CHKERRQ(ierr); if (A != J) { ierr = MatSetNullSpace(A, nullSpace);CHKERRQ(ierr); } } ierr = DMSNESSetFunctionLocal(dm, (PetscErrorCode (*)(DM,Vec,Vec,void*)) DMPlexComputeResidualFEM, &user);CHKERRQ(ierr); ierr = DMSNESSetJacobianLocal(dm, (PetscErrorCode (*)(DM,Vec,Mat,Mat,void*)) DMPlexComputeJacobianFEM, &user);CHKERRQ(ierr); ierr = SNESSetJacobian(snes, A, J, NULL, NULL);CHKERRQ(ierr); ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); ierr = DMPlexProjectFunction(dm, user.fe, user.exactFuncs, NULL, INSERT_ALL_VALUES, u);CHKERRQ(ierr); if (user.checkpoint) { #if defined(PETSC_HAVE_HDF5) ierr = PetscViewerHDF5PushGroup(user.checkpoint, "/fields");CHKERRQ(ierr); ierr = VecLoad(u, user.checkpoint);CHKERRQ(ierr); ierr = PetscViewerHDF5PopGroup(user.checkpoint);CHKERRQ(ierr); #endif } ierr = PetscViewerDestroy(&user.checkpoint);CHKERRQ(ierr); if (user.showInitial) { Vec lv; ierr = DMGetLocalVector(dm, &lv);CHKERRQ(ierr); ierr = DMGlobalToLocalBegin(dm, u, INSERT_VALUES, lv);CHKERRQ(ierr); ierr = DMGlobalToLocalEnd(dm, u, INSERT_VALUES, lv);CHKERRQ(ierr); ierr = DMPrintLocalVec(dm, "Local function", 1.0e-10, lv);CHKERRQ(ierr); ierr = DMRestoreLocalVector(dm, &lv);CHKERRQ(ierr); } if (user.runType == RUN_FULL) { void (*initialGuess[numComponents])(const PetscReal x[], PetscScalar *, void *ctx); PetscInt c; for (c = 0; c < numComponents; ++c) initialGuess[c] = zero; ierr = DMPlexProjectFunction(dm, user.fe, initialGuess, NULL, INSERT_VALUES, u);CHKERRQ(ierr); if (user.debug) { ierr = PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");CHKERRQ(ierr); ierr = VecView(u, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } ierr = SNESSolve(snes, NULL, u);CHKERRQ(ierr); ierr = SNESGetIterationNumber(snes, &its);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %D\n", its);CHKERRQ(ierr); ierr = DMPlexComputeL2Diff(dm, user.fe, user.exactFuncs, NULL, u, &error);CHKERRQ(ierr); if (error < 1.0e-11) {ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: < 1.0e-11\n");CHKERRQ(ierr);} else {ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %g\n", error);CHKERRQ(ierr);} if (user.showSolution) { ierr = PetscPrintf(PETSC_COMM_WORLD, "Solution\n");CHKERRQ(ierr); ierr = VecChop(u, 3.0e-9);CHKERRQ(ierr); ierr = VecView(u, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } } else if (user.runType == RUN_PERF) { PetscReal res = 0.0; ierr = SNESComputeFunction(snes, u, r);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Initial Residual\n");CHKERRQ(ierr); ierr = VecChop(r, 1.0e-10);CHKERRQ(ierr); ierr = VecNorm(r, NORM_2, &res);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Residual: %g\n", res);CHKERRQ(ierr); } else { PetscReal res = 0.0; /* Check discretization error */ ierr = PetscPrintf(PETSC_COMM_WORLD, "Initial guess\n");CHKERRQ(ierr); ierr = VecView(u, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = DMPlexComputeL2Diff(dm, user.fe, user.exactFuncs, NULL, u, &error);CHKERRQ(ierr); if (error < 1.0e-11) {ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: < 1.0e-11\n");CHKERRQ(ierr);} else {ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %g\n", error);CHKERRQ(ierr);} /* Check residual */ ierr = SNESComputeFunction(snes, u, r);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Initial Residual\n");CHKERRQ(ierr); ierr = VecChop(r, 1.0e-10);CHKERRQ(ierr); ierr = VecView(r, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecNorm(r, NORM_2, &res);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Residual: %g\n", res);CHKERRQ(ierr); /* Check Jacobian */ { Vec b; ierr = SNESComputeJacobian(snes, u, A, A);CHKERRQ(ierr); ierr = VecDuplicate(u, &b);CHKERRQ(ierr); ierr = VecSet(r, 0.0);CHKERRQ(ierr); ierr = SNESComputeFunction(snes, r, b);CHKERRQ(ierr); ierr = MatMult(A, u, r);CHKERRQ(ierr); ierr = VecAXPY(r, 1.0, b);CHKERRQ(ierr); ierr = VecDestroy(&b);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Au - b = Au + F(0)\n");CHKERRQ(ierr); ierr = VecChop(r, 1.0e-10);CHKERRQ(ierr); ierr = VecView(r, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecNorm(r, NORM_2, &res);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Linear L_2 Residual: %g\n", res);CHKERRQ(ierr); } } ierr = VecViewFromOptions(u, NULL, "-vec_view");CHKERRQ(ierr); if (user.bcType == NEUMANN) { ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr); } if (user.jacobianMF) { ierr = VecDestroy(&userJ.u);CHKERRQ(ierr); } if (A != J) {ierr = MatDestroy(&A);CHKERRQ(ierr);} ierr = PetscFEDestroy(&user.fe[0]);CHKERRQ(ierr); ierr = PetscFEDestroy(&user.feBd[0]);CHKERRQ(ierr); ierr = PetscFEDestroy(&user.feAux[0]);CHKERRQ(ierr); ierr = MatDestroy(&J);CHKERRQ(ierr); ierr = VecDestroy(&u);CHKERRQ(ierr); ierr = VecDestroy(&r);CHKERRQ(ierr); ierr = SNESDestroy(&snes);CHKERRQ(ierr); ierr = DMDestroy(&dm);CHKERRQ(ierr); ierr = PetscFree(user.exactFuncs);CHKERRQ(ierr); ierr = PetscFinalize(); return 0; }
/*@ DMGlobalToLocalSolve - Solve for the global vector that is mapped to a given local vector by DMGlobalToLocalBegin()/DMGlobalToLocalEnd() with mode = INSERT_VALUES. It is assumed that the sum of all the local vector sizes is greater than or equal to the global vector size, so the solution is a least-squares solution. It is also assumed that DMLocalToGlobalBegin()/DMLocalToGlobalEnd() with mode = ADD_VALUES is the adjoint of the global-to-local map, so that the least-squares solution may be found by the normal equations. collective Input Parameters: + dm - The DM object . x - The local vector - y - The global vector: the input value of globalVec is used as an initial guess Output Parameters: . y - The least-squares solution Level: advanced Note: If the DM is of type DMPLEX, then y is the solution of L' * D * L * y = L' * D * x, where D is a diagonal mask that is 1 for every point in the union of the closures of the local cells and 0 otherwise. This difference is only relevant if there are anchor points that are not in the closure of any local cell (see DMPlexGetAnchors()/DMPlexSetAnchors()). .seealso: DMGlobalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd(), DMPlexGetAnchors(), DMPlexSetAnchors() @*/ PetscErrorCode DMGlobalToLocalSolve(DM dm, Vec x, Vec y) { Mat CtC; PetscInt n, N, cStart, cEnd, c; PetscBool isPlex; KSP ksp; PC pc; Vec global, mask=NULL; projectConstraintsCtx ctx; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isPlex);CHKERRQ(ierr); if (isPlex) { /* mark points in the closure */ ierr = DMGetLocalVector(dm,&mask);CHKERRQ(ierr); ierr = VecSet(mask,0.0);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr); if (cEnd > cStart) { PetscScalar *ones; PetscInt numValues, i; ierr = DMPlexVecGetClosure(dm,NULL,mask,cStart,&numValues,NULL);CHKERRQ(ierr); ierr = PetscMalloc1(numValues,&ones);CHKERRQ(ierr); for (i = 0; i < numValues; i++) { ones[i] = 1.; } for (c = cStart; c < cEnd; c++) { ierr = DMPlexVecSetClosure(dm,NULL,mask,c,ones,INSERT_VALUES);CHKERRQ(ierr); } ierr = PetscFree(ones);CHKERRQ(ierr); } } ctx.dm = dm; ctx.mask = mask; ierr = VecGetSize(y,&N);CHKERRQ(ierr); ierr = VecGetLocalSize(y,&n);CHKERRQ(ierr); ierr = MatCreate(PetscObjectComm((PetscObject)dm),&CtC);CHKERRQ(ierr); ierr = MatSetSizes(CtC,n,n,N,N);CHKERRQ(ierr); ierr = MatSetType(CtC,MATSHELL);CHKERRQ(ierr); ierr = MatSetUp(CtC);CHKERRQ(ierr); ierr = MatShellSetContext(CtC,&ctx);CHKERRQ(ierr); ierr = MatShellSetOperation(CtC,MATOP_MULT,(void(*)(void))MatMult_GlobalToLocalNormal);CHKERRQ(ierr); ierr = KSPCreate(PetscObjectComm((PetscObject)dm),&ksp);CHKERRQ(ierr); ierr = KSPSetOperators(ksp,CtC,CtC);CHKERRQ(ierr); ierr = KSPSetType(ksp,KSPCG);CHKERRQ(ierr); ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr); ierr = KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);CHKERRQ(ierr); ierr = KSPSetUp(ksp);CHKERRQ(ierr); ierr = DMGetGlobalVector(dm,&global);CHKERRQ(ierr); ierr = VecSet(global,0.);CHKERRQ(ierr); if (mask) {ierr = VecPointwiseMult(x,mask,x);CHKERRQ(ierr);} ierr = DMLocalToGlobalBegin(dm,x,ADD_VALUES,global);CHKERRQ(ierr); ierr = DMLocalToGlobalEnd(dm,x,ADD_VALUES,global);CHKERRQ(ierr); ierr = KSPSetFromOptions(ksp);CHKERRQ(ierr); ierr = KSPSolve(ksp,global,y);CHKERRQ(ierr); ierr = DMRestoreGlobalVector(dm,&global);CHKERRQ(ierr); /* clean up */ if (isPlex) { ierr = DMRestoreLocalVector(dm,&mask);CHKERRQ(ierr); } ierr = KSPDestroy(&ksp);CHKERRQ(ierr); ierr = MatDestroy(&CtC);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@ DMGlobalToLocalSolve - Solve for the global vector that is mapped to a given local vector by DMGlobalToLocalBegin()/DMGlobalToLocalEnd() with mode = INSERT_VALUES. It is assumed that the sum of all the local vector sizes is greater than or equal to the global vector size, so the solution is a least-squares solution. It is also assumed that DMLocalToGlobalBegin()/DMLocalToGlobalEnd() with mode = ADD_VALUES is the adjoint of the global-to-local map, so that the least-squares solution may be found by the normal equations. collective Input Parameters: + dm - The DM object . x - The local vector - y - The global vector: the input value of globalVec is used as an initial guess Output Parameters: . y - The least-squares solution Level: advanced Note: If the DM is of type DMPLEX, then y is the solution of L' * D * L * y = L' * D * x, where D is a diagonal mask that is 1 for every point in the union of the closures of the local cells and 0 otherwise. This difference is only relevant if there are anchor points that are not in the closure of any local cell (see DMPlexGetAnchors()/DMPlexSetAnchors()). .seealso: DMGlobalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd(), DMPlexGetAnchors(), DMPlexSetAnchors() @*/ PetscErrorCode DMGlobalToLocalSolve(DM dm, Vec x, Vec y) { Mat CtC; PetscInt n, N, cStart, cEnd, cEndInterior, c; PetscBool isPlex; KSP ksp; PC pc; Vec global, mask=NULL; projectConstraintsCtx ctx; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isPlex);CHKERRQ(ierr); if (isPlex) { /* mark points in the closure */ ierr = DMCreateLocalVector(dm,&mask);CHKERRQ(ierr); ierr = VecSet(mask,0.0);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr); ierr = DMPlexGetHybridBounds(dm,&cEndInterior,NULL,NULL,NULL);CHKERRQ(ierr); cEnd = cEndInterior < 0 ? cEnd : cEndInterior; if (cEnd > cStart) { PetscScalar *ones; PetscInt numValues, i; ierr = DMPlexVecGetClosure(dm,NULL,mask,cStart,&numValues,NULL);CHKERRQ(ierr); ierr = PetscMalloc1(numValues,&ones);CHKERRQ(ierr); for (i = 0; i < numValues; i++) { ones[i] = 1.; } for (c = cStart; c < cEnd; c++) { ierr = DMPlexVecSetClosure(dm,NULL,mask,c,ones,INSERT_VALUES);CHKERRQ(ierr); } ierr = PetscFree(ones);CHKERRQ(ierr); } } else { PetscBool hasMask; ierr = DMHasNamedLocalVector(dm, "_DMGlobalToLocalSolve_mask", &hasMask);CHKERRQ(ierr); if (!hasMask) { PetscErrorCode (**func) (PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx); void **ctx; PetscInt Nf, f; ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr); ierr = PetscMalloc2(Nf, &func, Nf, &ctx);CHKERRQ(ierr); for (f = 0; f < Nf; ++f) { func[f] = DMGlobalToLocalSolve_project1; ctx[f] = NULL; } ierr = DMGetNamedLocalVector(dm, "_DMGlobalToLocalSolve_mask", &mask);CHKERRQ(ierr); ierr = DMProjectFunctionLocal(dm,0.0,func,ctx,INSERT_ALL_VALUES,mask);CHKERRQ(ierr); ierr = DMRestoreNamedLocalVector(dm, "_DMGlobalToLocalSolve_mask", &mask);CHKERRQ(ierr); ierr = PetscFree2(func, ctx);CHKERRQ(ierr); } ierr = DMGetNamedLocalVector(dm, "_DMGlobalToLocalSolve_mask", &mask);CHKERRQ(ierr); } ctx.dm = dm; ctx.mask = mask; ierr = VecGetSize(y,&N);CHKERRQ(ierr); ierr = VecGetLocalSize(y,&n);CHKERRQ(ierr); ierr = MatCreate(PetscObjectComm((PetscObject)dm),&CtC);CHKERRQ(ierr); ierr = MatSetSizes(CtC,n,n,N,N);CHKERRQ(ierr); ierr = MatSetType(CtC,MATSHELL);CHKERRQ(ierr); ierr = MatSetUp(CtC);CHKERRQ(ierr); ierr = MatShellSetContext(CtC,&ctx);CHKERRQ(ierr); ierr = MatShellSetOperation(CtC,MATOP_MULT,(void(*)(void))MatMult_GlobalToLocalNormal);CHKERRQ(ierr); ierr = KSPCreate(PetscObjectComm((PetscObject)dm),&ksp);CHKERRQ(ierr); ierr = KSPSetOperators(ksp,CtC,CtC);CHKERRQ(ierr); ierr = KSPSetType(ksp,KSPCG);CHKERRQ(ierr); ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr); ierr = KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);CHKERRQ(ierr); ierr = KSPSetUp(ksp);CHKERRQ(ierr); ierr = DMGetGlobalVector(dm,&global);CHKERRQ(ierr); ierr = VecSet(global,0.);CHKERRQ(ierr); if (mask) {ierr = VecPointwiseMult(x,mask,x);CHKERRQ(ierr);} ierr = DMLocalToGlobalBegin(dm,x,ADD_VALUES,global);CHKERRQ(ierr); ierr = DMLocalToGlobalEnd(dm,x,ADD_VALUES,global);CHKERRQ(ierr); ierr = KSPSolve(ksp,global,y);CHKERRQ(ierr); ierr = DMRestoreGlobalVector(dm,&global);CHKERRQ(ierr); /* clean up */ ierr = KSPDestroy(&ksp);CHKERRQ(ierr); ierr = MatDestroy(&CtC);CHKERRQ(ierr); if (isPlex) { ierr = VecDestroy(&mask);CHKERRQ(ierr); } else { ierr = DMRestoreNamedLocalVector(dm, "_DMGlobalToLocalSolve_mask", &mask);CHKERRQ(ierr); } PetscFunctionReturn(0); }