real D=0.1, H=0.41;
real cx0 = 0.2, cy0 = 0.2; // center of cyl. 
real xa = 0.15, ya=0.2, xe = 0.25,ye =0.2;
border fr1(t=0,2.2){x=t; y=0; label=1;}
border fr2(t=0,H){x=2.2; y=t; label=2;}
border fr3(t=2.2,0){x=t; y=H; label=1;}
border fr4(t=H,0){x=0; y=t; label=1;}
border fr5(t=2*pi,0){x=cx0+D*sin(t)/2; y=cy0+D*cos(t)/2; label=3;}
int nn=15;
 
mesh Th=buildmesh(fr1(5*nn)+fr2(nn)+fr3(5*nn)+fr4(nn)+fr5(-nn*3));
real Um= 1.5;// max velocity (Rey 100) 
func Ub = Um*2./3.; 
real nu = 1e-3; 
real Rey = Ub*D/nu;
// Boundary condition 
func U1 = 4.*Um*y*(H-y)/(H*H)  ;
func U2 = 0. ;

 real T=2,t=0; 
 real dt = D/nn/Um;// CFL = 1 
 cout << " dt = " << dt <<endl;
real alpha=1/dt,epspq=1e-10;


fespace Mh(Th,[P1]);
fespace Xh(Th,[P2]);
fespace Wh(Th,[P1dc]);
macro grad(u) [dx(u),dy(u)] //
macro div(u1,u2) (dx(u1)+dy(u2)) //

 
 varf von1([u1,u2,p],[v1,v2,q]) =  on(3,u1=0,u2=0) + on(1,u1=U1,u2=U2);

//remark : the value 1000 in next line is manualy fitted, because free outlet. 
 varf vA(p,q) =int2d(Th)((grad( p ) '*grad(q)) ) + int1d(Th,2)(1000*p*q) ;
 varf vM(p,q) =int2d(Th,qft=qf2pT)(  p*q );

 varf vu([u1],[v1]) = int2d(Th)(alpha*(u1*v1)+nu*(grad(u1)'*grad(v1) )) 
                       + on(1,3,u1=0) ;
 varf vu1([p],[v1]) = int2d(Th)(p*dx(v1)) ;
 varf vu2([p],[v1]) = int2d(Th)(p*dy(v1)) ;
   
 string solver="UMFPACK";
 if(!HaveUMFPACK) solver="CHOLESKY";
 matrix pAM=vM(Mh,Mh,solver=solver); 
 matrix pAA=vA(Mh,Mh,solver=solver); 
 matrix AU=vu(Xh,Xh,solver=solver); 
 matrix B1=vu1(Mh,Xh);
 matrix B2=vu2(Mh,Xh);
 Xh u1,u2;
 Mh p;
varf vonu1([u1],[v1]) =  on(1,u1=U1) + on(3,u1=0);
varf vonu2([u1],[v1]) =  on(1,u1=U2) + on(3,u1=0);


real[int] brhs1 = vonu1(0,Xh);
real[int] brhs2 = vonu2(0,Xh);
 
varf  vrhs1(uu,vv)  = int2d(Th) (convect([u1,u2],-dt,u1)*vv*alpha)+vonu1 ;
varf  vrhs2(v2,v1)  = int2d(Th) (convect([u1,u2],-dt,u2)*v1*alpha)+vonu2;


func  real[int]   JUzawa(real[int] & pp) 
{
	real[int] b1=brhs1; b1 += B1*pp;
	real[int] b2=brhs2; b2 += B2*pp;
	u1[] = AU^-1 * b1;
	u2[] = AU^-1 * b2;
	pp  = B1'*u1[];
	pp += B2'*u2[];
	pp = -pp; 
	return pp; 
}

func  real[int]   Precon(real[int] & p)
 {  
    real[int] pa= pAA^-1*p;
    real[int] pm= pAM^-1*p;
    real[int] pp= alpha*pa+nu*pm;
 
  	return pp;
 }

 verbosity = 0; 
 p=0;
 
   
 Wh w; // to store voticity ..
  
 real eps=1e-6;
 int ndt = T/dt;
 for(int i=0;i<ndt;++i)
 {
     brhs1 = vrhs1(0,Xh);
     brhs2 = vrhs2(0,Xh);
     int res=AffineCG(JUzawa,p[],precon=Precon,nbiter=100,verbosity=10,veps=eps); 
     assert(res==1) ; 
     eps = -abs(eps); 
     w = -dy(u1)+dx(u2);
     plot(w,fill=1,wait=0, nbiso=40,WindowIndex=0);
    
     dt = min(dt,T-t);
     t += dt; 
     if( dt < 1e-10*T) break;  
	 if( clock()>50)  break; // to remove CPU limit exceed on some slow machine  
 }
 plot(w,fill=1,wait=0, nbiso=40,ps="NScahouetChabart.eps");
 cout << " u1 max " << u1[].linfty 
      << " u2 max " << u2[].linfty 
      << " p max = " << p[].max << endl; 
 
