PetscErrorCode BSSCR_PCGtKGAttachNullSpace( PC pc ) { PC_GtKG ctx = (PC_GtKG)pc->data; MatNullSpace nsp; BSSCR_pc_error( pc, "__func__" ); /* Attach a null space */ MatNullSpaceCreate( PETSC_COMM_WORLD, PETSC_TRUE, PETSC_NULL, PETSC_NULL, &nsp ); #if ( (PETSC_VERSION_MAJOR >= 3) && (PETSC_VERSION_MINOR <6) ) KSPSetNullSpace( ctx->ksp, nsp ); #else Mat A; KSPGetOperators(ctx->ksp,&A,NULL);//Note: DOES NOT increase the reference counts of the matrix, so you should NOT destroy them. MatSetNullSpace( A, nsp); #endif /* NOTE: This does NOT destroy the memory for nsp, it just decrements the nsp->refct, so that the next time MatNullSpaceDestroy() is called, the memory will be released. The next time this is called will be by KSPDestroy(); */ MatNullSpaceDestroy( nsp ); PetscFunctionReturn(0); }
PetscErrorCode ComputeJacobian(KSP ksp,Mat J, Mat jac,void *ctx) { PetscErrorCode ierr; PetscInt i, j, M, N, xm, ym, xs, ys, num, numi, numj; PetscScalar v[5], Hx, Hy, HydHx, HxdHy; MatStencil row, col[5]; DM da; MatNullSpace nullspace; PetscFunctionBeginUser; ierr = KSPGetDM(ksp,&da);CHKERRQ(ierr); ierr = DMDAGetInfo(da,0,&M,&N,0,0,0,0,0,0,0,0,0,0);CHKERRQ(ierr); Hx = 1.0 / (PetscReal)(M); Hy = 1.0 / (PetscReal)(N); HxdHy = Hx/Hy; HydHx = Hy/Hx; ierr = DMDAGetCorners(da,&xs,&ys,0,&xm,&ym,0);CHKERRQ(ierr); for (j=ys; j<ys+ym; j++) { for (i=xs; i<xs+xm; i++) { row.i = i; row.j = j; if (i==0 || j==0 || i==M-1 || j==N-1) { num=0; numi=0; numj=0; if (j!=0) { v[num] = -HxdHy; col[num].i = i; col[num].j = j-1; num++; numj++; } if (i!=0) { v[num] = -HydHx; col[num].i = i-1; col[num].j = j; num++; numi++; } if (i!=M-1) { v[num] = -HydHx; col[num].i = i+1; col[num].j = j; num++; numi++; } if (j!=N-1) { v[num] = -HxdHy; col[num].i = i; col[num].j = j+1; num++; numj++; } v[num] = ((PetscReal)(numj)*HxdHy + (PetscReal)(numi)*HydHx); col[num].i = i; col[num].j = j; num++; ierr = MatSetValuesStencil(jac,1,&row,num,col,v,INSERT_VALUES);CHKERRQ(ierr); } else { v[0] = -HxdHy; col[0].i = i; col[0].j = j-1; v[1] = -HydHx; col[1].i = i-1; col[1].j = j; v[2] = 2.0*(HxdHy + HydHx); col[2].i = i; col[2].j = j; v[3] = -HydHx; col[3].i = i+1; col[3].j = j; v[4] = -HxdHy; col[4].i = i; col[4].j = j+1; ierr = MatSetValuesStencil(jac,1,&row,5,col,v,INSERT_VALUES);CHKERRQ(ierr); } } } ierr = MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,0,&nullspace);CHKERRQ(ierr); ierr = MatSetNullSpace(J,nullspace);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nullspace);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode ComputeMatrix(KSP ksp, Mat J,Mat jac, void *ctx) { PetscErrorCode ierr; PetscInt i,j,k,mx,my,mz,xm,ym,zm,xs,ys,zs,num, numi, numj, numk; PetscScalar v[7],Hx,Hy,Hz,HyHzdHx,HxHzdHy,HxHydHz; MatStencil row, col[7]; DM da; MatNullSpace nullspace; PetscFunctionBeginUser; ierr = KSPGetDM(ksp,&da);CHKERRQ(ierr); ierr = DMDAGetInfo(da,0,&mx,&my,&mz,0,0,0,0,0,0,0,0,0);CHKERRQ(ierr); Hx = 1.0 / (PetscReal)(mx); Hy = 1.0 / (PetscReal)(my); Hz = 1.0 / (PetscReal)(mz); HyHzdHx = Hy*Hz/Hx; HxHzdHy = Hx*Hz/Hy; HxHydHz = Hx*Hy/Hz; ierr = DMDAGetCorners(da,&xs,&ys,&zs,&xm,&ym,&zm);CHKERRQ(ierr); for (k=zs; k<zs+zm; k++) { for (j=ys; j<ys+ym; j++) { for (i=xs; i<xs+xm; i++) { row.i = i; row.j = j; row.k = k; if (i==0 || j==0 || k==0 || i==mx-1 || j==my-1 || k==mz-1) { num = 0; numi=0; numj=0; numk=0; if (k!=0) { v[num] = -HxHydHz; col[num].i = i; col[num].j = j; col[num].k = k-1; num++; numk++; } if (j!=0) { v[num] = -HxHzdHy; col[num].i = i; col[num].j = j-1; col[num].k = k; num++; numj++; } if (i!=0) { v[num] = -HyHzdHx; col[num].i = i-1; col[num].j = j; col[num].k = k; num++; numi++; } if (i!=mx-1) { v[num] = -HyHzdHx; col[num].i = i+1; col[num].j = j; col[num].k = k; num++; numi++; } if (j!=my-1) { v[num] = -HxHzdHy; col[num].i = i; col[num].j = j+1; col[num].k = k; num++; numj++; } if (k!=mz-1) { v[num] = -HxHydHz; col[num].i = i; col[num].j = j; col[num].k = k+1; num++; numk++; } v[num] = (PetscReal)(numk)*HxHydHz + (PetscReal)(numj)*HxHzdHy + (PetscReal)(numi)*HyHzdHx; col[num].i = i; col[num].j = j; col[num].k = k; num++; ierr = MatSetValuesStencil(jac,1,&row,num,col,v,INSERT_VALUES);CHKERRQ(ierr); } else { v[0] = -HxHydHz; col[0].i = i; col[0].j = j; col[0].k = k-1; v[1] = -HxHzdHy; col[1].i = i; col[1].j = j-1; col[1].k = k; v[2] = -HyHzdHx; col[2].i = i-1; col[2].j = j; col[2].k = k; v[3] = 2.0*(HyHzdHx + HxHzdHy + HxHydHz); col[3].i = i; col[3].j = j; col[3].k = k; v[4] = -HyHzdHx; col[4].i = i+1; col[4].j = j; col[4].k = k; v[5] = -HxHzdHy; col[5].i = i; col[5].j = j+1; col[5].k = k; v[6] = -HxHydHz; col[6].i = i; col[6].j = j; col[6].k = k+1; ierr = MatSetValuesStencil(jac,1,&row,7,col,v,INSERT_VALUES);CHKERRQ(ierr); } } } } ierr = MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,0,&nullspace);CHKERRQ(ierr); ierr = MatSetNullSpace(jac,nullspace);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nullspace);CHKERRQ(ierr); PetscFunctionReturn(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; }
/* PCISSetUp - */ PetscErrorCode PCISSetUp(PC pc, PetscBool computesolvers) { PC_IS *pcis = (PC_IS*)(pc->data); Mat_IS *matis; MatReuse reuse; PetscErrorCode ierr; PetscBool flg,issbaij; Vec counter; PetscFunctionBegin; ierr = PetscObjectTypeCompare((PetscObject)pc->pmat,MATIS,&flg);CHKERRQ(ierr); if (!flg) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG,"Preconditioner type of Neumann Neumman requires matrix of type MATIS"); matis = (Mat_IS*)pc->pmat->data; /* first time creation, get info on substructuring */ if (!pc->setupcalled) { PetscInt n_I; PetscInt *idx_I_local,*idx_B_local,*idx_I_global,*idx_B_global; PetscBT bt; PetscInt i,j; /* get info on mapping */ ierr = PetscObjectReference((PetscObject)pc->pmat->rmap->mapping);CHKERRQ(ierr); ierr = ISLocalToGlobalMappingDestroy(&pcis->mapping);CHKERRQ(ierr); pcis->mapping = pc->pmat->rmap->mapping; ierr = ISLocalToGlobalMappingGetSize(pcis->mapping,&pcis->n);CHKERRQ(ierr); ierr = ISLocalToGlobalMappingGetInfo(pcis->mapping,&(pcis->n_neigh),&(pcis->neigh),&(pcis->n_shared),&(pcis->shared));CHKERRQ(ierr); /* Identifying interior and interface nodes, in local numbering */ ierr = PetscBTCreate(pcis->n,&bt);CHKERRQ(ierr); for (i=0;i<pcis->n_neigh;i++) for (j=0;j<pcis->n_shared[i];j++) { ierr = PetscBTSet(bt,pcis->shared[i][j]);CHKERRQ(ierr); } /* Creating local and global index sets for interior and inteface nodes. */ ierr = PetscMalloc1(pcis->n,&idx_I_local);CHKERRQ(ierr); ierr = PetscMalloc1(pcis->n,&idx_B_local);CHKERRQ(ierr); for (i=0, pcis->n_B=0, n_I=0; i<pcis->n; i++) { if (!PetscBTLookup(bt,i)) { idx_I_local[n_I] = i; n_I++; } else { idx_B_local[pcis->n_B] = i; pcis->n_B++; } } /* Getting the global numbering */ idx_B_global = idx_I_local + n_I; /* Just avoiding allocating extra memory, since we have vacant space */ idx_I_global = idx_B_local + pcis->n_B; ierr = ISLocalToGlobalMappingApply(pcis->mapping,pcis->n_B,idx_B_local,idx_B_global);CHKERRQ(ierr); ierr = ISLocalToGlobalMappingApply(pcis->mapping,n_I,idx_I_local,idx_I_global);CHKERRQ(ierr); /* Creating the index sets */ ierr = ISCreateGeneral(PETSC_COMM_SELF,pcis->n_B,idx_B_local,PETSC_COPY_VALUES, &pcis->is_B_local);CHKERRQ(ierr); ierr = ISCreateGeneral(PETSC_COMM_SELF,pcis->n_B,idx_B_global,PETSC_COPY_VALUES,&pcis->is_B_global);CHKERRQ(ierr); ierr = ISCreateGeneral(PETSC_COMM_SELF,n_I,idx_I_local,PETSC_COPY_VALUES, &pcis->is_I_local);CHKERRQ(ierr); ierr = ISCreateGeneral(PETSC_COMM_SELF,n_I,idx_I_global,PETSC_COPY_VALUES,&pcis->is_I_global);CHKERRQ(ierr); /* Freeing memory */ ierr = PetscFree(idx_B_local);CHKERRQ(ierr); ierr = PetscFree(idx_I_local);CHKERRQ(ierr); ierr = PetscBTDestroy(&bt);CHKERRQ(ierr); /* Creating work vectors and arrays */ ierr = VecDuplicate(matis->x,&pcis->vec1_N);CHKERRQ(ierr); ierr = VecDuplicate(pcis->vec1_N,&pcis->vec2_N);CHKERRQ(ierr); ierr = VecCreateSeq(PETSC_COMM_SELF,pcis->n-pcis->n_B,&pcis->vec1_D);CHKERRQ(ierr); ierr = VecDuplicate(pcis->vec1_D,&pcis->vec2_D);CHKERRQ(ierr); ierr = VecDuplicate(pcis->vec1_D,&pcis->vec3_D);CHKERRQ(ierr); ierr = VecDuplicate(pcis->vec1_D,&pcis->vec4_D);CHKERRQ(ierr); ierr = VecCreateSeq(PETSC_COMM_SELF,pcis->n_B,&pcis->vec1_B);CHKERRQ(ierr); ierr = VecDuplicate(pcis->vec1_B,&pcis->vec2_B);CHKERRQ(ierr); ierr = VecDuplicate(pcis->vec1_B,&pcis->vec3_B);CHKERRQ(ierr); ierr = MatCreateVecs(pc->pmat,&pcis->vec1_global,0);CHKERRQ(ierr); ierr = PetscMalloc1(pcis->n,&pcis->work_N);CHKERRQ(ierr); /* scaling vector */ if (!pcis->D) { /* it can happen that the user passed in a scaling vector via PCISSetSubdomainDiagonalScaling */ ierr = VecDuplicate(pcis->vec1_B,&pcis->D);CHKERRQ(ierr); ierr = VecSet(pcis->D,pcis->scaling_factor);CHKERRQ(ierr); } /* Creating the scatter contexts */ ierr = VecScatterCreate(pcis->vec1_N,pcis->is_I_local,pcis->vec1_D,(IS)0,&pcis->N_to_D);CHKERRQ(ierr); ierr = VecScatterCreate(pcis->vec1_global,pcis->is_I_global,pcis->vec1_D,(IS)0,&pcis->global_to_D);CHKERRQ(ierr); ierr = VecScatterCreate(pcis->vec1_N,pcis->is_B_local,pcis->vec1_B,(IS)0,&pcis->N_to_B);CHKERRQ(ierr); ierr = VecScatterCreate(pcis->vec1_global,pcis->is_B_global,pcis->vec1_B,(IS)0,&pcis->global_to_B);CHKERRQ(ierr); /* map from boundary to local */ ierr = ISLocalToGlobalMappingCreateIS(pcis->is_B_local,&pcis->BtoNmap);CHKERRQ(ierr); } /* Extracting the blocks A_II, A_BI, A_IB and A_BB from A. If the numbering is such that interior nodes come first than the interface ones, we have [ A_II | A_IB ] A = [------+------] [ A_BI | A_BB ] */ reuse = MAT_INITIAL_MATRIX; if (pcis->reusesubmatrices && pc->setupcalled) { if (pc->flag == SAME_NONZERO_PATTERN) { reuse = MAT_REUSE_MATRIX; } else { reuse = MAT_INITIAL_MATRIX; } } if (reuse == MAT_INITIAL_MATRIX) { ierr = MatDestroy(&pcis->A_II);CHKERRQ(ierr); ierr = MatDestroy(&pcis->A_IB);CHKERRQ(ierr); ierr = MatDestroy(&pcis->A_BI);CHKERRQ(ierr); ierr = MatDestroy(&pcis->A_BB);CHKERRQ(ierr); } ierr = MatGetSubMatrix(matis->A,pcis->is_I_local,pcis->is_I_local,reuse,&pcis->A_II);CHKERRQ(ierr); ierr = MatGetSubMatrix(matis->A,pcis->is_B_local,pcis->is_B_local,reuse,&pcis->A_BB);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr); if (!issbaij) { ierr = MatGetSubMatrix(matis->A,pcis->is_I_local,pcis->is_B_local,reuse,&pcis->A_IB);CHKERRQ(ierr); ierr = MatGetSubMatrix(matis->A,pcis->is_B_local,pcis->is_I_local,reuse,&pcis->A_BI);CHKERRQ(ierr); } else { Mat newmat; ierr = MatConvert(matis->A,MATSEQBAIJ,MAT_INITIAL_MATRIX,&newmat);CHKERRQ(ierr); ierr = MatGetSubMatrix(newmat,pcis->is_I_local,pcis->is_B_local,reuse,&pcis->A_IB);CHKERRQ(ierr); ierr = MatGetSubMatrix(newmat,pcis->is_B_local,pcis->is_I_local,reuse,&pcis->A_BI);CHKERRQ(ierr); ierr = MatDestroy(&newmat);CHKERRQ(ierr); } /* Creating scaling vector D */ ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_is_use_stiffness_scaling",&pcis->use_stiffness_scaling,NULL);CHKERRQ(ierr); if (pcis->use_stiffness_scaling) { ierr = MatGetDiagonal(pcis->A_BB,pcis->D);CHKERRQ(ierr); } ierr = MatCreateVecs(pc->pmat,&counter,0);CHKERRQ(ierr); /* temporary auxiliar vector */ ierr = VecSet(counter,0.0);CHKERRQ(ierr); ierr = VecScatterBegin(pcis->global_to_B,pcis->D,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterEnd(pcis->global_to_B,pcis->D,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterBegin(pcis->global_to_B,counter,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(pcis->global_to_B,counter,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecPointwiseDivide(pcis->D,pcis->D,pcis->vec1_B);CHKERRQ(ierr); ierr = VecDestroy(&counter);CHKERRQ(ierr); /* See historical note 01, at the bottom of this file. */ /* Creating the KSP contexts for the local Dirichlet and Neumann problems */ if (computesolvers) { PC pc_ctx; pcis->pure_neumann = matis->pure_neumann; /* Dirichlet */ ierr = KSPCreate(PETSC_COMM_SELF,&pcis->ksp_D);CHKERRQ(ierr); ierr = KSPSetErrorIfNotConverged(pcis->ksp_D,pc->erroriffailure);CHKERRQ(ierr); ierr = PetscObjectIncrementTabLevel((PetscObject)pcis->ksp_D,(PetscObject)pc,1);CHKERRQ(ierr); ierr = KSPSetOperators(pcis->ksp_D,pcis->A_II,pcis->A_II);CHKERRQ(ierr); ierr = KSPSetOptionsPrefix(pcis->ksp_D,"is_localD_");CHKERRQ(ierr); ierr = KSPGetPC(pcis->ksp_D,&pc_ctx);CHKERRQ(ierr); ierr = PCSetType(pc_ctx,PCLU);CHKERRQ(ierr); ierr = KSPSetType(pcis->ksp_D,KSPPREONLY);CHKERRQ(ierr); ierr = KSPSetFromOptions(pcis->ksp_D);CHKERRQ(ierr); /* the vectors in the following line are dummy arguments, just telling the KSP the vector size. Values are not used */ ierr = KSPSetUp(pcis->ksp_D);CHKERRQ(ierr); /* Neumann */ ierr = KSPCreate(PETSC_COMM_SELF,&pcis->ksp_N);CHKERRQ(ierr); ierr = KSPSetErrorIfNotConverged(pcis->ksp_N,pc->erroriffailure);CHKERRQ(ierr); ierr = PetscObjectIncrementTabLevel((PetscObject)pcis->ksp_N,(PetscObject)pc,1);CHKERRQ(ierr); ierr = KSPSetOperators(pcis->ksp_N,matis->A,matis->A);CHKERRQ(ierr); ierr = KSPSetOptionsPrefix(pcis->ksp_N,"is_localN_");CHKERRQ(ierr); ierr = KSPGetPC(pcis->ksp_N,&pc_ctx);CHKERRQ(ierr); ierr = PCSetType(pc_ctx,PCLU);CHKERRQ(ierr); ierr = KSPSetType(pcis->ksp_N,KSPPREONLY);CHKERRQ(ierr); ierr = KSPSetFromOptions(pcis->ksp_N);CHKERRQ(ierr); { PetscBool damp_fixed = PETSC_FALSE, remove_nullspace_fixed = PETSC_FALSE, set_damping_factor_floating = PETSC_FALSE, not_damp_floating = PETSC_FALSE, not_remove_nullspace_floating = PETSC_FALSE; PetscReal fixed_factor, floating_factor; ierr = PetscOptionsGetReal(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_damp_fixed",&fixed_factor,&damp_fixed);CHKERRQ(ierr); if (!damp_fixed) fixed_factor = 0.0; ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_damp_fixed",&damp_fixed,NULL);CHKERRQ(ierr); ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_remove_nullspace_fixed",&remove_nullspace_fixed,NULL);CHKERRQ(ierr); ierr = PetscOptionsGetReal(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_set_damping_factor_floating", &floating_factor,&set_damping_factor_floating);CHKERRQ(ierr); if (!set_damping_factor_floating) floating_factor = 0.0; ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_set_damping_factor_floating",&set_damping_factor_floating,NULL);CHKERRQ(ierr); if (!set_damping_factor_floating) floating_factor = 1.e-12; ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_not_damp_floating",¬_damp_floating,NULL);CHKERRQ(ierr); ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_not_remove_nullspace_floating",¬_remove_nullspace_floating,NULL);CHKERRQ(ierr); if (pcis->pure_neumann) { /* floating subdomain */ if (!(not_damp_floating)) { ierr = PCFactorSetShiftType(pc_ctx,MAT_SHIFT_NONZERO);CHKERRQ(ierr); ierr = PCFactorSetShiftAmount(pc_ctx,floating_factor);CHKERRQ(ierr); } if (!(not_remove_nullspace_floating)) { MatNullSpace nullsp; ierr = MatNullSpaceCreate(PETSC_COMM_SELF,PETSC_TRUE,0,NULL,&nullsp);CHKERRQ(ierr); ierr = MatSetNullSpace(matis->A,nullsp);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nullsp);CHKERRQ(ierr); } } else { /* fixed subdomain */ if (damp_fixed) { ierr = PCFactorSetShiftType(pc_ctx,MAT_SHIFT_NONZERO);CHKERRQ(ierr); ierr = PCFactorSetShiftAmount(pc_ctx,floating_factor);CHKERRQ(ierr); } if (remove_nullspace_fixed) { MatNullSpace nullsp; ierr = MatNullSpaceCreate(PETSC_COMM_SELF,PETSC_TRUE,0,NULL,&nullsp);CHKERRQ(ierr); ierr = MatSetNullSpace(matis->A,nullsp);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nullsp);CHKERRQ(ierr); } } } /* the vectors in the following line are dummy arguments, just telling the KSP the vector size. Values are not used */ ierr = KSPSetUp(pcis->ksp_N);CHKERRQ(ierr); } PetscFunctionReturn(0); }
int main(int argc,char **argv) { SNES snes; /* SNES context */ Mat J; /* Jacobian matrix */ DM da; Vec x,r; /* vectors */ PetscErrorCode ierr; PetscInt N = 5; MatNullSpace constants; ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr; ierr = PetscOptionsGetInt(NULL,NULL,"-n",&N,NULL);CHKERRQ(ierr); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create nonlinear solver context - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = SNESCreate(PETSC_COMM_WORLD,&snes);CHKERRQ(ierr); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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_PERIODIC,N,1,1,NULL,&da);CHKERRQ(ierr); ierr = DMSetFromOptions(da);CHKERRQ(ierr); ierr = DMSetUp(da);CHKERRQ(ierr); /* Extract global and local vectors from DMDA; then duplicate for remaining vectors that are the same types */ ierr = DMCreateGlobalVector(da,&x);CHKERRQ(ierr); ierr = VecDuplicate(x,&r);CHKERRQ(ierr); /* Set function evaluation routine and vector. Whenever the nonlinear solver needs to compute the nonlinear function, it will call this routine. - Note that the final routine argument is the user-defined context that provides application-specific data for the function evaluation routine. */ ierr = SNESSetFunction(snes,r,FormFunction,da);CHKERRQ(ierr); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create matrix data structure; set Jacobian evaluation routine - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = DMCreateMatrix(da,&J);CHKERRQ(ierr); ierr = MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,NULL,&constants);CHKERRQ(ierr); ierr = MatSetNullSpace(J,constants);CHKERRQ(ierr); ierr = SNESSetJacobian(snes,J,J,FormJacobian,da);CHKERRQ(ierr); ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); ierr = SNESSolve(snes,NULL,x);CHKERRQ(ierr); ierr = VecDestroy(&x);CHKERRQ(ierr); ierr = VecDestroy(&r);CHKERRQ(ierr); ierr = MatDestroy(&J);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&constants);CHKERRQ(ierr); ierr = SNESDestroy(&snes);CHKERRQ(ierr); ierr = DMDestroy(&da);CHKERRQ(ierr); ierr = PetscFinalize(); return ierr; }
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; }
int main(int argc,char **args) { PetscErrorCode ierr; Mat C; PetscMPIInt rank,size; PetscInt i,m = 5,N,start,end,M; PetscInt idx[4]; PetscScalar Ke[16]; PetscReal h; Vec u,b; KSP ksp; MatNullSpace nullsp; ierr = PetscInitialize(&argc,&args,(char*)0,help);if (ierr) return ierr; ierr = PetscOptionsGetInt(NULL,NULL,"-m",&m,NULL);CHKERRQ(ierr); N = (m+1)*(m+1); /* dimension of matrix */ M = m*m; /* number of elements */ h = 1.0/m; /* mesh width */ ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr); ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr); /* Create stiffness matrix */ ierr = MatCreate(PETSC_COMM_WORLD,&C);CHKERRQ(ierr); ierr = MatSetSizes(C,PETSC_DECIDE,PETSC_DECIDE,N,N);CHKERRQ(ierr); ierr = MatSetFromOptions(C);CHKERRQ(ierr); ierr = MatSetUp(C);CHKERRQ(ierr); start = rank*(M/size) + ((M%size) < rank ? (M%size) : rank); end = start + M/size + ((M%size) > rank); /* Assemble matrix */ ierr = FormElementStiffness(h*h,Ke);CHKERRQ(ierr); /* element stiffness for Laplacian */ for (i=start; i<end; i++) { /* location of lower left corner of element */ /* node numbers for the four corners of element */ idx[0] = (m+1)*(i/m) + (i % m); idx[1] = idx[0]+1; idx[2] = idx[1] + m + 1; idx[3] = idx[2] - 1; ierr = MatSetValues(C,4,idx,4,idx,Ke,ADD_VALUES);CHKERRQ(ierr); } ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); /* Create right-hand-side and solution vectors */ ierr = VecCreate(PETSC_COMM_WORLD,&u);CHKERRQ(ierr); ierr = VecSetSizes(u,PETSC_DECIDE,N);CHKERRQ(ierr); ierr = VecSetFromOptions(u);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject)u,"Approx. Solution");CHKERRQ(ierr); ierr = VecDuplicate(u,&b);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject)b,"Right hand side");CHKERRQ(ierr); ierr = VecSet(b,1.0);CHKERRQ(ierr); ierr = VecSetValue(b,0,1.2,ADD_VALUES);CHKERRQ(ierr); ierr = VecSet(u,0.0);CHKERRQ(ierr); /* Solve linear system */ ierr = KSPCreate(PETSC_COMM_WORLD,&ksp);CHKERRQ(ierr); ierr = KSPSetOperators(ksp,C,C);CHKERRQ(ierr); ierr = KSPSetFromOptions(ksp);CHKERRQ(ierr); ierr = KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);CHKERRQ(ierr); ierr = MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,NULL,&nullsp);CHKERRQ(ierr); /* The KSP solver will remove this nullspace from the solution at each iteration */ ierr = MatSetNullSpace(C,nullsp);CHKERRQ(ierr); /* The KSP solver will remove from the right hand side any portion in this nullspace, thus making the linear system consistent. */ ierr = MatSetTransposeNullSpace(C,nullsp);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nullsp);CHKERRQ(ierr); ierr = KSPSolve(ksp,b,u);CHKERRQ(ierr); /* Free work space */ ierr = KSPDestroy(&ksp);CHKERRQ(ierr); ierr = VecDestroy(&u);CHKERRQ(ierr); ierr = VecDestroy(&b);CHKERRQ(ierr); ierr = MatDestroy(&C);CHKERRQ(ierr); ierr = PetscFinalize(); return ierr; }
static PetscErrorCode ComputeKSPBDDC(DomainData dd,Mat A,KSP *ksp) { PetscErrorCode ierr; KSP temp_ksp; PC pc; IS dirichletIS=0,neumannIS=0,*bddc_dofs_splitting; PetscInt localsize,*xadj=NULL,*adjncy=NULL; MatNullSpace near_null_space; PetscFunctionBeginUser; ierr = KSPCreate(dd.gcomm,&temp_ksp);CHKERRQ(ierr); ierr = KSPSetOperators(temp_ksp,A,A);CHKERRQ(ierr); ierr = KSPSetType(temp_ksp,KSPCG);CHKERRQ(ierr); ierr = KSPGetPC(temp_ksp,&pc);CHKERRQ(ierr); ierr = PCSetType(pc,PCBDDC);CHKERRQ(ierr); localsize = dd.xm_l*dd.ym_l*dd.zm_l; /* BDDC customization */ /* jumping coefficients case */ ierr = PCISSetSubdomainScalingFactor(pc,dd.scalingfactor);CHKERRQ(ierr); /* Dofs splitting Simple stride-1 IS It is not needed since, by default, PCBDDC assumes a stride-1 split */ ierr = PetscMalloc1(1,&bddc_dofs_splitting);CHKERRQ(ierr); #if 1 ierr = ISCreateStride(PETSC_COMM_WORLD,localsize,0,1,&bddc_dofs_splitting[0]);CHKERRQ(ierr); ierr = PCBDDCSetDofsSplittingLocal(pc,1,bddc_dofs_splitting);CHKERRQ(ierr); #else /* examples for global ordering */ /* each process lists the nodes it owns */ PetscInt sr,er; ierr = MatGetOwnershipRange(A,&sr,&er);CHKERRQ(ierr); ierr = ISCreateStride(PETSC_COMM_WORLD,er-sr,sr,1,&bddc_dofs_splitting[0]);CHKERRQ(ierr); ierr = PCBDDCSetDofsSplitting(pc,1,bddc_dofs_splitting);CHKERRQ(ierr); /* Split can be passed in a more general way since any process can list any node */ #endif ierr = ISDestroy(&bddc_dofs_splitting[0]);CHKERRQ(ierr); ierr = PetscFree(bddc_dofs_splitting);CHKERRQ(ierr); /* Primal constraints implemented by using a near null space attached to A -> now it passes in only the constants (which in practice is not needed since, by default, PCBDDC build the primal space using constants for quadrature formulas */ #if 0 Vec vecs[2]; PetscRandom rctx; ierr = MatCreateVecs(A,&vecs[0],&vecs[1]);CHKERRQ(ierr); ierr = PetscRandomCreate(dd.gcomm,&rctx);CHKERRQ(ierr); ierr = VecSetRandom(vecs[0],rctx);CHKERRQ(ierr); ierr = VecSetRandom(vecs[1],rctx);CHKERRQ(ierr); ierr = MatNullSpaceCreate(dd.gcomm,PETSC_TRUE,2,vecs,&near_null_space);CHKERRQ(ierr); ierr = VecDestroy(&vecs[0]);CHKERRQ(ierr); ierr = VecDestroy(&vecs[1]);CHKERRQ(ierr); ierr = PetscRandomDestroy(&rctx);CHKERRQ(ierr); #else ierr = MatNullSpaceCreate(dd.gcomm,PETSC_TRUE,0,NULL,&near_null_space);CHKERRQ(ierr); #endif ierr = MatSetNearNullSpace(A,near_null_space);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&near_null_space);CHKERRQ(ierr); /* CSR graph of subdomain dofs */ ierr = BuildCSRGraph(dd,&xadj,&adjncy);CHKERRQ(ierr); ierr = PCBDDCSetLocalAdjacencyGraph(pc,localsize,xadj,adjncy,PETSC_OWN_POINTER);CHKERRQ(ierr); /* Neumann/Dirichlet indices on the global boundary */ if (dd.DBC_zerorows) { /* Only in case you eliminate some rows matrix with zerorows function, you need to set dirichlet indices into PCBDDC data */ ierr = ComputeSpecialBoundaryIndices(dd,&dirichletIS,&neumannIS);CHKERRQ(ierr); ierr = PCBDDCSetNeumannBoundariesLocal(pc,neumannIS);CHKERRQ(ierr); ierr = PCBDDCSetDirichletBoundariesLocal(pc,dirichletIS);CHKERRQ(ierr); } else { if (dd.pure_neumann) { /* In such a case, all interface nodes lying on the global boundary are neumann nodes */ ierr = ComputeSpecialBoundaryIndices(dd,NULL,&neumannIS);CHKERRQ(ierr); ierr = PCBDDCSetNeumannBoundariesLocal(pc,neumannIS);CHKERRQ(ierr); } else { /* It is wrong setting dirichlet indices without having zeroed the corresponding rows in the global matrix */ /* But we can still compute them since nodes near the dirichlet boundaries does not need to be defined as neumann nodes */ ierr = ComputeSpecialBoundaryIndices(dd,&dirichletIS,&neumannIS);CHKERRQ(ierr); ierr = PCBDDCSetNeumannBoundariesLocal(pc,neumannIS);CHKERRQ(ierr); } } /* Pass local null space information to local matrices (needed when using approximate local solvers) */ if (dd.ipx || dd.pure_neumann) { MatNullSpace nsp; Mat local_mat; ierr = MatISGetLocalMat(A,&local_mat);CHKERRQ(ierr); ierr = MatNullSpaceCreate(PETSC_COMM_SELF,PETSC_TRUE,0,NULL,&nsp);CHKERRQ(ierr); ierr = MatSetNullSpace(local_mat,nsp);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nsp);CHKERRQ(ierr); } ierr = KSPSetComputeSingularValues(temp_ksp,PETSC_TRUE);CHKERRQ(ierr); ierr = KSPSetFromOptions(temp_ksp);CHKERRQ(ierr); ierr = KSPSetUp(temp_ksp);CHKERRQ(ierr); *ksp = temp_ksp; ierr = ISDestroy(&dirichletIS);CHKERRQ(ierr); ierr = ISDestroy(&neumannIS);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode computeMatrix3D(KSP ksp, Mat A, Mat pc, MatStructure * matStructure, void* ctx){ PetscUserCtx* context = (PetscUserCtx*) ctx; Parameters & parameters = context -> getParameters(); IntScalarField & flags = context->getFlowField().getFlags(); int *limitsX, *limitsY, *limitsZ; context->getLimits(&limitsX, &limitsY, &limitsZ); PetscScalar dx = parameters.geometry.dx, dy = parameters.geometry.dy, dz = parameters.geometry.dz; PetscScalar stencilValues[7]; MatStencil row, column[7]; PetscInt i, j, k, Nx, Ny, Nz; Nx = parameters.geometry.sizeX + 2; Ny = parameters.geometry.sizeY + 2; Nz = parameters.geometry.sizeZ + 2; // Loop for inner nodes for (k = limitsZ[0]; k < limitsZ[1]; k++){ for (j = limitsY[0]; j < limitsY[1]; j++){ for (i = limitsX[0]; i < limitsX[1]; i++){ row.i = i; row.j = j, row.k = k; const int obstacle = flags.getValue(i-limitsX[0]+2, j-limitsY[0]+2, k-limitsZ[0]+2); if ((obstacle & OBSTACLE_SELF) == 0) { // If the cell is fluid // Definition of values stencilValues[0] = 1/(dx*dx); stencilValues[1] = 1/(dx*dx); stencilValues[2] = 1/(dy*dy); stencilValues[3] = 1/(dy*dy); stencilValues[4] = 1/(dz*dz); stencilValues[5] = 1/(dz*dz); stencilValues[6] = -(2.0/(dx*dx) + 2.0/(dy*dy) + 2.0/(dz*dz)); // Definition of positions. Order must correspond to values column[0].i = i+1; column[0].j = j; column[0].k = k; column[1].i = i-1; column[1].j = j; column[1].k = k; column[2].i = i; column[2].j = j+1; column[2].k = k; column[3].i = i; column[3].j = j-1; column[3].k = k; column[4].i = i; column[4].j = j; column[4].k = k+1; column[5].i = i; column[5].j = j; column[5].k = k-1; column[6].i = i; column[6].j = j; column[6].k = k; MatSetValuesStencil(A, 1, &row, 7, column, stencilValues, INSERT_VALUES); } else if (obstacle != 127) { // If non-fluid and still not completely surounded int counter = 0; if ((obstacle & OBSTACLE_LEFT) == 0){ // If there's fluid to the left stencilValues[counter] = 1; column[counter].i = i-1; column[counter].j = j, column[counter].k = k; counter++; } if ((obstacle & OBSTACLE_RIGHT) == 0){ stencilValues[counter] = 1; column[counter].i = i+1; column[counter].j = j, column[counter].k = k; counter++; } if ((obstacle & OBSTACLE_BOTTOM) == 0){ stencilValues[counter] = 1; column[counter].i = i; column[counter].j = j-1, column[counter].k = k; counter++; } if ((obstacle & OBSTACLE_TOP) == 0){ stencilValues[counter] = 1; column[counter].i = i; column[counter].j = j+1, column[counter].k = k; counter++; } if ((obstacle & OBSTACLE_FRONT) == 0){ stencilValues[counter] = 1; column[counter].i = i; column[counter].j = j, column[counter].k = k-1; counter++; } if ((obstacle & OBSTACLE_BACK) == 0){ stencilValues[counter] = 1; column[counter].i = i; column[counter].j = j, column[counter].k = k+1; counter++; } // Now set a line for the element itself stencilValues[counter] = (double)(-counter); column[counter].i = i; column[counter].j = j, column[counter].k = k; MatSetValuesStencil(A, 1, &row, counter+1, column, stencilValues, INSERT_VALUES); } else { // If the cell is an inner obstacle cell stencilValues[0] = 1.0; column[0].i = i; column[0].j = j; column[0].k = k; MatSetValuesStencil(A, 1, &row, 1, column, stencilValues, INSERT_VALUES); } } } } // Left wall if (context->setAsBoundary & LEFT_WALL_BIT){ for (j = limitsY[0]; j < limitsY[1]; j++){ for (k = limitsZ[0]; k < limitsZ[1]; k++){ column[0].i = 0; column[0].j = j; column[0].k = k; column[1].i = context->displacement[0]; column[1].j = j; column[1].k = k; row.i = 0; row.j = j; row.k = k; if (parameters.walls.typeLeft == DIRICHLET){ stencilValues[0] = 1; stencilValues[1] = -1; } else if (parameters.walls.typeLeft == NEUMANN){ stencilValues[0] = 0.5; stencilValues[1] = 0.5; } MatSetValuesStencil(A, 1, &row, 2, column, stencilValues, INSERT_VALUES); } } } // Right wall if (context->setAsBoundary & RIGHT_WALL_BIT){ for (j = limitsY[0]; j < limitsY[1]; j++){ for (k = limitsZ[0]; k < limitsZ[1]; k++){ column[0].i = Nx-1; column[0].j = j; column[0].k = k; column[1].i = context->displacement[1]; column[1].j = j; column[1].k = k; row.i = Nx-1; row.j = j; row.k = k; if (parameters.walls.typeRight == DIRICHLET){ stencilValues[0] = 1; stencilValues[1] = -1; } else if (parameters.walls.typeRight == NEUMANN){ stencilValues[0] = 0.5; stencilValues[1] = 0.5; } MatSetValuesStencil(A, 1, &row, 2, column, stencilValues, INSERT_VALUES); } } } // Bottom wall if (context->setAsBoundary & BOTTOM_WALL_BIT){ for (i = limitsX[0]; i < limitsX[1]; i++){ for (k = limitsZ[0]; k < limitsZ[1]; k++){ column[0].i = i; column[0].j = 0; column[0].k = k; column[1].i = i; column[1].j = context->displacement[2]; column[1].k = k; row.i = i; row.j = 0; row.k = k; if (parameters.walls.typeBottom == DIRICHLET){ stencilValues[0] = 1; stencilValues[1] = -1; } else if (parameters.walls.typeBottom == NEUMANN){ stencilValues[0] = 0.5; stencilValues[1] = 0.5; } MatSetValuesStencil(A, 1, &row, 2, column, stencilValues, INSERT_VALUES); } } } // Top wall if (context->setAsBoundary & TOP_WALL_BIT){ for (i = limitsX[0]; i < limitsX[1]; i++){ for (k = limitsZ[0]; k < limitsZ[1]; k++){ column[0].i = i; column[0].j = Ny-1; column[0].k = k; column[1].i = i; column[1].j = context->displacement[3]; column[1].k = k; row.i = i; row.j = Ny-1; row.k = k; if (parameters.walls.typeTop == DIRICHLET){ stencilValues[0] = 1; stencilValues[1] = -1; } else if (parameters.walls.typeTop == NEUMANN){ stencilValues[0] = 0.5; stencilValues[1] = 0.5; } MatSetValuesStencil(A, 1, &row, 2, column, stencilValues, INSERT_VALUES); } } } // Front wall if (context->setAsBoundary & FRONT_WALL_BIT){ for (i = limitsX[0]; i < limitsX[1]; i++){ for (j = limitsY[0]; j < limitsY[1]; j++){ column[0].i = i; column[0].j = j; column[0].k = 0; column[1].i = i; column[1].j = j; column[1].k = context->displacement[4]; row.i = i; row.j = j; row.k = 0; if (parameters.walls.typeFront == DIRICHLET){ stencilValues[0] = 1; stencilValues[1] = -1; } else if (parameters.walls.typeFront == NEUMANN){ stencilValues[0] = 0.5; stencilValues[1] = 0.5; } MatSetValuesStencil(A, 1, &row, 2, column, stencilValues, INSERT_VALUES); } } } // Back wall if (context->setAsBoundary & BACK_WALL_BIT){ for (i = limitsX[0]; i < limitsX[1]; i++){ for (j = limitsY[0]; j < limitsY[1]; j++){ column[0].i = i; column[0].j = j; column[0].k = Nz-1; column[1].i = i; column[1].j = j; column[1].k = context->displacement[5]; row.i = i; row.j = j; row.k = Nz-1; if (parameters.walls.typeBack == DIRICHLET){ stencilValues[0] = 1; stencilValues[1] = -1; } else if (parameters.walls.typeBack == NEUMANN){ stencilValues[0] = 0.5; stencilValues[1] = 0.5; } MatSetValuesStencil(A, 1, &row, 2, column, stencilValues, INSERT_VALUES); } } } MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY); MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY); MatNullSpace nullspace; MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,0,&nullspace); MatSetNullSpace(A,nullspace); MatNullSpaceDestroy(&nullspace); return 0; }
PetscErrorCode computeMatrix2D(KSP ksp, Mat A, Mat pc, MatStructure * matStructure, void* ctx){ PetscUserCtx* context = (PetscUserCtx*) ctx; Parameters & parameters = context -> getParameters(); IntScalarField & flags = context->getFlowField().getFlags(); int *limitsX, *limitsY, *limitsZ; context->getLimits(&limitsX, &limitsY, &limitsZ); PetscScalar dx = parameters.geometry.dx, dy = parameters.geometry.dy; PetscScalar stencilValues[5]; MatStencil row, column[5]; PetscInt i, j, Nx, Ny; Nx = parameters.geometry.sizeX + 2; Ny = parameters.geometry.sizeY + 2; // Loop for inner nodes for (j = limitsY[0]; j < limitsY[1]; j++){ for (i = limitsX[0]; i < limitsX[1]; i++){ row.i = i; row.j = j; const int obstacle = flags.getValue(i-limitsX[0]+2, j-limitsY[0]+2); if ((obstacle & OBSTACLE_SELF) == 0) { // If we have a fluid cell // Definition of values stencilValues[0] = 1/(dx*dx); stencilValues[1] = 1/(dx*dx); stencilValues[2] = -(2.0/(dx*dx) + 2.0/(dy*dy)); stencilValues[3] = 1/(dy*dy); stencilValues[4] = 1/(dy*dy); // Definition of positions. Order must correspond to values column[0].i = i+1; column[0].j = j; column[1].i = i-1; column[1].j = j; column[2].i = i; column[2].j = j; column[3].i = i; column[3].j = j+1; column[4].i = i; column[4].j = j-1; MatSetValuesStencil(A, 1, &row, 5, column, stencilValues, INSERT_VALUES); } else if (obstacle != OBSTACLE_SELF + OBSTACLE_LEFT + OBSTACLE_RIGHT + OBSTACLE_TOP + OBSTACLE_BOTTOM) { // Not fluid, but fluid somewhere around int counter = 0; // This will contain how many neighbours are fluid if ((obstacle & OBSTACLE_LEFT) == 0){ // If there is fluid to the left stencilValues[counter] = 1.0; column[counter].i = i-1; column[counter].j = j; counter++; // We have just identified a fuid cell and prepared to average } if ((obstacle & OBSTACLE_RIGHT) == 0){ stencilValues[counter] = 1.0; column[counter].i = i+1; column[counter].j = j; counter++; } if ((obstacle & OBSTACLE_BOTTOM) == 0){ stencilValues[counter] = 1.0; column[counter].i = i; column[counter].j = j-1; counter++; } if ((obstacle & OBSTACLE_TOP) == 0){ stencilValues[counter] = 1.0; column[counter].i = i; column[counter].j = j+1; counter++; } // A column for the cell itself stencilValues[counter] = (double)(-counter); column[counter].i = i; column[counter].j = j; // Once we identified how many fluid cells are around and set columns for each, we // enter the row into the matrix. MatSetValuesStencil(A, 1, &row, counter+1, column, stencilValues, INSERT_VALUES); } else { // The remaining possibility is that the cell is obstacle surrounded // by more obstacle cells // Here, we just add an equation to set the value according to the right hand side stencilValues[0] = 1.0; column[0].i = i; column[0].j = j; MatSetValuesStencil(A, 1, &row, 1, column, stencilValues, INSERT_VALUES); } } } // Left wall if (context->setAsBoundary & LEFT_WALL_BIT){ for (j = limitsY[0]; j < limitsY[1]; j++){ column[0].i = 0; column[0].j = j; column[1].i = context->displacement[0]; column[1].j = j; row.i = 0; row.j = j; if (parameters.walls.typeLeft == DIRICHLET){ // If Dirichlet velocity boundary conditions // therefore, Neumann in the pressure stencilValues[0] = 1; stencilValues[1] = -1; } else if (parameters.walls.typeLeft == NEUMANN){ // Neumann velocity boundary conditions, stencilValues[0] = 0.5; stencilValues[1] = 0.5; } MatSetValuesStencil(A, 1, &row, 2, column, stencilValues, INSERT_VALUES); } } // Right wall if (context->setAsBoundary & RIGHT_WALL_BIT){ for (j = limitsY[0]; j < limitsY[1]; j++){ column[0].i = Nx-1; column[0].j = j; column[1].i = context->displacement[1]; column[1].j = j; row.i = Nx-1; row.j = j; if (parameters.walls.typeRight == DIRICHLET){ stencilValues[0] = 1; stencilValues[1] = -1; } else if (parameters.walls.typeRight == NEUMANN){ stencilValues[0] = 0.5; stencilValues[1] = 0.5; } MatSetValuesStencil(A, 1, &row, 2, column, stencilValues, INSERT_VALUES); } } // Bottom wall if (context->setAsBoundary & BOTTOM_WALL_BIT){ for (i = limitsX[0]; i < limitsX[1]; i++){ column[0].i = i; column[0].j = 0; column[1].i = i; column[1].j = context->displacement[2]; row.i = i; row.j = 0; if (parameters.walls.typeBottom == DIRICHLET){ stencilValues[0] = 1; stencilValues[1] = -1; } else if (parameters.walls.typeBottom == NEUMANN) { stencilValues[0] = 0.5; stencilValues[1] = 0.5; } MatSetValuesStencil(A, 1, &row, 2, column, stencilValues, INSERT_VALUES); } } // Top wall if (context->setAsBoundary & TOP_WALL_BIT){ for (i = limitsX[0]; i < limitsX[1]; i++){ column[0].i = i; column[0].j = Ny-1; column[1].i = i; column[1].j = context->displacement[3]; row.i = i; row.j = Ny-1; if (parameters.walls.typeTop == DIRICHLET){ stencilValues[0] = 1; stencilValues[1] = -1; } else if (parameters.walls.typeTop == NEUMANN) { stencilValues[0] = 0.5; stencilValues[1] = 0.5; } MatSetValuesStencil(A, 1, &row, 2, column, stencilValues, INSERT_VALUES); } } MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY); MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY); MatNullSpace nullspace; MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,0,&nullspace); MatSetNullSpace(A,nullspace); MatNullSpaceDestroy(&nullspace); return 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; }
PetscErrorCode ComputeMatrix(KSP ksp,Mat J,Mat jac,void *ctx) { UserContext *user = (UserContext*)ctx; PetscReal centerRho; PetscErrorCode ierr; PetscInt i,j,mx,my,xm,ym,xs,ys; PetscScalar v[5]; PetscReal Hx,Hy,HydHx,HxdHy,rho; MatStencil row, col[5]; DM da; PetscFunctionBeginUser; ierr = KSPGetDM(ksp,&da);CHKERRQ(ierr); centerRho = user->rho; ierr = DMDAGetInfo(da,0,&mx,&my,0,0,0,0,0,0,0,0,0,0);CHKERRQ(ierr); Hx = 1.0 / (PetscReal)(mx-1); Hy = 1.0 / (PetscReal)(my-1); HxdHy = Hx/Hy; HydHx = Hy/Hx; ierr = DMDAGetCorners(da,&xs,&ys,0,&xm,&ym,0);CHKERRQ(ierr); for (j=ys; j<ys+ym; j++) { for (i=xs; i<xs+xm; i++) { row.i = i; row.j = j; ierr = ComputeRho(i, j, mx, my, centerRho, &rho);CHKERRQ(ierr); if (i==0 || j==0 || i==mx-1 || j==my-1) { if (user->bcType == DIRICHLET) { v[0] = 2.0*rho*(HxdHy + HydHx); ierr = MatSetValuesStencil(jac,1,&row,1,&row,v,INSERT_VALUES);CHKERRQ(ierr); } else if (user->bcType == NEUMANN) { PetscInt numx = 0, numy = 0, num = 0; if (j!=0) { v[num] = -rho*HxdHy; col[num].i = i; col[num].j = j-1; numy++; num++; } if (i!=0) { v[num] = -rho*HydHx; col[num].i = i-1; col[num].j = j; numx++; num++; } if (i!=mx-1) { v[num] = -rho*HydHx; col[num].i = i+1; col[num].j = j; numx++; num++; } if (j!=my-1) { v[num] = -rho*HxdHy; col[num].i = i; col[num].j = j+1; numy++; num++; } v[num] = numx*rho*HydHx + numy*rho*HxdHy; col[num].i = i; col[num].j = j; num++; ierr = MatSetValuesStencil(jac,1,&row,num,col,v,INSERT_VALUES);CHKERRQ(ierr); } } else { v[0] = -rho*HxdHy; col[0].i = i; col[0].j = j-1; v[1] = -rho*HydHx; col[1].i = i-1; col[1].j = j; v[2] = 2.0*rho*(HxdHy + HydHx); col[2].i = i; col[2].j = j; v[3] = -rho*HydHx; col[3].i = i+1; col[3].j = j; v[4] = -rho*HxdHy; col[4].i = i; col[4].j = j+1; ierr = MatSetValuesStencil(jac,1,&row,5,col,v,INSERT_VALUES);CHKERRQ(ierr); } } } ierr = MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); if (user->bcType == NEUMANN) { MatNullSpace nullspace; ierr = MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,0,&nullspace);CHKERRQ(ierr); ierr = MatSetNullSpace(jac,nullspace);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nullspace);CHKERRQ(ierr); } PetscFunctionReturn(0); }
PetscErrorCode ComputeMatrix(KSP ksp, Mat J,Mat jac,MatStructure *str, void *ctx) { UserContext *user = (UserContext*)ctx; PetscErrorCode ierr; PetscInt i,j,mx,my,xm,ym,xs,ys,num, numi, numj; PetscScalar v[5],Hx,Hy,HydHx,HxdHy; MatStencil row, col[5]; DM da; PetscFunctionBeginUser; ierr = KSPGetDM(ksp,&da);CHKERRQ(ierr); ierr = DMDAGetInfo(da,0,&mx,&my,0,0,0,0,0,0,0,0,0,0);CHKERRQ(ierr); Hx = 1.0 / (PetscReal)(mx); Hy = 1.0 / (PetscReal)(my); HxdHy = Hx/Hy; HydHx = Hy/Hx; ierr = DMDAGetCorners(da,&xs,&ys,0,&xm,&ym,0);CHKERRQ(ierr); for (j=ys; j<ys+ym; j++) { for (i=xs; i<xs+xm; i++) { row.i = i; row.j = j; if (i==0 || j==0 || i==mx-1 || j==my-1) { if (user->bcType == DIRICHLET) { v[0] = 2.0*(HxdHy + HydHx); ierr = MatSetValuesStencil(jac,1,&row,1,&row,v,INSERT_VALUES);CHKERRQ(ierr); SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Dirichlet boundary conditions not supported !\n"); } else if (user->bcType == NEUMANN) { num = 0; numi=0; numj=0; if (j!=0) { v[num] = -HxdHy; col[num].i = i; col[num].j = j-1; num++; numj++; } if (i!=0) { v[num] = -HydHx; col[num].i = i-1; col[num].j = j; num++; numi++; } if (i!=mx-1) { v[num] = -HydHx; col[num].i = i+1; col[num].j = j; num++; numi++; } if (j!=my-1) { v[num] = -HxdHy; col[num].i = i; col[num].j = j+1; num++; numj++; } v[num] = (PetscReal)(numj)*HxdHy + (PetscReal)(numi)*HydHx; col[num].i = i; col[num].j = j; num++; ierr = MatSetValuesStencil(jac,1,&row,num,col,v,INSERT_VALUES);CHKERRQ(ierr); } } else { v[0] = -HxdHy; col[0].i = i; col[0].j = j-1; v[1] = -HydHx; col[1].i = i-1; col[1].j = j; v[2] = 2.0*(HxdHy + HydHx); col[2].i = i; col[2].j = j; v[3] = -HydHx; col[3].i = i+1; col[3].j = j; v[4] = -HxdHy; col[4].i = i; col[4].j = j+1; ierr = MatSetValuesStencil(jac,1,&row,5,col,v,INSERT_VALUES);CHKERRQ(ierr); } } } ierr = MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); if (user->bcType == NEUMANN) { MatNullSpace nullspace; ierr = MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,0,&nullspace);CHKERRQ(ierr); ierr = MatSetNullSpace(jac,nullspace);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nullspace);CHKERRQ(ierr); } PetscFunctionReturn(0); }
std::pair<unsigned int, Real> PetscNonlinearSolver<T>::solve (SparseMatrix<T>& jac_in, // System Jacobian Matrix NumericVector<T>& x_in, // Solution vector NumericVector<T>& r_in, // Residual vector const double, // Stopping tolerance const unsigned int) { START_LOG("solve()", "PetscNonlinearSolver"); this->init (); // Make sure the data passed in are really of Petsc types PetscMatrix<T>* jac = libmesh_cast_ptr<PetscMatrix<T>*>(&jac_in); PetscVector<T>* x = libmesh_cast_ptr<PetscVector<T>*>(&x_in); PetscVector<T>* r = libmesh_cast_ptr<PetscVector<T>*>(&r_in); PetscErrorCode ierr=0; PetscInt n_iterations =0; // Should actually be a PetscReal, but I don't know which version of PETSc first introduced PetscReal Real final_residual_norm=0.; ierr = SNESSetFunction (_snes, r->vec(), __libmesh_petsc_snes_residual, this); LIBMESH_CHKERRABORT(ierr); // Only set the jacobian function if we've been provided with something to call. // This allows a user to set their own jacobian function if they want to if (this->jacobian || this->jacobian_object || this->residual_and_jacobian_object) { ierr = SNESSetJacobian (_snes, jac->mat(), jac->mat(), __libmesh_petsc_snes_jacobian, this); LIBMESH_CHKERRABORT(ierr); } #if !PETSC_VERSION_LESS_THAN(3,3,0) // Only set the nullspace if we have a way of computing it and the result is non-empty. if (this->nullspace || this->nullspace_object) { MatNullSpace msp; this->build_mat_null_space(this->nullspace_object, this->nullspace, &msp); if (msp) { ierr = MatSetNullSpace(jac->mat(), msp); LIBMESH_CHKERRABORT(ierr); ierr = MatNullSpaceDestroy(&msp); LIBMESH_CHKERRABORT(ierr); } } // Only set the nearnullspace if we have a way of computing it and the result is non-empty. if (this->nearnullspace || this->nearnullspace_object) { MatNullSpace msp = PETSC_NULL; this->build_mat_null_space(this->nearnullspace_object, this->nearnullspace, &msp); if(msp) { ierr = MatSetNearNullSpace(jac->mat(), msp); LIBMESH_CHKERRABORT(ierr); ierr = MatNullSpaceDestroy(&msp); LIBMESH_CHKERRABORT(ierr); } } #endif // Have the Krylov subspace method use our good initial guess rather than 0 KSP ksp; ierr = SNESGetKSP (_snes, &ksp); LIBMESH_CHKERRABORT(ierr); // Set the tolerances for the iterative solver. Use the user-supplied // tolerance for the relative residual & leave the others at default values ierr = KSPSetTolerances (ksp, this->initial_linear_tolerance, PETSC_DEFAULT, PETSC_DEFAULT, this->max_linear_iterations); LIBMESH_CHKERRABORT(ierr); // Set the tolerances for the non-linear solver. ierr = SNESSetTolerances(_snes, this->absolute_residual_tolerance, this->relative_residual_tolerance, this->relative_step_tolerance, this->max_nonlinear_iterations, this->max_function_evaluations); LIBMESH_CHKERRABORT(ierr); //Pull in command-line options KSPSetFromOptions(ksp); SNESSetFromOptions(_snes); if (this->user_presolve) this->user_presolve(this->system()); //Set the preconditioning matrix if(this->_preconditioner) { this->_preconditioner->set_matrix(jac_in); this->_preconditioner->init(); } // ierr = KSPSetInitialGuessNonzero (ksp, PETSC_TRUE); // LIBMESH_CHKERRABORT(ierr); // Older versions (at least up to 2.1.5) of SNESSolve took 3 arguments, // the last one being a pointer to an int to hold the number of iterations required. # if PETSC_VERSION_LESS_THAN(2,2,0) ierr = SNESSolve (_snes, x->vec(), &n_iterations); LIBMESH_CHKERRABORT(ierr); // 2.2.x style #elif PETSC_VERSION_LESS_THAN(2,3,0) ierr = SNESSolve (_snes, x->vec()); LIBMESH_CHKERRABORT(ierr); // 2.3.x & newer style #else ierr = SNESSolve (_snes, PETSC_NULL, x->vec()); LIBMESH_CHKERRABORT(ierr); ierr = SNESGetIterationNumber(_snes,&n_iterations); LIBMESH_CHKERRABORT(ierr); ierr = SNESGetLinearSolveIterations(_snes, &_n_linear_iterations); LIBMESH_CHKERRABORT(ierr); ierr = SNESGetFunctionNorm(_snes,&final_residual_norm); LIBMESH_CHKERRABORT(ierr); #endif // Get and store the reason for convergence SNESGetConvergedReason(_snes, &_reason); //Based on Petsc 2.3.3 documentation all diverged reasons are negative this->converged = (_reason >= 0); this->clear(); STOP_LOG("solve()", "PetscNonlinearSolver"); // return the # of its. and the final residual norm. return std::make_pair(n_iterations, final_residual_norm); }
/*@ KSPSetFromOptions - Sets KSP options from the options database. This routine must be called before KSPSetUp() if the user is to be allowed to set the Krylov type. Collective on KSP Input Parameters: . ksp - the Krylov space context Options Database Keys: + -ksp_max_it - maximum number of linear iterations . -ksp_rtol rtol - relative tolerance used in default determination of convergence, i.e. if residual norm decreases by this factor than convergence is declared . -ksp_atol abstol - absolute tolerance used in default convergence test, i.e. if residual norm is less than this then convergence is declared . -ksp_divtol tol - if residual norm increases by this factor than divergence is declared . -ksp_converged_use_initial_residual_norm - see KSPConvergedDefaultSetUIRNorm() . -ksp_converged_use_min_initial_residual_norm - see KSPConvergedDefaultSetUMIRNorm() . -ksp_norm_type - none - skip norms used in convergence tests (useful only when not using convergence test (say you always want to run with 5 iterations) to save on communication overhead preconditioned - default for left preconditioning unpreconditioned - see KSPSetNormType() natural - see KSPSetNormType() . -ksp_check_norm_iteration it - do not compute residual norm until iteration number it (does compute at 0th iteration) works only for PCBCGS, PCIBCGS and and PCCG . -ksp_lag_norm - compute the norm of the residual for the ith iteration on the i+1 iteration; this means that one can use the norm of the residual for convergence test WITHOUT an extra MPI_Allreduce() limiting global synchronizations. This will require 1 more iteration of the solver than usual. . -ksp_fischer_guess <model,size> - uses the Fischer initial guess generator for repeated linear solves . -ksp_constant_null_space - assume the operator (matrix) has the constant vector in its null space . -ksp_test_null_space - tests the null space set with MatSetNullSpace() to see if it truly is a null space . -ksp_knoll - compute initial guess by applying the preconditioner to the right hand side . -ksp_monitor_cancel - cancel all previous convergene monitor routines set . -ksp_monitor <optional filename> - print residual norm at each iteration . -ksp_monitor_lg_residualnorm - plot residual norm at each iteration . -ksp_monitor_solution - plot solution at each iteration - -ksp_monitor_singular_value - monitor extreme singular values at each iteration Notes: To see all options, run your program with the -help option or consult Users-Manual: ch_ksp Level: beginner .keywords: KSP, set, from, options, database .seealso: KSPSetUseFischerGuess() @*/ PetscErrorCode KSPSetFromOptions(KSP ksp) { PetscErrorCode ierr; PetscInt indx; const char *convtests[] = {"default","skip"}; char type[256], monfilename[PETSC_MAX_PATH_LEN]; PetscViewer monviewer; PetscBool flg,flag,reuse,set; PetscInt model[2]={0,0},nmax; KSPNormType normtype; PCSide pcside; void *ctx; PetscFunctionBegin; PetscValidHeaderSpecific(ksp,KSP_CLASSID,1); if (!ksp->skippcsetfromoptions) { if (!ksp->pc) {ierr = KSPGetPC(ksp,&ksp->pc);CHKERRQ(ierr);} ierr = PCSetFromOptions(ksp->pc);CHKERRQ(ierr); } ierr = KSPRegisterAll();CHKERRQ(ierr); ierr = PetscObjectOptionsBegin((PetscObject)ksp);CHKERRQ(ierr); ierr = PetscOptionsFList("-ksp_type","Krylov method","KSPSetType",KSPList,(char*)(((PetscObject)ksp)->type_name ? ((PetscObject)ksp)->type_name : KSPGMRES),type,256,&flg);CHKERRQ(ierr); if (flg) { ierr = KSPSetType(ksp,type);CHKERRQ(ierr); } /* Set the type if it was never set. */ if (!((PetscObject)ksp)->type_name) { ierr = KSPSetType(ksp,KSPGMRES);CHKERRQ(ierr); } ierr = PetscObjectTypeCompare((PetscObject)ksp,KSPPREONLY,&flg);CHKERRQ(ierr); if (flg) goto skipoptions; ierr = PetscOptionsInt("-ksp_max_it","Maximum number of iterations","KSPSetTolerances",ksp->max_it,&ksp->max_it,NULL);CHKERRQ(ierr); ierr = PetscOptionsReal("-ksp_rtol","Relative decrease in residual norm","KSPSetTolerances",ksp->rtol,&ksp->rtol,NULL);CHKERRQ(ierr); ierr = PetscOptionsReal("-ksp_atol","Absolute value of residual norm","KSPSetTolerances",ksp->abstol,&ksp->abstol,NULL);CHKERRQ(ierr); ierr = PetscOptionsReal("-ksp_divtol","Residual norm increase cause divergence","KSPSetTolerances",ksp->divtol,&ksp->divtol,NULL);CHKERRQ(ierr); ierr = PetscOptionsBool("-ksp_converged_use_initial_residual_norm","Use initial residual residual norm for computing relative convergence","KSPConvergedDefaultSetUIRNorm",PETSC_FALSE,&flag,&set);CHKERRQ(ierr); if (set && flag) {ierr = KSPConvergedDefaultSetUIRNorm(ksp);CHKERRQ(ierr);} ierr = PetscOptionsBool("-ksp_converged_use_min_initial_residual_norm","Use minimum of initial residual norm and b for computing relative convergence","KSPConvergedDefaultSetUMIRNorm",PETSC_FALSE,&flag,&set);CHKERRQ(ierr); if (set && flag) {ierr = KSPConvergedDefaultSetUMIRNorm(ksp);CHKERRQ(ierr);} ierr = PetscOptionsBool("-ksp_initial_guess_nonzero","Use the contents of the solution vector for initial guess","KSPSetInitialNonzero",ksp->guess_zero ? PETSC_FALSE : PETSC_TRUE,&flag,&flg);CHKERRQ(ierr); if (flg) { ierr = KSPSetInitialGuessNonzero(ksp,flag);CHKERRQ(ierr); } ierr = PCGetReusePreconditioner(ksp->pc,&reuse);CHKERRQ(ierr); ierr = PetscOptionsBool("-ksp_reuse_preconditioner","Use initial preconditioner and don't ever compute a new one ","KSPReusePreconditioner",reuse,&reuse,NULL);CHKERRQ(ierr); ierr = KSPSetReusePreconditioner(ksp,reuse);CHKERRQ(ierr); ierr = PetscOptionsBool("-ksp_knoll","Use preconditioner applied to b for initial guess","KSPSetInitialGuessKnoll",ksp->guess_knoll,&ksp->guess_knoll,NULL);CHKERRQ(ierr); ierr = PetscOptionsBool("-ksp_error_if_not_converged","Generate error if solver does not converge","KSPSetErrorIfNotConverged",ksp->errorifnotconverged,&ksp->errorifnotconverged,NULL);CHKERRQ(ierr); nmax = 2; ierr = PetscOptionsIntArray("-ksp_fischer_guess","Use Paul Fischer's algorithm for initial guess","KSPSetUseFischerGuess",model,&nmax,&flag);CHKERRQ(ierr); if (flag) { if (nmax != 2) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_ARG_OUTOFRANGE,"Must pass in model,size as arguments"); ierr = KSPSetUseFischerGuess(ksp,model[0],model[1]);CHKERRQ(ierr); } ierr = PetscOptionsEList("-ksp_convergence_test","Convergence test","KSPSetConvergenceTest",convtests,2,"default",&indx,&flg);CHKERRQ(ierr); if (flg) { switch (indx) { case 0: ierr = KSPConvergedDefaultCreate(&ctx);CHKERRQ(ierr); ierr = KSPSetConvergenceTest(ksp,KSPConvergedDefault,ctx,KSPConvergedDefaultDestroy);CHKERRQ(ierr); break; case 1: ierr = KSPSetConvergenceTest(ksp,KSPConvergedSkip,NULL,NULL);CHKERRQ(ierr); break; } } ierr = KSPSetUpNorms_Private(ksp,&normtype,&pcside);CHKERRQ(ierr); ierr = PetscOptionsEnum("-ksp_norm_type","KSP Norm type","KSPSetNormType",KSPNormTypes,(PetscEnum)normtype,(PetscEnum*)&normtype,&flg);CHKERRQ(ierr); if (flg) { ierr = KSPSetNormType(ksp,normtype);CHKERRQ(ierr); } ierr = PetscOptionsInt("-ksp_check_norm_iteration","First iteration to compute residual norm","KSPSetCheckNormIteration",ksp->chknorm,&ksp->chknorm,NULL);CHKERRQ(ierr); ierr = PetscOptionsBool("-ksp_lag_norm","Lag the calculation of the residual norm","KSPSetLagNorm",ksp->lagnorm,&flag,&flg);CHKERRQ(ierr); if (flg) { ierr = KSPSetLagNorm(ksp,flag);CHKERRQ(ierr); } ierr = KSPGetDiagonalScale(ksp,&flag);CHKERRQ(ierr); ierr = PetscOptionsBool("-ksp_diagonal_scale","Diagonal scale matrix before building preconditioner","KSPSetDiagonalScale",flag,&flag,&flg);CHKERRQ(ierr); if (flg) { ierr = KSPSetDiagonalScale(ksp,flag);CHKERRQ(ierr); } ierr = KSPGetDiagonalScaleFix(ksp,&flag);CHKERRQ(ierr); ierr = PetscOptionsBool("-ksp_diagonal_scale_fix","Fix diagonally scaled matrix after solve","KSPSetDiagonalScaleFix",flag,&flag,&flg);CHKERRQ(ierr); if (flg) { ierr = KSPSetDiagonalScaleFix(ksp,flag);CHKERRQ(ierr); } ierr = PetscOptionsBool("-ksp_constant_null_space","Add constant null space to Krylov solver matrix","MatSetNullSpace",PETSC_FALSE,&flg,&set);CHKERRQ(ierr); if (set && flg) { MatNullSpace nsp; Mat Amat; ierr = MatNullSpaceCreate(PetscObjectComm((PetscObject)ksp),PETSC_TRUE,0,NULL,&nsp);CHKERRQ(ierr); ierr = PCGetOperators(ksp->pc,&Amat,NULL);CHKERRQ(ierr); if (Amat) { ierr = MatSetNullSpace(Amat,nsp);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nsp);CHKERRQ(ierr); } else SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_ARG_WRONGSTATE,"Cannot set nullspace, matrix has not yet been provided"); } ierr = PetscOptionsBool("-ksp_monitor_cancel","Remove any hardwired monitor routines","KSPMonitorCancel",PETSC_FALSE,&flg,&set);CHKERRQ(ierr); /* -----------------------------------------------------------------------*/ /* Cancels all monitors hardwired into code before call to KSPSetFromOptions() */ if (set && flg) { ierr = KSPMonitorCancel(ksp);CHKERRQ(ierr); } /* Prints preconditioned residual norm at each iteration */ ierr = PetscOptionsString("-ksp_monitor","Monitor preconditioned residual norm","KSPMonitorSet","stdout",monfilename,PETSC_MAX_PATH_LEN,&flg);CHKERRQ(ierr); if (flg) { ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ksp),monfilename,&monviewer);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorDefault,monviewer,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); } /* Prints preconditioned residual norm at each iteration */ ierr = PetscOptionsString("-ksp_monitor_range","Monitor percent of residual entries more than 10 percent of max","KSPMonitorRange","stdout",monfilename,PETSC_MAX_PATH_LEN,&flg);CHKERRQ(ierr); if (flg) { ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ksp),monfilename,&monviewer);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorRange,monviewer,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); } ierr = PetscObjectTypeCompare((PetscObject)ksp->pc,PCKSP,&flg);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)ksp->pc,PCBJACOBI,&flag);CHKERRQ(ierr); if (flg || flag) { /* A hack for using dynamic tolerance in preconditioner */ ierr = PetscOptionsString("-sub_ksp_dynamic_tolerance","Use dynamic tolerance for PC if PC is a KSP","KSPMonitorDynamicTolerance","stdout",monfilename,PETSC_MAX_PATH_LEN,&flg);CHKERRQ(ierr); if (flg) { KSPDynTolCtx *scale; ierr = PetscMalloc1(1,&scale);CHKERRQ(ierr); scale->bnrm = -1.0; scale->coef = 1.0; ierr = PetscOptionsReal("-sub_ksp_dynamic_tolerance_param","Parameter of dynamic tolerance for inner PCKSP","KSPMonitorDynamicToleranceParam",scale->coef,&scale->coef,&flg);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorDynamicTolerance,scale,KSPMonitorDynamicToleranceDestroy);CHKERRQ(ierr); } } /* Plots the vector solution */ ierr = PetscOptionsBool("-ksp_monitor_solution","Monitor solution graphically","KSPMonitorSet",PETSC_FALSE,&flg,&set);CHKERRQ(ierr); if (set && flg) { ierr = KSPMonitorSet(ksp,KSPMonitorSolution,NULL,NULL);CHKERRQ(ierr); } /* Prints preconditioned and true residual norm at each iteration */ ierr = PetscOptionsString("-ksp_monitor_true_residual","Monitor true residual norm","KSPMonitorSet","stdout",monfilename,PETSC_MAX_PATH_LEN,&flg);CHKERRQ(ierr); if (flg) { ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ksp),monfilename,&monviewer);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorTrueResidualNorm,monviewer,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); } /* Prints with max norm at each iteration */ ierr = PetscOptionsString("-ksp_monitor_max","Monitor true residual max norm","KSPMonitorSet","stdout",monfilename,PETSC_MAX_PATH_LEN,&flg);CHKERRQ(ierr); if (flg) { ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ksp),monfilename,&monviewer);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorTrueResidualMaxNorm,monviewer,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); } /* Prints extreme eigenvalue estimates at each iteration */ ierr = PetscOptionsString("-ksp_monitor_singular_value","Monitor singular values","KSPMonitorSet","stdout",monfilename,PETSC_MAX_PATH_LEN,&flg);CHKERRQ(ierr); if (flg) { ierr = KSPSetComputeSingularValues(ksp,PETSC_TRUE);CHKERRQ(ierr); ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ksp),monfilename,&monviewer);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorSingularValue,monviewer,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); } /* Prints preconditioned residual norm with fewer digits */ ierr = PetscOptionsString("-ksp_monitor_short","Monitor preconditioned residual norm with fewer digits","KSPMonitorSet","stdout",monfilename,PETSC_MAX_PATH_LEN,&flg);CHKERRQ(ierr); if (flg) { ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ksp),monfilename,&monviewer);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorDefaultShort,monviewer,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); } /* Calls Python function */ ierr = PetscOptionsString("-ksp_monitor_python","Use Python function","KSPMonitorSet",0,monfilename,PETSC_MAX_PATH_LEN,&flg);CHKERRQ(ierr); if (flg) {ierr = PetscPythonMonitorSet((PetscObject)ksp,monfilename);CHKERRQ(ierr);} /* Graphically plots preconditioned residual norm */ ierr = PetscOptionsBool("-ksp_monitor_lg_residualnorm","Monitor graphically preconditioned residual norm","KSPMonitorSet",PETSC_FALSE,&flg,&set);CHKERRQ(ierr); if (set && flg) { PetscDrawLG ctx; ierr = KSPMonitorLGResidualNormCreate(PetscObjectComm((PetscObject)ksp),NULL,NULL,PETSC_DECIDE,PETSC_DECIDE,300,300,&ctx);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorLGResidualNorm,ctx,(PetscErrorCode (*)(void**))PetscDrawLGDestroy);CHKERRQ(ierr); } /* Graphically plots preconditioned and true residual norm */ ierr = PetscOptionsBool("-ksp_monitor_lg_true_residualnorm","Monitor graphically true residual norm","KSPMonitorSet",PETSC_FALSE,&flg,&set);CHKERRQ(ierr); if (set && flg) { PetscDrawLG ctx; ierr = KSPMonitorLGTrueResidualNormCreate(PetscObjectComm((PetscObject)ksp),NULL,NULL,PETSC_DECIDE,PETSC_DECIDE,300,300,&ctx);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorLGTrueResidualNorm,ctx,(PetscErrorCode (*)(void**))PetscDrawLGDestroy);CHKERRQ(ierr); } /* Graphically plots preconditioned residual norm and range of residual element values */ ierr = PetscOptionsBool("-ksp_monitor_lg_range","Monitor graphically range of preconditioned residual norm","KSPMonitorSet",PETSC_FALSE,&flg,&set);CHKERRQ(ierr); if (set && flg) { PetscViewer ctx; ierr = PetscViewerDrawOpen(PetscObjectComm((PetscObject)ksp),NULL,NULL,PETSC_DECIDE,PETSC_DECIDE,300,300,&ctx);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorLGRange,ctx,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); } #if defined(PETSC_HAVE_SAWS) /* Publish convergence information using AMS */ ierr = PetscOptionsBool("-ksp_monitor_saws","Publish KSP progress using SAWs","KSPMonitorSet",PETSC_FALSE,&flg,&set);CHKERRQ(ierr); if (set && flg) { void *ctx; ierr = KSPMonitorSAWsCreate(ksp,&ctx);CHKERRQ(ierr); ierr = KSPMonitorSet(ksp,KSPMonitorSAWs,ctx,KSPMonitorSAWsDestroy);CHKERRQ(ierr); ierr = KSPSetComputeSingularValues(ksp,PETSC_TRUE);CHKERRQ(ierr); } #endif /* -----------------------------------------------------------------------*/ ierr = KSPSetUpNorms_Private(ksp,&normtype,&pcside);CHKERRQ(ierr); ierr = PetscOptionsEnum("-ksp_pc_side","KSP preconditioner side","KSPSetPCSide",PCSides,(PetscEnum)pcside,(PetscEnum*)&pcside,&flg);CHKERRQ(ierr); if (flg) {ierr = KSPSetPCSide(ksp,pcside);CHKERRQ(ierr);} ierr = PetscOptionsBool("-ksp_compute_singularvalues","Compute singular values of preconditioned operator","KSPSetComputeSingularValues",ksp->calc_sings,&flg,&set);CHKERRQ(ierr); if (set) { ierr = KSPSetComputeSingularValues(ksp,flg);CHKERRQ(ierr); } ierr = PetscOptionsBool("-ksp_compute_eigenvalues","Compute eigenvalues of preconditioned operator","KSPSetComputeSingularValues",ksp->calc_sings,&flg,&set);CHKERRQ(ierr); if (set) { ierr = KSPSetComputeSingularValues(ksp,flg);CHKERRQ(ierr); } ierr = PetscOptionsBool("-ksp_plot_eigenvalues","Scatter plot extreme eigenvalues","KSPSetComputeSingularValues",PETSC_FALSE,&flg,&set);CHKERRQ(ierr); if (set) { ierr = KSPSetComputeSingularValues(ksp,flg);CHKERRQ(ierr); } #if defined(PETSC_HAVE_SAWS) { PetscBool set; flg = PETSC_FALSE; ierr = PetscOptionsBool("-ksp_saws_block","Block for SAWs at end of KSPSolve","PetscObjectSAWsBlock",((PetscObject)ksp)->amspublishblock,&flg,&set);CHKERRQ(ierr); if (set) { ierr = PetscObjectSAWsSetBlock((PetscObject)ksp,flg);CHKERRQ(ierr); } } #endif if (ksp->ops->setfromoptions) { ierr = (*ksp->ops->setfromoptions)(PetscOptionsObject,ksp);CHKERRQ(ierr); } skipoptions: /* process any options handlers added with PetscObjectAddOptionsHandler() */ ierr = PetscObjectProcessOptionsHandlers((PetscObject)ksp);CHKERRQ(ierr); ierr = PetscOptionsEnd();CHKERRQ(ierr); PetscFunctionReturn(0); }
int main(int argc,char **argv) { AppCtx appctx; /* user-defined application context */ PetscErrorCode ierr; PetscInt i, xs, xm, ind, j, lenglob; PetscReal x, *wrk_ptr1, *wrk_ptr2; MatNullSpace nsp; PetscMPIInt size; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Initialize program and set problem parameters - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ PetscFunctionBegin; ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr; /*initialize parameters */ appctx.param.N = 10; /* order of the spectral element */ appctx.param.E = 10; /* number of elements */ appctx.param.L = 4.0; /* length of the domain */ appctx.param.mu = 0.01; /* diffusion coefficient */ appctx.initial_dt = 5e-3; appctx.param.steps = PETSC_MAX_INT; appctx.param.Tend = 4; ierr = PetscOptionsGetInt(NULL,NULL,"-N",&appctx.param.N,NULL);CHKERRQ(ierr); ierr = PetscOptionsGetInt(NULL,NULL,"-E",&appctx.param.E,NULL);CHKERRQ(ierr); ierr = PetscOptionsGetReal(NULL,NULL,"-Tend",&appctx.param.Tend,NULL);CHKERRQ(ierr); ierr = PetscOptionsGetReal(NULL,NULL,"-mu",&appctx.param.mu,NULL);CHKERRQ(ierr); appctx.param.Le = appctx.param.L/appctx.param.E; ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr); if (appctx.param.E % size) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Number of elements must be divisible by number of processes"); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create GLL data structures - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = PetscGLLCreate(appctx.param.N,PETSCGLL_VIA_LINEARALGEBRA,&appctx.SEMop.gll);CHKERRQ(ierr); lenglob = appctx.param.E*(appctx.param.N-1); /* Create distributed array (DMDA) to manage parallel grid and vectors and to set up the ghost point communication pattern. There are E*(Nl-1)+1 total grid values spread equally among all the processors, except first and last */ ierr = DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_PERIODIC,lenglob,1,1,NULL,&appctx.da);CHKERRQ(ierr); ierr = DMSetFromOptions(appctx.da);CHKERRQ(ierr); ierr = DMSetUp(appctx.da);CHKERRQ(ierr); /* Extract global and local vectors from DMDA; we use these to store the approximate solution. Then duplicate these for remaining vectors that have the same types. */ ierr = DMCreateGlobalVector(appctx.da,&appctx.dat.curr_sol);CHKERRQ(ierr); ierr = VecDuplicate(appctx.dat.curr_sol,&appctx.SEMop.grid);CHKERRQ(ierr); ierr = VecDuplicate(appctx.dat.curr_sol,&appctx.SEMop.mass);CHKERRQ(ierr); ierr = DMDAGetCorners(appctx.da,&xs,NULL,NULL,&xm,NULL,NULL);CHKERRQ(ierr); ierr = DMDAVecGetArray(appctx.da,appctx.SEMop.grid,&wrk_ptr1);CHKERRQ(ierr); ierr = DMDAVecGetArray(appctx.da,appctx.SEMop.mass,&wrk_ptr2);CHKERRQ(ierr); /* Compute function over the locally owned part of the grid */ xs=xs/(appctx.param.N-1); xm=xm/(appctx.param.N-1); /* Build total grid and mass over entire mesh (multi-elemental) */ for (i=xs; i<xs+xm; i++) { for (j=0; j<appctx.param.N-1; j++) { x = (appctx.param.Le/2.0)*(appctx.SEMop.gll.nodes[j]+1.0)+appctx.param.Le*i; ind=i*(appctx.param.N-1)+j; wrk_ptr1[ind]=x; wrk_ptr2[ind]=.5*appctx.param.Le*appctx.SEMop.gll.weights[j]; if (j==0) wrk_ptr2[ind]+=.5*appctx.param.Le*appctx.SEMop.gll.weights[j]; } } ierr = DMDAVecRestoreArray(appctx.da,appctx.SEMop.grid,&wrk_ptr1);CHKERRQ(ierr); ierr = DMDAVecRestoreArray(appctx.da,appctx.SEMop.mass,&wrk_ptr2);CHKERRQ(ierr); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create matrix data structure; set matrix evaluation routine. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = DMSetMatrixPreallocateOnly(appctx.da, PETSC_TRUE);CHKERRQ(ierr); ierr = DMCreateMatrix(appctx.da,&appctx.SEMop.stiff);CHKERRQ(ierr); ierr = DMCreateMatrix(appctx.da,&appctx.SEMop.grad);CHKERRQ(ierr); /* For linear problems with a time-dependent f(u,t) in the equation u_t = f(u,t), the user provides the discretized right-hand-side as a time-dependent matrix. */ ierr = RHSMatrixLaplaciangllDM(appctx.ts,0.0,appctx.dat.curr_sol,appctx.SEMop.stiff,appctx.SEMop.stiff,&appctx);CHKERRQ(ierr); ierr = RHSMatrixAdvectiongllDM(appctx.ts,0.0,appctx.dat.curr_sol,appctx.SEMop.grad,appctx.SEMop.grad,&appctx);CHKERRQ(ierr); /* For linear problems with a time-dependent f(u,t) in the equation u_t = f(u,t), the user provides the discretized right-hand-side as a time-dependent matrix. */ ierr = MatDuplicate(appctx.SEMop.stiff,MAT_COPY_VALUES,&appctx.SEMop.keptstiff);CHKERRQ(ierr); /* attach the null space to the matrix, this probably is not needed but does no harm */ ierr = MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,NULL,&nsp);CHKERRQ(ierr); ierr = MatSetNullSpace(appctx.SEMop.stiff,nsp);CHKERRQ(ierr); ierr = MatSetNullSpace(appctx.SEMop.keptstiff,nsp);CHKERRQ(ierr); ierr = MatNullSpaceTest(nsp,appctx.SEMop.stiff,NULL);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nsp);CHKERRQ(ierr); /* attach the null space to the matrix, this probably is not needed but does no harm */ ierr = MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,NULL,&nsp);CHKERRQ(ierr); ierr = MatSetNullSpace(appctx.SEMop.grad,nsp);CHKERRQ(ierr); ierr = MatNullSpaceTest(nsp,appctx.SEMop.grad,NULL);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nsp);CHKERRQ(ierr); /* Create the TS solver that solves the ODE and its adjoint; set its options */ ierr = TSCreate(PETSC_COMM_WORLD,&appctx.ts);CHKERRQ(ierr); ierr = TSSetProblemType(appctx.ts,TS_NONLINEAR);CHKERRQ(ierr); ierr = TSSetType(appctx.ts,TSRK);CHKERRQ(ierr); ierr = TSSetDM(appctx.ts,appctx.da);CHKERRQ(ierr); ierr = TSSetTime(appctx.ts,0.0);CHKERRQ(ierr); ierr = TSSetTimeStep(appctx.ts,appctx.initial_dt);CHKERRQ(ierr); ierr = TSSetMaxSteps(appctx.ts,appctx.param.steps);CHKERRQ(ierr); ierr = TSSetMaxTime(appctx.ts,appctx.param.Tend);CHKERRQ(ierr); ierr = TSSetExactFinalTime(appctx.ts,TS_EXACTFINALTIME_MATCHSTEP);CHKERRQ(ierr); ierr = TSSetTolerances(appctx.ts,1e-7,NULL,1e-7,NULL);CHKERRQ(ierr); ierr = TSSetSaveTrajectory(appctx.ts);CHKERRQ(ierr); ierr = TSSetFromOptions(appctx.ts);CHKERRQ(ierr); ierr = TSSetRHSFunction(appctx.ts,NULL,RHSFunction,&appctx);CHKERRQ(ierr); ierr = TSSetRHSJacobian(appctx.ts,appctx.SEMop.stiff,appctx.SEMop.stiff,RHSJacobian,&appctx);CHKERRQ(ierr); /* Set Initial conditions for the problem */ ierr = TrueSolution(appctx.ts,0,appctx.dat.curr_sol,&appctx);CHKERRQ(ierr); ierr = TSSetSolutionFunction(appctx.ts,(PetscErrorCode (*)(TS,PetscReal,Vec,void *))TrueSolution,&appctx);CHKERRQ(ierr); ierr = TSSetTime(appctx.ts,0.0);CHKERRQ(ierr); ierr = TSSetStepNumber(appctx.ts,0);CHKERRQ(ierr); ierr = TSSolve(appctx.ts,appctx.dat.curr_sol);CHKERRQ(ierr); ierr = MatDestroy(&appctx.SEMop.stiff);CHKERRQ(ierr); ierr = MatDestroy(&appctx.SEMop.keptstiff);CHKERRQ(ierr); ierr = MatDestroy(&appctx.SEMop.grad);CHKERRQ(ierr); ierr = VecDestroy(&appctx.SEMop.grid);CHKERRQ(ierr); ierr = VecDestroy(&appctx.SEMop.mass);CHKERRQ(ierr); ierr = VecDestroy(&appctx.dat.curr_sol);CHKERRQ(ierr); ierr = PetscGLLDestroy(&appctx.SEMop.gll);CHKERRQ(ierr); ierr = DMDestroy(&appctx.da);CHKERRQ(ierr); ierr = TSDestroy(&appctx.ts);CHKERRQ(ierr); /* Always call PetscFinalize() before exiting a program. This routine - finalizes the PETSc libraries as well as MPI - provides summary and diagnostic information if certain runtime options are chosen (e.g., -log_summary). */ ierr = PetscFinalize(); return ierr; }
/* FormJacobianLocal - Evaluates Jacobian matrix. */ PetscErrorCode FormJacobianLocal(DMDALocalInfo *info, Field **x, Mat A,Mat jac, AppCtx *user) { Field uLocal[4]; PetscScalar JLocal[144]; MatStencil rows[4*3], cols[4*3], ident; PetscInt lowerRow[3] = {0, 1, 3}; PetscInt upperRow[3] = {2, 3, 1}; PetscInt hasLower[3], hasUpper[3], velocityRows[4], pressureRows[4]; PetscScalar alpha,lambda,hx,hy,hxhy,detJInv,G[4],sc,one = 1.0; PetscInt i,j,k,l,numRows,dof = info->dof; PetscErrorCode ierr; MatNullSpace nullspace; Vec N; PetscFunctionBeginUser; alpha = user->alpha; lambda = user->lambda; hx = 1.0/(PetscReal)(info->mx-1); hy = 1.0/(PetscReal)(info->my-1); sc = hx*hy*lambda; hxhy = hx*hy; detJInv = hxhy; G[0] = (1.0/(hx*hx)) * detJInv; G[1] = 0.0; G[2] = G[1]; G[3] = (1.0/(hy*hy)) * detJInv; for (k = 0; k < 4; k++) { /* printf("G[%d] = %g\n", k, G[k]);*/ } ierr = MatZeroEntries(jac);CHKERRQ(ierr); /* Compute entries for the locally owned part of the Jacobian. - Currently, all PETSc parallel matrix formats are partitioned by contiguous chunks of rows across the processors. - Each processor needs to insert only elements that it owns locally (but any non-local elements will be sent to the appropriate processor during matrix assembly). - Here, we set all entries for a particular row at once. - We can set matrix entries either using either MatSetValuesLocal() or MatSetValues(), as discussed above. */ #define NOT_PRES_BC 1 for (j=info->ys; j<info->ys+info->ym-1; j++) { for (i=info->xs; i<info->xs+info->xm-1; i++) { ierr = PetscMemzero(JLocal, 144 * sizeof(PetscScalar));CHKERRQ(ierr); numRows = 0; /* Lower element */ uLocal[0] = x[j][i]; uLocal[1] = x[j][i+1]; uLocal[2] = x[j+1][i+1]; uLocal[3] = x[j+1][i]; /* i,j */ if (i == 0 || j == 0) { hasLower[0] = 0; ierr = MatAssemblyBegin(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ident.i = i; ident.j = j; ident.c = 0; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); ident.i = i; ident.j = j; ident.c = 1; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); #if defined(PRES_BC) ident.i = i; ident.j = j; ident.c = 2; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); #endif ierr = MatAssemblyBegin(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); } else { hasLower[0] = 1; velocityRows[0] = numRows; rows[numRows].i = i; rows[numRows].j = j; rows[numRows].c = 0; numRows++; rows[numRows].i = i; rows[numRows].j = j; rows[numRows].c = 1; numRows++; #if defined(PRES_BC) pressureRows[0] = numRows; rows[numRows].i = i; rows[numRows].j = j; rows[numRows].c = 2; numRows++; #endif } #if !defined(PRES_BC) pressureRows[0] = numRows; rows[numRows].i = i; rows[numRows].j = j; rows[numRows].c = 2; numRows++; #endif cols[0*dof+0].i = i; cols[0*dof+0].j = j; cols[0*dof+0].c = 0; cols[0*dof+1].i = i; cols[0*dof+1].j = j; cols[0*dof+1].c = 1; cols[0*dof+2].i = i; cols[0*dof+2].j = j; cols[0*dof+2].c = 2; /* i+1,j */ if ((i == info->mx-2) || (j == 0)) { hasLower[1] = 0; hasUpper[2] = 0; ierr = MatAssemblyBegin(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ident.i = i+1; ident.j = j; ident.c = 0; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); ident.i = i+1; ident.j = j; ident.c = 1; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); #if defined(PRES_BC) ident.i = i+1; ident.j = j; ident.c = 2; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); #endif ierr = MatAssemblyBegin(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); } else { hasLower[1] = 1; hasUpper[2] = 1; velocityRows[1] = numRows; rows[numRows].i = i+1; rows[numRows].j = j; rows[numRows].c = 0; numRows++; rows[numRows].i = i+1; rows[numRows].j = j; rows[numRows].c = 1; numRows++; #if defined(PRES_BC) pressureRows[1] = numRows; rows[numRows].i = i+1; rows[numRows].j = j; rows[numRows].c = 2; numRows++; #endif } #if !defined(PRES_BC) pressureRows[1] = numRows; rows[numRows].i = i+1; rows[numRows].j = j; rows[numRows].c = 2; numRows++; #endif cols[1*dof+0].i = i+1; cols[1*dof+0].j = j; cols[1*dof+0].c = 0; cols[1*dof+1].i = i+1; cols[1*dof+1].j = j; cols[1*dof+1].c = 1; cols[1*dof+2].i = i+1; cols[1*dof+2].j = j; cols[1*dof+2].c = 2; /* i+1,j+1 */ if ((i == info->mx-2) || (j == info->my-2)) { hasUpper[0] = 0; ierr = MatAssemblyBegin(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ident.i = i+1; ident.j = j+1; ident.c = 0; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); ident.i = i+1; ident.j = j+1; ident.c = 1; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); #if defined(PRES_BC) ident.i = i+1; ident.j = j+1; ident.c = 2; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); #endif ierr = MatAssemblyBegin(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); } else { hasUpper[0] = 1; velocityRows[2] = numRows; rows[numRows].i = i+1; rows[numRows].j = j+1; rows[numRows].c = 0; numRows++; rows[numRows].i = i+1; rows[numRows].j = j+1; rows[numRows].c = 1; numRows++; #if defined(PRES_BC) pressureRows[2] = numRows; rows[numRows].i = i+1; rows[numRows].j = j+1; rows[numRows].c = 2; numRows++; #endif } #if !defined(PRES_BC) pressureRows[2] = numRows; rows[numRows].i = i+1; rows[numRows].j = j+1; rows[numRows].c = 2; numRows++; #endif cols[2*dof+0].i = i+1; cols[2*dof+0].j = j+1; cols[2*dof+0].c = 0; cols[2*dof+1].i = i+1; cols[2*dof+1].j = j+1; cols[2*dof+1].c = 1; cols[2*dof+2].i = i+1; cols[2*dof+2].j = j+1; cols[2*dof+2].c = 2; /* i,j+1 */ if ((i == 0) || (j == info->my-2)) { hasLower[2] = 0; hasUpper[1] = 0; ierr = MatAssemblyBegin(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ident.i = i; ident.j = j+1; ident.c = 0; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); ident.i = i; ident.j = j+1; ident.c = 1; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); #if defined(PRES_BC) ident.i = i; ident.j = j+1; ident.c = 2; ierr = MatSetValuesStencil(jac,1,&ident,1,&ident,&one,INSERT_VALUES);CHKERRQ(ierr); #endif ierr = MatAssemblyBegin(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FLUSH_ASSEMBLY);CHKERRQ(ierr); } else { hasLower[2] = 1; hasUpper[1] = 1; velocityRows[3] = numRows; rows[numRows].i = i; rows[numRows].j = j+1; rows[numRows].c = 0; numRows++; rows[numRows].i = i; rows[numRows].j = j+1; rows[numRows].c = 1; numRows++; #if defined(PRES_BC) pressureRows[3] = numRows; rows[numRows].i = i; rows[numRows].j = j+1; rows[numRows].c = 2; numRows++; #endif } #if !defined(PRES_BC) pressureRows[3] = numRows; rows[numRows].i = i; rows[numRows].j = j+1; rows[numRows].c = 2; numRows++; #endif cols[3*dof+0].i = i; cols[3*dof+0].j = j+1; cols[3*dof+0].c = 0; cols[3*dof+1].i = i; cols[3*dof+1].j = j+1; cols[3*dof+1].c = 1; cols[3*dof+2].i = i; cols[3*dof+2].j = j+1; cols[3*dof+2].c = 2; /* Lower Element */ for (k = 0; k < 3; k++) { #if defined(PRES_BC) if (!hasLower[k]) continue; #endif for (l = 0; l < 3; l++) { /* Divergence */ JLocal[pressureRows[lowerRow[k]]*dof*4 + lowerRow[l]*dof+0] += hx*Divergence[(k*2+0)*3 + l]; JLocal[pressureRows[lowerRow[k]]*dof*4 + lowerRow[l]*dof+1] += hy*Divergence[(k*2+1)*3 + l]; /* JLocal[pressureRows[lowerRow[k]]*dof*4 + lowerRow[l]*dof+2] += Identity[k*3 + l]; */ } if (!hasLower[k]) continue; for (l = 0; l < 3; l++) { /* Laplacian */ JLocal[velocityRows[lowerRow[k]]*dof*4 + lowerRow[l]*dof+0] += alpha*(G[0]*Kref[(k*2*3 + l)*2]+G[1]*Kref[(k*2*3 + l)*2+1]+G[2]*Kref[((k*2+1)*3 + l)*2]+G[3]*Kref[((k*2+1)*3 + l)*2+1]); JLocal[(velocityRows[lowerRow[k]]+1)*dof*4 + lowerRow[l]*dof+1] += alpha*(G[0]*Kref[(k*2*3 + l)*2]+G[1]*Kref[(k*2*3 + l)*2+1]+G[2]*Kref[((k*2+1)*3 + l)*2]+G[3]*Kref[((k*2+1)*3 + l)*2+1]); /* JLocal[velocityRows[lowerRow[k]]*dof*4 + lowerRow[l]*dof+0] += Identity[k*3 + l]; */ /* JLocal[(velocityRows[lowerRow[k]]+1)*dof*4 + lowerRow[l]*dof+1] += Identity[k*3 + l]; */ /* Gradient */ JLocal[velocityRows[lowerRow[k]]*dof*4 + lowerRow[l]*dof+2] += hx*Gradient[(k*2+0)*3 + l]; JLocal[(velocityRows[lowerRow[k]]+1)*dof*4 + lowerRow[l]*dof+2] += hy*Gradient[(k*2+1)*3 + l]; } } /* Upper Element */ for (k = 0; k < 3; k++) { #if defined(PRES_BC) if (!hasUpper[k]) continue; #endif for (l = 0; l < 3; l++) { /* Divergence */ JLocal[pressureRows[upperRow[k]]*dof*4 + upperRow[l]*dof+0] += hx*Divergence[(k*2+0)*3 + l]; JLocal[pressureRows[upperRow[k]]*dof*4 + upperRow[l]*dof+1] += hy*Divergence[(k*2+1)*3 + l]; /* JLocal[pressureRows[upperRow[k]]*dof*4 + upperRow[l]*dof+2] += Identity[k*3 + l]; */ } if (!hasUpper[k]) continue; for (l = 0; l < 3; l++) { /* Laplacian */ JLocal[velocityRows[upperRow[k]]*dof*4 + upperRow[l]*dof+0] += alpha*(G[0]*Kref[(k*2*3 + l)*2]+G[1]*Kref[(k*2*3 + l)*2+1]+G[2]*Kref[((k*2+1)*3 + l)*2]+G[3]*Kref[((k*2+1)*3 + l)*2+1]); JLocal[(velocityRows[upperRow[k]]+1)*dof*4 + upperRow[l]*dof+1] += alpha*(G[0]*Kref[(k*2*3 + l)*2]+G[1]*Kref[(k*2*3 + l)*2+1]+G[2]*Kref[((k*2+1)*3 + l)*2]+G[3]*Kref[((k*2+1)*3 + l)*2+1]); /* Gradient */ JLocal[velocityRows[upperRow[k]]*dof*4 + upperRow[l]*dof+2] += hx*Gradient[(k*2+0)*3 + l]; JLocal[(velocityRows[upperRow[k]]+1)*dof*4 + upperRow[l]*dof+2] += hy*Gradient[(k*2+1)*3 + l]; } } ierr = nonlinearJacobian(-1.0*PetscAbsScalar(sc), uLocal, JLocal);CHKERRQ(ierr); /* printf("Element matrix for (%d, %d)\n", i, j);*/ /* printf(" col ");*/ for (l = 0; l < 4*3; l++) { /* printf("(%d, %d, %d) ", cols[l].i, cols[l].j, cols[l].c);*/ } /* printf("\n");*/ for (k = 0; k < numRows; k++) { /* printf("row (%d, %d, %d): ", rows[k].i, rows[k].j, rows[k].c);*/ for (l = 0; l < 4; l++) { /* printf("%9.6g %9.6g %9.6g ", JLocal[k*dof*4 + l*dof+0], JLocal[k*dof*4 + l*dof+1], JLocal[k*dof*4 + l*dof+2]);*/ } /* printf("\n");*/ } ierr = MatSetValuesStencil(jac,numRows,rows,4*dof,cols, JLocal,ADD_VALUES);CHKERRQ(ierr); } } /* Assemble matrix, using the 2-step process: MatAssemblyBegin(), MatAssemblyEnd(). */ ierr = MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); if (A != jac) { ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); } /* Tell the matrix we will never add a new nonzero location to the matrix. If we do, it will generate an error. */ ierr = MatSetOption(jac,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); ierr = CreateNullSpace(info->da,&N);CHKERRQ(ierr); ierr = MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_FALSE,1,&N,&nullspace);CHKERRQ(ierr); ierr = VecDestroy(&N);CHKERRQ(ierr); ierr = MatSetNullSpace(jac,nullspace);CHKERRQ(ierr); ierr = MatNullSpaceDestroy(&nullspace);CHKERRQ(ierr); PetscFunctionReturn(0); }