static gdouble get_size_next ( FttCell * cell, FttDirection d ) { FttCell * cellnext = ftt_cell_neighbor (cell, d); if (!cellnext) return ftt_cell_size (cell); gdouble size; if (!FTT_CELL_IS_LEAF (cellnext)) size = ftt_cell_size (cell) / 2.; else size = ftt_cell_size (cellnext); return size; }
static void diffusion_term (FttCell * cell, DataDif * data) { /* fixme: I need to account for the metric */ gdouble size, sizenext, size_ratio; gdouble un, unext, unprev; FttDirection d0; for (d0 = 0; d0 < FTT_NEIGHBORS; d0++) { FttCellFace face = gfs_cell_face(cell, d0); gdouble flux = 0.; gdouble invdens = data->alpha ? gfs_function_face_value (data->alpha, &face) : 1.; gdouble visc = gfs_diffusion_cell (data->d->D, cell); GfsStateVector * s = GFS_STATE (cell); FttDirection od = FTT_OPPOSITE_DIRECTION(d0); un = interpolate_value_skew (cell, d0, NULL, data->fd); if ((d0 % 2) != 0) { unext = interpolate_value_skew (cell, od , NULL, data->fd); unprev = interpolate_value_skew (cell, d0 , &(d0) , data->fd); sizenext = ftt_cell_size (cell); size = get_size_next (cell, d0); } else { unext = interpolate_value_skew (cell, d0, &(d0), data->fd); unprev = interpolate_value_skew (cell, od, NULL, data->fd); size = ftt_cell_size (cell); sizenext = get_size_next (cell, d0); } size_ratio = ( 1. + sizenext / size ) / 2; flux = ( (unext - un)/sizenext - (un - unprev)/size ); FttComponent c = d0/2; #if FTT_2D FttComponent oc = FTT_ORTHOGONAL_COMPONENT (c); flux += size_ratio * transverse_diffusion(cell, oc, d0, un, data->fd); #else static FttComponent orthogonal[FTT_DIMENSION][2] = { {FTT_Y, FTT_Z}, {FTT_X, FTT_Z}, {FTT_X, FTT_Y} }; flux += size_ratio * transverse_diffusion(cell, orthogonal[c][0], d0, un, data->fd); flux += size_ratio * transverse_diffusion(cell, orthogonal[c][1], d0, un, data->fd); #endif s->f[d0].v -= invdens*visc*flux; } }
/* see gfs_face_velocity_advection_flux() for the initial implementation with static boundaries */ static void moving_face_velocity_advection_flux (const FttCellFace * face, const GfsAdvectionParams * par) { gdouble flux; FttComponent c = par->v->component; g_return_if_fail (c >= 0 && c < FTT_DIMENSION); /* fixme: what's up with face mapping? */ flux = face_fraction_half (face, par)*GFS_FACE_NORMAL_VELOCITY (face)* par->dt/ftt_cell_size (face->cell); #if 0 if (c == face->d/2) /* normal component */ flux *= GFS_FACE_NORMAL_VELOCITY (face); else /* tangential component */ #else flux *= gfs_face_upwinded_value (face, par->upwinding, par->u) /* pressure correction */ - gfs_face_interpolated_value (face, par->g[c]->i)*par->dt/2.; #endif if (!FTT_FACE_DIRECT (face)) flux = - flux; GFS_VALUE (face->cell, par->fv) -= flux; switch (ftt_face_type (face)) { case FTT_FINE_FINE: GFS_VALUE (face->neighbor, par->fv) += flux; break; case FTT_FINE_COARSE: GFS_VALUE (face->neighbor, par->fv) += flux/FTT_CELLS; break; default: g_assert_not_reached (); } }
static void ftt_bbox(FttCell *cell, gpointer data) { FttVector p; ftt_cell_pos(cell,&p); double size = ftt_cell_size(cell)/2.0; bbox_t bb, *pbb = *(bbox_t**)data; bb.x.min = p.x - size; bb.x.max = p.x + size; bb.y.min = p.y - size; bb.y.max = p.y + size; if (pbb) { bbox_t bbx = bbox_join(bb,*pbb); *pbb = bbx; } else { pbb = malloc(sizeof(bbox_t)); *pbb = bb; *(bbox_t**)data = pbb; } }
static gdouble solid_curvature (FttCell * cell, FttCellFace * face, GfsDomain * domain, GfsGenericSurface * s) { KappaData d; d.kappa = gfs_solid_is_thin (cell, s) ? 1./ftt_cell_size (cell) : 0.; d.s = GFS_SURFACE (s)->s; gts_surface_foreach_vertex (d.s, (GtsFunc) max_kappa, &d); return d.kappa; }
/* b Adaptative boolean */ static gdouble transverse_advection (FttCell * cell, FttComponent oc, FttDirection d, gdouble un, FaceData * fd, gboolean b) { gdouble uauxbot, uauxtop,size_ratio; gdouble vn, vntop, vnbot, vndiag; FttDirection daux; FttCell * cellnext = ftt_cell_neighbor (cell, d); if (!cellnext) cellnext = cell; size_ratio = ftt_cell_size (cell); if (!b) { size_ratio = ftt_cell_size (cellnext)/size_ratio; if (!FTT_CELL_IS_LEAF (cellnext)) size_ratio /= 2.; vn = interpolate_value_skew (cell,2*oc,NULL,fd); vntop = interpolate_value_skew (cell,2*oc,&d ,fd); vndiag = interpolate_value_skew (cell,2*oc+1,&d ,fd); vnbot = interpolate_value_skew (cell,2*oc+1,NULL,fd); daux = 2*oc; uauxtop = interpolate_value_skew (cell, d, &daux, fd); daux = 2*oc+1; uauxbot = interpolate_value_skew (cell, d, &daux, fd); } else { size_ratio = size_ratio/ftt_cell_size (cellnext); if (!FTT_CELL_IS_LEAF (cellnext)) size_ratio *= 2.; daux = FTT_OPPOSITE_DIRECTION(d); vn = interpolate_value_skew (cell,2*oc,&daux, fd); vntop = interpolate_value_skew (cell,2*oc,&daux, fd); vndiag = interpolate_value_skew (cell,2*oc+1,NULL,fd); vnbot = interpolate_value_skew (cell,2*oc,&daux ,fd); daux = 2*oc; uauxtop = interpolate_value_skew (cell, FTT_OPPOSITE_DIRECTION(d), &daux, fd); daux = 2*oc+1; uauxbot = interpolate_value_skew (cell, FTT_OPPOSITE_DIRECTION(d), &daux, fd); } return (uauxtop*(vn + vntop*size_ratio) - uauxbot*(vnbot + vndiag*size_ratio)) / 4.; }
static void solid_flux (FttCell * cell, SolidFluxParams * par) { gfs_normal_divergence (cell, par->div); if (GFS_VALUE (cell, par->div) < 0.) { gdouble h = ftt_cell_size (cell); GFS_VALUE (cell, par->fv) = GFS_VALUE (cell, par->div)*par->p->dt* GFS_VALUE (cell, par->p->v)/(h*h); } else GFS_VALUE (cell, par->fv) = 0.; }
static gdouble cell_distance (FttCell * cell, FttCellFace * face, GfsSimulation * sim, GfsRefineDistance * refine) { FttVector pos; gdouble h = GFS_DIAGONAL*ftt_cell_size (cell), d; GtsPoint p; ftt_cell_pos (cell, &pos); p.x = pos.x; p.y = pos.y; p.z = pos.z; d = gts_bb_tree_point_distance (refine->stree, &p, (GtsBBoxDistFunc) gts_point_triangle_distance, NULL); return d > h ? d - h : 0.; }
static void diffusion (FttCell * cell, GSEData * p) { gdouble h2 = ftt_cell_size (cell); h2 *= h2; /* off-diagonal */ FttComponent j; for (j = 0; j < 2; j++) if (j != p->dF->component) GFS_VALUE (cell, p->F) += p->D[j][p->dF->component]*gfs_center_regular_gradient (cell, j, p->dF)/h2; /* diagonal */ GFS_VALUE (cell, p->F) += p->D[p->dF->component][p->dF->component]* gfs_center_regular_2nd_derivative (cell, p->dF->component, p->Fn)/h2; }
static void update_vel (FttCell * cell, FaceData * fd) { GfsStateVector * s = GFS_STATE (cell); gdouble size; FttDirection d; for (d = 0; d < FTT_NEIGHBORS; d++) { size = ( ftt_cell_size (cell) + get_size_next (cell, d) ) / 2; GFS_VALUE (cell, fd->velfaces[d]) = (GFS_VALUE (cell, fd->velfaces[d]) + fd->beta*GFS_VALUE (cell, fd->velold[d]))/(1.+fd->beta); s->f[d].un = (2*fd->beta*GFS_VALUE (cell, fd->velfaces[d]) + (0.5-fd->beta)*GFS_VALUE (cell, fd->velold[d]) - s->f[d].v*(*fd->dt)/size)/(0.5+fd->beta); GFS_VALUE (cell, fd->velold[d]) = GFS_VALUE (cell, fd->velfaces[d]); s->f[d].v = s->f[d].un; } }
static gdouble transverse_diffusion (FttCell * cell, FttComponent oc, FttDirection d, gdouble un, FaceData * fd) { gdouble uaux, size, flux = 0; gint i; for ( i = 0; i < 2; i++ ) { FttDirection daux = 2*oc + i; uaux = interpolate_value_skew (cell, d, &daux, fd); size = ( ftt_cell_size (cell) + get_size_next (cell, daux) ) / 2; flux += (uaux - un) / size; } return flux; }
/* see gfs_face_advection_flux() for the initial implementation with static boundaries */ static void moving_face_advection_flux (const FttCellFace * face, const GfsAdvectionParams * par) { gdouble flux; /* fixme: what's up with face mapping? */ flux = face_fraction_half (face, par)*GFS_FACE_NORMAL_VELOCITY (face)*par->dt* gfs_face_upwinded_value (face, GFS_FACE_UPWINDING, NULL)/ftt_cell_size (face->cell); if (!FTT_FACE_DIRECT (face)) flux = - flux; GFS_VALUE (face->cell, par->fv) -= flux; switch (ftt_face_type (face)) { case FTT_FINE_FINE: GFS_VALUE (face->neighbor, par->fv) += flux; break; case FTT_FINE_COARSE: GFS_VALUE (face->neighbor, par->fv) += flux/FTT_CELLS; break; default: g_assert_not_reached (); } }
static void ftt_sample(FttCell *cell, gpointer data) { ftts_t ftts = *((ftts_t*)data); int level = ftt_cell_level(cell); double size = ftt_cell_size(cell); bbox_t bb = bilinear_bbox(ftts.B[0]); FttVector p; ftt_cell_pos(cell,&p); /* the number in each directon we will sample */ int n = POW2(ftts.depth-level); /* cell coordinates at this level */ int ic = (p.x - bb.x.min)/size; int jc = (p.y - bb.y.min)/size; /* subgrid extent */ double xmin = p.x - size/2.0; double ymin = p.y - size/2.0; double d = size/n; #ifdef FFTS_DEBUG printf("%f %f (%i %i %i %i)\n",p.x,p.y,level,n,ic,jc); #endif int i,j; for (i=0 ; i<n ; i++) { double x = xmin + (i+0.5)*d; int ig = ic*n + i; for (j=0 ; j<n ; j++) { double y = ymin + (j+0.5)*d; int jg = jc*n + j; /* ig, jg are the global indicies, so give a sample point for the bilinear struct. Note that (x,y) and (x0,y0) shoule be the same, else the bilinear and octree grids are not aligned. */ #ifdef FFTS_DEBUG double x0, y0; bilinear_getxy(ig, jg, ftts.B[0], &x0, &y0); #endif FttVector p; p.x = x; p.y = y; double u = gfs_interpolate(cell,p,ftts.u), v = gfs_interpolate(cell,p,ftts.v); bilinear_setz(ig,jg,u,ftts.B[0]); bilinear_setz(ig,jg,v,ftts.B[1]); #ifdef FFTS_DEBUG printf(" (%f %f) (%f %f) (%i %i) %f %f (%f %f)\n", x, y, x0, y0, ig, jg, u, v, x-x0, y-y0); #endif } } }