static void getMoveDirection(MovingMesh *mmesh) { GRID *g = _m->g; SIMPLEX *e; DOF *logical_move = _m->logical_move; DOF *logical_node = _m->logical_node; DOF *move = _m->move; DOF *logical_node_new, *grad_logical_node; INT i, j, k, l0, l1; SOLVER *solver; DOF *mass_lumping; FLOAT *v_move, *v_mass; FLOAT max_vol = -1e10, min_vol = 1e10; /* Get new monitor */ _m->get_monitor(mmesh); DOF_SCALE(_m->monitor); logical_node_new = phgDofCopy(logical_node, NULL, NULL, "new logical node coordinates"); grad_logical_node = phgDofGradient(logical_node, NULL, NULL, "grad logical node coordinates"); /* if (logical_node_new->DB_mask == UNDEFINED) */ /* phgError(1, "g->types_vert and DB_mask is VAILD in moving mesh method!!!"); */ /* Create move solver */ phgOptionsPush(); #if 0 phgOptionsSetOptions("-default_solver mm_ml " "-mm_ml_solver gmres " "-mm_ml_pc mm_ml " "-mm_ml_sweep0 6 " "-solver_maxit 100 " "-solver_rtol 1e-12 "); #else phgOptionsSetOptions("-default_solver hypre " "-hypre_solver gmres " "-hypre_pc boomeramg " "-solver_maxit 100 " "-solver_rtol 1e-12 "); #endif phgOptionsSetOptions(_mp->move_opts); setMoveConstrain(mmesh, logical_node_new); solver = phgSolverCreate(SOLVER_DEFAULT, logical_node_new, NULL); solver->mat->mv_data = phgAlloc(sizeof(*solver->mat->mv_data)); solver->mat->mv_data[0] = (void *) mmesh; phgOptionsPop(); /* build mat */ ForAllElements(g, e) { int order = 1, q; int N = DofGetNBas(logical_node, e); /* number of bases in the element */ FLOAT A[N][Dim][N][Dim], rhs[N][Dim]; INT I[N][Dim]; QUAD *quad; const FLOAT *w, *lambda; FLOAT vol, mon; vol = phgGeomGetVolume(g, e); max_vol = MAX(max_vol, vol); min_vol = MIN(min_vol, vol); for (i = 0; i < N; i++) for (k = 0; k < Dim; k++) I[i][k] = phgMapE2L(solver->rhs->map, 0, e, i * Dim + k); bzero(A, sizeof(A)); bzero(rhs, sizeof(rhs)); quad = phgQuadGetQuad3D(order); mon = *DofElementData(_m->monitor, e->index); //printf("mon:%e\n", mon); lambda = quad->points; w = quad->weights; assert(quad->npoints == 1); for (q = 0; q < quad->npoints; q++) { for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { const FLOAT *ggi = phgQuadGetBasisGradient(e, _m->move, i, quad) + q*Dim; /* grad phi_i */ const FLOAT *ggj = phgQuadGetBasisGradient(e, _m->move, j, quad) + q*Dim; /* grad phi_j */ FLOAT a = vol*(*w) * mon * INNER_PRODUCT(ggj, ggi); for (k = 0; k < Dim; k++) { A[i][k][j][k] += a; } } } w++; lambda += Dim + 1; } /* end quad point */ for (i = 0; i < N; i++) { INT vert0 = e->verts[i]; if (_mp->fix_bdry || MM_FIXED(g->types_vert[vert0])) { /* no move */ bzero(A[i], sizeof(A[i])); for (k = 0; k < Dim; k++) { A[i][k][i][k] = 1.; rhs[i][k] = logical_node->data[vert0 * Dim + k]; } } else if (g->types_vert[vert0] & MM_CONSTR) { VERT_CONSTRAIN *vert_constr = _m->vert_constr + _m->vert_constr_index[vert0]; FLOAT *trans = vert_constr->Trans; FLOAT *bb = vert_constr->bb; assert(_m->vert_constr_index[vert0] >= 0); assert(vert0 == vert_constr->index); trans_left_ (&A[i][0][0][0], Dim*N, Dim*N, trans); trans_right_(&A[0][0][i][0], Dim*N, Dim*N, trans); if (vert_constr->n_constrain == 2) { bzero(A[i][0], sizeof(A[i][0])); bzero(A[i][1], sizeof(A[i][1])); A[i][0][i][0] = 1.; A[i][1][i][1] = 1.; rhs[i][0] = bb[0]; rhs[i][1] = bb[1]; } else if (vert_constr->n_constrain == 1) { bzero(A[i][0], sizeof(A[i][0])); A[i][0][i][0] = 1.; rhs[i][0] = bb[0]; } else { abort(); } } } for (i = 0; i < N; i++) phgSolverAddMatrixEntries(solver, Dim, &I[i][0], N * Dim, I[0], &A[i][0][0][0]); phgSolverAddRHSEntries(solver, N * Dim, &I[0][0], &rhs[0][0]); }
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; }