int main(int argc, char *argv[]) { MAT *A, *B; VEC *U = NULL, *x; FLOAT *C; SOLVER *solver, *solver1 = NULL; INT i, j, k, n, *pvt, N = 1000, K = 2; char *main_opts = NULL, *sub_opts = NULL; phgOptionsRegisterInt("-n", "N value", &N); phgOptionsRegisterInt("-k", "K value", &K); phgOptionsRegisterString("-main_solver_opts", "Options for the main solver", &main_opts); phgOptionsRegisterString("-sub_solver_opts", "Options for the subsolver", &sub_opts); /* a direct solver is preferable for the sparse matrix */ phgOptionsPreset("-solver mumps"); phgInit(&argc, &argv); phgPrintf( "----------------------------------------------------------------------------\n" "This code solves (A+UU^t)x=b using the Sherman-Morrison-Woodbury formula.\n" "Note: may use the following to disable use of the Sherman-Morrison-Woodbury\n" "algorithm and change to the default solver instead:\n" " -preonly_pc_type solver -preonly_pc_opts \"-solver_maxit 2000\"\n" "----------------------------------------------------------------------------\n" ); phgPrintf("Generating the linear system: N = %"dFMT", K = %"dFMT"\n", N, K); /* A is a distributed NxN SPD tridiagonal matrix (A = [-1, 2, -1]) */ n = N / phgNProcs + (phgRank < (N % phgNProcs) ? 1 : 0); A = phgMatCreate(phgComm, n, N); phgPrintf(" Generating matrix A.\n"); for (i = 0; i < n; i++) { /* diagonal */ phgMatAddEntry(A, i, i, 2.0); /* diagonal - 1 */ if (i > 0) phgMatAddEntry(A, i, i - 1, -1.0); else if (phgRank > 0) phgMatAddLGEntry(A, i, A->rmap->partition[phgRank] - 1, -1.0); /* diagonal + 1 */ if (i < n - 1) phgMatAddEntry(A, i, i + 1, -1.0); else if (phgRank < phgNProcs - 1) phgMatAddLGEntry(A, i, A->rmap->partition[phgRank] + n, -1.0); } phgMatAssemble(A); /* U is a K-component vector */ U = phgMapCreateVec(A->rmap, K); phgVecRandomize(U, 123); /* solver1 is the solver for A */ phgOptionsPush(); phgOptionsSetOptions(sub_opts); solver1 = phgMat2Solver(SOLVER_DEFAULT, A); phgOptionsPop(); /* x is a scratch vector */ x = phgMapCreateVec(A->rmap, 1); /* C is a KxK dense matrix, pvt is an integer array, they store the LU * factorization of (I + U^t*inv(A)*U) */ phgPrintf(" Generating the dense matrix I+U^t*inv(A)*U.\n"); C = phgCalloc(K * K, sizeof(*C)); pvt = phgAlloc(K * sizeof(*pvt)); for (i = 0; i < K; i++) { for (j = 0; j < n; j++) { solver1->rhs->data[j] = U->data[i * n + j]; x->data[j] = 0.0; } solver1->rhs->assembled = TRUE; phgSolverVecSolve(solver1, FALSE, x); for (j = 0; j < K; j++) for (k = 0; k < n; k++) C[i * K + j] += U->data[j * n + k] * x->data[k]; } #if USE_MPI if (U->map->nprocs > 1) { FLOAT *tmp = phgAlloc(K * K * sizeof(*tmp)); MPI_Allreduce(C, tmp, K * K, PHG_MPI_FLOAT, MPI_SUM, U->map->comm); phgFree(C); C = tmp; } #endif /* USE_MPI */ for (i = 0; i < K; i++) C[i * K + i] += 1.0; phgPrintf(" Factorizing the dense matrix I+U^t*inv(A)*U.\n"); phgSolverDenseLU(K, C, pvt); /* B is a matrix-free matrix representing A + U*U^t, B->mv_data is used * to pass A, U, solver1, C and pvt to callback functions */ B = phgMapCreateMatrixFreeMat(A->rmap, A->cmap, funcB, /* arguments carried over to CB functions */ A, U, solver1, C, pvt, NULL); /* solver is a PreOnly solver for B whose pc_proc is set to sherman(). * * Note: can also use pcg, gmres, or petsc for this solver, in this case * the solution obtained with the Sherman-Morisson formula is iteratively * refined. */ phgOptionsPush(); phgOptionsSetOptions("-solver preonly"); phgOptionsSetOptions(main_opts); solver = phgMat2Solver(SOLVER_DEFAULT, B); phgSolverSetPC(solver, solver, sherman); phgOptionsPop(); for (i = 0; i < n; i++) x->data[i] = 1.0; phgMatVec(MAT_OP_N, 1.0, B, x, 0.0, &solver->rhs); phgPrintf("Solving the linear system.\n"); /* reset initial solution to zero */ memset(x->data, 0, n * sizeof(*x->data)); phgSolverVecSolve(solver, TRUE, x); for (i = 0; i < n; i++) solver->rhs->data[i] = 1.0; phgVecAXPBY(-1.0, solver->rhs, 1.0, &x); phgPrintf("Checking the result: |x - x_exact| / |x_exact| = %lg\n", (double)phgVecNorm2(x, 0, NULL) / sqrt((double)N)); phgSolverDestroy(&solver); phgSolverDestroy(&solver1); phgMatDestroy(&A); phgMatDestroy(&B); phgVecDestroy(&U); phgVecDestroy(&x); phgFree(C); phgFree(pvt); phgFinalize(); return 0; }
void phgNSInitPc(NSSolver *ns) { GRID *g = ns->g; MAP *Pmap = ns->Pmap, *Pbcmap; BOOLEAN use_Fu = _nsp->use_Fu; int verb; /* pcd boundary type test */ _pcd->dof_inflow = phgDofNew(g, _nsp->ptype, 1, "dof inflow", DofNoAction); _pcd->dof_outflow = phgDofNew(g, _nsp->ptype, 1, "dof outflow", DofNoAction); _pcd->dof_nobdry = phgDofNew(g, _nsp->ptype, 1, "dof nobdry", DofNoAction); phgDofSetDirichletBoundaryMask(_pcd->dof_inflow, INFLOW); phgDofSetDirichletBoundaryMask(_pcd->dof_outflow, OUTFLOW); phgDofSetDirichletBoundaryMask(_pcd->dof_nobdry, 0); _pcd->map_inflow = phgMapCreate(_pcd->dof_inflow, NULL); _pcd->map_outflow = phgMapCreate(_pcd->dof_outflow, NULL); _pcd->map_nobdry = phgMapCreate(_pcd->dof_nobdry, NULL); _pcd->Pbcmap = phgMapCreate(_pcd->pbc, NULL); Pbcmap = _pcd->Pbcmap; Unused(Pmap); #warning PCD B.C.: step 1. build mat using map... /* * PCD boundary setup: should be consistent with code above */ if (_nsp->pin_node) { _pcd->matFp = phgMapCreateMat(Pbcmap, Pbcmap); _pcd->matAp = phgMapCreateMat(Pbcmap, Pbcmap); _pcd->matQp = phgMapCreateMat(Pbcmap, Pbcmap); } else { //_pcd->matAp = phgMapCreateMat(_pcd->map_inflow, _pcd->map_inflow); //_pcd->matFp = phgMapCreateMat(_pcd->map_inflow, _pcd->map_inflow); _pcd->matFp = phgMapCreateMat(_pcd->map_outflow, _pcd->map_outflow); _pcd->matAp = phgMapCreateMat(_pcd->map_outflow, _pcd->map_outflow); //_pcd->matQp = phgMapCreateMat(_pcd->map_outflow, _pcd->map_outflow); //_pcd->matQp = phgMapCreateMat(_pcd->map_inflow, _pcd->map_inflow); //_pcd->matFp = phgMapCreateMat(_pcd->map_nobdry, _pcd->map_nobdry); //_pcd->matAp = phgMapCreateMat(_pcd->map_nobdry, _pcd->map_nobdry); //_pcd->matFp = phgMapCreateMat(_pcd->map_nobdry, _pcd->map_nobdry); _pcd->matQp = phgMapCreateMat(_pcd->map_nobdry, _pcd->map_nobdry); } /* stokes problem: get SYMETRIC mat when assemble. * Handle_bdry_eqns means mat is composed with row of boundary row * and non-bdry row, and eliminating mat columes of dirichlet dof. */ if (_nsp->use_symetric) { _pcd->matFp->handle_bdry_eqns = TRUE; _pcd->matAp->handle_bdry_eqns = TRUE; _pcd->matQp->handle_bdry_eqns = TRUE; } /* genearl NS: no need to eliminate mat columes of dirichlet dof */ else { _pcd->matFp->handle_bdry_eqns = FALSE; _pcd->matAp->handle_bdry_eqns = FALSE; _pcd->matQp->handle_bdry_eqns = FALSE; } _pcd->rhsScale = phgMapCreateVec(_pcd->matQp->rmap, 1); phgVecDisassemble(_pcd->rhsScale); ns->pc = phgMat2Solver(SOLVER_PreOnly, ns->solver_u->mat); if (_nsp->use_PCD) phgSolverSetPC(ns->solver_u, ns->pc, pc_proc); /* solver F */ phgOptionsPush(); phgOptionsSetOptions("-solver hypre " "-hypre_solver pcg " "-hypre_pc boomeramg " "-solver_maxit 10 " "-solver_rtol 1e-4"); phgOptionsSetOptions(_nsp->F_opts); /* use matF in the preconditioning matrix */ _pcd->solver_F = phgMat2Solver(SOLVER_DEFAULT, ns->matF); _pcd->solver_F->verb = SUB_SOLVER_VERB; /* Set user options. */ _pcd->pc_F = NULL; #if USE_MG if (ns_params->use_mg_F) { MAT *matF = ns->matF; assert(ns_params->use_PCD && !ns_params->use_Fu); _pcd->pc_F = phgMat2Solver(SOLVER_PreOnly, matF); phgOptionsSetOptions("-solver petsc "); matF->mv_data = phgAlloc(sizeof(*matF->mv_data)); matF->mv_data[0] = (void *) ns->mg; phgSolverSetPC(_pcd->solver_F, _pcd->pc_F, mg_pc_proc); } #endif /* USE_MG */ _pcd->solver_F->warn_maxit = FALSE; phgOptionsPop(); /* solver Ap */ phgOptionsPush(); phgOptionsSetOptions("-solver hypre " "-hypre_solver gmres " "-hypre_pc boomeramg " "-solver_maxit 10 " "-solver_rtol 1e-3"); phgOptionsSetOptions(_nsp->Ap_opts); _pcd->solver_Ap = phgMat2Solver(SOLVER_DEFAULT, _pcd->matAp); _pcd->solver_Ap->warn_maxit = FALSE; _pcd->solver_Ap->verb = SUB_SOLVER_VERB; phgOptionsPop(); _pcd->pc_Ap = NULL; #if USE_MG if (ns_params->use_mg_Ap) { MAT *matAp = _pcd->matAp; assert(ns_params->use_PCD); _pcd->pc_Ap = phgMat2Solver(SOLVER_PreOnly, matAp); phgOptionsSetOptions("-solver petsc "); matAp->mv_data = phgAlloc(sizeof(*matAp->mv_data)); matAp->mv_data[0] = (void *) ns->mg; phgSolverSetPC(_pcd->solver_Ap, _pcd->pc_Ap, mg_pc_proc); } #endif /* USE_MG */ /* solver Qp */ phgOptionsPush(); phgOptionsSetOptions("-solver hypre " "-hypre_solver pcg " "-hypre_pc boomeramg " "-solver_maxit 10 " "-solver_rtol 1e-3"); phgOptionsSetOptions(_nsp->Qp_opts); _pcd->solver_Qp = phgMat2Solver(SOLVER_DEFAULT, _pcd->matQp); _pcd->solver_Qp->warn_maxit = FALSE; _pcd->solver_Qp->verb = SUB_SOLVER_VERB; phgOptionsPop(); _pcd->pc_Qp = NULL; #if USE_MG if (ns_params->use_mg_Qp) { MAT *matQp = _pcd->matQp; assert(ns_params->use_PCD); _pcd->pc_Qp = phgMat2Solver(SOLVER_PreOnly, matQp); phgOptionsSetOptions("-solver petsc "); matQp->mv_data = phgAlloc(sizeof(*matQp->mv_data)); matQp->mv_data[0] = (void *) ns->mg; phgSolverSetPC(_pcd->solver_Qp, _pcd->pc_Qp, mg_pc_proc); } #endif /* USE_MG */ /* Fu for solve F^{-1} */ if (use_Fu) { /* _nsp->implicit_centrip && */ DOF *u1; MAP *u1map; MAT *matFu; u1 = _pcd->u1 = phgDofNew(g, _nsp->utype, 1, "velocity component u", DofNoAction); phgDofSetDirichletBoundaryMask(u1, SETFLOW); u1map = _pcd->u1map = phgMapCreate(_pcd->u1, NULL); matFu = _pcd->matFu = phgMapCreateMat(u1map, u1map); if (_nsp->use_symetric) matFu->handle_bdry_eqns = TRUE; /* solver Fu */ phgOptionsPush(); phgOptionsSetOptions("-solver hypre " "-hypre_solver pcg " "-hypre_pc boomeramg " "-solver_maxit 10 " "-solver_rtol 1e-4"); phgOptionsSetOptions(_nsp->Fu_opts); _pcd->solver_Fu = phgMat2Solver(SOLVER_DEFAULT, _pcd->matFu); _pcd->solver_Fu->warn_maxit = FALSE; _pcd->solver_Fu->verb = SUB_SOLVER_VERB; phgOptionsPop(); } return; }