/**************************************************************** * Build RHS which is the residual of the nonlinear system. ***************************************************************/ void phgNSBuildSolverURHS(NSSolver *ns) { GRID *g = ns->g; SIMPLEX *e; SOLVER *solver_u = ns->solver_u; int i, k, l, q, s; FLOAT *dt = ns->dt; BOOLEAN tstep_minus = (ns->u[-1] != NULL); VEC *vec_rhs = phgMapCreateVec(solver_u->rhs->map, 1); FLOAT Theta = _nsp->Theta, nu = _nsp->nu, Thet1; int viscosity_type = ns->viscosity_type; SURF_BAS *surf_bas = ns->surf_bas; DOF *surf_dof = surf_bas->dof; BOOLEAN *rotated = surf_bas->rotated; const FLOAT *Trans = DofData(surf_dof); #if STEADY_STATE assert(fabs(Theta - 1) < 1e-12); Thet1 = 0; Unused(Thet1); Unused(dt); #else Thet1 = 1 - Theta; Unused(dt); #endif /* STEADY_STATE */ phgPrintf(" DB_mask: ["); for (k = 0; k < Dim; k++) phgPrintf("%d ", ns->u[1]->DB_masks[k]); phgPrintf("] "); nu_max = -1e10; nu_min = +1e10; phgVecDisassemble(vec_rhs); ForAllElements(g, e) { int M = ns->u[1]->type->nbas; /* num of bases of Velocity */ int N = ns->p[1]->type->nbas; /* num of bases of Pressure */ int order = DofTypeOrder(ns->u[1], e) * 3 - 1; /* Note: * quad order is really high here, * highest order term (u \nabla u, phi) */ FLOAT bufu[M], bufp[N], rhsu[M][Dim], rhsp[N]; INT Iu[M][Dim], Ip[N]; QUAD *quad; FLOAT vol, area, det; const FLOAT *w, *p, *normal, **vu, *vu_queue[3], *vf[2], *gu[2], *vp[2], *vw, *vT; FLOAT *vf_cache[2]; vu = vu_queue + 1; quad = phgQuadGetQuad3D(order); vu[0] = phgQuadGetDofValues(e, ns->u[0], quad); /* u^{n} */ vp[0] = phgQuadGetDofValues(e, ns->p[0], quad); /* p^{n} */ gu[0] = phgQuadGetDofValues(e, ns->gradu[0], quad); /* grad u^{n} */ vw = phgQuadGetDofValues(e, ns->wind, quad); /* wind */ vT = phgQuadGetDofValues(e, ns->T[1], quad); /* T^{n} */ if (tstep_minus) { vu[-1] = phgQuadGetDofValues(e, ns->u[-1], quad); /* u^{n-1} */ } else { vu[-1] = vu[0]; } #if STEADY_STATE || TIME_DEP_NON vu[1] = phgQuadGetDofValues(e, ns->u[1], quad); /* u^{n+1} */ gu[1] = phgQuadGetDofValues(e, ns->gradu[1], quad); /* grad u^{n} */ vp[1] = phgQuadGetDofValues(e, ns->p[1], quad); /* p^{n+1} */ #else TIME_DEP_LINEAR_ENTRY; /* Unavailable */ #endif /* STEADY_STATE || TIME_DEP_NON */ Unused(l); Unused(vf); Unused(vf_cache); if (!_nsp->no_extern_source) { /* cache f values */ for (l = 0; l < 2; l++) { const FLOAT *cache; size_t cache_size; setFuncTime(ns->time[l]); /* set static time in ins-test.c */ /* cache f */ cache_size = Dim * quad->npoints * sizeof(FLOAT); cache = phgQuadGetFuncValues(g, e, Dim, func_f, quad); vf[l] = vf_cache[l] = phgAlloc(cache_size); memcpy(vf_cache[l], cache, cache_size); phgQuadGetFuncValues(NULL, NULL, 0, NULL, NULL); /* clear cache */ } } /* Global Matrix */ Bzero(rhsu); Bzero(rhsp); p = quad->points; w = quad->weights; for (q = 0; q < quad->npoints; q++) { phgGeomGetCurvedJacobianAtLambda(g, e, p, &det); vol = fabs(det / 6.); /* rhs u */ for (i = 0; i < M; i++) { /* interior node or Neumann */ const FLOAT *gi_u = phgQuadGetBasisValues(e, ns->u[1], i, quad) + q; /* phi_i */ const FLOAT *ggi_u = phgQuadGetBasisCurvedGradient(e, ns->u[1], i, quad, q); /* grad phi_i */ for (k = 0; k < Dim; k++) { #if ICE_BENCH_TEST nu = get_effective_viscosity(gu[1], 0, 0, viscosity_type); FLOAT eu[DDim]; MAT3_SYM(gu[1], eu); rhsu[i][k] += vol*(*w) * EQU_SCALING * (- nu * INNER_PRODUCT(eu+k*Dim, ggi_u) + (*vp[1]) * *(ggi_u+k) * LEN_SCALING * PRES_SCALING ); /* left */ if (k == Z_DIR) { const FLOAT rho = RHO_ICE; const FLOAT grav = GRAVITY; const FLOAT a = SEC_PER_YEAR; const FLOAT f = rho*grav * EQU_SCALING * LEN_SCALING2; Unused(a); rhsu[i][k] += vol*(*w) * (-f * (*gi_u) ); /* right */ } #elif ESIMINT_TEST || \ HEINO_TEST || \ TEST_CASE == ICE_GREEN_LAND nu = get_effective_viscosity(gu[1], *vT, 0, viscosity_type); FLOAT eu[DDim]; MAT3_SYM(gu[1], eu); rhsu[i][k] += vol*(*w) * EQU_SCALING * (- nu * INNER_PRODUCT(eu+k*Dim, ggi_u) + (*vp[1]) * *(ggi_u+k) * LEN_SCALING * PRES_SCALING ); /* left */ if (k == Z_DIR) { const FLOAT rho = RHO_ICE; const FLOAT grav = GRAVITY; const FLOAT a = SEC_PER_YEAR; const FLOAT f = rho*grav * EQU_SCALING * LEN_SCALING2; Unused(a); rhsu[i][k] += vol*(*w) * (-f * (*gi_u) ); /* right */ } #elif STEADY_STATE rhsu[i][k] += vol*(*w) * (- nu * INNER_PRODUCT(gu[1]+k*Dim, ggi_u) + (*vp[1]) * *(ggi_u+k) ); /* left */ if (!_nsp->no_extern_source) rhsu[i][k] += vol*(*w) * (*(vf[1]+k) * (*gi_u) ); /* right */ #elif TIME_DEP_NON rhsu[i][k] -= vol*(*w) * ((vu[1][k] - vu[0][k]) * (*gi_u) / dt[0] + Theta * (nu * INNER_PRODUCT(gu[1]+k*Dim, ggi_u) ) - (*vp[1]) * *(ggi_u+k) + Thet1 * (nu * INNER_PRODUCT(gu[0]+k*Dim, ggi_u) ) ); /* left */ if (!_nsp->no_extern_source) rhsu[i][k] += vol*(*w) * (Theta * *(vf[1]+k) * (*gi_u) + Thet1 * *(vf[0]+k) * (*gi_u) ); /* right */ #else TIME_DEP_LINEAR_ENTRY; /* Unavailable */ #endif /* STEADY_STATE */ } } /* rhs p */ for (i = 0; i < N; i++) { const FLOAT *gi_p = phgQuadGetBasisValues(e, ns->p[1], i, quad) + q; /* psi_i */ FLOAT divu1 = gu[1][0] + gu[1][4] + gu[1][8]; //FLOAT divu0 = gu[0][0] + gu[0][4] + gu[0][8]; rhsp[i] += vol*(*w) * (divu1 * (*gi_p) ); } if (tstep_minus) vu[-1] += Dim; #if STEADY_STATE || TIME_DEP_NON vu[1] += Dim; gu[1] += Dim*Dim; vp[1]++; #else TIME_DEP_LINEAR; /* Unavailable */ #endif /* STEADY_STATE || TIME_DEP_NON */ vu[0] += Dim; gu[0] += Dim * Dim; vp[0]++; vw += Dim; if (!_nsp->no_extern_source) { vf[0] += Dim; vf[1] += Dim; } vT++; w++; p += Dim + 1; } if (!_nsp->no_extern_source) { phgFree(vf_cache[0]); phgFree(vf_cache[1]); } normal = NULL; Unused(normal); area = 0; Unused(area); if (!_nsp->enclosed_flow) { /* slip boundary */ for (s = 0; s < NFace; s++) { if (e->bound_type[s] & INFLOW) { int v0, v1, v2; int nbas_face = NbasFace(ns->u[1]); SHORT bases[nbas_face]; FLOAT lambda[Dim + 1], x,y,z, beta; order = DofTypeOrder(ns->u[1], e) * 3 - 1; phgDofGetBasesOnFace(ns->u[1], e, s, bases); v0 = GetFaceVertex(s, 0); v1 = GetFaceVertex(s, 1); v2 = GetFaceVertex(s, 2); lambda[s] = 0.; area = phgGeomGetFaceArea(g, e, s); normal = phgGeomGetFaceOutNormal(g, e, s); quad = phgQuadGetQuad2D(order); p = quad->points; w = quad->weights; for (q = 0; q < quad->npoints; q++) { FLOAT vu[Dim]; lambda[v0] = *(p++); lambda[v1] = *(p++); lambda[v2] = *(p++); phgGeomLambda2XYZ(g, e, lambda, &x, &y, &z); func_beta(x, y, z, &beta); phgDofEval(ns->u[1], e, lambda, vu); for (i = 0; i < nbas_face; i++) { int ii = bases[i]; FLOAT gi_u = *ns->u[1]->type->BasFuncs(ns->u[1], e, ii, ii + 1, lambda); for (k = 0; k < Dim; k++) { #if STEADY_STATE rhus[ii][k] += 0.; #elif TIME_DEP_NON # if USE_SLIDING_BC abort(); rhsu[ii][k] += SIGN_FRICTION * area*(*w) * beta * vu[k] * (gi_u) * EQU_SCALING * LEN_SCALING; # else Unused(gi_u); # endif #else TIME_DEP_LINEAR_ENTRY; /* Unavailable */ #endif /* STEADY_STATE */ } } /* end of bas_i */ w++; } /* end of quad point */ } /* end of face outflow */ } /* end of all outflow face in element */ } /* end out flow boundary */ #if USE_SLIDING_BC /* Rotate bases */ for (i = 0; i < M; i++) { INT id = phgDofMapE2D(surf_dof, e, i * (Dim*Dim)) / (Dim*Dim); if (!rotated[id]) continue; const FLOAT *trans = Trans + id*(Dim*Dim); trans_left(&rhsu[i][0], 1, 1, trans); } #else Unused(Trans); Unused(rotated); #endif /* Map: Element -> system */ for (i = 0; i < M; i++) for (k = 0; k < Dim; k++) Iu[i][k] = phgMapE2L(solver_u->rhs->map, 0, e, i * Dim + k); for (i = 0; i < N; i++) Ip[i] = phgMapE2L(solver_u->rhs->map, 1, e, i); /* set velocity dirichlet bdry */ FLOAT tmp[Dim]; for (i = 0; i < M; i++) for (k = 0; k < Dim; k++) if (phgDofDirichletBC_(ns->u[1], e, i*Dim+k, NULL, bufu, tmp, DOF_PROJ_NONE)) { rhsu[i][k] = 0.; } #if STEADY_STATE || TIME_DEP_NON /* set pressure dirichlet bdry for pinned point */ for (i = 0; i < N; i++) if (phgDofDirichletBC(ns->p[1], e, i, NULL, bufp, &rhsp[i], DOF_PROJ_NONE)) { if (!_nsp->enclosed_flow) phgError(1, "No dirichlet bc for Unenclosed flow!\n"); if (_nsp->pin_node) { # if PIN_AT_ROOT if (g->rank != 0) phgError(1, "Pinned node only on rank 0!\n"); if (g, e->verts[i] != ns->pinned_node_id) phgError(1, "Build rhs: pinned node e:%d, bas:%d, [%d] and [%d] " "doesn't coincide when build RHS!\n", e->index, i, e->verts[i], ns->pinned_node_id); # else if (GlobalVertex(g, e->verts[i]) != ns->pinned_node_id) phgError(1, "Build rhs: pinned node e:%d, bas:%d, [%d] and [%d] " "doesn't coincide when build RHS!\n", e->index, i, e->verts[i], ns->pinned_node_id); # endif /* PIN_AT_ROOT */ } } #else TIME_DEP_LINEAR; /* Unavailable */ #endif /* STEADY_STATE || TIME_DEP_NON */ /* Global res */ phgVecAddEntries(vec_rhs, 0, M * Dim, Iu[0], &rhsu[0][0]); phgVecAddEntries(vec_rhs, 0, N, Ip, rhsp); } /* end element */
static void build_matrices(MAT *matA, MAT *matM, MAT *matC, MAT *S, FLOAT s, DOF *u_h, DOF *p_h) /* S is used to store s*diag(M(p_h))^(-1) */ { int N = u_h->type->nbas; /* number of basis functions in an element */ int M = p_h->type->nbas; int i, j; GRID *g = u_h->g; ELEMENT *e; FLOAT A[N][N], B[N][N], C[N][M]; INT I[N], Ip[M]; INT k, n0; VEC *V = phgMapCreateVec(S->rmap, 1); phgVecDisassemble(V); /* for phgVecAddEntry */ ForAllElements(g, e) { for (i = 0; i < N; i++) { I[i] = phgMapE2L(matA->rmap, 0, e, i); for (k = 0; k < M; k++) { /* \int \grad\psi_k\cdot\phi_i */ C[i][k] = phgQuadGradBasDotBas(e, p_h, k, u_h, i, QUAD_DEFAULT); } for (j = 0; j <= i; j++) { /* \int \phi_i\cdot\phi_j */ B[j][i] = B[i][j] = phgQuadBasDotBas(e, u_h, j, u_h, i, QUAD_DEFAULT); /* \int \curl\phi_i\cdot\curl\phi_j */ A[j][i] = A[i][j] = phgQuadCurlBasDotCurlBas(e, u_h, j, u_h, i, QUAD_DEFAULT); } } for (i = 0; i < M; i++) { Ip[i] = phgMapE2L(matC->cmap, 0, e, i); if (Ip[i] < 0) /* boundary entry */ continue; phgVecAddEntry(V, 0, Ip[i], phgQuadBasDotBas(e, p_h, i, p_h, i, QUAD_DEFAULT)); } /* loop on basis functions */ for (i = 0; i < N; i++) { if (phgDofDirichletBC(u_h, e, i, NULL, NULL, NULL, DOF_PROJ_CROSS)) continue; phgMatAddEntries(matA, 1, I + i, N, I, A[i]); phgMatAddEntries(matM, 1, I + i, N, I, B[i]); phgMatAddEntries(matC, 1, I + i, M, Ip, C[i]); } } phgVecAssemble(V); n0 = V->map->partition[V->map->rank]; for (k = 0; k < V->map->nlocal; k++) phgMatAddGlobalEntry(S, k + n0, k + n0, s / V->data[k]); phgVecDestroy(&V); phgMatAssemble(S); phgMatSetupDiagonal(S); phgMatAssemble(matA); phgMatAssemble(matM); phgMatAssemble(matC); }
static void /*build_linear_system*/ build_mat_vec(DOF *dp, DOF *d_so, DOF *d_sw, DOF *dot_muo, DOF *dot_muw, DOF *dot_mug, DOF *dso_kro, DOF *dsw_kro, DOF *dsw_krw, DOF *dso_krg, DOF *dsw_krg, DOF *u_o, DOF *p_h, DOF *p_h_newton, DOF *s_o, DOF *s_o_l, DOF *mu_o, DOF *b_o, DOF *b_o_l, DOF *kro, DOF *dot_bo, DOF *q_o, DOF *s_w, DOF *s_w_l, DOF *mu_w, DOF *b_w, DOF *b_w_l, DOF *krw, DOF *dot_bw, DOF *q_w, DOF *phi, DOF *phi_l, DOF *dot_phi, DOF *Rs, DOF *Rs_l, DOF *dot_Rs, DOF *mu_g, DOF *b_g, DOF *b_g_l, DOF *krg, DOF *dot_bg, DOF *q_g, MAP *map_u, MAP *map_p, MAT *A, MAT *B, MAT *TB, MAT *C, VEC *vec_f, VEC *vec_g) { GRID *g = u_o->g; SIMPLEX *e; FLOAT *p_so, *p_sol, *p_bo, *p_bol, *p_kro, *p_phi, *p_phil, *p_dotbo, *p_Rs, *p_dotRs, *p_bg, *p_bgl, *p_krg, *p_dotbg, *p_muo, *p_mug, *p_dotphi, *p_Rsl, *p_sw, *p_swl, *p_bw, *p_bwl, *p_krw, *p_dotbw, *p_muw; FLOAT *p_dotmuo, *p_dotmuw, *p_dotmug, *p_dsokro, *p_dswkro, *p_dswkrw, *p_dsokrg, *p_dswkrg, *p_dp, *p_dso, *p_dsw; INT N = u_o->type->nbas * u_o->dim; INT M = dp->type->nbas * dp->dim; INT I[N], J[M]; FLOAT mat_A[N][N], mat_TB[N][M], mat_B[M][N], mat_C[M][M], rhs_f[N], rhs_g[M]; phgVecDisassemble(vec_f); phgVecDisassemble(vec_g); int i, j, k; ForAllElements(g, e){ p_so = DofElementData(s_o, e->index); p_sol = DofElementData(s_o_l, e->index); p_bo = DofElementData(b_o, e->index); p_bol = DofElementData(b_o_l, e->index); p_kro = DofElementData(kro, e->index); p_phi = DofElementData(phi, e->index); p_phil = DofElementData(phi_l, e->index); p_dotphi = DofElementData(dot_phi, e->index); p_dotbo = DofElementData(dot_bo, e->index); p_Rs = DofElementData(Rs, e->index); p_Rsl = DofElementData(Rs_l, e->index); p_dotRs = DofElementData(dot_Rs, e->index); p_bg = DofElementData(b_g, e->index); p_bgl = DofElementData(b_g_l, e->index); p_krg= DofElementData(krg, e->index); p_dotbg = DofElementData(dot_bg, e->index); p_muo = DofElementData(mu_o, e->index); p_muw = DofElementData(mu_w, e->index); p_mug = DofElementData(mu_g, e->index); p_sw = DofElementData(s_w, e->index); p_swl = DofElementData(s_w_l, e->index); p_bw = DofElementData(b_w, e->index); p_bwl = DofElementData(b_w_l, e->index); p_krw = DofElementData(krw, e->index); p_dotbw = DofElementData(dot_bw, e->index); /* Add Dofs For SS */ p_dp = DofElementData(dp, e->index); p_dso = DofElementData(d_so, e->index); p_dsw = DofElementData(d_sw, e->index); p_dotmuo = DofElementData(dot_muo, e->index); p_dotmuw = DofElementData(dot_muw, e->index); p_dotmug = DofElementData(dot_mug, e->index); p_dsokro = DofElementData(dso_kro, e->index); p_dswkro = DofElementData(dsw_kro, e->index); p_dswkrw = DofElementData(dsw_krw, e->index); p_dsokrg = DofElementData(dso_krg, e->index); p_dswkrg = DofElementData(dsw_krg, e->index); /*Create inverse matrix*/ FLOAT oil_so = 0., wat_sw = 0., gas_so = 0., gas_sw = 0.; for (i = 0; i < M; i++){ for (j = 0; j < M; j++){ oil_so = p_phi[0] * p_bo[0] * phgQuadBasDotBas(e, d_so, i, d_so, j, QUAD_DEFAULT); wat_sw = p_phi[0] * p_bw[0] * phgQuadBasDotBas(e, d_sw, i, d_sw, j, QUAD_DEFAULT); gas_so = p_phi[0] * (p_bg[0] - p_Rs[0] * p_bo[0]) * phgQuadBasDotBas(e, d_so, i, d_so, j, QUAD_DEFAULT); gas_sw = p_phi[0] * p_bg[0] * phgQuadBasDotBas(e, d_sw, i, d_sw, j, QUAD_DEFAULT); } } #if SS FLOAT alpha_o = 0., alpha_w = 0., alpha_g = 0.; alpha_o = K * p_kro[0] * p_bo[0] * p_muo[0] + K * p_kro[0] * (p_bo[0] * p_dotmuo[0] + p_dotbo[0] * p_muo[0]) * p_dp[0] \ + K * p_bo[0] * p_muo[0] * (p_dsokro[0] * p_dso[0] + p_dswkro[0] * p_dsw[0]); alpha_w = K * p_krw[0] * p_bw[0] * p_muw[0] + K * p_krw[0] * (p_bw[0] * p_dotmuw[0] + p_dotbw[0] * p_muw[0]) * p_dp[0] \ + K * p_bw[0] * p_muw[0] * p_dswkrw[0] * p_dsw[0]; alpha_g = K * p_krg[0] * p_bg[0] * p_mug[0] + K * p_krg[0] * (p_bg[0] * p_dotmug[0] + p_dotbg[0] * p_mug[0]) * p_dp[0] \ + K * p_bg[0] * p_mug[0] * (p_dsokrg[0] * p_dso[0] + p_dswkrg[0] * p_dsw[0]); for (i = 0; i < N; i++){ for (j = 0; j < N; j++){ mat_A[i][j] = stime * phgQuadBasDotBas(e, u_o, i, u_o, j, QUAD_DEFAULT) / alpha_o; } } FLOAT beta = 0; beta = gas_so / oil_so + gas_sw * alpha_w / (wat_sw * alpha_o) + (p_Rs[0] + alpha_g / alpha_o); #endif #if IMPES FLOAT T_o = 0, T_w = 0, T_g = 0; T_o = K * p_kro[0] * p_bo[0] * p_muo[0]; T_w = K * p_krw[0] * p_bw[0] * p_muw[0]; T_g = K * p_krg[0] * p_bg[0] * p_mug[0]; for (i = 0; i < N; i++){ for (j = 0; j < N; j++){ mat_A[i][j] = stime * phgQuadBasDotBas(e, u_o, i, u_o, j, QUAD_DEFAULT) / T_o; } } FLOAT beta = 0; beta = gas_so / oil_so + gas_sw * T_w / (wat_sw * T_o) + (p_Rs[0] + T_g / T_o); #endif for (i = 0; i < N; i++){ for (j = 0; j < M; j++){ mat_TB[i][j] = -stime * phgQuadDivBasDotBas(e, u_o, i, dp, j, QUAD_DEFAULT); } } FLOAT quad = 0., oil_cp = 0., wat_cp = 0., gas_cp = 0.; oil_cp = p_so[0] * (p_bo[0] * p_dotphi[0] + p_phi[0] * p_dotbo[0]); wat_cp = p_sw[0] * (p_bw[0] * p_dotphi[0] + p_phi[0] * p_dotbw[0]); gas_cp = p_so[0] * p_phi[0] * p_bo[0] * p_dotRs[0] + p_Rs[0] * oil_cp + (1. - p_so[0] - p_sw[0]) * (p_phi[0] * p_dotbg[0] + p_bg[0] * p_dotphi[0]); for (i = 0; i < M; i++){ for (j = 0; j < M; j++){ quad = phgQuadBasDotBas(e, dp, i, dp, j, QUAD_DEFAULT); mat_C[i][j] = (gas_so * oil_cp / oil_so + gas_sw * wat_cp / wat_sw + gas_cp) * quad / beta; } } /*Create rhs*/ FLOAT quad_qo = 0; FLOAT quad_qw = 0.; FLOAT quad_qg = 0.; FLOAT quad_phi = 0, quad_phil = 0; FLOAT rhs_oil = 0, rhs_wat = 0., rhs_gas = 0; for (i = 0; i < M; i++){ phgQuadDofTimesBas(e, q_o, dp, i, QUAD_DEFAULT, &quad_qo); phgQuadDofTimesBas(e, q_w, dp, i, QUAD_DEFAULT, &quad_qw); phgQuadDofTimesBas(e, q_g, dp, i, QUAD_DEFAULT, &quad_qg); phgQuadDofTimesBas(e, phi, dp, i, QUAD_DEFAULT, &quad_phi); phgQuadDofTimesBas(e, phi_l, dp, i, QUAD_DEFAULT, &quad_phil); rhs_oil = -stime * quad_qo + p_so[0] * p_bo[0] * quad_phi - p_sol[0] * p_bol[0] * quad_phil; rhs_wat = -stime * quad_qw + p_sw[0] * p_bw[0] * quad_phi - p_swl[0] * p_bwl[0] * quad_phil; rhs_gas = -stime * quad_qg + (p_bg[0] * (1. - p_so[0] - p_sw[0]) + p_Rs[0] * p_so[0] * p_bo[0]) * quad_phi \ - (p_Rsl[0] * p_bol[0] * p_sol[0] + p_bgl[0] * (1. - p_sol[0] - p_swl[0])) * quad_phil; rhs_g[i] = (gas_so * rhs_oil / oil_so + gas_sw * rhs_wat / wat_sw + rhs_gas) / beta; } for (i = 0; i < N; i++){ rhs_f[i] = stime * phgQuadDofTimesDivBas(e, p_h, u_o, i, QUAD_DEFAULT); } /* Handle Bdry Conditions */ for (i = 0; i < N; i++){ if (phgDofGetElementBoundaryType(u_o, e, i) & (NEUMANN | DIRICHLET)){ bzero(mat_A[i], N *sizeof(mat_A[i][0])); bzero(mat_TB[i], M *sizeof(mat_TB[i][0])); for (j = 0; j < N; j++){ mat_A[j][i] = 0.0; } mat_A[i][i] = 1.0; rhs_f[i] = 0.; } } for (i = 0; i < N; i++){ for (j = 0; j < M; j++){ mat_B[j][i] = mat_TB[i][j]; } } for (i = 0; i < N; i++){ I[i] = phgMapE2L(map_u, 0, e, i); } for (i = 0; i < M; i++){ J[i] = phgMapE2L(map_p, 0, e, i); } phgMatAddEntries(A, N, I, N, I, mat_A[0]); phgMatAddEntries(TB, N, I, M, J, mat_TB[0]); phgMatAddEntries(B, M, J, N, I, mat_B[0]); phgMatAddEntries(C, M, J, M, J, mat_C[0]); phgVecAddEntries(vec_f, 0, N, I, rhs_f); phgVecAddEntries(vec_g, 0, M, J, rhs_g); }
/* build linear system */ static void build_mat_vec(DOF *u_w, DOF *dp, DOF *p_nk, DOF *ds, DOF *s_w, DOF *s_w_l, DOF *b_o, DOF *b_o_l, DOF *kro, DOF *dot_kro, DOF *q_o, DOF *b_w, DOF *b_w_l, DOF *krw, DOF *dot_krw, DOF *q_w, DOF *phi, DOF *phi_l, MAP *map_u, MAP *map_p, MAT *A, MAT *B, MAT *TB, MAT *C, VEC *vec_f, VEC *vec_g) { GRID *g = u_w->g; SIMPLEX *e; FLOAT *p_bo, *p_bw, *p_bol, *p_bwl, *p_kro, *p_dotkro, *p_krw, *p_dotkrw, *p_swl, *p_dp, *p_ds, *p_sw, *p_phi; INT N = u_w->type->nbas * u_w->dim; INT M = dp->type->nbas * dp->dim; INT I[N], J[M]; FLOAT mat_A[N][N], mat_TB[N][M], mat_B[M][N], mat_C[M][M], rhs_f[N], rhs_g[M]; phgVecDisassemble(vec_f); phgVecDisassemble(vec_g); int i, j, k; ForAllElements(g, e) { p_phi = DofElementData(phi, e->index); p_bo = DofElementData(b_o, e->index); p_bol = DofElementData(b_o_l, e->index); p_bw = DofElementData(b_w, e->index); p_bwl = DofElementData(b_w_l, e->index); p_sw = DofElementData(s_w, e->index); p_swl = DofElementData(s_w_l, e->index); p_kro = DofElementData(kro, e->index); p_dotkro = DofElementData(dot_kro, e->index); p_krw = DofElementData(krw, e->index); p_dotkrw = DofElementData(dot_krw, e->index); p_dp = DofElementData(dp, e->index); p_ds = DofElementData(ds, e->index); FLOAT T_o = 0, T_w = 0; T_w = K * p_krw[0] * p_bw[0] / MU_W + K * p_krw[0] * C_W / (MU_W * B0_W) * p_dp[0] + K * p_bw[0] * p_dotkrw[0] / MU_W * p_ds[0]; T_o = K * p_kro[0] * p_bo[0] / MU_O + K * p_kro[0] * C_O / (MU_O * B0_O) * p_dp[0] + K * p_bo[0] * p_dotkro[0] / MU_O * p_ds[0]; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { mat_A[i][j] = stime * phgQuadBasDotBas(e, u_w, i, u_w, j, QUAD_DEFAULT) / T_w; } } for (i = 0; i < N; i++) { for (j = 0; j < M; j++) { mat_TB[i][j] = -stime * phgQuadDivBasDotBas(e, u_w, i, dp, j, QUAD_DEFAULT); } } FLOAT wat_sw = 0, oil_sw = 0, wat_cp = 0, oil_cp = 0, beta = 0; for (i = 0; i < M; i++) { for (j = 0; j < M; j++) { wat_sw = p_phi[0] * p_bw[0] * phgQuadBasDotBas(e, ds, i, ds, j, QUAD_DEFAULT); oil_sw = p_phi[0] * p_bo[0] * phgQuadBasDotBas(e, ds, i, ds, j, QUAD_DEFAULT); } } wat_cp = p_sw[0] * (p_bw[0] * PHI0 * C_R + p_phi[0] * C_W / B0_W); oil_cp = (1. - p_sw[0]) * (p_bo[0] * PHI0 * C_R + p_phi[0] * C_O / B0_O); beta = 1. / wat_sw + T_o / (T_w * oil_sw); FLOAT quad = 0.; for (i = 0; i < M; i++) { for (j = 0; j < M; j++) { quad = phgQuadBasDotBas(e, dp, i, dp, j, QUAD_DEFAULT); mat_C[i][j] = (wat_cp / wat_sw + oil_cp / oil_sw) * quad / beta; } } /*create oil rhs*/ FLOAT quad_phi = 0., quad_phil = 0., quad_qo = 0, quad_qw = 0; FLOAT rhs_oil = 0., rhs_wat = 0.; for (i = 0; i < M; i++) { phgQuadDofTimesBas(e, q_o, dp, i, QUAD_DEFAULT, &quad_qo); phgQuadDofTimesBas(e, q_w, dp, i, QUAD_DEFAULT, &quad_qw); phgQuadDofTimesBas(e, phi, dp, i, QUAD_DEFAULT, &quad_phi); phgQuadDofTimesBas(e, phi_l, dp, i, QUAD_DEFAULT, &quad_phil); rhs_oil = -stime * quad_qo + p_bo[0] * (1. - p_sw[0]) * quad_phi - p_bol[0] * (1. - p_swl[0]) * quad_phil; rhs_wat = -stime * quad_qw + p_bw[0] * p_sw[0] * quad_phi - p_bwl[0] * p_swl[0] * quad_phil; rhs_g[i] = (rhs_wat / wat_sw + rhs_oil / oil_sw) / beta; } for (i = 0; i < N; i++) { rhs_f[i] = stime * phgQuadDofTimesDivBas(e, p_nk, u_w, i, QUAD_DEFAULT); } /* Handle Bdry Conditions*/ for (i = 0; i < N; i++) { if (phgDofGetElementBoundaryType(u_w, e, i) & (NEUMANN | DIRICHLET)) { bzero(mat_A[i], N * sizeof(mat_A[i][0])); bzero(mat_TB[i], M * sizeof(mat_TB[i][0])); for (j = 0; j < N; j++) { mat_A[j][i] = 0.; } mat_A[i][i] = 1.; rhs_f[i] = 0.; } } for (i = 0; i < N; i++) { for (j = 0; j < M; j++) { mat_B[j][i] = mat_TB[i][j]; } } for (i = 0; i < N; i++) { I[i] = phgMapE2L(map_u, 0, e, i); } for (i = 0; i < M; i++) { J[i] = phgMapE2L(map_p, 0, e, i); } phgMatAddEntries(A, N, I, N, I, mat_A[0]); phgMatAddEntries(TB, N, I, M, J, mat_TB[0]); phgMatAddEntries(B, M, J, N, I, mat_B[0]); phgMatAddEntries(C, M, J, M, J, mat_C[0]); phgVecAddEntries(vec_f, 0, N, I, rhs_f); phgVecAddEntries(vec_g, 0, M, J, rhs_g); }
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; }