Example #1
0
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)));
	}
    }
Example #2
0
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 */