// preconditioned p-Laplace problem, p>2, Rayleigh-Ritz int nint = 100; real p = 4.0; // p > 2.0 otherwise NLCG input "too" exact. Do not forget .0 real r = 1.0; border Gamma (t=0,2*pi) { x = r * cos(t); y = r * sin(t); label = 1; } mesh Th = buildmesh(Gamma(nint)); fespace Vh(Th,P1); Vh u0,u,v; func f = 1.0; func uexact = (p-1)/p*(0.5)^(1/(p-1))*(1-(x^2+y^2)^(p/(2*p-2))); real Juexact = 2*pi*(0.5^(p/(p-1.0))*(p-1)/(3*p-2.0)/p- (p-1)/p*0.5^(1.0/(p-1))*(0.5-(p-1)/(3*p-2))); func real J(real[int] & ucoeff) { Vh uloc; uloc[] = ucoeff; return int2d(Th)((dx(uloc)^2+dy(uloc)^2)^(p/2)/p-f*uloc); } func real[int] deltaJR(real[int] & ucoeff) { Vh uloc; uloc[] = ucoeff; varf F(unused,phi) = int2d(Th)((dx(uloc)^2+dy(uloc)^2)^((p-2)/2)* (dx(uloc)*dx(phi)+dy(uloc)*dy(phi))-f*phi) +on(1,unused=0); real[int] r = F(0,Vh); return r; } // initial solution given by Poisson (p=2) solve Poisson(u0,v) = int2d(Th)((dx(u0)*dx(v)+dy(u0)*dy(v))) -int2d(Th)(f*v) +on(1,u0=0); u = u0; NLCG(deltaJR,u[],nbiter=200,eps=-1e-6); cout << "L2 error " << sqrt(int2d(Th)((uexact-u)^2)) << endl; cout << "J error " << abs(J(u[])-Juexact) << endl; // we try with a preconditioner // now we construct a bilinear simplification of delta(deltaJR) // notice that u0 is Poisson's solution varf delta2tildeJR(w,v) = int2d(Th)((dx(u0)^2+dy(u0)^2)^((p-2)/2)* (dx(w)*dx(v)+dy(w)*dy(v))) +on(1,w=0); // we compute the corresponding matrix and factorize once and for all matrix H = delta2tildeJR(Vh,Vh,solver=Cholesky,factorize=1); // we construct a function which apply the preconditioner func real[int] applyprec(real[int] & vec) { real[int] r = H^(-1)*vec; return r; } // one preconditioner u = u0; NLCG(deltaJR,precon=applyprec,u[],nbiter=200,eps=-1e-6); cout << "L2 error " << sqrt(int2d(Th)((uexact-u)^2)) << endl; cout << "J error " << abs(J(u[])-Juexact) << endl; // after a certain (small) number of NLCG iterations, it would be possible // to compute a new preconditioner with its solution and then restart