static void build_matrix(MAT *mat, DOF *u_h) { int N = u_h->type->nbas; /* number of basis functions in an element */ int i, j; GRID *g = u_h->g; ELEMENT *e; FLOAT A[N][N], buf[N]; INT I[N]; assert(u_h->dim == 1); ForAllElements(g, e) { /* compute \int \grad\phi_j \cdot \grad\phi_i making use of symmetry */ for (i = 0; i < N; i++) { I[i] = phgMapE2L(mat->cmap, 0, e, i); for (j = 0; j <= i; j++) A[j][i] = A[i][j] = phgQuadGradBasDotGradBas(e, u_h, j, u_h, i, QUAD_DEFAULT); } /* loop on basis functions */ for (i = 0; i < N; i++) { if (phgDofDirichletBC(u_h, e, i, NULL, buf, NULL, DOF_PROJ_NONE)) { phgMatAddEntries(mat, 1, I + i, N, I, buf); } else { /* interior node */ phgMatAddEntries(mat, 1, I + i, N, I, A[i]); } } } }
static void build_matrices(MAT *matA, MAT *matM, DOF *u_h, DOF *p_h) { 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[M][N]; INT I[N], Ip[N]; INT k; assert(DofTypeDim(u_h) == Dim); assert(u_h->dim == 1); ForAllElements(g, e) { for (i = 0; i < N; i++) I[i] = phgMapE2L(matA->rmap, 0, e, i); for (i = 0; i < M; i++) Ip[i] = phgMapE2L(matA->rmap, 1, e, i); for (i = 0; i < N; i++) { for (k = 0; k < M; k++) { /* \int \grad\psi_k\cdot\phi_i */ C[k][i] = phgQuadGradBasDotBas(e, p_h, k, u_h, i, QUAD_DEFAULT); } for (j = 0; j <= i; j++) { /* \int \phi_j\cdot\phi_i */ B[j][i] = B[i][j] = phgQuadBasDotBas(e, u_h, j, u_h, i, QUAD_DEFAULT); /* \int \curl\phi_j\cdot\curl\phi_i */ A[j][i] = A[i][j] = phgQuadCurlBasDotCurlBas(e, u_h, j, u_h, i, QUAD_DEFAULT); } } /* loop on basis functions of u_h */ 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]); for (j = 0; j < M; j++) phgMatAddEntry(matA, I[i], Ip[j], C[j][i]); } /* loop on basis functions of p_h */ for (i = 0; i < M; i++) phgMatAddEntries(matA, 1, Ip + i, N, I, C[i]); } }
static void build_matrices(MAT *ma, MAT *mb, VEC *rhs_vec, DOF *u_h, DOF *f) /* build stiffness (ma) and mass (mb) matrices */ { int N = u_h->type->nbas; /* number of element basis functions */ int i, j, k, l; GRID *g = u_h->g; ELEMENT *e; FLOAT A[N][3][N][3], buffer[N], rhs[N][3], d; static FLOAT *B0 = NULL; FLOAT B[N][N]; INT I[N][3], J[3][N]; QUAD *quad = phgQuadGetQuad3D((u_h->type->order - 1) * 2); assert(u_h->type->dim == 1 && u_h->dim == 3); assert(mb == NULL || u_h->type->invariant); if (mb != NULL && B0 == NULL && g->nroot > 0) { /* (\int \phi_j\cdot\phi_i)/vol is independent of element */ FreeAtExit(B0); B0 = phgAlloc(N * N * sizeof(*B0)); e = g->roots; d = 1. / phgGeomGetVolume(g, e); for (i = 0; i < N; i++) for (j = 0; j <= i; j++) B0[i * N + j] = B0[i + j * N] = d * phgQuadBasDotBas(e, u_h, j, u_h, i, QUAD_DEFAULT); } ForAllElements(g, e) { d = phgGeomGetVolume(g, e) * rho; for (i = 0; i < N; i++) { for (k = 0; k < 3; k++) J[k][i] = I[i][k] = phgMapE2L(ma->rmap, 0, e, i * 3 + k); for (j = 0; j <= i; j++) { /* the stiffness matrix */ stiffness_matrix(e, u_h, i, j, E, nu, 3 * N, &A[i][0][j][0], quad); if (j != i) { for (k = 0; k < 3; k++) for (l = 0; l < 3; l++) A[j][k][i][l] = A[i][l][j][k]; } /* the mass matrix: \int \phi_i\cdot\phi_j */ if (mb != NULL) B[j][i] = B[i][j] = B0[i * N + j] * d; } } #if 0 /* print element stiffness matrix */ FLOAT *p = (void *)A; printf("vol = %0.16lg;\n", phgGeomGetVolume(g, e)); printf("a = [\n"); for (i = 0; i < 3 * N; i++) { for (j = 0; j < 3 * N; j++) printf("%0.16lg ", p[i * 3 * N + j]); printf("\n"); } printf("];\n"); printf("b = [\n"); for (i = 0; i < N; i++) for (k = 0; k < 3; k++) { for (j = 0; j < N; j++) for (l = 0; l < 3; l++) printf("%0.16lg ", l == k ? B[i][j] : 0.0); printf("\n"); } printf("];\n"); exit(0); #endif /* loop on basis functions */ for (i = 0; i < N; i++) { if (phgDofDirichletBC(u_h, e, i, func_g, buffer, rhs[i], DOF_PROJ_NONE)) { /* Dirichlet boundary */ for (k = 0; k < 3; k++) { phgMatAddEntries(ma, 1, I[i] + k, N, J[k], buffer); if (mb != NULL) phgMatAddEntries(mb, 1, I[i] + k, N, J[k], buffer); } } else { /* interior node */ phgMatAddEntries(ma, 3, I[i], 3 * N, I[0], &A[i][0][0][0]); if (mb == NULL) { phgQuadDofTimesBas(e, f, u_h, i, QUAD_DEFAULT, rhs[i]); for (k = 0; k < 3; k++) rhs[i][k] = -rhs[i][k]; } else { for (k = 0; k < 3; k++) phgMatAddEntries(mb, 1, I[i] + k, N, J[k], B[i]); } } } if (rhs_vec != NULL) phgVecAddEntries(rhs_vec, 0, N * 3, I[0], rhs[0]); }
/*************************************************************************** * Build matrices *F, *Fu, *B, *Bt, *Fp, *Ap, and *Qp used * by the solvers. **************************************************************************/ static void build_matrices(SOLVER *solver, SOLVER *pc, DOF **dofs, MAT **mats, LTYPE type) { DOF *u = dofs[0], *p = dofs[1]; DOF *f, *pbc, *gn[3], *gradu, *divu; int M = u->type->nbas; /* num of bases of Velocity */ int N = p->type->nbas; /* num of bases of Pressure */ int i, j, k, l; GRID *g = u->g; ELEMENT *e; MAT *matB, *matC, *matAp, *matQp; FLOAT F[M][Dim][M][Dim], Fu[M][M], B[N][M][Dim], Bt[M][Dim][N], Ap[N][N], Fp[N][N], Qp[N][N], bufu[M], bufp[N], tmp[9]; INT Iu[M][Dim], Ju[Dim][M], Iu0[M], Ip[N]; /* Unpack Dofs */ unpackDof(dofs, 9, &u, &p, &gradu, &divu, &f, &pbc, &gn[0], &gn[1], &gn[2]); unpackMat(mats, 4, &matB, &matC, &matAp, &matQp); #if 0 #warning remove me! SOLVER *s = phgSolverCreate(SOLVER_PCG, p, NULL); #endif ForAllElements(g, e) { /* Map: Element -> system */ for (i = 0; i < M; i++) { for (k = 0; k < Dim; k++) Ju[k][i] = Iu[i][k] = phgMapE2L(matF->cmap, 0, e, i * Dim + k); Iu0[i] = phgMapE2L(matFu->cmap, 0, e, i); } for (i = 0; i < N; i++) { Ip[i] = phgMapE2L(matFp->cmap, 0, e, i); } /* A V W */ for (i = 0; i < M; i++) { for (j = 0; j < M; j++) { FLOAT m, a, v, w[9]; /* \phi_j \dot \phi_i */ m = phgQuadBasDotBas(e, u, j, u, i, QUAD_DEFAULT); /* (\grad \phi_j) \cdot (\grad \phi_i) */ a = nu * phgQuadGradBasDotGradBas(e, u, j, u, i, QUAD_DEFAULT); /* (u \cdot \grad) \phi_j \times \phi_i, 1 item */ v = phgQuadDofDotGradBasBas(e, u, u, j, i, QUAD_DEFAULT); Fu[i][j] = a + v; if (type == PICARD) { memset(w, 0, sizeof(w)); } else { /* \phi_j (\grad u) \times \phi_i, 9 items */ phgQuadGradDofBasDotBas(e, gradu, u, j, i, QUAD_DEFAULT, w); } for (k = 0; k < Dim; k++) { for (l = 0; l < Dim; l++) { F[i][k][j][l] = Theta * dt * *(w + k * Dim + l); if (k == l) F[i][k][j][k] += m + Theta * dt * (a + v); } } } } /* B Bt */ for (i = 0; i < M; i++) { for (j = 0; j < N; j++) { FLOAT bxyz[3]; phgQuadGradBasDotBas3(e, u, i, p, j, bxyz, QUAD_DEFAULT); for (k = 0; k < Dim; k++) Bt[i][k][j] = B[j][i][k] = -Theta * dt * bxyz[k]; } } /* Ap Qp; Fp(update) */ for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { FLOAT ap, qp, cp; ap = phgQuadGradBasDotGradBas(e, p, j, p, i, QUAD_DEFAULT); Ap[i][j] = Theta * dt * ap; qp = phgQuadBasDotBas(e, p, j, p, i, QUAD_DEFAULT); Qp[i][j] = Theta * dt * qp; cp = phgQuadDofDotGradBasBas(e, u, p, j, i, QUAD_DEFAULT); Fp[i][j] = qp + Theta * dt * (nu * ap + cp); } } /* Global Matrix */ for (i = 0; i < M; i++) { /* Dirichle Boundary for velocity. */ if (phgDofDirichletBC(u, e, i, NULL, bufu, NULL, DOF_PROJ_NONE)) { for (k = 0; k < Dim; k++) phgMatAddEntries(matF, 1, Iu[i] + k, M, Ju[k], bufu); phgMatAddEntries(matFu, 1, Iu0 + i, M, Iu0, bufu); } else { /* interior node Or Neumann */ /* Matrix F */ phgMatAddEntries(matF, Dim, Iu[i], M * Dim, Iu[0], &(F[i][0][0][0])); /* Matrix Fu */ phgMatAddEntries(matFu, 1, Iu0 + i, M, Iu0, &(Fu[i][0])); /* Matrix Bt */ for (k = 0; k < Dim; k++) phgMatAddEntries(matBt, 1, &Iu[i][k], N, Ip, &Bt[i][k][0]); } } /* end of Block (1,1), (1,2) */ for (i = 0; i < N; i++) phgMatAddEntries(matB, 1, Ip + i, M * Dim, Iu[0], &B[i][0][0]); /* Matrix Ap Qp Fp */ for (i = 0; i < N; i++) { if (phgDofDirichletBC(pbc, e, i, NULL, bufp, tmp, DOF_PROJ_NONE)) { /* Dirichle Boundary for pressure PC. */ phgMatAddEntries(matAp, 1, Ip + i, N, Ip, bufp); phgMatAddEntries(matFp, 1, Ip + i, N, Ip, bufp); } else { /* interior node Or Neumann */ phgMatAddEntries(matAp, 1, Ip + i, N, Ip, Ap[i]); phgMatAddEntries(matFp, 1, Ip + i, N, Ip, Fp[i]); } #if 0 /* use only diagonal of the mass matrix in the preconditioner */ phgMatAddEntries(matQp, 1, Ip + i, 1, Ip + i, &Qp[i][i]); #else /* use full mass matrix in the preconditioner */ phgMatAddEntries(matQp, 1, Ip + i, N, Ip, Qp[i]); #endif #if 0 phgMatAddEntries(s->mat, 1, Ip + i, N, Ip, Qp[i]); #endif } } /* end element */ #if 0 VEC *v = phgMapCreateVec(s->rhs->map, 1); memcpy(s->rhs->data, solver->rhs->data + DofGetDataCount(u), s->rhs->map->nlocal * sizeof(FLOAT)); s->rhs_updated = TRUE; s->rhs->assembled = TRUE; s->rtol = 1e-10; s->maxit = 10000; phgSolverVecSolve(s, TRUE, v); phgPrintf("v = %e\n", phgVecNormInfty(v, 0, NULL)); phgVecDestroy(&v); phgSolverDestroy(&s); #endif return; }
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); }
/* 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); }
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); }
void phgNSBuildPc(NSSolver *ns) { GRID *g = ns->g; SIMPLEX *e; FLOAT *dt = ns->dt; int i, j, q, s, k, l; FLOAT Theta = _nsp->Theta, nu = _nsp->nu, Thet1, nu0 = 0; DOF *tmp_u1 = phgDofNew(g, _nsp->utype, Dim, "tmp u1", func_u); int viscosity_type = ns->viscosity_type; LTYPE ltype = ns->ltype; #if STEADY_STATE assert(fabs(Theta - 1) < 1e-12); Thet1 = 0; Unused(Thet1); Unused(dt); #else Thet1 = 1 - Theta; #endif /* STEADY_STATE */ 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 = 2 * DofTypeOrder(ns->p[1], e) + DofTypeOrder(ns->u[1], e) - 1; /* highest order term (u \nabla p, psi) */ FLOAT Ap[N][N], Fp[N][N], Qp[N][N], bufp[N], rhs1 = 1; FLOAT F[M*Dim][M*Dim], B[N][M*Dim], Bt[M*Dim][N]; INT Ip[N]; QUAD *quad; FLOAT vol, det; const FLOAT *w, *p, *vw, *gu, *vTe; quad = phgQuadGetQuad3D(order); vw = phgQuadGetDofValues(e, ns->wind, quad); /* value wind */ gu = phgQuadGetDofValues(e, ns->gradu[1], quad); /* grad u^{n+1} */ if (ns_params->noniter_temp) vTe = phgQuadGetDofValues(e, ns->T[1], quad); /* value temp */ else vTe = phgQuadGetDofValues(e, ns->T[0], quad); /* value temp */ vol = 0; Bzero(Ap); Bzero(Fp); Bzero(Qp); Bzero(F); Bzero(Bt); Bzero(B); Bzero(bufp); p = quad->points; w = quad->weights; for (q = 0; q < quad->npoints; q++) { phgGeomGetCurvedJacobianAtLambda(g, e, p, &det); vol = fabs(det / 6.); for (i = 0; i < N; i++) { const FLOAT *gi = phgQuadGetBasisValues(e, ns->p[1], i, quad) + q; /* phi_i */ const FLOAT *ggi = phgQuadGetBasisCurvedGradient(e, ns->p[1], i, quad, q); /* grad phi_i */ for (j = 0; j < N; j++) { const FLOAT *gj = phgQuadGetBasisValues(e, ns->p[1], j, quad) + q; /* phi_j */ const FLOAT *ggj = phgQuadGetBasisCurvedGradient(e, ns->p[1], j, quad, q); /* grad phi_i */ nu = get_effective_viscosity(gu, *vTe, 0, viscosity_type); if (i == 0 && j == 0) nu0 += nu; #if ICE_BENCH_TEST || \ ESIMINT_TEST || \ HEINO_TEST || \ TEST_CASE == ICE_EXACT || \ TEST_CASE == ICE_GREEN_LAND Unused(dt); /* Note: B Q^-1 Bt ~ Ap(nu=1), * Fp(nu varies) is very different to Ap */ Ap[i][j] += vol*(*w) * INNER_PRODUCT(ggj, ggi); # if USE_QP_ONLY //Qp[i][j] += vol*(*w) * LEN_SCALING * PRES_SCALING /(nu) * (*gj) * (*gi); Qp[i][j] += vol*(*w) * 1. /(EQU_SCALING * nu) * (*gj) * (*gi); /* if (i < NVert && j < NVert) { */ /* Qp[i][j] += vol*(*w) * LEN_SCALING * PRES_SCALING / (nu) * (*gj) * (*gi); */ /* } else if (i == NVert && j == NVert) { */ /* Qp[i][j] += vol*(*w) * LEN_SCALING * PRES_SCALING / (nu) * (*gj) * (*gi); */ /* } */ # else Qp[i][j] += vol*(*w) * (*gj) * (*gi); # endif Fp[i][j] += vol*(*w) * (EQU_SCALING * nu * INNER_PRODUCT(ggj, ggi) ); #elif STEADY_STATE Ap[i][j] += vol*(*w) * INNER_PRODUCT(ggj, ggi); Qp[i][j] += vol*(*w) * (*gj) * (*gi); Fp[i][j] += vol*(*w) * (nu * INNER_PRODUCT(ggj, ggi) * EQU_SCALING ); #elif TIME_DEP_NON Ap[i][j] += vol*(*w) * INNER_PRODUCT(ggj, ggi); Qp[i][j] += vol*(*w) * (*gj) * (*gi); Fp[i][j] += vol*(*w) * ((*gj) * (*gi) / dt[0] + Theta * (nu * INNER_PRODUCT(ggj, ggi) ) ); #else TIME_DEP_LINEAR_ENTRY; /* Unavailable */ #endif /* STEADY_STATE */ } } vw += Dim; gu += DDim; vTe++; w++; p += Dim+1; } /* Map: Element -> system */ for (i = 0; i < N; i++) Ip[i] = phgMapE2L(_pcd->matFp->cmap, 0, e, i); /* * PCD boundary setup I: * Automaticly decide inflow boundary condition using wind direction. * * NOT active. * */ if (FALSE && !_nsp->pin_node) { for (i = 0; i < N; i++) { BOOLEAN flag_inflow = FALSE; for (s = 0; s < NFace; s++) { SHORT bases[NbasFace(ns->p[1])]; FLOAT *coord, vw_[3]; const FLOAT *lam, *normal; if (!(e->bound_type[s] & BDRY_MASK)) //if (!(e->bound_type[s] & INFLOW)) continue; /* boundary face */ phgDofGetBasesOnFace(ns->p[1], e, s, bases); for (j = 0; j < NbasFace(ns->p[1]); j++) if (i == bases[j]) { normal = phgGeomGetFaceOutNormal(g, e, s); coord = phgDofGetElementCoordinates(ns->p[1], e, i); lam = phgGeomXYZ2Lambda(g, e, coord[0], coord[1], coord[2]); phgDofEval(tmp_u1, e, lam, vw_); if (INNER_PRODUCT(vw_, normal) > 1e-8) flag_inflow = TRUE; } } if (flag_inflow) { Bzero(bufp); bufp[i] = 1.0; phgMatAddEntries(_pcd->matAp, 1, Ip + i, N, Ip, bufp); phgMatAddEntries(_pcd->matFp, 1, Ip + i, N, Ip, bufp); //phgMatAddEntries(_pcd->matQp, 1, Ip + i, N, Ip, bufp); phgVecAddEntries(_pcd->rhsScale, 0, 1, Ip + i, &rhs1); } else { /* interior node Or Neumann */ phgMatAddEntries(_pcd->matAp, 1, Ip + i, N, Ip, Ap[i]); phgMatAddEntries(_pcd->matFp, 1, Ip + i, N, Ip, Fp[i]); //phgMatAddEntries(_pcd->matQp, 1, Ip + i, N, Ip, Qp[i]); } phgMatAddEntries(_pcd->matQp, 1, Ip + i, N, Ip, Qp[i]); } } /* * PCD boundary setup II: * Enclose flow: use pinnode boundary. * * Qp is pinned, this is different to open flow. * * */ else if (_nsp->pin_node) { for (i = 0; i < N; i++) { if (phgDofDirichletBC(_pcd->pbc, e, i, NULL, bufp, NULL, DOF_PROJ_NONE)) { #if PIN_AT_ROOT if (g->rank != 0) phgError(1, "Pinned node only on rank 0!\n"); if (e->verts[i] != ns->pinned_node_id) phgError(1, "pinned node [%d] & [%d] doesn't coincide when build pc!\n", e->verts[i], ns->pinned_node_id); #else if (GlobalVertex(g, e->verts[i]) != ns->pinned_node_id) phgError(1, "pinned node [%d] & [%d] doesn't coincide when build pc!\n", e->verts[i], ns->pinned_node_id); #endif /* PIN_AT_ROOT */ phgMatAddEntries(_pcd->matAp, 1, Ip + i, N, Ip, bufp); phgMatAddEntries(_pcd->matFp, 1, Ip + i, N, Ip, bufp); phgMatAddEntries(_pcd->matQp, 1, Ip + i, N, Ip, bufp); phgVecAddEntries(_pcd->rhsScale, 0, 1, Ip + i, &rhs1); } else { /* interior node Or Neumann */ phgMatAddEntries(_pcd->matAp, 1, Ip + i, N, Ip, Ap[i]); phgMatAddEntries(_pcd->matFp, 1, Ip + i, N, Ip, Fp[i]); phgMatAddEntries(_pcd->matQp, 1, Ip + i, N, Ip, Qp[i]); } } } /* * PCD boundary setup III: * Open flow: there could be varies kinds of combination on seting up * boundary conditon, but Inflow:Robin & Outflow:scaled Dirich is * prefered. See Ref[2]. * * */ else { for (i = 0; i < N; i++) { /*****************/ /* Inflow */ /*****************/ #warning PCD B.C.: Step 2.1. build mat, all neumann, add dirich entries if (FALSE && phgDofDirichletBC(_pcd->dof_inflow, e, i, NULL, bufp, NULL, DOF_PROJ_NONE)) { phgMatAddEntries(_pcd->matAp, 1, Ip + i, N, Ip, bufp); phgMatAddEntries(_pcd->matFp, 1, Ip + i, N, Ip, bufp); phgMatAddEntries(_pcd->matQp, 1, Ip + i, N, Ip, bufp); phgVecAddEntries(_pcd->rhsScale, 0, 1, Ip + i, &rhs1); } else if (FALSE && phgDofDirichletBC(_pcd->dof_outflow, e, i, NULL, bufp, NULL, DOF_PROJ_NONE) && !(phgDofGetElementBoundaryType(ns->p[1], e, i) & INFLOW) ) { ERROR_MSG("Fp, Qp"); nu = get_effective_viscosity(NULL, 0, 0, viscosity_type); phgMatAddEntries(_pcd->matAp, 1, Ip + i, N, Ip, bufp); bufp[i] *= EQU_SCALING * nu; phgMatAddEntries(_pcd->matFp, 1, Ip + i, N, Ip, bufp); phgVecAddEntries(_pcd->rhsScale, 0, 1, Ip + i, &rhs1); //phgMatAddEntries(_pcd->matQp, 1, Ip + i, N, Ip, bufp); } else if (FALSE && phgDofDirichletBC(_pcd->pbc, e, i, NULL, bufp, NULL, DOF_PROJ_NONE)) { phgMatAddEntries(_pcd->matAp, 1, Ip + i, N, Ip, bufp); phgMatAddEntries(_pcd->matFp, 1, Ip + i, N, Ip, bufp); phgMatAddEntries(_pcd->matQp, 1, Ip + i, N, Ip, bufp); phgVecAddEntries(_pcd->rhsScale, 0, 1, Ip + i, &rhs1); } else if (FALSE) { /* interior node Or Neumann */ ERROR_MSG("Fp, Qp"); phgMatAddEntries(_pcd->matAp, 1, Ip + i, N, Ip, Ap[i]); phgMatAddEntries(_pcd->matFp, 1, Ip + i, N, Ip, Fp[i]); //phgMatAddEntries(_pcd->matQp, 1, Ip + i, N, Ip, Qp[i]); } /******************/ /* No bdry */ /******************/ //phgMatAddEntries(_pcd->matFp, 1, Ip + i, N, Ip, Fp[i]); phgMatAddEntries(_pcd->matQp, 1, Ip + i, N, Ip, Qp[i]); } } if (0) { /* Special term <[[p_i]], [[p_j]]> */ int face; nu0 /= quad->npoints; for (face = 0; face < NFace; face++) { FLOAT area = phgGeomGetFaceArea(g, e, face); //FLOAT value = {area, -area}; FLOAT values[2] = {vol * 1. /(EQU_SCALING * nu0), -vol * 1. /(EQU_SCALING * nu0)}; SIMPLEX *e_neigh; phgMatAddEntries(_pcd->matQp, 1, Ip+NVert, 1, Ip+NVert, values); if ((e_neigh = GetNeighbour(e, face)) != NULL) { INT Ip_neigh = phgMapE2L(_pcd->matFp->cmap, 0, e_neigh, NVert); phgMatAddEntries(_pcd->matQp, 1, Ip+NVert, 1, &Ip_neigh, values + 1); } } } } /* end element */