int main(int argc, char *argv[]) { const char *fn = "cube.dat"; ELEMENT *e; GRID *g; DOF *u; int i, n; /* Test initialize MPI before phgInit */ MPI_Init(&argc, &argv); phgInit(&argc, &argv); g = phgNewGrid(-1); if (argc > 1) fn = argv[1]; if (!phgImport(g, fn, FALSE)) phgError(1, "can't read file \"%s\".\n", fn); phgRefineAllElements(g, 0); u = phgDofNew(g, DOF_DEFAULT, 1, "u", DofNoAction); n = u->type->nbas; ForAllElements(g, e) { FLOAT xyz[3]; const FLOAT *c; for (i = 0; i < n; i++) { c = phgDofGetElementCoordinates(u, e, i); phgDofGetElementBasisInfo_(u, e, i, NULL, NULL, NULL, xyz, NULL); assert(!memcmp(c, xyz, sizeof(xyz))); } }
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 */