#include "mypoisson.h" struct Viscosity { vector u; face vector mu; scalar rho; double dt; int nrelax; scalar * res; #if EMBED void (* embed_stress_flux) (Point, vector, vector, coord *, coord *); #endif // EMBED }; #if AXI // fixme: RHO here not correct # define lambda ((coord){1., 1. + dt/RHO*(mu.x[] + mu.x[1] + \ mu.y[] + mu.y[0,1])/2./sq(y)}) #else // not AXI # if dimension == 1 # define lambda ((coord){1.}) # elif dimension == 2 # define lambda ((coord){1.,1.}) # elif dimension == 3 # define lambda ((coord){1.,1.,1.}) #endif #endif // Temporary placement for tangential face gradients #ifndef EMBED #define face_avg_gradient_t1_x(a,i) \ ((a[1,i-1] + a[1,i] - a[-1,i-1] - a[-1,i])/(4.*Delta)) #define face_avg_gradient_t2_x(a,i) \ ((a[1,0,i-1] + a[1,0,i] - a[-1,0,i-1] - a[-1,0,i])/(4.*Delta)) #define face_avg_gradient_t1_y(a,i) \ ((a[i-1,1] + a[i,1] - a[i-1,-1] - a[i,-1])/(4.*Delta)) #define face_avg_gradient_t2_y(a,i) \ ((a[0,1,i-1] + a[0,1,i] - a[0,-1,i-1] - a[0,-1,i])/(4.*Delta)) #define face_avg_gradient_t1_z(a,i) \ ((a[i-1,0,1] + a[i,0,1] - a[i-1,0,-1] - a[i,0,-1])/(4.*Delta)) #define face_avg_gradient_t2_z(a,i) \ ((a[0,i-1,1] + a[0,i,1] - a[i-1,0,-1] - a[0,i,-1])/(4.*Delta)) #endif // EMBED // Note how the relaxation function uses "naive" gradients i.e. not // the face_gradient_* macros. static void relax_viscosity (scalar * a, scalar * b, int l, void * data) { struct Viscosity * p = (struct Viscosity *) data; (const) face vector mu = p->mu; (const) scalar rho = p->rho; double dt = p->dt; vector u = vector(a[0]), r = vector(b[0]); #if EMBED void (* embed_stress_flux) (Point, vector, vector, coord *, coord *) = p->embed_stress_flux; #endif // EMBED #if JACOBI vector w[]; #else vector w = u; #endif foreach_level_or_leaf (l) { coord c = {0., 0., 0.}, d = {0., 0., 0.}; #if EMBED if (embed_stress_flux) embed_stress_flux (point, u, mu, &c, &d); #endif // EMBED foreach_dimension() { w.x[] = (dt*(2.*mu.x[1]*u.x[1] + 2.*mu.x[]*u.x[-1] #if dimension > 1 + mu.y[0,1]*(u.x[0,1] + face_avg_gradient_t1_x (u.y, 1)*Delta) - mu.y[]*(- u.x[0,-1] + face_avg_gradient_t1_x (u.y, 0)*Delta) #endif #if dimension > 2 + mu.z[0,0,1]*(u.x[0,0,1] + face_avg_gradient_t2_x (u.z, 1)*Delta) - mu.z[]*(- u.x[0,0,-1] + face_avg_gradient_t2_x (u.z, 0)*Delta) #endif ) + (r.x[] - dt*c.x)*sq(Delta))/ (sq(Delta)*(rho[]*lambda.x + dt*d.x) + dt*(2.*mu.x[1] + 2.*mu.x[] #if dimension > 1 + mu.y[0,1] + mu.y[] #endif #if dimension > 2 + mu.z[0,0,1] + mu.z[] #endif ) + SEPS); } } #if JACOBI foreach_level_or_leaf (l) foreach_dimension() u.x[] = (u.x[] + 2.*w.x[])/3.; #endif #if TRASH vector u1[]; foreach_level_or_leaf (l) foreach_dimension() u1.x[] = u.x[]; trash ({u}); foreach_level_or_leaf (l) foreach_dimension() u.x[] = u1.x[]; #endif } static double residual_viscosity (scalar * a, scalar * b, scalar * resl, void * data) { struct Viscosity * p = (struct Viscosity *) data; (const) face vector mu = p->mu; (const) scalar rho = p->rho; double dt = p->dt; vector u = vector(a[0]), r = vector(b[0]), res = vector(resl[0]); double maxres = 0.; #if EMBED void (* embed_stress_flux) (Point, vector, vector, coord *, coord *) = p->embed_stress_flux; #endif #if TREE /* conservative coarse/fine discretisation (2nd order) */ foreach_dimension() { face vector taux[]; foreach_face(x) taux.x[] = 2.*mu.x[]*face_gradient_x (u.x, 0); #if dimension > 1 foreach_face(y) taux.y[] = mu.y[]*(face_gradient_y (u.x, 0) + face_avg_gradient_t1_x (u.y, 0)); #endif #if dimension > 2 foreach_face(z) taux.z[] = mu.z[]*(face_gradient_z (u.x, 0) + face_avg_gradient_t2_x (u.z, 0)); #endif boundary_flux ({taux}); foreach (reduction(max:maxres)) { double a = 0.; coord c = {0., 0., 0.}, d = {0., 0., 0.}; #if EMBED if (embed_stress_flux) embed_stress_flux (point, u, mu, &c, &d); #endif // EMBED foreach_dimension() a += taux.x[1] - taux.x[]; res.x[] = r.x[] - rho[]*lambda.x*u.x[] + dt*(a/Delta - (c.x + d.x*u.x[])); if (fabs (res.x[]) > maxres) maxres = fabs (res.x[]); } } boundary (resl); #else /* "naive" discretisation (only 1st order on trees) */ foreach (reduction(max:maxres)) { coord c = {0., 0., 0.}, d = {0., 0., 0.}; #if EMBED if (embed_stress_flux) embed_stress_flux (point, u, mu, &c, &d); #endif // EMBED foreach_dimension() { res.x[] = r.x[] - rho[]*lambda.x*u.x[] + dt*(2.*mu.x[1,0]*face_gradient_x (u.x, 1) - 2.*mu.x[]*face_gradient_x (u.x, 0) #if dimension > 1 + mu.y[0,1]* (face_gradient_y (u.x, 1) + face_avg_gradient_t1_x (u.y, 1)) - mu.y[]*(face_gradient_y (u.x, 0) + face_avg_gradient_t1_x (u.y, 0)) #endif #if dimension > 2 + mu.z[0,0,1]*(face_gradient_z (u.x, 1) + face_avg_gradient_t2_x (u.z, 1)) - mu.z[]*(face_gradient_z (u.x, 0) + face_avg_gradient_t2_x (u.z, 0)) #endif )/Delta - dt*(c.x + d.x*u.x[]); if (fabs (res.x[]) > maxres) maxres = fabs (res.x[]); } } #endif return maxres; } #undef lambda double TOLERANCE_MU = 0.; // default to TOLERANCE trace mgstats viscosity (struct Viscosity p) { vector u = p.u, r[]; scalar rho = p.rho; foreach() foreach_dimension() r.x[] = rho[]*u.x[]; face vector mu = p.mu; restriction ({mu, rho}); #if EMBED p.embed_stress_flux = u.x.boundary[embed] != antisymmetry ? embed_stress_flux : NULL; #endif // EMBED return mg_solve ((scalar *){u}, (scalar *){r}, residual_viscosity, relax_viscosity, &p, p.nrelax, p.res, minlevel = 1, // fixme: because of root level // BGHOSTS = 2 bug on trees tolerance = TOLERANCE_MU); }